From e11405d01139cd447bc2d3039d0f354f49954562 Mon Sep 17 00:00:00 2001 From: roentgen Date: Thu, 3 Jan 2019 17:20:47 +0900 Subject: [PATCH 1/6] fixed calcuration of alignment to use alignof --- include/aggregate.hpp | 4 ++-- test/recurse.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/aggregate.hpp b/include/aggregate.hpp index 32d0e56..18c124b 100644 --- a/include/aggregate.hpp +++ b/include/aggregate.hpp @@ -27,7 +27,7 @@ constexpr size_t align(size_t o) { size_t a = Align; if (Align == 0) /* natural align */ - a = sizeof(T); + a = alignof(T); size_t m = (a-1); return (o & m) ? ((o + (a-1)) & ~m) : o; } @@ -85,7 +85,7 @@ struct has_offset { template < alignment_t Align, 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 std::is_empty< T >::value ? 0 : sizeof(T); } /* aggregation diff --git a/test/recurse.cpp b/test/recurse.cpp index aefee7c..7f221b7 100644 --- a/test/recurse.cpp +++ b/test/recurse.cpp @@ -10,7 +10,7 @@ size_t foo(C c, P... p) 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()); From 59bbf3c889d274b071de7b846ad3dfcefed9a756 Mon Sep 17 00:00:00 2001 From: roentgen Date: Fri, 4 Jan 2019 21:01:13 +0900 Subject: [PATCH 2/6] test --- include/aggregate.hpp | 128 ++++++++++++++++++++++++++++++++++-------- test/recurse.cpp | 34 ++++++++++- 2 files changed, 136 insertions(+), 26 deletions(-) diff --git a/include/aggregate.hpp b/include/aggregate.hpp index 18c124b..b0f8117 100644 --- a/include/aggregate.hpp +++ b/include/aggregate.hpp @@ -14,11 +14,29 @@ struct compo_t { using alignment_t = size_t; +template < typename T> +struct has_align { + template < typename U > static auto check(U u) -> decltype(U::align, std::true_type{}); + static std::false_type check(...); + 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::align; } + +template < alignment_t A, typename T> +constexpr auto decision_align() -> std::enable_if_t< !has_align::value, alignment_t > { return A; } + +template < alignment_t A, typename T> +constexpr auto decision_align_value() -> std::enable_if_t< has_align::value, alignment_t > { return T::align == 0 ? alignof(T) : T::align; } + +template < alignment_t A, typename T> +constexpr auto decision_align_value() -> std::enable_if_t< !has_align::value, alignment_t > { return A == 0 ? alignof(T) : A; } + 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(...); -public: static bool const value = decltype(check(std::declval()))::value; }; @@ -35,28 +53,67 @@ constexpr size_t align(size_t o) /* 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_(size_t placement=0) -> decltype(T::trv()) { return T::template trv< Align >(placement); } /* trv を持たない */ template < typename T, alignment_t Align = 1 > -constexpr auto sizeof_() -> std::enable_if_t< !has_trv::value, size_t > +constexpr auto sizeof_(size_t placement=0) -> std::enable_if_t< !has_trv::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; +} + +#if 1 +template < typename Prev, alignment_t Align, size_t Acc, typename ...Ts > +struct sigma_size_impl { + static const size_t value = Acc; +}; + +template < typename Prev, alignment_t Align, size_t Acc, typename CAR> +struct sigma_size_impl< Prev, Align, Acc, CAR > { + static const alignment_t a0_ = decision_align< Align, CAR >(); + static const alignment_t a1_ = constexpr_max(decision_align_value< Align, Prev >(), decision_align_value< Align, CAR >()); + static const size_t value = decision_align< Align, Prev >() != decision_align< Align, CAR >() ? + align< a1_, CAR >(Acc + sizeof_< CAR, a1_ >(Acc)) : + align< a0_, CAR >(Acc + sizeof_< CAR, a0_ >(Acc)); +}; + +template < typename Prev, alignment_t Align, size_t Acc, typename CAR, typename ...CDR> +struct sigma_size_impl< Prev, Align, Acc, CAR, CDR... > { + static const alignment_t a0_ = decision_align< Align, CAR >(); + static const alignment_t a1_ = constexpr_max(decision_align_value< Align, Prev >(), decision_align_value< Align, CAR >()); + static const size_t value = decision_align< Align, Prev >() != decision_align< Align, CAR >() ? + sigma_size_impl< CAR, a1_, align< a1_, CAR >(Acc + sizeof_< CAR, a1_ >(Acc)), CDR... >::value : + sigma_size_impl< CAR, a0_, align< a0_, CAR >(Acc + sizeof_< CAR, a0_ >(Acc)), CDR... >::value; +}; +#endif 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 >()); + static const alignment_t a_ = decision_align< Align, CAR >(); + static const size_t value = align< a_, CAR >(Acc + sizeof_< CAR, a_ >()); }; - + */ + 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_impl< CAR, a_, align< a_, CAR >(Acc + sizeof_< CAR, a_ >()), CDR... >::value; + //static const size_t value = sigma_size< a_, align< a_, CAR >(Acc + sizeof_< CAR, a_ >()), CDR... >::value; }; template < alignment_t Align, typename ...Ts > @@ -93,7 +150,7 @@ constexpr auto offset_() -> std::enable_if_t< !has_offset::value, siz 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; } @@ -103,12 +160,18 @@ struct agg_t : public compo_t { /* 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{})); }; + struct offset< Align, Cur > { + using T_ = typename at_type< Cur, S...>::type; + static const alignment_t a_ = decision_align< Align, T_>(); + static const size_t value = align< a_, T_ >(sigma_type_list< a_ >(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... >(); + using T_ = typename at_type< Cur, S...>::type; + static const alignment_t a_ = decision_align< Align, T_>(); + static const size_t value = sigma_type_list< a_ >(typename to_types< Cur, S... >::types{}) + + offset_< a_, T_, Rest... >(); }; template < alignment_t Align, size_t... Rest > struct get { using type = void; }; @@ -120,20 +183,11 @@ struct agg_t : public compo_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; -} - /* 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_()...); } @@ -157,7 +211,7 @@ struct sel_t : public compo_t { 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...); } @@ -181,11 +235,30 @@ 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; + + template < alignment_t A > + static constexpr size_t align_(size_t o) + { + size_t a = A; + size_t m = (a-1); + return (o & m) ? ((o + (a-1)) & ~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 placement = 0) { - return sizeof_(); + if (EA == Align) + return sizeof_(); + /* 自身の align と Enclosure の align が異なる場合, + 自身の align で sizeof_ を計算し, placement を加えた offset を enclosure の align で計算する. + */ + size_t size = sizeof_(); + size_t offset = placement + size; + /* TODO: 最大 leaf 要素の size をとる alignof_ が必要 */ + //return align_()>(offset) - placement + size; + return size; } template < size_t Cur, size_t ...Rest > @@ -194,6 +267,13 @@ struct type_t < S, Align, std::enable_if_t< std::is_base_of< compo_t, S >::value return sub::template offset< Align, Rest... >::value; } + 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 にアクセスするためにはトリックが必要になった. diff --git a/test/recurse.cpp b/test/recurse.cpp index 7f221b7..9e21f1c 100644 --- a/test/recurse.cpp +++ b/test/recurse.cpp @@ -7,6 +7,17 @@ size_t foo(C c, P... p) return c; } +struct FF { + double d; + float f; +}; + +struct F { + char b; + int i; + FF d; +}; + int main() { using namespace typu; @@ -39,14 +50,15 @@ int main() 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()); + 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<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("agg0:char %zu (20)\n", Agg1::offset<0, 3>()); using Sel2 = type_t< sel_t< int, float, sel_t< double, float > >, 1 >; printf("sizeof Sel2: %zu (8)\n", Sel2::trv()); @@ -132,5 +144,23 @@ 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); + + // alighment override + using Aligned_1_0 = type_t< agg_t< char, int, type_t< agg_t, 0>, char, char, char >, 1>; + printf("size(align:-): %zu (24)\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); + printf("offset<0,2>(align:0): %zu (8)\n", get< Aligned_1_0, 0, 2>::offset); + printf("size (align:0): %zu (8)\n", get< Aligned_1_0, 0, 2>::size); + printf("offset(align:0): %zu (8)\n", get< Aligned_1_0, 0, 2, 0, 0>::offset); + printf("offset<0,3>(align:1): %zu (17)\n", get< Aligned_1_0, 0, 3>::offset); + printf("offset<0,4>(align:1): %zu (18)\n", get< Aligned_1_0, 0, 4>::offset); + printf("offset<0,5>(align:1): %zu (19)\n", get< Aligned_1_0, 0, 5>::offset); + + printf("size<0,0>(align:1): %zu (0)\n", get< Aligned_1_0, 0, 0>::size); + printf("size<0,1>(align:1): %zu (1)\n", get< Aligned_1_0, 0, 1>::size); + printf("size<0,2>(align:0): %zu (8)\n", get< Aligned_1_0, 0, 2>::size); + + printf("alignof:%zu\n", alignof(F)); return 0; } From 1b3e1292952bd5ae09ce3e85e5f054d1fa042d20 Mon Sep 17 00:00:00 2001 From: roentgen Date: Tue, 8 Jan 2019 02:23:08 +0900 Subject: [PATCH 3/6] fixed illegal offset --- include/aggregate.hpp | 257 +++++++++++++++++++++++++++++++++--------- test/recurse.cpp | 202 +++++++++++++++++++++------------ 2 files changed, 334 insertions(+), 125 deletions(-) diff --git a/include/aggregate.hpp b/include/aggregate.hpp index b0f8117..3062c2c 100644 --- a/include/aggregate.hpp +++ b/include/aggregate.hpp @@ -14,6 +14,26 @@ struct compo_t { using alignment_t = size_t; +template < typename T > +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, std::true_type{}); @@ -22,13 +42,13 @@ struct has_align { }; template < alignment_t A, typename T> -constexpr auto decision_align() -> std::enable_if_t< has_align::value, alignment_t > { return T::align; } +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 A, typename T> -constexpr auto decision_align_value() -> std::enable_if_t< has_align::value, alignment_t > { return T::align == 0 ? alignof(T) : T::align; } +constexpr auto decision_align_value() -> std::enable_if_t< has_align::value, alignment_t > { return T::align == 0 ? alignof_() : T::align; } template < alignment_t A, typename T> constexpr auto decision_align_value() -> std::enable_if_t< !has_align::value, alignment_t > { return A == 0 ? alignof(T) : A; } @@ -45,7 +65,17 @@ constexpr size_t align(size_t o) { size_t a = Align; if (Align == 0) /* natural align */ - a = alignof(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; } @@ -53,11 +83,34 @@ constexpr size_t align(size_t o) /* trv を持つ. trv はテンプレート引数に align を持つこと. (テンプレート引数はデフォルトの alignment を持つべき) */ -template < typename T, alignment_t Align = 1 > constexpr auto sizeof_(size_t placement=0) -> decltype(T::trv()) { return T::template trv< Align >(placement); } +template < typename T, alignment_t Align = 1 > constexpr auto sizeof_() -> decltype(T::trv()) +{ + return T::template trv< Align >(); +} /* trv を持たない */ template < typename T, alignment_t Align = 1 > -constexpr auto sizeof_(size_t placement=0) -> std::enable_if_t< !has_trv::value, size_t > +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 LastAlign, alignment_t Align = 1 > +constexpr auto sizeof_(size_t place) -> std::enable_if_t< has_placement::value, size_t > +{ + return T::template placement< LastAlign, Align >(place); +} + +template < typename T, alignment_t LastAlign, alignment_t Align = 1 > +constexpr auto sizeof_(size_t) -> std::enable_if_t< !has_placement::value, size_t > { return align(sizeof(T)); } @@ -79,72 +132,78 @@ struct sigma_size_impl { template < typename Prev, alignment_t Align, size_t Acc, typename CAR> struct sigma_size_impl< Prev, Align, Acc, CAR > { - static const alignment_t a0_ = decision_align< Align, CAR >(); - static const alignment_t a1_ = constexpr_max(decision_align_value< Align, Prev >(), decision_align_value< Align, CAR >()); + static const alignment_t a0_ = decision_align_value< Align, CAR >(); + static const alignment_t a1_ = decision_align_value< Align, Prev >(); static const size_t value = decision_align< Align, Prev >() != decision_align< Align, CAR >() ? - align< a1_, CAR >(Acc + sizeof_< CAR, a1_ >(Acc)) : - align< a0_, CAR >(Acc + sizeof_< CAR, a0_ >(Acc)); + align< a0_, CAR >(Acc + sizeof_< CAR, a1_, a0_ >(Acc)) : + align< a0_, CAR >(Acc + sizeof_< CAR, a1_, a0_ >(Acc)); }; template < typename Prev, alignment_t Align, size_t Acc, typename CAR, typename ...CDR> struct sigma_size_impl< Prev, Align, Acc, CAR, CDR... > { - static const alignment_t a0_ = decision_align< Align, CAR >(); - static const alignment_t a1_ = constexpr_max(decision_align_value< Align, Prev >(), decision_align_value< Align, CAR >()); + static const alignment_t a0_ = decision_align_value< Align, CAR >(); + static const alignment_t a1_ = decision_align_value< Align, Prev >(); static const size_t value = decision_align< Align, Prev >() != decision_align< Align, CAR >() ? - sigma_size_impl< CAR, a1_, align< a1_, CAR >(Acc + sizeof_< CAR, a1_ >(Acc)), CDR... >::value : - sigma_size_impl< CAR, a0_, align< a0_, CAR >(Acc + sizeof_< CAR, a0_ >(Acc)), CDR... >::value; + sigma_size_impl< CAR, a0_, align< a0_, CAR >(Acc + sizeof_< CAR, a1_, a0_ >(Acc)), CDR... >::value : + sigma_size_impl< CAR, a0_, align< a0_, CAR >(Acc + sizeof_< CAR, a1_, a0_ >(Acc)), CDR... >::value; }; #endif + 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 alignment_t a_ = decision_align< Align, CAR >(); - static const size_t value = align< a_, CAR >(Acc + sizeof_< CAR, a_ >()); + static const size_t value = align< Align, CAR >(Acc + sizeof_< CAR, a_, a_ >(Acc)); }; - */ - +*/ template < alignment_t Align, size_t Acc, typename CAR, typename ...CDR> struct sigma_size< Align, Acc, CAR, CDR... > { static const alignment_t a_ = decision_align< Align, CAR >(); - static const size_t value = sigma_size_impl< CAR, a_, align< a_, CAR >(Acc + sizeof_< CAR, a_ >()), CDR... >::value; - //static const size_t value = sigma_size< a_, align< a_, CAR >(Acc + sizeof_< CAR, a_ >()), CDR... >::value; + //static const size_t value = sigma_size_impl< CAR, a_, align< a_, CAR >(Acc + sizeof_< CAR, a_ , Align>(Acc)), CDR... >::value; + static const size_t value = sigma_size< Align, align< a_, CAR >(Acc + sizeof_< CAR, a_, 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, 0, Ts... >::value; + 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, 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 ? 0 : sizeof(T); + return Acc + (std::is_empty< T >::value ? 0 : sizeof(T)); } - + /* aggregation */ template < typename ...S > @@ -155,23 +214,43 @@ struct agg_t : public compo_t { 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 Last, 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 > { + 計算の途中も制約を満たす必要がある. + + FIXME: + type がもし type_t であって、アラインメントオーバーライドが行われるとしても, + 一回の sigma_type_list の呼び出しを通じては一貫して上位の制約が用いられるべきだが + なぜか逆でないと正しく動かない. + 具体的には static const alignment_t a_ = decision_align< Align, T) >(); ではなく, + 単に Align を用いるべきだ. + */ +#if 1 + template < alignment_t Align, size_t Acc, size_t Cur > + struct offset< Align, Acc, Cur > { + /* 各 row 内の総和 */ using T_ = typename at_type< Cur, S...>::type; - static const alignment_t a_ = decision_align< Align, T_>(); - static const size_t value = align< a_, T_ >(sigma_type_list< a_ >(typename to_types< Cur, S... >::types{})); + static const alignment_t a_ = Align; //decision_align< Align, T_>(); + static const size_t value = align< Align, T_ >(sigma_type_list< a_, Acc >(typename to_types< Cur, S... >::types{})); }; - - template < alignment_t Align, size_t Cur, size_t ... Rest > - struct offset< Align, Cur, Rest...> { +#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; - static const alignment_t a_ = decision_align< Align, T_>(); - static const size_t value = sigma_type_list< a_ >(typename to_types< Cur, S... >::types{}) + - offset_< a_, T_, Rest... >(); + static const alignment_t a_ = Align; //decision_align< Align, T_>(); + /* column ごとの総和: */ + static const size_t s = align< Align, T_ >(sigma_type_list< a_, Acc >(typename to_types< Cur, S... >::types{})); + + //static const size_t value = align< Align, T_ >(offset_< a_, s, T_, Rest... >()); + static const size_t value = align< Align, T_ >(offset_< Align, s, typename at_type< Cur, S... >::type, Rest... >()); }; template < alignment_t Align, size_t... Rest > struct get { using type = void; }; @@ -181,6 +260,10 @@ 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_()...); + } }; /* selector */ @@ -192,11 +275,17 @@ struct sel_t : public compo_t { 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 Last, 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; }; @@ -205,7 +294,7 @@ struct sel_t : public compo_t { struct get< Align, Pos, Rest...> { using type = typename at_type< Pos, S... >::type::template get< Align, Rest ... >::type; }; - + }; template < typename T, T ...S > @@ -231,6 +320,16 @@ template < typename S, alignment_t Align, typename Enabled = void > struct type_t { }; +/* 収容されるすべての型は固有のアラインメントを持つが, + 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 の収容型は +*/ 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; @@ -239,9 +338,10 @@ struct type_t < S, Align, std::enable_if_t< std::is_base_of< compo_t, S >::value template < alignment_t A > static constexpr size_t align_(size_t o) { + static_assert(A != 0, "align_ need not align-mode"); size_t a = A; size_t m = (a-1); - return (o & m) ? ((o + (a-1)) & ~m) : o; + return (o & m) ? ((o + m) & ~m): o; } /* type_t をネストして alignment を override するとき, @@ -254,19 +354,61 @@ struct type_t < S, Align, std::enable_if_t< std::is_base_of< compo_t, S >::value /* 自身の align と Enclosure の align が異なる場合, 自身の align で sizeof_ を計算し, placement を加えた offset を enclosure の align で計算する. */ + size_t ma = typu::alignof_(); + /* effective alignment for the members */ + size_t iea = Align == 0 ? ma : Align; + /* effective alignment for placement */ + size_t pea = EA == 0 ? ma : EA; + size_t size = sizeof_(); - size_t offset = placement + size; + /* ヘッドルームは,自身のアラインメント制約よりも大きなアラインメントに配置されるときに生じる. + ヘッドルームの大きさはコンテナの padding に含まれ, sizeof_ には含まれない. このため trv は sizeof_ とは異なる. */ + size_t offset = placement; /* TODO: 最大 leaf 要素の size をとる alignof_ が必要 */ - //return align_()>(offset) - placement + size; - return size; + return align_< EA ? EA : typu::alignof_() >(offset) - placement + size; + //return ((EA == 0) ? align_< typu::alignof_() >(offset) : align_< EA >(offset)) - placement + size; + } + + /* type_t をネストして alignment を override するとき, + type_t の配置オフセットによって type_t 自身が pack を含む可能性がある */ + template < alignment_t LastAlign, alignment_t EA = Align > + constexpr static size_t placement(size_t place = 0) + { + if (EA == Align) { + auto r = sizeof_(place); + return r; + } + /* 自身の align と Enclosure の align が異なる場合, + 自身の align で sizeof_ を計算し, placement を加えた offset を enclosure の align で計算する. + */ + size_t size = sizeof_(place); + //return align_< constexpr_max((Align == 0 ? typu::alignof_() : Align), + // (EA == 0 ? typu::alignof_() : EA)) >(place) - place + size; + return align_< EA ? EA : (Align ? Align : typu::alignof_()) >(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; + 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; + } + + static constexpr alignment_t alignof__() {return Align == 0 ? sub::alignof_() : Align;} + + template < alignment_t A, size_t Acc, size_t Pos, size_t ... Rest > + struct offset { + static const size_t value = check_aligned< A, sub::template offset< alignof__(), Acc, Rest... >::value >(); + }; + 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 > @@ -288,6 +430,11 @@ 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 alignof__(); + } }; /* get 公開インターフェイス. @@ -299,7 +446,7 @@ 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 offset = T::template offset_from(); }; } diff --git a/test/recurse.cpp b/test/recurse.cpp index 9e21f1c..f5de66b 100644 --- a/test/recurse.cpp +++ b/test/recurse.cpp @@ -1,23 +1,6 @@ #include #include -template < typename C, typename...P > -size_t foo(C c, P... p) -{ - return c; -} - -struct FF { - double d; - float f; -}; - -struct F { - char b; - int i; - FF d; -}; - int main() { using namespace typu; @@ -38,58 +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>()); + 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<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("agg0:char %zu (20)\n", Agg1::offset<0, 3>()); + 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()); @@ -103,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()); @@ -145,22 +128,101 @@ int main() 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 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>; - printf("size(align:-): %zu (24)\n", get< Aligned_1_0, 0 >::size); + /* 0 1 5 8 F + |-+----+---+--------| + +0 |1| 4|pad| 8| + +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); - printf("offset<0,2>(align:0): %zu (8)\n", get< Aligned_1_0, 0, 2>::offset); - printf("size (align:0): %zu (8)\n", get< Aligned_1_0, 0, 2>::size); - printf("offset(align:0): %zu (8)\n", get< Aligned_1_0, 0, 2, 0, 0>::offset); - printf("offset<0,3>(align:1): %zu (17)\n", get< Aligned_1_0, 0, 3>::offset); - printf("offset<0,4>(align:1): %zu (18)\n", get< Aligned_1_0, 0, 4>::offset); - printf("offset<0,5>(align:1): %zu (19)\n", get< Aligned_1_0, 0, 5>::offset); - - printf("size<0,0>(align:1): %zu (0)\n", get< Aligned_1_0, 0, 0>::size); - printf("size<0,1>(align:1): %zu (1)\n", get< Aligned_1_0, 0, 1>::size); - printf("size<0,2>(align:0): %zu (8)\n", get< Aligned_1_0, 0, 2>::size); - - printf("alignof:%zu\n", alignof(F)); + 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<0,1>(5), + get< Aligned_1_0, 0, 2>::type::align, + alignof_< get< Aligned_1_0, 0, 2, 0>::type >()); +#endif + /* agg_t の alignment は未定義 */ + printf("offset<0,2,0>(align:0): %zu (5)\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 が入る */ + using Aligned_0_1 = type_t< agg_t< char, int, char, type_t< agg_t, 2>, int, char, char >, 0>; + /* 0 1 4 8 |D F| + |-+---+----+-------| + +0 |1|pad| 4| 8|pad| + +10 |1|1|1| + */ + 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,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; } From e0100dd40d3afbee63d115851323eccf52990fff Mon Sep 17 00:00:00 2001 From: roentgen Date: Tue, 8 Jan 2019 02:45:05 +0900 Subject: [PATCH 4/6] removed unused type and params (LastAlign, sigma_size_impl) --- include/aggregate.hpp | 97 +++++++++++-------------------------------- test/recurse.cpp | 4 +- 2 files changed, 27 insertions(+), 74 deletions(-) diff --git a/include/aggregate.hpp b/include/aggregate.hpp index 3062c2c..788b965 100644 --- a/include/aggregate.hpp +++ b/include/aggregate.hpp @@ -103,14 +103,14 @@ struct has_placement { }; /* placement を考慮する size 計算を呼び出す. */ -template < typename T, alignment_t LastAlign, alignment_t Align = 1 > -constexpr auto sizeof_(size_t place) -> std::enable_if_t< has_placement::value, size_t > +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< LastAlign, Align >(place); + return T::template placement< Align >(place); } -template < typename T, alignment_t LastAlign, alignment_t Align = 1 > -constexpr auto sizeof_(size_t) -> std::enable_if_t< !has_placement::value, size_t > +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)); } @@ -123,50 +123,16 @@ constexpr CAR constexpr_max(CAR&& car, CDR&&... cdr){ (void)s{ (void(r = r < cdr ? cdr : r),0)... }; return r; } - -#if 1 -template < typename Prev, alignment_t Align, size_t Acc, typename ...Ts > -struct sigma_size_impl { - static const size_t value = Acc; -}; - -template < typename Prev, alignment_t Align, size_t Acc, typename CAR> -struct sigma_size_impl< Prev, Align, Acc, CAR > { - static const alignment_t a0_ = decision_align_value< Align, CAR >(); - static const alignment_t a1_ = decision_align_value< Align, Prev >(); - static const size_t value = decision_align< Align, Prev >() != decision_align< Align, CAR >() ? - align< a0_, CAR >(Acc + sizeof_< CAR, a1_, a0_ >(Acc)) : - align< a0_, CAR >(Acc + sizeof_< CAR, a1_, a0_ >(Acc)); -}; - -template < typename Prev, alignment_t Align, size_t Acc, typename CAR, typename ...CDR> -struct sigma_size_impl< Prev, Align, Acc, CAR, CDR... > { - static const alignment_t a0_ = decision_align_value< Align, CAR >(); - static const alignment_t a1_ = decision_align_value< Align, Prev >(); - static const size_t value = decision_align< Align, Prev >() != decision_align< Align, CAR >() ? - sigma_size_impl< CAR, a0_, align< a0_, CAR >(Acc + sizeof_< CAR, a1_, a0_ >(Acc)), CDR... >::value : - sigma_size_impl< CAR, a0_, align< a0_, CAR >(Acc + sizeof_< CAR, a1_, a0_ >(Acc)), CDR... >::value; -}; -#endif - 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 alignment_t a_ = decision_align< Align, CAR >(); - static const size_t value = align< Align, CAR >(Acc + sizeof_< CAR, a_, a_ >(Acc)); -}; -*/ template < alignment_t Align, size_t Acc, typename CAR, typename ...CDR> struct sigma_size< Align, Acc, CAR, CDR... > { static const alignment_t a_ = decision_align< Align, CAR >(); - //static const size_t value = sigma_size_impl< CAR, a_, align< a_, CAR >(Acc + sizeof_< CAR, a_ , Align>(Acc)), CDR... >::value; - static const size_t value = sigma_size< Align, align< a_, CAR >(Acc + sizeof_< CAR, a_, a_ >(Acc)), CDR... >::value; + static const size_t value = sigma_size< Align, align< a_, CAR >(Acc + sizeof_< CAR, a_ >(Acc)), CDR... >::value; }; template < alignment_t Align, size_t Acc, typename ...Ts > @@ -214,7 +180,7 @@ struct agg_t : public compo_t { return sigma_size< Align, 0, S... >::value; } - template < alignment_t Last, alignment_t Align = 1 > + template < alignment_t Align = 1 > static constexpr size_t placement(size_t place = 0) { return trv(place); @@ -224,33 +190,31 @@ struct agg_t : public compo_t { /* offset は Idx-1 までのサイズの総和だが, address alignment 制約の保証のために Idx の type を知る必要がある. 計算の途中も制約を満たす必要がある. - - FIXME: - type がもし type_t であって、アラインメントオーバーライドが行われるとしても, - 一回の sigma_type_list の呼び出しを通じては一貫して上位の制約が用いられるべきだが - なぜか逆でないと正しく動かない. - 具体的には static const alignment_t a_ = decision_align< Align, T) >(); ではなく, - 単に Align を用いるべきだ. + このときの alignment は placement alignment で, 型の要求 alignment に優先する. + (alignment がオーバーライドされるとき, 内側の type_t の align より placement-align が優先される. + ただし type_t の内部は type_t の align が適用される. この padding を 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 も同様(FIXME) + get< T, 0, 1, 0, 0>::offset は内部の alignment に従い 16 */ #if 1 template < alignment_t Align, size_t Acc, size_t Cur > struct offset< Align, Acc, Cur > { - /* 各 row 内の総和 */ + /* 最終 column の 総和. 最後の要素の加算前の値を返す */ using T_ = typename at_type< Cur, S...>::type; - static const alignment_t a_ = Align; //decision_align< Align, T_>(); - static const size_t value = align< Align, T_ >(sigma_type_list< a_, Acc >(typename to_types< Cur, S... >::types{})); + 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; - static const alignment_t a_ = Align; //decision_align< Align, T_>(); /* column ごとの総和: */ - static const size_t s = align< Align, T_ >(sigma_type_list< a_, Acc >(typename to_types< Cur, S... >::types{})); + 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_< a_, s, T_, Rest... >()); - static const size_t value = align< Align, T_ >(offset_< Align, s, typename at_type< Cur, S... >::type, Rest... >()); + 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; }; @@ -275,7 +239,7 @@ struct sel_t : public compo_t { return constexpr_max(sizeof_()...); } - template < alignment_t Last, alignment_t Align = 1 > + template < alignment_t Align = 1 > constexpr static size_t placement(size_t place=0) { return trv(place); @@ -347,43 +311,32 @@ struct type_t < S, Align, std::enable_if_t< std::is_base_of< compo_t, S >::value /* type_t をネストして alignment を override するとき, type_t の配置オフセットによって type_t 自身が pack を含む可能性がある */ template < alignment_t EA = Align > - constexpr static size_t trv(size_t placement = 0) + constexpr static size_t trv(size_t place = 0) { if (EA == Align) return sizeof_(); /* 自身の align と Enclosure の align が異なる場合, 自身の align で sizeof_ を計算し, placement を加えた offset を enclosure の align で計算する. */ - size_t ma = typu::alignof_(); - /* effective alignment for the members */ - size_t iea = Align == 0 ? ma : Align; - /* effective alignment for placement */ - size_t pea = EA == 0 ? ma : EA; - size_t size = sizeof_(); /* ヘッドルームは,自身のアラインメント制約よりも大きなアラインメントに配置されるときに生じる. ヘッドルームの大きさはコンテナの padding に含まれ, sizeof_ には含まれない. このため trv は sizeof_ とは異なる. */ - size_t offset = placement; - /* TODO: 最大 leaf 要素の size をとる alignof_ が必要 */ - return align_< EA ? EA : typu::alignof_() >(offset) - placement + size; - //return ((EA == 0) ? align_< typu::alignof_() >(offset) : align_< EA >(offset)) - placement + size; + return align_< EA ? EA : typu::alignof_() >(place) - place + size; } /* type_t をネストして alignment を override するとき, type_t の配置オフセットによって type_t 自身が pack を含む可能性がある */ - template < alignment_t LastAlign, alignment_t EA = Align > + template < alignment_t EA = Align > constexpr static size_t placement(size_t place = 0) { if (EA == Align) { - auto r = sizeof_(place); + auto r = sizeof_(place); return r; } /* 自身の align と Enclosure の align が異なる場合, 自身の align で sizeof_ を計算し, placement を加えた offset を enclosure の align で計算する. */ - size_t size = sizeof_(place); - //return align_< constexpr_max((Align == 0 ? typu::alignof_() : Align), - // (EA == 0 ? typu::alignof_() : EA)) >(place) - place + size; + size_t size = sizeof_(place); return align_< EA ? EA : (Align ? Align : typu::alignof_()) >(place) - place + size; } diff --git a/test/recurse.cpp b/test/recurse.cpp index f5de66b..1899e42 100644 --- a/test/recurse.cpp +++ b/test/recurse.cpp @@ -187,7 +187,7 @@ int main() 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<0,1>(5), + 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 @@ -217,7 +217,7 @@ int main() 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,0>(10)); // 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); From 172548c3d0629edd361da877c5c87ca8b987d63c Mon Sep 17 00:00:00 2001 From: roentgen Date: Tue, 8 Jan 2019 03:07:28 +0900 Subject: [PATCH 5/6] refactored --- include/aggregate.hpp | 57 ++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/include/aggregate.hpp b/include/aggregate.hpp index 788b965..464a81a 100644 --- a/include/aggregate.hpp +++ b/include/aggregate.hpp @@ -36,7 +36,7 @@ constexpr auto alignof_() -> std::enable_if_t< !has_alignof< T >::value, alignme template < typename T> struct has_align { - template < typename U > static auto check(U u) -> decltype(U::align, std::true_type{}); + template < typename U > static auto check(U u) -> decltype(U::align_mode, std::true_type{}); static std::false_type check(...); static bool const value = decltype(check(std::declval()))::value; }; @@ -47,19 +47,6 @@ constexpr auto decision_align() -> std::enable_if_t< has_align::value, alignm template < alignment_t A, typename T> constexpr auto decision_align() -> std::enable_if_t< !has_align::value, alignment_t > { return A; } -template < alignment_t A, typename T> -constexpr auto decision_align_value() -> std::enable_if_t< has_align::value, alignment_t > { return T::align == 0 ? alignof_() : T::align; } - -template < alignment_t A, typename T> -constexpr auto decision_align_value() -> std::enable_if_t< !has_align::value, alignment_t > { return A == 0 ? alignof(T) : A; } - -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; -}; - template < alignment_t Align, typename T > constexpr size_t align(size_t o) { @@ -80,10 +67,19 @@ constexpr size_t align(size_t o) 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()) +template < typename T, alignment_t Align = 1 > +constexpr auto sizeof_() -> std::enable_if_t< has_trv::value, size_t > { return T::template trv< Align >(); } @@ -259,6 +255,10 @@ struct sel_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_()...); + } }; template < typename T, T ...S > @@ -297,12 +297,13 @@ struct type_t { 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_ need not align-mode"); + 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; @@ -321,7 +322,7 @@ struct type_t < S, Align, std::enable_if_t< std::is_base_of< compo_t, S >::value size_t size = sizeof_(); /* ヘッドルームは,自身のアラインメント制約よりも大きなアラインメントに配置されるときに生じる. ヘッドルームの大きさはコンテナの padding に含まれ, sizeof_ には含まれない. このため trv は sizeof_ とは異なる. */ - return align_< EA ? EA : typu::alignof_() >(place) - place + size; + return align_< EA ? EA : align >(place) - place + size; } /* type_t をネストして alignment を override するとき, @@ -329,21 +330,20 @@ struct type_t < S, Align, std::enable_if_t< std::is_base_of< compo_t, S >::value template < alignment_t EA = Align > constexpr static size_t placement(size_t place = 0) { - if (EA == Align) { - auto r = sizeof_(place); - return r; - } + 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 ? Align : typu::alignof_()) >(place) - place + size; + return align_< EA ? EA : align >(place) - place + size; } /* ignore the first 0 */ template < size_t Cur, size_t ...Rest > constexpr static size_t offset_from() { + static_assert(Cur == 0, "type_t has to get 0 for the first enclosure"); return sub::template offset< Align, 0, Rest... >::value; } @@ -355,11 +355,9 @@ struct type_t < S, Align, std::enable_if_t< std::is_base_of< compo_t, S >::value return offs; } - static constexpr alignment_t alignof__() {return Align == 0 ? sub::alignof_() : Align;} - template < alignment_t A, size_t Acc, size_t Pos, size_t ... Rest > struct offset { - static const size_t value = check_aligned< A, sub::template offset< alignof__(), Acc, Rest... >::value >(); + static const size_t value = check_aligned< A, sub::template offset< align, Acc, Rest... >::value >(); }; template < alignment_t A, size_t... Rest > struct get { using type = void; }; @@ -384,10 +382,7 @@ struct type_t < S, Align, std::enable_if_t< std::is_base_of< compo_t, S >::value using type = sub; }; - static constexpr alignment_t alignof_() - { - return alignof__(); - } + static constexpr alignment_t alignof_() { return align; } }; /* get 公開インターフェイス. @@ -398,7 +393,7 @@ 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 size = sizeof_(); static const size_t offset = T::template offset_from(); }; From dd51c2b344ed6064548fc1bb894f24eb3d12ea17 Mon Sep 17 00:00:00 2001 From: roentgen Date: Tue, 8 Jan 2019 06:33:46 +0900 Subject: [PATCH 6/6] fixed calcuration of type_t's 1st containee's offset --- include/aggregate.hpp | 25 +++++++++++-------------- test/recurse.cpp | 25 ++++++++++++++++++------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/include/aggregate.hpp b/include/aggregate.hpp index 464a81a..0648090 100644 --- a/include/aggregate.hpp +++ b/include/aggregate.hpp @@ -33,7 +33,6 @@ constexpr auto alignof_() -> std::enable_if_t< !has_alignof< T >::value, alignme return alignof(T); } - template < typename T> struct has_align { template < typename U > static auto check(U u) -> decltype(U::align_mode, std::true_type{}); @@ -188,12 +187,12 @@ struct agg_t : public compo_t { 計算の途中も制約を満たす必要がある. このときの alignment は placement alignment で, 型の要求 alignment に優先する. (alignment がオーバーライドされるとき, 内側の type_t の align より placement-align が優先される. - ただし type_t の内部は type_t の align が適用される. この padding を type_t が持つ. + ただし 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 も同様(FIXME) - get< T, 0, 1, 0, 0>::offset は内部の alignment に従い 16 + 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 > @@ -284,15 +283,15 @@ template < typename S, alignment_t Align, typename Enabled = void > struct type_t { }; -/* 収容されるすべての型は固有のアラインメントを持つが, - type_t はそれをオーバーライドする. - 一方, 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 の収容型は + とすると, 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 > > { @@ -320,8 +319,6 @@ struct type_t < S, Align, std::enable_if_t< std::is_base_of< compo_t, S >::value 自身の align で sizeof_ を計算し, placement を加えた offset を enclosure の align で計算する. */ size_t size = sizeof_(); - /* ヘッドルームは,自身のアラインメント制約よりも大きなアラインメントに配置されるときに生じる. - ヘッドルームの大きさはコンテナの padding に含まれ, sizeof_ には含まれない. このため trv は sizeof_ とは異なる. */ return align_< EA ? EA : align >(place) - place + size; } @@ -346,18 +343,18 @@ struct type_t < S, Align, std::enable_if_t< std::is_base_of< compo_t, S >::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"); + 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 { - static const size_t value = check_aligned< A, sub::template offset< align, Acc, Rest... >::value >(); + /* 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; }; @@ -371,7 +368,7 @@ struct type_t < S, Align, std::enable_if_t< std::is_base_of< compo_t, S >::value また 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... > { diff --git a/test/recurse.cpp b/test/recurse.cpp index 1899e42..1a17053 100644 --- a/test/recurse.cpp +++ b/test/recurse.cpp @@ -151,6 +151,11 @@ int main() 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 >; @@ -179,11 +184,13 @@ int main() /* 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 @@ -191,20 +198,24 @@ int main() get< Aligned_1_0, 0, 2>::type::align, alignof_< get< Aligned_1_0, 0, 2, 0>::type >()); #endif - /* agg_t の alignment は未定義 */ - printf("offset<0,2,0>(align:0): %zu (5)\n", get< Aligned_1_0, 0, 2, 0>::offset); + /* 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 が入る */ + /* 前方,後方に 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 1 4 8 |D F| - |-+---+----+-------| - +0 |1|pad| 4| 8|pad| - +10 |1|1|1| + /* 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);