123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- #
- #
- # The Nim Compiler
- # (c) Copyright 2012 Andreas Rumpf
- #
- # See the file "copying.txt", included in this
- # distribution, for details about the copyright.
- #
- # this unit handles Nim sets; it implements symbolic sets
- import
- ast, astalgo, trees, nversion, msgs, platform, bitsets, types, renderer
- proc toBitSet*(s: PNode, b: var TBitSet)
- # this function is used for case statement checking:
- proc overlap*(a, b: PNode): bool
- proc inSet*(s: PNode, elem: PNode): bool
- proc someInSet*(s: PNode, a, b: PNode): bool
- proc emptyRange*(a, b: PNode): bool
- proc setHasRange*(s: PNode): bool
- # returns true if set contains a range (needed by the code generator)
- # these are used for constant folding:
- proc unionSets*(a, b: PNode): PNode
- proc diffSets*(a, b: PNode): PNode
- proc intersectSets*(a, b: PNode): PNode
- proc symdiffSets*(a, b: PNode): PNode
- proc containsSets*(a, b: PNode): bool
- proc equalSets*(a, b: PNode): bool
- proc cardSet*(s: PNode): BiggestInt
- # implementation
- proc inSet(s: PNode, elem: PNode): bool =
- if s.kind != nkCurly:
- internalError(s.info, "inSet")
- return false
- for i in countup(0, sonsLen(s) - 1):
- if s.sons[i].kind == nkRange:
- if leValue(s.sons[i].sons[0], elem) and
- leValue(elem, s.sons[i].sons[1]):
- return true
- else:
- if sameValue(s.sons[i], elem):
- return true
- result = false
- proc overlap(a, b: PNode): bool =
- if a.kind == nkRange:
- if b.kind == nkRange:
- # X..Y and C..D overlap iff (X <= D and C <= Y)
- result = leValue(a.sons[0], b.sons[1]) and
- leValue(b.sons[0], a.sons[1])
- else:
- result = leValue(a.sons[0], b) and leValue(b, a.sons[1])
- else:
- if b.kind == nkRange:
- result = leValue(b.sons[0], a) and leValue(a, b.sons[1])
- else:
- result = sameValue(a, b)
- proc someInSet(s: PNode, a, b: PNode): bool =
- # checks if some element of a..b is in the set s
- if s.kind != nkCurly:
- internalError(s.info, "SomeInSet")
- return false
- for i in countup(0, sonsLen(s) - 1):
- if s.sons[i].kind == nkRange:
- if leValue(s.sons[i].sons[0], b) and leValue(b, s.sons[i].sons[1]) or
- leValue(s.sons[i].sons[0], a) and leValue(a, s.sons[i].sons[1]):
- return true
- else:
- # a <= elem <= b
- if leValue(a, s.sons[i]) and leValue(s.sons[i], b):
- return true
- result = false
- proc toBitSet(s: PNode, b: var TBitSet) =
- var first, j: BiggestInt
- first = firstOrd(s.typ.sons[0])
- bitSetInit(b, int(getSize(s.typ)))
- for i in countup(0, sonsLen(s) - 1):
- if s.sons[i].kind == nkRange:
- j = getOrdValue(s.sons[i].sons[0])
- while j <= getOrdValue(s.sons[i].sons[1]):
- bitSetIncl(b, j - first)
- inc(j)
- else:
- bitSetIncl(b, getOrdValue(s.sons[i]) - first)
- proc toTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
- var
- a, b, e, first: BiggestInt # a, b are interval borders
- elemType: PType
- n: PNode
- elemType = settype.sons[0]
- first = firstOrd(elemType)
- result = newNodeI(nkCurly, info)
- result.typ = settype
- result.info = info
- e = 0
- while e < len(s) * ElemSize:
- if bitSetIn(s, e):
- a = e
- b = e
- while true:
- inc(b)
- if (b >= len(s) * ElemSize) or not bitSetIn(s, b): break
- dec(b)
- let aa = newIntTypeNode(nkIntLit, a + first, elemType)
- aa.info = info
- if a == b:
- addSon(result, aa)
- else:
- n = newNodeI(nkRange, info)
- n.typ = elemType
- addSon(n, aa)
- let bb = newIntTypeNode(nkIntLit, b + first, elemType)
- bb.info = info
- addSon(n, bb)
- addSon(result, n)
- e = b
- inc(e)
- template nodeSetOp(a, b: PNode, op: untyped) {.dirty.} =
- var x, y: TBitSet
- toBitSet(a, x)
- toBitSet(b, y)
- op(x, y)
- result = toTreeSet(x, a.typ, a.info)
- proc unionSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetUnion)
- proc diffSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetDiff)
- proc intersectSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetIntersect)
- proc symdiffSets(a, b: PNode): PNode = nodeSetOp(a, b, bitSetSymDiff)
- proc containsSets(a, b: PNode): bool =
- var x, y: TBitSet
- toBitSet(a, x)
- toBitSet(b, y)
- result = bitSetContains(x, y)
- proc equalSets(a, b: PNode): bool =
- var x, y: TBitSet
- toBitSet(a, x)
- toBitSet(b, y)
- result = bitSetEquals(x, y)
- proc complement*(a: PNode): PNode =
- var x: TBitSet
- toBitSet(a, x)
- for i in countup(0, high(x)): x[i] = not x[i]
- result = toTreeSet(x, a.typ, a.info)
- proc cardSet(s: PNode): BiggestInt =
- # here we can do better than converting it into a compact set
- # we just count the elements directly
- result = 0
- for i in countup(0, sonsLen(s) - 1):
- if s.sons[i].kind == nkRange:
- result = result + getOrdValue(s.sons[i].sons[1]) -
- getOrdValue(s.sons[i].sons[0]) + 1
- else:
- inc(result)
- proc setHasRange(s: PNode): bool =
- if s.kind != nkCurly:
- internalError(s.info, "SetHasRange")
- return false
- for i in countup(0, sonsLen(s) - 1):
- if s.sons[i].kind == nkRange:
- return true
- result = false
- proc emptyRange(a, b: PNode): bool =
- result = not leValue(a, b) # a > b iff not (a <= b)
|