123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- #
- #
- # Nim's Runtime Library
- # (c) Copyright 2012 Andreas Rumpf
- #
- # See the file "copying.txt", included in this
- # distribution, for details about the copyright.
- #
- ## Implementation of a `deque`:idx: (double-ended queue).
- ## The underlying implementation uses a ``seq``.
- ##
- ## None of the procs that get an individual value from the deque can be used
- ## on an empty deque.
- ## If compiled with `boundChecks` option, those procs will raise an `IndexError`
- ## on such access. This should not be relied upon, as `-d:release` will
- ## disable those checks and may return garbage or crash the program.
- ##
- ## As such, a check to see if the deque is empty is needed before any
- ## access, unless your program logic guarantees it indirectly.
- ##
- ## .. code-block:: Nim
- ## proc foo(a, b: Positive) = # assume random positive values for `a` and `b`
- ## var deq = initDeque[int]() # initializes the object
- ## for i in 1 ..< a: deq.addLast i # populates the deque
- ##
- ## if b < deq.len: # checking before indexed access
- ## echo "The element at index position ", b, " is ", deq[b]
- ##
- ## # The following two lines don't need any checking on access due to the
- ## # logic of the program, but that would not be the case if `a` could be 0.
- ## assert deq.peekFirst == 1
- ## assert deq.peekLast == a
- ##
- ## while deq.len > 0: # checking if the deque is empty
- ## echo deq.popLast()
- ##
- ## Note: For inter thread communication use
- ## a `Channel <channels.html>`_ instead.
- import math, typetraits
- type
- Deque*[T] = object
- ## A double-ended queue backed with a ringed seq buffer.
- data: seq[T]
- head, tail, count, mask: int
- proc initDeque*[T](initialSize: int = 4): Deque[T] =
- ## Create a new deque.
- ## Optionally, the initial capacity can be reserved via `initialSize` as a
- ## performance optimization. The length of a newly created deque will still
- ## be 0.
- ##
- ## `initialSize` needs to be a power of two. If you need to accept runtime
- ## values for this you could use the ``nextPowerOfTwo`` proc from the
- ## `math <math.html>`_ module.
- assert isPowerOfTwo(initialSize)
- result.mask = initialSize-1
- newSeq(result.data, initialSize)
- proc len*[T](deq: Deque[T]): int {.inline.} =
- ## Return the number of elements of `deq`.
- result = deq.count
- template emptyCheck(deq) =
- # Bounds check for the regular deque access.
- when compileOption("boundChecks"):
- if unlikely(deq.count < 1):
- raise newException(IndexError, "Empty deque.")
- template xBoundsCheck(deq, i) =
- # Bounds check for the array like accesses.
- when compileOption("boundChecks"): # d:release should disable this.
- if unlikely(i >= deq.count): # x < deq.low is taken care by the Natural parameter
- raise newException(IndexError,
- "Out of bounds: " & $i & " > " & $(deq.count - 1))
- proc `[]`*[T](deq: Deque[T], i: Natural) : T {.inline.} =
- ## Access the i-th element of `deq` by order from first to last.
- ## deq[0] is the first, deq[^1] is the last.
- xBoundsCheck(deq, i)
- return deq.data[(deq.head + i) and deq.mask]
- proc `[]`*[T](deq: var Deque[T], i: Natural): var T {.inline.} =
- ## Access the i-th element of `deq` and returns a mutable
- ## reference to it.
- xBoundsCheck(deq, i)
- return deq.data[(deq.head + i) and deq.mask]
- proc `[]=`* [T] (deq: var Deque[T], i: Natural, val : T) {.inline.} =
- ## Change the i-th element of `deq`.
- xBoundsCheck(deq, i)
- deq.data[(deq.head + i) and deq.mask] = val
- iterator items*[T](deq: Deque[T]): T =
- ## Yield every element of `deq`.
- var i = deq.head
- for c in 0 ..< deq.count:
- yield deq.data[i]
- i = (i + 1) and deq.mask
- iterator mitems*[T](deq: var Deque[T]): var T =
- ## Yield every element of `deq`.
- var i = deq.head
- for c in 0 ..< deq.count:
- yield deq.data[i]
- i = (i + 1) and deq.mask
- iterator pairs*[T](deq: Deque[T]): tuple[key: int, val: T] =
- ## Yield every (position, value) of `deq`.
- var i = deq.head
- for c in 0 ..< deq.count:
- yield (c, deq.data[i])
- i = (i + 1) and deq.mask
- proc contains*[T](deq: Deque[T], item: T): bool {.inline.} =
- ## Return true if `item` is in `deq` or false if not found. Usually used
- ## via the ``in`` operator. It is the equivalent of ``deq.find(item) >= 0``.
- ##
- ## .. code-block:: Nim
- ## if x in q:
- ## assert q.contains x
- for e in deq:
- if e == item: return true
- return false
- proc expandIfNeeded[T](deq: var Deque[T]) =
- var cap = deq.mask + 1
- if unlikely(deq.count >= cap):
- var n = newSeq[T](cap * 2)
- for i, x in pairs(deq): # don't use copyMem because the GC and because it's slower.
- shallowCopy(n[i], x)
- shallowCopy(deq.data, n)
- deq.mask = cap * 2 - 1
- deq.tail = deq.count
- deq.head = 0
- proc addFirst*[T](deq: var Deque[T], item: T) =
- ## Add an `item` to the beginning of the `deq`.
- expandIfNeeded(deq)
- inc deq.count
- deq.head = (deq.head - 1) and deq.mask
- deq.data[deq.head] = item
- proc addLast*[T](deq: var Deque[T], item: T) =
- ## Add an `item` to the end of the `deq`.
- expandIfNeeded(deq)
- inc deq.count
- deq.data[deq.tail] = item
- deq.tail = (deq.tail + 1) and deq.mask
- proc peekFirst*[T](deq: Deque[T]): T {.inline.}=
- ## Returns the first element of `deq`, but does not remove it from the deque.
- emptyCheck(deq)
- result = deq.data[deq.head]
- proc peekLast*[T](deq: Deque[T]): T {.inline.} =
- ## Returns the last element of `deq`, but does not remove it from the deque.
- emptyCheck(deq)
- result = deq.data[(deq.tail - 1) and deq.mask]
- template destroy(x: untyped) =
- reset(x)
- proc popFirst*[T](deq: var Deque[T]): T {.inline, discardable.} =
- ## Remove and returns the first element of the `deq`.
- emptyCheck(deq)
- dec deq.count
- result = deq.data[deq.head]
- destroy(deq.data[deq.head])
- deq.head = (deq.head + 1) and deq.mask
- proc popLast*[T](deq: var Deque[T]): T {.inline, discardable.} =
- ## Remove and returns the last element of the `deq`.
- emptyCheck(deq)
- dec deq.count
- deq.tail = (deq.tail - 1) and deq.mask
- result = deq.data[deq.tail]
- destroy(deq.data[deq.tail])
- proc clear*[T](deq: var Deque[T]) {.inline.} =
- ## Resets the deque so that it is empty.
- for el in mitems(deq): destroy(el)
- deq.count = 0
- deq.tail = deq.head
- proc shrink*[T](deq: var Deque[T], fromFirst = 0, fromLast = 0) =
- ## Remove `fromFirst` elements from the front of the deque and
- ## `fromLast` elements from the back. If the supplied number of
- ## elements exceeds the total number of elements in the deque,
- ## the deque will remain empty.
- ##
- ## Any user defined destructors
- if fromFirst + fromLast > deq.count:
- clear(deq)
- return
- for i in 0 ..< fromFirst:
- destroy(deq.data[deq.head])
- deq.head = (deq.head + 1) and deq.mask
- for i in 0 ..< fromLast:
- destroy(deq.data[deq.tail])
- deq.tail = (deq.tail - 1) and deq.mask
- dec deq.count, fromFirst + fromLast
- proc `$`*[T](deq: Deque[T]): string =
- ## Turn a deque into its string representation.
- result = "["
- for x in deq:
- if result.len > 1: result.add(", ")
- result.addQuoted(x)
- result.add("]")
- when isMainModule:
- var deq = initDeque[int](1)
- deq.addLast(4)
- deq.addFirst(9)
- deq.addFirst(123)
- var first = deq.popFirst()
- deq.addLast(56)
- assert(deq.peekLast() == 56)
- deq.addLast(6)
- assert(deq.peekLast() == 6)
- var second = deq.popFirst()
- deq.addLast(789)
- assert(deq.peekLast() == 789)
- assert first == 123
- assert second == 9
- assert($deq == "[4, 56, 6, 789]")
- assert deq[0] == deq.peekFirst and deq.peekFirst == 4
- #assert deq[^1] == deq.peekLast and deq.peekLast == 789
- deq[0] = 42
- deq[deq.len - 1] = 7
- assert 6 in deq and 789 notin deq
- assert deq.find(6) >= 0
- assert deq.find(789) < 0
- block:
- var d = initDeque[int](1)
- d.addLast 7
- d.addLast 8
- d.addLast 10
- d.addFirst 5
- d.addFirst 2
- d.addFirst 1
- d.addLast 20
- d.shrink(fromLast = 2)
- doAssert($d == "[1, 2, 5, 7, 8]")
- d.shrink(2, 1)
- doAssert($d == "[5, 7]")
- d.shrink(2, 2)
- doAssert d.len == 0
- for i in -2 .. 10:
- if i in deq:
- assert deq.contains(i) and deq.find(i) >= 0
- else:
- assert(not deq.contains(i) and deq.find(i) < 0)
- when compileOption("boundChecks"):
- try:
- echo deq[99]
- assert false
- except IndexError:
- discard
- try:
- assert deq.len == 4
- for i in 0 ..< 5: deq.popFirst()
- assert false
- except IndexError:
- discard
- # grabs some types of resize error.
- deq = initDeque[int]()
- for i in 1 .. 4: deq.addLast i
- deq.popFirst()
- deq.popLast()
- for i in 5 .. 8: deq.addFirst i
- assert $deq == "[8, 7, 6, 5, 2, 3]"
- # Similar to proc from the documentation example
- proc foo(a, b: Positive) = # assume random positive values for `a` and `b`.
- var deq = initDeque[int]()
- assert deq.len == 0
- for i in 1 .. a: deq.addLast i
- if b < deq.len: # checking before indexed access.
- assert deq[b] == b + 1
- # The following two lines don't need any checking on access due to the logic
- # of the program, but that would not be the case if `a` could be 0.
- assert deq.peekFirst == 1
- assert deq.peekLast == a
- while deq.len > 0: # checking if the deque is empty
- assert deq.popFirst() > 0
- #foo(0,0)
- foo(8,5)
- foo(10,9)
- foo(1,1)
- foo(2,1)
- foo(1,5)
- foo(3,2)
|