summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--changelog.md2
-rw-r--r--compiler/ccgcalls.nim36
-rw-r--r--compiler/ccgexprs.nim17
-rw-r--r--compiler/seminst.nim4
-rw-r--r--lib/system.nim10
-rw-r--r--tests/system/tsystem_misc.nim29
6 files changed, 84 insertions, 14 deletions
diff --git a/changelog.md b/changelog.md
index 749450bdc..b8d28b633 100644
--- a/changelog.md
+++ b/changelog.md
@@ -13,6 +13,8 @@
 
 - ``re.split`` now also supports the ``maxsplit`` parameter for consistency
   with ``strutils.split``.
+- Added ``system.toOpenArray`` in order to support zero-copy slicing
+  operations. This is currently not yet available for the JavaScript target.
 
 ### Library changes
 
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 18741732c..5f14b6804 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -83,6 +83,8 @@ proc isInCurrentFrame(p: BProc, n: PNode): bool =
     result = isInCurrentFrame(p, n.sons[0])
   else: discard
 
+proc genIndexCheck(p: BProc; arr, idx: TLoc)
+
 proc openArrayLoc(p: BProc, n: PNode): Rope =
   var a: TLoc
 
@@ -93,18 +95,28 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
     initLocExpr(p, q[1], a)
     initLocExpr(p, q[2], b)
     initLocExpr(p, q[3], c)
-    let fmt =
-      case skipTypes(a.t, abstractVar+{tyPtr}).kind
-      of tyOpenArray, tyVarargs, tyArray:
-        "($1)+($2), ($3)-($2)+1"
-      of tyString, tySequence:
-        if skipTypes(n.typ, abstractInst).kind == tyVar and
-            not compileToCpp(p.module):
-          "(*$1)->data+($2), ($3)-($2)+1"
-        else:
-          "$1->data+($2), ($3)-($2)+1"
-      else: (internalError("openArrayLoc: " & typeToString(a.t)); "")
-    result = fmt % [rdLoc(a), rdLoc(b), rdLoc(c)]
+    # but first produce the required index checks:
+    if optBoundsCheck in p.options:
+      genIndexCheck(p, a, b)
+      genIndexCheck(p, a, c)
+    let ty = skipTypes(a.t, abstractVar+{tyPtr})
+    case ty.kind
+    of tyArray:
+      let first = firstOrd(ty)
+      if first == 0:
+        result = "($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)]
+      else:
+        result = "($1)+(($2)-($4)), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), intLiteral(first)]
+    of tyOpenArray, tyVarargs:
+      result = "($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)]
+    of tyString, tySequence:
+      if skipTypes(n.typ, abstractInst).kind == tyVar and
+          not compileToCpp(p.module):
+        result = "(*$1)->data+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)]
+      else:
+        result = "$1->data+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)]
+    else:
+      internalError("openArrayLoc: " & typeToString(a.t))
   else:
     initLocExpr(p, n, a)
     case skipTypes(a.t, abstractVar).kind
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 6ea56d71d..dc06c8482 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -880,6 +880,23 @@ proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) =
   putIntoDest(p, d, n,
               rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
 
+proc genIndexCheck(p: BProc; arr, idx: TLoc) =
+  let ty = skipTypes(arr.t, abstractVarRange)
+  case ty.kind
+  of tyOpenArray, tyVarargs:
+    linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)) #raiseIndexError();$n",
+            rdLoc(idx), rdLoc(arr))
+  of tyArray:
+    let first = intLiteral(firstOrd(ty))
+    if tfUncheckedArray notin ty.flags:
+      linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n",
+              rdCharLoc(idx), first, intLiteral(lastOrd(ty)))
+  of tySequence, tyString:
+    linefmt(p, cpsStmts,
+          "if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
+          rdLoc(idx), rdLoc(arr), lenField(p))
+  else: discard
+
 proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
   var a, b: TLoc
   initLocExpr(p, x, a)
diff --git a/compiler/seminst.nim b/compiler/seminst.nim
index 7fedaca5b..32b385308 100644
--- a/compiler/seminst.nim
+++ b/compiler/seminst.nim
@@ -346,7 +346,9 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
     if c.inGenericContext == 0:
       instantiateBody(c, n, fn.typ.n, result, fn)
     sideEffectsCheck(c, result)
-    paramsTypeCheck(c, result.typ)
+    if result.magic != mSlice:
+      # 'toOpenArray' is special and it is allowed to return 'openArray':
+      paramsTypeCheck(c, result.typ)
   else:
     result = oldPrc
   popProcCon(c)
diff --git a/lib/system.nim b/lib/system.nim
index 7a8c81666..7116f8818 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -4131,3 +4131,13 @@ when defined(cpp) and appType != "lib" and not defined(js) and
     stderr.write trace & "Error: unhandled exception: " & ex.msg &
                  " [" & $ex.name & "]\n"
     quit 1
+
+when not defined(js):
+  proc toOpenArray*[T](x: seq[T]; first, last: int): openarray[T] {.
+    magic: "Slice".}
+  proc toOpenArray*[T](x: openarray[T]; first, last: int): openarray[T] {.
+    magic: "Slice".}
+  proc toOpenArray*[I, T](x: array[I, T]; first, last: I): openarray[T] {.
+    magic: "Slice".}
+  proc toOpenArray*(x: string; first, last: int): openarray[char] {.
+    magic: "Slice".}
diff --git a/tests/system/tsystem_misc.nim b/tests/system/tsystem_misc.nim
index ce36895a1..85228e9e7 100644
--- a/tests/system/tsystem_misc.nim
+++ b/tests/system/tsystem_misc.nim
@@ -1,5 +1,17 @@
 discard """
-  output:""
+  output:'''1
+1
+2
+3
+11
+12
+13
+14
+15
+2
+3
+4
+'''
 """
 
 # check high/low implementations
@@ -20,3 +32,18 @@ doAssert high(float64) > low(float64)
 # bug #6710
 var s = @[1]
 s.delete(0)
+
+
+proc foo(a: openArray[int]) =
+  for x in a: echo x
+
+foo(toOpenArray([1, 2, 3], 0, 0))
+
+foo(toOpenArray([1, 2, 3], 0, 2))
+
+var arr: array[8..12, int] = [11, 12, 13, 14, 15]
+
+foo(toOpenArray(arr, 8, 12))
+
+var seqq = @[1, 2, 3, 4, 5]
+foo(toOpenArray(seqq, 1, 3))