vulkan-playground/positional_utl.h

269 lines
9.1 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
// 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;
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;
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;
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
{
ArgumentList<Ts...>::CallMember(f, i,ts..., v);
}
template<typename Func, typename I, typename... Ts2> 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;
ArgumentList(const T &t) : v(t){}
template<typename Func, typename I, typename... Ts2> 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
{
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;
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){}
};
#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;
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>
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) {}
};
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;
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>
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) {}
};
// todo: sync with other utilities...
template <typename T, uint32_t cnt>
struct Array
{
T array[cnt];
constexpr static uint32_t count = cnt;
};
template <typename T, typename... Args>
struct ArrayInitializer
{
T array[sizeof... (Args)];
constexpr static uint32_t 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;
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);}
template <typename T1>
SetterVal<T,T1,UpdateObject> operator += (const ObjectUpdater<T1>& v) {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);}
template <typename V>
SetterValPtr<T,V> operator &= (const V &v) {return SetterValPtr<T,V>(*this,&v);}
template <typename V>
SetterVal<T,V> operator= (const V &v) {return SetterVal<T,V>(*this,v);}
template <typename... Vs>
SetterFunc<T,Vs...> operator() (const Vs&... v) {return SetterFunc<T,Vs...>(*this,v...);}
template <typename T1>
SetterArray<T,T1> ptrWithLength (const Setter<T1> &v) {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);}
};
// macro wrapper for building positional argument setters
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
{
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);
};
(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;
}
#endif // POSITIONAL_UTL_H