Skip to content

Commit ba19bdf

Browse files
authored
refactor: store dom::String as a single pointer
closes #413
1 parent d5b7b3d commit ba19bdf

File tree

2 files changed

+196
-245
lines changed

2 files changed

+196
-245
lines changed

include/mrdox/Dom/String.hpp

+120-75
Original file line numberDiff line numberDiff line change
@@ -28,70 +28,114 @@ concept StringLikeTy =
2828
! std::is_same_v<StringTy, String> &&
2929
std::convertible_to<StringTy, std::string_view>;
3030

31-
/** An immutable string with shared ownership.
32-
*/
3331
class MRDOX_DECL
3432
String final
3533
{
36-
struct Impl;
34+
const char* ptr_ = nullptr;
3735

38-
union
39-
{
40-
Impl* impl_;
41-
// len is stored with the low bit moved to
42-
// the hi bit, and the low bit always set.
43-
std::size_t len_;
44-
};
45-
char const* psz_;
46-
47-
static void allocate(std::string_view s,Impl*&, char const*&);
48-
static void deallocate(Impl*) noexcept;
49-
static consteval std::size_t len(std::size_t n)
36+
bool
37+
is_literal() const noexcept
5038
{
51-
return (n << (sizeof(std::size_t)*8 - 1)) | n | 1UL;
39+
MRDOX_ASSERT(! empty());
40+
// for string literals, data_ stores a pointer
41+
// to the first character of the string.
42+
// for ref-counted strings, data_ stores a pointer
43+
// to the null-terminator of the string.
44+
return *ptr_;
5245
}
5346

54-
constexpr bool is_literal() const noexcept
55-
{
56-
return (len_ & 1) != 0;
57-
}
47+
class impl_view;
5848

59-
public:
60-
/** Destructor.
49+
impl_view impl() const noexcept;
50+
51+
/** Construct a ref-counted string.
6152
*/
62-
~String();
53+
void
54+
construct(
55+
const char* s,
56+
std::size_t n);
6357

58+
public:
6459
/** Constructor.
6560
6661
Default constructed strings have a zero size,
6762
and include a null terminator.
6863
*/
69-
String() noexcept;
64+
constexpr String() noexcept = default;
7065

7166
/** Constructor.
7267
7368
Ownership of the string is transferred to
7469
the newly constructed string. The moved-from
7570
string behaves as if default constructed.
7671
*/
77-
String(String&& other) noexcept;
72+
constexpr String(String&& other) noexcept
73+
{
74+
swap(other);
75+
}
7876

7977
/** Constructor.
8078
8179
The newly constructed string acquries shared
8280
ownership of the string referenced by other.
8381
*/
84-
String(String const& other) noexcept;
82+
String(const String& other) noexcept;
83+
84+
/** Destructor.
85+
*/
86+
~String() noexcept;
87+
88+
/** Constructor.
89+
90+
This function constructs a string literal
91+
which references the buffer pointed to by
92+
`str`. Ownership is not transferred; the lifetime
93+
of the buffer must extend until the string is
94+
destroyed, otherwise the behavior is undefined.
95+
96+
@param str A null-terminated string. If the
97+
string is not null-terminated, the result is
98+
undefined.
99+
*/
100+
template<std::size_t N>
101+
constexpr
102+
String(const char(&str)[N])
103+
{
104+
// empty strings are stored as nullptr
105+
if constexpr(N > 1)
106+
ptr_ = str;
107+
}
85108

86109
/** Constructor.
87110
88111
This function constructs a new string from
89-
the buffer pointed to by `s`.
112+
the string pointed to by `str` of length `len`.
90113
91-
@param s The string to construct with.
114+
@param `str` The string to construct with.
115+
A copy of this string is made.
116+
@param `len` The length of the string.
117+
*/
118+
String(
119+
const char* str,
120+
std::size_t len)
121+
{
122+
// empty strings are stored as nullptr
123+
if(len)
124+
construct(str, len);
125+
}
126+
127+
/** Constructor.
128+
129+
This function constructs a new string from
130+
the buffer pointed to by `sv`.
131+
132+
@param sv The string to construct with.
92133
A copy of this string is made.
93134
*/
94-
String(std::string_view s);
135+
String(std::string_view sv)
136+
: String(sv.data(), sv.size())
137+
{
138+
}
95139

96140
/** Constructor.
97141
@@ -107,25 +151,19 @@ class MRDOX_DECL
107151
{
108152
}
109153

110-
/** Constructor.
111-
112-
This function constructs a string literal
113-
which references the buffer pointed to by
114-
sz. Ownership is not transferred; the lifetime
115-
of the buffer must extend until the string is
116-
destroyed, otherwise the behavior is undefined.
154+
/** Assignment.
117155
118-
@param psz A null-terminated string. If the
119-
string is not null-terminated, the result is
120-
undefined.
156+
This acquires shared ownership of the
157+
string referenced by other. Ownership of
158+
the previously referenced string is released.
121159
*/
122-
template<std::size_t N>
123-
constexpr String(char const(&psz)[N]) noexcept
124-
: len_(len(N-1))
125-
, psz_(psz)
160+
String&
161+
operator=(
162+
const String& other) noexcept
126163
{
127-
static_assert(N > 0);
128-
static_assert(N <= std::size_t(-1)>>1);
164+
String temp(other);
165+
swap(temp);
166+
return *this;
129167
}
130168

131169
/** Assignment.
@@ -136,33 +174,29 @@ class MRDOX_DECL
136174
After the assignment, the moved-from string
137175
behaves as if default constructed.
138176
*/
139-
String& operator=(String&& other) noexcept;
140-
141-
/** Assignment.
142-
143-
This acquires shared ownership of the
144-
string referenced by other. Ownership of
145-
the previously referenced string is released.
146-
*/
147-
String& operator=(String const& other) noexcept;
148-
149-
/** Return true if the string is empty.
150-
*/
151-
constexpr bool empty() const noexcept
177+
String&
178+
operator=(
179+
String&& other) noexcept
152180
{
153-
return psz_[0] == '\0';
181+
String temp(std::move(other));
182+
swap(temp);
183+
return *this;
154184
}
155185

156186
/** Return the string.
157187
*/
158-
std::string_view
159-
get() const noexcept;
188+
operator std::string_view() const noexcept
189+
{
190+
return get();
191+
}
160192

161193
/** Return the string.
162194
*/
163-
operator std::string_view() const noexcept
195+
std::string_view
196+
get() const noexcept
164197
{
165-
return get();
198+
return std::string_view(
199+
data(), size());
166200
}
167201

168202
/** Return the string.
@@ -172,19 +206,24 @@ class MRDOX_DECL
172206
return std::string(get());
173207
}
174208

175-
/** Return the size.
209+
/** Return true if the string is empty.
176210
*/
177-
std::size_t size() const noexcept
211+
bool
212+
empty() const noexcept
178213
{
179-
return get().size();
214+
return ! ptr_;
180215
}
181216

182217
/** Return the size.
183218
*/
184-
char const* data() const noexcept
185-
{
186-
return get().data();
187-
}
219+
std::size_t size() const noexcept;
220+
221+
/** Return the string.
222+
223+
The pointed-to character buffer returned
224+
by this function is always null-terminated.
225+
*/
226+
const char* data() const noexcept;
188227

189228
/** Return the string.
190229
@@ -193,20 +232,26 @@ class MRDOX_DECL
193232
*/
194233
char const* c_str() const noexcept
195234
{
196-
return psz_;
235+
return data();
197236
}
198237

199238
/** Swap two strings.
200239
*/
201-
void swap(String& other) noexcept
240+
constexpr
241+
void
242+
swap(String& other) noexcept
202243
{
203-
std::swap(impl_, other.impl_);
204-
std::swap(psz_, other.psz_);
244+
std::swap(ptr_, other.ptr_);
205245
}
206246

207247
/** Swap two strings.
208248
*/
209-
friend void swap(String& lhs, String& rhs) noexcept
249+
friend
250+
constexpr
251+
void
252+
swap(
253+
String& lhs,
254+
String& rhs) noexcept
210255
{
211256
lhs.swap(rhs);
212257
}

0 commit comments

Comments
 (0)