summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim2
-rw-r--r--compiler/semfold.nim2
-rw-r--r--doc/manual/generics.txt6
-rw-r--r--lib/pure/collections/sets.nim98
-rw-r--r--lib/pure/nativesockets.nim4
-rw-r--r--lib/system.nim2
-rw-r--r--lib/system/nimscript.nim9
-rw-r--r--tests/array/tarraylen.nim18
8 files changed, 133 insertions, 8 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index e3caa5d86..6e87959bf 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -631,7 +631,7 @@ type
     mPointer, mEmptySet, mIntSetBaseType, mNil, mExpr, mStmt, mTypeDesc,
     mVoidType, mPNimrodNode, mShared, mGuarded, mLock, mSpawn, mDeepCopy,
     mIsMainModule, mCompileDate, mCompileTime, mProcCall,
-    mCpuEndian, mHostOS, mHostCPU, mAppType,
+    mCpuEndian, mHostOS, mHostCPU, mBuildOS, mBuildCPU, mAppType,
     mNaN, mInf, mNegInf,
     mCompileOption, mCompileOptionArg,
     mNLen, mNChild, mNSetChild, mNAdd, mNAddMultiple, mNDel, mNKind,
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index 84cb0071f..9733564e7 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -616,6 +616,8 @@ proc getConstExpr(m: PSym, n: PNode): PNode =
       of mCpuEndian: result = newIntNodeT(ord(CPU[targetCPU].endian), n)
       of mHostOS: result = newStrNodeT(toLowerAscii(platform.OS[targetOS].name), n)
       of mHostCPU: result = newStrNodeT(platform.CPU[targetCPU].name.toLowerAscii, n)
+      of mBuildOS: result = newStrNodeT(toLowerAscii(platform.OS[platform.hostOS].name), n)
+      of mBuildCPU: result = newStrNodeT(platform.CPU[platform.hostCPU].name.toLowerAscii, n)
       of mAppType: result = getAppType(n)
       of mNaN: result = newFloatNodeT(NaN, n)
       of mInf: result = newFloatNodeT(Inf, n)
diff --git a/doc/manual/generics.txt b/doc/manual/generics.txt
index 87fcb7828..cceea33c0 100644
--- a/doc/manual/generics.txt
+++ b/doc/manual/generics.txt
@@ -633,6 +633,9 @@ the ``vtptr`` magic produced types bound to ``ptr`` types.
 Symbol lookup in generics
 -------------------------
 
+Open and Closed symbols
+~~~~~~~~~~~~~~~~~~~~~~~
+
 The symbol binding rules in generics are slightly subtle: There are "open" and
 "closed" symbols. A "closed" symbol cannot be re-bound in the instantiation
 context, an "open" symbol can. Per default overloaded symbols are open
@@ -658,6 +661,9 @@ the ``Index`` type is defined *after* the ``==`` for tuples; yet the example
 compiles as the instantiation takes the currently defined symbols into account
 too.
 
+Mixin statement
+---------------
+
 A symbol can be forced to be open by a `mixin`:idx: declaration:
 
 .. code-block:: nim
diff --git a/lib/pure/collections/sets.nim b/lib/pure/collections/sets.nim
index d51a5c388..dbdf17514 100644
--- a/lib/pure/collections/sets.nim
+++ b/lib/pure/collections/sets.nim
@@ -287,8 +287,6 @@ proc exclImpl[A](s: var HashSet[A], key: A) : bool {. inline .} =
 
   if i >= 0:
     result = false
-    s.data[i].hcode = 0
-    s.data[i].key = default(type(s.data[i].key))
     dec(s.counter)
     while true:         # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1
       var j = i         # The correctness of this depends on (h+1) in nextTry,
@@ -300,7 +298,7 @@ proc exclImpl[A](s: var HashSet[A], key: A) : bool {. inline .} =
         if isEmpty(s.data[i].hcode):   # end of collision cluster; So all done
           return
         r = s.data[i].hcode and msk    # "home" location of key@i
-      shallowCopy(s.data[j], s.data[i]) # data[j] will be marked EMPTY next loop
+      shallowCopy(s.data[j], s.data[i]) # data[i] will be marked EMPTY next loop
 
 proc missingOrExcl*[A](s: var HashSet[A], key: A): bool =
   ## Excludes `key` in the set `s` and tells if `key` was removed from `s`.
@@ -662,9 +660,12 @@ proc card*[A](s: OrderedSet[A]): int {.inline.} =
 
 template forAllOrderedPairs(yieldStmt: untyped) {.dirty.} =
   var h = s.first
+  var idx = 0
   while h >= 0:
     var nxt = s.data[h].next
-    if isFilled(s.data[h].hcode): yieldStmt
+    if isFilled(s.data[h].hcode):
+      yieldStmt
+      inc(idx)
     h = nxt
 
 iterator items*[A](s: OrderedSet[A]): A =
@@ -689,6 +690,11 @@ iterator items*[A](s: OrderedSet[A]): A =
   forAllOrderedPairs:
     yield s.data[h].key
 
+iterator pairs*[A](s: OrderedSet[A]): tuple[a: int, b: A] =
+  assert s.isValid, "The set needs to be initialized"
+  forAllOrderedPairs:
+    yield (idx, s.data[h].key)
+
 proc rawGetKnownHC[A](s: OrderedSet[A], key: A, hc: Hash): int {.inline.} =
   rawGetKnownHCImpl()
 
@@ -760,6 +766,67 @@ proc incl*[A](s: var HashSet[A], other: OrderedSet[A]) =
   assert other.isValid, "The set `other` needs to be initialized."
   for item in other: incl(s, item)
 
+proc exclImpl[A](s: var OrderedSet[A], key: A) : bool {. inline .} =
+  assert s.isValid, "The set needs to be initialized."
+  var hc: Hash
+  var i = rawGet(s, key, hc)
+  var msk = high(s.data)
+  result = true
+
+  if i >= 0:
+    result = false
+    # Fix ordering
+    if s.first == i:
+      s.first = s.data[i].next
+    else:
+      var itr = s.first
+      while true:
+        if (s.data[itr].next == i):
+          s.data[itr].next = s.data[i].next
+          if s.last == i:
+            s.last = itr
+          break
+        itr = s.data[itr].next
+
+    dec(s.counter)
+    while true:         # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1
+      var j = i         # The correctness of this depends on (h+1) in nextTry,
+      var r = j         # though may be adaptable to other simple sequences.
+      s.data[i].hcode = 0              # mark current EMPTY
+      s.data[i].key = default(type(s.data[i].key))
+      s.data[i].next = 0
+      doWhile((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)):
+        i = (i + 1) and msk            # increment mod table size
+        if isEmpty(s.data[i].hcode):   # end of collision cluster; So all done
+          return
+        r = s.data[i].hcode and msk    # "home" location of key@i
+      shallowCopy(s.data[j], s.data[i]) # data[i] will be marked EMPTY next loop
+
+proc missingOrExcl*[A](s: var OrderedSet[A], key: A): bool =
+  ## Excludes `key` in the set `s` and tells if `key` was removed from `s`. Efficiency: O(n).
+  ##
+  ## The difference with regards to the `excl() <#excl,TOrderedSet[A],A>`_ proc is
+  ## that this proc returns `true` if `key` was not present in `s`. Example:
+  ##
+  ## .. code-block::
+  ##  var s = toOrderedSet([2, 3, 6, 7])
+  ##  assert s.missingOrExcl(4) == true
+  ##  assert s.missingOrExcl(6) == false
+  exclImpl(s, key)
+
+
+proc excl*[A](s: var OrderedSet[A], key: A) =
+  ## Excludes `key` from the set `s`. Efficiency: O(n).
+  ##
+  ## This doesn't do anything if `key` is not found in `s`. Example:
+  ##
+  ## .. code-block::
+  ##   var s = toOrderedSet([2, 3, 6, 7])
+  ##   s.excl(2)
+  ##   s.excl(2)
+  ##   assert s.len == 3
+  discard exclImpl(s, key)
+
 proc containsOrIncl*[A](s: var OrderedSet[A], key: A): bool =
   ## Includes `key` in the set `s` and tells if `key` was added to `s`.
   ##
@@ -986,6 +1053,24 @@ when isMainModule and not defined(release):
       assert a.len == b.card
       assert a.len == 2
 
+    block setPairsIterator:
+      var s = toOrderedSet([1, 3, 5, 7])
+      var items = newSeq[tuple[a: int, b: int]]()
+      for idx, item in s: items.add((idx, item))
+      assert items == @[(0, 1), (1, 3), (2, 5), (3, 7)]
+
+    block exclusions:
+      var s = toOrderedSet([1, 2, 3, 6, 7, 4])
+
+      s.excl(3)
+      s.excl(3)
+      s.excl(1)
+      s.excl(4)
+
+      var items = newSeq[int]()
+      for item in s: items.add item
+      assert items == @[2, 6, 7]
+
     #block orderedSetIterator:
     #  var a = initOrderedSet[int]()
     #  for value in [9, 2, 1, 5, 1, 8, 4, 2]:
@@ -1030,6 +1115,11 @@ when isMainModule and not defined(release):
       if s <= i or mustRehash(s, i):
         echo "performance issue: rightSize() will not elide enlarge() at ", i
 
+    block missingOrExcl:
+      var s = toOrderedSet([2, 3, 6, 7])
+      assert s.missingOrExcl(4) == true
+      assert s.missingOrExcl(6) == false
+
     when not defined(testing):
       echo "Micro tests run successfully."
 
diff --git a/lib/pure/nativesockets.nim b/lib/pure/nativesockets.nim
index 1a62c0bf6..98fc62a3b 100644
--- a/lib/pure/nativesockets.nim
+++ b/lib/pure/nativesockets.nim
@@ -498,7 +498,7 @@ proc getLocalAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
     # Cannot use INET6_ADDRSTRLEN here, because it's a C define.
     var buf: array[64, char]
     if inet_ntop(name.sin6_family.cint,
-                 addr name, buf.cstring, sizeof(buf).int32).isNil:
+                 addr name.sin6_addr, buf.cstring, sizeof(buf).int32).isNil:
       raiseOSError(osLastError())
     result = ($buf, Port(nativesockets.ntohs(name.sin6_port)))
   else:
@@ -534,7 +534,7 @@ proc getPeerAddr*(socket: SocketHandle, domain: Domain): (string, Port) =
     # Cannot use INET6_ADDRSTRLEN here, because it's a C define.
     var buf: array[64, char]
     if inet_ntop(name.sin6_family.cint,
-                 addr name, buf.cstring, sizeof(buf).int32).isNil:
+                 addr name.sin6_addr, buf.cstring, sizeof(buf).int32).isNil:
       raiseOSError(osLastError())
     result = ($buf, Port(nativesockets.ntohs(name.sin6_port)))
   else:
diff --git a/lib/system.nim b/lib/system.nim
index cc5ef9810..61d79bac3 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -717,7 +717,7 @@ proc len*[TOpenArray: openArray|varargs](x: TOpenArray): int {.
   magic: "LengthOpenArray", noSideEffect.}
 proc len*(x: string): int {.magic: "LengthStr", noSideEffect.}
 proc len*(x: cstring): int {.magic: "LengthStr", noSideEffect.}
-proc len*[I, T](x: array[I, T]): int {.magic: "LengthArray", noSideEffect.}
+proc len*(x: (type array)|array): int {.magic: "LengthArray", noSideEffect.}
 proc len*[T](x: seq[T]): int {.magic: "LengthSeq", noSideEffect.}
   ## returns the length of an array, an openarray, a sequence or a string.
   ## This is roughly the same as ``high(T)-low(T)+1``, but its resulting type is
diff --git a/lib/system/nimscript.nim b/lib/system/nimscript.nim
index 73bb91fef..f5b9cf3ed 100644
--- a/lib/system/nimscript.nim
+++ b/lib/system/nimscript.nim
@@ -11,6 +11,15 @@
 # Nim's configuration system now uses Nim for scripting. This module provides
 # a few things that are required for this to work.
 
+const
+  buildOS* {.magic: "BuildOS".}: string = ""
+    ## The OS this build is running on. Can be different from ``system.hostOS``
+    ## for cross compilations.
+
+  buildCPU* {.magic: "BuildCPU".}: string = ""
+    ## The CPU this build is running on. Can be different from ``system.hostCPU``
+    ## for cross compilations.
+
 template builtin = discard
 
 # We know the effects better than the compiler:
diff --git a/tests/array/tarraylen.nim b/tests/array/tarraylen.nim
new file mode 100644
index 000000000..e9612de58
--- /dev/null
+++ b/tests/array/tarraylen.nim
@@ -0,0 +1,18 @@
+discard """
+  output: ""
+"""
+var a: array[0, int]
+doAssert a.len == 0
+doAssert array[0..0, int].len == 1
+doAssert array[0..0, int]([1]).len == 1
+doAssert array[1..1, int].len == 1
+doAssert array[1..1, int]([1]).len == 1
+doAssert array[2, int].len == 2
+doAssert array[2, int]([1, 2]).len == 2
+doAssert array[1..3, int].len == 3
+doAssert array[1..3, int]([1, 2, 3]).len == 3
+doAssert array[0..2, int].len == 3
+doAssert array[0..2, int]([1, 2, 3]).len == 3
+doAssert array[-2 .. -2, int].len == 1
+doAssert([1, 2, 3].len == 3)
+doAssert([42].len == 1)
\ No newline at end of file