Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add std/smartptrs #17333

Closed
wants to merge 35 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
3273fd7
improve test coverage for isolation
ringabout Mar 8, 2021
b4fa432
a bit better
ringabout Mar 8, 2021
421cf08
Merge remote-tracking branch 'upstream/devel' into a141
ringabout Mar 9, 2021
ea5fe84
Merge remote-tracking branch 'upstream/devel' into a144
ringabout Mar 10, 2021
7b329bc
add std/smartptrs
ringabout Mar 11, 2021
4aae28e
more
ringabout Mar 11, 2021
b6af261
add comments
ringabout Mar 11, 2021
f9bf78d
add comments
ringabout Mar 11, 2021
5e3eb8d
up
ringabout Mar 11, 2021
57e18ad
add comment
ringabout Mar 11, 2021
162db95
Merge remote-tracking branch 'upstream/devel' into a147
ringabout Mar 19, 2021
120716f
Apply suggestions from code review
ringabout Mar 19, 2021
5566515
Merge branch 'a147' of https://github.com/xflywind/Nim into a147
ringabout Mar 19, 2021
6f30a8c
use doAssert
ringabout Mar 19, 2021
7992e60
smartptrs
ringabout Mar 19, 2021
ef0819e
add changelog
ringabout Mar 19, 2021
fe8b805
a bit more tests
ringabout Mar 19, 2021
546cfb9
add examples
ringabout Mar 21, 2021
d59eca6
disable freebsd
ringabout Mar 21, 2021
d62f0e2
Merge branch 'devel' into a147
ringabout Mar 21, 2021
5bbbdc5
disable copy instead of assign
ringabout Apr 5, 2021
8503a75
polish
ringabout Apr 5, 2021
2910418
fix
ringabout Apr 5, 2021
290097c
Apply suggestions from code review
ringabout Apr 5, 2021
9321cc6
Update lib/std/smartptrs.nim
Araq Apr 10, 2021
246bff5
Update lib/std/smartptrs.nim
Araq Apr 10, 2021
df0b217
Update lib/std/smartptrs.nim
Araq Apr 10, 2021
275887c
Update lib/std/smartptrs.nim
Araq Apr 10, 2021
abd5937
Update tests/stdlib/tsmartptrs.nim
ringabout Apr 10, 2021
7a85e22
Update lib/std/smartptrs.nim
ringabout Apr 10, 2021
6b7226a
Update lib/std/smartptrs.nim
ringabout Apr 10, 2021
fd9bdf5
Merge remote-tracking branch 'upstream/devel' into a147
ringabout Apr 11, 2021
56afd30
Merge branch 'a147' of https://github.com/xflywind/Nim into a147
ringabout Apr 11, 2021
9c9f915
better
ringabout Apr 11, 2021
3111c8c
remove deleter
ringabout Apr 20, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions lib/std/smartptrs.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#
#
# Nim's Runtime Library
# (c) Copyright 2020 Nim contributors
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.

ringabout marked this conversation as resolved.
Show resolved Hide resolved
## C++11 like Smart pointers. It always uses the shared allocator.
ringabout marked this conversation as resolved.
Show resolved Hide resolved


import std/isolation


type
UniquePtr*[T] = object
## Non copyable pointer to object T, exclusive ownership of the object.
ringabout marked this conversation as resolved.
Show resolved Hide resolved
val: ptr T

proc `=destroy`*[T](p: var UniquePtr[T]) =
if p.val != nil:
`=destroy`(p.val[])
when compileOption("threads"):
deallocShared(p.val)
else:
dealloc(p.val)

proc `=`*[T](dest: var UniquePtr[T], src: UniquePtr[T]) {.error.}

proc newUniquePtr*[T](val: sink Isolated[T]): UniquePtr[T] {.nodestroy.} =
ringabout marked this conversation as resolved.
Show resolved Hide resolved
when compileOption("threads"):
result.val = cast[ptr T](allocShared(sizeof(T)))
else:
result.val = cast[ptr T](alloc(sizeof(T)))
# thanks to '.nodestroy' we don't have to use allocShared0 here.
# This is compiled into a copyMem operation, no need for a sink
# here either.
result.val[] = val.extract
# no destructor call for 'val: sink T' here either.

converter convertUniquePtrToObj*[T](p: UniquePtr[T]): var T {.inline.} =
when compileOption("boundChecks"):
assert(p.val != nil, "deferencing nil unique pointer")
ringabout marked this conversation as resolved.
Show resolved Hide resolved
p.val[]

proc isNil*[T](p: UniquePtr[T]): bool {.inline.} =
p.val == nil

proc `[]`*[T](p: UniquePtr[T]): var T {.inline.} =
when compileOption("boundChecks"):
assert(p.val != nil, "deferencing nil unique pointer")
ringabout marked this conversation as resolved.
Show resolved Hide resolved
p.val[]

proc `$`*[T](p: UniquePtr[T]): string {.inline.} =
if p.val == nil: "UniquePtr[" & $T & "](nil)"
else: "UniquePtr[" & $T & "](" & $p.val[] & ")"
ringabout marked this conversation as resolved.
Show resolved Hide resolved

#------------------------------------------------------------------------------

type
SharedPtr*[T] = object
## Shared ownership reference counting pointer.
val: ptr tuple[value: T, atomicCounter: int]

proc `=destroy`*[T](p: var SharedPtr[T]) =
if p.val != nil:
if (when compileOption("threads"):
atomicLoadN(addr p.val[].atomicCounter, ATOMIC_CONSUME) == 0 else:
p.val[].atomicCounter == 0):
`=destroy`(p.val[])
when compileOption("threads"):
deallocShared(p.val)
else:
dealloc(p.val)
else:
when compileOption("threads"):
discard atomicDec(p.val[].atomicCounter)
else:
dec(p.val[].atomicCounter)

proc `=`*[T](dest: var SharedPtr[T], src: SharedPtr[T]) =
if src.val != nil:
when compileOption("threads"):
discard atomicInc(src.val[].atomicCounter)
else:
inc(src.val[].atomicCounter)
if dest.val != nil:
`=destroy`(dest)
dest.val = src.val

proc newSharedPtr*[T](val: sink Isolated[T]): SharedPtr[T] {.nodestroy.} =
ringabout marked this conversation as resolved.
Show resolved Hide resolved
ringabout marked this conversation as resolved.
Show resolved Hide resolved
when compileOption("threads"):
result.val = cast[typeof(result.val)](allocShared(sizeof(result.val[])))
else:
result.val = cast[typeof(result.val)](alloc(sizeof(result.val[])))
result.val.atomicCounter = 0
result.val.value = val.extract

converter convertSharedPtrToObj*[T](p: SharedPtr[T]): var T {.inline.} =
ringabout marked this conversation as resolved.
Show resolved Hide resolved
when compileOption("boundChecks"):
doAssert(p.val != nil, "deferencing nil shared pointer")
ringabout marked this conversation as resolved.
Show resolved Hide resolved
p.val.value

proc isNil*[T](p: SharedPtr[T]): bool {.inline.} =
p.val == nil

proc `[]`*[T](p: SharedPtr[T]): var T {.inline.} =
when compileOption("boundChecks"):
doAssert(p.val != nil, "deferencing nil shared pointer")
ringabout marked this conversation as resolved.
Show resolved Hide resolved
p.val.value

proc `$`*[T](p: SharedPtr[T]): string {.inline.} =
if p.val == nil: "SharedPtr[" & $T & "](nil)"
else: "SharedPtr[" & $T & "](" & $p.val.value & ")"
ringabout marked this conversation as resolved.
Show resolved Hide resolved

#------------------------------------------------------------------------------

type
ConstPtr*[T] = distinct SharedPtr[T]
## Distinct version of referencing counting smart pointer SharedPtr[T],
## which doesn't allow mutating underlying object.
ringabout marked this conversation as resolved.
Show resolved Hide resolved

proc newConstPtr*[T](val: sink Isolated[T]): ConstPtr[T] =
ConstPtr[T](newSharedPtr(val))

converter convertConstPtrToObj*[T](p: ConstPtr[T]): lent T {.inline.} =
SharedPtr[T](p).val.value

proc isNil*[T](p: ConstPtr[T]): bool {.inline.} =
SharedPtr[T](p).val == nil

proc `[]`*[T](p: ConstPtr[T]): lent T {.inline.} =
when compileOption("boundChecks"):
doAssert(SharedPtr[T](p).val != nil, "deferencing nil const pointer")
ringabout marked this conversation as resolved.
Show resolved Hide resolved
SharedPtr[T](p).val.value

proc `$`*[T](p: ConstPtr[T]): string {.inline.} =
if SharedPtr[T](p).val == nil: "ConstPtr[" & $T & "](nil)"
ringabout marked this conversation as resolved.
Show resolved Hide resolved
else: "ConstPtr[" & $T & "](" & $SharedPtr[T](p).val.value & ")"
51 changes: 51 additions & 0 deletions tests/stdlib/tsmartptrs.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import std/[unittest, smartptrs]

block: # UniquePtr[T] test
var a1: UniquePtr[float]
var a2 = newUniquePtr(isolate(0))
ringabout marked this conversation as resolved.
Show resolved Hide resolved

check:
$a1 == "UniquePtr[float](nil)"
a1.isNil == true
$a2 == "UniquePtr[int](0)"
a2.isNil == false
a2[] == 0

let a3 = move a2

check:
$a2 == "UniquePtr[int](nil)"
a2.isNil == true

$a3 == "UniquePtr[int](0)"
a3.isNil == false
a3[] == 0

block: # SharedPtr[T] test
var a1: SharedPtr[float]
let a2 = newSharedPtr(isolate(0))
ringabout marked this conversation as resolved.
Show resolved Hide resolved
let a3 = a2
check:
$a1 == "SharedPtr[float](nil)"
a1.isNil == true
$a2 == "SharedPtr[int](0)"
a2.isNil == false
a2[] == 0
$a3 == "SharedPtr[int](0)"
a3.isNil == false
a3[] == 0

block: # ConstPtr[T] test
var a1: ConstPtr[float]
let a2 = newConstPtr(isolate(0))
ringabout marked this conversation as resolved.
Show resolved Hide resolved
let a3 = a2

check:
$a1 == "ConstPtr[float](nil)"
a1.isNil == true
$a2 == "ConstPtr[int](0)"
a2.isNil == false
a2[] == 0
$a3 == "ConstPtr[int](0)"
a3.isNil == false
a3[] == 0