2015-05-27 20:43:13 +00:00
|
|
|
/* String for OctaSTD.
|
|
|
|
*
|
|
|
|
* This file is part of OctaSTD. See COPYING.md for futher information.
|
|
|
|
*/
|
|
|
|
|
2015-06-28 15:04:49 +00:00
|
|
|
#ifndef OCTA_STRING_HH
|
|
|
|
#define OCTA_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-06-28 14:39:04 +00:00
|
|
|
#include "octa/utility.hh"
|
|
|
|
#include "octa/range.hh"
|
|
|
|
#include "octa/vector.hh"
|
2015-05-27 20:43:13 +00:00
|
|
|
|
|
|
|
namespace octa {
|
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>
|
|
|
|
struct StringRangeBase: InputRange<
|
|
|
|
StringRangeBase<T>, FiniteRandomAccessRangeTag, T
|
|
|
|
> {
|
2015-06-29 22:33:20 +00:00
|
|
|
StringRangeBase() = delete;
|
2015-06-09 17:59:25 +00:00
|
|
|
StringRangeBase(T *beg, T *end): p_beg(beg), p_end(end) {}
|
2015-07-05 22:59:36 +00:00
|
|
|
StringRangeBase(T *beg, Size n): p_beg(beg), p_end(beg + n) {}
|
2015-06-09 17:59:25 +00:00
|
|
|
/* TODO: traits for utf-16/utf-32 string lengths, for now assume char */
|
|
|
|
StringRangeBase(T *beg): p_beg(beg), p_end(beg + strlen(beg)) {}
|
2015-07-01 19:09:02 +00:00
|
|
|
|
|
|
|
template<typename A>
|
|
|
|
StringRangeBase(const StringBase<T, A> &s): p_beg(s.data()),
|
2015-06-09 17:59:25 +00:00
|
|
|
p_end(s.data() + s.size()) {}
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
template<typename U, typename = EnableIf<
|
|
|
|
IsConvertible<U *, T *>::value
|
2015-06-29 20:56:13 +00:00
|
|
|
>> StringRangeBase(const StringRangeBase<U> &v):
|
|
|
|
p_beg(&v[0]), p_end(&v[v.size()]) {}
|
2015-06-17 01:00:39 +00:00
|
|
|
|
2015-06-09 17:59:25 +00:00
|
|
|
StringRangeBase &operator=(const StringRangeBase &v) {
|
|
|
|
p_beg = v.p_beg; p_end = v.p_end; return *this;
|
|
|
|
}
|
2015-07-01 19:09:02 +00:00
|
|
|
|
|
|
|
template<typename A>
|
|
|
|
StringRangeBase &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 */
|
|
|
|
StringRangeBase &operator=(T *s) {
|
|
|
|
p_beg = s; p_end = s + strlen(s); return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
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; }
|
|
|
|
|
|
|
|
bool equals_front(const StringRangeBase &range) const {
|
|
|
|
return p_beg == range.p_beg;
|
|
|
|
}
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
Ptrdiff distance_front(const StringRangeBase &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); }
|
|
|
|
|
|
|
|
bool equals_back(const StringRangeBase &range) const {
|
|
|
|
return p_end == range.p_end;
|
|
|
|
}
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
Ptrdiff distance_back(const StringRangeBase &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-05 22:59:36 +00:00
|
|
|
StringRangeBase slice(Size start, Size end) const {
|
2015-06-09 17:59:25 +00:00
|
|
|
return StringRangeBase(p_beg + start, p_beg + end);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
/* non-range methods */
|
|
|
|
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-06-09 17:59:25 +00:00
|
|
|
const T *d = data();
|
|
|
|
Size h = 5381, len = size();
|
|
|
|
for (Size i = 0; i < len; ++i)
|
|
|
|
h = ((h << 5) + h) ^ d[i];
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
T *p_beg, *p_end;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T, typename A>
|
2015-06-03 22:07:57 +00:00
|
|
|
class StringBase {
|
2015-07-05 22:59:36 +00:00
|
|
|
Vector<T, A> p_buf;
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-06-03 22:07:57 +00:00
|
|
|
void terminate() {
|
|
|
|
if (p_buf.empty() || (p_buf.back() != '\0')) p_buf.push('\0');
|
|
|
|
}
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-06-03 22:07:57 +00:00
|
|
|
public:
|
2015-07-11 00:22:48 +00:00
|
|
|
using Size = octa::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>;
|
|
|
|
using Range = StringRangeBase<T>;
|
|
|
|
using ConstRange = StringRangeBase<const T>;
|
2015-06-07 23:55:08 +00:00
|
|
|
using Allocator = A;
|
2015-06-03 22:07:57 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
StringBase(const A &a = A()): p_buf(1, '\0', a) {}
|
2015-06-03 22:07:57 +00:00
|
|
|
|
2015-07-01 00:46:01 +00:00
|
|
|
StringBase(Size n, const T &val = T(), const A &al = A()):
|
|
|
|
p_buf(n + 1, val, al) {}
|
|
|
|
|
2015-06-03 22:07:57 +00:00
|
|
|
StringBase(const StringBase &s): p_buf(s.p_buf) {}
|
2015-06-04 21:57:06 +00:00
|
|
|
StringBase(const StringBase &s, const A &a):
|
2015-06-03 22:07:57 +00:00
|
|
|
p_buf(s.p_buf, a) {}
|
2015-07-05 22:59:36 +00:00
|
|
|
StringBase(StringBase &&s): p_buf(move(s.p_buf)) {}
|
2015-06-04 21:57:06 +00:00
|
|
|
StringBase(StringBase &&s, const A &a):
|
2015-07-05 22:59:36 +00:00
|
|
|
p_buf(move(s.p_buf), a) {}
|
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-06-04 21:57:06 +00:00
|
|
|
const A &a = A()):
|
2015-06-26 20:01:16 +00:00
|
|
|
p_buf(s.p_buf.iter().slice(pos,
|
2015-06-03 22:07:57 +00:00
|
|
|
(len == npos) ? s.p_buf.size() : (pos + len)), a) {
|
|
|
|
terminate();
|
|
|
|
}
|
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-06-16 23:15:44 +00:00
|
|
|
StringBase(const Value *v, const A &a = A()):
|
2015-06-03 22:07:57 +00:00
|
|
|
p_buf(ConstRange(v, strlen(v) + 1), a) {}
|
2015-05-28 00:26:48 +00:00
|
|
|
|
2015-06-16 23:15:44 +00:00
|
|
|
StringBase(const Value *v, Size n, const A &a = A()):
|
2015-06-09 17:59:25 +00:00
|
|
|
p_buf(ConstRange(v, n), a) {}
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
template<typename R, typename = EnableIf<
|
|
|
|
IsInputRange<R>::value &&
|
|
|
|
IsConvertible<RangeReference<R>, Value>::value
|
2015-06-29 20:56:13 +00:00
|
|
|
>> StringBase(R range, const A &a = A()): p_buf(range, a) {
|
2015-06-03 22:07:57 +00:00
|
|
|
terminate();
|
|
|
|
}
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-06-03 22:07:57 +00:00
|
|
|
void clear() { p_buf.clear(); }
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-06-09 23:16:25 +00:00
|
|
|
StringBase &operator=(const StringBase &v) {
|
2015-06-03 22:07:57 +00:00
|
|
|
p_buf.operator=(v);
|
|
|
|
return *this;
|
|
|
|
}
|
2015-06-09 23:16:25 +00:00
|
|
|
StringBase &operator=(StringBase &&v) {
|
2015-07-05 22:59:36 +00:00
|
|
|
p_buf.operator=(move(v));
|
2015-06-03 22:07:57 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2015-06-16 23:15:44 +00:00
|
|
|
StringBase &operator=(const Value *v) {
|
2015-06-03 22:07:57 +00:00
|
|
|
p_buf = ConstRange(v, strlen(v) + 1);
|
|
|
|
return *this;
|
|
|
|
}
|
2015-07-05 22:59:36 +00:00
|
|
|
template<typename R, typename = EnableIf<
|
|
|
|
IsInputRange<R>::value &&
|
|
|
|
IsConvertible<RangeReference<R>, Value>::value
|
2015-06-29 20:56:13 +00:00
|
|
|
>> StringBase &operator=(const R &r) {
|
2015-06-09 17:59:25 +00:00
|
|
|
p_buf = r;
|
|
|
|
terminate();
|
|
|
|
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-06-03 22:07:57 +00:00
|
|
|
p_buf.pop();
|
|
|
|
p_buf.resize(n, v);
|
|
|
|
terminate();
|
|
|
|
}
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
void reserve(Size n) {
|
2015-06-03 22:07:57 +00:00
|
|
|
p_buf.reserve(n + 1);
|
|
|
|
}
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
T &operator[](Size i) { return p_buf[i]; }
|
|
|
|
const T &operator[](Size i) const { return p_buf[i]; }
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
T &at(Size i) { return p_buf[i]; }
|
|
|
|
const T &at(Size i) const { return p_buf[i]; }
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
T &front() { return p_buf[0]; }
|
|
|
|
const T &front() const { return p_buf[0]; };
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
T &back() { return p_buf[size() - 1]; }
|
|
|
|
const T &back() const { return p_buf[size() - 1]; }
|
2015-05-27 21:15:24 +00:00
|
|
|
|
2015-06-16 23:15:44 +00:00
|
|
|
Value *data() { return p_buf.data(); }
|
|
|
|
const Value *data() const { return p_buf.data(); }
|
2015-05-29 00:02:19 +00:00
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
Size size() const {
|
2015-06-03 22:07:57 +00:00
|
|
|
return p_buf.size() - 1;
|
|
|
|
}
|
2015-05-29 00:02:19 +00:00
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
Size capacity() const {
|
2015-06-03 22:07:57 +00:00
|
|
|
return p_buf.capacity() - 1;
|
|
|
|
}
|
2015-05-29 00:02:19 +00:00
|
|
|
|
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-06-04 21:57:06 +00:00
|
|
|
void push(T v) {
|
2015-06-03 22:07:57 +00:00
|
|
|
p_buf.back() = v;
|
|
|
|
p_buf.push('\0');
|
|
|
|
}
|
2015-05-29 00:02:19 +00:00
|
|
|
|
2015-06-09 23:16:25 +00:00
|
|
|
StringBase &append(const StringBase &s) {
|
2015-06-03 22:07:57 +00:00
|
|
|
p_buf.pop();
|
2015-06-26 20:01:16 +00:00
|
|
|
p_buf.insert_range(p_buf.size(), s.p_buf.iter());
|
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(const StringBase &s, Size idx, Size len) {
|
2015-06-03 22:07:57 +00:00
|
|
|
p_buf.pop();
|
2015-06-08 20:20:12 +00:00
|
|
|
p_buf.insert_range(p_buf.size(), Range(&s[idx],
|
2015-06-03 22:07:57 +00:00
|
|
|
(len == npos) ? (s.size() - idx) : len));
|
|
|
|
terminate();
|
|
|
|
return *this;
|
|
|
|
}
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-06-16 23:15:44 +00:00
|
|
|
StringBase &append(const Value *s) {
|
2015-06-03 22:07:57 +00:00
|
|
|
p_buf.pop();
|
|
|
|
p_buf.insert_range(p_buf.size(), ConstRange(s,
|
|
|
|
strlen(s) + 1));
|
|
|
|
return *this;
|
|
|
|
}
|
2015-05-27 20:43:13 +00:00
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
StringBase &append(Size n, T c) {
|
2015-06-03 22:07:57 +00:00
|
|
|
p_buf.pop();
|
2015-07-05 22:59:36 +00:00
|
|
|
for (Size i = 0; i < n; ++i) p_buf.push(c);
|
2015-06-03 22:07:57 +00:00
|
|
|
p_buf.push('\0');
|
|
|
|
return *this;
|
|
|
|
}
|
2015-05-27 21:05:51 +00:00
|
|
|
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename R>
|
2015-06-09 23:16:25 +00:00
|
|
|
StringBase &append_range(R range) {
|
2015-06-03 22:07:57 +00:00
|
|
|
p_buf.pop();
|
|
|
|
p_buf.insert_range(p_buf.size(), range);
|
|
|
|
terminate();
|
|
|
|
return *this;
|
|
|
|
}
|
2015-05-31 18:50:00 +00:00
|
|
|
|
2015-06-09 23:16:25 +00:00
|
|
|
StringBase &operator+=(const StringBase &s) {
|
2015-06-03 22:07:57 +00:00
|
|
|
return append(s);
|
|
|
|
}
|
2015-06-16 23:15:44 +00:00
|
|
|
StringBase &operator+=(const Value *s) {
|
2015-06-03 22:07:57 +00:00
|
|
|
return append(s);
|
|
|
|
}
|
2015-06-09 23:16:25 +00:00
|
|
|
StringBase &operator+=(T c) {
|
2015-06-03 22:07:57 +00:00
|
|
|
p_buf.pop();
|
|
|
|
p_buf.push(c);
|
|
|
|
p_buf.push('\0');
|
|
|
|
return *this;
|
2015-05-27 21:29:57 +00:00
|
|
|
}
|
|
|
|
|
2015-06-14 01:36:20 +00:00
|
|
|
int compare(const StringBase &s) const {
|
|
|
|
return strcmp(p_buf.data(), s.data());
|
|
|
|
}
|
|
|
|
|
2015-06-16 23:15:44 +00:00
|
|
|
int compare(const Value *p) const {
|
2015-06-14 01:36:20 +00:00
|
|
|
return strcmp(p_buf.data(), p);
|
|
|
|
}
|
|
|
|
|
2015-06-26 20:01:16 +00:00
|
|
|
Range iter() {
|
2015-06-03 22:07:57 +00:00
|
|
|
return Range(p_buf.data(), size());
|
|
|
|
}
|
2015-06-26 20:01:16 +00:00
|
|
|
ConstRange iter() const {
|
2015-06-03 22:07:57 +00:00
|
|
|
return ConstRange(p_buf.data(), size());
|
2015-05-27 21:05:51 +00:00
|
|
|
}
|
2015-06-26 20:01:16 +00:00
|
|
|
ConstRange citer() const {
|
2015-06-09 20:18:43 +00:00
|
|
|
return ConstRange(p_buf.data(), size());
|
|
|
|
}
|
|
|
|
|
2015-07-03 17:21:05 +00:00
|
|
|
Range iter_cap() {
|
|
|
|
return Range(p_buf.data(), capacity());
|
|
|
|
}
|
|
|
|
|
2015-06-03 22:07:57 +00:00
|
|
|
void swap(StringBase &v) {
|
2015-06-14 23:18:08 +00:00
|
|
|
p_buf.swap(v.p_buf);
|
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 {
|
|
|
|
return p_buf.get_allocator();
|
|
|
|
}
|
2015-06-03 22:07:57 +00:00
|
|
|
};
|
|
|
|
|
2015-06-07 23:55:08 +00:00
|
|
|
using String = StringBase<char>;
|
2015-06-09 17:59:25 +00:00
|
|
|
using StringRange = StringRangeBase<char>;
|
|
|
|
using ConstStringRange = StringRangeBase<const char>;
|
2015-06-03 22:07:57 +00:00
|
|
|
|
2015-07-01 19:09:02 +00:00
|
|
|
template<typename A> using AnyString = StringBase<char, A>;
|
|
|
|
|
|
|
|
template<typename T, typename A>
|
2015-07-11 15:07:52 +00:00
|
|
|
inline bool operator==(const StringBase<T, A> &lhs,
|
|
|
|
const StringBase<T, A> &rhs) {
|
2015-06-14 01:36:20 +00:00
|
|
|
return !lhs.compare(rhs);
|
|
|
|
}
|
2015-07-01 19:09:02 +00:00
|
|
|
template<typename T, typename A>
|
2015-07-11 15:07:52 +00:00
|
|
|
inline bool operator==(const StringBase<T, A> &lhs, const char *rhs) {
|
2015-06-14 01:36:20 +00:00
|
|
|
return !lhs.compare(rhs);
|
|
|
|
}
|
2015-07-01 19:09:02 +00:00
|
|
|
template<typename T, typename A>
|
2015-07-11 15:07:52 +00:00
|
|
|
inline bool operator==(const char *lhs, const StringBase<T, A> &rhs) {
|
2015-06-14 01:36:20 +00:00
|
|
|
return !rhs.compare(lhs);
|
|
|
|
}
|
|
|
|
|
2015-07-01 19:09:02 +00:00
|
|
|
template<typename T, typename A>
|
2015-07-11 15:07:52 +00:00
|
|
|
inline bool operator!=(const StringBase<T, A> &lhs,
|
|
|
|
const StringBase<T, A> &rhs) {
|
|
|
|
return !(lhs == rhs);
|
2015-06-14 01:36:20 +00:00
|
|
|
}
|
2015-07-01 19:09:02 +00:00
|
|
|
template<typename T, typename A>
|
2015-07-11 15:07:52 +00:00
|
|
|
inline bool operator!=(const StringBase<T, A> &lhs, const char *rhs) {
|
|
|
|
return !(lhs == rhs);
|
2015-06-14 01:36:20 +00:00
|
|
|
}
|
2015-07-01 19:09:02 +00:00
|
|
|
template<typename T, typename A>
|
2015-07-11 15:07:52 +00:00
|
|
|
inline bool operator!=(const char *lhs, const StringBase<T, A> &rhs) {
|
|
|
|
return !(rhs == lhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename A>
|
|
|
|
inline bool operator<(const StringBase<T, A> &lhs,
|
|
|
|
const StringBase<T, A> &rhs) {
|
|
|
|
return lhs.compare(rhs) < 0;
|
|
|
|
}
|
|
|
|
template<typename T, typename A>
|
|
|
|
inline bool operator<(const StringBase<T, A> &lhs, const char *rhs) {
|
|
|
|
return lhs.compare(rhs) < 0;
|
|
|
|
}
|
|
|
|
template<typename T, typename A>
|
|
|
|
inline bool operator<(const char *lhs, const StringBase<T, A> &rhs) {
|
|
|
|
return rhs.compare(lhs) > 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename A>
|
|
|
|
inline bool operator>(const StringBase<T, A> &lhs,
|
|
|
|
const StringBase<T, A> &rhs) {
|
|
|
|
return rhs < lhs;
|
|
|
|
}
|
|
|
|
template<typename T, typename A>
|
|
|
|
inline bool operator>(const StringBase<T, A> &lhs, const char *rhs) {
|
|
|
|
return rhs < lhs;
|
|
|
|
}
|
|
|
|
template<typename T, typename A>
|
|
|
|
inline bool operator>(const char *lhs, const StringBase<T, A> &rhs) {
|
|
|
|
return rhs < lhs;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename A>
|
|
|
|
inline bool operator<=(const StringBase<T, A> &lhs,
|
|
|
|
const StringBase<T, A> &rhs) {
|
|
|
|
return !(rhs < lhs);
|
|
|
|
}
|
|
|
|
template<typename T, typename A>
|
|
|
|
inline bool operator<=(const StringBase<T, A> &lhs, const char *rhs) {
|
|
|
|
return !(rhs < lhs);
|
|
|
|
}
|
|
|
|
template<typename T, typename A>
|
|
|
|
inline bool operator<=(const char *lhs, const StringBase<T, A> &rhs) {
|
|
|
|
return !(rhs < lhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T, typename A>
|
|
|
|
inline bool operator>=(const StringBase<T, A> &lhs,
|
|
|
|
const StringBase<T, A> &rhs) {
|
|
|
|
return !(lhs < rhs);
|
|
|
|
}
|
|
|
|
template<typename T, typename A>
|
|
|
|
inline bool operator>=(const StringBase<T, A> &lhs, const char *rhs) {
|
|
|
|
return !(lhs < rhs);
|
|
|
|
}
|
|
|
|
template<typename T, typename A>
|
|
|
|
inline bool operator>=(const char *lhs, const StringBase<T, A> &rhs) {
|
|
|
|
return !(lhs < rhs);
|
2015-06-14 01:36:20 +00:00
|
|
|
}
|
|
|
|
|
2015-07-01 19:09:02 +00:00
|
|
|
template<typename T, typename F, typename S = const char *,
|
|
|
|
typename A = typename String::Allocator>
|
|
|
|
AnyString<A> concat(const T &v, const S &sep, F func) {
|
|
|
|
AnyString<A> ret;
|
2015-06-26 20:01:16 +00:00
|
|
|
auto range = octa::iter(v);
|
2015-06-25 17:59:26 +00:00
|
|
|
if (range.empty()) return ret;
|
2015-06-03 22:07:57 +00:00
|
|
|
for (;;) {
|
|
|
|
ret += func(range.front());
|
|
|
|
range.pop_front();
|
|
|
|
if (range.empty()) break;
|
|
|
|
ret += sep;
|
|
|
|
}
|
2015-06-25 17:59:26 +00:00
|
|
|
return ret;
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-05-28 18:58:05 +00:00
|
|
|
|
2015-07-01 19:09:02 +00:00
|
|
|
template<typename T, typename S = const char *,
|
|
|
|
typename A = typename String::Allocator>
|
|
|
|
AnyString<A> concat(const T &v, const S &sep = " ") {
|
|
|
|
AnyString<A> ret;
|
2015-06-26 20:01:16 +00:00
|
|
|
auto range = octa::iter(v);
|
2015-06-25 17:59:26 +00:00
|
|
|
if (range.empty()) return ret;
|
2015-06-03 22:07:57 +00:00
|
|
|
for (;;) {
|
|
|
|
ret += range.front();
|
|
|
|
range.pop_front();
|
|
|
|
if (range.empty()) break;
|
|
|
|
ret += sep;
|
2015-05-28 18:58:05 +00:00
|
|
|
}
|
2015-06-25 17:59:26 +00:00
|
|
|
return ret;
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
|
|
|
|
2015-07-01 19:09:02 +00:00
|
|
|
template<typename T, typename F, typename S = const char *,
|
|
|
|
typename A = typename String::Allocator>
|
|
|
|
AnyString<A> concat(std::initializer_list<T> v, const S &sep, F func) {
|
2015-06-26 20:01:16 +00:00
|
|
|
return concat(octa::iter(v), sep, func);
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-05-28 18:58:05 +00:00
|
|
|
|
2015-07-01 19:09:02 +00:00
|
|
|
template<typename T, typename S = const char *,
|
|
|
|
typename A = typename String::Allocator>
|
|
|
|
AnyString<A> concat(std::initializer_list<T> v, const S &sep = " ") {
|
2015-06-26 20:01:16 +00:00
|
|
|
return concat(octa::iter(v), sep);
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace detail {
|
2015-06-04 21:57:06 +00:00
|
|
|
template<typename T>
|
2015-07-11 18:54:51 +00:00
|
|
|
auto test_tostring(int) ->
|
|
|
|
decltype(IsSame<decltype(declval<T>().to_string()), String>());
|
|
|
|
template<typename>
|
|
|
|
False test_tostring(...);
|
2015-07-11 16:26:41 +00:00
|
|
|
|
|
|
|
template<typename T>
|
2015-07-11 18:54:51 +00:00
|
|
|
using ToStringTest = decltype(test_tostring<T>(0));
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
True test_iterable(decltype(octa::iter(declval<T>())) *);
|
2015-07-11 16:26:41 +00:00
|
|
|
template<typename> static False test_iterable(...);
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
using IterableTest = decltype(test_iterable<T>(0));
|
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>
|
|
|
|
struct ToString<T, EnableIf<detail::IterableTest<T>::value>> {
|
2015-06-07 23:55:08 +00:00
|
|
|
using Argument = T;
|
|
|
|
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-04 13:52:02 +00:00
|
|
|
ret += concat(octa::iter(v), ", ", ToString<
|
2015-07-11 17:50:13 +00:00
|
|
|
RemoveConst<RemoveReference<
|
2015-07-05 22:59:36 +00:00
|
|
|
RangeReference<decltype(octa::iter(v))>
|
|
|
|
>>
|
2015-07-04 13:52:02 +00:00
|
|
|
>());
|
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>
|
|
|
|
struct ToString<T, EnableIf<IsScalar<T>::value>> {
|
|
|
|
using Argument = T;
|
|
|
|
using Result = String;
|
|
|
|
|
|
|
|
String operator()(const T &v) const {
|
|
|
|
return ToString<T>()(v);
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
2015-07-11 16:26:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
struct ToString<T, EnableIf<detail::ToStringTest<T>::value>> {
|
|
|
|
using Argument = T;
|
|
|
|
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-11 16:26:41 +00:00
|
|
|
return v.to_string();
|
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-05 22:59:36 +00:00
|
|
|
void str_printf(Vector<char> *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);
|
|
|
|
s->clear();
|
|
|
|
s->reserve(n + 1);
|
|
|
|
if (n >= (int)sizeof(buf))
|
|
|
|
snprintf(s->data(), n + 1, fmt, v);
|
|
|
|
else if (n > 0)
|
|
|
|
memcpy(s->data(), buf, n + 1);
|
2015-05-28 00:44:21 +00:00
|
|
|
else {
|
2015-06-03 22:07:57 +00:00
|
|
|
n = 0;
|
|
|
|
*(s->data()) = '\0';
|
2015-05-28 00:44:21 +00:00
|
|
|
}
|
2015-07-05 22:59:36 +00:00
|
|
|
*((Size *)s) = n + 1;
|
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) {
|
|
|
|
return b ? "true" : "false";
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
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-06-04 21:57:06 +00:00
|
|
|
#define OCTA_TOSTR_NUM(T, fmt) \
|
|
|
|
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-05 22:59:36 +00:00
|
|
|
detail::str_printf((Vector<char> *)&ret, fmt, v); \
|
2015-06-25 17:59:26 +00:00
|
|
|
return ret; \
|
2015-06-03 22:07:57 +00:00
|
|
|
} \
|
|
|
|
};
|
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
OCTA_TOSTR_NUM(sbyte, "%d")
|
2015-06-03 22:07:57 +00:00
|
|
|
OCTA_TOSTR_NUM(int, "%d")
|
|
|
|
OCTA_TOSTR_NUM(int &, "%d")
|
|
|
|
OCTA_TOSTR_NUM(long, "%ld")
|
|
|
|
OCTA_TOSTR_NUM(float, "%f")
|
|
|
|
OCTA_TOSTR_NUM(double, "%f")
|
2015-06-08 20:20:12 +00:00
|
|
|
|
2015-07-05 22:59:36 +00:00
|
|
|
OCTA_TOSTR_NUM(byte, "%u")
|
|
|
|
OCTA_TOSTR_NUM(uint, "%u")
|
|
|
|
OCTA_TOSTR_NUM(ulong, "%lu")
|
|
|
|
OCTA_TOSTR_NUM(llong, "%lld")
|
|
|
|
OCTA_TOSTR_NUM(ullong, "%llu")
|
|
|
|
OCTA_TOSTR_NUM(ldouble, "%Lf")
|
2015-06-03 22:07:57 +00:00
|
|
|
|
|
|
|
#undef OCTA_TOSTR_NUM
|
|
|
|
|
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-05 22:59:36 +00:00
|
|
|
detail::str_printf((Vector<char> *)&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-06-09 17:59:25 +00:00
|
|
|
template<> struct ToString<StringRange> {
|
2015-07-01 17:51:39 +00:00
|
|
|
using Argument = StringRange;
|
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-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("{");
|
2015-07-11 19:18:46 +00:00
|
|
|
ret += ToString<RemoveReference<RemoveCv<T>>>()(v.first);
|
2015-06-03 22:07:57 +00:00
|
|
|
ret += ", ";
|
2015-07-11 19:18:46 +00:00
|
|
|
ret += ToString<RemoveReference<RemoveCv<U>>>()(v.second);
|
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) {
|
2015-07-11 19:18:46 +00:00
|
|
|
return ToString<RemoveReference<RemoveCv<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-06-25 17:59:26 +00:00
|
|
|
return ToString<std::initializer_list<T>>()(init);
|
2015-06-03 22:07:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} /* namespace octa */
|
|
|
|
|
2015-05-27 20:43:13 +00:00
|
|
|
#endif
|