• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef API_BASE_CONTAINERS_BASIC_FIXED_STRING_H
17 #define API_BASE_CONTAINERS_BASIC_FIXED_STRING_H
18 
19 #include <base/containers/allocator.h>
20 #include <base/containers/iterator.h>
21 #include <base/containers/string_view.h>
22 #include <base/containers/type_traits.h>
23 #include <base/namespace.h>
24 
25 BASE_BEGIN_NAMESPACE()
26 template<class CharT, size_t maxSize>
27 class basic_fixed_string;
28 
29 template<size_t maxSize>
30 using fixed_string = BASE_NS::basic_fixed_string<char, maxSize>;
31 
32 template<size_t maxSize>
33 using fixed_wstring = BASE_NS::basic_fixed_string<wchar_t, maxSize>;
34 
35 template<class CharT, size_t maxSize>
36 class basic_fixed_string {
37 public:
38     using string_view = basic_string_view<CharT>;
39     using value_type = CharT;
40     using size_type = typename string_view::size_type;
41     static constexpr size_type npos = string_view::npos;
42     basic_fixed_string() = default;
43     ~basic_fixed_string() = default;
44 
basic_fixed_string(const basic_fixed_string & a)45     constexpr basic_fixed_string(const basic_fixed_string& a) noexcept
46     {
47         initialize({ a.data_, a.len_ });
48     }
49 
basic_fixed_string(basic_fixed_string && a)50     constexpr basic_fixed_string(basic_fixed_string&& a) noexcept
51     {
52         initialize({ a.data_, a.len_ });
53     }
54 
55     template<size_t N>
basic_fixed_string(const basic_fixed_string<CharT,N> & a)56     constexpr basic_fixed_string(const basic_fixed_string<CharT, N>& a) noexcept
57     {
58         initialize({ a.data(), a.size() });
59     }
60 
61     template<size_t N>
basic_fixed_string(const CharT (& a)[N])62     constexpr basic_fixed_string(const CharT (&a)[N])
63     {
64         initialize({ a, N - 1 });
65     }
66 
basic_fixed_string(const CharT * const a)67     constexpr basic_fixed_string(const CharT* const a) noexcept
68     {
69         initialize({ a, constexpr_strlen(a) });
70     }
71 
basic_fixed_string(const basic_string_view<CharT> & a)72     constexpr basic_fixed_string(const basic_string_view<CharT>& a) noexcept
73     {
74         initialize(a);
75     }
76 
basic_fixed_string(const size_t size)77     constexpr basic_fixed_string(const size_t size) noexcept : len_((size < maxSize) ? size : maxSize) {}
78 
79     template<typename T, typename = void>
80     struct HasData : false_type {};
81     template<typename T>
82     struct HasData<T, void_t<decltype(declval<T>().data())>> : true_type {};
83     template<typename T, typename = void>
84     struct HasSize : false_type {};
85     template<typename T>
86     struct HasSize<T, void_t<decltype(declval<T>().size())>> : true_type {};
87     template<typename T>
88     using HasDataAndSize = enable_if_t<(HasData<T>::value && HasSize<T>::value)>;
89     template<class StringT, class = HasDataAndSize<StringT>>
90     constexpr explicit basic_fixed_string(const StringT& s) noexcept;
91 
92     constexpr bool empty() const noexcept
93     {
94         return len_ == 0;
95     }
96 
97     constexpr size_t size() const noexcept
98     {
99         return len_;
100     }
101 
102     constexpr size_t length() const noexcept
103     {
104         return len_;
105     }
106 
107     constexpr size_t capacity() const noexcept
108     {
109         return maxSize;
110     }
111 
112     constexpr basic_fixed_string& operator=(const basic_fixed_string& a) noexcept
113     {
114         initialize({ a.data_, a.len_ });
115         return *this;
116     }
117 
118     constexpr basic_fixed_string& operator=(basic_fixed_string&& a) noexcept
119     {
120         initialize({ a.data_, a.len_ });
121         return *this;
122     }
123 
124     template<size_t N>
125     constexpr basic_fixed_string& operator=(const basic_fixed_string<CharT, N>& a) noexcept
126     {
127         initialize({ a.data(), a.size() });
128         return *this;
129     }
130 
131     template<size_t N>
132     constexpr basic_fixed_string& operator=(basic_fixed_string<CharT, N>&& a) noexcept
133     {
134         initialize({ a.data(), a.size() });
135         return *this;
136     }
137 
138     constexpr basic_fixed_string& operator=(const string_view& a) noexcept
139     {
140         initialize(a);
141         return *this;
142     }
143 
144     constexpr basic_fixed_string& operator=(CharT const* const& a) noexcept
145     {
146         initialize({ a, constexpr_strlen(a) });
147         return *this;
148     }
149 
150     constexpr basic_fixed_string operator+(const string_view& b) const
151     {
152         basic_fixed_string res(*this);
153         res.append_impl(b);
154         return res;
155     }
156 
157     constexpr basic_fixed_string operator+(CharT const* const& a) const
158     {
159         basic_fixed_string res(*this);
160         res.append_impl({ a, constexpr_strlen(a) });
161         return res;
162     }
163 
164     constexpr basic_fixed_string& operator+=(const string_view& a)
165     {
166         append_impl(a);
167         return *this;
168     }
169 
170     constexpr basic_fixed_string& operator+=(CharT const* const& a)
171     {
172         append_impl({ a, constexpr_strlen(a) });
173         return *this;
174     }
175 
176     constexpr CharT const* data() const
177     {
178         return data_;
179     }
180 
181     constexpr CharT* data()
182     {
183         return data_;
184     }
185 
186     constexpr CharT const* c_str() const
187     {
188         return data_;
189     }
190 
191     constexpr operator string_view() const noexcept
192     {
193         return string_view(data_, len_);
194     }
195 
196     constexpr void copy(CharT* const dst, size_type todo, size_type pos = 0) const
197     {
198         string_view(*this).copy(dst, todo, pos);
199     }
200 
201     /** find substring in the view */
202     constexpr size_type find(const CharT str, size_type pos = 0) const noexcept
203     {
204         return string_view(*this).find(str, pos);
205     }
206 
207     constexpr size_type find(const string_view& str, size_type pos = 0) const noexcept
208     {
209         return string_view(*this).find(str, pos);
210     }
211 
212     /* find the last occurrence of a substring in the view */
213     constexpr size_type rfind(const CharT str, size_type pos = npos) const noexcept
214     {
215         return string_view(*this).rfind(str, pos);
216     }
217 
218     constexpr size_type rfind(const string_view& str, size_type pos = npos) const noexcept
219     {
220         return string_view(*this).rfind(str, pos);
221     }
222 
223     /* find first occurance of characters in the view */
224     constexpr size_type find_first_of(const string_view& str, size_type pos = 0) const noexcept
225     {
226         return string_view(*this).find_first_of(str, pos);
227     }
228 
229     constexpr size_type find_first_of(CharT ch, size_type pos = 0) const noexcept
230     {
231         return string_view(*this).find_first_of(ch, pos);
232     }
233 
234     /* find last occurrence of characters in the view */
235     constexpr size_type find_last_of(const string_view& str, size_type pos = npos) const noexcept
236     {
237         return string_view(*this).find_last_of(str, pos);
238     }
239 
240     constexpr size_type find_last_of(CharT ch, size_type pos = npos) const noexcept
241     {
242         return string_view(*this).find_last_of(ch, pos);
243     }
244 
245     /* find first absence of characters
246     find_first_not_of
247 
248     find last absence of characters
249     find_last_not_of */
250     constexpr basic_fixed_string& append(const string_view& b)
251     {
252         append_impl(b);
253         return *this;
254     }
255 
256     constexpr basic_fixed_string& append(CharT const* const a)
257     {
258         append_impl({ a, constexpr_strlen(a) });
259         return *this;
260     }
261 
262     basic_fixed_string& replace(size_t first, size_t last, const basic_string_view<CharT>& str)
263     {
264         const auto replace = last - first;
265         const auto add = str.length();
266         const auto newSize = len_ + add - replace;
267         if (add < replace) {
268             CloneData(data() + first, replace, str.data(), add);
269             CloneData(data() + first + add, len_ - first - add, data() + last, len_ - last);
270         } else if (add > replace) {
271             const auto start = newSize < maxSize ? newSize : maxSize;
272             for (auto i = start; i > last; --i) {
273                 data_[i] = data_[i - add + replace];
274             }
275             CloneData(data() + first, len_, str.data(), add);
276         } else {
277             CloneData(data() + first, replace, str.data(), add);
278         }
279         len_ = newSize < maxSize ? newSize : maxSize;
280         data_[len_] = 0;
281         return *this;
282     }
283 
284 protected:
285     constexpr void initialize(const string_view& other)
286     {
287         len_ = other.length();
288         len_ = (len_ < maxSize) ? len_ : maxSize;
289         other.copy(data_, len_);
290         data_[len_] = 0;
291     }
292 
293     constexpr void append_impl(const string_view& other)
294     {
295         size_t todo = other.length();
296         todo = ((todo + len_) > maxSize) ? (maxSize - len_) : todo;
297         other.copy(data_ + len_, todo);
298         len_ += todo;
299         data_[len_] = 0;
300     }
301 
302     size_t len_ { 0 };
303     CharT data_[maxSize + 1] { 0 };
304 };
305 
306 template<class CharT, size_t maxSize>
307 template<class StringT, class>
308 constexpr basic_fixed_string<CharT, maxSize>::basic_fixed_string(const StringT& s) noexcept
309 {
310     initialize({ s.data(), s.length() });
311 }
312 template<class CharT, size_t N>
313 basic_fixed_string(const CharT (&)[N]) -> basic_fixed_string<CharT, N - 1>;
314 
315 template<class CharT, size_t M, size_t N>
316 constexpr basic_fixed_string<CharT, M + N> operator+(
317     const basic_fixed_string<CharT, M>& lhs, const basic_fixed_string<CharT, N>& rhs) noexcept
318 {
319     basic_fixed_string<CharT, M + N> res { lhs };
320     res.append(rhs);
321     return res;
322 }
323 
324 template<class CharT, size_t M, size_t N>
325 constexpr basic_fixed_string<CharT, M + N> operator+(
326     const CharT (&lhs)[M], const basic_fixed_string<CharT, N>& rhs) noexcept
327 {
328     basic_fixed_string<CharT, M + N> res { lhs };
329     res.append(rhs);
330     return res;
331 }
332 
333 template<class CharT, size_t M, size_t N>
334 constexpr basic_fixed_string<CharT, M + N> operator+(
335     const basic_fixed_string<CharT, M>& lhs, const CharT (&rhs)[N]) noexcept
336 {
337     basic_fixed_string<CharT, M + N> res { lhs };
338     res.append(rhs);
339     return res;
340 }
341 
342 template<class CharT, size_t N>
343 constexpr basic_fixed_string<CharT, 1 + N> operator+(CharT lhs, const basic_fixed_string<CharT, N>& rhs) noexcept
344 {
345     basic_fixed_string<CharT, 1 + N> res(string_view(&lhs, 1));
346     res.append(rhs);
347     return res;
348 }
349 
350 template<class CharT, size_t M, size_t N>
351 constexpr bool operator==(const basic_fixed_string<CharT, M>& lhs, const basic_fixed_string<CharT, N>& rhs) noexcept
352 {
353     return string_view(lhs) == string_view(rhs);
354 }
355 
356 template<class CharT, size_t M, int = 1>
357 constexpr bool operator==(
358     const basic_fixed_string<CharT, M>& lhs, const type_identity_t<basic_string_view<CharT>> rhs) noexcept
359 {
360     return string_view(lhs) == rhs;
361 }
362 
363 template<class CharT, size_t M, int = 2>
364 constexpr bool operator==(
365     const type_identity_t<basic_string_view<CharT>> lhs, const basic_fixed_string<CharT, M>& rhs) noexcept
366 {
367     return lhs == string_view(rhs);
368 }
369 
370 template<class CharT, size_t M, size_t N>
371 constexpr bool operator!=(const basic_fixed_string<CharT, M>& lhs, const basic_fixed_string<CharT, N>& rhs) noexcept
372 {
373     return string_view(lhs) != string_view(rhs);
374 }
375 
376 template<class CharT, size_t M, int = 1>
377 constexpr bool operator!=(
378     const basic_fixed_string<CharT, M>& lhs, const type_identity_t<basic_string_view<CharT>> rhs) noexcept
379 {
380     return string_view(lhs) != rhs;
381 }
382 
383 template<class CharT, size_t M, int = 2>
384 constexpr bool operator!=(
385     const type_identity_t<basic_string_view<CharT>> lhs, const basic_fixed_string<CharT, M>& rhs) noexcept
386 {
387     return lhs != string_view(rhs);
388 }
389 
390 template<class CharT, size_t M, size_t N>
391 constexpr bool operator<(const basic_fixed_string<CharT, M>& lhs, const basic_fixed_string<CharT, N>& rhs) noexcept
392 {
393     return string_view(lhs) < string_view(rhs);
394 }
395 
396 template<class CharT, size_t M, int = 1>
397 constexpr bool operator<(
398     const basic_fixed_string<CharT, M>& lhs, const type_identity_t<basic_string_view<CharT>> rhs) noexcept
399 {
400     return string_view(lhs) < rhs;
401 }
402 
403 template<class CharT, size_t M, int = 2>
404 constexpr bool operator<(
405     const type_identity_t<basic_string_view<CharT>> lhs, const basic_fixed_string<CharT, M>& rhs) noexcept
406 {
407     return lhs < string_view(rhs);
408 }
409 
410 template<typename Number, typename = enable_if_t<is_integral_v<Number>>>
411 constexpr fixed_string<21u> to_string(Number num)
412 {
413     fixed_string<21u> str;
414     uint64_t n = num;
415     // negate negative values
416     if constexpr (is_signed<Number>::value) {
417         if (num < 0) {
418             n = -num;
419         }
420     }
421 
422     // write starting from the end
423     const auto end = str.data() + str.capacity();
424     auto p = end - 1;
425     do {
426         *p-- = '0' + (n % 10);
427         n /= 10;
428     } while (n != 0);
429 
430     // add sign if needed
431     if constexpr (is_signed<Number>::value) {
432         if (num < 0) {
433             *p-- = '-';
434         }
435     }
436 
437     ++p;
438     str.append(string_view(p, end - p));
439     return str;
440 }
441 
442 template<typename Number, typename = enable_if_t<is_integral_v<Number>>>
443 constexpr fixed_string<21u> to_hex(Number num)
444 {
445     fixed_string<21u> str;
446     uint64_t n = num;
447     // negate negative values
448     if constexpr (is_signed<Number>::value) {
449         if (num < 0) {
450             n = -num;
451         }
452     }
453 
454     // write starting from the end
455     const auto end = str.data() + str.capacity();
456     auto p = end - 1;
457     const char* hex = "0123456789ABCDEF";
458     do {
459         *p-- = hex[(n % 16)];
460         n /= 16;
461     } while (n != 0);
462 
463     // add sign if needed
464     if constexpr (is_signed<Number>::value) {
465         if (num < 0) {
466             *p-- = '-';
467         }
468     }
469 
470     ++p;
471     str.append(string_view(p, end - p));
472     return str;
473 }
474 
475 template<size_t maxSize>
476 inline uint64_t hash(const fixed_string<maxSize>& value)
477 {
478     return BASE_NS::FNV1aHash(value.data(), value.size());
479 }
480 BASE_END_NAMESPACE()
481 #endif // API_BASE_CONTAINERS_BASIC_FIXED_STRING_H