1919#include < ostream>
2020
2121#include " lcf/string_view.h"
22+ #include " lcf/dbarray.h"
2223
2324namespace lcf {
2425
2526// A custom string class optimized for database storage.
2627// This string type is good for storing and retrieving values.
2728// It is not good for string manipulation like insertion or concatenation.
28- class DBString {
29+ class DBString : public DBArrayBase {
2930 public:
3031 using value_type = char ;
3132 using size_type = uint32_t ;
@@ -41,14 +42,14 @@ class DBString {
4142 static constexpr size_type npos = size_type(-1 );
4243
4344 constexpr DBString () = default;
44- explicit DBString (StringView s);
45- explicit DBString (const std::string& s) : DBString(StringView(s )) {}
45+ explicit DBString (StringView s) : _storage(construct_sv(s.data(), s.size())) {}
46+ explicit DBString (const std::string& s) : _storage(construct_z(s.c_str(), s.size() )) {}
4647
4748 // Explicit construct for general const char*
4849 explicit DBString (const char * s) : DBString(StringView(s)) {}
4950 // Implicit constructor to capture string literals
5051 template <size_t N>
51- DBString (const char (&literal)[N]) : DBString(StringView (literal)) {}
52+ DBString (const char (&literal)[N]) : _storage(construct_z (literal, N - 1 )) {}
5253 DBString (const char * s, size_t len) : DBString(StringView(s, len)) {}
5354
5455 DBString (const DBString& o) : DBString(StringView(o)) {}
@@ -61,7 +62,7 @@ class DBString {
6162 std::swap (_storage, o._storage );
6263 }
6364
64- ~DBString () { _reset (); }
65+ ~DBString () { destroy (); }
6566
6667 explicit operator std::string () const { return std::string (data (), size ()); }
6768 operator StringView () const { return StringView (data (), size ()); }
@@ -75,8 +76,8 @@ class DBString {
7576 char & back () { return (*this )[size ()-1 ]; }
7677 char back () const { return (*this )[size ()-1 ]; }
7778
78- char * data () { return _storage; }
79- const char * data () const { return _storage; }
79+ char * data () { return static_cast < char *>( _storage) ; }
80+ const char * data () const { return static_cast < const char *>( _storage) ; }
8081
8182 const char * c_str () const { return data (); }
8283
@@ -99,16 +100,20 @@ class DBString {
99100 const_reverse_iterator crend () const { return rend (); }
100101
101102 bool empty () const { return size () == 0 ; }
102- size_type size () const ;
103+ size_type size () const { return * this -> get_size_ptr (_storage); }
103104
104- static constexpr char * empty_str () {
105- return const_cast <char *>(_empty_str + sizeof (size_type));
106- }
107105 private:
108- void _reset () noexcept ;
106+ char * alloc (size_t count) {
107+ return reinterpret_cast <char *>(DBArrayBase::alloc (count + 1 , count, 1 ));
108+ }
109+ void free (void * p) {
110+ DBArrayBase::free (p, 1 );
111+ }
112+ void destroy () noexcept ;
113+ char * construct_z (const char * s, size_t len);
114+ char * construct_sv (const char * s, size_t len);
109115 private:
110- alignas (size_type) static constexpr char _empty_str[sizeof (size_type)] = {};
111- char * _storage = empty_str();
116+ void * _storage = this ->empty_buf ();
112117};
113118
114119// This should be used over the conversion operator, so we can track all dbstr -> str instances
@@ -151,17 +156,17 @@ namespace lcf {
151156
152157inline DBString& DBString::operator =(DBString&& o) noexcept {
153158 if (this != &o) {
154- if (!empty ()) {
155- _reset ();
156- }
157- _storage = o._storage ;
158- o._storage = empty_str ();
159+ destroy ();
160+ swap (o);
159161 }
160162 return *this ;
161163}
162164
163- inline DBString::size_type DBString::size () const {
164- return *(reinterpret_cast <const size_type*>(_storage) - 1 );
165+ inline void DBString::destroy () noexcept {
166+ if (_storage != this ->empty_buf ()) {
167+ free (_storage);
168+ _storage = this ->empty_buf ();
169+ }
165170}
166171
167172} // namespace lcf
0 commit comments