From aaa9780a3b5a1c78b6f5e0eb1c46405ee044b750 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 25 Aug 2015 17:47:34 +0800 Subject: Rename tagged_enum to tagged_union --- src/include/tagged_enum.hpp | 143 ---------------------------------------- src/include/tagged_union.hpp | 151 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 143 deletions(-) delete mode 100644 src/include/tagged_enum.hpp create mode 100644 src/include/tagged_union.hpp (limited to 'src/include') diff --git a/src/include/tagged_enum.hpp b/src/include/tagged_enum.hpp deleted file mode 100644 index 8f5b34e0..00000000 --- a/src/include/tagged_enum.hpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * The most evil CPP abuse I have ever written - */ -#ifndef INCLUDED_TAGGED_UNION_H_ -#define INCLUDED_TAGGED_UNION_H_ - -#define TE_DATANAME(name) Data_##name -#define ENUM_CONS(__tag, __type) \ - static self_t make_null_##__tag() { self_t ret; ret.m_tag = __tag; new (ret.m_data) __type; return ::std::move(ret); } \ - static self_t make_##__tag(__type v) \ - {\ - self_t ret;\ - ret.m_tag = __tag;\ - new (ret.m_data) __type( ::std::move(v) ); \ - return ::std::move(ret); \ - }\ - bool is_##__tag() const { return m_tag == __tag; } \ - const __type& as_##__tag() const { return reinterpret_cast(m_data); } \ - __type& as_##__tag() { return reinterpret_cast<__type&>(m_data); } \ - __type unwrap_##__tag() { return ::std::move(reinterpret_cast<__type&>(m_data)); } \ - -// Argument iteration -#define _DISP2(n, _1, _2) n _1 n _2 -#define _DISP3(n, v, v2, v3) n v n v2 n v3 // _DISP2(n, __VA_ARGS__) -#define _DISP4(n, v, v2, v3, v4) n v n v2 n v3 n v4 // #define _DISP4(n, v, ...) n v _DISP3(n, __VA_ARGS__) -#define _DISP5(n, v, ...) n v _DISP4(n, __VA_ARGS__) -#define _DISP6(n, v, ...) n v _DISP5(n, __VA_ARGS__) -#define _DISP7(n, v, ...) n v _DISP6(n, __VA_ARGS__) -#define _DISP8(n, v, ...) n v _DISP7(n, __VA_ARGS__) -#define _DISP9(n, v, ...) n v _DISP8(n, __VA_ARGS__) -#define _DISP10(n, v, ...) n v _DISP9(n, __VA_ARGS__) -#define _DISP11(n, v, ...) n v _DISP10(n, __VA_ARGS__) -#define _DISP12(n, a1,a2,a3,a4, b1,b2,b3,b4, c1,c2,c3,c4) _DISP4(n, a1,a2,a3,a4) _DISP4(n, b1,b2,b3,b4) _DISP4(n, c1,c2,c3,c4) //n v _DISP11(n, __VA_ARGS__) - -// Macro to obtain a numbered macro for argument counts -// - Raw variant -#define TE_GM_I(SUF,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,COUNT,...) SUF##COUNT -#define TE_GM(SUF,...) TE_GM_I(SUF,__VA_ARGS__,12,11,10,9,8,7,6,5,4,3,2,x) -// - _DISP based variant (for iteration) -#define TE_GMX(...) TE_GM(_DISP,__VA_ARGS__) - - -// " -#define TE_CONS(name, _) ENUM_CONS(name, TE_DATANAME(name)) - -// Sizes of structures -#define TE_SO(name, _) sizeof(TE_DATANAME(name)) -#define MAX2(a, b) (a < b ? b : a) -#define MAXS2(a, b) (TE_SO a < TE_SO b ? TE_SO b : TE_SO a) -#define MAXS3(a, b, c) MAX2(MAXS2(a, b), TE_SO c) -#define MAXS4(a, b, c, d) MAX2(MAXS2(a, b), MAXS2(c, d)) -#define MAXS5(a, b, c, d, e) MAX2(MAXS3(a, b, c), MAXS2(d, e)) -#define MAXS6(a, b, c, d, e, f) MAX2(MAXS3(a, b, c), MAXS3(d, e, f)) -#define MAXS7(a, b, c, d, e, f, g) MAX2(MAXS3(a, b, c), MAXS4(d, e, f, g)) -#define MAXS8(a, b, c, d, e, f, g, h) MAX2(MAXS4(a, b, c, d), MAXS4(e, f, g, h)) -#define MAXS9(a, b, c, d, e, f, g, h, i) MAX2(MAXS4(a, b, c, d), MAXS5(e, f, g, h, i)) -#define MAXS10(a, b, c, d, e, f, g, h, i, j) MAX2(MAXS5(a, b, c, d, e), MAXS5(f, g, h, i, j)) -#define MAXS11(a, b, c, d, e, f, g, h, i, j, k) MAX2(MAXS6(a, b, c, d, e, f), MAXS5(g, h, i, j, k)) -#define MAXS12(a, b, c, d, e, f, g, h, i, j, k, l) MAX2(MAXS6(a, b, c, d, e, f), MAXS6(g, h, i, j, k, l)) - -// Type definitions -#define TE_EXP(...) __VA_ARGS__ -#define TE_TYPEDEF(name, content) struct TE_DATANAME(name) { TE_EXP content; };/* -*/ - -#define TE_TAG(name, _) name, - -// Destructor internals -#define TE_DEST_CASE(tag, _) case tag: as_##tag().~TE_DATANAME(tag)(); break;/* -*/ - -// move constructor internals -#define TE_MOVE_CASE(tag, _) case tag: new(m_data) TE_DATANAME(tag)(x.unwrap_##tag()); break;/* -*/ - -// "tag_to_str" internals -#define TE_TOSTR_CASE(tag,_) case tag: return #tag;/* -*/ -// "tag_from_str" internals -#define TE_FROMSTR_CASE(tag,_) else if(str == #tag) return tag;/* -*/ - -#define MAXS(...) TE_GM(MAXS,__VA_ARGS__)(__VA_ARGS__) -#define TE_CONSS(...) TE_GMX(__VA_ARGS__)(TE_CONS , __VA_ARGS__) -#define TE_TYPEDEFS(...) TE_GMX(__VA_ARGS__)(TE_TYPEDEF ,__VA_ARGS__) -#define TE_TAGS(...) TE_GMX(__VA_ARGS__)(TE_TAG ,__VA_ARGS__) -#define TE_DEST_CASES(...) TE_GMX(__VA_ARGS__)(TE_DEST_CASE,__VA_ARGS__) -#define TE_MOVE_CASES(...) TE_GMX(__VA_ARGS__)(TE_MOVE_CASE,__VA_ARGS__) -#define TE_TOSTR_CASES(...) TE_GMX(__VA_ARGS__)(TE_TOSTR_CASE ,__VA_ARGS__) -#define TE_FROMSTR_CASES(...) TE_GMX(__VA_ARGS__)(TE_FROMSTR_CASE,__VA_ARGS__) - -#define TAGGED_ENUM(_name, _def, ...) \ -class _name { \ - typedef _name self_t;/* -*/ TE_TYPEDEFS(__VA_ARGS__)/* -*/public:\ - enum Tag { \ - TE_TAGS(__VA_ARGS__)\ - };/* -*/ private:\ - Tag m_tag; \ - char m_data[MAXS(__VA_ARGS__)];/* -*/ public:\ - _name(): m_tag(_def) {}\ - _name(const _name&) = delete; \ - _name(_name&& x): m_tag(x.m_tag) { x.m_tag = _def; switch(m_tag) { TE_MOVE_CASES(__VA_ARGS__) } } \ - _name& operator =(_name&& x) { this->~_name(); m_tag = x.m_tag; x.m_tag = _def; switch(m_tag) { TE_MOVE_CASES(__VA_ARGS__) }; return *this; } \ - ~_name() { switch(m_tag) { TE_DEST_CASES(__VA_ARGS__) } } \ - \ - Tag tag() const { return m_tag; }\ - TE_CONSS(__VA_ARGS__) \ -/* -*/ static const char *tag_to_str(Tag tag) { \ - switch(tag) {/* -*/ TE_TOSTR_CASES(__VA_ARGS__)/* -*/ } return ""; \ - }/* -*/ static Tag tag_from_str(const ::std::string& str) { \ - if(0); /* -*/ TE_FROMSTR_CASES(__VA_ARGS__)/* -*/ else throw ::std::runtime_error("enum "#_name" No conversion"); \ - }\ -} - -#define ENUM3(_name, _def, _t1, _v1, _t2, _v2, _t3, _v3)\ - TAGGED_ENUM(_name, _def,\ - (_t1, _v1), \ - (_t2, _v2), \ - (_t3, _v3) \ - ) - -/* - ENUM5(Inner, Any, - Any, bool, - Tuple, ::std::vector, - TupleStruct, struct { Path path; ::std::vector sub_patterns; }, - Value, ::std::unique_ptr, - Range, struct { ::std::unique_ptr left; ::std::unique_ptr right; } - ) m_contents; -*/ - -#endif - diff --git a/src/include/tagged_union.hpp b/src/include/tagged_union.hpp new file mode 100644 index 00000000..64e7f84a --- /dev/null +++ b/src/include/tagged_union.hpp @@ -0,0 +1,151 @@ +/* + * The most evil CPP abuse I have ever written + * + * Constructs a tagged union that correctly handles objects. + * + * Union is NOT copy-constructable + */ +#ifndef INCLUDED_TAGGED_UNION_H_ +#define INCLUDED_TAGGED_UNION_H_ + +#define TU_CASE_ITEM(src, mod, var, name) mod auto& name = src.as_##var(); (void)&name; +#define TU_CASE_BODY(class,var, ...) case class::var: { __VA_ARGS__ } break; +#define TU_CASE(mod, class, var, name,src, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(src,mod,var,name) __VA_ARGS__) +#define TU_CASE2(mod, class, var, n1,s1, n2,s2, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(s1,mod,var,n1) TU_CASE_ITEM(s2,mod,var,n2) __VA_ARGS__) + +#define TU_DATANAME(name) Data_##name +// Internals of TU_CONS +#define TU_CONS_I(__tag, __type) \ + static self_t make_null_##__tag() { self_t ret; ret.m_tag = __tag; new (ret.m_data) __type; return ::std::move(ret); } \ + static self_t make_##__tag(__type v) \ + {\ + self_t ret;\ + ret.m_tag = __tag;\ + new (ret.m_data) __type( ::std::move(v) ); \ + return ::std::move(ret); \ + }\ + bool is_##__tag() const { return m_tag == __tag; } \ + const __type& as_##__tag() const { return reinterpret_cast(m_data); } \ + __type& as_##__tag() { return reinterpret_cast<__type&>(m_data); } \ + __type unwrap_##__tag() { return ::std::move(reinterpret_cast<__type&>(m_data)); } \ +// Define a tagged union constructor +#define TU_CONS(name, _) TU_CONS_I(name, TU_DATANAME(name)) + +// Argument iteration +#define _DISP2(n, _1, _2) n _1 n _2 +#define _DISP3(n, v, v2, v3) n v n v2 n v3 // _DISP2(n, __VA_ARGS__) +#define _DISP4(n, v, v2, v3, v4) n v n v2 n v3 n v4 // #define _DISP4(n, v, ...) n v _DISP3(n, __VA_ARGS__) +#define _DISP5(n, v, ...) n v _DISP4(n, __VA_ARGS__) +#define _DISP6(n, v, ...) n v _DISP5(n, __VA_ARGS__) +#define _DISP7(n, v, ...) n v _DISP6(n, __VA_ARGS__) +#define _DISP8(n, v, ...) n v _DISP7(n, __VA_ARGS__) +#define _DISP9(n, v, ...) n v _DISP8(n, __VA_ARGS__) +#define _DISP10(n, v, ...) n v _DISP9(n, __VA_ARGS__) +#define _DISP11(n, v, ...) n v _DISP10(n, __VA_ARGS__) +#define _DISP12(n, a1,a2,a3,a4, b1,b2,b3,b4, c1,c2,c3,c4) _DISP4(n, a1,a2,a3,a4) _DISP4(n, b1,b2,b3,b4) _DISP4(n, c1,c2,c3,c4) //n v _DISP11(n, __VA_ARGS__) + +// Macro to obtain a numbered macro for argument counts +// - Raw variant +#define TU_GM_I(SUF,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,COUNT,...) SUF##COUNT +#define TU_GM(SUF,...) TU_GM_I(SUF,__VA_ARGS__,12,11,10,9,8,7,6,5,4,3,2,x) +// - _DISP based variant (for iteration) +#define TU_GMX(...) TU_GM(_DISP,__VA_ARGS__) + + +// Sizes of structures +#define TU_SO(name, _) sizeof(TU_DATANAME(name)) +#define MAX2(a, b) (a < b ? b : a) +#define MAXS2(a, b) (TU_SO a < TU_SO b ? TU_SO b : TU_SO a) +#define MAXS3(a, b, c) MAX2(MAXS2(a, b), TU_SO c) +#define MAXS4(a, b, c, d) MAX2(MAXS2(a, b), MAXS2(c, d)) +#define MAXS5(a, b, c, d, e) MAX2(MAXS3(a, b, c), MAXS2(d, e)) +#define MAXS6(a, b, c, d, e, f) MAX2(MAXS3(a, b, c), MAXS3(d, e, f)) +#define MAXS7(a, b, c, d, e, f, g) MAX2(MAXS3(a, b, c), MAXS4(d, e, f, g)) +#define MAXS8(a, b, c, d, e, f, g, h) MAX2(MAXS4(a, b, c, d), MAXS4(e, f, g, h)) +#define MAXS9(a, b, c, d, e, f, g, h, i) MAX2(MAXS4(a, b, c, d), MAXS5(e, f, g, h, i)) +#define MAXS10(a, b, c, d, e, f, g, h, i, j) MAX2(MAXS5(a, b, c, d, e), MAXS5(f, g, h, i, j)) +#define MAXS11(a, b, c, d, e, f, g, h, i, j, k) MAX2(MAXS6(a, b, c, d, e, f), MAXS5(g, h, i, j, k)) +#define MAXS12(a, b, c, d, e, f, g, h, i, j, k, l) MAX2(MAXS6(a, b, c, d, e, f), MAXS6(g, h, i, j, k, l)) + +// Type definitions +#define TU_EXP(...) __VA_ARGS__ +#define TU_TYPEDEF(name, content) struct TU_DATANAME(name) { TU_EXP content; };/* +*/ + +#define TU_TAG(name, _) name, + +// Destructor internals +#define TU_DEST_CASE(tag, _) case tag: as_##tag().~TU_DATANAME(tag)(); break;/* +*/ + +// move constructor internals +#define TU_MOVE_CASE(tag, _) case tag: new(m_data) TU_DATANAME(tag)(x.unwrap_##tag()); break;/* +*/ + +// "tag_to_str" internals +#define TU_TOSTR_CASE(tag,_) case tag: return #tag;/* +*/ +// "tag_from_str" internals +#define TU_FROMSTR_CASE(tag,_) else if(str == #tag) return tag;/* +*/ + +#define MAXS(...) TU_GM(MAXS,__VA_ARGS__)(__VA_ARGS__) +#define TU_CONSS(...) TU_GMX(__VA_ARGS__)(TU_CONS , __VA_ARGS__) +#define TU_TYPEDEFS(...) TU_GMX(__VA_ARGS__)(TU_TYPEDEF ,__VA_ARGS__) +#define TU_TAGS(...) TU_GMX(__VA_ARGS__)(TU_TAG ,__VA_ARGS__) +#define TU_DEST_CASES(...) TU_GMX(__VA_ARGS__)(TU_DEST_CASE,__VA_ARGS__) +#define TU_MOVE_CASES(...) TU_GMX(__VA_ARGS__)(TU_MOVE_CASE,__VA_ARGS__) +#define TU_TOSTR_CASES(...) TU_GMX(__VA_ARGS__)(TU_TOSTR_CASE ,__VA_ARGS__) +#define TU_FROMSTR_CASES(...) TU_GMX(__VA_ARGS__)(TU_FROMSTR_CASE,__VA_ARGS__) + +/** + * Define a new tagged union + * + * ``` + * TAGGED_UNION(Inner, Any, + * (Any, (bool flag)), + * (Tuple, (::std::vector subpats)), + * (TupleStruct, (Path path; ::std::vector sub_patterns;)), + * (Value, (::std::unique_ptr val )), + * (Range, (::std::unique_ptr left; ::std::unique_ptr right;)) + * ); + * ``` + */ +#define TAGGED_UNION(_name, _def, ...) \ +class _name { \ + typedef _name self_t;/* +*/ TU_TYPEDEFS(__VA_ARGS__)/* +*/public:\ + enum Tag { \ + TU_TAGS(__VA_ARGS__)\ + };/* +*/ private:\ + Tag m_tag; \ + char m_data[MAXS(__VA_ARGS__)];/* +*/ public:\ + _name(): m_tag(_def) {}\ + _name(const _name&) = delete; \ + _name(_name&& x): m_tag(x.m_tag) { x.m_tag = _def; switch(m_tag) { TU_MOVE_CASES(__VA_ARGS__) } } \ + _name& operator =(_name&& x) { this->~_name(); m_tag = x.m_tag; x.m_tag = _def; switch(m_tag) { TU_MOVE_CASES(__VA_ARGS__) }; return *this; } \ + ~_name() { switch(m_tag) { TU_DEST_CASES(__VA_ARGS__) } } \ + \ + Tag tag() const { return m_tag; }\ + TU_CONSS(__VA_ARGS__) \ +/* +*/ static const char *tag_to_str(Tag tag) { \ + switch(tag) {/* +*/ TU_TOSTR_CASES(__VA_ARGS__)/* +*/ } return ""; \ + }/* +*/ static Tag tag_from_str(const ::std::string& str) { \ + if(0); /* +*/ TU_FROMSTR_CASES(__VA_ARGS__)/* +*/ else throw ::std::runtime_error("enum "#_name" No conversion"); \ + }\ +} + +/* +*/ + +#endif + -- cgit v1.2.3