qxLib
string_utils.inl
Go to the documentation of this file.
1 /**
2 
3  @file string_utils.inl
4  @author Khrapov
5  @date 14.10.2026
6  @copyright (c) Nick Khrapov, 2026. All right reserved.
7 
8 **/
9 
10 namespace qx
11 {
12 
13 template<class value_t>
14 constexpr size_t djb2a_hash(const value_t* pszStr, size_t nSeed, size_t nLen)
15 {
16  size_t nHash = nSeed;
17 
18  for (size_t i = 0; i < nLen; ++i)
19  nHash = nHash * 33 ^ pszStr[i];
20 
21  return nHash;
22 }
23 
24 template<class value_t>
25 constexpr size_t djb2a_hash(const value_t* pszStr, size_t nSeed)
26 {
27  size_t nHash = nSeed;
28 
29  for (size_t i = 0; pszStr[i]; ++i)
30  nHash = nHash * 33 ^ pszStr[i];
31 
32  return nHash;
33 }
34 
35 template<class value_t>
36 constexpr size_t murmur_32_hash(const value_t* pStr, size_t nSeed, size_t nLen) noexcept
37 {
38  size_t nHash = nSeed;
39 
40  if (nLen > 3)
41  {
42  size_t i = nLen >> 2;
43  do
44  {
45  size_t k = 0;
46 
47  // constexpr version of std::memcpy(&k, pszStr, sizeof(u32));
48  static_assert(
49  sizeof(value_t) == sizeof(u8) || sizeof(value_t) == sizeof(u16) || sizeof(value_t) == sizeof(u32));
50 
51  if constexpr (sizeof(value_t) == sizeof(u32))
52  {
53  k += *(pStr + 0);
54  }
55  else if constexpr (sizeof(value_t) == sizeof(u16))
56  {
57  k += *(pStr + 0);
58  k <<= sizeof(u16);
59  k += *(pStr + 1);
60  }
61  else
62  {
63  k += *(pStr + 0);
64  k <<= sizeof(u8);
65  k += *(pStr + 1);
66  k <<= sizeof(u8);
67  k += *(pStr + 2);
68  k <<= sizeof(u8);
69  k += *(pStr + 3);
70  }
71 
72  pStr += sizeof(u32);
73 
74  k *= 0xcc9e2d51; //-V101
75  k = (k << 15) | (k >> 17);
76  k *= 0x1b873593;
77 
78  nHash ^= k;
79  nHash = (nHash << 13) | (nHash >> 19);
80  nHash = nHash * 5 + 0xe6546b64; //-V104
81  } while (--i);
82  }
83 
84  if (nLen & 3)
85  {
86  size_t i = nLen & 3;
87  size_t k = 0;
88  do
89  {
90  k <<= 8;
91  k |= pStr[i - 1];
92  } while (--i);
93  k *= 0xcc9e2d51; //-V101
94  k = (k << 15) | (k >> 17);
95  k *= 0x1b873593;
96  nHash ^= k;
97  }
98 
99  nHash ^= nLen; //-V103
100  nHash ^= nHash >> 16;
101  nHash *= 0x85ebca6b; //-V101
102  nHash ^= nHash >> 13;
103  nHash *= 0xc2b2ae35; //-V101
104  nHash ^= nHash >> 16;
105 
106  return nHash;
107 }
108 
109 template<class fwd_it_1_t, class fwd_it_2_t>
110 constexpr int iter_strcmp(fwd_it_1_t itBegin1, fwd_it_1_t itEnd1, fwd_it_2_t itBegin2, fwd_it_2_t itEnd2) noexcept
111 {
112  auto it1 = itBegin1;
113  auto it2 = itBegin2;
114 
115  while (it1 != itEnd1 && it2 != itEnd2 && *it1 == *it2)
116  {
117  ++it1;
118  ++it2;
119  }
120 
121  if (it1 == itEnd1 && it2 == itEnd2)
122  return 0;
123 
124  if (it1 == itEnd1)
125  return -static_cast<int>(*it2);
126 
127  if (it2 == itEnd2)
128  return static_cast<int>(*it1);
129 
130  return static_cast<int>(*it1) - static_cast<int>(*it2);
131 }
132 
133 template<class value_t>
134 constexpr int strcmp(const value_t* pszLeft, const value_t* pszRight)
135 {
136  while (*pszLeft && (*pszLeft == *pszRight))
137  {
138  ++pszLeft;
139  ++pszRight;
140  }
141  return *pszLeft - *pszRight;
142 }
143 
144 namespace details
145 {
146 
147 template<class value_t, size_t N>
148 constexpr const auto& choose_str_prefix(const char (&c)[N], const wchar_t (&w)[N]) noexcept
149 {
150  if constexpr (std::is_same_v<value_t, char>)
151  return c;
152  else
153  return w;
154 }
155 
156 template<>
157 constexpr char choose_char_prefix<char>(char c, wchar_t) noexcept
158 {
159  return c;
160 }
161 
162 template<>
163 constexpr wchar_t choose_char_prefix<wchar_t>(char, wchar_t w) noexcept
164 {
165  return w;
166 }
167 
168 } // namespace details
169 
170 template<class value_t, class T>
171 constexpr const value_t* get_format_specifier() noexcept
172 {
173  const value_t* pszFormat = nullptr;
174 
175  using test_type = std::remove_cvref_t<T>;
176 
177  if constexpr (std::is_same_v<test_type, char>)
178  {
179  pszFormat = QX_STR_PREFIX(value_t, "%hhd");
180  }
181  else if constexpr (std::is_same_v<test_type, unsigned char>)
182  {
183  pszFormat = QX_STR_PREFIX(value_t, "%hhu");
184  }
185  else if constexpr (std::is_same_v<test_type, short>)
186  {
187  pszFormat = QX_STR_PREFIX(value_t, "%hd");
188  }
189  else if constexpr (std::is_same_v<test_type, unsigned short>)
190  {
191  pszFormat = QX_STR_PREFIX(value_t, "%hu");
192  }
193  else if constexpr (std::is_same_v<test_type, int>)
194  {
195  pszFormat = QX_STR_PREFIX(value_t, "%d");
196  }
197  else if constexpr (std::is_same_v<test_type, unsigned int>)
198  {
199  pszFormat = QX_STR_PREFIX(value_t, "%u");
200  }
201  else if constexpr (std::is_same_v<test_type, long>)
202  {
203  pszFormat = QX_STR_PREFIX(value_t, "%ld");
204  }
205  else if constexpr (std::is_same_v<test_type, unsigned long>)
206  {
207  pszFormat = QX_STR_PREFIX(value_t, "%lu");
208  }
209  else if constexpr (std::is_same_v<test_type, long long>)
210  {
211  pszFormat = QX_STR_PREFIX(value_t, "%lld");
212  }
213  else if constexpr (std::is_same_v<test_type, unsigned long long>)
214  {
215  pszFormat = QX_STR_PREFIX(value_t, "%llu");
216  }
217  else if constexpr (std::is_same_v<test_type, float>)
218  {
219  pszFormat = QX_STR_PREFIX(value_t, "%f");
220  }
221  else if constexpr (std::is_same_v<test_type, double>)
222  {
223  pszFormat = QX_STR_PREFIX(value_t, "%lf");
224  }
225  else if constexpr (std::is_same_v<test_type, long double>)
226  {
227  pszFormat = QX_STR_PREFIX(value_t, "%Lf");
228  }
229  else if constexpr (std::is_same_v<std::remove_cv_t<std::remove_pointer_t<test_type>>, char>)
230  {
231  pszFormat = QX_STR_PREFIX(value_t, "%s");
232  }
233  else if constexpr (std::is_same_v<std::remove_cv_t<std::remove_pointer_t<test_type>>, wchar_t>)
234  {
235  pszFormat = QX_STR_PREFIX(value_t, "%ls");
236  }
237  else if constexpr (std::is_pointer_v<test_type>)
238  {
239 #if QX_MSVC
240  pszFormat = QX_STR_PREFIX(value_t, "0x%p");
241 #else
242  pszFormat = QX_STR_PREFIX(value_t, "%p");
243 #endif
244  }
245 
246  return pszFormat;
247 }
248 
249 template<class value_t>
250 constexpr std::size_t strlen(const value_t* psz)
251 {
252  if (!psz)
253  return 0;
254 
255  std::size_t nLen = 0;
256  while (*psz != QX_CHAR_PREFIX(value_t, '\0'))
257  {
258  ++psz;
259  ++nLen;
260  }
261 
262  return nLen;
263 }
264 
265 } // namespace qx
constexpr size_t djb2a_hash(const value_t *pszStr, size_t nSeed, size_t nLen)
djb2a hash
#define QX_CHAR_PREFIX(value_t, ch)
Chose witch of prefixes add to char : L or none.
Definition: string_utils.h:128
constexpr int iter_strcmp(fwd_it_1_t itBegin1, fwd_it_1_t itEnd1, fwd_it_2_t itBegin2, fwd_it_2_t itEnd2) noexcept
Compares string 1 with string 2.
constexpr size_t murmur_32_hash(const value_t *pStr, size_t nSeed, size_t nLen) noexcept
Murmur nHash.
constexpr int strcmp(const value_t *pszLeft, const value_t *pszRight)
Constexpr compare two strings.
constexpr std::size_t strlen(const value_t *psz)
Naive but constexpr string length algorithm, for runtime prefer std::strlen as there are may be a lot...
#define QX_STR_PREFIX(value_t, str)
Chose witch of prefixes add to string : L or none.
Definition: string_utils.h:120
constexpr const value_t * get_format_specifier() noexcept
Get format specifier for type.
std::uint8_t u8
0 .. 65 535
Definition: typedefs.h:19
std::uint32_t u32
0 .. 18 446 744 073 709 551 615
Definition: typedefs.h:23
std::uint16_t u16
0 .. 4 294 967 295
Definition: typedefs.h:21