1 /** 2 Unique Pointers 3 4 Copyright: 5 Copyright © 2023-2025, Kitsunebi Games 6 Copyright © 2023-2025, Inochi2D Project 7 8 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 Authors: Luna Nielsen 10 */ 11 module nulib.memory.unique_ptr; 12 import nulib.memory.weak_ptr; 13 import nulib.memory.internal; 14 import numem.core.traits; 15 import numem; 16 17 public import numem.lifetime : nogc_move, move, moveTo; 18 19 /** 20 A unique pointer. 21 22 Unique pointers are a specialization of shared pointers, these pointers 23 can not be copied, only moved. $(D numem.core.lifetime) contains functions 24 for achieving moves. 25 26 You may borrow weak references from $(D unique_ptr), these weak references 27 may become invalid at $(I any) point, so make sure to check the state of the 28 object using $(D isValid). 29 30 Example: 31 --- 32 static 33 class A { } 34 35 auto p = unique_new!A(); 36 auto b = move(p); 37 38 assert(!p.isValid); 39 assert(b.isValid); 40 --- 41 42 43 Threadsafety: 44 The internal reference count kept by shared_ptr is $(B not) atomic. 45 As such you should take care with accessing the value and refcount 46 stored within. 47 48 See_Also: 49 $(D nulib.memory.shared_ptr.shared_ptr) 50 $(D nulib.memory.weak_ptr.weak_ptr) 51 */ 52 struct unique_ptr(T) { 53 @nogc: 54 private: 55 __refcount_t!(T)* ptr = null; 56 57 public: 58 alias value this; 59 60 /** 61 The value stored within the smart pointer. 62 */ 63 @property ref T value() @trusted nothrow { 64 return ptr.get(); 65 } 66 67 /** 68 Whether the smart pointer value is still valid. 69 */ 70 @property bool isValid() @trusted nothrow { 71 return ptr && ptr.strongrefs > 0 && ptr.ptr !is null; 72 } 73 74 /// Destructor. 75 ~this() @trusted { 76 if (ptr) { 77 ptr.release!true; 78 ptr = null; 79 } 80 } 81 82 /** 83 Constructs a shared_ptr with the given memory address. 84 */ 85 this()(Ref!T ptr) @system if(!is(Ref!T == typeof(this))) { 86 this.ptr = __refcount_t!(T).createNew(ptr); 87 } 88 89 /** 90 Disable copying. 91 */ 92 @disable this()(ref inout(typeof(this)) src); 93 @disable this(this); 94 95 /** 96 Borrows a weak reference from the shared pointer. 97 98 Returns: 99 A new weak pointer, pointing to the same storage as 100 the shared pointer. 101 */ 102 weak_ptr!T borrow() @trusted { 103 return weak_ptr!T(ptr); 104 } 105 106 /** 107 Post-move operator. 108 */ 109 void opPostMove(ref typeof(this) other) { 110 other.ptr = null; 111 } 112 } 113 114 /** 115 Creates a new unique pointer. 116 117 Params: 118 args = The arguments to pass to $(D T)'s constructor. 119 120 Returns: 121 A unique pointer pointing to the newly allocated object. 122 */ 123 unique_ptr!T unique_new(T, Args...)(Args args) @trusted { 124 auto ptr = unique_ptr!T(nogc_new!T(args)); 125 126 // NOTE: This extra retain is needed since we can't 127 // 128 ptr.ptr.retain!true; 129 return ptr; 130 } 131 132 @("unique_ptr") 133 unittest { 134 static 135 class A { } 136 137 auto p = unique_new!A(); 138 auto b = move(p); 139 140 assert(!p.isValid); 141 assert(b.isValid); 142 143 // p.ptr should be null. 144 assert(p.ptr is null); 145 146 // Move to nowhere, destroying it. 147 move(b); 148 assert(!b.isValid); 149 }