xref: /llvm-project/libcxx/test/support/constexpr_char_traits.h (revision 937643b8e1017ce6456de0c05b1673bd9ed0800d)
1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef _CONSTEXPR_CHAR_TRAITS
11 #define _CONSTEXPR_CHAR_TRAITS
12 
13 #include <string>
14 #include <cassert>
15 #include <cstddef>
16 
17 #include "test_macros.h"
18 
19 // Tests whether the pointer p is in the range [first, last).
20 //
21 // Precondition: The range [first, last) is a valid range.
22 //
23 // Typically the pointers are compared with less than. This is not allowed when
24 // the pointers belong to different ranges, which is UB. Typically, this is
25 // benign at run-time, however since UB is not allowed during constant
26 // evaluation this does not compile. This function does the validation without
27 // UB.
28 //
29 // When p is in the range [first, last) the data can be copied from the
30 // beginning to the end. Otherwise it needs to be copied from the end to the
31 // beginning.
32 template <class CharT>
is_pointer_in_range(const CharT * first,const CharT * last,const CharT * p)33 TEST_CONSTEXPR_CXX14 bool is_pointer_in_range(const CharT* first, const CharT* last, const CharT* p) {
34   if (first == p) // Needed when n == 0
35     return true;
36 
37   for (; first != last; ++first)
38     if (first == p)
39       return true;
40 
41   return false;
42 }
43 
44 template <class CharT>
45 struct constexpr_char_traits
46 {
47     typedef CharT     char_type;
48     typedef int       int_type;
49     typedef std::streamoff off_type;
50     typedef std::streampos pos_type;
51     typedef std::mbstate_t state_type;
52     // The comparison_category is omitted so the class will have weak_ordering
53     // in C++20. This is intentional.
54 
assignconstexpr_char_traits55     static TEST_CONSTEXPR_CXX14 void assign(char_type& c1, const char_type& c2) TEST_NOEXCEPT
56         {c1 = c2;}
57 
eqconstexpr_char_traits58     static TEST_CONSTEXPR bool eq(char_type c1, char_type c2) TEST_NOEXCEPT
59         {return c1 == c2;}
60 
ltconstexpr_char_traits61     static TEST_CONSTEXPR  bool lt(char_type c1, char_type c2) TEST_NOEXCEPT
62         {return c1 < c2;}
63 
64     static TEST_CONSTEXPR_CXX14 int              compare(const char_type* s1, const char_type* s2, std::size_t n);
65     static TEST_CONSTEXPR_CXX14 std::size_t           length(const char_type* s);
66     static TEST_CONSTEXPR_CXX14 const char_type* find(const char_type* s, std::size_t n, const char_type& a);
67     static TEST_CONSTEXPR_CXX14 char_type*       move(char_type* s1, const char_type* s2, std::size_t n);
68     static TEST_CONSTEXPR_CXX14 char_type*       copy(char_type* s1, const char_type* s2, std::size_t n);
69     static TEST_CONSTEXPR_CXX14 char_type*       assign(char_type* s, std::size_t n, char_type a);
70 
not_eofconstexpr_char_traits71     static TEST_CONSTEXPR int_type  not_eof(int_type c) TEST_NOEXCEPT
72         {return eq_int_type(c, eof()) ? ~eof() : c;}
73 
to_char_typeconstexpr_char_traits74     static TEST_CONSTEXPR char_type to_char_type(int_type c) TEST_NOEXCEPT
75         {return char_type(c);}
76 
to_int_typeconstexpr_char_traits77     static TEST_CONSTEXPR int_type  to_int_type(char_type c) TEST_NOEXCEPT
78         {return int_type(c);}
79 
eq_int_typeconstexpr_char_traits80     static TEST_CONSTEXPR bool      eq_int_type(int_type c1, int_type c2) TEST_NOEXCEPT
81         {return c1 == c2;}
82 
eofconstexpr_char_traits83     static TEST_CONSTEXPR int_type  eof() TEST_NOEXCEPT
84         {return int_type(EOF);}
85 };
86 
87 
88 template <class CharT>
89 TEST_CONSTEXPR_CXX14 int
compare(const char_type * s1,const char_type * s2,std::size_t n)90 constexpr_char_traits<CharT>::compare(const char_type* s1, const char_type* s2, std::size_t n)
91 {
92     for (; n; --n, ++s1, ++s2)
93     {
94         if (lt(*s1, *s2))
95             return -1;
96         if (lt(*s2, *s1))
97             return 1;
98     }
99     return 0;
100 }
101 
102 template <class CharT>
103 TEST_CONSTEXPR_CXX14 std::size_t
length(const char_type * s)104 constexpr_char_traits<CharT>::length(const char_type* s)
105 {
106     std::size_t len = 0;
107     for (; !eq(*s, char_type(0)); ++s)
108         ++len;
109     return len;
110 }
111 
112 template <class CharT>
113 TEST_CONSTEXPR_CXX14 const CharT*
find(const char_type * s,std::size_t n,const char_type & a)114 constexpr_char_traits<CharT>::find(const char_type* s, std::size_t n, const char_type& a)
115 {
116     for (; n; --n)
117     {
118         if (eq(*s, a))
119             return s;
120         ++s;
121     }
122     return 0;
123 }
124 
125 template <class CharT>
move(char_type * s1,const char_type * s2,std::size_t n)126 TEST_CONSTEXPR_CXX14 CharT* constexpr_char_traits<CharT>::move(char_type* s1, const char_type* s2, std::size_t n) {
127   if (s1 == s2)
128     return s1;
129 
130   char_type* r = s1;
131   if (is_pointer_in_range(s1, s1 + n, s2)) {
132     for (; n; --n)
133       assign(*s1++, *s2++);
134   } else {
135     s1 += n;
136     s2 += n;
137     for (; n; --n)
138       assign(*--s1, *--s2);
139   }
140   return r;
141 }
142 
143 template <class CharT>
144 TEST_CONSTEXPR_CXX14 CharT*
copy(char_type * s1,const char_type * s2,std::size_t n)145 constexpr_char_traits<CharT>::copy(char_type* s1, const char_type* s2, std::size_t n)
146 {
147     if (!TEST_IS_CONSTANT_EVALUATED) // fails in constexpr because we might be comparing unrelated pointers
148         assert(s2 < s1 || s2 >= s1+n);
149     char_type* r = s1;
150     for (; n; --n, ++s1, ++s2)
151         assign(*s1, *s2);
152     return r;
153 }
154 
155 template <class CharT>
156 TEST_CONSTEXPR_CXX14 CharT*
assign(char_type * s,std::size_t n,char_type a)157 constexpr_char_traits<CharT>::assign(char_type* s, std::size_t n, char_type a)
158 {
159     char_type* r = s;
160     for (; n; --n, ++s)
161         assign(*s, a);
162     return r;
163 }
164 
165 #endif // _CONSTEXPR_CHAR_TRAITS
166