2 * This file is open source software, licensed to you under the terms
3 * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4 * distributed with this work for additional information regarding copyright
5 * ownership. You may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing,
12 * software distributed under the License is distributed on an
13 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 * KIND, either express or implied. See the License for the
15 * specific language governing permissions and limitations
19 * Copyright 2014 Cloudius Systems
22 * C++2014 dependencies removed. Uses of std::string_view adapted to
23 * boost::string_ref. Matt Benjamin <mbenjamin@redhat.com>
29 #include <type_traits>
30 #include <boost/utility/string_view.hpp>
32 #include "include/buffer.h"
33 #include "include/denc.h"
35 template <typename char_type, typename Size, Size max_size>
38 using sstring = basic_sstring<char, uint32_t, 15>;
40 template <typename string_type = sstring, typename T>
41 inline string_type to_sstring(T value);
43 template <typename char_type, typename Size, Size max_size>
46 (std::is_same<char_type, char>::value
47 || std::is_same<char_type, signed char>::value
48 || std::is_same<char_type, unsigned char>::value),
49 "basic_sstring only supports single byte char types");
51 struct external_type {
56 struct internal_type {
57 char_type str[max_size];
60 static_assert(sizeof(external_type) <= sizeof(internal_type), "max_size too small");
61 static_assert(max_size <= 127, "max_size too large");
63 bool is_internal() const noexcept {
64 return u.internal.size >= 0;
66 bool is_external() const noexcept {
67 return !is_internal();
69 const char_type* str() const {
70 return is_internal() ? u.internal.str : u.external.str;
73 return is_internal() ? u.internal.str : u.external.str;
76 template <typename string_type, typename T>
77 static inline string_type to_sstring_sprintf(T value, const char* fmt) {
78 char tmp[sizeof(value) * 3 + 2];
79 auto len = std::sprintf(tmp, fmt, value);
80 using ch_type = typename string_type::value_type;
81 return string_type(reinterpret_cast<ch_type*>(tmp), len);
84 template <typename string_type>
85 static inline string_type to_sstring(int value) {
86 return to_sstring_sprintf<string_type>(value, "%d");
89 template <typename string_type>
90 static inline string_type to_sstring(unsigned value) {
91 return to_sstring_sprintf<string_type>(value, "%u");
94 template <typename string_type>
95 static inline string_type to_sstring(long value) {
96 return to_sstring_sprintf<string_type>(value, "%ld");
99 template <typename string_type>
100 static inline string_type to_sstring(unsigned long value) {
101 return to_sstring_sprintf<string_type>(value, "%lu");
104 template <typename string_type>
105 static inline string_type to_sstring(long long value) {
106 return to_sstring_sprintf<string_type>(value, "%lld");
109 template <typename string_type>
110 static inline string_type to_sstring(unsigned long long value) {
111 return to_sstring_sprintf<string_type>(value, "%llu");
114 template <typename string_type>
115 static inline string_type to_sstring(float value) {
116 return to_sstring_sprintf<string_type>(value, "%g");
119 template <typename string_type>
120 static inline string_type to_sstring(double value) {
121 return to_sstring_sprintf<string_type>(value, "%g");
124 template <typename string_type>
125 static inline string_type to_sstring(long double value) {
126 return to_sstring_sprintf<string_type>(value, "%Lg");
129 template <typename string_type>
130 static inline string_type to_sstring(const char* value) {
131 return string_type(value);
134 template <typename string_type>
135 static inline string_type to_sstring(sstring value) {
140 using value_type = char_type;
141 using traits_type = std::char_traits<char_type>;
142 using allocator_type = std::allocator<char_type>;
143 using reference = char_type&;
144 using const_reference = const char_type&;
145 using pointer = char_type*;
146 using const_pointer = const char_type*;
147 using iterator = char_type*;
148 using const_iterator = const char_type*;
149 // FIXME: add reverse_iterator and friend
150 using difference_type = ssize_t; // std::make_signed_t<Size> can be too small
151 using size_type = Size;
152 static constexpr size_type npos = static_cast<size_type>(-1);
154 struct initialized_later {};
156 basic_sstring() noexcept {
158 u.internal.str[0] = '\0';
160 basic_sstring(const basic_sstring& x) {
161 if (x.is_internal()) {
162 u.internal = x.u.internal;
164 u.internal.size = -1;
165 u.external.str = reinterpret_cast<char_type*>(std::malloc(x.u.external.size + 1));
166 if (!u.external.str) {
167 throw std::bad_alloc();
169 std::copy(x.u.external.str, x.u.external.str + x.u.external.size + 1, u.external.str);
170 u.external.size = x.u.external.size;
173 basic_sstring(basic_sstring&& x) noexcept {
175 x.u.internal.size = 0;
176 x.u.internal.str[0] = '\0';
178 basic_sstring(initialized_later, size_t size) {
179 if (size_type(size) != size) {
180 throw std::overflow_error("sstring overflow");
182 if (size + 1 <= sizeof(u.internal.str)) {
183 u.internal.str[size] = '\0';
184 u.internal.size = size;
186 u.internal.size = -1;
187 u.external.str = reinterpret_cast<char_type*>(std::malloc(size + 1));
188 if (!u.external.str) {
189 throw std::bad_alloc();
191 u.external.size = size;
192 u.external.str[size] = '\0';
195 basic_sstring(const char_type* x, size_t size) {
196 if (size_type(size) != size) {
197 throw std::overflow_error("sstring overflow");
199 if (size + 1 <= sizeof(u.internal.str)) {
200 std::copy(x, x + size, u.internal.str);
201 u.internal.str[size] = '\0';
202 u.internal.size = size;
204 u.internal.size = -1;
205 u.external.str = reinterpret_cast<char_type*>(std::malloc(size + 1));
206 if (!u.external.str) {
207 throw std::bad_alloc();
209 u.external.size = size;
210 std::copy(x, x + size, u.external.str);
211 u.external.str[size] = '\0';
215 basic_sstring(size_t size, char_type x) : basic_sstring(initialized_later(), size) {
216 memset(begin(), x, size);
219 basic_sstring(const char* x) : basic_sstring(reinterpret_cast<const char_type*>(x), std::strlen(x)) {}
220 basic_sstring(std::basic_string<char_type>& x) : basic_sstring(x.c_str(), x.size()) {}
221 basic_sstring(std::initializer_list<char_type> x) : basic_sstring(x.begin(), x.end() - x.begin()) {}
222 basic_sstring(const char_type* b, const char_type* e) : basic_sstring(b, e - b) {}
223 basic_sstring(const std::basic_string<char_type>& s)
224 : basic_sstring(s.data(), s.size()) {}
225 template <typename InputIterator>
226 basic_sstring(InputIterator first, InputIterator last)
227 : basic_sstring(initialized_later(), std::distance(first, last)) {
228 std::copy(first, last, begin());
230 ~basic_sstring() noexcept {
232 std::free(u.external.str);
235 basic_sstring& operator=(const basic_sstring& x) {
236 basic_sstring tmp(x);
240 basic_sstring& operator=(basic_sstring&& x) noexcept {
247 operator std::basic_string<char_type>() const {
248 return { str(), size() };
250 size_t size() const noexcept {
251 return is_internal() ? u.internal.size : u.external.size;
254 size_t length() const noexcept {
258 size_t find(char_type t, size_t pos = 0) const noexcept {
259 const char_type* it = str() + pos;
260 const char_type* end = str() + size();
270 size_t find(const basic_sstring& s, size_t pos = 0) const noexcept {
271 const char_type* it = str() + pos;
272 const char_type* end = str() + size();
273 const char_type* c_str = s.str();
274 const char_type* c_str_end = s.str() + s.size();
279 while ( i < end && j < c_str_end && *i == *j) {
283 if (j == c_str_end) {
292 * find_last_of find the last occurrence of c in the string.
293 * When pos is specified, the search only includes characters
294 * at or before position pos.
297 size_t find_last_of (char_type c, size_t pos = npos) const noexcept {
298 const char_type* str_start = str();
303 const char_type* p = str_start + pos + 1;
307 return (p - str_start);
309 } while (p != str_start);
315 * Append a C substring.
316 * @param s The C string to append.
317 * @param n The number of characters to append.
318 * @return Reference to this string.
320 basic_sstring& append (const char_type* s, size_t n) {
321 basic_sstring ret(initialized_later(), size() + n);
322 std::copy(begin(), end(), ret.begin());
323 std::copy(s, s + n, ret.begin() + size());
324 *this = std::move(ret);
329 * Replace characters with a value of a C style substring.
332 basic_sstring& replace(size_type pos, size_type n1, const char_type* s,
335 throw std::out_of_range("sstring::replace out of range");
338 if (n1 > size() - pos) {
344 std::copy(s, s + n2, begin() + pos);
348 basic_sstring ret(initialized_later(), size() + n2 - n1);
349 char_type* p= ret.begin();
350 std::copy(begin(), begin() + pos, p);
353 std::copy(s, s + n2, p);
356 std::copy(begin() + pos + n1, end(), p);
357 *this = std::move(ret);
361 template <class InputIterator>
362 basic_sstring& replace (const_iterator i1, const_iterator i2,
363 InputIterator first, InputIterator last) {
364 if (i1 < begin() || i1 > end() || i2 < begin()) {
365 throw std::out_of_range("sstring::replace out of range");
371 if (i2 - i1 == last - first) {
372 //in place replacement
373 std::copy(first, last, const_cast<char_type*>(i1));
376 basic_sstring ret(initialized_later(), size() + (last - first) - (i2 - i1));
377 char_type* p = ret.begin();
378 p = std::copy(cbegin(), i1, p);
379 p = std::copy(first, last, p);
380 std::copy(i2, cend(), p);
381 *this = std::move(ret);
385 iterator erase(iterator first, iterator last) {
386 size_t pos = first - begin();
387 replace(pos, last - first, nullptr, 0);
388 return begin() + pos;
392 * Inserts additional characters into the string right before
393 * the character indicated by p.
395 template <class InputIterator>
396 void insert(const_iterator p, InputIterator beg, InputIterator end) {
397 replace(p, p, beg, end);
401 * Returns a read/write reference to the data at the last
402 * element of the string.
403 * This function shall not be called on empty strings.
407 return operator[](size() - 1);
411 * Returns a read-only (constant) reference to the data at the last
412 * element of the string.
413 * This function shall not be called on empty strings.
416 back() const noexcept {
417 return operator[](size() - 1);
420 basic_sstring substr(size_t from, size_t len = npos) const {
422 throw std::out_of_range("sstring::substr out of range");
424 if (len > size() - from) {
430 return { str() + from , len };
433 const char_type& at(size_t pos) const {
435 throw std::out_of_range("sstring::at out of range");
437 return *(str() + pos);
440 char_type& at(size_t pos) {
442 throw std::out_of_range("sstring::at out of range");
444 return *(str() + pos);
447 bool empty() const noexcept {
448 return u.internal.size == 0;
450 void reset() noexcept {
452 std::free(u.external.str);
455 u.internal.str[0] = '\0';
458 int compare(const basic_sstring& x) const noexcept {
459 auto n = traits_type::compare(begin(), x.begin(), std::min(size(), x.size()));
463 if (size() < x.size()) {
465 } else if (size() > x.size()) {
472 int compare(size_t pos, size_t sz, const basic_sstring& x) const {
474 throw std::out_of_range("pos larger than string size");
477 sz = std::min(size() - pos, sz);
478 auto n = traits_type::compare(begin() + pos, x.begin(), std::min(sz, x.size()));
484 } else if (sz > x.size()) {
491 void swap(basic_sstring& x) noexcept {
497 const char_type* c_str() const {
500 const char_type* begin() const { return str(); }
501 const char_type* end() const { return str() + size(); }
502 const char_type* cbegin() const { return str(); }
503 const char_type* cend() const { return str() + size(); }
504 char_type* begin() { return str(); }
505 char_type* end() { return str() + size(); }
506 bool operator==(const basic_sstring& x) const {
507 return size() == x.size() && std::equal(begin(), end(), x.begin());
509 bool operator!=(const basic_sstring& x) const {
510 return !operator==(x);
512 bool operator<(const basic_sstring& x) const {
513 return compare(x) < 0;
515 basic_sstring operator+(const basic_sstring& x) const {
516 basic_sstring ret(initialized_later(), size() + x.size());
517 std::copy(begin(), end(), ret.begin());
518 std::copy(x.begin(), x.end(), ret.begin() + size());
521 basic_sstring& operator+=(const basic_sstring& x) {
522 return *this = *this + x;
524 char_type& operator[](size_type pos) {
527 const char_type& operator[](size_type pos) const {
530 operator boost::basic_string_view<char_type, traits_type>() const {
531 return boost::basic_string_view<char_type, traits_type>(str(), size());
533 template <typename string_type, typename T>
534 friend inline string_type to_sstring(T value);
536 template <typename char_type, typename Size, Size max_size>
537 constexpr Size basic_sstring<char_type, Size, max_size>::npos;
539 template <typename char_type, typename size_type, size_type Max, size_type N>
541 basic_sstring<char_type, size_type, Max>
542 operator+(const char(&s)[N], const basic_sstring<char_type, size_type, Max>& t) {
543 using sstring = basic_sstring<char_type, size_type, Max>;
544 // don't copy the terminating NUL character
545 sstring ret(typename sstring::initialized_later(), N-1 + t.size());
546 auto p = std::copy(std::begin(s), std::end(s)-1, ret.begin());
547 std::copy(t.begin(), t.end(), p);
553 size_t str_len(const char(&s)[N]) { return N - 1; }
557 const char* str_begin(const char(&s)[N]) { return s; }
561 const char* str_end(const char(&s)[N]) { return str_begin(s) + str_len(s); }
563 template <typename char_type, typename size_type, size_type max_size>
565 const char_type* str_begin(const basic_sstring<char_type, size_type, max_size>& s) { return s.begin(); }
567 template <typename char_type, typename size_type, size_type max_size>
569 const char_type* str_end(const basic_sstring<char_type, size_type, max_size>& s) { return s.end(); }
571 template <typename char_type, typename size_type, size_type max_size>
573 size_type str_len(const basic_sstring<char_type, size_type, max_size>& s) { return s.size(); }
575 template <typename First, typename Second, typename... Tail>
577 size_t str_len(const First& first, const Second& second, const Tail&... tail) {
578 return str_len(first) + str_len(second, tail...);
581 template <typename char_type, typename size_type, size_type max_size>
583 void swap(basic_sstring<char_type, size_type, max_size>& x,
584 basic_sstring<char_type, size_type, max_size>& y) noexcept
589 template <typename char_type, typename size_type, size_type max_size, typename char_traits>
591 std::basic_ostream<char_type, char_traits>&
592 operator<<(std::basic_ostream<char_type, char_traits>& os,
593 const basic_sstring<char_type, size_type, max_size>& s) {
594 return os.write(s.begin(), s.size());
597 template <typename char_type, typename size_type, size_type max_size, typename char_traits>
599 std::basic_istream<char_type, char_traits>&
600 operator>>(std::basic_istream<char_type, char_traits>& is,
601 basic_sstring<char_type, size_type, max_size>& s) {
610 template <typename char_type, typename size_type, size_type max_size>
611 struct hash<basic_sstring<char_type, size_type, max_size>> {
612 size_t operator()(const basic_sstring<char_type, size_type, max_size>& s) const {
613 using traits_type = std::char_traits<char_type>;
614 return std::hash<boost::basic_string_view<char_type,traits_type>>()(s);
621 char* copy_str_to(char* dst) {
625 template <typename Head, typename... Tail>
627 char* copy_str_to(char* dst, const Head& head, const Tail&... tail) {
628 return copy_str_to(std::copy(str_begin(head), str_end(head), dst), tail...);
631 template <typename String = sstring, typename... Args>
632 static String make_sstring(Args&&... args)
634 String ret(sstring::initialized_later(), str_len(args...));
635 copy_str_to(ret.begin(), args...);
639 template <typename string_type, typename T>
640 inline string_type to_sstring(T value) {
641 return sstring::to_sstring<string_type>(value);
646 template <typename Char, typename Size, Size Max>
647 struct denc_traits<basic_sstring<Char, Size, Max>> {
649 using value_type = basic_sstring<Char, Size, Max>;
651 static constexpr bool supported = true;
652 static constexpr bool featured = false;
653 static constexpr bool bounded = false;
655 static void bound_encode(const value_type& s, size_t& p, uint64_t f=0) {
656 p += sizeof(Size) + s.size();
659 static void encode_nohead(const value_type& s,
660 buffer::list::contiguous_appender& p)
664 p.append(reinterpret_cast<const char*>(s.c_str()), len);
668 static void decode_nohead(size_t len, value_type& s,
669 buffer::ptr::iterator& p)
673 s.append(reinterpret_cast<const Char*>(p.get_pos_add(len)), len);
677 static void encode(const value_type& s,
678 buffer::list::contiguous_appender& p,
681 Size len = (Size)(s.size());
684 p.append(reinterpret_cast<const char*>(s.c_str()), len);
688 static void decode(value_type& s,
689 buffer::ptr::iterator& p,
694 decode_nohead(len, s, p);
698 #if 0 /* XXX conflicts w/Ceph types.h */
699 template <typename T>
701 std::ostream& operator<<(std::ostream& os, const std::vector<T>& v) {
704 for (auto&& elem : v) {
717 #endif /* SSTRING_HH_ */