1 ///
2 module dpq.smartptr;
3 
4 import dpq.exception;
5 
6 version(unittest)
7 {
8 	int nFrees = 0;
9 	void fakeFree(T)(T* val)
10 	{
11 		++nFrees;
12 	}
13 }
14 
15 class SmartPointer(T, alias _free)
16 {
17 	private T _ptr;
18 
19 	alias get this;
20 
21 	this()
22 	{
23 		_ptr = null;
24 	}
25 
26 	this(T ptr)
27 	{
28 		_ptr = ptr;
29 	}
30 
31 	~this()
32 	{
33 		clear();
34 	}
35 
36 	@property T get()
37 	{
38 		if (_ptr == null)
39 			throw new DPQException("get called on a null SmartPointer!(" ~ T.stringof ~ ")");
40 		return _ptr;
41 	}
42 
43 	@property bool isNull()
44 	{
45 		return _ptr == null;
46 	}
47 
48 	void opAssign(typeof(null) n)
49 	{
50 		clear();
51 	}
52 
53 	void opAssign(T ptr)
54 	{
55 		if (ptr == _ptr)
56 			return;
57 
58 		clear();
59 		_ptr = ptr;
60 	}
61 
62 	void clear()
63 	{
64 		if (_ptr == null)
65 			return;
66 
67 		_free(_ptr);
68 
69 		_ptr = null;
70 	}
71 }
72 
73 unittest
74 {
75 	import std.stdio;
76 
77 	writeln(" * SmartPointer");
78 
79 	alias Ptr = SmartPointer!(ubyte*, fakeFree);
80 
81 	ubyte* p = new ubyte;
82 	*p = 2;
83 	auto sp = new Ptr;
84 
85 	assert(sp._ptr == null);
86 
87 	sp = p;
88 	assert(sp._ptr == p);
89 
90 	// assign the same ptr
91 	sp = p;
92 	assert(nFrees == 0);
93 	assert(!sp.isNull);
94 	assert(sp._ptr == p);
95 
96 	ubyte* p2 = new ubyte;
97 	*p2 = 255;
98 
99 	sp = p2;
100 	assert(nFrees == 1);
101 	assert(sp._ptr == p2);
102 
103 	sp = new Ptr(p2);
104 	assert(sp._ptr == p2);
105 
106 	sp.clear();
107 	assert(sp.isNull);
108 	assert(sp._ptr == null);
109 }
110