std.set

Reed's standard library. Imported with use std.set; not on disk.

Functions

int_setAn empty IntSet.
int_set_with_capacityAn empty IntSet with room for capacity members before the first rehash.
int_set_fromAn IntSet holding every distinct value in values.
bit_setAn empty BitSet able to hold members 0..capacity.

int_set #

line 47
func int_set() -> &IntSet

An empty IntSet.

Returns
a new empty set
Source
func int_set() -> &IntSet {
  return new IntSet { entries: int_map() };
}

int_set_with_capacity #

line 55
func int_set_with_capacity(capacity: i32) -> &IntSet

An empty IntSet with room for capacity members before the first rehash.

Parameters
capacity — how many members to plan for
Returns
a new empty set
Source
func int_set_with_capacity(capacity: i32) -> &IntSet {
  return new IntSet { entries: int_map_with_capacity(capacity) };
}

int_set_from #

line 63
func int_set_from(values: &I32Values) -> &IntSet

An IntSet holding every distinct value in values.

Parameters
values — the members to insert
Returns
a new set
Source
func int_set_from(values: &I32Values) -> &IntSet {
  let out: &IntSet = int_set_with_capacity(#values);
  for i in 0..#values {
    out.add(values[i]);
  }
  return out;
}

bit_set #

line 197
func bit_set(capacity: i32) -> &BitSet

An empty BitSet able to hold members 0..capacity.

A capacity below zero is treated as zero.

Parameters
capacity — the exclusive upper bound on membership
Returns
a new empty set
Source
func bit_set(capacity: i32) -> &BitSet {
  let n: i32 = capacity < 0 ? 0 : capacity;
  // Round up to whole 32-bit words.
  return new BitSet { words: new I32Values[(n + 31) / 32]{}, capacity: n };
}

Methods

IntSet.lenHow many members the set holds.
IntSet.is_emptyWhether the set holds no members.
IntSet.addAdds value to the set.
IntSet.containsWhether value is a member.
IntSet.removeRemoves value from the set.
IntSet.clearRemoves every member, keeping the allocated capacity.
IntSet.to_listEvery member, in unspecified order.
IntSet.unionA new set holding every member of either set.
IntSet.intersectA new set holding the members present in both sets.
IntSet.differenceA new set holding the members of self that are not in other.
IntSet.is_subsetWhether every member of self is also a member of other.
BitSet.capacityThe exclusive upper bound on membership, as given at construction.
BitSet.addAdds value to the set.
BitSet.containsWhether value is a member.
BitSet.removeRemoves value from the set.
BitSet.toggleAdds value if absent and removes it if present.
BitSet.lenHow many members the set holds.
BitSet.is_emptyWhether the set holds no members.
BitSet.clearRemoves every member.
BitSet.fill_allAdds every member of 0..capacity.
BitSet.nextThe smallest member at or above from, or -1 when there is none.
BitSet.to_arrayEvery member, in ascending order.
BitSet.union_withAdds every member of other to self, in place.
BitSet.intersect_withRemoves from self every member not also in other, in place.
BitSet.subtractRemoves from self every member also in other, in place.
BitSet.trimClears any bits at or above capacity in the final word.

IntSet.len #

line 74
func IntSet.len(self: &IntSet) -> i32

How many members the set holds.

Returns
the member count
Source
func IntSet.len(self: &IntSet) -> i32 {
  return self->entries.len();
}

IntSet.is_empty #

line 81
func IntSet.is_empty(self: &IntSet) -> i32

Whether the set holds no members.

Returns
1 when empty, 0 otherwise
Source
func IntSet.is_empty(self: &IntSet) -> i32 {
  return self->entries.len() == 0;
}

IntSet.add #

line 90
func IntSet.add(self: &IntSet, value: i32) -> i32

Adds value to the set.

Parameters
value — the member to add
Returns
1 when the value was newly added, 0 when it was already present
See also
IntSet.remove
Source
func IntSet.add(self: &IntSet, value: i32) -> i32 {
  if (self->entries.contains(value)) { return 0; }
  self->entries.put(value, 1);
  return 1;
}

IntSet.contains #

line 100
func IntSet.contains(self: &IntSet, value: i32) -> i32

Whether value is a member.

Parameters
value — the value to test
Returns
1 when present, 0 otherwise
Source
func IntSet.contains(self: &IntSet, value: i32) -> i32 {
  return self->entries.contains(value);
}

IntSet.remove #

line 108
func IntSet.remove(self: &IntSet, value: i32) -> i32

Removes value from the set.

Parameters
value — the member to remove
Returns
1 when a member was removed, 0 when it was absent
Source
func IntSet.remove(self: &IntSet, value: i32) -> i32 {
  return self->entries.remove(value);
}

IntSet.clear #

line 113
func IntSet.clear(self: &IntSet) -> void

Removes every member, keeping the allocated capacity.

Source
func IntSet.clear(self: &IntSet) {
  self->entries.clear();
}

IntSet.to_list #

line 120
func IntSet.to_list(self: &IntSet) -> &IntList

Every member, in unspecified order.

Returns
a list of the members
Source
func IntSet.to_list(self: &IntSet) -> &IntList {
  return self->entries.keys();
}

IntSet.union #

line 129
func IntSet.union(self: &IntSet, other: &IntSet) -> &IntSet

A new set holding every member of either set.

Parameters
other — the set to union with
Returns
a new set
See also
IntSet.intersect, IntSet.difference
Source
func IntSet.union(self: &IntSet, other: &IntSet) -> &IntSet {
  let out: &IntSet = int_set_with_capacity(self.len() + other.len());
  let mine: &IntList = self.to_list();
  for i in 0..mine.len() {
    out.add(mine.at(i));
  }
  let theirs: &IntList = other.to_list();
  for i in 0..theirs.len() {
    out.add(theirs.at(i));
  }
  return out;
}

IntSet.intersect #

line 150
func IntSet.intersect(self: &IntSet, other: &IntSet) -> &IntSet

A new set holding the members present in both sets.

Iterates the smaller set and probes the larger, so the cost is proportional to the smaller operand rather than to whichever happens to be the receiver.

Parameters
other — the set to intersect with
Returns
a new set
See also
IntSet.union
Source
func IntSet.intersect(self: &IntSet, other: &IntSet) -> &IntSet {
  let out: &IntSet = int_set();
  let smaller: &IntSet = self.len() <= other.len() ? self : other;
  let larger: &IntSet = self.len() <= other.len() ? other : self;
  let members: &IntList = smaller.to_list();
  for i in 0..members.len() {
    let value: i32 = members.at(i);
    if (larger.contains(value)) { out.add(value); }
  }
  return out;
}

IntSet.difference #

line 167
func IntSet.difference(self: &IntSet, other: &IntSet) -> &IntSet

A new set holding the members of self that are not in other.

Parameters
other — the set to subtract
Returns
a new set
See also
IntSet.union
Source
func IntSet.difference(self: &IntSet, other: &IntSet) -> &IntSet {
  let out: &IntSet = int_set();
  let members: &IntList = self.to_list();
  for i in 0..members.len() {
    let value: i32 = members.at(i);
    if (other.contains(value) == 0) { out.add(value); }
  }
  return out;
}

IntSet.is_subset #

line 183
func IntSet.is_subset(self: &IntSet, other: &IntSet) -> i32

Whether every member of self is also a member of other.

The empty set is a subset of everything.

Parameters
other — the candidate superset
Returns
1 when self is a subset, 0 otherwise
Source
func IntSet.is_subset(self: &IntSet, other: &IntSet) -> i32 {
  let members: &IntList = self.to_list();
  for i in 0..members.len() {
    if (other.contains(members.at(i)) == 0) { return 0; }
  }
  return 1;
}

BitSet.capacity #

line 207
func BitSet.capacity(self: &BitSet) -> i32

The exclusive upper bound on membership, as given at construction.

Returns
the capacity
See also
BitSet.len
Source
func BitSet.capacity(self: &BitSet) -> i32 {
  return self->capacity;
}

BitSet.add #

line 219
func BitSet.add(self: &BitSet, value: i32) -> i32

Adds value to the set.

A value outside 0..capacity is ignored rather than trapping or growing the set: a BitSet's bound is chosen by its creator and silently extending it would break the memory guarantee that is the whole point of the type.

Parameters
value — the member to add
Returns
1 when newly added, 0 when already present or out of range
Source
func BitSet.add(self: &BitSet, value: i32) -> i32 {
  if (value < 0 || value >= self->capacity) { return 0; }
  let word: i32 = value >>> 5;
  let bit: i32 = 1 << (value & 31);
  if ((self->words[word] & bit) != 0) { return 0; }
  self->words[word] = self->words[word] | bit;
  return 1;
}

BitSet.contains #

line 234
func BitSet.contains(self: &BitSet, value: i32) -> i32

Whether value is a member.

A value out of range is never a member.

Parameters
value — the value to test
Returns
1 when present, 0 otherwise
Source
func BitSet.contains(self: &BitSet, value: i32) -> i32 {
  if (value < 0 || value >= self->capacity) { return 0; }
  return (self->words[value >>> 5] >>> (value & 31)) & 1;
}

BitSet.remove #

line 243
func BitSet.remove(self: &BitSet, value: i32) -> i32

Removes value from the set.

Parameters
value — the member to remove
Returns
1 when a member was removed, 0 otherwise
Source
func BitSet.remove(self: &BitSet, value: i32) -> i32 {
  if (value < 0 || value >= self->capacity) { return 0; }
  let word: i32 = value >>> 5;
  let bit: i32 = 1 << (value & 31);
  if ((self->words[word] & bit) == 0) { return 0; }
  self->words[word] = self->words[word] & ~bit;
  return 1;
}

BitSet.toggle #

line 256
func BitSet.toggle(self: &BitSet, value: i32) -> i32

Adds value if absent and removes it if present.

Parameters
value — the member to toggle
Returns
1 when the value is now present, 0 when it is now absent
Source
func BitSet.toggle(self: &BitSet, value: i32) -> i32 {
  if (value < 0 || value >= self->capacity) { return 0; }
  let word: i32 = value >>> 5;
  let bit: i32 = 1 << (value & 31);
  self->words[word] = self->words[word] ^ bit;
  return (self->words[word] & bit) != 0;
}

BitSet.len #

line 271
func BitSet.len(self: &BitSet) -> i32

How many members the set holds.

Counts set bits a word at a time with popcnt, so this is 32 members per instruction rather than a per-member loop.

Returns
the member count
See also
BitSet.capacity
Source
func BitSet.len(self: &BitSet) -> i32 {
  var total: i32 = 0;
  for i in 0..#self->words {
    total = total + self->words[i].popcnt();
  }
  return total;
}

BitSet.is_empty #

line 282
func BitSet.is_empty(self: &BitSet) -> i32

Whether the set holds no members.

Returns
1 when empty, 0 otherwise
Source
func BitSet.is_empty(self: &BitSet) -> i32 {
  for i in 0..#self->words {
    if (self->words[i] != 0) { return 0; }
  }
  return 1;
}

BitSet.clear #

line 290
func BitSet.clear(self: &BitSet) -> void

Removes every member.

Source
func BitSet.clear(self: &BitSet) {
  self->words.fill(0, 0, #self->words);
}

BitSet.fill_all #

line 298
func BitSet.fill_all(self: &BitSet) -> void

Adds every member of 0..capacity.

Sets only the bits below capacity, leaving the word array's padding bits clear -- if they were set, len would over-count.

Source
func BitSet.fill_all(self: &BitSet) {
  self->words.fill(0, -1, #self->words);
  let extra: i32 = #self->words * 32 - self->capacity;
  if (extra > 0) {
    self->words[#self->words - 1] = self->words[#self->words - 1] & (-1 >>> extra);
  }
}

BitSet.next #

line 315
func BitSet.next(self: &BitSet, from: i32) -> i32

The smallest member at or above from, or -1 when there is none.

Iterating with this is how a BitSet is enumerated: var i: i32 = s.next(0); loop { if (i < 0) break; ...; i = s.next(i + 1); }. It skips empty words wholesale and uses ctz within a word, so scanning a sparse set costs time proportional to the words, not to the capacity.

Parameters
from — where to start looking, inclusive
Returns
the member, or -1 when none remain
Source
func BitSet.next(self: &BitSet, from: i32) -> i32 {
  var at: i32 = from < 0 ? 0 : from;
  if (at >= self->capacity) { return -1; }
  var word: i32 = at >>> 5;
  // Mask off the bits below `at` in the first word, so the scan starts exactly at `from`.
  var bits: i32 = self->words[word] & (-1 << (at & 31));
  loop scan() {
    if (bits != 0) {
      let found: i32 = word * 32 + bits.ctz();
      return found < self->capacity ? found : -1;
    }
    word = word + 1;
    if (word >= #self->words) { break scan(); }
    bits = self->words[word];
    continue scan();
  }
  return -1;
}

BitSet.to_array #

line 337
func BitSet.to_array(self: &BitSet) -> &I32Values

Every member, in ascending order.

Returns
an array of the members
Source
func BitSet.to_array(self: &BitSet) -> &I32Values {
  let out: &I32Values = new I32Values[self.len()]{};
  var index: i32 = 0;
  var value: i32 = self.next(0);
  loop collect() {
    if (value < 0) { break collect(); }
    out[index] = value;
    index = index + 1;
    value = self.next(value + 1);
    continue collect();
  }
  return out;
}

BitSet.union_with #

line 358
func BitSet.union_with(self: &BitSet, other: &BitSet) -> void

Adds every member of other to self, in place.

A capacity mismatch is handled by operating on the words both sets have; members of other beyond self's capacity are dropped, matching add's out-of-range rule.

Parameters
other — the set to merge in
See also
BitSet.intersect_with
Source
func BitSet.union_with(self: &BitSet, other: &BitSet) {
  let n: i32 = #self->words < #other->words ? #self->words : #other->words;
  for i in 0..n {
    self->words[i] = self->words[i] | other->words[i];
  }
  self.trim();
}

BitSet.intersect_with #

line 370
func BitSet.intersect_with(self: &BitSet, other: &BitSet) -> void

Removes from self every member not also in other, in place.

Parameters
other — the set to intersect with
See also
BitSet.union_with
Source
func BitSet.intersect_with(self: &BitSet, other: &BitSet) {
  for i in 0..#self->words {
    let mask: i32 = i < #other->words ? other->words[i] : 0;
    self->words[i] = self->words[i] & mask;
  }
}

BitSet.subtract #

line 380
func BitSet.subtract(self: &BitSet, other: &BitSet) -> void

Removes from self every member also in other, in place.

Parameters
other — the set to subtract
Source
func BitSet.subtract(self: &BitSet, other: &BitSet) {
  let n: i32 = #self->words < #other->words ? #self->words : #other->words;
  for i in 0..n {
    self->words[i] = self->words[i] & ~other->words[i];
  }
}

BitSet.trim #

line 391
func BitSet.trim(self: &BitSet) -> void

Clears any bits at or above capacity in the final word.

The invariant every operation must restore: padding bits are never set, so len and is_empty can read whole words without masking.

Source
func BitSet.trim(self: &BitSet) {
  if (#self->words == 0) { return; }
  let extra: i32 = #self->words * 32 - self->capacity;
  if (extra > 0) {
    self->words[#self->words - 1] = self->words[#self->words - 1] & (-1 >>> extra);
  }
}

Types

IntSetA hash set of i32 members.
BitSetA dense set of members drawn from 0..capacity, stored one bit each.

IntSet #

line 32
struct IntSet {
  entries: mut &IntMap,
}

A hash set of i32 members.

Source
struct IntSet {
  entries: mut &IntMap,
}

BitSet #

line 37
struct BitSet {
  words: mut &I32Values,
  capacity: mut i32,
}

A dense set of members drawn from 0..capacity, stored one bit each.

Source
struct BitSet {
  words: mut &I32Values,
  /// The exclusive upper bound on membership. Kept separately because the word array
  /// rounds up to a multiple of 32 and the padding bits must never be reported as members.
  capacity: mut i32,
}