Skip to content

Commit 1d93430

Browse files
committed
added toOpenArray builtin for zero-copy slices; syntax sugar yet to come
1 parent 121b9e2 commit 1d93430

File tree

6 files changed

+84
-14
lines changed

6 files changed

+84
-14
lines changed

changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
- ``re.split`` now also supports the ``maxsplit`` parameter for consistency
1515
with ``strutils.split``.
16+
- Added ``system.toOpenArray`` in order to support zero-copy slicing
17+
operations. This is currently not yet available for the JavaScript target.
1618

1719
### Library changes
1820

compiler/ccgcalls.nim

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ proc isInCurrentFrame(p: BProc, n: PNode): bool =
8383
result = isInCurrentFrame(p, n.sons[0])
8484
else: discard
8585

86+
proc genIndexCheck(p: BProc; arr, idx: TLoc)
87+
8688
proc openArrayLoc(p: BProc, n: PNode): Rope =
8789
var a: TLoc
8890

@@ -93,18 +95,28 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
9395
initLocExpr(p, q[1], a)
9496
initLocExpr(p, q[2], b)
9597
initLocExpr(p, q[3], c)
96-
let fmt =
97-
case skipTypes(a.t, abstractVar+{tyPtr}).kind
98-
of tyOpenArray, tyVarargs, tyArray:
99-
"($1)+($2), ($3)-($2)+1"
100-
of tyString, tySequence:
101-
if skipTypes(n.typ, abstractInst).kind == tyVar and
102-
not compileToCpp(p.module):
103-
"(*$1)->data+($2), ($3)-($2)+1"
104-
else:
105-
"$1->data+($2), ($3)-($2)+1"
106-
else: (internalError("openArrayLoc: " & typeToString(a.t)); "")
107-
result = fmt % [rdLoc(a), rdLoc(b), rdLoc(c)]
98+
# but first produce the required index checks:
99+
if optBoundsCheck in p.options:
100+
genIndexCheck(p, a, b)
101+
genIndexCheck(p, a, c)
102+
let ty = skipTypes(a.t, abstractVar+{tyPtr})
103+
case ty.kind
104+
of tyArray:
105+
let first = firstOrd(ty)
106+
if first == 0:
107+
result = "($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)]
108+
else:
109+
result = "($1)+(($2)-($4)), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c), intLiteral(first)]
110+
of tyOpenArray, tyVarargs:
111+
result = "($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)]
112+
of tyString, tySequence:
113+
if skipTypes(n.typ, abstractInst).kind == tyVar and
114+
not compileToCpp(p.module):
115+
result = "(*$1)->data+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)]
116+
else:
117+
result = "$1->data+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)]
118+
else:
119+
internalError("openArrayLoc: " & typeToString(a.t))
108120
else:
109121
initLocExpr(p, n, a)
110122
case skipTypes(a.t, abstractVar).kind

compiler/ccgexprs.nim

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,23 @@ proc genCStringElem(p: BProc, n, x, y: PNode, d: var TLoc) =
880880
putIntoDest(p, d, n,
881881
rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)), a.storage)
882882

883+
proc genIndexCheck(p: BProc; arr, idx: TLoc) =
884+
let ty = skipTypes(arr.t, abstractVarRange)
885+
case ty.kind
886+
of tyOpenArray, tyVarargs:
887+
linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)) #raiseIndexError();$n",
888+
rdLoc(idx), rdLoc(arr))
889+
of tyArray:
890+
let first = intLiteral(firstOrd(ty))
891+
if tfUncheckedArray notin ty.flags:
892+
linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n",
893+
rdCharLoc(idx), first, intLiteral(lastOrd(ty)))
894+
of tySequence, tyString:
895+
linefmt(p, cpsStmts,
896+
"if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
897+
rdLoc(idx), rdLoc(arr), lenField(p))
898+
else: discard
899+
883900
proc genOpenArrayElem(p: BProc, n, x, y: PNode, d: var TLoc) =
884901
var a, b: TLoc
885902
initLocExpr(p, x, a)

compiler/seminst.nim

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,9 @@ proc generateInstance(c: PContext, fn: PSym, pt: TIdTable,
346346
if c.inGenericContext == 0:
347347
instantiateBody(c, n, fn.typ.n, result, fn)
348348
sideEffectsCheck(c, result)
349-
paramsTypeCheck(c, result.typ)
349+
if result.magic != mSlice:
350+
# 'toOpenArray' is special and it is allowed to return 'openArray':
351+
paramsTypeCheck(c, result.typ)
350352
else:
351353
result = oldPrc
352354
popProcCon(c)

lib/system.nim

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4131,3 +4131,13 @@ when defined(cpp) and appType != "lib" and not defined(js) and
41314131
stderr.write trace & "Error: unhandled exception: " & ex.msg &
41324132
" [" & $ex.name & "]\n"
41334133
quit 1
4134+
4135+
when not defined(js):
4136+
proc toOpenArray*[T](x: seq[T]; first, last: int): openarray[T] {.
4137+
magic: "Slice".}
4138+
proc toOpenArray*[T](x: openarray[T]; first, last: int): openarray[T] {.
4139+
magic: "Slice".}
4140+
proc toOpenArray*[I, T](x: array[I, T]; first, last: I): openarray[T] {.
4141+
magic: "Slice".}
4142+
proc toOpenArray*(x: string; first, last: int): openarray[char] {.
4143+
magic: "Slice".}

tests/system/tsystem_misc.nim

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
discard """
2-
output:""
2+
output:'''1
3+
1
4+
2
5+
3
6+
11
7+
12
8+
13
9+
14
10+
15
11+
2
12+
3
13+
4
14+
'''
315
"""
416

517
# check high/low implementations
@@ -20,3 +32,18 @@ doAssert high(float64) > low(float64)
2032
# bug #6710
2133
var s = @[1]
2234
s.delete(0)
35+
36+
37+
proc foo(a: openArray[int]) =
38+
for x in a: echo x
39+
40+
foo(toOpenArray([1, 2, 3], 0, 0))
41+
42+
foo(toOpenArray([1, 2, 3], 0, 2))
43+
44+
var arr: array[8..12, int] = [11, 12, 13, 14, 15]
45+
46+
foo(toOpenArray(arr, 8, 12))
47+
48+
var seqq = @[1, 2, 3, 4, 5]
49+
foo(toOpenArray(seqq, 1, 3))

0 commit comments

Comments
 (0)