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 }