diff --git a/include/aggregate.hpp b/include/aggregate.hpp index 32d0e56..0648090 100644 --- a/include/aggregate.hpp +++ b/include/aggregate.hpp @@ -15,27 +15,73 @@ struct compo_t { using alignment_t = size_t; template < typename T > -struct has_trv { - template < typename U > static auto check(U u) -> decltype(u.trv(), std::true_type{}) { } +struct has_alignof { + template < typename U > static auto check(U u) -> decltype(U::alignof_(), std::true_type{}); + static std::false_type check(...); + static bool const value = decltype(check(std::declval()))::value; +}; + +template < typename T > +constexpr auto alignof_() -> std::enable_if_t< has_alignof< T >::value, alignment_t > +{ + return T::alignof_(); +} + +template < typename T > +constexpr auto alignof_() -> std::enable_if_t< !has_alignof< T >::value, alignment_t > +{ + return alignof(T); +} + +template < typename T> +struct has_align { + template < typename U > static auto check(U u) -> decltype(U::align_mode, std::true_type{}); static std::false_type check(...); -public: static bool const value = decltype(check(std::declval()))::value; }; +template < alignment_t A, typename T> +constexpr auto decision_align() -> std::enable_if_t< has_align::value, alignment_t > { return T::alignof_(); } + +template < alignment_t A, typename T> +constexpr auto decision_align() -> std::enable_if_t< !has_align::value, alignment_t > { return A; } + template < alignment_t Align, typename T > constexpr size_t align(size_t o) { size_t a = Align; if (Align == 0) /* natural align */ - a = sizeof(T); + a = alignof_(); + size_t m = (a-1); + return (o & m) ? ((o + (a-1)) & ~m) : o; +} + +template < alignment_t Align > +constexpr size_t align(size_t o) +{ + size_t a = Align; + if (Align == 0) /* natural align */ + return o; size_t m = (a-1); return (o & m) ? ((o + (a-1)) & ~m) : o; } + +template < typename T > +struct has_trv { + template < typename U > static auto check(U u) -> decltype(u.trv(), std::true_type{}) { } + static std::false_type check(...); + static bool const value = decltype(check(std::declval()))::value; +}; + /* trv を持つ. trv はテンプレート引数に align を持つこと. (テンプレート引数はデフォルトの alignment を持つべき) */ -template < typename T, alignment_t Align = 1 > constexpr auto sizeof_() -> decltype(T::trv()) { return T::template trv< Align >(); } +template < typename T, alignment_t Align = 1 > +constexpr auto sizeof_() -> std::enable_if_t< has_trv::value, size_t > +{ + return T::template trv< Align >(); +} /* trv を持たない */ template < typename T, alignment_t Align = 1 > @@ -43,72 +89,127 @@ constexpr auto sizeof_() -> std::enable_if_t< !has_trv::value, size_t > { return align(sizeof(T)); } + +template < typename T, alignment_t A > +struct has_placement { + template < typename U > static auto check(U u) -> decltype(U::template placement(), std::true_type{}) { } + static std::false_type check(...); + static bool const value = decltype(check(std::declval()))::value; +}; + +/* placement を考慮する size 計算を呼び出す. */ +template < typename T, alignment_t Align = 1 > +constexpr auto sizeof_(size_t place) -> std::enable_if_t< has_placement::value, size_t > +{ + return T::template placement< Align >(place); +} + +template < typename T, alignment_t Align = 1 > +constexpr auto sizeof_(size_t) -> std::enable_if_t< !has_placement::value, size_t > +{ + return align(sizeof(T)); +} + +/* C++14 で std::max は constexpr 版ができたはずだが, clang-3.5+libc++ でなぜかだめ */ +template < typename CAR, typename... CDR > +constexpr CAR constexpr_max(CAR&& car, CDR&&... cdr){ + CAR r = car; + using s = std::initializer_list; + (void)s{ (void(r = r < cdr ? cdr : r),0)... }; + return r; +} template < alignment_t Align, size_t Acc, typename ...Ts > struct sigma_size { static const size_t value = Acc; }; -template < alignment_t Align, size_t Acc, typename CAR> -struct sigma_size< Align, Acc, CAR > { - static const size_t value = align< Align, CAR >(Acc + sizeof_< CAR >()); -}; - template < alignment_t Align, size_t Acc, typename CAR, typename ...CDR> struct sigma_size< Align, Acc, CAR, CDR... > { - static const size_t value = sigma_size< Align, align< Align, CAR >(Acc + sizeof_< CAR >()), CDR... >::value; + static const alignment_t a_ = decision_align< Align, CAR >(); + static const size_t value = sigma_size< Align, align< a_, CAR >(Acc + sizeof_< CAR, a_ >(Acc)), CDR... >::value; }; -template < alignment_t Align, typename ...Ts > +template < alignment_t Align, size_t Acc, typename ...Ts > +constexpr size_t sigma_type_list(type_list< Ts ... >&&) +{ + return sigma_size< Align, Acc, Ts... >::value; +} + +template < alignment_t Align, size_t Acc, typename Cur, typename ...Ts > constexpr size_t sigma_type_list(type_list< Ts ... >&&) { - return sigma_size< Align, 0, Ts... >::value; + return sigma_size< Align, Acc, Cur, Ts... >::value; } /* offset 計算のサブ関数: 型 T が offset() を持っていれば Rest... のパターンに従って探索し, なければ終端する. */ -template < alignment_t Align, typename T, size_t...Pos > -constexpr auto offset_() -> decltype(T::template offset< Align, Pos... >::value) +template < alignment_t Align, size_t Acc, typename T, size_t...Pos > +constexpr auto offset_() -> decltype(T::template offset< Align, Acc, Pos... >::value) { - return T::template offset< Align, Pos... >::value; + return T::template offset< Align, Acc, Pos... >::value ; } -template < typename T, size_t... Pos > +template < typename T, alignment_t A, size_t Acc, size_t... Pos > struct has_offset { - template < typename U > static auto check(U u) -> decltype(U::template offset< 0, Pos ... >::value, std::true_type{}) { } + template < typename U > static auto check(U u) -> decltype(U::template offset< A, Acc, Pos ... >::value, std::true_type{}) { } static std::false_type check(...); public: static bool const value = decltype(check(std::declval()))::value; }; /* offset を持たないので Pos... の探索は終了 */ -template < alignment_t Align, typename T, size_t...Pos > -constexpr auto offset_() -> std::enable_if_t< !has_offset::value, size_t > +template < alignment_t Align, size_t Acc, typename T, size_t...Pos > +constexpr auto offset_() -> std::enable_if_t< !has_offset::value, size_t > { - return std::is_empty< T >::value ? T() : sizeof(T); + return Acc + (std::is_empty< T >::value ? 0 : sizeof(T)); } - + /* aggregation */ template < typename ...S > struct agg_t : public compo_t { template < alignment_t Align = 1 > - constexpr static size_t trv() + constexpr static size_t trv(size_t placement=0) { return sigma_size< Align, 0, S... >::value; } - template < alignment_t Align, size_t... Rest > struct offset { static const size_t value = 0; }; + template < alignment_t Align = 1 > + static constexpr size_t placement(size_t place = 0) + { + return trv(place); + } + + template < alignment_t Align, size_t Acc, size_t... Rest > struct offset { static const size_t value = Acc; }; /* offset は Idx-1 までのサイズの総和だが, address alignment 制約の保証のために Idx の type を知る必要がある. - 計算の途中も制約を満たす必要がある. */ - template < alignment_t Align, size_t Cur > - struct offset< Align, Cur > { static const size_t value = align< Align, typename at_type< Cur, S...>::type >(sigma_type_list< Align >(typename to_types< Cur, S... >::types{})); }; - - template < alignment_t Align, size_t Cur, size_t ... Rest > - struct offset< Align, Cur, Rest...> { - static const size_t value = sigma_type_list< Align >(typename to_types< Cur, S... >::types{}) + - offset_< Align, typename at_type< Cur, S... >::type, Rest... >(); + 計算の途中も制約を満たす必要がある. + このときの alignment は placement alignment で, 型の要求 alignment に優先する. + (alignment がオーバーライドされるとき, 内側の type_t の align より placement-align が優先される. + ただし type_t の内部は type_t の align が適用される. この padding/headroom を type_t が持つ. + headroom は type_t が直接収容する agg_t/sel_t の offset をとれば計算済みとなる) + using T = type_t< agg_t< char, type_t< agg_t< int >, 0 >, 1 > のとき: + get< T, 0, 1 >::offset は placement-alignment=1 に従い 1 + get< T, 0, 1, 0>::offset は T の内部 alignment に従い 4 + get< T, 0, 1, 0, 0>::offset は内部の alignment に従い 4 + */ +#if 1 + template < alignment_t Align, size_t Acc, size_t Cur > + struct offset< Align, Acc, Cur > { + /* 最終 column の 総和. 最後の要素の加算前の値を返す */ + using T_ = typename at_type< Cur, S...>::type; + static const size_t value = align< Align, T_ >(sigma_type_list< Align, Acc >(typename to_types< Cur, S... >::types{})); + }; +#endif + + template < alignment_t Align, size_t Acc, size_t Cur, size_t ... Rest > + struct offset< Align, Acc, Cur, Rest...> { + using T_ = typename at_type< Cur, S...>::type; + /* column ごとの総和: */ + static const size_t s = align< Align, T_ >(sigma_type_list< Align, Acc >(typename to_types< Cur, S... >::types{})); + + static const size_t value = align< Align, T_ >(offset_< Align, s, T_, Rest... >()); }; template < alignment_t Align, size_t... Rest > struct get { using type = void; }; @@ -118,31 +219,32 @@ struct agg_t : public compo_t { using type = typename at_type< Pos, S... >::type::template get< Align, Rest ... >::type; }; + static constexpr alignment_t alignof_() + { + return constexpr_max(typu::alignof_()...); + } }; -/* C++14 で std::max は constexpr 版ができたはずだが, clang-3.5+libc++ でなぜかだめ */ -template < typename CAR, typename... CDR > -constexpr CAR constexpr_max(CAR&& car, CDR&&... cdr){ - CAR r = car; - using s = std::initializer_list; - (void)s{ (void(r = r < cdr ? cdr : r),0)... }; - return r; -} - /* selector */ template < typename ...S > struct sel_t : public compo_t { template < alignment_t Align = 1 > - constexpr static size_t trv() + constexpr static size_t trv(size_t placement=0) { return constexpr_max(sizeof_()...); } - template < alignment_t Align, size_t... Rest > struct offset { static const size_t value = 0; }; - template < alignment_t Align, size_t Pos > struct offset< Align, Pos > { static const size_t value = 0; }; - template < alignment_t Align, size_t Pos, size_t ... Rest > - struct offset< Align, Pos, Rest...> { - static const size_t value = offset_< Align, typename at_type< Pos, S... >::type, Rest... >(); + template < alignment_t Align = 1 > + constexpr static size_t placement(size_t place=0) + { + return trv(place); + } + + template < alignment_t Align, size_t Acc, size_t... Rest > struct offset { static const size_t value = Acc; }; + //template < alignment_t Align, size_t Acc, size_t Pos > struct offset< Align, Acc, Pos > { static const size_t value = Acc; }; + template < alignment_t Align, size_t Acc, size_t Pos, size_t ... Rest > + struct offset< Align, Acc, Pos, Rest...> { + static const size_t value = offset_< Align, Acc, typename at_type< Pos, S... >::type, Rest... >(); }; template < alignment_t Align, size_t... Rest > struct get { using type = void; }; @@ -151,13 +253,17 @@ struct sel_t : public compo_t { struct get< Align, Pos, Rest...> { using type = typename at_type< Pos, S... >::type::template get< Align, Rest ... >::type; }; - + + static constexpr alignment_t alignof_() + { + return constexpr_max(typu::alignof_()...); + } }; template < typename T, T ...S > struct sel_t_t { template < alignment_t A=1 > - constexpr static size_t trv() + constexpr static size_t trv(size_t placement=0) { return constexpr_max(S...); } @@ -177,28 +283,92 @@ template < typename S, alignment_t Align, typename Enabled = void > struct type_t { }; +/* 収容されるすべての型は固有のアラインメントを持ち, type_t はそれをオーバーライドする. + type_t は他の type_t に収容されるとき, その type_t のアラインメントにオーバーライドされる. + + これは, 上位 type_t がよりコンパクトなアラインを要求するときに要求に矛盾が生じる. + using T1 = type_t< agg_t< double >, 0 >; + using T0 = type_t< char, T2, 1>; + とすると, T0 の収容型は packed となり T1 も offset=1 となるが, + T1 の収容型は自然な align を要求されるので type_t が 7byte の headroom となり + T1 収容型のオフセットは 8byte align となる. +*/ template < typename S, alignment_t Align> struct type_t < S, Align, std::enable_if_t< std::is_base_of< compo_t, S >::value > > { using sub = S; - static const size_t align = Align; + static const alignment_t align_mode = Align; /* maybe 0 */ + static const size_t align = align_mode ? align_mode : sub::alignof_(); /* a concret value. non zero */ + + template < alignment_t A > + static constexpr size_t align_(size_t o) + { + static_assert(A != 0, "align_ needs not align-mode"); + size_t a = A; + size_t m = (a-1); + return (o & m) ? ((o + m) & ~m): o; + } - template < alignment_t A = Align > - constexpr static size_t trv() + /* type_t をネストして alignment を override するとき, + type_t の配置オフセットによって type_t 自身が pack を含む可能性がある */ + template < alignment_t EA = Align > + constexpr static size_t trv(size_t place = 0) { - return sizeof_(); + if (EA == Align) + return sizeof_(); + /* 自身の align と Enclosure の align が異なる場合, + 自身の align で sizeof_ を計算し, placement を加えた offset を enclosure の align で計算する. + */ + size_t size = sizeof_(); + return align_< EA ? EA : align >(place) - place + size; } + /* type_t をネストして alignment を override するとき, + type_t の配置オフセットによって type_t 自身が pack を含む可能性がある */ + template < alignment_t EA = Align > + constexpr static size_t placement(size_t place = 0) + { + if (EA == Align) + return sizeof_(place); + /* 自身の align と Enclosure の align が異なる場合, + 自身の align で sizeof_ を計算し, placement を加えた offset を enclosure の align で計算する. + */ + size_t size = sizeof_(place); + return align_< EA ? EA : align >(place) - place + size; + } + + /* ignore the first 0 */ template < size_t Cur, size_t ...Rest > - constexpr static size_t offset() + constexpr static size_t offset_from() { - return sub::template offset< Align, Rest... >::value; + static_assert(Cur == 0, "type_t has to get 0 for the first enclosure"); + return sub::template offset< Align, 0, Rest... >::value; } + + template < alignment_t A, size_t offs > + constexpr static size_t check_aligned() + { + static_assert((offs & ((A==0 ? sub::alignof_() : A) - 1)) == 0, "offset is not aligned"); + return offs; + } + + template < alignment_t A, size_t Acc, size_t Pos, size_t ... Rest > + struct offset { + /* type_t の内部 offset の計算にしか呼ばれないので上位 placement align は無視 */ + static const size_t value = align_< align >(offset_< align, Acc, sub, Rest... >()); + }; + template < alignment_t A, size_t... Rest > struct get { using type = void; }; + template < alignment_t A, size_t Pos > struct get< A, Pos > { using type = sub; }; + template < alignment_t A, size_t Pos, size_t ... Rest > + struct get< A, Pos, Rest...> { + using type = typename sub::template get< Align, Rest ... >::type; + }; + /* get インターフェイスのために compo_t の派生としたが, type_t 自身は compo_t を継承しない. また variadic parameter もとらないため, get< type_t<...>, 0 > とやって sub にアクセスするためにはトリックが必要になった. とりあえず特殊化で誤魔化す. - (そもそも最初の次元はもう要らないのではないかという気がする) */ + (そもそも最初の次元はもう要らないのではないかという気がするが type_t は alignment override の際境界となる) */ template < size_t ... Pos > struct inner; template < size_t Cur, size_t ...Rest > struct inner< Cur, Rest... > { @@ -208,6 +378,8 @@ struct type_t < S, Align, std::enable_if_t< std::is_base_of< compo_t, S >::value struct inner { using type = sub; }; + + static constexpr alignment_t alignof_() { return align; } }; /* get 公開インターフェイス. @@ -218,8 +390,8 @@ struct type_t < S, Align, std::enable_if_t< std::is_base_of< compo_t, S >::value template < typename T, size_t... Pos > struct get { using type = typename T::template inner< Pos... >::type; - static const size_t size = sizeof_(); - static const size_t offset = T::template offset(); + static const size_t size = sizeof_(); + static const size_t offset = T::template offset_from(); }; } diff --git a/test/recurse.cpp b/test/recurse.cpp index aefee7c..1a17053 100644 --- a/test/recurse.cpp +++ b/test/recurse.cpp @@ -1,16 +1,10 @@ #include #include -template < typename C, typename...P > -size_t foo(C c, P... p) -{ - return c; -} - int main() { using namespace typu; - + printf("%s\n", typeid(agg_t< int, int >::get< 0 >::type).name()); printf("%zu\n", type_t< agg_t< int >, 1 >::trv()); @@ -27,57 +21,58 @@ int main() using Simple1 = type_t< agg_t< char, char, int, double >, 1 >; printf("sizeof Simple1: %zu (14)\n", Simple1::trv()); - printf("char1: %zu (0)\n", Simple1::offset<0, 0>()); - printf("char2: %zu (1)\n", Simple1::offset<0, 1>()); - printf("int: %zu (2)\n", Simple1::offset<0, 2>()); - printf("double: %zu (6)\n", Simple1::offset<0, 3>()); + printf("char1: %zu (0)\n", Simple1::offset_from<0, 0>()); + printf("char2: %zu (1)\n", Simple1::offset_from<0, 1>()); + printf("int: %zu (2)\n", Simple1::offset_from<0, 2>()); + printf("double: %zu (6)\n", Simple1::offset_from<0, 3>()); using Sel1 = type_t< sel_t< int, char, bool, double >, 1 >; printf("sizeof Sel1: %zu (8)\n", Sel1::trv()); - printf("int: %zu (0)\n", Sel1::offset<0, 0>()); - printf("char: %zu (0)\n", Sel1::offset<0, 1>()); - printf("bool: %zu (0)\n", Sel1::offset<0, 2>()); - printf("double: %zu (0)\n", Sel1::offset<0, 3>()); - - using Agg1 = type_t< agg_t< int, float, agg_t< double, float > >, 1 >; - printf("sizeof Agg1: %zu (20)\n", Agg1::trv()); - printf("agg0: %zu (0)\n", Agg1::offset<0>()); - printf("agg0:int: %zu (0)\n", Agg1::offset<0, 0>()); - printf("agg0:float: %zu (4)\n", Agg1::offset<0, 1>()); - printf("agg1: %zu (8)\n", Agg1::offset<0, 2>()); - printf("agg1:double %zu (8)\n", Agg1::offset<0, 2, 0>()); - printf("agg1:float %zu (16)\n", Agg1::offset<0, 2, 1>()); + printf("int: %zu (0)\n", Sel1::offset_from<0, 0>()); + printf("char: %zu (0)\n", Sel1::offset_from<0, 1>()); + printf("bool: %zu (0)\n", Sel1::offset_from<0, 2>()); + printf("double: %zu (0)\n", Sel1::offset_from<0, 3>()); + + using Agg1 = type_t< agg_t< int, float, agg_t< double, float >, char >, 1 >; + printf("sizeof Agg1: %zu (21)\n", Agg1::trv()); + printf("agg0: %zu (0)\n", Agg1::offset_from<0>()); + printf("agg0:int: %zu (0)\n", Agg1::offset_from<0, 0>()); + printf("agg0:float: %zu (4)\n", Agg1::offset_from<0, 1>()); + printf("agg1: %zu (8)\n", Agg1::offset_from<0, 2>()); + printf("agg1:double %zu (8)\n", Agg1::offset_from<0, 2, 0>()); + printf("agg1:float %zu (16)\n", Agg1::offset_from<0, 2, 1>()); + printf("agg0:char %zu (20)\n", Agg1::offset_from<0, 3>()); using Sel2 = type_t< sel_t< int, float, sel_t< double, float > >, 1 >; printf("sizeof Sel2: %zu (8)\n", Sel2::trv()); - printf("sel0: %zu (0)\n", Sel2::offset<0>()); - printf("sel0:int: %zu (0)\n", Sel2::offset<0, 0>()); - printf("sel0:float: %zu (0)\n", Sel2::offset<0, 1>()); - printf("sel1: %zu (0)\n", Sel2::offset<0, 2>()); - printf("sel1:double %zu (0)\n", Sel2::offset<0, 2, 0>()); - printf("sel1:float %zu (0)\n", Sel2::offset<0, 2, 1>()); + printf("sel0: %zu (0)\n", Sel2::offset_from<0>()); + printf("sel0:int: %zu (0)\n", Sel2::offset_from<0, 0>()); + printf("sel0:float: %zu (0)\n", Sel2::offset_from<0, 1>()); + printf("sel1: %zu (0)\n", Sel2::offset_from<0, 2>()); + printf("sel1:double %zu (0)\n", Sel2::offset_from<0, 2, 0>()); + printf("sel1:float %zu (0)\n", Sel2::offset_from<0, 2, 1>()); using SA1 = type_t< sel_t< int, float, agg_t< double, float > >, 1 >; printf("sizeof SA1: %zu (12)\n", SA1::trv()); - printf("sel0: %zu (0)\n", SA1::offset<0>()); - printf("sel0:int: %zu (0)\n", SA1::offset<0, 0>()); - printf("sel0:float: %zu (0)\n", SA1::offset<0, 1>()); - printf("agg0: %zu (0)\n", SA1::offset<0, 2>()); - printf("agg0:double %zu (0)\n", SA1::offset<0, 2, 0>()); - printf("agg0:float %zu (8)\n", SA1::offset<0, 2, 1>()); + printf("sel0: %zu (0)\n", SA1::offset_from<0>()); + printf("sel0:int: %zu (0)\n", SA1::offset_from<0, 0>()); + printf("sel0:float: %zu (0)\n", SA1::offset_from<0, 1>()); + printf("agg0: %zu (0)\n", SA1::offset_from<0, 2>()); + printf("agg0:double %zu (0)\n", SA1::offset_from<0, 2, 0>()); + printf("agg0:float %zu (8)\n", SA1::offset_from<0, 2, 1>()); using AS1 = type_t< agg_t< int, float, sel_t< double, float > >, 1 >; printf("sizeof AS1: %zu (16)\n", AS1::trv()); - printf("agg0: %zu (0)\n", AS1::offset<0>()); - printf("agg0:int: %zu (0)\n", AS1::offset<0, 0>()); - printf("agg0:float: %zu (4)\n", AS1::offset<0, 1>()); - printf("sel0: %zu (8)\n", AS1::offset<0, 2>()); - printf("sel0:double %zu (8)\n", AS1::offset<0, 2, 0>()); - printf("sel0:float %zu (8)\n", AS1::offset<0, 2, 1>()); + printf("agg0: %zu (0)\n", AS1::offset_from<0>()); + printf("agg0:int: %zu (0)\n", AS1::offset_from<0, 0>()); + printf("agg0:float: %zu (4)\n", AS1::offset_from<0, 1>()); + printf("sel0: %zu (8)\n", AS1::offset_from<0, 2>()); + printf("sel0:double %zu (8)\n", AS1::offset_from<0, 2, 0>()); + printf("sel0:float %zu (8)\n", AS1::offset_from<0, 2, 1>()); - printf("bool: %zu (0)\n", Sel1::offset<0, 2>()); - printf("double: %zu (0)\n", Sel1::offset<0, 3>()); + printf("bool: %zu (0)\n", Sel1::offset_from<0, 2>()); + printf("double: %zu (0)\n", Sel1::offset_from<0, 3>()); using T = type_t< agg_t< char, sel_t< int, char > , sel_t< agg_t< int, int >, agg_t< double, double > >, sel_t< int > >, 0 >; printf("%zu\n", T::trv()); @@ -91,11 +86,11 @@ int main() printf("offset: %zu\n", sel_t< int, sel_t< int, int > >::offset< 1, 1 >::value); #if 1 - printf("%zu (5)\n", T::offset<0, 2>()); - printf("%zu (5)\n", T::offset<0, 2, 1>()); /* sel> のほうだが, sel の開始までの offset なので 5 */ - printf("%zu(13)\n", T::offset<0, 2, 1, 1>()); /* sel> の二つ目の double までの offset なので 13 */ - printf("%zu (5)\n", T::offset<0, 2, 0>()); /* sel> で同上 */ - printf("%zu(21)\n", T::offset<0, 3>()); /* sel>,agg> の次なので 21 */ + printf("%zu (5)\n", T::offset_from<0, 2>()); + printf("%zu (5)\n", T::offset_from<0, 2, 1>()); /* sel> のほうだが, sel の開始までの offset なので 5 */ + printf("%zu(13)\n", T::offset_from<0, 2, 1, 1>()); /* sel> の二つ目の double までの offset なので 13 */ + printf("%zu (5)\n", T::offset_from<0, 2, 0>()); /* sel> で同上 */ + printf("%zu(21)\n", T::offset_from<0, 3>()); /* sel>,agg> の次なので 21 */ #endif printf("%s \n", typeid(get< T, 0, 2, 1>::type).name()); @@ -132,5 +127,113 @@ int main() printf("offset(align:0): %zu (16)\n", get< Aligned0_3, 0, 3>::offset); printf("offset(align:0): %zu (17)\n", get< Aligned0_3, 0, 4>::offset); printf("offset(align:0): %zu (20)\n", get< Aligned0_3, 0, 5>::offset); + + using Sub = agg_t< char, char, char >; + using Sub2 = agg_t< char, Sub, char >; + using Aligned0_4 = type_t< agg_t< char, char, char, Sub, Sub, Sub2, int, char >, 0 >; + printf("size(align:0): %zu (21)\n", get< Aligned0_4, 0 >::size); + printf("offset: %zu (0) <0,0>\n", get< Aligned0_4, 0, 0>::offset); + printf("offset: %zu (1) <0,1>\n", get< Aligned0_4, 0, 1>::offset); + printf("offset: %zu (2) <0,2>\n", get< Aligned0_4, 0, 2>::offset); + printf("offset: %zu (3) <0,3>\n", get< Aligned0_4, 0, 3>::offset); + printf("offset: %zu (3) <0,3,0>\n", get< Aligned0_4, 0, 3, 0>::offset); + printf("offset: %zu (4) <0,3,1>\n", get< Aligned0_4, 0, 3, 1>::offset); + printf("offset: %zu (5) <0,3,2>\n", get< Aligned0_4, 0, 3, 2>::offset); + printf("offset: %zu (6) <0,4,0>\n", get< Aligned0_4, 0, 4, 0>::offset); + printf("offset: %zu (7) <0,4,1>\n", get< Aligned0_4, 0, 4, 1>::offset); + printf("offset: %zu (8) <0,4,2>\n", get< Aligned0_4, 0, 4, 2>::offset); + printf("offset: %zu (9) <0,5,0>\n", get< Aligned0_4, 0, 5, 0>::offset); + printf("offset: %zu (10) <0,5,1>\n", get< Aligned0_4, 0, 5, 1>::offset); + printf("offset: %zu (10) <0,5,1,0>\n", get< Aligned0_4, 0, 5, 1, 0>::offset); + printf("offset: %zu (11) <0,5,1,1>\n", get< Aligned0_4, 0, 5, 1, 1>::offset); + printf("offset: %zu (12) <0,5,1,2>\n", get< Aligned0_4, 0, 5, 1, 2>::offset); + printf("offset: %zu (13)<0,5,2>\n", get< Aligned0_4, 0, 5, 2>::offset); + printf("offset: %zu (16)<0,6>\n", get< Aligned0_4, 0, 6>::offset); + printf("offset: %zu (20)<0,7>\n", get< Aligned0_4, 0, 7>::offset); + + using T0 = type_t< agg_t< char, type_t< agg_t< int >, 0> >, 1 >; + printf("offset: %zu <0,1> (1) align:1\n", get< T0, 0, 1 >::offset); + printf("offset: %zu <0,1,0> (4) align:1->0\n", get< T0, 0, 1, 0 >::offset); + printf("offset: %zu <0,1,0,0>(4) align:0\n", get< T0, 0, 1, 0, 0 >::offset); + + using SubT = type_t < agg_t< char, char, char >, 0 >; + using SubT2 = type_t < agg_t< char, SubT, char >, 0 >; + using Aligned0_5 = type_t< agg_t< char, char, char, SubT, SubT, SubT2, int, char >, 0 >; + printf("size(align:0): %zu (21)\n", get< Aligned0_5, 0 >::size); + printf("offset: %zu (0) <0,0>\n", get< Aligned0_5, 0, 0>::offset); + printf("offset: %zu (1) <0,1>\n", get< Aligned0_5, 0, 1>::offset); + printf("offset: %zu (2) <0,2>\n", get< Aligned0_5, 0, 2>::offset); + printf("offset: %zu (3) <0,3>\n", get< Aligned0_5, 0, 3>::offset); + printf("offset: %zu (3) <0,3,0,0>\n", get< Aligned0_5, 0, 3, 0, 0>::offset); + printf("offset: %zu (4) <0,3,0,1>\n", get< Aligned0_5, 0, 3, 0, 1>::offset); + printf("offset: %zu (5) <0,3,0,2>\n", get< Aligned0_5, 0, 3, 0, 2>::offset); + printf("offset: %zu (6) <0,4,0,0>\n", get< Aligned0_5, 0, 4, 0, 0>::offset); + printf("offset: %zu (7) <0,4,0,1>\n", get< Aligned0_5, 0, 4, 0, 1>::offset); + printf("offset: %zu (8) <0,4,0,2>\n", get< Aligned0_5, 0, 4, 0, 2>::offset); + printf("offset: %zu (9) <0,5,0,0>\n", get< Aligned0_5, 0, 5, 0, 0>::offset); + printf("offset: %zu (10) <0,5,0,1>\n", get< Aligned0_5, 0, 5, 0, 1>::offset); + printf("offset: %zu (10) <0,5,0,1,0,0>\n", get< Aligned0_5, 0, 5, 0, 1, 0, 0>::offset); + printf("offset: %zu (11) <0,5,0,1,0,1>\n", get< Aligned0_5, 0, 5, 0, 1, 0, 1>::offset); + printf("offset: %zu (12) <0,5,0,1,0,2>\n", get< Aligned0_5, 0, 5, 0, 1, 0, 2>::offset); + printf("offset: %zu (13)<0,5,2>\n", get< Aligned0_5, 0, 5, 0, 2>::offset); + printf("offset: %zu (16)<0,6>\n", get< Aligned0_5, 0, 6>::offset); + printf("offset: %zu (20)<0,7>\n", get< Aligned0_5, 0, 7>::offset); + + // alighment override + using Aligned_1_0 = type_t< agg_t< char, int, type_t< agg_t, 0>, char, char, char >, 1>; + /* 0 1 5 8 F + |-+----+---+--------| + +0 |1| 4|pad| 8| + type_t^ ^agg_t + +10 |1|1|1| + */ + printf("size(align:-): %zu (19)\n", get< Aligned_1_0, 0 >::size); + printf("offset<0,0>(align:1): %zu (0)\n", get< Aligned_1_0, 0, 0>::offset); + printf("offset<0,1>(align:1): %zu (1)\n", get< Aligned_1_0, 0, 1>::offset); + /* align=0 の type_t は上位 enclosure の placement align に従う */ + printf("offset<0,2>(align:0): %zu (5)\n", get< Aligned_1_0, 0, 2>::offset); + printf("size: %zu (8)\n", get< Aligned_1_0, 0, 2>::size); +#if 0 + printf("size: %zu (8) placement-align:1 type_t-align:%zu real-align:%zu\n", get< Aligned_1_0, 0, 2>::type::placement<1>(5), + get< Aligned_1_0, 0, 2>::type::align, + alignof_< get< Aligned_1_0, 0, 2, 0>::type >()); +#endif + /* agg_t の alignment は type_t に従う */ + printf("offset<0,2,0>(align:0): %zu (8)\n", get< Aligned_1_0, 0, 2, 0>::offset); + printf("offset<0,2,0,0>(align:0): %zu (8)\n", get< Aligned_1_0, 0, 2, 0, 0>::offset); + //printf("align (align:0): %zu (8)\n", get< Aligned_1_0, 0, 2>::type::alignof_()); // debug + printf("offset<0,3>(align:1): %zu (16)\n", get< Aligned_1_0, 0, 3>::offset); + printf("offset<0,4>(align:1): %zu (17)\n", get< Aligned_1_0, 0, 4>::offset); + printf("offset<0,5>(align:1): %zu (18)\n", get< Aligned_1_0, 0, 5>::offset); + + /* 前方,後方に padding が入る(どちらも type_t の外に padding がある) */ + using Aligned_0_1 = type_t< agg_t< char, int, char, type_t< agg_t, 2>, int, char, char >, 0>; + /* 0 4 8 |A F + |-+--+----+-+-+------| + +0 |1|pa| 4|1|p| 6/8| + ^type_t/agg_t(align=2) + 2/8|pa| 4|1|1| + +10 |--+--+----+-+-+ + 0 |2 |4 |8|9| + ~^ ^int + */ + printf("size(align:-): %zu (26)\n", get< Aligned_0_1, 0 >::size); + printf("offset<0,0>(align:0): %zu (0)\n", get< Aligned_0_1, 0, 0>::offset); + printf("offset<0,1>(align:0): %zu (4)\n", get< Aligned_0_1, 0, 1>::offset); + printf("offset<0,2>(align:0): %zu (8)\n", get< Aligned_0_1, 0, 2>::offset); + printf("offset<0,3>(align:1): %zu (10)\n", get< Aligned_0_1, 0, 3>::offset); + printf("size (align:1): %zu (8)\n", get< Aligned_0_1, 0, 3>::size); + printf("offset(align:1): %zu (10)\n", get< Aligned_0_1, 0, 3, 0, 0>::offset); + printf("type_t align<0,3> (align:0): %zu (2)\n", get< Aligned_0_1, 0, 3>::type::alignof_()); // debug + printf("real align<0,3> (align:0): %zu (8)\n", typu::alignof_< get< Aligned_0_1, 0, 3>::type::sub >()); // debug + printf("size (align:1): %zu (8)\n", get< Aligned_0_1, 0, 3>::type::trv<1>(10)); // debug + printf("size (align:0): %zu (8)\n", get< Aligned_0_1, 0, 3>::size); // debug + printf("size (align:0): %zu (8) padded\n", get< Aligned_0_1, 0, 3>::type::placement<0>(10)); // debug + printf("offset<0,4>(align:0): %zu (20)\n", get< Aligned_0_1, 0, 4>::offset); + //printf("align (align:0): %zu (4)\n", Aligned_0_1::alignof_()); // debug + printf("offset<0,5>(align:0): %zu (24)\n", get< Aligned_0_1, 0, 5>::offset); + printf("offset<0,6>(align:0): %zu (25)\n", get< Aligned_0_1, 0, 6>::offset); + + //printf("align (align:0): %zu (20) padded\n", get< Aligned_0_1, 0, 4>::type::trv<0>(20)); // debug return 0; }