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
parent 8939de15d7
commit 44ceefa9fe
3 changed files with 154 additions and 151 deletions

View File

@@ -32,15 +32,15 @@ Automatic imports
* `system <system.html>`_
Basic procs and operators that every program needs. It also provides IO
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.
* `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``.
* `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``.
@@ -107,6 +107,7 @@ Collections
* `intsets <intsets.html>`_
Efficient implementation of a set of ints as a sparse bit set.
**Deprecated:** Use the packedsets module instead.
* `lists <lists.html>`_
Nim linked list support. Contains singly and doubly linked lists and
@@ -115,6 +116,9 @@ Collections
* `options <options.html>`_
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>`_
Nim hash and bit set support.
@@ -154,7 +158,7 @@ String handling
* `ropes <ropes.html>`_
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).
* `strformat <strformat.html>`_
@@ -231,8 +235,8 @@ Generic Operating System Services
* `streams <streams.html>`_
This module provides a stream interface and two implementations thereof:
the `FileStream` and the `StringStream` which implement the stream
interface for Nim file objects (`File`) and strings. Other modules
the `FileStream` and the `StringStream` which implement the stream
interface for Nim file objects (`File`) and strings. Other modules
may provide other implementations for this standard stream interface.
* `terminal <terminal.html>`_
@@ -373,12 +377,12 @@ Docutils
--------
* `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.
The interface supports one language nested in another.
* `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.
* `packages/docutils/rstast <rstast.html>`_
@@ -403,8 +407,8 @@ Generators
----------
* `htmlgen <htmlgen.html>`_
This module implements a simple XML and HTML code
generator. Each commonly used HTML tag has a corresponding macro
This module implements a simple XML and HTML code
generator. Each commonly used HTML tag has a corresponding macro
that generates a string with its HTML representation.
@@ -489,7 +493,7 @@ Regular expressions
-------------------
* `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.

View File

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

View File

@@ -7,17 +7,18 @@
# 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:.
##
## 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
## 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.
##
## **See also:**
## See also
## ========
## * `sets module <sets.html>`_ for more general hash sets
import std/private/since
@@ -45,8 +46,8 @@ type
TrunkSeq = seq[PTrunk]
## An efficient set of `Ordinal` types implemented as a sparse bit set.
PackedSet*[A: Ordinal] = object
## An efficient set of `Ordinal` types implemented as a sparse bit set.
elems: int # only valid for small numbers
counter, max: int
head: PTrunk
@@ -62,7 +63,7 @@ proc nextTry(h, maxHash: Hash, perturb: var Hash): Hash {.inline.} =
const PERTURB_SHIFT = 5
var perturb2 = cast[uint](perturb) shr PERTURB_SHIFT
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 =
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 perturb = desc.key
while data[h] != nil:
assert(data[h] != desc)
assert data[h] != desc
h = nextTry(h, t.max, perturb)
assert(data[h] == nil)
assert data[h] == nil
data[h] = desc
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
perturb = key
while t.data[h] != nil: h = nextTry(h, t.max, perturb)
assert(t.data[h] == nil)
assert t.data[h] == nil
new(result)
result.next = t.head
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.} =
var ret: PTrunk
var t = intSetPut(s, `shr`(key, TrunkShift))
var t = intSetPut(s, key shr TrunkShift)
var u = key and TrunkMask
t.bits[u shr IntShift] = t.bits[u shr IntShift] or
(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:
for i in 0..<s.elems:
if s.a[i] == key:
s.a[i] = s.a[s.elems-1]
dec s.elems
s.a[i] = s.a[s.elems - 1]
dec(s.elems)
return
else:
var t = packedSetGet(s, key shr TrunkShift)
@@ -161,13 +162,13 @@ iterator items*[A](s: PackedSet[A]): A {.inline.} =
r = r.next
proc initPackedSet*[A]: PackedSet[A] =
## Returns an empty PackedSet[A].
## A must be Ordinal
## Returns an empty `PackedSet[A]`.
## `A` must be `Ordinal`.
##
## See also:
## * `toPackedSet[A] proc <#toPackedSet,openArray[A]>`_
## **See also:**
## * `toPackedSet proc <#toPackedSet,openArray[A]>`_
runnableExamples:
var a = initPackedSet[int]()
let a = initPackedSet[int]()
assert len(a) == 0
type Id = distinct int
@@ -185,21 +186,17 @@ proc initPackedSet*[A]: PackedSet[A] =
proc contains*[A](s: PackedSet[A], key: A): bool =
## Returns true if `key` is in `s`.
##
## This allows the usage of `in` operator.
## This allows the usage of the `in` operator.
runnableExamples:
type ABCD = enum A, B, C, D
var a = initPackedSet[int]()
for x in [1, 3, 5]:
a.incl(x)
let a = [1, 3, 5].toPackedSet
assert a.contains(3)
assert 3 in a
assert(not a.contains(8))
assert not a.contains(8)
assert 8 notin a
var letters = initPackedSet[ABCD]()
for x in [A, C]:
letters.incl(x)
let letters = [A, C].toPackedSet
assert A in letters
assert C in letters
assert B notin letters
@@ -208,7 +205,7 @@ proc contains*[A](s: PackedSet[A], key: A): bool =
for i in 0..<s.elems:
if s.a[i] == ord(key): return true
else:
var t = packedSetGet(s, `shr`(ord(key), TrunkShift))
var t = packedSetGet(s, ord(key) shr TrunkShift)
if t != nil:
var u = ord(key) and TrunkMask
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`.
##
## See also:
## **See also:**
## * `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>`_
runnableExamples:
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.elems < s.a.len:
s.a[s.elems] = ord(key)
inc s.elems
inc(s.elems)
return
newSeq(s.data, InitIntSetSize)
s.max = InitIntSetSize-1
s.max = InitIntSetSize - 1
for i in 0..<s.elems:
bitincl(s, s.a[i])
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]>`_.
##
## See also:
## * `excl proc <#excl,PackedSet[A],PackedSet[A]>`_ for excluding other set
## **See also:**
## * `excl proc <#excl,PackedSet[A],PackedSet[A]>`_ for excluding a set
## * `incl proc <#incl,PackedSet[A],A>`_ for including an element
## * `containsOrIncl proc <#containsOrIncl,PackedSet[A],A>`_
runnableExamples:
var
a = initPackedSet[int]()
b = initPackedSet[int]()
a.incl(1)
b.incl(5)
a.incl(b)
var a = [1].toPackedSet
a.incl([5].toPackedSet)
assert len(a) == 2
assert 5 in a
for item in other.items: incl(s, item)
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.
##
## See also:
## * `initPackedSet[A] proc <#initPackedSet>`_
## **See also:**
## * `initPackedSet proc <#initPackedSet>`_
runnableExamples:
var
a = toPackedSet([5, 6, 7])
b = toPackedSet(@[1, 8, 8, 8])
assert len(a) == 3
assert len(b) == 2
let a = [5, 6, 7, 8, 8].toPackedSet
assert len(a) == 4
assert $a == "{5, 6, 7, 8}"
result = initPackedSet[A]()
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`.
##
## The difference with regards to the `incl proc <#incl,PackedSet[A],A>`_ is
## 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
## 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
## this call.
##
## See also:
## **See also:**
## * `incl proc <#incl,PackedSet[A],A>`_ for including an element
## * `missingOrExcl proc <#missingOrExcl,PackedSet[A],A>`_
runnableExamples:
@@ -309,7 +300,7 @@ proc containsOrIncl*[A](s: var PackedSet[A], key: A): bool =
incl(s, key)
result = false
else:
var t = packedSetGet(s, `shr`(ord(key), TrunkShift))
var t = packedSetGet(s, ord(key) shr TrunkShift)
if t != nil:
var u = ord(key) and TrunkMask
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`.
##
## See also:
## **See also:**
## * `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>`_
runnableExamples:
var a = initPackedSet[int]()
a.incl(3)
var a = [3].toPackedSet
a.excl(3)
a.excl(3)
a.excl(99)
assert len(a) == 0
exclImpl[A](s, cast[int](key))
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]>`_.
##
## See also:
## * `incl proc <#incl,PackedSet[A],PackedSet[A]>`_ for including other set
## **See also:**
## * `incl proc <#incl,PackedSet[A],PackedSet[A]>`_ for including a set
## * `excl proc <#excl,PackedSet[A],A>`_ for excluding an element
## * `missingOrExcl proc <#missingOrExcl,PackedSet[A],A>`_
runnableExamples:
var
a = initPackedSet[int]()
b = initPackedSet[int]()
a.incl(1)
a.incl(5)
b.incl(5)
a.excl(b)
var a = [1, 5].toPackedSet
a.excl([5].toPackedSet)
assert len(a) == 1
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.} =
## Returns the number of elements in `s`.
runnableExamples:
let a = [1, 3, 5].toPackedSet
assert len(a) == 3
if s.elems < s.a.len:
result = s.elems
else:
@@ -372,20 +362,19 @@ proc len*[A](s: PackedSet[A]): int {.inline.} =
inc(result)
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
## 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
## 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
## during this call.
##
## See also:
## **See also:**
## * `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>`_
runnableExamples:
var a = initPackedSet[int]()
a.incl(5)
var a = [5].toPackedSet
assert a.missingOrExcl(5) == false
assert a.missingOrExcl(5) == true
@@ -394,17 +383,15 @@ proc missingOrExcl*[A](s: var PackedSet[A], key: A): bool =
result = count == s.len
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:
var a = initPackedSet[int]()
a.incl(5)
a.incl(7)
var a = [5, 7].toPackedSet
clear(a)
assert len(a) == 0
# setLen(result.data, InitIntSetSize)
# for i in 0..InitIntSetSize-1: result.data[i] = nil
# result.max = InitIntSetSize-1
# for i in 0..InitIntSetSize - 1: result.data[i] = nil
# result.max = InitIntSetSize - 1
when defined(nimNoNilSeqs):
result.data = @[]
else:
@@ -414,11 +401,21 @@ proc clear*[A](result: var PackedSet[A]) =
result.head = nil
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]) =
## 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:
var
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 perturb = it.key
while dest.data[h] != nil: h = nextTry(h, dest.max, perturb)
assert(dest.data[h] == nil)
assert dest.data[h] == nil
var n: PTrunk
new(n)
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]>`_.
runnableExamples:
var
a = initPackedSet[int]()
b = initPackedSet[int]()
a.incl(1); a.incl(2); a.incl(3)
b.incl(3); b.incl(4); b.incl(5)
assert union(a, b).len == 5
## {1, 2, 3, 4, 5}
let
a = [1, 2, 3].toPackedSet
b = [3, 4, 5].toPackedSet
c = union(a, b)
assert c.len == 5
assert c == [1, 2, 3, 4, 5].toPackedSet
result.assign(s1)
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]>`_.
runnableExamples:
var
a = initPackedSet[int]()
b = initPackedSet[int]()
a.incl(1); a.incl(2); a.incl(3)
b.incl(3); b.incl(4); b.incl(5)
assert intersection(a, b).len == 1
## {3}
let
a = [1, 2, 3].toPackedSet
b = [3, 4, 5].toPackedSet
c = intersection(a, b)
assert c.len == 1
assert c == [3].toPackedSet
result = initPackedSet[A]()
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]>`_.
runnableExamples:
var
a = initPackedSet[int]()
b = initPackedSet[int]()
a.incl(1); a.incl(2); a.incl(3)
b.incl(3); b.incl(4); b.incl(5)
assert difference(a, b).len == 2
## {1, 2}
let
a = [1, 2, 3].toPackedSet
b = [3, 4, 5].toPackedSet
c = difference(a, b)
assert c.len == 2
assert c == [1, 2].toPackedSet
result = initPackedSet[A]()
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] =
## Returns the symmetric difference of the sets `s1` and `s2`.
runnableExamples:
var
a = initPackedSet[int]()
b = initPackedSet[int]()
a.incl(1); a.incl(2); a.incl(3)
b.incl(3); b.incl(4); b.incl(5)
assert symmetricDifference(a, b).len == 4
## {1, 2, 4, 5}
let
a = [1, 2, 3].toPackedSet
b = [3, 4, 5].toPackedSet
c = symmetricDifference(a, b)
assert c.len == 4
assert c == [1, 2, 4, 5].toPackedSet
result.assign(s1)
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.} =
## 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 =
## Returns true if the sets `s1` and `s2` have no items in common.
runnableExamples:
var
a = initPackedSet[int]()
b = initPackedSet[int]()
a.incl(1); a.incl(2)
b.incl(2); b.incl(3)
let
a = [1, 2].toPackedSet
b = [2, 3].toPackedSet
c = [3, 4].toPackedSet
assert disjoint(a, b) == false
b.excl(2)
assert disjoint(a, b) == true
assert disjoint(a, c) == true
for item in s1.items:
if contains(s2, item):
@@ -557,24 +549,24 @@ proc disjoint*[A](s1, s2: PackedSet[A]): bool =
proc card*[A](s: PackedSet[A]): int {.inline.} =
## Alias for `len() <#len,PackedSet[A]>`_.
##
## Card stands for the [cardinality](http://en.wikipedia.org/wiki/Cardinality)
## of a set.
result = s.len()
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`.
runnableExamples:
var
a = initPackedSet[int]()
b = initPackedSet[int]()
a.incl(1)
b.incl(1); b.incl(2)
let
a = [1].toPackedSet
b = [1, 2].toPackedSet
c = [1, 3].toPackedSet
assert a <= b
a.incl(2)
assert a <= b
a.incl(3)
assert(not (a <= b))
assert b <= b
assert not (c <= b)
for item in s1.items:
if not s2.contains(item):
@@ -582,27 +574,33 @@ proc `<=`*[A](s1, s2: PackedSet[A]): bool =
return true
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
## more elements than `s1`.
runnableExamples:
var
a = initPackedSet[int]()
b = initPackedSet[int]()
a.incl(1)
b.incl(1); b.incl(2)
let
a = [1].toPackedSet
b = [1, 2].toPackedSet
c = [1, 3].toPackedSet
assert a < b
a.incl(2)
assert(not (a < b))
assert not (b < b)
assert not (c < b)
return s1 <= s2 and not (s2 <= s1)
proc `==`*[A](s1, s2: PackedSet[A]): bool =
## 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
proc `$`*[A](s: PackedSet[A]): string =
## The `$` operator for int sets.
##
## Converts the set `s` to a string, mostly for logging and printing purposes.
## Converts `s` to a string.
runnableExamples:
let a = [1, 2, 3].toPackedSet
assert $a == "{1, 2, 3}"
dollarImpl()