1 module dhdf5.dataspec; 2 3 import std.traits : isStaticArray, isDynamicArray; 4 import std..string: toStringz; 5 6 private 7 { 8 import std.typetuple : TypeTuple, staticIndexOf; 9 import std.traits : Unqual; 10 import std.range : isInputRange; 11 12 // bool is special type and is processed like enum 13 alias AllowedTypes = TypeTuple!(float, int, double, char, uint, long, ulong, short, ubyte, ushort); 14 enum string[] VectorHdf5Types = 15 [ 16 "H5T_NATIVE_FLOAT", 17 "H5T_NATIVE_INT", 18 "H5T_NATIVE_DOUBLE", 19 "H5T_NATIVE_B8", 20 "H5T_NATIVE_B32", 21 "H5T_NATIVE_LONG", 22 "H5T_NATIVE_B64", 23 "H5T_NATIVE_SHORT", 24 "H5T_NATIVE_UCHAR", 25 "H5T_NATIVE_USHORT", 26 ]; 27 28 template typeToHdf5Type(T) 29 { 30 alias U = Unqual!T; 31 enum index = staticIndexOf!(U, AllowedTypes); 32 static if (index == -1) 33 { 34 static assert(false, "Could not use " ~ T.stringof ~ ", there is no corresponding hdf5 data type"); 35 } 36 else 37 { 38 enum typeToHdf5Type = VectorHdf5Types[index]; 39 } 40 } 41 } 42 43 auto countDimensions(T)() if(isStaticArray!T) 44 { 45 Unqual!T t; 46 47 size_t[] dim; 48 49 auto countDimensionsImpl(R)() 50 { 51 Unqual!R r; 52 dim ~= R.length; 53 static if(isStaticArray!(typeof(r[0]))) 54 { 55 return countDimensionsImpl!(typeof(r[0])); 56 } 57 else 58 { 59 return dim; 60 } 61 } 62 63 return countDimensionsImpl!T; 64 } 65 66 auto countDimensions(T)() if(isInputRange!T) 67 { 68 import hdf5.hdf5 : H5S_UNLIMITED; 69 70 size_t[] dim; 71 72 auto countDimensionsImpl(R)() 73 { 74 R r; 75 76 dim ~= H5S_UNLIMITED; 77 static if(isDynamicArray!(typeof(r[0]))) 78 { 79 return countDimensionsImpl!(typeof(r[0]))(r[0]); 80 } 81 else 82 { 83 return dim; 84 } 85 } 86 87 return countDimensionsImpl!T; 88 } 89 90 auto countDimensions(T)(T t) if(isDynamicArray!T) 91 { 92 size_t[] dim; 93 94 auto countDimensionsImpl(R)(R r) 95 { 96 dim ~= r.length; 97 static if(isDynamicArray!(typeof(r[0]))) 98 { 99 return countDimensionsImpl!(typeof(r[0]))(r[0]); 100 } 101 else 102 { 103 return dim; 104 } 105 } 106 107 return countDimensionsImpl(t); 108 } 109 110 /// Used as UDA to disable a field of struct of class 111 struct HDF5disable 112 { 113 114 } 115 116 struct DataAttribute 117 { 118 import hdf5.hdf5 : hid_t; 119 120 hid_t type; 121 size_t offset; 122 string varName; 123 } 124 125 struct DataSpecification(Data) 126 { 127 import std.traits : isArray, isScalarType, ForeachType, FieldTypeTuple, 128 FieldNameTuple; 129 import std.range : ElementType; 130 import std.typecons : RefCounted; 131 import hdf5.hdf5; 132 133 alias DataType = Data; 134 135 private static makeImpl(S)() if(is(S == struct)) 136 { 137 DataAttribute[] attributes; 138 139 template isDisabled(TP...) 140 { 141 auto isDisabledImpl() 142 { 143 bool disabled = false; 144 foreach(t; TP) 145 { 146 static if(t == "HDF5disabled") 147 { 148 disabled = true; 149 break; 150 } 151 } 152 153 return disabled; 154 } 155 156 enum isDisabled = isDisabledImpl(); 157 } 158 159 // Создаем атрибуты 160 hid_t createStruct(D)(ref DataAttribute[] attributes) if(is(D == struct)) 161 { 162 import std.traits : OriginalType; 163 164 alias TT = FieldTypeTuple!D; 165 166 auto tid = H5Tcreate (H5T_class_t.H5T_COMPOUND, D.sizeof); 167 168 foreach (member; FieldNameTuple!D) 169 { 170 enum fullName = "D." ~ member; 171 enum hdf5Name = (Unqual!D).stringof ~ "." ~ member; 172 173 mixin("alias T = typeof(" ~ fullName ~ ");"); 174 175 static if (staticIndexOf!(T, TT) != -1) 176 { 177 mixin("alias A = " ~ fullName ~";"); 178 alias TP = TypeTuple!(__traits(getAttributes, A)); 179 enum disabled = isDisabled!TP; // check if field is disabled using UDA 180 181 static if(disabled) 182 { 183 184 } 185 else 186 static if(is(T == bool)) 187 { 188 // TODO Don't know wouldn't it be better if bool enum were created 189 // once per library in static this()? 190 191 // Create enum type 192 hid_t hdf5Type = H5Tenum_create (H5T_NATIVE_INT); 193 194 auto val = 0; 195 auto status = H5Tenum_insert (hdf5Type, "false", &val); 196 assert(status >= 0); 197 198 val = 1; 199 status = H5Tenum_insert (hdf5Type, "true", &val); 200 assert(status >= 0); 201 } 202 else 203 static if(is(T == enum)) 204 { 205 static assert(is(T : int), "hdf5 supports only enumeration based on integer type."); 206 // Create enum type 207 alias BaseEnumType = OriginalType!T; 208 mixin("hid_t hdf5Type = H5Tenum_create (" ~ typeToHdf5Type!BaseEnumType ~ ");"); 209 210 foreach (size_t cnt, enumMember; __traits(allMembers, T)) 211 { 212 auto val = cnt; 213 auto status = H5Tenum_insert (hdf5Type, (T.stringof ~ "." ~ enumMember).toStringz, &val); 214 assert(status >= 0); 215 } 216 } 217 else static if(isStaticArray!T) 218 { 219 alias ElemType = ForeachType!T; 220 static if(is(ElemType == struct)) 221 { 222 import std.conv: castFrom; 223 224 DataAttribute[] da; 225 auto elemType = createStruct!ElemType(da); 226 insertAttributes(elemType, da); 227 //hid_t hdf5Type = H5Tvlen_create (elemType); 228 alias dim = countDimensions!T; 229 //mixin("hid_t hdf5Type = H5Tarray_create2 (" ~ typeToHdf5Type!ElemType ~ ", " ~ dim.length.text ~ ", dim.ptr);"); 230 hid_t hdf5Type = H5Tarray_create2 (elemType, castFrom!size_t.to!uint(dim.length), dim.ptr); 231 } 232 else 233 { 234 import std.conv: text; 235 236 alias dim = countDimensions!T; 237 mixin("hid_t hdf5Type = H5Tarray_create2 (" ~ typeToHdf5Type!ElemType ~ ", " ~ dim.length.text ~ ", dim.ptr);"); 238 } 239 } 240 else static if(isDynamicArray!T) 241 { 242 alias ElemType = ElementType!T; 243 static if(is(ElemType == struct)) 244 { 245 DataAttribute[] da; 246 auto elemType = createStruct!ElemType(da); 247 insertAttributes(elemType, da); 248 hid_t hdf5Type = H5Tvlen_create (elemType); 249 } 250 else 251 mixin("hid_t hdf5Type = H5Tvlen_create (" ~ typeToHdf5Type!(ForeachType!T) ~ ");"); 252 } 253 else static if(is(T == struct)) 254 { 255 DataAttribute[] da; 256 auto hdf5Type = createStruct!T(da); 257 258 insertAttributes(hdf5Type, da); 259 } 260 else 261 { 262 mixin("hid_t hdf5Type = " ~ typeToHdf5Type!T ~ ";"); 263 } 264 265 static if(!disabled) 266 { 267 // Add the attribute 268 mixin("string varName = \"" ~ hdf5Name ~ "\";"); 269 mixin("enum offset = D." ~ member ~ ".offsetof;"); 270 attributes ~= DataAttribute(hdf5Type, offset, varName); 271 } 272 } 273 } 274 275 return tid; 276 } 277 278 // Insert attributes of the structure into the datatype 279 auto insertAttributes(hid_t hdf5Type, DataAttribute[] da) 280 { 281 import hdf5.hdf5 : H5Tinsert; 282 283 foreach(attr; da) 284 { 285 auto status = H5Tinsert(hdf5Type, attr.varName.toStringz, attr.offset, attr.type); 286 assert(status >= 0); 287 } 288 } 289 290 auto tid = createStruct!S(attributes); 291 292 insertAttributes(tid, attributes); 293 294 return RefCounted!(DataSpecification!S)(tid, attributes); 295 } 296 297 private static makeImpl(D)() if(isScalarType!D) 298 { 299 mixin("hid_t tid = " ~ typeToHdf5Type!D ~ ";"); 300 301 return RefCounted!(DataSpecification!D)(tid, (DataAttribute[]).init); 302 } 303 304 private static makeImpl(D)() if(isStaticArray!D) 305 { 306 import std.conv: text; 307 308 alias ElemType = ForeachType!D; 309 310 alias dim = countDimensions!D; 311 mixin("hid_t tid = H5Tarray_create2 (" ~ typeToHdf5Type!(ElemType) ~ ", " ~ dim.length.text ~ ", dim.ptr);"); 312 return RefCounted!(DataSpecification!D)(tid, (DataAttribute[]).init); 313 } 314 315 private static makeImpl(D)() if(isDynamicArray!D) 316 { 317 alias ElemType = ForeachType!D; 318 319 mixin("hid_t tid = H5Tvlen_create (" ~ typeToHdf5Type!(ElemType) ~ ");"); 320 return RefCounted!(DataSpecification!D)(tid, (DataAttribute[]).init); 321 } 322 323 static make() 324 { 325 import std.range : isInputRange; 326 static if(isInputRange!Data) // if "outer" type of data is an input range it's processed, 327 // on Dataset level so skip it 328 { 329 return makeImpl!(ForeachType!Data); 330 } 331 else 332 { 333 return makeImpl!(Data); 334 } 335 } 336 337 this(const(hid_t) tid, DataAttribute[] attributes) 338 { 339 _tid = tid; 340 _attributes = attributes; 341 } 342 343 ~this() 344 { 345 static if(is(Data == struct)) 346 { 347 H5Tclose(_tid); 348 } 349 else 350 static if(isScalarType!Data) 351 { 352 // do nothing because built-in type is used(?) 353 } 354 } 355 356 auto tid() const 357 { 358 return _tid; 359 } 360 361 private: 362 DataAttribute[] _attributes; 363 immutable hid_t _tid = -1; 364 }