2015-05-27 20:43:13 +00:00
|
|
|
/* String for OctaSTD.
|
|
|
|
*
|
|
|
|
* This file is part of OctaSTD. See COPYING.md for futher information.
|
|
|
|
*/
|
|
|
|
|
2015-07-13 19:08:55 +00:00
|
|
|
#ifndef OSTD_STRING_HH
|
|
|
|
#define OSTD_STRING_HH
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-05-27 21:15:24 +00:00
|
|
|
#include <stdio.h>
|
2015-05-27 20:43:13 +00:00
|
|
|
#include <stddef.h>
|
|
|
|
|
2015-07-13 19:08:55 +00:00
|
|
|
#include "ostd/utility.hh"
|
|
|
|
#include "ostd/range.hh"
|
|
|
|
#include "ostd/vector.hh"
|
2015-07-20 01:15:12 +00:00
|
|
|
#include "ostd/functional.hh"
|
2015-07-21 19:19:27 +00:00
|
|
|
#include "ostd/type_traits.hh"
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-07-13 19:07:14 +00:00
|
|
|
namespace ostd {
|
2015-07-05 22:59:36 +00:00
|
|
|
static constexpr Size npos = -1;
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
template<typename T, typename A = Allocator<T>> class StringBase;
|
2015-06-09 17:59:25 +00:00
|
|
|
|
|
|
|
template<typename T>
|
2015-07-21 21:06:23 +00:00
|
|
|
struct CharRangeBase: InputRange<
|
2015-07-23 00:28:25 +00:00
|
|
|
CharRangeBase<T>, ContiguousRangeTag, T
|
2015-06-09 17:59:25 +00:00
|
|
|
> {
|
2015-07-21 20:16:38 +00:00
|
|
|
private:
|
|
|
|
struct Nat {};
|
|
|
|
|
|
|
|
public:
|
2015-07-21 21:06:23 +00:00
|
|
|
CharRangeBase(): p_beg(nullptr), p_end(nullptr) {};
|
2015-08-05 01:09:44 +00:00
|
|
|
|
|
|
|
template<typename U>
|
|
|
|
CharRangeBase(T *beg, U end, EnableIf<
|
2016-01-13 18:09:21 +00:00
|
|
|
(IsPointer<U> || IsNullPointer<U>) && IsConvertible<U, T *>, Nat
|
2015-08-05 01:09:44 +00:00
|
|
|
> = Nat()): p_beg(beg), p_end(end) {}
|
|
|
|
|
2015-07-21 21:06:23 +00:00
|
|
|
CharRangeBase(T *beg, Size n): p_beg(beg), p_end(beg + n) {}
|
2015-07-21 19:19:27 +00:00
|
|
|
|
2015-06-09 17:59:25 +00:00
|
|
|
/* TODO: traits for utf-16/utf-32 string lengths, for now assume char */
|
2015-07-21 19:19:27 +00:00
|
|
|
template<typename U>
|
2016-01-13 18:09:21 +00:00
|
|
|
CharRangeBase(U beg, EnableIf<IsConvertible<U, T *> && !IsArray<U>, Nat>
|
|
|
|
= Nat()): p_beg(beg), p_end((T *)beg + (beg ? strlen(beg) : 0)) {}
|
2015-07-21 19:19:27 +00:00
|
|
|
|
2015-08-06 23:08:59 +00:00
|
|
|
CharRangeBase(Nullptr): p_beg(nullptr), p_end(nullptr) {}
|
|
|
|
|
2015-07-21 19:19:27 +00:00
|
|
|
template<typename U, Size N>
|
2016-01-13 18:09:21 +00:00
|
|
|
CharRangeBase(U (&beg)[N], EnableIf<IsConvertible<U *, T *>, Nat> = Nat()):
|
|
|
|
p_beg(beg), p_end(beg + N - (beg[N - 1] == '\0')) {}
|
2015-07-01 19:09:02 +00:00
|
|
|
|
2015-07-21 19:23:31 +00:00
|
|
|
template<typename U, typename A>
|
2015-07-21 21:06:23 +00:00
|
|
|
CharRangeBase(const StringBase<U, A> &s, EnableIf<
|
2016-01-13 18:09:21 +00:00
|
|
|
IsConvertible<U *, T *>, Nat
|
2015-07-21 20:16:38 +00:00
|
|
|
> = Nat()): p_beg(s.data()),
|
2015-06-09 17:59:25 +00:00
|
|
|
p_end(s.data() + s.size()) {}
|
|
|
|
|
2016-01-13 18:09:21 +00:00
|
|
|
template<typename U, typename = EnableIf<IsConvertible<U *, T *>>>
|
|
|
|
CharRangeBase(const CharRangeBase<U> &v):
|
2015-06-29 20:56:13 +00:00
|
|
|
p_beg(&v[0]), p_end(&v[v.size()]) {}
|
2015-06-17 01:00:39 +00:00
|
|
|
|
2015-07-21 21:06:23 +00:00
|
|
|
CharRangeBase &operator=(const CharRangeBase &v) {
|
2015-06-09 17:59:25 +00:00
|
|
|
p_beg = v.p_beg; p_end = v.p_end; return *this;
|
|
|
|
}
|
2015-07-01 19:09:02 +00:00
|
|
|
|
|
|
|
template<typename A>
|
2015-07-21 21:06:23 +00:00
|
|
|
CharRangeBase &operator=(const StringBase<T, A> &s) {
|
2015-06-09 17:59:25 +00:00
|
|
|
p_beg = s.data(); p_end = s.data() + s.size(); return *this;
|
|
|
|
}
|
|
|
|
/* TODO: traits for utf-16/utf-32 string lengths, for now assume char */
|
2015-07-21 21:06:23 +00:00
|
|
|
CharRangeBase &operator=(T *s) {
|
2015-08-06 22:57:40 +00:00
|
|
|
p_beg = s; p_end = s + (s ? strlen(s) : 0); return *this;
|
2015-06-09 17:59:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool empty() const { return p_beg == p_end; }
|
|
|
|
|
|
|
|
bool pop_front() {
|
|
|
|
if (p_beg == p_end) return false;
|
|
|
|
++p_beg;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool push_front() { --p_beg; return true; }
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
Size pop_front_n(Size n) {
|
|
|
|
Size olen = p_end - p_beg;
|
2015-06-09 17:59:25 +00:00
|
|
|
p_beg += n;
|
|
|
|
if (p_beg > p_end) {
|
|
|
|
p_beg = p_end;
|
|
|
|
return olen;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
Size push_front_n(Size n) { p_beg -= n; return true; }
|
2015-06-09 17:59:25 +00:00
|
|
|
|
|
|
|
T &front() const { return *p_beg; }
|
|
|
|
|
2015-07-21 21:06:23 +00:00
|
|
|
bool equals_front(const CharRangeBase &range) const {
|
2015-06-09 17:59:25 +00:00
|
|
|
return p_beg == range.p_beg;
|
|
|
|
}
|
|
|
|
|
2015-07-21 21:06:23 +00:00
|
|
|
Ptrdiff distance_front(const CharRangeBase &range) const {
|
2015-06-09 17:59:25 +00:00
|
|
|
return range.p_beg - p_beg;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool pop_back() {
|
|
|
|
if (p_end == p_beg) return false;
|
|
|
|
--p_end;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
bool push_back() { ++p_end; return true; }
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
Size pop_back_n(Size n) {
|
|
|
|
Size olen = p_end - p_beg;
|
2015-06-09 17:59:25 +00:00
|
|
|
p_end -= n;
|
|
|
|
if (p_end < p_beg) {
|
|
|
|
p_end = p_beg;
|
|
|
|
return olen;
|
|
|
|
}
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
Size push_back_n(Size n) { p_end += n; return true; }
|
2015-06-09 17:59:25 +00:00
|
|
|
|
|
|
|
T &back() const { return *(p_end - 1); }
|
|
|
|
|
2015-07-21 21:06:23 +00:00
|
|
|
bool equals_back(const CharRangeBase &range) const {
|
2015-06-09 17:59:25 +00:00
|
|
|
return p_end == range.p_end;
|
|
|
|
}
|
|
|
|
|
2015-07-21 21:06:23 +00:00
|
|
|
Ptrdiff distance_back(const CharRangeBase &range) const {
|
2015-06-09 17:59:25 +00:00
|
|
|
return range.p_end - p_end;
|
|
|
|
}
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
Size size() const { return p_end - p_beg; }
|
2015-06-09 17:59:25 +00:00
|
|
|
|
2015-07-21 21:06:23 +00:00
|
|
|
CharRangeBase slice(Size start, Size end) const {
|
|
|
|
return CharRangeBase(p_beg + start, p_beg + end);
|
2015-06-09 17:59:25 +00:00
|
|
|
}
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
T &operator[](Size i) const { return p_beg[i]; }
|
2015-06-09 17:59:25 +00:00
|
|
|
|
2015-07-01 20:12:45 +00:00
|
|
|
bool put(T v) {
|
|
|
|
if (empty()) return false;
|
2015-06-09 17:59:25 +00:00
|
|
|
*(p_beg++) = v;
|
2015-07-01 20:12:45 +00:00
|
|
|
return true;
|
2015-06-09 17:59:25 +00:00
|
|
|
}
|
|
|
|
|
2016-03-23 22:11:15 +00:00
|
|
|
Size put_n(const T *p, Size n) {
|
|
|
|
Size an = ostd::min(n, size());
|
|
|
|
memcpy(p_beg, p, an * sizeof(T));
|
|
|
|
p_beg += an;
|
|
|
|
return an;
|
|
|
|
}
|
|
|
|
|
2015-06-09 17:59:25 +00:00
|
|
|
T *data() { return p_beg; }
|
|
|
|
const T *data() const { return p_beg; }
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
Size to_hash() const {
|
2015-07-20 01:15:12 +00:00
|
|
|
return detail::mem_hash(data(), size());
|
2015-06-09 17:59:25 +00:00
|
|
|
}
|
|
|
|
|
2015-07-24 18:43:39 +00:00
|
|
|
/* non-range */
|
|
|
|
int compare(CharRangeBase<const T> s) const {
|
|
|
|
int ret = memcmp(data(), s.data(), ostd::min(size(), s.size()));
|
|
|
|
return ret ? ret : (size() - s.size());
|
|
|
|
}
|
|
|
|
|
2016-03-23 22:32:30 +00:00
|
|
|
template<typename R>
|
|
|
|
EnableIf<IsOutputRange<R>, Size> copy(R &&orange, Size n = -1) {
|
|
|
|
return orange.put_n(data(), ostd::min(n, size()));
|
|
|
|
}
|
|
|
|
|
|
|
|
Size copy(RemoveCv<T> *p, Size n = -1) {
|
|
|
|
Size c = ostd::min(n, size());
|
|
|
|
memcpy(p, data(), c * sizeof(T));
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2015-06-09 17:59:25 +00:00
|
|
|
private:
|
|
|
|
T *p_beg, *p_end;
|
|
|
|
};
|
|
|
|
|
2015-07-24 18:43:39 +00:00
|
|
|
using CharRange = CharRangeBase<char>;
|
|
|
|
using ConstCharRange = CharRangeBase<const char>;
|
|
|
|
|
|
|
|
inline bool operator==(ConstCharRange lhs, ConstCharRange rhs) {
|
|
|
|
return !lhs.compare(rhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool operator!=(ConstCharRange lhs, ConstCharRange rhs) {
|
2015-07-25 01:34:07 +00:00
|
|
|
return lhs.compare(rhs);
|
2015-07-24 18:43:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline bool operator<(ConstCharRange lhs, ConstCharRange rhs) {
|
|
|
|
return lhs.compare(rhs) < 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool operator>(ConstCharRange lhs, ConstCharRange rhs) {
|
|
|
|
return lhs.compare(rhs) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool operator<=(ConstCharRange lhs, ConstCharRange rhs) {
|
|
|
|
return lhs.compare(rhs) <= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool operator>=(ConstCharRange lhs, ConstCharRange rhs) {
|
|
|
|
return lhs.compare(rhs) >= 0;
|
|
|
|
}
|
|
|
|
|
2015-12-31 15:36:41 +00:00
|
|
|
inline bool starts_with(ConstCharRange a, ConstCharRange b) {
|
|
|
|
if (a.size() < b.size())
|
|
|
|
return false;
|
|
|
|
return a.slice(0, b.size()) == b;
|
|
|
|
}
|
|
|
|
|
2015-06-09 17:59:25 +00:00
|
|
|
template<typename T, typename A>
|
2015-06-03 22:07:57 +00:00
|
|
|
class StringBase {
|
2015-07-12 02:11:05 +00:00
|
|
|
using StrPair = detail::CompressedPair<AllocatorPointer<A>, A>;
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-07-13 19:07:14 +00:00
|
|
|
ostd::Size p_len, p_cap;
|
2015-07-12 02:11:05 +00:00
|
|
|
StrPair p_buf;
|
|
|
|
|
|
|
|
template<typename R>
|
|
|
|
void ctor_from_range(R &range, EnableIf<
|
2016-01-13 17:42:37 +00:00
|
|
|
IsFiniteRandomAccessRange<R> && IsSame<T, RemoveCv<RangeValue<R>>>, bool
|
2015-07-12 02:11:05 +00:00
|
|
|
> = true) {
|
|
|
|
if (range.empty()) return;
|
|
|
|
RangeSize<R> l = range.size();
|
|
|
|
reserve(l);
|
|
|
|
p_len = l;
|
|
|
|
range.copy(p_buf.first(), l);
|
|
|
|
p_buf.first()[l] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename R>
|
|
|
|
void ctor_from_range(R &range, EnableIf<
|
2016-01-13 17:42:37 +00:00
|
|
|
!IsFiniteRandomAccessRange<R> || !IsSame<T, RemoveCv<RangeValue<R>>>,
|
|
|
|
bool
|
2015-07-12 02:11:05 +00:00
|
|
|
> = true) {
|
|
|
|
if (range.empty()) return;
|
|
|
|
Size i = 0;
|
|
|
|
for (; !range.empty(); range.pop_front()) {
|
|
|
|
reserve(i + 1);
|
|
|
|
allocator_construct(p_buf.second(), &p_buf.first()[i],
|
|
|
|
range.front());
|
|
|
|
++i;
|
|
|
|
p_len = i;
|
|
|
|
}
|
|
|
|
p_buf.first()[p_len] = '\0';
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-06-03 22:07:57 +00:00
|
|
|
public:
|
2015-07-13 19:07:14 +00:00
|
|
|
using Size = ostd::Size;
|
2015-07-05 22:59:36 +00:00
|
|
|
using Difference = Ptrdiff;
|
2015-06-07 23:55:08 +00:00
|
|
|
using Value = T;
|
|
|
|
using Reference = T &;
|
|
|
|
using ConstReference = const T &;
|
2015-07-05 22:59:36 +00:00
|
|
|
using Pointer = AllocatorPointer<A>;
|
|
|
|
using ConstPointer = AllocatorConstPointer<A>;
|
2015-07-21 21:06:23 +00:00
|
|
|
using Range = CharRangeBase<T>;
|
|
|
|
using ConstRange = CharRangeBase<const T>;
|
2015-06-07 23:55:08 +00:00
|
|
|
using Allocator = A;
|
2015-06-03 22:07:57 +00:00
|
|
|
|
2015-07-12 02:11:05 +00:00
|
|
|
StringBase(const A &a = A()): p_len(0), p_cap(0),
|
|
|
|
p_buf((Pointer)&p_len, a) {}
|
|
|
|
|
|
|
|
explicit StringBase(Size n, T val = T(), const A &al = A()):
|
|
|
|
StringBase(al) {
|
|
|
|
if (!n) return;
|
|
|
|
p_buf.first() = allocator_allocate(p_buf.second(), n + 1);
|
|
|
|
p_len = p_cap = n;
|
|
|
|
Pointer cur = p_buf.first(), last = p_buf.first() + n;
|
|
|
|
while (cur != last) *cur++ = val;
|
|
|
|
*cur = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
StringBase(const StringBase &s): p_len(0), p_cap(0),
|
|
|
|
p_buf((Pointer)&p_len, allocator_container_copy(s.p_buf.second())) {
|
|
|
|
if (!s.p_len) return;
|
|
|
|
reserve(s.p_len);
|
|
|
|
p_len = s.p_len;
|
|
|
|
memcpy(p_buf.first(), s.p_buf.first(), (p_len + 1) * sizeof(T));
|
|
|
|
}
|
|
|
|
StringBase(const StringBase &s, const A &a): p_len(0), p_cap(0),
|
|
|
|
p_buf((Pointer)&p_len, a) {
|
|
|
|
if (!s.p_len) return;
|
|
|
|
reserve(s.p_len);
|
|
|
|
p_len = s.p_len;
|
|
|
|
memcpy(p_buf.first(), s.p_buf.first(), (p_len + 1) * sizeof(T));
|
|
|
|
}
|
|
|
|
StringBase(StringBase &&s): p_len(s.p_len), p_cap(s.p_cap),
|
|
|
|
p_buf(s.p_buf.first(), move(s.p_buf.second())) {
|
|
|
|
s.p_len = s.p_cap = 0;
|
|
|
|
s.p_buf.first() = (Pointer)&s.p_len;
|
|
|
|
}
|
|
|
|
StringBase(StringBase &&s, const A &a): p_len(0), p_cap(0),
|
|
|
|
p_buf((Pointer)&p_len, a) {
|
|
|
|
if (!s.p_len) return;
|
|
|
|
if (a != s.p_buf.second()) {
|
|
|
|
reserve(s.p_cap);
|
|
|
|
p_len = s.p_len;
|
|
|
|
memcpy(p_buf.first(), s.p_buf.first(), (p_len + 1) * sizeof(T));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
p_buf.first() = s.p_buf.first();
|
|
|
|
p_len = s.p_len;
|
|
|
|
p_cap = s.p_cap;
|
|
|
|
s.p_len = s.p_cap = 0;
|
|
|
|
s.p_buf.first() = &s.p_cap;
|
|
|
|
}
|
2015-06-03 22:07:57 +00:00
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
StringBase(const StringBase &s, Size pos, Size len = npos,
|
2015-07-12 02:11:05 +00:00
|
|
|
const A &a = A()): StringBase(a) {
|
|
|
|
Size end = (len == npos) ? s.size() : (pos + len);
|
|
|
|
Size nch = (end - pos);
|
|
|
|
reserve(nch);
|
|
|
|
memcpy(p_buf.first(), s.p_buf.first() + pos, nch);
|
|
|
|
p_len += nch;
|
|
|
|
p_buf.first()[p_len] = '\0';
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-05-29 00:02:19 +00:00
|
|
|
|
2015-06-03 22:07:57 +00:00
|
|
|
/* TODO: traits for utf-16/utf-32 string lengths, for now assume char */
|
2015-07-22 19:51:12 +00:00
|
|
|
StringBase(ConstRange v, const A &a = A()): StringBase(a) {
|
|
|
|
if (!v.size()) return;
|
|
|
|
reserve(v.size());
|
|
|
|
memcpy(p_buf.first(), &v[0], v.size());
|
|
|
|
p_buf.first()[v.size()] = '\0';
|
|
|
|
p_len = v.size();
|
2015-07-12 02:11:05 +00:00
|
|
|
}
|
2015-06-09 17:59:25 +00:00
|
|
|
|
2015-07-22 20:00:20 +00:00
|
|
|
template<typename U>
|
|
|
|
StringBase(U v, const EnableIf<
|
2016-01-13 18:09:21 +00:00
|
|
|
IsConvertible<U, const Value *> && !IsArray<U>, A
|
2015-07-22 20:00:20 +00:00
|
|
|
> &a = A()): StringBase(ConstRange(v), a) {}
|
|
|
|
|
|
|
|
template<typename U, Size N>
|
|
|
|
StringBase(U (&v)[N], const EnableIf<
|
2016-01-13 18:09:21 +00:00
|
|
|
IsConvertible<U *, const Value *>, A
|
2015-07-22 20:00:20 +00:00
|
|
|
> &a = A()): StringBase(ConstRange(v), a) {}
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
template<typename R, typename = EnableIf<
|
2016-01-13 18:09:21 +00:00
|
|
|
IsInputRange<R> && IsConvertible<RangeReference<R>, Value>
|
2015-07-12 02:11:05 +00:00
|
|
|
>> StringBase(R range, const A &a = A()): StringBase(a) {
|
|
|
|
ctor_from_range(range);
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-07-22 19:51:12 +00:00
|
|
|
~StringBase() {
|
2015-07-22 23:40:07 +00:00
|
|
|
if (!p_cap) return;
|
2015-07-22 19:51:12 +00:00
|
|
|
allocator_deallocate(p_buf.second(), p_buf.first(), p_cap + 1);
|
|
|
|
}
|
|
|
|
|
2015-07-12 02:11:05 +00:00
|
|
|
void clear() {
|
2015-08-05 20:58:06 +00:00
|
|
|
if (!p_len) return;
|
2015-07-12 02:11:05 +00:00
|
|
|
p_len = 0;
|
|
|
|
*p_buf.first() = '\0';
|
|
|
|
}
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-06-09 23:16:25 +00:00
|
|
|
StringBase &operator=(const StringBase &v) {
|
2015-07-12 02:11:05 +00:00
|
|
|
if (this == &v) return *this;
|
|
|
|
clear();
|
2016-01-20 19:05:11 +00:00
|
|
|
if (AllocatorPropagateOnContainerCopyAssignment<A>) {
|
2015-07-12 02:11:05 +00:00
|
|
|
if ((p_buf.second() != v.p_buf.second()) && p_cap) {
|
|
|
|
allocator_deallocate(p_buf.second(), p_buf.first(), p_cap);
|
|
|
|
p_cap = 0;
|
2015-08-01 03:29:26 +00:00
|
|
|
p_buf.first() = (Pointer)&p_len;
|
2015-07-12 02:11:05 +00:00
|
|
|
}
|
|
|
|
p_buf.second() = v.p_buf.second();
|
|
|
|
}
|
|
|
|
reserve(v.p_cap);
|
|
|
|
p_len = v.p_len;
|
|
|
|
if (p_len) {
|
|
|
|
memcpy(p_buf.first(), v.p_buf.first(), p_len);
|
|
|
|
p_buf.first()[p_len] = '\0';
|
2015-08-01 03:29:26 +00:00
|
|
|
} else p_buf.first() = (Pointer)&p_len;
|
2015-06-03 22:07:57 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2015-08-01 03:19:37 +00:00
|
|
|
|
2015-06-09 23:16:25 +00:00
|
|
|
StringBase &operator=(StringBase &&v) {
|
2015-07-12 02:11:05 +00:00
|
|
|
clear();
|
|
|
|
if (p_cap) allocator_deallocate(p_buf.second(), p_buf.first(), p_cap);
|
2016-01-20 19:05:11 +00:00
|
|
|
if (AllocatorPropagateOnContainerMoveAssignment<A>)
|
2015-07-12 02:11:05 +00:00
|
|
|
p_buf.second() = v.p_buf.second();
|
|
|
|
p_len = v.p_len;
|
|
|
|
p_cap = v.p_cap;
|
|
|
|
p_buf.~StrPair();
|
|
|
|
new (&p_buf) StrPair(v.disown(), move(v.p_buf.second()));
|
2015-07-18 16:01:11 +00:00
|
|
|
if (!p_cap) p_buf.first() = (Pointer)&p_len;
|
2015-06-03 22:07:57 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2015-08-01 03:19:37 +00:00
|
|
|
|
2015-07-22 19:51:12 +00:00
|
|
|
StringBase &operator=(ConstRange v) {
|
|
|
|
reserve(v.size());
|
|
|
|
if (v.size()) memcpy(p_buf.first(), &v[0], v.size());
|
|
|
|
p_buf.first()[v.size()] = '\0';
|
|
|
|
p_len = v.size();
|
2015-06-03 22:07:57 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2015-08-01 03:19:37 +00:00
|
|
|
|
|
|
|
template<typename U>
|
2016-01-13 18:09:21 +00:00
|
|
|
EnableIf<IsConvertible<U, const Value *> && !IsArray<U>, StringBase &>
|
|
|
|
operator=(U v) {
|
2015-08-01 03:19:37 +00:00
|
|
|
return operator=(ConstRange(v));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename U, Size N>
|
2016-01-13 18:09:21 +00:00
|
|
|
EnableIf<IsConvertible<U *, const Value *>, StringBase &>
|
|
|
|
operator=(U (&v)[N]) {
|
2015-08-01 03:19:37 +00:00
|
|
|
return operator=(ConstRange(v));
|
|
|
|
}
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
template<typename R, typename = EnableIf<
|
2016-01-13 18:09:21 +00:00
|
|
|
IsInputRange<R> && IsConvertible<RangeReference<R>, Value>
|
2015-06-29 20:56:13 +00:00
|
|
|
>> StringBase &operator=(const R &r) {
|
2015-07-12 02:11:05 +00:00
|
|
|
clear();
|
|
|
|
ctor_from_range(r);
|
2015-06-09 17:59:25 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
void resize(Size n, T v = T()) {
|
2015-07-12 02:11:05 +00:00
|
|
|
if (!n) {
|
|
|
|
clear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Size l = p_len;
|
|
|
|
reserve(n);
|
|
|
|
p_len = n;
|
|
|
|
for (Size i = l; i < p_len; ++i) {
|
|
|
|
p_buf.first()[i] = T(v);
|
|
|
|
}
|
|
|
|
p_buf.first()[l] = '\0';
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
void reserve(Size n) {
|
2015-07-12 02:11:05 +00:00
|
|
|
if (n <= p_cap) return;
|
|
|
|
Size oc = p_cap;
|
|
|
|
if (!oc) {
|
|
|
|
p_cap = max(n, Size(8));
|
|
|
|
} else {
|
|
|
|
while (p_cap < n) p_cap *= 2;
|
|
|
|
}
|
|
|
|
Pointer tmp = allocator_allocate(p_buf.second(), p_cap + 1);
|
|
|
|
if (oc > 0) {
|
|
|
|
memcpy(tmp, p_buf.first(), (p_len + 1) * sizeof(T));
|
|
|
|
allocator_deallocate(p_buf.second(), p_buf.first(), oc + 1);
|
|
|
|
}
|
|
|
|
tmp[p_len] = '\0';
|
|
|
|
p_buf.first() = tmp;
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-08-07 02:12:00 +00:00
|
|
|
T &operator[](Size i) { return p_buf.first()[i]; }
|
|
|
|
const T &operator[](Size i) const { return p_buf.first()[i]; }
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-08-07 02:12:00 +00:00
|
|
|
T &at(Size i) { return p_buf.first()[i]; }
|
|
|
|
const T &at(Size i) const { return p_buf.first()[i]; }
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-08-07 02:12:00 +00:00
|
|
|
T &front() { return p_buf.first()[0]; }
|
|
|
|
const T &front() const { return p_buf.first()[0]; };
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-08-07 02:12:00 +00:00
|
|
|
T &back() { return p_buf.first()[size() - 1]; }
|
|
|
|
const T &back() const { return p_buf.first()[size() - 1]; }
|
2015-05-27 21:15:24 +00:00
|
|
|
|
2015-07-12 02:11:05 +00:00
|
|
|
Value *data() { return p_buf.first(); }
|
|
|
|
const Value *data() const { return p_buf.first(); }
|
2015-05-29 00:02:19 +00:00
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
Size size() const {
|
2015-07-12 02:11:05 +00:00
|
|
|
return p_len;
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-05-29 00:02:19 +00:00
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
Size capacity() const {
|
2015-07-12 02:11:05 +00:00
|
|
|
return p_cap;
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-05-29 00:02:19 +00:00
|
|
|
|
2015-08-07 02:12:00 +00:00
|
|
|
void advance(Size s) { p_len += s; }
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
Size length() const {
|
2015-07-01 20:03:44 +00:00
|
|
|
/* TODO: unicode */
|
|
|
|
return size();
|
|
|
|
}
|
|
|
|
|
2015-06-03 22:07:57 +00:00
|
|
|
bool empty() const { return (size() == 0); }
|
2015-05-29 00:02:19 +00:00
|
|
|
|
2015-07-18 16:01:11 +00:00
|
|
|
Value *disown() {
|
|
|
|
Pointer r = p_buf.first();
|
|
|
|
p_buf.first() = nullptr;
|
|
|
|
p_len = p_cap = 0;
|
|
|
|
return (Value *)r;
|
|
|
|
}
|
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
void push(T v) {
|
2015-07-12 02:11:05 +00:00
|
|
|
reserve(p_len + 1);
|
|
|
|
p_buf.first()[p_len++] = v;
|
|
|
|
p_buf.first()[p_len] = '\0';
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-05-29 00:02:19 +00:00
|
|
|
|
2015-07-25 01:34:07 +00:00
|
|
|
StringBase &append(ConstRange r) {
|
|
|
|
if (!r.size()) return *this;
|
|
|
|
reserve(p_len + r.size());
|
|
|
|
memcpy(p_buf.first() + p_len, &r[0], r.size());
|
|
|
|
p_len += r.size();
|
2015-07-12 02:11:05 +00:00
|
|
|
p_buf.first()[p_len] = '\0';
|
2015-06-03 22:07:57 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
StringBase &append(Size n, T c) {
|
2016-05-24 00:30:11 +00:00
|
|
|
if (!n) return *this;
|
2015-07-12 02:11:05 +00:00
|
|
|
reserve(p_len + n);
|
|
|
|
for (Size i = 0; i < n; ++n) p_buf.first()[p_len + i] = c;
|
|
|
|
p_len += n;
|
|
|
|
p_buf.first()[p_len] = '\0';
|
2015-06-03 22:07:57 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2015-05-27 21:05:51 +00:00
|
|
|
|
2015-07-25 01:34:07 +00:00
|
|
|
template<typename R, typename = EnableIf<
|
2016-01-13 18:09:21 +00:00
|
|
|
IsInputRange<R> && IsConvertible<RangeReference<R>, Value> &&
|
|
|
|
!IsConvertible<R, ConstRange>
|
2015-07-25 01:34:07 +00:00
|
|
|
>> StringBase &append(R range) {
|
2015-07-12 02:11:05 +00:00
|
|
|
Size nadd = 0;
|
|
|
|
for (; !range.empty(); range.pop_front()) {
|
|
|
|
reserve(p_len + nadd + 1);
|
|
|
|
p_buf.first()[p_len + nadd++] = range.front();
|
|
|
|
}
|
|
|
|
p_len += nadd;
|
|
|
|
p_buf.first()[p_len] = '\0';
|
2015-06-03 22:07:57 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2015-05-31 18:50:00 +00:00
|
|
|
|
2015-07-25 01:34:07 +00:00
|
|
|
StringBase &operator+=(ConstRange r) {
|
|
|
|
return append(r);
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-06-09 23:16:25 +00:00
|
|
|
StringBase &operator+=(T c) {
|
2016-05-22 14:31:11 +00:00
|
|
|
return append(1, c);
|
2015-05-27 21:29:57 +00:00
|
|
|
}
|
2015-07-25 01:34:07 +00:00
|
|
|
template<typename R>
|
|
|
|
StringBase &operator+=(const R &v) {
|
|
|
|
return append(v);
|
|
|
|
}
|
2015-05-27 21:29:57 +00:00
|
|
|
|
2015-07-24 18:43:39 +00:00
|
|
|
int compare(ConstRange r) const {
|
|
|
|
return iter().compare(r);
|
2015-06-14 01:36:20 +00:00
|
|
|
}
|
|
|
|
|
2015-06-26 20:01:16 +00:00
|
|
|
Range iter() {
|
2015-07-12 02:11:05 +00:00
|
|
|
return Range(p_buf.first(), size());
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-06-26 20:01:16 +00:00
|
|
|
ConstRange iter() const {
|
2015-07-12 02:11:05 +00:00
|
|
|
return ConstRange(p_buf.first(), size());
|
2015-05-27 21:05:51 +00:00
|
|
|
}
|
2015-06-26 20:01:16 +00:00
|
|
|
ConstRange citer() const {
|
2015-07-12 02:11:05 +00:00
|
|
|
return ConstRange(p_buf.dfirst(), size());
|
2015-06-09 20:18:43 +00:00
|
|
|
}
|
|
|
|
|
2015-07-03 17:21:05 +00:00
|
|
|
Range iter_cap() {
|
2015-07-12 02:11:05 +00:00
|
|
|
return Range(p_buf.first(), capacity());
|
2015-07-03 17:21:05 +00:00
|
|
|
}
|
|
|
|
|
2015-06-03 22:07:57 +00:00
|
|
|
void swap(StringBase &v) {
|
2015-07-12 02:11:05 +00:00
|
|
|
detail::swap_adl(p_len, v.p_len);
|
|
|
|
detail::swap_adl(p_cap, v.p_cap);
|
|
|
|
detail::swap_adl(p_buf.first(), v.p_buf.first());
|
2016-01-20 19:05:11 +00:00
|
|
|
if (AllocatorPropagateOnContainerSwap<A>)
|
2015-07-12 02:11:05 +00:00
|
|
|
detail::swap_adl(p_buf.second(), v.p_buf.second());
|
2015-05-28 18:58:05 +00:00
|
|
|
}
|
2015-06-09 17:58:21 +00:00
|
|
|
|
|
|
|
Size to_hash() const {
|
2015-06-26 20:01:16 +00:00
|
|
|
return iter().to_hash();
|
2015-06-09 17:58:21 +00:00
|
|
|
}
|
2015-06-12 19:13:27 +00:00
|
|
|
|
|
|
|
A get_allocator() const {
|
2015-07-12 02:11:05 +00:00
|
|
|
return p_buf.second();
|
2015-06-12 19:13:27 +00:00
|
|
|
}
|
2015-06-03 22:07:57 +00:00
|
|
|
};
|
|
|
|
|
2015-06-07 23:55:08 +00:00
|
|
|
using String = StringBase<char>;
|
2015-06-03 22:07:57 +00:00
|
|
|
|
2015-07-18 00:02:13 +00:00
|
|
|
/* string literals */
|
|
|
|
|
|
|
|
inline namespace literals { inline namespace string_literals {
|
2015-08-01 02:08:11 +00:00
|
|
|
inline String operator "" _s(const char *str, Size len) {
|
2015-07-22 19:51:12 +00:00
|
|
|
return String(ConstCharRange(str, len));
|
2015-07-18 00:02:13 +00:00
|
|
|
}
|
2015-07-21 23:13:44 +00:00
|
|
|
|
2015-08-01 02:08:11 +00:00
|
|
|
inline ConstCharRange operator "" _S(const char *str, Size len) {
|
2015-07-21 23:13:44 +00:00
|
|
|
return ConstCharRange(str, len);
|
|
|
|
}
|
2015-07-18 00:02:13 +00:00
|
|
|
} }
|
|
|
|
|
2015-07-23 01:04:54 +00:00
|
|
|
namespace detail {
|
2016-01-13 18:09:21 +00:00
|
|
|
template<typename T, bool = IsConvertible<T, ConstCharRange>,
|
|
|
|
bool = IsConvertible<T, char>>
|
2015-07-23 01:04:54 +00:00
|
|
|
struct ConcatPut;
|
|
|
|
|
|
|
|
template<typename T, bool B>
|
|
|
|
struct ConcatPut<T, true, B> {
|
|
|
|
template<typename R>
|
|
|
|
static bool put(R &sink, ConstCharRange v) {
|
|
|
|
return v.size() && (sink.put_n(&v[0], v.size()) == v.size());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
struct ConcatPut<T, false, true> {
|
|
|
|
template<typename R>
|
|
|
|
static bool put(R &sink, char v) {
|
|
|
|
return sink.put(v);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename R, typename T, typename F>
|
|
|
|
bool concat(R &&sink, const T &v, ConstCharRange sep, F func) {
|
2015-07-13 19:07:14 +00:00
|
|
|
auto range = ostd::iter(v);
|
2015-07-23 01:04:54 +00:00
|
|
|
if (range.empty()) return true;
|
2015-06-03 22:07:57 +00:00
|
|
|
for (;;) {
|
2015-07-23 01:04:54 +00:00
|
|
|
if (!detail::ConcatPut<
|
|
|
|
decltype(func(range.front()))
|
|
|
|
>::put(sink, func(range.front())))
|
|
|
|
return false;
|
2015-06-03 22:07:57 +00:00
|
|
|
range.pop_front();
|
|
|
|
if (range.empty()) break;
|
2015-07-23 01:04:54 +00:00
|
|
|
sink.put_n(&sep[0], sep.size());
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-07-23 01:04:54 +00:00
|
|
|
return true;
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-05-28 18:58:05 +00:00
|
|
|
|
2015-07-23 01:04:54 +00:00
|
|
|
template<typename R, typename T>
|
|
|
|
bool concat(R &&sink, const T &v, ConstCharRange sep = " ") {
|
2015-07-13 19:07:14 +00:00
|
|
|
auto range = ostd::iter(v);
|
2015-07-23 01:04:54 +00:00
|
|
|
if (range.empty()) return true;
|
2015-06-03 22:07:57 +00:00
|
|
|
for (;;) {
|
2015-07-23 01:04:54 +00:00
|
|
|
ConstCharRange ret = range.front();
|
|
|
|
if (!ret.size() || (sink.put_n(&ret[0], ret.size()) != ret.size()))
|
|
|
|
return false;
|
2015-06-03 22:07:57 +00:00
|
|
|
range.pop_front();
|
|
|
|
if (range.empty()) break;
|
2015-07-23 01:04:54 +00:00
|
|
|
sink.put_n(&sep[0], sep.size());
|
2015-05-28 18:58:05 +00:00
|
|
|
}
|
2015-07-23 01:04:54 +00:00
|
|
|
return true;
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
|
|
|
|
2015-07-23 01:04:54 +00:00
|
|
|
template<typename R, typename T, typename F>
|
|
|
|
bool concat(R &&sink, std::initializer_list<T> v, ConstCharRange sep, F func) {
|
|
|
|
return concat(sink, ostd::iter(v), sep, func);
|
2015-07-12 14:55:41 +00:00
|
|
|
}
|
|
|
|
|
2015-07-23 01:04:54 +00:00
|
|
|
template<typename R, typename T>
|
2015-07-25 01:07:51 +00:00
|
|
|
bool concat(R &&sink, std::initializer_list<T> v, ConstCharRange sep = " ") {
|
2015-07-23 01:04:54 +00:00
|
|
|
return concat(sink, ostd::iter(v), sep);
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace detail {
|
2015-07-22 23:40:07 +00:00
|
|
|
template<typename R>
|
|
|
|
struct TostrRange: OutputRange<TostrRange<R>, char> {
|
|
|
|
TostrRange() = delete;
|
|
|
|
TostrRange(R &out): p_out(out), p_written(0) {}
|
|
|
|
bool put(char v) {
|
|
|
|
bool ret = p_out.put(v);
|
|
|
|
p_written += ret;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
Size put_n(const char *v, Size n) {
|
|
|
|
Size ret = p_out.put_n(v, n);
|
|
|
|
p_written += ret;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
Size put_string(ConstCharRange r) {
|
|
|
|
return put_n(&r[0], r.size());
|
|
|
|
}
|
|
|
|
Size get_written() const { return p_written; }
|
|
|
|
private:
|
|
|
|
R &p_out;
|
|
|
|
Size p_written;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T, typename R>
|
2015-07-23 01:04:54 +00:00
|
|
|
auto test_stringify(int) ->
|
2016-01-20 18:42:29 +00:00
|
|
|
BoolConstant<IsSame<decltype(declval<T>().stringify()), String>>;
|
2015-07-22 23:40:07 +00:00
|
|
|
|
|
|
|
template<typename T, typename R>
|
2015-07-23 01:04:54 +00:00
|
|
|
static True test_stringify(decltype(declval<const T &>().to_string
|
2015-07-22 23:40:07 +00:00
|
|
|
(declval<R &>())) *);
|
|
|
|
|
|
|
|
template<typename, typename>
|
2015-07-23 01:04:54 +00:00
|
|
|
False test_stringify(...);
|
2015-07-11 16:26:41 +00:00
|
|
|
|
2015-07-22 23:40:07 +00:00
|
|
|
template<typename T, typename R>
|
2016-01-20 18:42:29 +00:00
|
|
|
constexpr bool StringifyTest = decltype(test_stringify<T, R>(0))::value;
|
2015-07-11 18:54:51 +00:00
|
|
|
|
|
|
|
template<typename T>
|
2015-07-13 19:07:14 +00:00
|
|
|
True test_iterable(decltype(ostd::iter(declval<T>())) *);
|
2015-07-11 16:26:41 +00:00
|
|
|
template<typename> static False test_iterable(...);
|
|
|
|
|
|
|
|
template<typename T>
|
2016-01-20 18:42:29 +00:00
|
|
|
constexpr bool IterableTest = decltype(test_iterable<T>(0))::value;
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-05-28 01:38:52 +00:00
|
|
|
|
2015-07-11 16:26:41 +00:00
|
|
|
template<typename T, typename = void>
|
|
|
|
struct ToString;
|
|
|
|
|
|
|
|
template<typename T>
|
2016-01-20 18:42:29 +00:00
|
|
|
struct ToString<T, EnableIf<detail::IterableTest<T>>> {
|
2015-07-11 19:21:49 +00:00
|
|
|
using Argument = RemoveCv<RemoveReference<T>>;
|
2015-06-07 23:55:08 +00:00
|
|
|
using Result = String;
|
2015-05-28 01:38:52 +00:00
|
|
|
|
2015-07-11 16:26:41 +00:00
|
|
|
String operator()(const T &v) const {
|
2015-06-03 22:07:57 +00:00
|
|
|
String ret("{");
|
2015-07-23 01:04:54 +00:00
|
|
|
auto x = appender<String>();
|
|
|
|
if (concat(x, ostd::iter(v), ", ", ToString<
|
2015-07-11 17:50:13 +00:00
|
|
|
RemoveConst<RemoveReference<
|
2015-07-13 19:07:14 +00:00
|
|
|
RangeReference<decltype(ostd::iter(v))>
|
2015-07-05 22:59:36 +00:00
|
|
|
>>
|
2015-07-23 01:04:54 +00:00
|
|
|
>())) ret += x.get();
|
2015-06-03 22:07:57 +00:00
|
|
|
ret += "}";
|
2015-06-25 17:59:26 +00:00
|
|
|
return ret;
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-07-11 16:26:41 +00:00
|
|
|
};
|
2015-05-28 18:58:05 +00:00
|
|
|
|
2015-07-11 16:26:41 +00:00
|
|
|
template<typename T>
|
2015-07-22 23:40:07 +00:00
|
|
|
struct ToString<T, EnableIf<
|
2016-01-20 18:42:29 +00:00
|
|
|
detail::StringifyTest<T, detail::TostrRange<AppenderRange<String>>>
|
2015-07-22 23:40:07 +00:00
|
|
|
>> {
|
2015-07-11 19:21:49 +00:00
|
|
|
using Argument = RemoveCv<RemoveReference<T>>;
|
2015-07-11 16:26:41 +00:00
|
|
|
using Result = String;
|
2015-05-28 01:38:52 +00:00
|
|
|
|
2015-06-09 17:58:21 +00:00
|
|
|
String operator()(const T &v) const {
|
2015-07-22 23:40:07 +00:00
|
|
|
auto app = appender<String>();
|
|
|
|
detail::TostrRange<AppenderRange<String>> sink(app);
|
|
|
|
if (!v.to_string(sink)) return String();
|
|
|
|
return move(app.get());
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
|
|
|
};
|
2015-05-27 21:15:24 +00:00
|
|
|
|
2015-06-03 22:07:57 +00:00
|
|
|
namespace detail {
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T>
|
2015-07-12 02:11:05 +00:00
|
|
|
void str_printf(String &s, const char *fmt, T v) {
|
2015-06-03 22:07:57 +00:00
|
|
|
char buf[256];
|
|
|
|
int n = snprintf(buf, sizeof(buf), fmt, v);
|
2015-07-12 02:11:05 +00:00
|
|
|
s.clear();
|
|
|
|
s.reserve(n);
|
2015-06-03 22:07:57 +00:00
|
|
|
if (n >= (int)sizeof(buf))
|
2015-07-12 02:11:05 +00:00
|
|
|
snprintf(s.data(), n + 1, fmt, v);
|
2015-06-03 22:07:57 +00:00
|
|
|
else if (n > 0)
|
2015-07-12 02:11:05 +00:00
|
|
|
memcpy(s.data(), buf, n + 1);
|
2015-05-28 00:44:21 +00:00
|
|
|
else {
|
2015-07-12 02:11:05 +00:00
|
|
|
s.clear();
|
2015-05-28 00:44:21 +00:00
|
|
|
}
|
2015-07-12 02:11:05 +00:00
|
|
|
*((Size *)&s) = n;
|
2015-05-28 00:26:48 +00:00
|
|
|
}
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-05-28 00:26:48 +00:00
|
|
|
|
2015-06-03 22:07:57 +00:00
|
|
|
template<> struct ToString<bool> {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Argument = bool;
|
|
|
|
using Result = String;
|
2015-06-03 22:07:57 +00:00
|
|
|
String operator()(bool b) {
|
2015-07-22 20:00:20 +00:00
|
|
|
return b ? "true" : "false";
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<> struct ToString<char> {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Argument = char;
|
|
|
|
using Result = String;
|
2015-06-03 22:07:57 +00:00
|
|
|
String operator()(char c) {
|
|
|
|
String ret;
|
|
|
|
ret.push(c);
|
2015-06-25 17:59:26 +00:00
|
|
|
return ret;
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-07-13 19:08:55 +00:00
|
|
|
#define OSTD_TOSTR_NUM(T, fmt) \
|
2015-06-04 21:57:06 +00:00
|
|
|
template<> struct ToString<T> { \
|
2015-06-07 23:55:08 +00:00
|
|
|
using Argument = T; \
|
|
|
|
using Result = String; \
|
2015-06-04 21:57:06 +00:00
|
|
|
String operator()(T v) { \
|
2015-06-03 22:07:57 +00:00
|
|
|
String ret; \
|
2015-07-12 02:11:05 +00:00
|
|
|
detail::str_printf(ret, fmt, v); \
|
2015-06-25 17:59:26 +00:00
|
|
|
return ret; \
|
2015-06-03 22:07:57 +00:00
|
|
|
} \
|
|
|
|
};
|
|
|
|
|
2015-07-13 19:08:55 +00:00
|
|
|
OSTD_TOSTR_NUM(sbyte, "%d")
|
|
|
|
OSTD_TOSTR_NUM(int, "%d")
|
|
|
|
OSTD_TOSTR_NUM(int &, "%d")
|
|
|
|
OSTD_TOSTR_NUM(long, "%ld")
|
|
|
|
OSTD_TOSTR_NUM(float, "%f")
|
|
|
|
OSTD_TOSTR_NUM(double, "%f")
|
|
|
|
|
|
|
|
OSTD_TOSTR_NUM(byte, "%u")
|
|
|
|
OSTD_TOSTR_NUM(uint, "%u")
|
|
|
|
OSTD_TOSTR_NUM(ulong, "%lu")
|
|
|
|
OSTD_TOSTR_NUM(llong, "%lld")
|
|
|
|
OSTD_TOSTR_NUM(ullong, "%llu")
|
|
|
|
OSTD_TOSTR_NUM(ldouble, "%Lf")
|
|
|
|
|
|
|
|
#undef OSTD_TOSTR_NUM
|
2015-06-03 22:07:57 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T> struct ToString<T *> {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Argument = T *;
|
|
|
|
using Result = String;
|
2015-06-03 22:07:57 +00:00
|
|
|
String operator()(Argument v) {
|
|
|
|
String ret;
|
2015-07-12 02:11:05 +00:00
|
|
|
detail::str_printf(ret, "%p", v);
|
2015-06-25 17:59:26 +00:00
|
|
|
return ret;
|
2015-05-28 18:58:05 +00:00
|
|
|
}
|
2015-06-03 22:07:57 +00:00
|
|
|
};
|
2015-05-28 18:58:05 +00:00
|
|
|
|
2015-07-10 00:17:08 +00:00
|
|
|
template<> struct ToString<const char *> {
|
|
|
|
using Argument = const char *;
|
|
|
|
using Result = String;
|
|
|
|
String operator()(const char *s) {
|
|
|
|
return String(s);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-07-11 19:18:46 +00:00
|
|
|
template<> struct ToString<char *> {
|
|
|
|
using Argument = char *;
|
|
|
|
using Result = String;
|
|
|
|
String operator()(char *s) {
|
|
|
|
return String(s);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-06-03 22:07:57 +00:00
|
|
|
template<> struct ToString<String> {
|
2015-07-01 17:51:39 +00:00
|
|
|
using Argument = String;
|
2015-06-07 23:55:08 +00:00
|
|
|
using Result = String;
|
2015-07-01 17:51:39 +00:00
|
|
|
String operator()(const Argument &s) {
|
2015-06-03 22:07:57 +00:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-07-21 21:06:23 +00:00
|
|
|
template<> struct ToString<CharRange> {
|
|
|
|
using Argument = CharRange;
|
2015-06-09 17:59:25 +00:00
|
|
|
using Result = String;
|
2015-07-01 17:51:39 +00:00
|
|
|
String operator()(const Argument &s) {
|
2015-06-09 17:59:25 +00:00
|
|
|
return String(s);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-07-21 21:06:23 +00:00
|
|
|
template<> struct ToString<ConstCharRange> {
|
|
|
|
using Argument = ConstCharRange;
|
2015-07-21 19:25:09 +00:00
|
|
|
using Result = String;
|
|
|
|
String operator()(const Argument &s) {
|
|
|
|
return String(s);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
template<typename T, typename U> struct ToString<Pair<T, U>> {
|
|
|
|
using Argument = Pair<T, U>;
|
2015-06-07 23:55:08 +00:00
|
|
|
using Result = String;
|
2015-07-01 17:51:39 +00:00
|
|
|
String operator()(const Argument &v) {
|
2015-06-03 22:07:57 +00:00
|
|
|
String ret("{");
|
2016-03-27 22:49:27 +00:00
|
|
|
ret += ToString<RemoveCv<RemoveReference<T>>>()(v.first);
|
2015-06-03 22:07:57 +00:00
|
|
|
ret += ", ";
|
2016-03-27 22:49:27 +00:00
|
|
|
ret += ToString<RemoveCv<RemoveReference<U>>>()(v.second);
|
|
|
|
ret += "}";
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
namespace detail {
|
|
|
|
template<Size I, Size N>
|
|
|
|
struct TupleToString {
|
|
|
|
template<typename T>
|
|
|
|
static void append(String &ret, const T &tup) {
|
|
|
|
ret += ", ";
|
|
|
|
ret += ToString<RemoveCv<RemoveReference<
|
|
|
|
decltype(ostd::get<I>(tup))>>>()(ostd::get<I>(tup));
|
|
|
|
TupleToString<I + 1, N>::append(ret, tup);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<Size N>
|
|
|
|
struct TupleToString<N, N> {
|
|
|
|
template<typename T>
|
|
|
|
static void append(String &, const T &) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<Size N>
|
|
|
|
struct TupleToString<0, N> {
|
|
|
|
template<typename T>
|
|
|
|
static void append(String &ret, const T &tup) {
|
|
|
|
ret += ToString<RemoveCv<RemoveReference<
|
|
|
|
decltype(ostd::get<0>(tup))>>>()(ostd::get<0>(tup));
|
|
|
|
TupleToString<1, N>::append(ret, tup);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename ...T> struct ToString<Tuple<T...>> {
|
|
|
|
using Argument = Tuple<T...>;
|
|
|
|
using Result = String;
|
|
|
|
String operator()(const Argument &v) {
|
|
|
|
String ret("{");
|
|
|
|
detail::TupleToString<0, sizeof...(T)>::append(ret, v);
|
2015-06-03 22:07:57 +00:00
|
|
|
ret += "}";
|
2015-06-25 17:59:26 +00:00
|
|
|
return ret;
|
2015-05-28 00:26:48 +00:00
|
|
|
}
|
2015-06-03 22:07:57 +00:00
|
|
|
};
|
|
|
|
|
2015-07-11 16:26:41 +00:00
|
|
|
template<typename T>
|
|
|
|
typename ToString<T>::Result to_string(const T &v) {
|
2016-03-27 22:49:27 +00:00
|
|
|
return ToString<RemoveCv<RemoveReference<T>>>()(v);
|
2015-05-27 20:43:13 +00:00
|
|
|
}
|
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T>
|
|
|
|
String to_string(std::initializer_list<T> init) {
|
2015-07-11 20:54:58 +00:00
|
|
|
return to_string(iter(init));
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
|
|
|
|
2016-05-07 16:25:40 +00:00
|
|
|
/* TODO: rvalue ref versions for rhs when we have efficient prepend */
|
|
|
|
|
2016-05-21 14:36:14 +00:00
|
|
|
inline String operator+(const String &lhs, ConstCharRange rhs) {
|
2016-05-07 16:25:40 +00:00
|
|
|
String ret(lhs); ret += rhs; return ret;
|
|
|
|
}
|
|
|
|
|
2016-05-21 14:36:14 +00:00
|
|
|
inline String operator+(ConstCharRange lhs, const String &rhs) {
|
|
|
|
String ret(lhs); ret += rhs; return ret;
|
2016-05-07 16:25:40 +00:00
|
|
|
}
|
|
|
|
|
2016-05-21 14:36:14 +00:00
|
|
|
inline String operator+(const String &lhs, char rhs) {
|
2016-05-07 16:25:40 +00:00
|
|
|
String ret(lhs); ret += rhs; return ret;
|
|
|
|
}
|
|
|
|
|
2016-05-21 14:36:14 +00:00
|
|
|
inline String operator+(char lhs, const String &rhs) {
|
|
|
|
String ret(lhs); ret += rhs; return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline String operator+(String &&lhs, ConstCharRange rhs) {
|
2016-05-07 16:25:40 +00:00
|
|
|
String ret(move(lhs)); ret += rhs; return ret;
|
|
|
|
}
|
|
|
|
|
2016-05-21 14:36:14 +00:00
|
|
|
inline String operator+(String &&lhs, char rhs) {
|
|
|
|
String ret(move(lhs)); ret += rhs; return ret;
|
2016-05-07 16:25:40 +00:00
|
|
|
}
|
|
|
|
|
2016-03-21 21:21:41 +00:00
|
|
|
template<typename R>
|
2016-03-19 19:52:46 +00:00
|
|
|
struct TempCString {
|
|
|
|
private:
|
2016-03-24 21:52:16 +00:00
|
|
|
RemoveCv<RangeValue<R>> *p_buf;
|
2016-03-19 19:52:46 +00:00
|
|
|
bool p_allocated;
|
|
|
|
|
|
|
|
public:
|
|
|
|
TempCString() = delete;
|
|
|
|
TempCString(const TempCString &) = delete;
|
|
|
|
TempCString(TempCString &&s): p_buf(s.p_buf), p_allocated(s.p_allocated) {
|
|
|
|
s.p_buf = nullptr;
|
|
|
|
s.p_allocated = false;
|
|
|
|
}
|
2016-03-24 21:52:16 +00:00
|
|
|
TempCString(R input, RemoveCv<RangeValue<R>> *sbuf, Size bufsize)
|
2016-03-19 19:52:46 +00:00
|
|
|
: p_buf(nullptr), p_allocated(false) {
|
2016-03-21 21:21:41 +00:00
|
|
|
if (input.empty()) return;
|
2016-03-19 19:52:46 +00:00
|
|
|
if (input.size() >= bufsize) {
|
2016-03-24 21:52:16 +00:00
|
|
|
p_buf = new RemoveCv<RangeValue<R>>[input.size() + 1];
|
2016-03-19 19:52:46 +00:00
|
|
|
p_allocated = true;
|
|
|
|
} else p_buf = sbuf;
|
2016-03-21 21:21:41 +00:00
|
|
|
p_buf[input.copy(p_buf)] = '\0';
|
2016-03-19 19:52:46 +00:00
|
|
|
}
|
|
|
|
~TempCString() {
|
|
|
|
if (p_allocated) delete[] p_buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
TempCString &operator=(const TempCString &) = delete;
|
|
|
|
TempCString &operator=(TempCString &&s) {
|
|
|
|
swap(s);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2016-03-24 21:52:16 +00:00
|
|
|
operator const RemoveCv<RangeValue<R>> *() const { return p_buf; }
|
|
|
|
const RemoveCv<RangeValue<R>> *get() const { return p_buf; }
|
2016-03-19 19:52:46 +00:00
|
|
|
|
|
|
|
void swap(TempCString &s) {
|
|
|
|
detail::swap_adl(p_buf, s.p_buf);
|
|
|
|
detail::swap_adl(p_allocated, s.p_allocated);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-03-21 21:21:41 +00:00
|
|
|
template<typename R>
|
2016-03-22 01:13:43 +00:00
|
|
|
inline TempCString<R> to_temp_cstr(R input, RemoveCv<RangeValue<R>> *buf,
|
2016-03-21 21:21:41 +00:00
|
|
|
Size bufsize) {
|
|
|
|
return TempCString<R>(input, buf, bufsize);
|
2016-03-19 19:52:46 +00:00
|
|
|
}
|
|
|
|
|
2015-07-13 19:07:14 +00:00
|
|
|
} /* namespace ostd */
|
2015-06-03 22:07:57 +00:00
|
|
|
|
2016-02-07 21:17:15 +00:00
|
|
|
#endif
|