@@ -36,7 +36,7 @@ constexpr bool is_iequal(char const c1, char const c2)
3636}
3737
3838
39- namespace detail {
39+ namespace {
4040
4141template <char ... CHARS>
4242using chars = std::integer_sequence<char , CHARS...>;
@@ -46,39 +46,36 @@ using indexes = std::index_sequence<INDEXES...>;
4646template <class ... ICs>
4747struct sequence {};
4848
49- template <std::size_t I, char C>
50- struct index_char
49+ template <std::size_t I, std:: size_t C>
50+ struct ic // index + char
5151{
5252 static constexpr std::size_t my_index = I;
53- static constexpr char my_char = C;
53+ static constexpr std:: size_t my_char = C;
5454};
5555
56- template <std::size_t ...Is>
56+ template <class Map , std::size_t ...Is>
5757struct zip
5858{
5959 template <char ...Cs>
6060 struct with
6161 {
62- using type = sequence<index_char <Is, Cs >...>;
62+ using type = sequence<ic <Is, Map::apply(Cs, Is) >...>;
6363 };
6464};
6565
66- template <std::size_t ... Is, char ... Cs>
67- constexpr auto add_index (indexes<Is...>, chars<Cs...>) -> typename zip<Is...>::template with<Cs...>::type;
68-
69- template <char ... Cs>
70- using indexed_chars = decltype (
71- add_index (std::make_index_sequence<sizeof ...(Cs)>{}, chars<Cs...>{})
72- );
73-
74- template <char ... CHARS>
75- class Chars
66+ struct plain
7667{
77- public:
78- static constexpr std::size_t length () { return sizeof ...(CHARS); }
79- using type = detail::indexed_chars<CHARS...>;
68+ static constexpr std::size_t apply (std::size_t c, std::size_t )
69+ {
70+ return c;
71+ }
8072};
8173
74+ template <class Map , std::size_t ... Is, char ... Cs>
75+ constexpr auto map_index (indexes<Is...>, chars<Cs...>) -> typename zip<Map, Is...>::template with<Cs...>::type;
76+
77+ template <char ... Cs>
78+ using indexed_chars = decltype ( map_index<plain>(std::make_index_sequence<sizeof ...(Cs)>{}, chars<Cs...>{}) );
8279
8380// TODO: replace with fold expression in c++17
8481template <class FUNC >
@@ -118,26 +115,27 @@ constexpr bool apply(FUNC&& func, char const* p, sequence<ICs...>, std::size_t o
118115 return apply_impl<FUNC, ICs...>(std::forward<FUNC>(func), p, offset);
119116}
120117
121- } // end: namespace detail
118+ } // end: namespace
122119
123120
124121template <char ... CHARS>
125- class Chars : public detail ::Chars<CHARS...>
122+ class Chars
126123{
127- using base_t = detail::Chars<CHARS...>;
128-
129124public:
125+ static constexpr std::size_t length () { return sizeof ...(CHARS); }
126+ using type = indexed_chars<CHARS...>;
127+
130128 constexpr bool match (char const * begin, char const * end) const
131129 {
132- return (begin + base_t:: length () <= end)
133- ? detail:: apply (is_equal, begin, typename base_t :: type{})
130+ return (begin + length () <= end)
131+ ? apply (is_equal, begin, type{})
134132 : false ;
135133 }
136134
137135 constexpr bool match (char const * begin, char const * end, std::size_t offset) const
138136 {
139- return (begin + base_t:: length () <= end && offset < base_t:: length ())
140- ? detail:: apply (is_equal, begin, typename base_t :: type{}, offset)
137+ return (begin + length () <= end && offset < length ())
138+ ? apply (is_equal, begin, type{}, offset)
141139 : false ;
142140 }
143141
@@ -154,22 +152,23 @@ template <char... CHARS>
154152constexpr char Chars<CHARS...>::m_string[];
155153
156154template <char ... CHARS>
157- class CaseChars : public detail ::Chars<CHARS...>
155+ class CaseChars
158156{
159- using base_t = detail::Chars<CHARS...>;
160-
161157public:
158+ static constexpr std::size_t length () { return sizeof ...(CHARS); }
159+ using type = indexed_chars<CHARS...>;
160+
162161 constexpr bool match (char const * begin, char const * end) const
163162 {
164- return (begin + base_t:: length () <= end)
165- ? detail:: apply (is_iequal, begin, typename base_t :: type{})
163+ return (begin + length () <= end)
164+ ? apply (is_iequal, begin, type{})
166165 : false ;
167166 }
168167
169168 constexpr bool match (char const * begin, char const * end, std::size_t offset) const
170169 {
171- return (begin + base_t:: length () <= end && offset < base_t:: length ())
172- ? detail:: apply (is_iequal, begin, typename base_t :: type{}, offset)
170+ return (begin + length () <= end && offset < length ())
171+ ? apply (is_iequal, begin, type{}, offset)
173172 : false ;
174173 }
175174
@@ -186,13 +185,16 @@ template <char... CHARS>
186185constexpr char CaseChars<CHARS...>::m_string[];
187186
188187
189- namespace detail {
188+ namespace {
190189
191190#ifndef CTS_RND_SEED
192191#define CTS_TIME (index ) ((__TIME__[index]-' 0' )*10 + (__TIME__[index+1 ]-' 0' ))
193192#define CTS_RND_SEED uint32_t (CTS_TIME(0 )*3600 + CTS_TIME(3 )*60 + CTS_TIME(6 ) + 13709*(31 + __COUNTER__))
194193#endif
195194
195+ constexpr std::size_t STATE_OFFSET = 137 ;
196+ constexpr std::size_t CHAR_SHIFT_MOD = 7 ;
197+
196198// https://en.wikipedia.org/wiki/Linear_congruential_generator
197199// LCG: X(n + 1) = (A * X(n) + C) % m
198200constexpr std::size_t rand (std::size_t n)
@@ -201,80 +203,89 @@ constexpr std::size_t rand(std::size_t n)
201203 return static_cast <uint32_t >(1664525u * (n ? rand (n - 1 ) : CTS_RND_SEED) + 1013904223u );
202204}
203205
204- constexpr std::size_t rand_next (std::size_t rand_curr = CTS_RND_SEED )
206+ constexpr std::size_t rand_next (std::size_t rand_curr)
205207{
206208 // NOTE: cast makes the mod 2^32
207209 return static_cast <uint32_t >(1664525u * rand_curr + 1013904223u );
208210}
211+ /*
212+ a+b = (a ^ b) + 2*(a | b)
213+ a-b = (a ^ b) - 2*(~a | b)
214+ a*a(a+1)^2 % 4 = 0
215+ (a*a*a -3) % 3 = 0
216+ a + b >= a ^ b
217+ 7*a*a - 1 != b*b
218+ */
209219
210- constexpr char xor_char (char const c, std::size_t const index)
211- {
212- return c ^ static_cast <char >(rand (index));
213- }
214-
215- template <std::size_t ...Is>
216- struct xor_zip
220+ struct xmap
217221{
218- template <char ...Cs>
219- struct with
222+ static constexpr std::size_t apply (std::size_t c, std::size_t index)
220223 {
221- using type = sequence<index_char<Is, xor_char(Cs, Is)>...> ;
222- };
224+ return ((c + index) << (index % CHAR_SHIFT_MOD)) ^ rand (index + STATE_OFFSET) ;
225+ }
223226};
224227
225- template <std::size_t ... Is, char ... Cs>
226- constexpr auto xor_index (indexes<Is...>, chars<Cs...>) -> typename xor_zip<Is...>::template with<Cs...>::type;
228+ // __attribute__((noinline))
229+ __attribute__ ((optimize(0 )))
230+ inline std::size_t decode(std::size_t c, std::size_t index, std::size_t state)
231+ {
232+ return ((c ^ state) >> (index % CHAR_SHIFT_MOD)) - index;
233+ }
227234
228235template <char ... Cs>
229- using xored_chars = decltype (
230- xor_index (std::make_index_sequence< sizeof ...(Cs)>{}, chars<Cs...>{})
231- );
236+ using xchars = decltype ( map_index<xmap>(std::make_index_sequence< sizeof ...(Cs)>{}, chars<Cs...>{}) );
237+
238+ // [[gnu::visibility("hidden")]]
232239
233240template <std::size_t STATE>
234- constexpr void xor_impl (char * p) { }
241+ constexpr void ximpl (char * p) { }
235242
236243template <std::size_t STATE, class IC , class ... ICs>
237- constexpr void xor_impl (char * p)
244+ __attribute__ ((always_inline, visibility(" internal" )))
245+ inline void ximpl(char * p)
238246{
239- p[IC::my_index] = IC::my_char ^ static_cast < char >( STATE);
240- xor_impl <rand_next (STATE), ICs...>(p);
247+ p[IC::my_index] = static_cast < char >( decode ( IC::my_char, IC::my_index, STATE) );
248+ ximpl <rand_next (STATE), ICs...>(p);
241249}
242250
243251template <class ... ICs>
244- constexpr void apply_xor (char * p, sequence<ICs...>)
252+ __attribute__ ((always_inline, visibility(" internal" )))
253+ inline void xapply(char * p, sequence<ICs...>)
245254{
246- return xor_impl <rand (0 ), ICs...>(p);
255+ return ximpl <rand (STATE_OFFSET ), ICs...>(p);
247256}
248257
249- } // end: namespace detail
258+ } // end: namespace
250259
251260
252261// obfuscated string via XOR
253262template <char ... CHARS>
254- class XorChars
263+ class XChars
255264{
256- using type = detail::xored_chars <CHARS...>;
265+ using type = xchars <CHARS...>;
257266
258267public:
259268 static constexpr std::size_t size () { return sizeof ...(CHARS); }
260269 static constexpr std::size_t length () { return size (); }
261270
262271 // de-obfuscate at run-time into string on heap which will clean up its data in dtor
272+ __attribute__ ((always_inline, visibility(" internal" )))
263273 string str () const
264274 {
265275 string result{ this ->size () };
266- detail::apply_xor (result.data (), type{});
276+ xapply (result.data (), type{});
267277 return result;
268278 }
269279
270280 // de-obfuscate at run-time avoiding intermediate copy
271- // but you should clean-up buffer once it's used/no longer needed
281+ // but you should clean-up buffer once it's used and no longer needed to erase protected data from memory
282+ __attribute__ ((always_inline, visibility(" internal" )))
272283 char * str (void * buffer, std::size_t buf_size) const
273284 {
274285 if (buf_size >= size ())
275286 {
276287 auto * p = static_cast <char *>(buffer);
277- detail::apply_xor (p, type{});
288+ xapply (p, type{});
278289 if (buf_size > size ()) // NULL terminate if space allows
279290 {
280291 p[size ()] = ' \0 ' ;
@@ -285,6 +296,7 @@ class XorChars
285296 }
286297
287298 template <typename T, std::size_t QTY>
299+ __attribute__ ((always_inline, visibility(" internal" )))
288300 char * str (T (&buffer)[QTY]) const
289301 {
290302 static_assert (sizeof (buffer) >= size (), " buffer is too small to fit the string" );
@@ -302,7 +314,7 @@ template <typename T, T... CHARS>
302314constexpr cts::CaseChars<CHARS...> operator " " _ichars() { return { }; }
303315
304316template <typename T, T... CHARS>
305- constexpr cts::XorChars <CHARS...> operator " " _xchars() { return { }; }
317+ constexpr cts::XChars <CHARS...> operator " " _xchars() { return { }; }
306318
307319} // end: namespace
308320
0 commit comments