positional: ensure compile-time setter deduction, add new type-generic initializator syntax
This commit is contained in:
parent
0ba723f71c
commit
fad96fab0d
1 changed files with 111 additions and 74 deletions
185
positional_utl.h
185
positional_utl.h
|
@ -34,7 +34,13 @@ template <class T>
|
|||
struct ClearType_w<const T&> { typedef T tp; };
|
||||
#define ClearType(x) ClearType_w<x>::tp
|
||||
#define ClearValType(x) typename ClearType_w<decltype(x)>::tp
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define _inl __attribute__((always_inline))
|
||||
#elif __MSC_VER
|
||||
#define _inl __attribute__((always_inline))
|
||||
#else
|
||||
#define _inl __forceinline
|
||||
#endif
|
||||
// Positional arguments? Im my C++? It's more likely than you think!
|
||||
enum SetterOperation
|
||||
{
|
||||
|
@ -59,7 +65,7 @@ struct SetterVal // keeps val reference and SetterFunc wrapper
|
|||
constexpr static SetterOperation op = o;
|
||||
const Setter<T> &member;
|
||||
const V& val;
|
||||
SetterVal(const Setter<T> &m, const V &v) : member(m), val(v){}
|
||||
constexpr _inl SetterVal(const Setter<T> &m, const V &v) : member(m), val(v){}
|
||||
};
|
||||
template<typename T, typename V>
|
||||
struct SetterValPtr // keeps val reference and SetterFunc wrapper
|
||||
|
@ -67,7 +73,7 @@ struct SetterValPtr // keeps val reference and SetterFunc wrapper
|
|||
constexpr static SetterOperation op = AssignVal;
|
||||
const Setter<T> &member;
|
||||
const V *val;
|
||||
SetterValPtr(const Setter<T> &m, const V *v) : member(m), val(v){}
|
||||
constexpr _inl SetterValPtr(const Setter<T> &m, const V *v) : member(m), val(v){}
|
||||
};
|
||||
/* Delayed function call (maybe useless)
|
||||
* struct aaa{
|
||||
|
@ -79,12 +85,12 @@ template <typename T, typename... Ts>
|
|||
struct ArgumentList : ArgumentList<Ts...>
|
||||
{
|
||||
const T &v;
|
||||
ArgumentList(const T &t, const Ts&... a) : v(t), ArgumentList<Ts...>(a...){}
|
||||
template<typename Func, typename I, typename... Ts2> void CallMember(Func f, I &i, const Ts2&... ts) const
|
||||
_inl ArgumentList(const T &t, const Ts&... a) : v(t), ArgumentList<Ts...>(a...){}
|
||||
template<typename Func, typename I, typename... Ts2> _inl void CallMember(Func f, I &i, const Ts2&... ts) const
|
||||
{
|
||||
ArgumentList<Ts...>::CallMember(f, i,ts..., v);
|
||||
}
|
||||
template<typename Func, typename I, typename... Ts2> void CallCtx(Func f, I &i, const Ts2&... ts) const
|
||||
template<typename Func, typename I, typename... Ts2> _inl void CallCtx(Func f, I &i, const Ts2&... ts) const
|
||||
{
|
||||
ArgumentList<Ts...>::CallCtx(f, i,ts..., v);
|
||||
}
|
||||
|
@ -94,12 +100,12 @@ template <typename T>
|
|||
struct ArgumentList<T>
|
||||
{
|
||||
const T &v;
|
||||
ArgumentList(const T &t) : v(t){}
|
||||
template<typename Func, typename I, typename... Ts2> void CallMember(Func f, I &i, const Ts2&... ts) const
|
||||
_inl ArgumentList(const T &t) : v(t){}
|
||||
template<typename Func, typename I, typename... Ts2> _inl void CallMember(Func f, I &i, const Ts2&... ts) const
|
||||
{
|
||||
(i.*f)(ts..., v);
|
||||
}
|
||||
template<typename Func, typename I, typename... Ts2> void CallCtx(Func f, I &i, const Ts2&... ts) const
|
||||
template<typename Func, typename I, typename... Ts2> _inl void CallCtx(Func f, I &i, const Ts2&... ts) const
|
||||
{
|
||||
f(i,ts...,v);
|
||||
}
|
||||
|
@ -111,14 +117,14 @@ struct SetterFunc // keeps val reference and SetterFunc wrapper
|
|||
constexpr static SetterOperation op = CallMethod;
|
||||
const Setter<T> &func;
|
||||
ArgumentList<Vs... > vals;
|
||||
SetterFunc(const Setter<T> &f, const Vs&... vs) : func(f), vals(vs...) {}
|
||||
constexpr _inl SetterFunc(const Setter<T> &f, const Vs&... vs) : func(f), vals(vs...) {}
|
||||
};
|
||||
|
||||
// container for updating vals
|
||||
template <typename T>
|
||||
struct ObjectUpdater:T
|
||||
{
|
||||
ObjectUpdater(const T& t): T(t){}
|
||||
constexpr _inl ObjectUpdater(const T& t): T(t){}
|
||||
};
|
||||
|
||||
#define Vals(...) ObjectUpdater([&](auto &s){ $F(s,__VA_ARGS__);})
|
||||
|
@ -132,7 +138,7 @@ struct SetterArrayVal // keeps val reference and SetterFunc wrapper
|
|||
constexpr static SetterOperation op = O;
|
||||
const SetterArray<T,T1> &arr;
|
||||
const V &val;
|
||||
SetterArrayVal(const SetterArray<T, T1> &f, const V &v) : arr(f), val(v){}
|
||||
constexpr _inl SetterArrayVal(const SetterArray<T, T1> &f, const V &v) : arr(f), val(v){}
|
||||
};
|
||||
|
||||
template<typename T, typename T1>
|
||||
|
@ -141,8 +147,8 @@ struct SetterArray // keeps val reference and SetterFunc wrapper
|
|||
const Setter<T> &member;
|
||||
const Setter<T1> &count;
|
||||
template <typename V>
|
||||
SetterArrayVal<T,T1,V> operator= (const V &v) {return SetterArrayVal<T,T1,V>(*this,v);}
|
||||
SetterArray(const Setter<T> &m, const Setter<T1> &c) : member(m), count(c) {}
|
||||
constexpr _inl SetterArrayVal<T,T1,V> operator= (const V &v) const {return SetterArrayVal<T,T1,V>(*this,v);}
|
||||
constexpr _inl SetterArray(const Setter<T> &m, const Setter<T1> &c) : member(m), count(c) {}
|
||||
};
|
||||
template<typename T>
|
||||
struct SetterArrayIndex;
|
||||
|
@ -152,7 +158,7 @@ struct SetterArrayIndexVal // keeps val reference and SetterFunc wrapper
|
|||
constexpr static SetterOperation op = AssignArrayByIndex;
|
||||
const SetterArrayIndex<T> &arr;
|
||||
const V &val;
|
||||
SetterArrayIndexVal(const SetterArrayIndex<T> &f, const V &v) : arr(f), val(v){}
|
||||
constexpr _inl SetterArrayIndexVal(const SetterArrayIndex<T> &f, const V &v) : arr(f), val(v){}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
|
@ -161,22 +167,22 @@ struct SetterArrayIndex // keeps val reference and SetterFunc wrapper
|
|||
const Setter<T> &member;
|
||||
const int idx;
|
||||
template <typename V>
|
||||
SetterArrayIndexVal<T,V> operator= (const V &v) {return SetterArrayIndexVal<T,V>(*this,v);}
|
||||
SetterArrayIndex(const Setter<T> &m, const int i) : member(m), idx(i) {}
|
||||
_inl SetterArrayIndexVal<T,V> operator= (const V &v) const {return SetterArrayIndexVal<T,V>(*this,v);}
|
||||
constexpr _inl SetterArrayIndex(const Setter<T> &m, const int i) : member(m), idx(i) {}
|
||||
};
|
||||
// todo: sync with other utilities...
|
||||
template <typename T, uint32_t cnt>
|
||||
template <typename T, unsigned int cnt>
|
||||
struct Array
|
||||
{
|
||||
T array[cnt];
|
||||
constexpr static uint32_t count = cnt;
|
||||
constexpr static unsigned int count = cnt;
|
||||
};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct ArrayInitializer
|
||||
{
|
||||
T array[sizeof... (Args)];
|
||||
constexpr static uint32_t count = sizeof... (Args);
|
||||
constexpr static unsigned int count = sizeof... (Args);
|
||||
};
|
||||
#define ARRAY_WRAPPER(x,y) template <typename... Args> Array<x, sizeof... (Args)> y(const Args&... arguments) { return {arguments...};}
|
||||
template <typename T0, typename... Ts>
|
||||
|
@ -190,73 +196,87 @@ struct Setter // keeps member pointer getter, wrapper for user-provided lambda
|
|||
{
|
||||
constexpr static SetterOperation op = SetTrue;
|
||||
const T &func;
|
||||
Setter(const T &data) :func(data){}
|
||||
inline _inl constexpr Setter(const T &data) :func(data){}
|
||||
template <typename T1>
|
||||
SetterVal<T,T1,AssignObject> operator = (const ObjectUpdater<T1>& v) {return SetterVal<T,T1,AssignObject>(*this,v);}
|
||||
_inl SetterVal<T,T1,AssignObject> operator = (const ObjectUpdater<T1>& v) const {return SetterVal<T,T1,AssignObject>(*this,v);}
|
||||
template <typename T1>
|
||||
SetterVal<T,T1,UpdateObject> operator += (const ObjectUpdater<T1>& v) {return SetterVal<T,T1,UpdateObject>(*this,v);}
|
||||
_inl SetterVal<T,T1,UpdateObject> operator += (const ObjectUpdater<T1>& v) const {return SetterVal<T,T1,UpdateObject>(*this,v);}
|
||||
template <typename T1>
|
||||
SetterVal<T,T1,AppendObject> operator += (const T1& v) {return SetterVal<T,T1,AppendObject>(*this,v);}
|
||||
template <typename T1, uint32_t cnt>
|
||||
SetterVal<T,Array<T1, cnt>,AssignArrayCopy> operator = (const Array<T1, cnt>& v) {return SetterVal<T,Array<T1, cnt>,AssignArrayCopy>(*this,v);}
|
||||
_inl SetterVal<T,T1,AppendObject> operator += (const T1& v) const {return SetterVal<T,T1,AppendObject>(*this,v);}
|
||||
template <typename T1, unsigned int cnt>
|
||||
_inl SetterVal<T,Array<T1, cnt>,AssignArrayCopy> operator = (const Array<T1, cnt>& v) const {return SetterVal<T,Array<T1, cnt>,AssignArrayCopy>(*this,v);}
|
||||
template <typename V>
|
||||
SetterValPtr<T,V> operator &= (const V &v) {return SetterValPtr<T,V>(*this,&v);}
|
||||
_inl SetterValPtr<T,V> operator &= (const V &v) const {return SetterValPtr<T,V>(*this,&v);}
|
||||
template <typename V>
|
||||
SetterVal<T,V> operator= (const V &v) {return SetterVal<T,V>(*this,v);}
|
||||
_inl SetterVal<T,V> operator= (const V &v) const {return SetterVal<T,V>(*this,v);}
|
||||
template <typename... Vs>
|
||||
SetterFunc<T,Vs...> operator() (const Vs&... v) {return SetterFunc<T,Vs...>(*this,v...);}
|
||||
_inl SetterFunc<T,Vs...> operator() (const Vs&... v) const {return SetterFunc<T,Vs...>(*this,v...);}
|
||||
template <typename T1>
|
||||
SetterArray<T,T1> ptrWithLength (const Setter<T1> &v) {return SetterArray<T,T1>(*this,v);}
|
||||
_inl SetterArray<T,T1> ptrWithLength (const Setter<T1> &v) const {return SetterArray<T,T1>(*this,v);}
|
||||
template <typename T1>
|
||||
SetterArray<T,T1> copyWidthength (const Setter<T1> &v) {return SetterArray<T,T1>(*this,v);}
|
||||
SetterArrayIndex<T> operator [](int v) {return SetterArrayIndex<T>(*this,v);}
|
||||
_inl SetterArray<T,T1> copyWidthength (const Setter<T1> &v) const {return SetterArray<T,T1>(*this,v);}
|
||||
_inl SetterArrayIndex<T> operator [](int v) const {return SetterArrayIndex<T>(*this,v);}
|
||||
};
|
||||
|
||||
|
||||
// macro wrapper for building positional argument setters
|
||||
// constexpr type holders
|
||||
template <typename T> struct Twrap{using type = T;};
|
||||
#define $(k) Setter([](const auto a) constexpr -> decltype(&decltype(a)::type::k) {return &decltype(a)::type::k;})
|
||||
|
||||
template <typename T, typename... Ts>
|
||||
void $F(T &t, const Ts&... ts) // fills all SetterVal's member pointers with it's values
|
||||
// holds member pointer as constexpr
|
||||
template <typename T, typename T2>
|
||||
struct MPtrWrap
|
||||
{
|
||||
auto filler = [](T &t, const auto &arg){
|
||||
// broken clang constexpr fails on arg.op!!!
|
||||
constexpr SetterOperation op = ClearType(decltype(arg))::op;
|
||||
if constexpr(op == AssignArrayPtrWithLength)
|
||||
{
|
||||
t.*arg.arr.member.func(Twrap<T>{}) = arg.val.array;
|
||||
t.*arg.arr.count.func(Twrap<T>{}) = arg.val.count;
|
||||
}
|
||||
else if constexpr(op == AssignArrayCopyWithLength)
|
||||
{
|
||||
for(int i = 0; i < arg.val.count; i++)
|
||||
(t.*arg.member.func(Twrap<T>{}))[i] = arg.val.array[i];
|
||||
t.*arg.arr.count.func(Twrap<T>{}) = arg.val.count;
|
||||
}
|
||||
else if constexpr(op == AssignArrayByIndex)
|
||||
(t.*arg.arr.member.func(Twrap<T>{}))[arg.arr.idx] = arg.val;
|
||||
else if constexpr(op == AssignArrayCopy)
|
||||
for(int i = 0; i < arg.val.count; i++)
|
||||
(t.*arg.member.func(Twrap<T>{}))[i] = arg.val.array[i];
|
||||
else if constexpr(op == CallMethod)
|
||||
arg.vals.CallMember(arg.func.func(Twrap<T>{}), t);
|
||||
else if constexpr(op == UpdateObject)
|
||||
arg.val(t.*arg.member.func(Twrap<T>{}));
|
||||
else if constexpr(op == AssignObject)
|
||||
{
|
||||
t.*arg.member.func(Twrap<T>{}) = {};
|
||||
arg.val(t.*arg.member.func(Twrap<T>{}));
|
||||
}
|
||||
else if constexpr(op == AppendObject)
|
||||
t.*arg.member.func(Twrap<T>{}) += arg.val;
|
||||
else if constexpr(op == SetTrue)
|
||||
t.*arg.func(Twrap<T>{}) = (ClearValType(t.*arg.func(Twrap<T>{})))(1);
|
||||
else
|
||||
t.*arg.member.func(Twrap<T>{}) = (ClearValType(t.*arg.member.func(Twrap<T>{})))(arg.val);
|
||||
// deduction helper for T2,T
|
||||
constexpr _inl MPtrWrap(T2 T::* val){}
|
||||
template <T2 T::*V>
|
||||
struct RetType{
|
||||
constexpr static T2 T::* v = V;
|
||||
constexpr _inl RetType(){}
|
||||
};
|
||||
(void)filler; // gcc false unused warning
|
||||
(filler(t,ts),...);
|
||||
};
|
||||
|
||||
// skip actual lambda call, only deduce type and constexpr value
|
||||
#define getp(x) (decltype(x(Twrap<T>{}))::v)
|
||||
|
||||
template <typename T, typename A>
|
||||
constexpr static _inl void Filler(T &t, const A &arg)
|
||||
{
|
||||
// broken clang constexpr fails on arg.op!!!
|
||||
constexpr SetterOperation op = ClearType(decltype(arg))::op;
|
||||
if constexpr(op == AssignArrayPtrWithLength)
|
||||
{
|
||||
t.*getp(arg.arr.member.func) = arg.val.array;
|
||||
t.*getp(arg.arr.count.func) = arg.val.count;
|
||||
}
|
||||
else if constexpr(op == AssignArrayCopyWithLength)
|
||||
{
|
||||
for(int i = 0; i < arg.val.count; i++)
|
||||
(t.*getp(arg.member.func)).v[i] = arg.val.array[i];
|
||||
t.*getp(arg.arr.count.func) = arg.val.count;
|
||||
}
|
||||
else if constexpr(op == AssignArrayByIndex)
|
||||
(t.*getp(arg.arr.member.func))[arg.arr.idx] = arg.val;
|
||||
else if constexpr(op == AssignArrayCopy)
|
||||
for(int i = 0; i < arg.val.count; i++)
|
||||
(t.*getp(arg.member.func))[i] = arg.val.array[i];
|
||||
else if constexpr(op == CallMethod)
|
||||
arg.vals.CallMember(getp(arg.func.func), t);
|
||||
else if constexpr(op == UpdateObject)
|
||||
arg.val(t.*getp(arg.member.func));
|
||||
else if constexpr(op == AssignObject)
|
||||
{
|
||||
t.*getp(arg.member.func) = {};
|
||||
arg.val(t.*getp(arg.member.func));
|
||||
}
|
||||
else if constexpr(op == AppendObject)
|
||||
t.*getp(arg.member.func) += arg.val;
|
||||
else if constexpr(op == SetTrue)
|
||||
t.*getp(arg.func) = (ClearValType(t.*getp(arg.func)))(1);
|
||||
else
|
||||
t.*getp(arg.member.func) = (ClearValType(t.*getp(arg.member.func)))(arg.val);
|
||||
}
|
||||
template <typename T, typename... Ts>
|
||||
static inline _inl void $F(T &t, const Ts&... ts) // fills all SetterVal's member pointers with it's values
|
||||
{
|
||||
(Filler(t,ts),...);
|
||||
}
|
||||
// wrapper for inline constructors with FillStructure
|
||||
template <typename T, typename... Ts>
|
||||
|
@ -266,4 +286,21 @@ T $M(T t, const Ts&... ts)
|
|||
return t;
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
struct $
|
||||
{
|
||||
ArgumentList<Ts... > vals;
|
||||
_inl $(const Ts&... ts) : vals(ts...){}
|
||||
template <typename T>
|
||||
_inl operator T()
|
||||
{
|
||||
T t;
|
||||
vals.CallCtx($F<T, Ts...>,t);
|
||||
return t;
|
||||
}
|
||||
};
|
||||
|
||||
// macro wrapper for building positional argument setters
|
||||
#define $(k) Setter([](const auto a) constexpr -> typename decltype(MPtrWrap(&decltype(a)::type::k))::template RetType<&decltype(a)::type::k> {return {};})
|
||||
|
||||
#endif // POSITIONAL_UTL_H
|
||||
|
|
Loading…
Reference in a new issue