Skip to content

Commit a5eb6c1

Browse files
new interface for static_string::delayed_build()
1 parent 4ce4082 commit a5eb6c1

File tree

4 files changed

+139
-20
lines changed

4 files changed

+139
-20
lines changed

src/mod/rdp/rdp_negociation_data.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,15 @@ RdpLogonInfo::RdpLogonInfo(bounded_chars_view<0, HOST_NAME_MAX> hostname, bool h
3030
char const* target_user, bool split_domain) noexcept
3131
{
3232
if (hide_client_name) {
33-
this->_hostname.delayed_build([](auto& array) {
33+
this->_hostname.delayed_build([](auto buffer) {
34+
auto array = buffer.chars_with_null_terminated();
3435
::gethostname(array.data(), array.size());
3536
array.back() = '\0';
3637
char* separator = strchr(array.data(), '.');
3738
if (!separator) {
38-
return strlen(array.data());
39+
return buffer.compute_strlen();
3940
}
40-
size_t hostlen = checked_int(separator - array.data());
41-
return hostlen;
41+
return buffer.set_end_string_ptr(separator);
4242
});
4343
}
4444
else{

src/utils/ascii.hpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -346,13 +346,12 @@ namespace detail
346346
};
347347

348348
template<class Transform>
349-
constexpr inline std::size_t unsafe_ascii_to(char* dest, chars_view src, Transform&& transform) noexcept
349+
constexpr inline char* unsafe_ascii_to(char* dest, chars_view src, Transform&& transform) noexcept
350350
{
351-
auto* start = dest;
352351
for (char c : src) {
353352
*dest++ = transform(c);
354353
}
355-
return std::size_t(dest - start);
354+
return dest;
356355
}
357356
} // namespace detail
358357

@@ -365,7 +364,7 @@ chars_to_tagged_string_array(chars_view str, To&& to)
365364
if (str.size() <= N) {
366365
auto& array = detail::StringAsArrayAccess::internal(upper.str);
367366
auto* p = array.buffer.data();
368-
array.len = detail::unsafe_ascii_to(p, str, to);
367+
array.len = static_cast<std::size_t>(detail::unsafe_ascii_to(p, str, to) - p);
369368
}
370369
return upper;
371370
}
@@ -377,8 +376,9 @@ chars_to_tagged_zstring_array(chars_view str, To&& to)
377376
{
378377
TaggedZStringArray<Tag, N> upper;
379378
if (str.size() <= N) {
380-
upper.str.delayed_build([&](auto& array){
381-
return detail::unsafe_ascii_to(array.data(), str, to);
379+
upper.str.delayed_build([&](auto buffer){
380+
auto* end_ptr = detail::unsafe_ascii_to(buffer.data(), str, to);
381+
return buffer.set_end_string_ptr(end_ptr);
382382
});
383383
}
384384
return upper;

src/utils/static_string.hpp

+74-3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Author(s): Proxies Team
2121
#pragma once
2222

2323
#include "utils/sugar/bounded_array_view.hpp"
24+
#include "utils/sugar/cast.hpp"
2425
#include "utils/traits/is_null_terminated.hpp"
2526
#include "utils/traits/static_array_desc.hpp"
2627
#include "cxx/compiler_version.hpp"
@@ -50,6 +51,76 @@ namespace detail
5051
} // namespace detail
5152

5253

54+
struct delayed_build_string_buffer
55+
{
56+
enum class ResultLen : std::size_t;
57+
58+
delayed_build_string_buffer(writable_chars_view null_terminated_buffer) noexcept
59+
: null_terminated_buffer(null_terminated_buffer)
60+
{
61+
assert(!null_terminated_buffer.empty());
62+
}
63+
64+
writable_chars_view chars_without_null_terminated() noexcept
65+
{
66+
return null_terminated_buffer.drop_back(1);
67+
}
68+
69+
writable_chars_view chars_with_null_terminated() noexcept
70+
{
71+
return null_terminated_buffer;
72+
}
73+
74+
char* data() noexcept
75+
{
76+
return null_terminated_buffer.data();
77+
}
78+
79+
/// Compute len with strlen().
80+
/// \pre buffer is initialized with a valid null terminated c-string
81+
ResultLen compute_strlen() noexcept
82+
{
83+
return ResultLen(strlen(null_terminated_buffer.data()));
84+
}
85+
86+
/// Length of the final string.
87+
/// Null terminated is automatically added.
88+
ResultLen set_string_len(std::size_t len) noexcept
89+
{
90+
assert(len < null_terminated_buffer.size());
91+
null_terminated_buffer[len] = '\0';
92+
return ResultLen(len);
93+
}
94+
95+
/// Position of the final string.
96+
/// Null terminated is automatically added.
97+
ResultLen set_end_string_ptr(char const* end_ptr) noexcept
98+
{
99+
return set_string_len(checked_int(end_ptr - null_terminated_buffer.data()));
100+
}
101+
102+
/// Length of the final buffer (with null terminated character).
103+
/// \param len length with null terminated char
104+
ResultLen set_buffer_len(std::size_t len) noexcept
105+
{
106+
assert(len > 0);
107+
assert(len <= null_terminated_buffer.size());
108+
assert(null_terminated_buffer[len - 1] == '\0');
109+
return ResultLen(len - 1);
110+
}
111+
112+
/// Position of the final buffer (with null terminated character).
113+
/// \param end_ptr position after null terminated char
114+
ResultLen set_end_buffer_ptr(char const* end_ptr) noexcept
115+
{
116+
return set_buffer_len(checked_int(end_ptr - null_terminated_buffer.data()));
117+
}
118+
119+
private:
120+
writable_chars_view null_terminated_buffer;
121+
};
122+
123+
53124
// N = size without null character
54125
template<std::size_t N>
55126
struct static_string
@@ -110,9 +181,9 @@ struct static_string
110181
template<class Builder>
111182
void delayed_build(Builder&& builder)
112183
{
113-
m_len = builder(m_str);
114-
assert(m_len <= max_capacity());
115-
m_str[m_len] = '\0';
184+
auto res = builder(delayed_build_string_buffer(make_writable_array_view(m_str)));
185+
static_assert(std::is_same_v<decltype(res), delayed_build_string_buffer::ResultLen>);
186+
m_len = checked_int(res);
116187
}
117188

118189
static std::size_t max_capacity() noexcept

tests/utils/test_static_string.cpp

+55-7
Original file line numberDiff line numberDiff line change
@@ -63,17 +63,65 @@ RED_AUTO_TEST_CASE(TestStaticString)
6363
s3.clear();
6464
RED_CHECK_EQUAL(s3, ""_av);
6565

66-
s3.delayed_build([](auto& array){
67-
array[0] = 'a';
68-
array[1] = 'b';
69-
array[2] = 'c';
70-
return checked_int(3u);
66+
// set_string_len()
67+
s3.delayed_build([](auto buffer) {
68+
auto array = buffer.chars_without_null_terminated();
69+
std::size_t i = 0;
70+
array[i++] = 'a';
71+
array[i++] = 'b';
72+
array[i++] = 'c';
73+
return buffer.set_string_len(i);
7174
});
7275
RED_CHECK_EQUAL(s3, "abc"_av);
7376

77+
// set_null_terminated_string_len()
78+
s3.delayed_build([](auto buffer) {
79+
auto array = buffer.chars_without_null_terminated();
80+
std::size_t i = 0;
81+
array[i++] = 'x';
82+
array[i++] = 'y';
83+
array[i++] = 'z';
84+
// '\0' is already present
85+
return buffer.compute_strlen();
86+
});
87+
RED_CHECK_EQUAL(s3, "xyz"_av);
88+
89+
// set_end_string_ptr()
90+
s3.delayed_build([](auto buffer) {
91+
auto array = buffer.chars_without_null_terminated().data();
92+
*array++ = 'd';
93+
*array++ = 'e';
94+
return buffer.set_end_string_ptr(array);
95+
});
96+
RED_CHECK_EQUAL(s3, "de"_av);
97+
98+
// set_buffer_len()
99+
s3.delayed_build([](auto buffer) {
100+
auto array = buffer.chars_with_null_terminated();
101+
std::size_t i = 0;
102+
array[i++] = 'f';
103+
array[i++] = 'g';
104+
array[i++] = 'h';
105+
array[i++] = '\0';
106+
return buffer.set_buffer_len(i);
107+
});
108+
RED_CHECK_EQUAL(s3, "fgh"_av);
109+
110+
// set_end_buffer_ptr()
111+
s3.delayed_build([](auto buffer) {
112+
auto array = buffer.chars_with_null_terminated().data();
113+
*array++ = 'i';
114+
*array++ = 'j';
115+
*array++ = '\0';
116+
return buffer.set_end_buffer_ptr(array);
117+
});
118+
RED_CHECK_EQUAL(s3, "ij"_av);
119+
74120
// test that there is no assertion
75-
s3.delayed_build([&](auto&){
76-
return checked_int(s3.max_capacity());
121+
s3.delayed_build([&](auto buffer){
122+
auto array = buffer.chars_with_null_terminated();
123+
memset(array.data(), 0, array.size());
124+
return buffer.set_buffer_len(s3.max_capacity());
77125
});
78126
}
79127

0 commit comments

Comments
 (0)