add StringRange (provides hashing and proper ToString), make it the range for String, add extra ptr-ctor for Vector and new ctors for String, optimizations
parent
13b8b06d33
commit
1553e2d30f
|
@ -636,6 +636,10 @@ struct PointerRange: InputRange<PointerRange<T>, FiniteRandomAccessRangeTag, T>
|
|||
*(p_beg++) = octa::move(v);
|
||||
}
|
||||
|
||||
/* non-range methods */
|
||||
T *data() { return p_beg; }
|
||||
const T *data() const { return p_beg; }
|
||||
|
||||
private:
|
||||
T *p_beg, *p_end;
|
||||
};
|
||||
|
|
145
octa/string.h
145
octa/string.h
|
@ -16,7 +16,122 @@
|
|||
namespace octa {
|
||||
static constexpr octa::Size npos = -1;
|
||||
|
||||
template<typename T, typename A = octa::Allocator<T>>
|
||||
template<typename T, typename A = octa::Allocator<T>> class StringBase;
|
||||
|
||||
template<typename T>
|
||||
struct StringRangeBase: InputRange<
|
||||
StringRangeBase<T>, FiniteRandomAccessRangeTag, T
|
||||
> {
|
||||
StringRangeBase(): p_beg(nullptr), p_end(nullptr) {}
|
||||
StringRangeBase(const StringRangeBase &v): p_beg(v.p_beg),
|
||||
p_end(v.p_end) {}
|
||||
StringRangeBase(T *beg, T *end): p_beg(beg), p_end(end) {}
|
||||
StringRangeBase(T *beg, octa::Size n): p_beg(beg), p_end(beg + n) {}
|
||||
/* TODO: traits for utf-16/utf-32 string lengths, for now assume char */
|
||||
StringRangeBase(T *beg): p_beg(beg), p_end(beg + strlen(beg)) {}
|
||||
StringRangeBase(const StringBase<T> &s): p_beg(s.data()),
|
||||
p_end(s.data() + s.size()) {}
|
||||
|
||||
StringRangeBase &operator=(const StringRangeBase &v) {
|
||||
p_beg = v.p_beg; p_end = v.p_end; return *this;
|
||||
}
|
||||
StringRangeBase &operator=(const StringBase<T> &s) {
|
||||
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; }
|
||||
|
||||
octa::Size pop_front_n(octa::Size n) {
|
||||
octa::Size olen = p_end - p_beg;
|
||||
p_beg += n;
|
||||
if (p_beg > p_end) {
|
||||
p_beg = p_end;
|
||||
return olen;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
octa::Size push_front_n(octa::Size n) { p_beg -= n; return true; }
|
||||
|
||||
T &front() const { return *p_beg; }
|
||||
|
||||
bool equals_front(const StringRangeBase &range) const {
|
||||
return p_beg == range.p_beg;
|
||||
}
|
||||
|
||||
octa::Ptrdiff distance_front(const StringRangeBase &range) const {
|
||||
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; }
|
||||
|
||||
octa::Size pop_back_n(octa::Size n) {
|
||||
octa::Size olen = p_end - p_beg;
|
||||
p_end -= n;
|
||||
if (p_end < p_beg) {
|
||||
p_end = p_beg;
|
||||
return olen;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
octa::Size push_back_n(octa::Size n) { p_end += n; return true; }
|
||||
|
||||
T &back() const { return *(p_end - 1); }
|
||||
|
||||
bool equals_back(const StringRangeBase &range) const {
|
||||
return p_end == range.p_end;
|
||||
}
|
||||
|
||||
octa::Ptrdiff distance_back(const StringRangeBase &range) const {
|
||||
return range.p_end - p_end;
|
||||
}
|
||||
|
||||
octa::Size size() const { return p_end - p_beg; }
|
||||
|
||||
StringRangeBase slice(octa::Size start, octa::Size end) const {
|
||||
return StringRangeBase(p_beg + start, p_beg + end);
|
||||
}
|
||||
|
||||
T &operator[](octa::Size i) const { return p_beg[i]; }
|
||||
|
||||
void put(T v) {
|
||||
*(p_beg++) = v;
|
||||
}
|
||||
|
||||
/* non-range methods */
|
||||
T *data() { return p_beg; }
|
||||
const T *data() const { return p_beg; }
|
||||
|
||||
octa::Size to_hash() const {
|
||||
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>
|
||||
class StringBase {
|
||||
octa::Vector<T> p_buf;
|
||||
|
||||
|
@ -32,8 +147,8 @@ public:
|
|||
using ConstReference = const T &;
|
||||
using Pointer = T *;
|
||||
using ConstPointer = const T *;
|
||||
using Range = octa::PointerRange<T>;
|
||||
using ConstRange = octa::PointerRange<const T>;
|
||||
using Range = octa::StringRangeBase<T>;
|
||||
using ConstRange = octa::StringRangeBase<const T>;
|
||||
using Allocator = A;
|
||||
|
||||
StringBase(const A &a = A()): p_buf(1, '\0', a) {}
|
||||
|
@ -56,6 +171,9 @@ public:
|
|||
StringBase(const T *v, const A &a = A()):
|
||||
p_buf(ConstRange(v, strlen(v) + 1), a) {}
|
||||
|
||||
StringBase(const T *v, Size n, const A &a = A()):
|
||||
p_buf(ConstRange(v, n), a) {}
|
||||
|
||||
template<typename R> StringBase(R range, const A &a = A()):
|
||||
p_buf(range, a) {
|
||||
terminate();
|
||||
|
@ -75,6 +193,11 @@ public:
|
|||
p_buf = ConstRange(v, strlen(v) + 1);
|
||||
return *this;
|
||||
}
|
||||
StringBase<T> &operator=(const Range &r) {
|
||||
p_buf = r;
|
||||
terminate();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void resize(octa::Size n, T v = T()) {
|
||||
p_buf.pop();
|
||||
|
@ -177,15 +300,13 @@ public:
|
|||
}
|
||||
|
||||
Size to_hash() const {
|
||||
const T *d = data();
|
||||
Size h = 5381, len = size();
|
||||
for (Size i = 0; i < len; ++i)
|
||||
h = ((h << 5) + h) ^ d[i];
|
||||
return h;
|
||||
return each().to_hash();
|
||||
}
|
||||
};
|
||||
|
||||
using String = StringBase<char>;
|
||||
using StringRange = StringRangeBase<char>;
|
||||
using ConstStringRange = StringRangeBase<const char>;
|
||||
|
||||
template<typename T, typename F>
|
||||
String concat(const T v, const String &sep, F func) {
|
||||
|
@ -354,6 +475,14 @@ template<> struct ToString<String> {
|
|||
}
|
||||
};
|
||||
|
||||
template<> struct ToString<StringRange> {
|
||||
using Argument = const StringRange &;
|
||||
using Result = String;
|
||||
String operator()(Argument s) {
|
||||
return String(s);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, typename U> struct ToString<octa::Pair<T, U>> {
|
||||
using Argument = const octa::Pair<T, U> &;
|
||||
using Result = String;
|
||||
|
|
|
@ -79,6 +79,10 @@ class Vector {
|
|||
octa::RangeSize<R> l = range.size();
|
||||
reserve(l);
|
||||
p_len = l;
|
||||
if (octa::IsPod<T>() && octa::IsSame<T, octa::RangeValue<R>>()) {
|
||||
memcpy(p_buf.p_ptr, &range.front(), range.size());
|
||||
return;
|
||||
}
|
||||
for (octa::Size i = 0; !range.empty(); range.pop_front()) {
|
||||
octa::allocator_construct(p_buf.get_alloc(),
|
||||
&p_buf.p_ptr[i], range.front());
|
||||
|
@ -182,16 +186,21 @@ public:
|
|||
v.p_len = v.p_cap = 0;
|
||||
}
|
||||
|
||||
Vector(InitializerList<T> v, const A &a = A()): Vector(a) {
|
||||
Size l = v.end() - v.begin();
|
||||
const T *ptr = v.begin();
|
||||
reserve(l);
|
||||
for (Size i = 0; i < l; ++i)
|
||||
octa::allocator_construct(p_buf.get_alloc(),
|
||||
&p_buf.p_ptr[i], ptr[i]);
|
||||
p_len = l;
|
||||
Vector(const T *buf, Size n, const A &a = A()): Vector(a) {
|
||||
reserve(n);
|
||||
if (octa::IsPod<T>()) {
|
||||
memcpy(p_buf.p_ptr, buf, n * sizeof(T));
|
||||
} else {
|
||||
for (Size i = 0; i < n; ++i)
|
||||
octa::allocator_construct(p_buf.get_alloc(),
|
||||
&p_buf.p_ptr[i], buf[i]);
|
||||
}
|
||||
p_len = n;
|
||||
}
|
||||
|
||||
Vector(InitializerList<T> v, const A &a = A()):
|
||||
Vector(v.begin(), v.size(), a) {}
|
||||
|
||||
template<typename R> Vector(R range, const A &a = A()):
|
||||
Vector(a) {
|
||||
ctor_from_range(range);
|
||||
|
@ -252,6 +261,7 @@ public:
|
|||
Vector &operator=(R range) {
|
||||
clear();
|
||||
ctor_from_range(range);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void resize(Size n, const T &v = T()) {
|
||||
|
|
Loading…
Reference in New Issue