1 /**
2 * D-LevelDB Slice
3 *
4 * Pointer Slice
5 *
6 * Copyright: Copyright © 2013 Byron Heads
7 * License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
8 * Authors: Byron Heads
9 */
10 /* Copyright © 2013 Byron Heads
11 * Distributed under the Boost Software License, Version 1.0.
12 * (See accompanying file LICENSE_1_0.txt or copy at
13 * http://www.boost.org/LICENSE_1_0.txt)
14 */
15 module leveldb.slice;
16
17 private import leveldb.exceptions;
18 private import std.traits : isArray, isStaticArray, isDynamicArray,
19 isPointer, isBasicType, ForeachType, isSomeString;
20 private import deimos.leveldb.leveldb : leveldb_free;
21
22 /**
23 * Holds a pointer returned from leveldb, or passed to leveldb.
24 *
25 * Leveldb memory is freed on destruction.
26 */
27 struct Slice
28 {
29 private:
30 bool free = false;
31 void* _ptr;
32 size_t len;
33
34 package:
35 /// Used by DB class to hold leveldb raw pointers
36 this(P = void*)(void* p, size_t l, bool free)
37 {
38 this.free = free;
39 _ptr = p;
40 len = l;
41 }
42
43 public:
44 /// Takes reference
45 this(P)(ref P p)
46 {
47 this(p._lib_obj_ptr__, p._lib_obj_size__);
48 }
49
50 this(P)(in P p)
51 if(!__traits(isRef, p))
52 {
53 this(p._lib_obj_ptr__, p._lib_obj_size__);
54 }
55
56 /// Takes reference
57 this(P)(P p, size_t l)
58 if(isPointer!P)
59 {
60 _ptr = cast(void*)p;
61 len = l;
62 }
63
64 /// Calles free on leveldb raw memory
65 ~this()
66 {
67 if(free)
68 leveldb_free(_ptr);
69 }
70
71 /// Get slice pointer
72 @property
73 inout(T) ptr(T)() inout
74 if(isPointer!T)
75 {
76 return cast(inout(T))_ptr;
77 }
78
79 alias ptr!(const(char*)) _lib_obj_ptr__;
80
81 /// Get slice as a data type
82 @property
83 inout(T) as(T)() inout
84 if(!isPointer!T && __traits(compiles, *(cast(inout(T*))_ptr)))
85 {
86 static if(isArray!T)
87 return cast(inout(T))(cast(char[])(_ptr)[0..length]);
88 else static if(is(T == class))
89 {
90 if(typeid(T).sizeof > length)
91 throw new LeveldbException("Casting size is larger then slice data");
92 return *(cast(inout(T*))_ptr);
93 }
94 else
95 {
96 if(T.sizeof > length)
97 throw new LeveldbException("Casting size is larger then slice data");
98 return *(cast(inout(T*))_ptr);
99 }
100 }
101
102 alias as to;
103
104 /// length or size of slice
105 @property
106 size_t length() inout
107 {
108 return len;
109 }
110 alias length _lib_obj_size__;
111
112 /// Test is slice is valid
113 @property
114 bool ok() inout
115 {
116 return _ptr !is null;
117 }
118
119 /// Slice casting
120 inout(T) opCast(T)() inout
121 {
122 static if(isPointer!T)
123 return ptr!T;
124 else
125 return as!T;
126 }
127
128 /// Create a safe refrence for slicing, good for primitive type constants
129 static Slice Ref(T)(T t)
130 {
131 align(1) static struct Ref{ T t; }
132 return Slice(new Ref(t), T.sizeof);
133 }
134 }
135
136 package:
137
138 /// Find the byte size of a valid Slice type
139 size_t _lib_obj_size__(P)(in P p)
140 if(isSomeString!P || ((isStaticArray!P || isDynamicArray!P) && !isBanned!(ForeachType!P)))
141 {
142 return p.length ? p[0].sizeof * p.length : 0;
143 }
144
145 /// Find the byte size of a valid Slice type
146 size_t _lib_obj_size__(P)(in P p)
147 if(isBasicType!P || isPODStruct!P)
148 {
149 return P.sizeof;
150 }
151
152 /// Find the byte size of a valid Slice type
153 size_t _lib_obj_size__(P)(in P p)
154 if(isPointer!P)
155 {
156 return _lib_obj_size__(*p);
157 }
158
159 /// Find the pointer of a valid Slice type
160 const(char)* _lib_obj_ptr__(P)(ref P p)
161 {
162 static if((isArray!P && !isBanned!(ForeachType!P)))
163 return cast(const(char*))p.ptr;
164 else static if(isBasicType!P || isPODStruct!P)
165 return cast(const(char*))(&p);
166 else static if(isPointer!P)
167 return _lib_obj_ptr__(*p);
168 else assert(false, "Not a valid type for leveldb slice: ref " ~ typeof(p).stringof);
169 }
170
171 template isBanned(T)
172 {
173 static if(is(T == class) || isDynamicArray!T || isPointer!T)
174 enum isBanned = true;
175 else
176 enum isBanned = false;
177 }
178
179 template isPODStruct(T)
180 {
181 static if(is(T == struct))
182 enum isPODStruct = __traits(isPOD, T);
183 else
184 enum isPODStruct = false;
185 }
186
187 unittest
188 {
189 assert(_lib_obj_size__("1234567890") == 10);
190 assert(_lib_obj_size__("1234") == 4);
191 int i = 123567;
192 assert(_lib_obj_size__(i) == int.sizeof);
193 long l = 123567;
194 assert(_lib_obj_size__(l) == long.sizeof);
195 double d = 123567;
196 assert(_lib_obj_size__(d) == double.sizeof);
197 }
198
199 unittest
200 {
201 auto s = "Hello";
202 auto s1 = Slice(s);
203 assert(s1);
204 assert(s1.ok);
205 assert(s1.length == 5);
206 assert(s1.ptr!(const(char*)) == s.ptr);
207 assert(s1.length == s.length);
208 assert(s1.as!string == s);
209 }
210
211 unittest
212 {
213 auto s = "Hello World";
214 auto s1 = Slice(s[0..5]);
215 assert(s1.ok);
216 assert(s1.length == 5);
217 assert(s1.ptr!(const(char*)) == s.ptr);
218 assert(s1.length == s[0..5].length);
219 assert(s1.as!string == s[0..5]);
220 }
221
222 unittest
223 {
224 int s = 454;
225 auto s1 = Slice(s);
226 assert(s1.ok);
227 assert(s1.length == int.sizeof);
228 assert(s1.length == s.sizeof);
229 assert(s1.ptr!(int*) == &s);
230 assert(s1.as!int == s);
231 }
232
233 unittest
234 {
235 struct Point(T)
236 {
237 T x, y;
238 }
239
240 auto p1 = Point!int(1, 2);
241 auto s = Slice(p1);
242 assert(s.ok);
243 assert(s.length == int.sizeof * 2);
244 assert(s.as!(Point!int).x == 1);
245 assert(s.as!(Point!int).y == 2);
246 try
247 {
248 s.as!(Point!long);
249 assert(false, "Should have thrown");
250 }catch(LeveldbException e)
251 {}
252 catch(Exception e)
253 {
254 assert(false, "Should have thrown a LeveldbException");
255 }
256
257 s = Slice(new Point!real(10, 12));
258 assert(s.length == real.sizeof * 2);
259 }
260
261
262
263 unittest
264 {
265 align(1) struct Ref(T) { T t; }
266 auto s1 = Slice(new Ref!int(451), 4);
267 assert(s1.ok);
268 assert(s1.length == int.sizeof);
269 assert(s1.as!int == 451);
270
271 /// Make a safe constant slice
272 s1 = Slice.Ref(999);
273 assert(s1.ok);
274 assert(s1.length == int.sizeof);
275 assert(s1.as!int == 999);
276 }