Add enum utilities and add enum with holes support (#115)
This commit is contained in:
parent
412a691f5d
commit
c2f0cbf0d9
|
@ -1,5 +1,6 @@
|
|||
import
|
||||
macros
|
||||
macros,
|
||||
sequtils
|
||||
|
||||
template init*(lvalue: var auto) =
|
||||
mixin init
|
||||
|
@ -67,26 +68,28 @@ proc baseType*(obj: RootObj): cstring =
|
|||
proc baseType*(obj: ref RootObj): cstring =
|
||||
obj[].baseType
|
||||
|
||||
when false:
|
||||
# TODO: Implementing this doesn't seem possible at the moment.
|
||||
#
|
||||
# When given enum like:
|
||||
#
|
||||
# type WithoutHoles2 = enum
|
||||
# A2 = 2, B2 = 3, C2 = 4
|
||||
#
|
||||
# ...the code below will print:
|
||||
#
|
||||
# EnumTy
|
||||
# Empty
|
||||
# Sym "A2"
|
||||
# Sym "B2"
|
||||
# Sym "C2"
|
||||
#
|
||||
macro enumRangeInt64*(a: type[enum]): untyped =
|
||||
## This macro returns an array with all the ordinal values of an enum
|
||||
let
|
||||
values = a.getType[1][1..^1]
|
||||
valuesOrded = values.mapIt(newCall("int64", it))
|
||||
newNimNode(nnkBracket).add(valuesOrded)
|
||||
|
||||
macro hasHoles*(T: type[enum]): bool =
|
||||
let t = getType(T)[1]
|
||||
echo t.treeRepr
|
||||
return newLit(true)
|
||||
# As an enum is always sorted, just substract the first and the last ordinal value
|
||||
# and compare the result to the number of element in it will do the trick.
|
||||
let len = T.getType[1].len - 2
|
||||
|
||||
quote: `T`.high.ord - `T`.low.ord != `len`
|
||||
|
||||
proc contains*[I: SomeInteger](e: type[enum], v: I): bool =
|
||||
when I is uint64:
|
||||
if v > int.high.uint64:
|
||||
return false
|
||||
when e.hasHoles():
|
||||
v.int64 in enumRangeInt64(e)
|
||||
else:
|
||||
v.int64 in e.low.int64 .. e.high.int64
|
||||
|
||||
func checkedEnumAssign*[E: enum, I: SomeInteger](res: var E, value: I): bool =
|
||||
## This function can be used to safely assign a tainted integer value (coming
|
||||
|
@ -94,14 +97,7 @@ func checkedEnumAssign*[E: enum, I: SomeInteger](res: var E, value: I): bool =
|
|||
## if the integer value is within the acceped values of the enum and `false`
|
||||
## otherwise.
|
||||
|
||||
# TODO: Enums with holes are not supported yet
|
||||
# static: doAssert(not hasHoles(E))
|
||||
|
||||
when I is SomeSignedInt or low(E).int > 0:
|
||||
if value < I(low(E)):
|
||||
return false
|
||||
|
||||
if value > I(high(E)):
|
||||
if value notin E:
|
||||
return false
|
||||
|
||||
res = E value
|
||||
|
@ -113,4 +109,3 @@ func isZeroMemory*[T](x: T): bool =
|
|||
if b != 0:
|
||||
return false
|
||||
return true
|
||||
|
||||
|
|
|
@ -70,10 +70,63 @@ suite "Objects":
|
|||
T6 is DistinctBar
|
||||
T6 isnot Bar
|
||||
|
||||
when false:
|
||||
# TODO: Not possible yet (see objects.nim)
|
||||
test "enumRangeInt64":
|
||||
type
|
||||
WithoutHoles = enum
|
||||
A1, A2, A3
|
||||
WithoutHoles2 = enum
|
||||
B1 = 4, B2 = 5, B3 = 6
|
||||
WithHoles = enum
|
||||
C1 = 1, C2 = 3, C3 = 5
|
||||
|
||||
check:
|
||||
enumRangeInt64(WithoutHoles) == [ 0'i64, 1, 2 ]
|
||||
enumRangeInt64(WithoutHoles2) == [ 4'i64, 5, 6 ]
|
||||
enumRangeInt64(WithHoles) == [ 1'i64, 3, 5 ]
|
||||
|
||||
|
||||
test "contains":
|
||||
type
|
||||
WithoutHoles = enum
|
||||
A1, A2, A3
|
||||
WithoutHoles2 = enum
|
||||
B1 = 4, B2 = 5, B3 = 6
|
||||
WithHoles = enum
|
||||
C1 = 1, C2 = 3, C3 = 5
|
||||
WithoutHoles3 = enum
|
||||
D1 = -1, D2 = 0, D3 = 1
|
||||
WithHoles2 = enum
|
||||
E1 = -5, E2 = 0, E3 = 5
|
||||
|
||||
check:
|
||||
1 in WithoutHoles
|
||||
5 notin WithoutHoles
|
||||
1 notin WithoutHoles2
|
||||
5 in WithoutHoles2
|
||||
1 in WithHoles
|
||||
2 notin WithHoles
|
||||
6 notin WithHoles
|
||||
5 in WithHoles
|
||||
1.byte in WithoutHoles
|
||||
4294967295'u32 notin WithoutHoles3
|
||||
-1.int8 in WithoutHoles3
|
||||
-4.int16 notin WithoutHoles3
|
||||
-5.int16 in WithHoles2
|
||||
5.uint64 in WithHoles2
|
||||
-12.int8 notin WithHoles2
|
||||
int64.high notin WithoutHoles
|
||||
int64.high notin WithHoles
|
||||
int64.low notin WithoutHoles
|
||||
int64.low notin WithHoles
|
||||
int64.high.uint64 * 2 notin WithoutHoles
|
||||
int64.high.uint64 * 2 notin WithHoles
|
||||
|
||||
|
||||
test "hasHoles":
|
||||
type
|
||||
EnumWithOneValue = enum
|
||||
A0
|
||||
|
||||
WithoutHoles = enum
|
||||
A1, B1, C1
|
||||
|
||||
|
@ -83,10 +136,15 @@ suite "Objects":
|
|||
WithHoles = enum
|
||||
A3, B3 = 2, C3
|
||||
|
||||
WithBigHoles = enum
|
||||
A4 = 0, B4 = 2000, C4 = 4000
|
||||
|
||||
check:
|
||||
hasHoles(WithoutHoles2) == false
|
||||
hasHoles(EnumWithOneValue) == false
|
||||
hasHoles(WithoutHoles) == false
|
||||
hasHoles(WithoutHoles2) == false
|
||||
hasHoles(WithHoles) == true
|
||||
hasHoles(WithBigHoles) == true
|
||||
|
||||
test "checkedEnumAssign":
|
||||
type
|
||||
|
@ -96,42 +154,41 @@ suite "Objects":
|
|||
AnotherEnum = enum
|
||||
A2 = 2, B2, C2
|
||||
|
||||
EnumWithHoles = enum
|
||||
A3, B3 = 3, C3
|
||||
var
|
||||
e1 = A1
|
||||
e2 = A2
|
||||
e3 = A3
|
||||
|
||||
check:
|
||||
checkedEnumAssign(e1, 2)
|
||||
e1 == C1
|
||||
|
||||
check:
|
||||
not checkedEnumAssign(e1, 5)
|
||||
e1 == C1
|
||||
|
||||
check:
|
||||
checkedEnumAssign(e1, 0)
|
||||
e1 == A1
|
||||
|
||||
check:
|
||||
not checkedEnumAssign(e1, -1)
|
||||
e1 == A1
|
||||
|
||||
check:
|
||||
checkedEnumAssign(e2, 2)
|
||||
e2 == A2
|
||||
|
||||
check:
|
||||
not checkedEnumAssign(e2, 5)
|
||||
e2 == A2
|
||||
|
||||
check:
|
||||
checkedEnumAssign(e2, 4)
|
||||
e2 == C2
|
||||
|
||||
check:
|
||||
not checkedEnumAssign(e2, 1)
|
||||
e2 == C2
|
||||
|
||||
checkedEnumAssign(e3, 4)
|
||||
e3 == C3
|
||||
not checkedEnumAssign(e3, 1)
|
||||
e3 == C3
|
||||
checkedEnumAssign(e3, 0)
|
||||
e3 == A3
|
||||
not checkedEnumAssign(e3, -1)
|
||||
e3 == A3
|
||||
|
||||
test "isZeroMemory":
|
||||
type
|
||||
Foo = object
|
||||
|
|
Loading…
Reference in New Issue