Skip to content

Commit

Permalink
Static str (#1605)
Browse files Browse the repository at this point in the history
* prototype

* add static_str support

* add static_str support

* type trait

* namespace detail

* has_data for static_str_t

* meta concept
  • Loading branch information
SlaaneshChosen authored Feb 11, 2025
1 parent 2f9db34 commit 7cf9508
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 2 deletions.
12 changes: 11 additions & 1 deletion include/glaze/core/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,10 +239,20 @@ namespace glz
(!std::same_as<std::nullptr_t, T> && std::constructible_from<std::string_view, std::decay_t<T>>) ||
array_char_t<T>;

template <class T>
concept is_static_string = requires { meta<std::decay_t<T>>::glaze_static_string == true; } || std::decay_t<T>::glaze_static_string == true ;

// this concept requires that T is a writeable string. It can be resized, appended to, or assigned to
template <class T>
concept string_t =
str_t<T> && !string_view_t<T> && (has_assign<T> || (resizable<T> && has_data<T>) || has_append<T>);
str_t<T> && !string_view_t<T> &&
(has_assign<T> || (resizable<T> && has_data<T>) || has_append<T>) && !is_static_string<T>;

// static string; very like `string_t`, but with a fixed max capacity
template <class T>
concept static_string_t =
str_t<T> && !string_view_t<T> &&
(has_assign<T> || (resizable<T> && has_data<T>) || has_append<T>) && is_static_string<T>;

template <class T>
concept char_array_t = str_t<T> && std::is_array_v<std::remove_pointer_t<std::remove_reference_t<T>>>;
Expand Down
9 changes: 8 additions & 1 deletion include/glaze/json/read.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -987,7 +987,7 @@ namespace glz
};

template <class T>
requires(string_view_t<T> || char_array_t<T> || array_char_t<T>)
requires(string_view_t<T> || char_array_t<T> || array_char_t<T> || static_string_t<T>)
struct from<JSON, T>
{
template <auto Opts, class It, class End>
Expand Down Expand Up @@ -1027,6 +1027,13 @@ namespace glz
}
std::memcpy(value.data(), start, n);
value[n] = '\0';
} else if constexpr (static_string_t<T>) {
const size_t n = it - start;
if (n > value.size()) {
ctx.error = error_code::unexpected_end;
return;
}
value.assign(start, n);
}
++it; // skip closing quote
GLZ_VALID_END();
Expand Down
62 changes: 62 additions & 0 deletions tests/json_test/json_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9740,6 +9740,68 @@ suite array_char_tests = [] {
};
};

template <size_t N>
struct naive_static_string_t
{
using value_type = char;
using size_type = size_t;


naive_static_string_t() = default;
naive_static_string_t(std::string_view sv) { assign(sv.data(), sv.size()); }
operator std::string_view() const { return std::string_view(buffer, length); }

size_t size() const { return N; }
size_t capacity() const { return N; }
const char* data() const { return buffer; }

naive_static_string_t& assign(const char* v, size_t sz)
{
const auto bytes_to_copy = std::min(N, sz);
length = bytes_to_copy;
memcpy(buffer, v, bytes_to_copy);
return *this;
}

void resize(size_t sz)
{
const auto bytes_to_keep = std::min(N, sz);
length = bytes_to_keep;
}

size_t length{};
char buffer[N]{};
};

template <size_t N>
struct glz::meta<naive_static_string_t<N>> {
static constexpr auto glaze_static_string = true;
};

static_assert(std::constructible_from<std::string_view, std::decay_t<naive_static_string_t<3>>>);
static_assert(glz::detail::has_assign<naive_static_string_t<3>>);
static_assert(glz::detail::is_static_string<naive_static_string_t<3>>);
static_assert(glz::detail::static_string_t<naive_static_string_t<3>>);

suite static_string_tests = [] {
"static_str<N> value"_test = [] {
naive_static_string_t<6> value{};
expect(not glz::read_json(value, R"("hello")"));
expect(std::string_view{value} == "hello");
expect(glz::write_json(value).value_or("error") == R"("hello")");

expect(not glz::read_json(value, R"("hello!")"));
expect(std::string_view{value} == "hello!");
expect(glz::write_json(value).value_or("error") == R"("hello!")");

// too long!!
expect(glz::read_json(value, R"("hello!!")"));

expect(not glz::read_json(value, R"("bye")"));
expect(std::string_view{value} == "bye");
};
};

template <class T>
struct response_t
{
Expand Down

0 comments on commit 7cf9508

Please sign in to comment.