Operations on Sets
Cant:
ERROR [set: Set];
Raised when a Set is asked to perform an operation it can't (not because it's inappropriate, that raises Error; Cant signals that a sensible operation just isn't implemented).
HasMember:
PROC [set: Set, elt: Value]
RETURNS [
BOOL]
~ INLINE {RETURN [set.class.HasMember[set, elt]]};
HasMemA:
PROC [set: Set, elt:
REF
ANY]
RETURNS [
BOOL]
= HasMember[elt: [a[elt]] ]
~ INLINE {RETURN [set.class.HasMember[set, [a[elt]] ]]};
HasMemI:
PROC [set: Set, elt:
INT]
RETURNS [
BOOL]
= HasMember[elt: [a[elt]] ]
~ INLINE {RETURN [set.class.HasMember[set, [i[elt]] ]]};
Enumerate:
PROC [set: Set,
Consumer:
PROC [Value], ro: RelOrder ← no];
It's valid to operate on the set from inside a Consumer, but there are no guarantees about whether elements added or deleted inside a Consumer are seen in that enumeration.
EnumA: PROC [set: Set, Consumer: PROC [REF ANY], ro: RelOrder ← no];
EnumI: PROC [set: Set, Consumer: PROC [INT], ro: RelOrder ← no];
Tester: TYPE ~ PROC [Value] RETURNS [BOOL];
AcceptAny: Tester--={RETURN[TRUE]}--;
Scan:
PROC [set: Set,
Test: Tester, ro: RelOrder ← no]
RETURNS [MaybeValue]
A stoppable enumeration. The Tester returns TRUE to stop the enumeration. If the Tester returned TRUE, Scan returns [TRUE, the value accepted]; otherwise Scan returns noMaybe.
~ INLINE {RETURN set.class.Scan[set, Test, ro]};
ParallelScan:
PROC [a, b: Set,
Test: ParallelTester, roA, roB: RelOrder ← no]
RETURNS [ParallelFind];
The elements are produced in the order they would be produced by calls on Scan for the individual collections. The tester takes MaybeValues instead of Values because one collection may run out before the other.
ParallelTester: TYPE ~ PROC [a, b: MaybeValue] RETURNS [pass: BOOL ← FALSE];
ParallelFind: TYPE ~ RECORD [found: BOOL, a, b: MaybeValue];
InterleavedProduce: PROC [a, b: Set, Consume: InterleavedConsumer, roA, roB: RelOrder ← no] RETURNS [MaybeValue];
InterleavedConsumer: TYPE ~ PROC [PROC [Which] RETURNS [MaybeValue]] RETURNS [MaybeValue];
Which: TYPE ~ {a, b};
TheElt:
PROC [set: Set]
RETURNS [Value]
Returns the element, if there is exactly one; Error["%g not a singleton", LIST[set]] otherwise.
~ INLINE {RETURN set.class.TheElt[set]};
notASingleton: READONLY ROPE;
GetOne:
PROC [set: Set, remove:
BOOL, ro: RelOrder]
RETURNS [MaybeValue]
Returns, and optionally deletes, some value in the set, if it's non-empty; returns noMaybe if the set is empty. That value is the first one that would be enumerated.
~ INLINE {RETURN set.class.GetOne[set, remove, ro]};
AnElt:
PROC [set: Set, ro: RelOrder ← no]
RETURNS [MaybeValue]
=GetOne[remove: FALSE]
~ INLINE {RETURN set.class.GetOne[set, FALSE, ro]};
Pop:
PROC [set: Set, ro: RelOrder ← no]
RETURNS [MaybeValue]
=GetOne[remove: TRUE]
~ INLINE {RETURN set.class.GetOne[set, TRUE, ro]};
First:
PROC [set: Set]
RETURNS [MaybeValue]
~ INLINE {RETURN set.class.GetOne[set, FALSE, fwd]};
Last:
PROC [set: Set]
RETURNS [MaybeValue]
~ INLINE {RETURN set.class.GetOne[set, FALSE, bwd]};
TripleMaybeValue: TYPE ~ RECORD [prev, same, next: MaybeValue];
TripleBool: TYPE ~ RECORD [prev, same, next: BOOL ← TRUE];
Next:
PROC [set: Set, elt: Value]
RETURNS [MaybeValue]
Returns the next (according to the order of the set's space) element in the set.
~ INLINE {RETURN [set.class.Get3[set, elt, [FALSE, FALSE, TRUE]].next]};
Prev:
PROC [set: Set, elt: Value]
RETURNS [MaybeValue]
~ INLINE {RETURN [set.class.Get3[set, elt, [TRUE, FALSE, FALSE]].prev]};
Get3:
PROC [set: Set, elt: Value, want: TripleBool ← []]
RETURNS [TripleMaybeValue]
No guarantees about unwanted results.
~ INLINE {RETURN set.class.Get3[set, elt, want]};
Size:
PROC [set: Set, limit:
EINT ← lastEINT]
RETURNS [
EINT]
Size = number of elements, or limit <= Size <= number of elements.
~ INLINE {RETURN [set.class.Size[set, limit]]};
Empty:
PROC [set: Set]
RETURNS [
BOOL]
~ INLINE {RETURN [set.class.Size[set, IntStuff.one]=IntStuff.zero]};
When: TYPE ~ {now, always};
IsDense:
PROC [set: Set, when: When ← always]
RETURNS [
BOOL]
Iff you can find an x and z in the set, and a y (in the set's space but) not in the set, such that x < y < z (according to the total ordering of the space of the set), then the set is not dense. Clients may ask about the current state of a variable, or whether the variable is ever allowed to be non-dense. Stupid implementations may return a conservative answer (i.e., FALSE).
~ INLINE {RETURN set.class.IsDense[set, when]};
EndBools: TYPE ~ PACKED ARRAY End OF TrueBool;
TrueBool: TYPE ~ BOOL ← TRUE;
GetBounds:
PROC [set: Set, want: EndBools ← []]
RETURNS [MaybeInterval]
Returns [TRUE, extrema according to the total ordering of the space] when set non-empty; NOT result.found when set empty. No guarantees about unwanted fields (result.found is considered unwanted when neither wantMin nor wantMax).
~ INLINE {RETURN set.class.GetBounds[set, want]};
MaybeInterval: TYPE ~ RECORD [found: BOOL, it: Interval];
Mutability:
TYPE ~ {constant, readonly, variable};
A variable Set represents a set variable: a variable that ranges over sets (but with fixed space, and perhaps fixed denseness). A readonly Set is a reference to a set variable that does not give write permission to the holder (but other references to that variable might have it). A constant Set does not represent a variable; it represents a set value.
ChangeableMutability: TYPE ~ Mutability[readonly..variable];
UnwriteableMutability: TYPE ~ Mutability[constant..readonly];
MutabilityOf:
PROC [set: Set]
RETURNS [Mutability]
~ INLINE {RETURN [set.class.mutability]};
Copy:
PROC [set: Set]
RETURNS [VarSet]
Returns a new set variable, using same implementation, initialized to the current contents of the argument.
~ INLINE {RETURN [set.class.Copy[set]]};
Insulate:
PROC [set: Set]
RETURNS [UWSet]
When applied to a variable set, returns a readonly reference to that variable; otherwise returns the given set.
~ INLINE {RETURN [set.class.Insulate[set]]};
ValueOf:
PROC [set: Set]
RETURNS [ConstSet]
When applied to a variable or readonly set, returns a constant set that is the current value of the variable and has the same implementation; otherwise returns the given (constant) set.
~ INLINE {RETURN set.class.ValueOf[set]};
Freeze:
PROC [set: Set]
RETURNS [ConstSet]
So what do you do when you've got a variable set you want to pass to a procecure that wants a constant one? What if you also know that the variable is not going to vary for the duration of the call? It would be a pain to make a copy just to satisfy the mutability checking. So here's an alternative. Freeze[a variable set] prohibits changes, and returns a set that is allegedly constant. Attempts to update a frozen variable raise Error[frozen, LIST[set]]. When, if ever, the variable is thawed, attempts to use the constant set raise Error[unfrozen, LIST[const]]. Pairs of Freeze and Thaw nest like parentheses; a variable can only be changed if it is outside the scope of any Freeze...Thaw.
~ INLINE {RETURN set.class.Freeze[set]};
frozen, unfrozen: READONLY ROPE;
Thaw:
PROC [set: Set]
~ INLINE {set.class.Thaw[set]};
AddElt:
PROC [set: Set, elt: Value]
RETURNS [new:
BOOL]
Union the singleton set {elt} into self; obviously applicable only to set variables. new tells whether there was already an equivalent element in the set.
~ INLINE {new ← set.class.AddSet[set, CreateSingleton[elt, set.SpaceOf]].new.some};
AddA:
PROC [set: Set, elt:
REF
ANY]
RETURNS [new:
BOOL]
~ INLINE {new ← set.class.AddSet[set, CreateSingleton[[a[elt]], set.SpaceOf]].new.some};
AddI:
PROC [set: Set, elt:
INT]
RETURNS [new:
BOOL]
~ INLINE {new ← set.class.AddSet[set, CreateSingleton[[i[elt]], set.SpaceOf]].new.some};
NAddElt:
PROC [set: Set, elt: Value]
RETURNS [new:
BOOL];
A non-INLINE version, for the benefit of interpreter calling.
SomeAll: TYPE ~ RECORD [some: BOOL ← FALSE, all: BOOL ← TRUE];
AddSet:
PROC [set, other: Set]
RETURNS [new: SomeAll]
Like a series of AddElts. Uses the current value of other. When other has two elements that are considered equal by set's space, no guarantees about new.all.
~ INLINE {RETURN set.class.AddSet[set, other]};
RemElt:
PROC [set: Set, elt: Value]
RETURNS [had:
BOOL]
~ INLINE {had ← set.class.RemSet[set, CreateSingleton[elt, set.SpaceOf]].had.some};
RemA:
PROC [set: Set, elt:
REF
ANY]
RETURNS [had:
BOOL]
~ INLINE {had ← set.class.RemSet[set, CreateSingleton[[a[elt]], set.SpaceOf]].had.some};
RemI:
PROC [set: Set, elt:
INT]
RETURNS [had:
BOOL]
~ INLINE {had ← set.class.RemSet[set, CreateSingleton[[i[elt]], set.SpaceOf]].had.some};
RemSet:
PROC [set, other: Set]
RETURNS [had: SomeAll]
RemSet is equivalent to a series of RemElts. Uses the current value of other.
~ INLINE {RETURN set.class.RemSet[set, other]};
Erase:
PROC [set: Set]
~ INLINE {[] ← set.RemSet[set]};
SpaceOf:
PROC [set: Set]
RETURNS [Space]
Every Set knows its space; SpaceOf never raises Cant, and never returns NIL.
~ INLINE {RETURN set.class.SpaceOf[set]};
Equal:
PROC [a, b: Set]
RETURNS [
BOOL];