Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- module parameter;
- import std.stdio;
- import std.algorithm;
- import std.traits;
- import std.meta;
- import std.conv;
- interface IParameter
- {
- void toString(scope void delegate(const(char)[]) sink) const;
- @property string[] members();
- @property size_t length();
- IParameter opIndex(size_t i);
- IParameter opIndex(string memberName);
- /* Pointer to Parameter */
- @property void* ptr();
- /* Byte size of Parameter */
- @property size_t byteSize();
- T to(T)()
- {
- assert(byteSize == T.sizeof);
- return *cast(T*)(ptr);
- }
- }
- template Parameter(T)
- {
- static if (isArray!T && !is(T : string))
- alias TypeNonArray = ArrayElementType!T;
- else
- alias TypeNonArray = T;
- // Find members
- static if (!isBasicType!T && !isArray!T)
- {
- // Find all getter functions
- template AllMemberFunctions(T)
- {
- template createDg(alias fn)
- {
- // skip bitfield setters
- static if (Parameters!fn.length > 0)
- alias createDg = AliasSeq!();
- else static if (__traits(isStaticFunction, fn))
- alias createDg = fn;
- else
- ReturnType!fn createDg(ref T ctx, Parameters!fn args)
- {
- ReturnType!fn delegate(Parameters!fn) fun;
- fun.funcptr = &fn;
- fun.ptr = cast(void*)&ctx;
- return fun(args);
- }
- }
- template GetOverloads(string name)
- {
- static if (is(typeof(__traits(getOverloads, T, name))))
- {
- alias GetOverloads = AliasSeq!(__traits(getOverloads, T, name));
- }
- else
- alias GetOverloads = AliasSeq!();
- }
- alias AllMemberFunctions = staticMap!(createDg,
- staticMap!(GetOverloads, __traits(allMembers, T)));
- }
- // Create a map which maps 'Unfolded' to AllFields or Funcs/funcNames
- // with j = MemberMap[i] where 0 <= i < Unfolded.length
- // then
- // if j >= AllFields.length
- // then member: Funcs[j - AllFields.length]
- // else member: AllFields[j]
- template GetMemberMap(int i, alias fields, string[] funcNames,
- string[] AllFields)
- {
- template GetIndex(alias field)
- {
- import std.algorithm : countUntil;
- static if (funcNames.canFind(field))
- alias GetIndex = Alias!(
- AllFields.length + funcNames.countUntil(field));
- else static if (AllFields.canFind(field))
- alias GetIndex = Alias!(
- AllFields.countUntil(field));
- else
- // alias GetIndex = Alias!(i);
- static assert(false);
- }
- static if (fields.length > 1)
- alias GetMemberMap = AliasSeq!(
- GetIndex!(fields[0]),
- GetMemberMap!(i+1, fields[1..$],
- funcNames, AllFields));
- else
- alias GetMemberMap = GetIndex!(fields[0]);
- }
- alias AllFields = FieldNameTuple!T;
- alias _allMemberNames = aliasSeqOf!([__traits(allMembers, T)]);
- alias _funcMembers = Filter!(isFunction, staticMap!(GetMember, _allMemberNames));
- alias _funcNames = staticMap!(GetMemberName, _funcMembers);
- alias Funcs = AllMemberFunctions!T;
- alias Unfolded = UnfoldMembers!T;
- alias MemberMap = GetMemberMap!(0, [Unfolded],
- [_funcNames], [AllFields]);
- }
- else
- {
- alias Unfolded = AliasSeq!();
- }
- class Parameter : IParameter
- {
- private:
- T* _mtype;
- public:
- this(ref ubyte[] stream)
- {
- // TODO: some types have variable length "(<min>[:<max>])"
- // -> see how long stream is and check how often (N) type T
- // fits into stream?!
- static if (isArray!T)
- // because array should point to array
- this._mtype = cast(T*)(&stream);
- else
- // because T pointer should point to actual data of array
- this._mtype = cast(T*)(stream.ptr);
- }
- this(T inValue)
- {
- import core.memory : pureMalloc;
- this._mtype = cast(T*)pureMalloc(T.sizeof);
- import core.stdc.string : memcpy;
- memcpy(this._mtype, &inValue, T.sizeof);
- }
- void toString(scope void delegate(const(char)[]) sink) const
- {
- import std.conv : to;
- sink((*(this._mtype)).to!string);
- }
- @property string[] members()
- {
- static if (Unfolded.length == 0)
- return [];
- else
- return [Unfolded];
- }
- @property size_t length()
- {
- static if (isArray!T && !is(T : string))
- {
- return this._mtype.length;
- }
- else
- return Unfolded.length;
- }
- unittest
- {
- byte[3] b = [0x01, 0x02, 0x03];
- auto t = new Parameter!(byte[3])(b);
- assert(t.length == 3);
- }
- IParameter opIndex(size_t i)
- {
- assert(i < this.length);
- static if (!isBasicType!T && !isArray!T)
- {
- switch (i)
- {
- static foreach (index, trueIndex; MemberMap)
- {
- case index:
- {
- static if (MemberMap[index] >= AllFields.length)
- {
- switch (trueIndex - AllFields.length)
- {
- static foreach (j, fn; Funcs)
- {
- case j:
- return new Parameter!
- (ReturnType!fn)
- (fn(*(this._mtype)));
- }
- default:
- return null;
- }
- }
- else
- return new Parameter!
- (typeof(this._mtype.tupleof[MemberMap[index]]))
- (this._mtype.tupleof[MemberMap[index]]);
- }
- }
- default:
- return null;
- }
- }
- else static if (isArray!T)
- return new Parameter!(typeof(this._mtype[i]))(this._mtype[i]);
- else
- return null;
- }
- IParameter opIndex(string memberName)
- {
- static if (!isBasicType!T && !isArray!T)
- {
- auto idx = [Unfolded].countUntil(memberName);
- if (idx < 0)
- // not found
- return null;
- else
- return this[idx];
- }
- else
- return null;
- }
- @property void* ptr() { return cast(void*)(this._mtype); }
- @property size_t byteSize() { return T.sizeof; }
- T get() { return *(this._mtype); }
- }
- template GetMember(string memberName)
- {
- // in case memberName does not exist or is private/protected
- static if (is(typeof(__traits(getMember, T, memberName))))
- alias GetMember = Alias!(__traits(getMember, T, memberName));
- else
- alias GetMember = Alias!null;
- }
- import std.string : split;
- alias GetMemberName(alias member) = Alias!(fullyQualifiedName!(member).split('.')[$-1]);
- }
- unittest
- {
- ubyte[] stream = [104, 105];
- string streamstring = cast(string)stream;
- assert((new Parameter!(string)(stream)).get == streamstring);
- assert((new Parameter!(string)(streamstring)).get == streamstring);
- import std.bitmanip;
- struct F
- {
- uint one;
- mixin(bitfields!(bool, "field1", 1, uint, "field2", 7));
- }
- ubyte[] streami = nativeToLittleEndian(0x00000011) ~ cast(ubyte[])[0x05];
- F f = *cast(F*)(streami.ptr);
- assert(streami.length == 5);
- auto structType = new Parameter!F(streami);
- assert(structType[0].to!uint == f.one);
- assert(structType[1].to!bool == f.field1);
- assert(structType[2].to!uint == f.field2);
- assert(structType["one"].to!uint == f.one);
- }
- template ArrayElementType(T : T[])
- {
- alias T ArrayElementType;
- }
- // Returns all field members of struct T in order
- // If T contains bitfields it returns the bitfield fields as well
- template UnfoldMembers(T)
- {
- import std.range : drop;
- import std.string : split;
- template GetMember(string memberName)
- {
- // in case memberName does not exist or is private/protected
- static if (is(typeof(__traits(getMember, T, memberName))))
- alias GetMember = Alias!(__traits(getMember, T, memberName));
- else
- alias GetMember = Alias!null;
- }
- alias GetMemberName(alias member) = Alias!(fullyQualifiedName!(member).split('.')[$-1]);
- // Checks if Field is a bitfield member. If so unfolds
- // bitfield fields and returns them. Otherwise returns Field.
- // Strategy:
- // a bitfield member is named '_<field1>_<field2>_...'. Further,
- // T contains functions named '<field1>', '<field2>' in the same
- // order as they are listed in the bitfield member variable name.
- // -> Iterate over function names, if found in bitfield member string
- // add it to bitfieldMembers
- // => If bitfieldMembers == bitfield member (all bitfields
- // discovered) return them, otherwise return Field
- template GetBitfieldMembers(alias Field)
- {
- // Returns true if the function name can be found in Field
- template discoverBitfieldMembers(string funcName)
- {
- static if (Field.canFind(funcName))
- alias discoverBitfieldMembers = funcName;
- else
- alias discoverBitfieldMembers = Alias!"";
- }
- static if (Field[0] != '_')
- {
- alias GetBitfieldMembers = Field;
- }
- else
- {
- alias allMemberNames = aliasSeqOf!([__traits(allMembers, T)]);
- alias funcMembers = Filter!(isFunction, staticMap!(GetMember, allMemberNames));
- alias funcMemberNames = staticMap!(GetMemberName, funcMembers);
- alias bitfieldMembers = staticMap!(discoverBitfieldMembers,
- funcMemberNames);
- import std.array : join;
- static if (bitfieldMembers.length > 0 &&
- "_" ~ [bitfieldMembers].join("_") == Field)
- alias GetBitfieldMembers = bitfieldMembers;
- else
- alias GetBitfieldMembers = Field;
- }
- }
- alias AllFields = FieldNameTuple!T;
- alias UnfoldMembers = staticMap!(GetBitfieldMembers, AllFields);
- }
Add Comment
Please, Sign In to add comment