diff options
author | Jason Beetham <beefers331@gmail.com> | 2021-02-18 18:33:28 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-18 17:33:28 -0800 |
commit | 35ded020748641379f68adf68c23d1f0aa167c2a (patch) | |
tree | a21af43dd37152fcb57ec33eb7e720af4c0d997c | |
parent | 148e5ba2a5e51f19c51e2c11150e6986c04990ba (diff) | |
download | Nim-35ded020748641379f68adf68c23d1f0aa167c2a.tar.gz |
Add setutils.complement, setutils.fullSet (#17066)
-rw-r--r-- | changelog.md | 5 | ||||
-rw-r--r-- | lib/std/setutils.nim | 25 | ||||
-rw-r--r-- | tests/stdlib/tsetutils.nim | 34 |
3 files changed, 55 insertions, 9 deletions
diff --git a/changelog.md b/changelog.md index 059f8d986..d016d2604 100644 --- a/changelog.md +++ b/changelog.md @@ -75,8 +75,11 @@ - `strscans.scanf` now supports parsing single characters. - `strscans.scanTuple` added which uses `strscans.scanf` internally, returning a tuple which can be unpacked for easier usage of `scanf`. -- Added `setutils.toSet` that can take any iterable and convert it to a built-in set, +- Added `setutils.toSet` that can take any iterable and convert it to a built-in `set`, if the iterable yields a built-in settable type. +- Added `setutils.fullSet` which returns a full built-in `set` for a valid type. +- Added `setutils.complement` which returns the complement of a built-in `set`. + - Added `math.isNaN`. diff --git a/lib/std/setutils.nim b/lib/std/setutils.nim index 215c7a76a..74f0dc819 100644 --- a/lib/std/setutils.nim +++ b/lib/std/setutils.nim @@ -14,7 +14,7 @@ ## * `std/packedsets <packedsets.html>`_ ## * `std/sets <sets.html>`_ -import std/typetraits +import std/[typetraits, macros] #[ type SetElement* = char|byte|bool|int16|uint16|enum|uint8|int8 @@ -35,3 +35,26 @@ template toSet*(iter: untyped): untyped = for x in iter: incl(result, x) result + +macro enmRange(enm: typed): untyped = result = newNimNode(nnkCurly).add(enm.getType[1][1..^1]) + +proc fullSet*(T: typedesc): auto {.inline.} = + ## Returns a full set of all valid elements. + runnableExamples: + assert {true, false} == fullSet(bool) + when T is Ordinal: + {T.low..T.high} + else: # Hole filled enum + enmRange(T) + +proc complement*[T](s: set[T]): set[T] {.inline.} = + ## Returns the complement of the set. + ## Can also be thought of as inverting the set. + runnableExamples: + type Colors = enum + red, green = 3, blue + assert complement({red, blue}) == {green} + assert complement({red, green, blue}).card == 0 + assert complement({range[0..10](0), 1, 2, 3}) == {range[0..10](4), 5, 6, 7, 8, 9, 10} + assert complement({'0'..'9'}) == {0.char..255.char} - {'0'..'9'} + fullSet(T) - s diff --git a/tests/stdlib/tsetutils.nim b/tests/stdlib/tsetutils.nim index d99807f92..faf427210 100644 --- a/tests/stdlib/tsetutils.nim +++ b/tests/stdlib/tsetutils.nim @@ -1,14 +1,34 @@ discard """ targets: "c js" + disabled: "bsd" # pending #17093 """ import std/setutils - +type + Colors = enum + red, green = 5, blue = 10 + Bar = enum + bar0 = -1, bar1, bar2 template main = - doAssert "abcbb".toSet == {'a', 'b', 'c'} - doAssert toSet([10u8, 12, 13]) == {10u8, 12, 13} - doAssert toSet(0u16..30) == {0u16..30} - type A = distinct char - doAssert [A('x')].toSet == {A('x')} - + block: # toSet + doAssert "abcbb".toSet == {'a', 'b', 'c'} + doAssert toSet([10u8, 12, 13]) == {10u8, 12, 13} + doAssert toSet(0u16..30) == {0u16..30} + type A = distinct char + doAssert [A('x')].toSet == {A('x')} + + block: # fullSet + doAssert fullSet(Colors) == {red, green, blue} + doAssert fullSet(char) == {0.chr..255.chr} + doAssert fullSet(Bar) == {bar0, bar1, bar2} + doAssert fullSet(bool) == {true, false} + + block: # complement + doAssert {red, blue}.complement == {green} + doAssert (complement {red, green, blue}).card == 0 + doAssert (complement {false}) == {true} + doAssert {bar0}.complement == {bar1, bar2} + doAssert {range[0..10](0), 1, 2, 3}.complement == {range[0..10](4), 5, 6, 7, 8, 9, 10} + doAssert {'0'..'9'}.complement == {0.char..255.char} - {'0'..'9'} + main() static: main() \ No newline at end of file |