diff --git a/changelog.md b/changelog.md index 8caee8affc750..17844e09a165a 100644 --- a/changelog.md +++ b/changelog.md @@ -41,8 +41,10 @@ - Added `randState` template that exposes the default random number generator. Useful for library authors. -- Added std/enumutils module containing `genEnumCaseStmt` macro that generates - case statement to parse string to enum. +- Added `std/enumutils` module. Added `genEnumCaseStmt` macro that generates case statement to parse string to enum. + Added `items` for enums with holes. + +- Added `typetraits.SomeEnumWithHoles` for enums with holes. - Removed deprecated `iup` module from stdlib, it has already moved to [nimble](https://github.com/nim-lang/iup). diff --git a/doc/lib.rst b/doc/lib.rst index 11b479902ceec..47ede70ee8c7e 100644 --- a/doc/lib.rst +++ b/doc/lib.rst @@ -85,6 +85,9 @@ Algorithms * `algorithm `_ This module implements some common generic algorithms like sort or binary search. +* `std/enumutils `_ + This module adds functionality for the built-in ``enum`` type. + * `sequtils `_ This module implements operations for the built-in ``seq`` type which were inspired by functional programming languages. diff --git a/lib/pure/typetraits.nim b/lib/pure/typetraits.nim index 7af78bf31f887..69c0329ef1a5b 100644 --- a/lib/pure/typetraits.nim +++ b/lib/pure/typetraits.nim @@ -15,6 +15,17 @@ import std/private/since export system.`$` # for backward compatibility +type SomeEnumWithHoles* = (not Ordinal) and enum ## Enum with holes. + +runnableExamples: + type A = enum a0 = 2, a1 = 4, a2 + type B = enum b0 = 2, b1, b2 + assert A is SomeEnumWithHoles + assert B isnot SomeEnumWithHoles + assert int isnot SomeEnumWithHoles + type C[T] = enum h0 = 2, h1 = 4 + assert C[float] is SomeEnumWithHoles + proc name*(t: typedesc): string {.magic: "TypeTrait".} = ## Returns the name of the given type. ## diff --git a/lib/std/enumutils.nim b/lib/std/enumutils.nim index 704e42de5227e..56a6d82a7e7d5 100644 --- a/lib/std/enumutils.nim +++ b/lib/std/enumutils.nim @@ -7,7 +7,9 @@ # distribution, for details about the copyright. # -import macros +import std/macros + +# xxx `genEnumCaseStmt` needs tests and runnableExamples macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed, userMin, userMax: static[int], normalizer: static[proc(s :string): string]): untyped = @@ -61,4 +63,17 @@ macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed, result.add nnkElse.newTree(raiseStmt) else: expectKind(default, nnkSym) - result.add nnkElse.newTree(default) \ No newline at end of file + result.add nnkElse.newTree(default) + +macro enumWithHolesFullRange(a: typed): untyped = + newNimNode(nnkCurly).add(a.getType[1][1..^1]) + +iterator items*[T: enum and not Ordinal](E: typedesc[T]): T = + ## Iterates over an enum with holes. + runnableExamples: + type A = enum a0 = 2, a1 = 4, a2 + type B[T] = enum b0 = 2, b1 = 4 + from std/sequtils import toSeq + assert A.toSeq == [a0, a1, a2] + assert B[float].toSeq == [B[float].b0, B[float].b1] + for a in enumWithHolesFullRange(E): yield a diff --git a/lib/system/iterators.nim b/lib/system/iterators.nim index 504695bf6296e..7f0076a444652 100644 --- a/lib/system/iterators.nim +++ b/lib/system/iterators.nim @@ -82,8 +82,13 @@ iterator mitems*(a: var cstring): var char {.inline.} = yield a[i] inc(i) -iterator items*[T: enum](E: typedesc[T]): T = - ## Iterates over the values of the enum ``E``. +iterator items*[T: enum and Ordinal](E: typedesc[T]): T = + ## Iterates over the values of `E`. + ## See also `enumutils.items` for enums with holes. + runnableExamples: + type Goo = enum g0 = 2, g1, g2 + from std/sequtils import toSeq + assert Goo.toSeq == [g0, g1, g2] for v in low(E) .. high(E): yield v diff --git a/tests/stdlib/tenumutils.nim b/tests/stdlib/tenumutils.nim new file mode 100644 index 0000000000000..dd5da19748562 --- /dev/null +++ b/tests/stdlib/tenumutils.nim @@ -0,0 +1,16 @@ +discard """ + targets: "c js" +""" + +import std/enumutils +from std/sequtils import toSeq + +template main = + block: # items + type A = enum a0 = 2, a1 = 4, a2 + type B[T] = enum b0 = 2, b1 = 4 + doAssert A.toSeq == [a0, a1, a2] + doAssert B[float].toSeq == [B[float].b0, B[float].b1] + +static: main() +main()