positional: ensure compile-time setter deduction, add new type-generic initializator syntax

This commit is contained in:
mittorn 2024-12-09 03:42:13 +03:00
parent 0ba723f71c
commit fad96fab0d

View file

@ -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