Improve documentation for packedsets (#16715)

* Improve documentation for packedsets

Add more runnableExamples
Add deprecated pragma to intsets
Replace intsets with packedsets in lib.rst

* Apply suggested changes
This commit is contained in:
konsumlamm 2021-01-16 16:09:53 +01:00 • committed by GitHub
commit 44ceefa9fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 154 additions and 151 deletions

View file

@ -32,15 +32,15 @@ Automatic imports
* `system <system.html>`_ * `system <system.html>`_
Basic procs and operators that every program needs. It also provides IO Basic procs and operators that every program needs. It also provides IO
facilities for reading and writing text and binary files. It is imported facilities for reading and writing text and binary files. It is imported
implicitly by the compiler. Do not import it directly. It relies on compiler implicitly by the compiler. Do not import it directly. It relies on compiler
magic to work. magic to work.
* `threads <threads.html>`_ * `threads <threads.html>`_
Basic Nim thread support. **Note**: This is part of the system module. Do not Basic Nim thread support. **Note:** This is part of the system module. Do not
import it explicitly. Enabled with ``--threads:on``. import it explicitly. Enabled with ``--threads:on``.
* `channels <channels.html>`_ * `channels <channels.html>`_
Nim message passing support for threads. **Note**: This is part of the Nim message passing support for threads. **Note:** This is part of the
system module. Do not import it explicitly. Enabled with ``--threads:on``. system module. Do not import it explicitly. Enabled with ``--threads:on``.
@ -107,6 +107,7 @@ Collections
* `intsets <intsets.html>`_ * `intsets <intsets.html>`_
Efficient implementation of a set of ints as a sparse bit set. Efficient implementation of a set of ints as a sparse bit set.
**Deprecated:** Use the packedsets module instead.
* `lists <lists.html>`_ * `lists <lists.html>`_
Nim linked list support. Contains singly and doubly linked lists and Nim linked list support. Contains singly and doubly linked lists and
@ -115,6 +116,9 @@ Collections
* `options <options.html>`_ * `options <options.html>`_
The option type encapsulates an optional value. The option type encapsulates an optional value.
* `packedsets <packedsets.html>`_
Efficient implementation of a set of ordinals as a sparse bit set.
* `sets <sets.html>`_ * `sets <sets.html>`_
Nim hash and bit set support. Nim hash and bit set support.
@ -154,7 +158,7 @@ String handling
* `ropes <ropes.html>`_ * `ropes <ropes.html>`_
This module contains support for a *rope* data type. This module contains support for a *rope* data type.
Ropes can represent very long strings efficiently; Ropes can represent very long strings efficiently;
especially concatenation is done in O(1) instead of O(n). especially concatenation is done in O(1) instead of O(n).
* `strformat <strformat.html>`_ * `strformat <strformat.html>`_
@ -231,8 +235,8 @@ Generic Operating System Services
* `streams <streams.html>`_ * `streams <streams.html>`_
This module provides a stream interface and two implementations thereof: This module provides a stream interface and two implementations thereof:
the `FileStream` and the `StringStream` which implement the stream the `FileStream` and the `StringStream` which implement the stream
interface for Nim file objects (`File`) and strings. Other modules interface for Nim file objects (`File`) and strings. Other modules
may provide other implementations for this standard stream interface. may provide other implementations for this standard stream interface.
* `terminal <terminal.html>`_ * `terminal <terminal.html>`_
@ -373,12 +377,12 @@ Docutils
-------- --------
* `packages/docutils/highlite <highlite.html>`_ * `packages/docutils/highlite <highlite.html>`_
Source highlighter for programming or markup languages. Currently, Source highlighter for programming or markup languages. Currently,
only a few languages are supported, other languages may be added. only a few languages are supported, other languages may be added.
The interface supports one language nested in another. The interface supports one language nested in another.
* `packages/docutils/rst <rst.html>`_ * `packages/docutils/rst <rst.html>`_
This module implements a reStructuredText parser. A large subset This module implements a reStructuredText parser. A large subset
is implemented. Some features of the markdown wiki syntax are also supported. is implemented. Some features of the markdown wiki syntax are also supported.
* `packages/docutils/rstast <rstast.html>`_ * `packages/docutils/rstast <rstast.html>`_
@ -403,8 +407,8 @@ Generators
---------- ----------
* `htmlgen <htmlgen.html>`_ * `htmlgen <htmlgen.html>`_
This module implements a simple XML and HTML code This module implements a simple XML and HTML code
generator. Each commonly used HTML tag has a corresponding macro generator. Each commonly used HTML tag has a corresponding macro
that generates a string with its HTML representation. that generates a string with its HTML representation.
@ -489,7 +493,7 @@ Regular expressions
------------------- -------------------
* `re <re.html>`_ * `re <re.html>`_
This module contains procedures and operators for handling regular This module contains procedures and operators for handling regular
expressions. The current implementation uses PCRE. expressions. The current implementation uses PCRE.

View file

@ -7,9 +7,10 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
## Deprecated by the generic `PackedSet` for ordinal sparse sets. ## Deprecated in favor of the generic `packedsets module <packedsets.html>`_
## **See also:** ## for ordinal sparse sets.
## * `Ordinal packed sets module <packedsets.html>`_ for more general packed sets
{.deprecated: "Use the 'packedsets' module instead".}
import std/private/since import std/private/since
import std/packedsets import std/packedsets

View file

@ -7,17 +7,18 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
## The ``packedsets`` module implements an efficient `Ordinal`set implemented as a ## The `packedsets` module implements an efficient `Ordinal` set implemented as a
## `sparse bit set`:idx:. ## `sparse bit set`:idx:.
## ##
## Supports any Ordinal type. ## Supports any Ordinal type.
## ##
## **Note**: Currently the assignment operator ``=`` for ``PackedSet[A]`` ## **Note**: Currently the assignment operator `=` for `PackedSet[A]`
## performs some rather meaningless shallow copy. Since Nim currently does ## performs some rather meaningless shallow copy. Since Nim currently does
## not allow the assignment operator to be overloaded, use `assign proc ## not allow the assignment operator to be overloaded, use the `assign proc
## <#assign,PackedSet[A],PackedSet[A]>`_ to get a deep copy. ## <#assign,PackedSet[A],PackedSet[A]>`_ to get a deep copy.
## ##
## **See also:** ## See also
## ========
## * `sets module <sets.html>`_ for more general hash sets ## * `sets module <sets.html>`_ for more general hash sets
import std/private/since import std/private/since
@ -45,8 +46,8 @@ type
TrunkSeq = seq[PTrunk] TrunkSeq = seq[PTrunk]
## An efficient set of `Ordinal` types implemented as a sparse bit set.
PackedSet*[A: Ordinal] = object PackedSet*[A: Ordinal] = object
## An efficient set of `Ordinal` types implemented as a sparse bit set.
elems: int # only valid for small numbers elems: int # only valid for small numbers
counter, max: int counter, max: int
head: PTrunk head: PTrunk
@ -62,7 +63,7 @@ proc nextTry(h, maxHash: Hash, perturb: var Hash): Hash {.inline.} =
const PERTURB_SHIFT = 5 const PERTURB_SHIFT = 5
var perturb2 = cast[uint](perturb) shr PERTURB_SHIFT var perturb2 = cast[uint](perturb) shr PERTURB_SHIFT
perturb = cast[Hash](perturb2) perturb = cast[Hash](perturb2)
result = ((5*h) + 1 + perturb) and maxHash result = ((5 * h) + 1 + perturb) and maxHash
proc packedSetGet[A](t: PackedSet[A], key: int): PTrunk = proc packedSetGet[A](t: PackedSet[A], key: int): PTrunk =
var h = key and t.max var h = key and t.max
@ -77,9 +78,9 @@ proc intSetRawInsert[A](t: PackedSet[A], data: var TrunkSeq, desc: PTrunk) =
var h = desc.key and t.max var h = desc.key and t.max
var perturb = desc.key var perturb = desc.key
while data[h] != nil: while data[h] != nil:
assert(data[h] != desc) assert data[h] != desc
h = nextTry(h, t.max, perturb) h = nextTry(h, t.max, perturb)
assert(data[h] == nil) assert data[h] == nil
data[h] = desc data[h] = desc
proc intSetEnlarge[A](t: var PackedSet[A]) = proc intSetEnlarge[A](t: var PackedSet[A]) =
@ -103,7 +104,7 @@ proc intSetPut[A](t: var PackedSet[A], key: int): PTrunk =
h = key and t.max h = key and t.max
perturb = key perturb = key
while t.data[h] != nil: h = nextTry(h, t.max, perturb) while t.data[h] != nil: h = nextTry(h, t.max, perturb)
assert(t.data[h] == nil) assert t.data[h] == nil
new(result) new(result)
result.next = t.head result.next = t.head
result.key = key result.key = key
@ -112,7 +113,7 @@ proc intSetPut[A](t: var PackedSet[A], key: int): PTrunk =
proc bitincl[A](s: var PackedSet[A], key: int) {.inline.} = proc bitincl[A](s: var PackedSet[A], key: int) {.inline.} =
var ret: PTrunk var ret: PTrunk
var t = intSetPut(s, `shr`(key, TrunkShift)) var t = intSetPut(s, key shr TrunkShift)
var u = key and TrunkMask var u = key and TrunkMask
t.bits[u shr IntShift] = t.bits[u shr IntShift] or t.bits[u shr IntShift] = t.bits[u shr IntShift] or
(BitScalar(1) shl (u and IntMask)) (BitScalar(1) shl (u and IntMask))
@ -121,8 +122,8 @@ proc exclImpl[A](s: var PackedSet[A], key: int) =
if s.elems <= s.a.len: if s.elems <= s.a.len:
for i in 0..<s.elems: for i in 0..<s.elems:
if s.a[i] == key: if s.a[i] == key:
s.a[i] = s.a[s.elems-1] s.a[i] = s.a[s.elems - 1]
dec s.elems dec(s.elems)
return return
else: else:
var t = packedSetGet(s, key shr TrunkShift) var t = packedSetGet(s, key shr TrunkShift)
@ -161,13 +162,13 @@ iterator items*[A](s: PackedSet[A]): A {.inline.} =
r = r.next r = r.next
proc initPackedSet*[A]: PackedSet[A] = proc initPackedSet*[A]: PackedSet[A] =
## Returns an empty PackedSet[A]. ## Returns an empty `PackedSet[A]`.
## A must be Ordinal ## `A` must be `Ordinal`.
## ##
## See also: ## **See also:**
## * `toPackedSet[A] proc <#toPackedSet,openArray[A]>`_ ## * `toPackedSet proc <#toPackedSet,openArray[A]>`_
runnableExamples: runnableExamples:
var a = initPackedSet[int]() let a = initPackedSet[int]()
assert len(a) == 0 assert len(a) == 0
type Id = distinct int type Id = distinct int
@ -185,21 +186,17 @@ proc initPackedSet*[A]: PackedSet[A] =
proc contains*[A](s: PackedSet[A], key: A): bool = proc contains*[A](s: PackedSet[A], key: A): bool =
## Returns true if `key` is in `s`. ## Returns true if `key` is in `s`.
## ##
## This allows the usage of `in` operator. ## This allows the usage of the `in` operator.
runnableExamples: runnableExamples:
type ABCD = enum A, B, C, D type ABCD = enum A, B, C, D
var a = initPackedSet[int]() let a = [1, 3, 5].toPackedSet
for x in [1, 3, 5]:
a.incl(x)
assert a.contains(3) assert a.contains(3)
assert 3 in a assert 3 in a
assert(not a.contains(8)) assert not a.contains(8)
assert 8 notin a assert 8 notin a
var letters = initPackedSet[ABCD]() let letters = [A, C].toPackedSet
for x in [A, C]:
letters.incl(x)
assert A in letters assert A in letters
assert C in letters assert C in letters
assert B notin letters assert B notin letters
@ -208,7 +205,7 @@ proc contains*[A](s: PackedSet[A], key: A): bool =
for i in 0..<s.elems: for i in 0..<s.elems:
if s.a[i] == ord(key): return true if s.a[i] == ord(key): return true
else: else:
var t = packedSetGet(s, `shr`(ord(key), TrunkShift)) var t = packedSetGet(s, ord(key) shr TrunkShift)
if t != nil: if t != nil:
var u = ord(key) and TrunkMask var u = ord(key) and TrunkMask
result = (t.bits[u shr IntShift] and result = (t.bits[u shr IntShift] and
@ -221,9 +218,9 @@ proc incl*[A](s: var PackedSet[A], key: A) =
## ##
## This doesn't do anything if `key` is already in `s`. ## This doesn't do anything if `key` is already in `s`.
## ##
## See also: ## **See also:**
## * `excl proc <#excl,PackedSet[A],A>`_ for excluding an element ## * `excl proc <#excl,PackedSet[A],A>`_ for excluding an element
## * `incl proc <#incl,PackedSet[A],PackedSet[A]>`_ for including other set ## * `incl proc <#incl,PackedSet[A],PackedSet[A]>`_ for including a set
## * `containsOrIncl proc <#containsOrIncl,PackedSet[A],A>`_ ## * `containsOrIncl proc <#containsOrIncl,PackedSet[A],A>`_
runnableExamples: runnableExamples:
var a = initPackedSet[int]() var a = initPackedSet[int]()
@ -236,10 +233,10 @@ proc incl*[A](s: var PackedSet[A], key: A) =
if s.a[i] == ord(key): return if s.a[i] == ord(key): return
if s.elems < s.a.len: if s.elems < s.a.len:
s.a[s.elems] = ord(key) s.a[s.elems] = ord(key)
inc s.elems inc(s.elems)
return return
newSeq(s.data, InitIntSetSize) newSeq(s.data, InitIntSetSize)
s.max = InitIntSetSize-1 s.max = InitIntSetSize - 1
for i in 0..<s.elems: for i in 0..<s.elems:
bitincl(s, s.a[i]) bitincl(s, s.a[i])
s.elems = s.a.len + 1 s.elems = s.a.len + 1
@ -251,35 +248,29 @@ proc incl*[A](s: var PackedSet[A], other: PackedSet[A]) =
## ##
## This is the in-place version of `s + other <#+,PackedSet[A],PackedSet[A]>`_. ## This is the in-place version of `s + other <#+,PackedSet[A],PackedSet[A]>`_.
## ##
## See also: ## **See also:**
## * `excl proc <#excl,PackedSet[A],PackedSet[A]>`_ for excluding other set ## * `excl proc <#excl,PackedSet[A],PackedSet[A]>`_ for excluding a set
## * `incl proc <#incl,PackedSet[A],A>`_ for including an element ## * `incl proc <#incl,PackedSet[A],A>`_ for including an element
## * `containsOrIncl proc <#containsOrIncl,PackedSet[A],A>`_ ## * `containsOrIncl proc <#containsOrIncl,PackedSet[A],A>`_
runnableExamples: runnableExamples:
var var a = [1].toPackedSet
a = initPackedSet[int]() a.incl([5].toPackedSet)
b = initPackedSet[int]()
a.incl(1)
b.incl(5)
a.incl(b)
assert len(a) == 2 assert len(a) == 2
assert 5 in a assert 5 in a
for item in other.items: incl(s, item) for item in other.items: incl(s, item)
proc toPackedSet*[A](x: openArray[A]): PackedSet[A] {.since: (1, 3).} = proc toPackedSet*[A](x: openArray[A]): PackedSet[A] {.since: (1, 3).} =
## Creates a new PackedSet[A] that contains the elements of `x`. ## Creates a new `PackedSet[A]` that contains the elements of `x`.
## ##
## Duplicates are removed. ## Duplicates are removed.
## ##
## See also: ## **See also:**
## * `initPackedSet[A] proc <#initPackedSet>`_ ## * `initPackedSet proc <#initPackedSet>`_
runnableExamples: runnableExamples:
var let a = [5, 6, 7, 8, 8].toPackedSet
a = toPackedSet([5, 6, 7]) assert len(a) == 4
b = toPackedSet(@[1, 8, 8, 8]) assert $a == "{5, 6, 7, 8}"
assert len(a) == 3
assert len(b) == 2
result = initPackedSet[A]() result = initPackedSet[A]()
for item in x: for item in x:
@ -289,11 +280,11 @@ proc containsOrIncl*[A](s: var PackedSet[A], key: A): bool =
## Includes `key` in the set `s` and tells if `key` was already in `s`. ## Includes `key` in the set `s` and tells if `key` was already in `s`.
## ##
## The difference with regards to the `incl proc <#incl,PackedSet[A],A>`_ is ## The difference with regards to the `incl proc <#incl,PackedSet[A],A>`_ is
## that this proc returns `true` if `s` already contained `key`. The ## that this proc returns true if `s` already contained `key`. The
## proc will return `false` if `key` was added as a new value to `s` during ## proc will return false if `key` was added as a new value to `s` during
## this call. ## this call.
## ##
## See also: ## **See also:**
## * `incl proc <#incl,PackedSet[A],A>`_ for including an element ## * `incl proc <#incl,PackedSet[A],A>`_ for including an element
## * `missingOrExcl proc <#missingOrExcl,PackedSet[A],A>`_ ## * `missingOrExcl proc <#missingOrExcl,PackedSet[A],A>`_
runnableExamples: runnableExamples:
@ -309,7 +300,7 @@ proc containsOrIncl*[A](s: var PackedSet[A], key: A): bool =
incl(s, key) incl(s, key)
result = false result = false
else: else:
var t = packedSetGet(s, `shr`(ord(key), TrunkShift)) var t = packedSetGet(s, ord(key) shr TrunkShift)
if t != nil: if t != nil:
var u = ord(key) and TrunkMask var u = ord(key) and TrunkMask
result = (t.bits[u shr IntShift] and BitScalar(1) shl (u and IntMask)) != 0 result = (t.bits[u shr IntShift] and BitScalar(1) shl (u and IntMask)) != 0
@ -325,17 +316,17 @@ proc excl*[A](s: var PackedSet[A], key: A) =
## ##
## This doesn't do anything if `key` is not found in `s`. ## This doesn't do anything if `key` is not found in `s`.
## ##
## See also: ## **See also:**
## * `incl proc <#incl,PackedSet[A],A>`_ for including an element ## * `incl proc <#incl,PackedSet[A],A>`_ for including an element
## * `excl proc <#excl,PackedSet[A],PackedSet[A]>`_ for excluding other set ## * `excl proc <#excl,PackedSet[A],PackedSet[A]>`_ for excluding a set
## * `missingOrExcl proc <#missingOrExcl,PackedSet[A],A>`_ ## * `missingOrExcl proc <#missingOrExcl,PackedSet[A],A>`_
runnableExamples: runnableExamples:
var a = initPackedSet[int]() var a = [3].toPackedSet
a.incl(3)
a.excl(3) a.excl(3)
a.excl(3) a.excl(3)
a.excl(99) a.excl(99)
assert len(a) == 0 assert len(a) == 0
exclImpl[A](s, cast[int](key)) exclImpl[A](s, cast[int](key))
proc excl*[A](s: var PackedSet[A], other: PackedSet[A]) = proc excl*[A](s: var PackedSet[A], other: PackedSet[A]) =
@ -343,18 +334,13 @@ proc excl*[A](s: var PackedSet[A], other: PackedSet[A]) =
## ##
## This is the in-place version of `s - other <#-,PackedSet[A],PackedSet[A]>`_. ## This is the in-place version of `s - other <#-,PackedSet[A],PackedSet[A]>`_.
## ##
## See also: ## **See also:**
## * `incl proc <#incl,PackedSet[A],PackedSet[A]>`_ for including other set ## * `incl proc <#incl,PackedSet[A],PackedSet[A]>`_ for including a set
## * `excl proc <#excl,PackedSet[A],A>`_ for excluding an element ## * `excl proc <#excl,PackedSet[A],A>`_ for excluding an element
## * `missingOrExcl proc <#missingOrExcl,PackedSet[A],A>`_ ## * `missingOrExcl proc <#missingOrExcl,PackedSet[A],A>`_
runnableExamples: runnableExamples:
var var a = [1, 5].toPackedSet
a = initPackedSet[int]() a.excl([5].toPackedSet)
b = initPackedSet[int]()
a.incl(1)
a.incl(5)
b.incl(5)
a.excl(b)
assert len(a) == 1 assert len(a) == 1
assert 5 notin a assert 5 notin a
@ -363,6 +349,10 @@ proc excl*[A](s: var PackedSet[A], other: PackedSet[A]) =
proc len*[A](s: PackedSet[A]): int {.inline.} = proc len*[A](s: PackedSet[A]): int {.inline.} =
## Returns the number of elements in `s`. ## Returns the number of elements in `s`.
runnableExamples:
let a = [1, 3, 5].toPackedSet
assert len(a) == 3
if s.elems < s.a.len: if s.elems < s.a.len:
result = s.elems result = s.elems
else: else:
@ -372,20 +362,19 @@ proc len*[A](s: PackedSet[A]): int {.inline.} =
inc(result) inc(result)
proc missingOrExcl*[A](s: var PackedSet[A], key: A): bool = proc missingOrExcl*[A](s: var PackedSet[A], key: A): bool =
## Excludes `key` in the set `s` and tells if `key` was already missing from `s`. ## Excludes `key` from the set `s` and tells if `key` was already missing from `s`.
## ##
## The difference with regards to the `excl proc <#excl,PackedSet[A],A>`_ is ## The difference with regards to the `excl proc <#excl,PackedSet[A],A>`_ is
## that this proc returns `true` if `key` was missing from `s`. ## that this proc returns true if `key` was missing from `s`.
## The proc will return `false` if `key` was in `s` and it was removed ## The proc will return false if `key` was in `s` and it was removed
## during this call. ## during this call.
## ##
## See also: ## **See also:**
## * `excl proc <#excl,PackedSet[A],A>`_ for excluding an element ## * `excl proc <#excl,PackedSet[A],A>`_ for excluding an element
## * `excl proc <#excl,PackedSet[A],PackedSet[A]>`_ for excluding other set ## * `excl proc <#excl,PackedSet[A],PackedSet[A]>`_ for excluding a set
## * `containsOrIncl proc <#containsOrIncl,PackedSet[A],A>`_ ## * `containsOrIncl proc <#containsOrIncl,PackedSet[A],A>`_
runnableExamples: runnableExamples:
var a = initPackedSet[int]() var a = [5].toPackedSet
a.incl(5)
assert a.missingOrExcl(5) == false assert a.missingOrExcl(5) == false
assert a.missingOrExcl(5) == true assert a.missingOrExcl(5) == true
@ -394,17 +383,15 @@ proc missingOrExcl*[A](s: var PackedSet[A], key: A): bool =
result = count == s.len result = count == s.len
proc clear*[A](result: var PackedSet[A]) = proc clear*[A](result: var PackedSet[A]) =
## Clears the PackedSet[A] back to an empty state. ## Clears the `PackedSet[A]` back to an empty state.
runnableExamples: runnableExamples:
var a = initPackedSet[int]() var a = [5, 7].toPackedSet
a.incl(5)
a.incl(7)
clear(a) clear(a)
assert len(a) == 0 assert len(a) == 0
# setLen(result.data, InitIntSetSize) # setLen(result.data, InitIntSetSize)
# for i in 0..InitIntSetSize-1: result.data[i] = nil # for i in 0..InitIntSetSize - 1: result.data[i] = nil
# result.max = InitIntSetSize-1 # result.max = InitIntSetSize - 1
when defined(nimNoNilSeqs): when defined(nimNoNilSeqs):
result.data = @[] result.data = @[]
else: else:
@ -414,11 +401,21 @@ proc clear*[A](result: var PackedSet[A]) =
result.head = nil result.head = nil
result.elems = 0 result.elems = 0
proc isNil*[A](x: PackedSet[A]): bool {.inline.} = x.head.isNil and x.elems == 0 proc isNil*[A](x: PackedSet[A]): bool {.inline.} =
## Returns true if `x` is empty, false otherwise.
runnableExamples:
var a = initPackedSet[int]()
assert a.isNil
a.incl(2)
assert not a.isNil
a.excl(2)
assert a.isNil
x.head.isNil and x.elems == 0
proc assign*[A](dest: var PackedSet[A], src: PackedSet[A]) = proc assign*[A](dest: var PackedSet[A], src: PackedSet[A]) =
## Copies `src` to `dest`. ## Copies `src` to `dest`.
## `dest` does not need to be initialized by `initPackedSet[A] proc <#initPackedSet>`_. ## `dest` does not need to be initialized by the `initPackedSet proc <#initPackedSet>`_.
runnableExamples: runnableExamples:
var var
a = initPackedSet[int]() a = initPackedSet[int]()
@ -449,7 +446,7 @@ proc assign*[A](dest: var PackedSet[A], src: PackedSet[A]) =
var h = it.key and dest.max var h = it.key and dest.max
var perturb = it.key var perturb = it.key
while dest.data[h] != nil: h = nextTry(h, dest.max, perturb) while dest.data[h] != nil: h = nextTry(h, dest.max, perturb)
assert(dest.data[h] == nil) assert dest.data[h] == nil
var n: PTrunk var n: PTrunk
new(n) new(n)
n.next = dest.head n.next = dest.head
@ -464,13 +461,12 @@ proc union*[A](s1, s2: PackedSet[A]): PackedSet[A] =
## ##
## The same as `s1 + s2 <#+,PackedSet[A],PackedSet[A]>`_. ## The same as `s1 + s2 <#+,PackedSet[A],PackedSet[A]>`_.
runnableExamples: runnableExamples:
var let
a = initPackedSet[int]() a = [1, 2, 3].toPackedSet
b = initPackedSet[int]() b = [3, 4, 5].toPackedSet
a.incl(1); a.incl(2); a.incl(3) c = union(a, b)
b.incl(3); b.incl(4); b.incl(5) assert c.len == 5
assert union(a, b).len == 5 assert c == [1, 2, 3, 4, 5].toPackedSet
## {1, 2, 3, 4, 5}
result.assign(s1) result.assign(s1)
incl(result, s2) incl(result, s2)
@ -480,13 +476,12 @@ proc intersection*[A](s1, s2: PackedSet[A]): PackedSet[A] =
## ##
## The same as `s1 * s2 <#*,PackedSet[A],PackedSet[A]>`_. ## The same as `s1 * s2 <#*,PackedSet[A],PackedSet[A]>`_.
runnableExamples: runnableExamples:
var let
a = initPackedSet[int]() a = [1, 2, 3].toPackedSet
b = initPackedSet[int]() b = [3, 4, 5].toPackedSet
a.incl(1); a.incl(2); a.incl(3) c = intersection(a, b)
b.incl(3); b.incl(4); b.incl(5) assert c.len == 1
assert intersection(a, b).len == 1 assert c == [3].toPackedSet
## {3}
result = initPackedSet[A]() result = initPackedSet[A]()
for item in s1.items: for item in s1.items:
@ -498,13 +493,12 @@ proc difference*[A](s1, s2: PackedSet[A]): PackedSet[A] =
## ##
## The same as `s1 - s2 <#-,PackedSet[A],PackedSet[A]>`_. ## The same as `s1 - s2 <#-,PackedSet[A],PackedSet[A]>`_.
runnableExamples: runnableExamples:
var let
a = initPackedSet[int]() a = [1, 2, 3].toPackedSet
b = initPackedSet[int]() b = [3, 4, 5].toPackedSet
a.incl(1); a.incl(2); a.incl(3) c = difference(a, b)
b.incl(3); b.incl(4); b.incl(5) assert c.len == 2
assert difference(a, b).len == 2 assert c == [1, 2].toPackedSet
## {1, 2}
result = initPackedSet[A]() result = initPackedSet[A]()
for item in s1.items: for item in s1.items:
@ -514,17 +508,17 @@ proc difference*[A](s1, s2: PackedSet[A]): PackedSet[A] =
proc symmetricDifference*[A](s1, s2: PackedSet[A]): PackedSet[A] = proc symmetricDifference*[A](s1, s2: PackedSet[A]): PackedSet[A] =
## Returns the symmetric difference of the sets `s1` and `s2`. ## Returns the symmetric difference of the sets `s1` and `s2`.
runnableExamples: runnableExamples:
var let
a = initPackedSet[int]() a = [1, 2, 3].toPackedSet
b = initPackedSet[int]() b = [3, 4, 5].toPackedSet
a.incl(1); a.incl(2); a.incl(3) c = symmetricDifference(a, b)
b.incl(3); b.incl(4); b.incl(5) assert c.len == 4
assert symmetricDifference(a, b).len == 4 assert c == [1, 2, 4, 5].toPackedSet
## {1, 2, 4, 5}
result.assign(s1) result.assign(s1)
for item in s2.items: for item in s2.items:
if containsOrIncl(result, item): excl(result, item) if containsOrIncl(result, item):
excl(result, item)
proc `+`*[A](s1, s2: PackedSet[A]): PackedSet[A] {.inline.} = proc `+`*[A](s1, s2: PackedSet[A]): PackedSet[A] {.inline.} =
## Alias for `union(s1, s2) <#union,PackedSet[A],PackedSet[A]>`_. ## Alias for `union(s1, s2) <#union,PackedSet[A],PackedSet[A]>`_.
@ -541,14 +535,12 @@ proc `-`*[A](s1, s2: PackedSet[A]): PackedSet[A] {.inline.} =
proc disjoint*[A](s1, s2: PackedSet[A]): bool = proc disjoint*[A](s1, s2: PackedSet[A]): bool =
## Returns true if the sets `s1` and `s2` have no items in common. ## Returns true if the sets `s1` and `s2` have no items in common.
runnableExamples: runnableExamples:
var let
a = initPackedSet[int]() a = [1, 2].toPackedSet
b = initPackedSet[int]() b = [2, 3].toPackedSet
a.incl(1); a.incl(2) c = [3, 4].toPackedSet
b.incl(2); b.incl(3)
assert disjoint(a, b) == false assert disjoint(a, b) == false
b.excl(2) assert disjoint(a, c) == true
assert disjoint(a, b) == true
for item in s1.items: for item in s1.items:
if contains(s2, item): if contains(s2, item):
@ -557,24 +549,24 @@ proc disjoint*[A](s1, s2: PackedSet[A]): bool =
proc card*[A](s: PackedSet[A]): int {.inline.} = proc card*[A](s: PackedSet[A]): int {.inline.} =
## Alias for `len() <#len,PackedSet[A]>`_. ## Alias for `len() <#len,PackedSet[A]>`_.
##
## Card stands for the [cardinality](http://en.wikipedia.org/wiki/Cardinality)
## of a set.
result = s.len() result = s.len()
proc `<=`*[A](s1, s2: PackedSet[A]): bool = proc `<=`*[A](s1, s2: PackedSet[A]): bool =
## Returns true if `s1` is subset of `s2`. ## Returns true if `s1` is a subset of `s2`.
## ##
## A subset `s1` has all of its elements in `s2`, and `s2` doesn't necessarily ## A subset `s1` has all of its elements in `s2`, but `s2` doesn't necessarily
## have more elements than `s1`. That is, `s1` can be equal to `s2`. ## have more elements than `s1`. That is, `s1` can be equal to `s2`.
runnableExamples: runnableExamples:
var let
a = initPackedSet[int]() a = [1].toPackedSet
b = initPackedSet[int]() b = [1, 2].toPackedSet
a.incl(1) c = [1, 3].toPackedSet
b.incl(1); b.incl(2)
assert a <= b assert a <= b
a.incl(2) assert b <= b
assert a <= b assert not (c <= b)
a.incl(3)
assert(not (a <= b))
for item in s1.items: for item in s1.items:
if not s2.contains(item): if not s2.contains(item):
@ -582,27 +574,33 @@ proc `<=`*[A](s1, s2: PackedSet[A]): bool =
return true return true
proc `<`*[A](s1, s2: PackedSet[A]): bool = proc `<`*[A](s1, s2: PackedSet[A]): bool =
## Returns true if `s1` is proper subset of `s2`. ## Returns true if `s1` is a proper subset of `s2`.
## ##
## A strict or proper subset `s1` has all of its elements in `s2`, but `s2` has ## A strict or proper subset `s1` has all of its elements in `s2`, but `s2` has
## more elements than `s1`. ## more elements than `s1`.
runnableExamples: runnableExamples:
var let
a = initPackedSet[int]() a = [1].toPackedSet
b = initPackedSet[int]() b = [1, 2].toPackedSet
a.incl(1) c = [1, 3].toPackedSet
b.incl(1); b.incl(2)
assert a < b assert a < b
a.incl(2) assert not (b < b)
assert(not (a < b)) assert not (c < b)
return s1 <= s2 and not (s2 <= s1) return s1 <= s2 and not (s2 <= s1)
proc `==`*[A](s1, s2: PackedSet[A]): bool = proc `==`*[A](s1, s2: PackedSet[A]): bool =
## Returns true if both `s1` and `s2` have the same elements and set size. ## Returns true if both `s1` and `s2` have the same elements and set size.
runnableExamples:
assert [1, 2].toPackedSet == [2, 1].toPackedSet
assert [1, 2].toPackedSet == [2, 1, 2].toPackedSet
return s1 <= s2 and s2 <= s1 return s1 <= s2 and s2 <= s1
proc `$`*[A](s: PackedSet[A]): string = proc `$`*[A](s: PackedSet[A]): string =
## The `$` operator for int sets. ## Converts `s` to a string.
## runnableExamples:
## Converts the set `s` to a string, mostly for logging and printing purposes. let a = [1, 2, 3].toPackedSet
assert $a == "{1, 2, 3}"
dollarImpl() dollarImpl()