1 // PR c++/84684
2 // { dg-do compile { target c++17 } }
3 
4 typedef decltype (sizeof (0)) size_t;
5 
6 namespace std {
7   template<class _E>
8   struct initializer_list
9   {
10     typedef _E value_type;
11     typedef const _E& reference;
12     typedef const _E& const_reference;
13     typedef size_t size_type;
14     typedef const _E* iterator;
15     typedef const _E* const_iterator;
16     iterator _M_array;
17     size_type _M_len;
initializer_listinitializer_list18     constexpr initializer_list(const_iterator __a, size_type __l) : _M_array(__a), _M_len(__l) { }
initializer_listinitializer_list19     constexpr initializer_list() noexcept : _M_array(0), _M_len(0) { }
sizeinitializer_list20     constexpr size_type size() const noexcept { return _M_len; }
begininitializer_list21     constexpr const_iterator begin() const noexcept { return _M_array; }
endinitializer_list22     constexpr const_iterator end() const noexcept { return begin() + size(); }
23   };
24 }
25 
26 template <typename E, size_t N>
27 struct array
28 {
29   constexpr E &operator[](size_t n) noexcept { return elems[n]; }
30   constexpr const E &operator[](size_t n) const noexcept { return elems[n]; }
sizearray31   constexpr size_t size() const { return N; }
32   E elems[N];
33 };
34 
35 template<typename T>
36 constexpr
37 inline T
max(std::initializer_list<T> i)38 max (std::initializer_list<T> i)
39 {
40   const T *b = i.begin ();
41   const T *e = i.end ();
42   if (b == e) return *b;
43   const T *r = b;
44   while (++b != e)
45   if (*r < *b)
46     r = b;
47   return *r;
48 }
49 
50 template <typename alphabet_type>
to_char(alphabet_type const alph)51 constexpr char to_char(alphabet_type const alph)
52 {
53   return alph.to_char();
54 }
55 
56 template <typename ...alphabet_types>
57 struct union_composition
58 {
59   static constexpr size_t value_size = (alphabet_types::value_size + ... );
60   unsigned char _value;
61   template <size_t fixed_size, typename alphabet_t>
value_to_char_helperunion_composition62   static constexpr auto value_to_char_helper(alphabet_t alphabet)
63   {
64     array<char, fixed_size> value_to_char{};
65     for (size_t i = 0u; i < alphabet_t::value_size; ++i)
66       value_to_char[i] = to_char(alphabet.assign_rank(i));
67     return value_to_char;
68   }
69 
make_value_to_charunion_composition70   static constexpr auto make_value_to_char()
71   {
72     constexpr auto N = sizeof...(alphabet_types);
73     constexpr array<size_t, N> alphabet_sizes { alphabet_types::value_size... };
74     constexpr size_t fixed_size = max({alphabet_types::value_size...});
75     array value_to_char_tables = array<array<char, fixed_size>, N> {
76       value_to_char_helper<fixed_size>(alphabet_types{})...
77     };
78     array<char, value_size> value_to_char{};
79     for (size_t i = 0u, value = 0u; i < N; ++i)
80       for (size_t k = 0u; k < alphabet_sizes[i]; ++k, ++value)
81         value_to_char[value] = value_to_char_tables[i][k];
82     return value_to_char;
83   }
84 };
85 
86 struct gap
87 {
to_chargap88   constexpr char to_char() const noexcept { return '-'; }
assign_rankgap89   constexpr gap & assign_rank([[maybe_unused]] bool const i) noexcept { return *this; }
90   static constexpr size_t value_size{1};
91 };
92 
93 struct dna4
94 {
to_chardna495   constexpr char to_char() const noexcept { return value_to_char[_value]; }
assign_rankdna496   constexpr dna4 & assign_rank(unsigned char const c) { _value = c; return *this; }
97   static constexpr size_t value_size{4};
98   static constexpr char value_to_char[value_size] { 'A', 'C', 'G', 'T' };
99   unsigned char _value;
100 };
101 
102 struct dna5
103 {
to_chardna5104   constexpr char to_char() const noexcept { return value_to_char[_value]; }
assign_rankdna5105   constexpr dna5 & assign_rank(unsigned char const c) { _value = c; return *this; }
106   static constexpr size_t value_size{5};
107   static constexpr char value_to_char[value_size] { 'A', 'C', 'G', 'T', 'N' };
108   unsigned char _value;
109 };
110 
111 constexpr array value_to_char1 = union_composition<dna4>::make_value_to_char();
112 static_assert(value_to_char1.size() == 4u);
113 static_assert(value_to_char1[0] == 'A');
114 static_assert(value_to_char1[1] == 'C');
115 static_assert(value_to_char1[2] == 'G');
116 static_assert(value_to_char1[3] == 'T');
117 
118 constexpr array value_to_char2 = union_composition<dna4, gap>::make_value_to_char();
119 static_assert(value_to_char2.size() == 5u);
120 static_assert(value_to_char2[0] == 'A');
121 static_assert(value_to_char2[1] == 'C');
122 static_assert(value_to_char2[2] == 'G');
123 static_assert(value_to_char2[3] == 'T');
124 static_assert(value_to_char2[4] == '-');
125 
126 constexpr array value_to_char3 = union_composition<dna4, gap, dna5>::make_value_to_char();
127 static_assert(value_to_char3.size() == 10u);
128 static_assert(value_to_char3[0] == 'A');
129 static_assert(value_to_char3[1] == 'C');
130 static_assert(value_to_char3[2] == 'G');
131 static_assert(value_to_char3[3] == 'T');
132 static_assert(value_to_char3[4] == '-');
133 static_assert(value_to_char3[5] == 'A');
134 static_assert(value_to_char3[6] == 'C');
135 static_assert(value_to_char3[7] == 'G');
136 static_assert(value_to_char3[8] == 'T');
137 static_assert(value_to_char3[9] == 'N');
138 
139 constexpr array value_to_char4 = union_composition<dna5, gap, dna4>::make_value_to_char();
140 static_assert(value_to_char4.size() == 10u);
141 static_assert(value_to_char4[0] == 'A');
142 static_assert(value_to_char4[1] == 'C');
143 static_assert(value_to_char4[2] == 'G');
144 static_assert(value_to_char4[3] == 'T');
145 static_assert(value_to_char4[4] == 'N');
146 static_assert(value_to_char4[5] == '-');
147 static_assert(value_to_char4[6] == 'A');
148 static_assert(value_to_char4[7] == 'C');
149 static_assert(value_to_char4[8] == 'G');
150 static_assert(value_to_char4[9] == 'T');
151 
152 constexpr array value_to_char5 = union_composition<gap, dna4, dna5>::make_value_to_char();
153 static_assert(value_to_char5.size() == 10u);
154 static_assert(value_to_char5[0] == '-');
155 static_assert(value_to_char5[1] == 'A');
156 static_assert(value_to_char5[2] == 'C');
157 static_assert(value_to_char5[3] == 'G');
158 static_assert(value_to_char5[4] == 'T');
159 static_assert(value_to_char5[5] == 'A');
160 static_assert(value_to_char5[6] == 'C');
161 static_assert(value_to_char5[7] == 'G');
162 static_assert(value_to_char5[8] == 'T');
163 static_assert(value_to_char5[9] == 'N');
164