306 lines
10 KiB
C++
306 lines
10 KiB
C++
/*
|
|
* Copyright (c) 2024 mittorn
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sub license, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the
|
|
* next paragraph) shall be included in all copies or substantial portions
|
|
* of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
|
* IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
|
|
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
#ifndef POSITIONAL_UTL_H
|
|
#define POSITIONAL_UTL_H
|
|
|
|
template <typename T>
|
|
struct ClearType_w{ typedef T tp; };
|
|
template <typename T>
|
|
struct ClearType_w<T&> { typedef T tp; };
|
|
template <class T>
|
|
struct ClearType_w<T&&> { typedef T tp; };
|
|
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
|
|
{
|
|
AssignVal,
|
|
AssignArrayPtrWithLength,
|
|
UpdateObject,
|
|
AssignObject,
|
|
AppendObject,
|
|
AssignArrayByIndex,
|
|
AssignArrayCopy,
|
|
AssignArrayCopyWithLength,
|
|
// CallWith
|
|
CallMethod,
|
|
SetTrue
|
|
};
|
|
|
|
template<typename T>
|
|
struct Setter;
|
|
template<typename T, typename V, SetterOperation o = AssignVal>
|
|
struct SetterVal // keeps val reference and SetterFunc wrapper
|
|
{
|
|
constexpr static SetterOperation op = o;
|
|
const Setter<T> &member;
|
|
const V& val;
|
|
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
|
|
{
|
|
constexpr static SetterOperation op = AssignVal;
|
|
const Setter<T> &member;
|
|
const V *val;
|
|
constexpr _inl SetterValPtr(const Setter<T> &m, const V *v) : member(m), val(v){}
|
|
};
|
|
/* Delayed function call (maybe useless)
|
|
* struct aaa{
|
|
void Func(int a, int b, int c){printf("%d %d %d\n",a,b,c);}
|
|
} s;
|
|
$F(s, $(Func) (10, 20, 30));
|
|
*/
|
|
template <typename T, typename... Ts>
|
|
struct ArgumentList : ArgumentList<Ts...>
|
|
{
|
|
const T &v;
|
|
_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> _inl void CallCtx(Func f, I &i, const Ts2&... ts) const
|
|
{
|
|
ArgumentList<Ts...>::CallCtx(f, i,ts..., v);
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct ArgumentList<T>
|
|
{
|
|
const T &v;
|
|
_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> _inl void CallCtx(Func f, I &i, const Ts2&... ts) const
|
|
{
|
|
f(i,ts...,v);
|
|
}
|
|
};
|
|
|
|
template<typename T, typename... Vs>
|
|
struct SetterFunc // keeps val reference and SetterFunc wrapper
|
|
{
|
|
constexpr static SetterOperation op = CallMethod;
|
|
const Setter<T> &func;
|
|
ArgumentList<Vs... > vals;
|
|
constexpr _inl SetterFunc(const Setter<T> &f, const Vs&... vs) : func(f), vals(vs...) {}
|
|
};
|
|
|
|
// container for updating vals
|
|
template <typename T>
|
|
struct ObjectUpdater:T
|
|
{
|
|
constexpr _inl ObjectUpdater(const T& t): T(t){}
|
|
};
|
|
|
|
#define Vals(...) ObjectUpdater([&](auto &s){ $F(s,__VA_ARGS__);})
|
|
|
|
template<typename T, typename T1>
|
|
struct SetterArray;
|
|
|
|
template<typename T, typename T1, typename V, SetterOperation O = AssignArrayPtrWithLength>
|
|
struct SetterArrayVal // keeps val reference and SetterFunc wrapper
|
|
{
|
|
constexpr static SetterOperation op = O;
|
|
const SetterArray<T,T1> &arr;
|
|
const V &val;
|
|
constexpr _inl SetterArrayVal(const SetterArray<T, T1> &f, const V &v) : arr(f), val(v){}
|
|
};
|
|
|
|
template<typename T, typename T1>
|
|
struct SetterArray // keeps val reference and SetterFunc wrapper
|
|
{
|
|
const Setter<T> &member;
|
|
const Setter<T1> &count;
|
|
template <typename V>
|
|
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;
|
|
template<typename T, typename V>
|
|
struct SetterArrayIndexVal // keeps val reference and SetterFunc wrapper
|
|
{
|
|
constexpr static SetterOperation op = AssignArrayByIndex;
|
|
const SetterArrayIndex<T> &arr;
|
|
const V &val;
|
|
constexpr _inl SetterArrayIndexVal(const SetterArrayIndex<T> &f, const V &v) : arr(f), val(v){}
|
|
};
|
|
|
|
template<typename T>
|
|
struct SetterArrayIndex // keeps val reference and SetterFunc wrapper
|
|
{
|
|
const Setter<T> &member;
|
|
const int idx;
|
|
template <typename V>
|
|
_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, unsigned int cnt>
|
|
struct Array
|
|
{
|
|
T array[cnt];
|
|
constexpr static unsigned int count = cnt;
|
|
};
|
|
|
|
template <typename T, typename... Args>
|
|
struct ArrayInitializer
|
|
{
|
|
T array[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>
|
|
Array<T0, sizeof...(Ts)+1> Arr(T0 arg0, Ts... arguments)
|
|
{
|
|
return {arg0, arguments...};
|
|
}
|
|
|
|
template<typename T>
|
|
struct Setter // keeps member pointer getter, wrapper for user-provided lambda
|
|
{
|
|
constexpr static SetterOperation op = SetTrue;
|
|
const T &func;
|
|
inline _inl constexpr Setter(const T &data) :func(data){}
|
|
template <typename T1>
|
|
_inl SetterVal<T,T1,AssignObject> operator = (const ObjectUpdater<T1>& v) const {return SetterVal<T,T1,AssignObject>(*this,v);}
|
|
template <typename T1>
|
|
_inl SetterVal<T,T1,UpdateObject> operator += (const ObjectUpdater<T1>& v) const {return SetterVal<T,T1,UpdateObject>(*this,v);}
|
|
template <typename T1>
|
|
_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>
|
|
_inl SetterValPtr<T,V> operator &= (const V &v) const {return SetterValPtr<T,V>(*this,&v);}
|
|
template <typename V>
|
|
_inl SetterVal<T,V> operator= (const V &v) const {return SetterVal<T,V>(*this,v);}
|
|
template <typename... Vs>
|
|
_inl SetterFunc<T,Vs...> operator() (const Vs&... v) const {return SetterFunc<T,Vs...>(*this,v...);}
|
|
template <typename T1>
|
|
_inl SetterArray<T,T1> ptrWithLength (const Setter<T1> &v) const {return SetterArray<T,T1>(*this,v);}
|
|
template <typename T1>
|
|
_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);}
|
|
};
|
|
|
|
// constexpr type holders
|
|
template <typename T> struct Twrap{using type = T;};
|
|
// holds member pointer as constexpr
|
|
template <typename T, typename T2>
|
|
struct MPtrWrap
|
|
{
|
|
// 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(){}
|
|
};
|
|
};
|
|
|
|
// 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>
|
|
T $M(T t, const Ts&... ts)
|
|
{
|
|
$F(t, 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
|