setutils.nim 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2020 Nim Contributors
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. ## This module adds functionality for the built-in `set` type.
  10. ##
  11. ## See also
  12. ## ========
  13. ## * `std/packedsets <packedsets.html>`_
  14. ## * `std/sets <sets.html>`_
  15. import std/[typetraits, macros]
  16. #[
  17. type SetElement* = char|byte|bool|int16|uint16|enum|uint8|int8
  18. ## The allowed types of a built-in set.
  19. ]#
  20. template toSet*(iter: untyped): untyped =
  21. ## Returns a built-in set from the elements of the iterable `iter`.
  22. runnableExamples:
  23. assert "helloWorld".toSet == {'W', 'd', 'e', 'h', 'l', 'o', 'r'}
  24. assert toSet([10u16, 20, 30]) == {10u16, 20, 30}
  25. assert [30u8, 100, 10].toSet == {10u8, 30, 100}
  26. assert toSet(@[1321i16, 321, 90]) == {90i16, 321, 1321}
  27. assert toSet([false]) == {false}
  28. assert toSet(0u8..10) == {0u8..10}
  29. var result: set[elementType(iter)]
  30. for x in iter:
  31. incl(result, x)
  32. result
  33. macro enumElementsAsSet(enm: typed): untyped = result = newNimNode(nnkCurly).add(enm.getType[1][1..^1])
  34. # func fullSet*(T: typedesc): set[T] {.inline.} = # xxx would give: Error: ordinal type expected
  35. func fullSet*[T](U: typedesc[T]): set[T] {.inline.} =
  36. ## Returns a set containing all elements in `U`.
  37. runnableExamples:
  38. assert bool.fullSet == {true, false}
  39. type A = range[1..3]
  40. assert A.fullSet == {1.A, 2, 3}
  41. assert int8.fullSet.len == 256
  42. when T is Ordinal:
  43. {T.low..T.high}
  44. else: # Hole filled enum
  45. enumElementsAsSet(T)
  46. func complement*[T](s: set[T]): set[T] {.inline.} =
  47. ## Returns the set complement of `a`.
  48. runnableExamples:
  49. type Colors = enum
  50. red, green = 3, blue
  51. assert complement({red, blue}) == {green}
  52. assert complement({red, green, blue}).card == 0
  53. assert complement({range[0..10](0), 1, 2, 3}) == {range[0..10](4), 5, 6, 7, 8, 9, 10}
  54. assert complement({'0'..'9'}) == {0.char..255.char} - {'0'..'9'}
  55. fullSet(T) - s
  56. func `[]=`*[T](t: var set[T], key: T, val: bool) {.inline.} =
  57. ## Syntax sugar for `if val: t.incl key else: t.excl key`
  58. runnableExamples:
  59. type A = enum
  60. a0, a1, a2, a3
  61. var s = {a0, a3}
  62. s[a0] = false
  63. s[a1] = false
  64. assert s == {a3}
  65. s[a2] = true
  66. s[a3] = true
  67. assert s == {a2, a3}
  68. if val: t.incl key else: t.excl key
  69. when defined(nimHasXorSet):
  70. func symmetricDifference*[T](x, y: set[T]): set[T] {.magic: "XorSet".} =
  71. ## This operator computes the symmetric difference of two sets,
  72. ## equivalent to but more efficient than `x + y - x * y` or
  73. ## `(x - y) + (y - x)`.
  74. runnableExamples:
  75. assert symmetricDifference({1, 2, 3}, {2, 3, 4}) == {1, 4}
  76. else:
  77. func symmetricDifference*[T](x, y: set[T]): set[T] {.inline.} =
  78. result = x + y - (x * y)
  79. proc `-+-`*[T](x, y: set[T]): set[T] {.inline.} =
  80. ## Operator alias for `symmetricDifference`.
  81. runnableExamples:
  82. assert {1, 2, 3} -+- {2, 3, 4} == {1, 4}
  83. result = symmetricDifference(x, y)
  84. proc toggle*[T](x: var set[T], y: set[T]) {.inline.} =
  85. ## Toggles the existence of each value of `y` in `x`.
  86. ## If any element in `y` is also in `x`, it is excluded from `x`;
  87. ## otherwise it is included.
  88. ## Equivalent to `x = symmetricDifference(x, y)`.
  89. runnableExamples:
  90. var x = {1, 2, 3}
  91. x.toggle({2, 3, 4})
  92. assert x == {1, 4}
  93. x = symmetricDifference(x, y)