Skip to content

Commit 04fc1dd

Browse files
committed
chore: length for dom::String literals
1 parent 09854bc commit 04fc1dd

File tree

2 files changed

+51
-29
lines changed

2 files changed

+51
-29
lines changed

include/mrdox/Support/Dom.hpp

+29-6
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,26 @@ class MRDOX_DECL
6868
{
6969
struct Impl;
7070

71-
Impl* impl_ = nullptr;
72-
char const* psz_ = nullptr;
71+
union
72+
{
73+
Impl* impl_;
74+
// len is stored with the low bit moved to
75+
// the hi bit, and the low bit always set.
76+
std::size_t len_;
77+
};
78+
char const* psz_;
7379

74-
static Impl* allocate(std::string_view s);
80+
static void allocate(std::string_view s,Impl*&, char const*&);
7581
static void deallocate(Impl*) noexcept;
82+
static consteval std::size_t len(std::size_t n)
83+
{
84+
return (n << (sizeof(std::size_t)*8 - 1)) | n | 1UL;
85+
}
86+
87+
constexpr bool is_literal() const noexcept
88+
{
89+
return (len_ & 1) != 0;
90+
}
7691

7792
public:
7893
/** Destructor.
@@ -139,9 +154,11 @@ class MRDOX_DECL
139154
*/
140155
template<std::size_t N>
141156
constexpr String(char const(&psz)[N]) noexcept
142-
: psz_(psz)
157+
: len_(len(N-1))
158+
, psz_(psz)
143159
{
144160
static_assert(N > 0);
161+
static_assert(N <= std::size_t(-1)>>1);
145162
}
146163

147164
/** Assignment.
@@ -164,7 +181,10 @@ class MRDOX_DECL
164181

165182
/** Return true if the string is empty.
166183
*/
167-
bool empty() const noexcept;
184+
constexpr bool empty() const noexcept
185+
{
186+
return psz_[0] == '\0';
187+
}
168188

169189
/** Return the string.
170190
*/
@@ -204,7 +224,10 @@ class MRDOX_DECL
204224
The pointed-to character buffer returned
205225
by this function is always null-terminated.
206226
*/
207-
char const* c_str() const noexcept;
227+
char const* c_str() const noexcept
228+
{
229+
return psz_;
230+
}
208231

209232
/** Swap two strings.
210233
*/

lib/Support/Dom.cpp

+22-23
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ class varint
9494
}
9595
};
9696

97-
static constinit char sz_empty[1] = { '\0' };
97+
static constinit char sz_empty = { '\0' };
9898

9999
} // (anon)
100100

@@ -130,21 +130,24 @@ struct String::Impl
130130
}
131131
};
132132

133-
auto
133+
void
134134
String::
135135
allocate(
136-
std::string_view s) ->
137-
Impl*
136+
std::string_view s,
137+
Impl*& impl,
138+
char const*& psz)
138139
{
139140
std::allocator<Impl> alloc;
140-
varint<std::size_t> uv(s.size());
141+
varint<std::size_t> uv(s.size());
142+
auto const varlen = uv.get().size();
141143
auto n =
142144
sizeof(Impl) + // header
143-
uv.get().size() + // size (varint)
145+
varlen + // size (varint)
144146
s.size() + // string data
145147
1 + // null term '\0'
146148
(sizeof(Impl) - 1); // round up to nearest sizeof(Impl)
147-
return new(alloc.allocate(n / sizeof(Impl))) Impl(s, uv);
149+
impl = new(alloc.allocate(n / sizeof(Impl))) Impl(s, uv);
150+
psz = reinterpret_cast<char const*>(impl + 1) + varlen;
148151
}
149152

150153
void
@@ -155,9 +158,10 @@ deallocate(
155158
std::allocator<Impl> alloc;
156159
auto const s = impl->get();
157160
varint<std::size_t> uv(s.size());
161+
auto const varlen = uv.get().size();
158162
auto n =
159163
sizeof(Impl) + // header
160-
uv.get().size() + // size (varint)
164+
varlen + // size (varint)
161165
s.size() + // string data
162166
1 + // null term '\0'
163167
(sizeof(Impl) - 1); // round up to nearest sizeof(Impl)
@@ -170,7 +174,7 @@ deallocate(
170174
String::
171175
~String()
172176
{
173-
if(! impl_)
177+
if(is_literal())
174178
return;
175179
if(--impl_->refs > 0)
176180
return;
@@ -179,7 +183,8 @@ String::
179183

180184
String::
181185
String() noexcept
182-
: psz_(&sz_empty[0])
186+
: len_(len(0))
187+
, psz_(&sz_empty)
183188
{
184189
}
185190

@@ -197,15 +202,16 @@ String(
197202
: impl_(other.impl_)
198203
, psz_(other.psz_)
199204
{
200-
if(impl_)
205+
if(! is_literal())
201206
++impl_->refs;
202207
}
203208

204209
String::
205210
String(
206211
std::string_view s)
207-
: impl_(allocate(s))
208212
{
213+
allocate(s, impl_, psz_);
214+
MRDOX_ASSERT(! is_literal());
209215
}
210216

211217
String&
@@ -228,21 +234,14 @@ operator=(
228234
return *this;
229235
}
230236

231-
bool
232-
String::
233-
empty() const noexcept
234-
{
235-
if(impl_)
236-
return impl_->get().size() == 0;
237-
return psz_[0] == '\0';
238-
}
239-
240237
std::string_view
241238
String::
242239
get() const noexcept
243240
{
244-
if(psz_)
245-
return std::string_view(psz_);
241+
if(is_literal())
242+
return std::string_view(psz_,
243+
(len_ & ((std::size_t(-1) >> 1) & ~std::size_t(1))) |
244+
(len_ >> (sizeof(std::size_t)*8 - 1)));
246245
return impl_->get();
247246
}
248247

0 commit comments

Comments
 (0)