Skip to content

Commit fc8f00d

Browse files
Merge pull request #405 from LASTRADA-Software/string/same_interface
Make Fixed and Dynamic string provide same interface
2 parents 54c337f + 79f64f5 commit fc8f00d

File tree

5 files changed

+191
-45
lines changed

5 files changed

+191
-45
lines changed

.github/workflows/build.yml

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,20 @@ jobs:
3535
name: "Check PR-TODOs"
3636
runs-on: ubuntu-24.04
3737
steps:
38-
- uses: actions/checkout@v4
38+
- uses: actions/checkout@v6
3939
- name: "Checking for open PR-related TODO items"
4040
run: ./scripts/check-pr-todos.sh
4141

4242
check_clang_format:
4343
name: "Check C++ style"
4444
runs-on: ubuntu-24.04
4545
steps:
46-
- uses: actions/checkout@v4
46+
- uses: actions/checkout@v2
4747
with:
4848
persist-credentials: true
4949
repository: ${{ github.event.pull_request.head.repo.full_name }}
5050
ref: ${{ github.event.pull_request.head.ref }}
51-
token: ${{ secrets.CLANG_FORMAT_PAT }}
51+
# token: ${{ secrets.CLANG_FORMAT_PAT }}
5252
- uses: DoozyX/clang-format-lint-action@v0.20
5353
with:
5454
source: '.'
@@ -57,18 +57,19 @@ jobs:
5757
clangFormatVersion: 20
5858
style: file
5959
inplace: True
60-
- uses: EndBug/add-and-commit@v9
61-
if: github.event.pull_request.head.repo.full_name == github.repository
62-
with:
63-
message: 'Committing clang-format changes'
64-
default_author: github_actions
60+
# does not work for now
61+
# - uses: EndBug/add-and-commit@v9
62+
# if: github.event.pull_request.head.repo.full_name == github.repository
63+
# with:
64+
# message: 'Committing clang-format changes'
65+
# default_author: github_actions
6566

6667
check_clang_tidy:
6768
name: "Check clang-tidy"
6869
runs-on: ubuntu-24.04
6970
if: github.ref != 'refs/heads/master'
7071
steps:
71-
- uses: actions/checkout@v4
72+
- uses: actions/checkout@v6
7273
- name: Fetch tags
7374
run: git fetch --prune --unshallow --tags
7475
- name: ccache
@@ -110,7 +111,7 @@ jobs:
110111
name: "Windows-${{ matrix.preset }}"
111112
runs-on: windows-2025
112113
steps:
113-
- uses: actions/checkout@v4
114+
- uses: actions/checkout@v6
114115
- name: Fetch tags
115116
run: git fetch --prune --unshallow --tags
116117
- name: Run sccache-cache
@@ -164,7 +165,7 @@ jobs:
164165
outputs:
165166
id: "${{ matrix.compiler }} (C++${{ matrix.cxx }}, ${{ matrix.build_type }})"
166167
steps:
167-
- uses: actions/checkout@v4
168+
- uses: actions/checkout@v6
168169
- name: Fetch tags
169170
run: git fetch --prune --unshallow --tags
170171
- name: ccache
@@ -251,7 +252,7 @@ jobs:
251252
name: "C++26 reflection implementation"
252253
runs-on: ubuntu-latest
253254
steps:
254-
- uses: actions/checkout@v4
255+
- uses: actions/checkout@v6
255256
- name: Set up QEMU
256257
uses: docker/setup-qemu-action@v2
257258
with:
@@ -274,7 +275,7 @@ jobs:
274275
runs-on: ubuntu-24.04
275276
needs: [ubuntu_build_cc_matrix]
276277
steps:
277-
- uses: actions/checkout@v4
278+
- uses: actions/checkout@v6
278279
- name: Fetch tags
279280
run: git fetch --prune --unshallow --tags
280281
- name: "Download binaries"
@@ -323,7 +324,7 @@ jobs:
323324
env:
324325
DBMS: "${{ matrix.database }}"
325326
steps:
326-
- uses: actions/checkout@v4
327+
- uses: actions/checkout@v6
327328
- name: "Download unit test binaries"
328329
uses: actions/download-artifact@v4
329330
with:

src/Lightweight/DataBinder/SqlDynamicString.hpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "../SqlColumnTypeDefinitions.hpp"
66
#include "../Utils.hpp"
77
#include "Core.hpp"
8+
#include "StringInterface.hpp"
89
#include "UnicodeConverter.hpp"
910

1011
#include <format>
@@ -28,6 +29,10 @@ class SqlDynamicString
2829
static constexpr std::size_t DynamicCapacity = N;
2930
using value_type = T;
3031
using string_type = std::basic_string<T>;
32+
using iterator = string_type::iterator;
33+
using const_iterator = string_type::const_iterator;
34+
using pointer_type = T*;
35+
using const_pointer_type = T const*;
3136

3237
/// Constructs a fixed-size string from a string literal.
3338
template <std::size_t SourceSize>
@@ -122,12 +127,55 @@ class SqlDynamicString
122127
_value.clear();
123128
}
124129

130+
LIGHTWEIGHT_FORCE_INLINE void reserve(std::size_t capacity)
131+
{
132+
_value.reserve(capacity);
133+
}
134+
135+
LIGHTWEIGHT_FORCE_INLINE constexpr void push_back(T c) noexcept
136+
{
137+
_value += c;
138+
}
139+
140+
LIGHTWEIGHT_FORCE_INLINE constexpr void pop_back() noexcept
141+
{
142+
_value.pop_back();
143+
}
144+
145+
// NOLINTNEXTLINE(readability-identifier-naming)
146+
LIGHTWEIGHT_FORCE_INLINE void setsize(std::size_t n) noexcept
147+
{
148+
auto const newSize = (std::min) (n, N);
149+
_value.resize(newSize);
150+
}
151+
125152
/// Resizes the string.
126153
LIGHTWEIGHT_FORCE_INLINE constexpr void resize(std::size_t n) noexcept
127154
{
128155
_value.resize(n);
129156
}
130157

158+
/// Retrieves a string view of the string.
159+
[[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr std::basic_string_view<T> substr(
160+
std::size_t offset = 0, std::size_t count = (std::numeric_limits<std::size_t>::max)()) const noexcept
161+
{
162+
if (count != (std::numeric_limits<std::size_t>::max)())
163+
{
164+
return _value.substr(offset, count);
165+
}
166+
return _value.substr(offset);
167+
}
168+
169+
[[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr string_type ToString() const noexcept
170+
{
171+
return _value;
172+
}
173+
174+
[[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr explicit operator std::basic_string<T>() const noexcept
175+
{
176+
return ToString();
177+
}
178+
131179
/// Retrieves a string view of the string.
132180
[[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr std::basic_string_view<T> ToStringView() const noexcept
133181
{
@@ -177,10 +225,32 @@ class SqlDynamicString
177225
return !(*this == other);
178226
}
179227

228+
[[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr iterator begin() noexcept
229+
{
230+
return _value.begin();
231+
}
232+
233+
[[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr iterator end() noexcept
234+
{
235+
return _value.end();
236+
}
237+
238+
[[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr const_iterator begin() const noexcept
239+
{
240+
return _value.begin();
241+
}
242+
243+
[[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr const_iterator end() const noexcept
244+
{
245+
return _value.end();
246+
}
247+
180248
private:
181249
string_type _value;
182250
};
183251

252+
static_assert(SqlStringInterface<SqlDynamicString<10>>);
253+
184254
template <std::size_t N, typename CharT>
185255
struct detail::SqlViewHelper<SqlDynamicString<N, CharT>>
186256
{

src/Lightweight/DataBinder/SqlFixedString.hpp

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "../SqlColumnTypeDefinitions.hpp"
66
#include "Core.hpp"
77
#include "UnicodeConverter.hpp"
8+
#include "StringInterface.hpp"
89

910
#include <format>
1011
#include <ranges>
@@ -138,21 +139,21 @@ class SqlFixedString
138139
_size = 0;
139140
}
140141

141-
/// Assigns a string literal to the string.
142-
template <std::size_t SourceSize>
143-
LIGHTWEIGHT_FORCE_INLINE constexpr void assign(T const (&source)[SourceSize]) noexcept
144-
{
145-
static_assert(SourceSize <= N + 1, "Source string must not overflow the target string's capacity.");
146-
_size = SourceSize - 1;
147-
std::copy_n(source, SourceSize, _data);
148-
}
142+
// /// Assigns a string literal to the string.
143+
// template <std::size_t SourceSize>
144+
// LIGHTWEIGHT_FORCE_INLINE constexpr void assign(T const (&source)[SourceSize]) noexcept
145+
// {
146+
// static_assert(SourceSize <= N + 1, "Source string must not overflow the target string's capacity.");
147+
// _size = SourceSize - 1;
148+
// std::copy_n(source, SourceSize, _data);
149+
// }
149150

150-
/// Assigns a string view to the string.
151-
LIGHTWEIGHT_FORCE_INLINE constexpr void assign(std::basic_string_view<T> s) noexcept
152-
{
153-
_size = (std::min) (N, s.size());
154-
std::copy_n(s.data(), _size, _data); // NOLINT(bugprone-suspicious-stringview-data-usage)
155-
}
151+
// /// Assigns a string view to the string.
152+
// LIGHTWEIGHT_FORCE_INLINE constexpr void assign(std::basic_string_view<T> s) noexcept
153+
// {
154+
// _size = (std::min) (N, s.size());
155+
// std::copy_n(s.data(), _size, _data); // NOLINT(bugprone-suspicious-stringview-data-usage)
156+
// }
156157

157158
/// Appends a character to the string.
158159
LIGHTWEIGHT_FORCE_INLINE constexpr void push_back(T c) noexcept
@@ -191,18 +192,15 @@ class SqlFixedString
191192
}
192193

193194
// clang-format off
194-
[[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr pointer_type c_str() noexcept { _data[_size] = '\0'; return _data; }
195195
[[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr pointer_type data() noexcept { return _data; }
196196
[[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr iterator begin() noexcept { return _data; }
197197
[[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr iterator end() noexcept { return _data + size(); }
198-
[[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr T& at(std::size_t i) noexcept { return _data[i]; }
199198
[[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr T& operator[](std::size_t i) noexcept { return _data[i]; }
200199

201200
[[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr const_pointer_type c_str() const noexcept { return _data; }
202201
[[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr const_pointer_type data() const noexcept { return _data; }
203202
[[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr const_iterator begin() const noexcept { return _data; }
204203
[[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr const_iterator end() const noexcept { return _data + size(); }
205-
[[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr T const& at(std::size_t i) const noexcept { return _data[i]; }
206204
[[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr T const& operator[](std::size_t i) const noexcept { return _data[i]; }
207205
// clang-format on
208206

@@ -266,6 +264,8 @@ class SqlFixedString
266264
}
267265
};
268266

267+
static_assert(SqlStringInterface<SqlFixedString<10>>);
268+
269269
template <std::size_t N, typename CharT, SqlFixedStringMode Mode>
270270
struct detail::SqlViewHelper<SqlFixedString<N, CharT, Mode>>
271271
{
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#pragma once
2+
#include <concepts>
3+
#include <string>
4+
5+
template <typename S>
6+
concept SqlStringInterface =
7+
requires(S s,
8+
S const cs,
9+
std::size_t n,
10+
S::value_type ch,
11+
std::basic_string_view<typename S::value_type> sv)
12+
{
13+
/* =========================
14+
Associated types
15+
========================= */
16+
typename S::value_type;
17+
typename S::iterator;
18+
typename S::const_iterator;
19+
typename S::pointer_type;
20+
typename S::const_pointer_type;
21+
22+
/* =========================
23+
Construction
24+
========================= */
25+
std::is_default_constructible_v<S>;
26+
std::is_copy_constructible_v<S>;
27+
std::is_move_constructible_v<S>;
28+
29+
/* =========================
30+
Capacity & size
31+
========================= */
32+
{ cs.size() } -> std::same_as<std::size_t>;
33+
{ cs.capacity() } -> std::same_as<std::size_t>;
34+
{ cs.empty() } -> std::same_as<bool>;
35+
36+
/* =========================
37+
Modifiers
38+
========================= */
39+
{ s.clear() } -> std::same_as<void>;
40+
{ s.resize(n) } -> std::same_as<void>;
41+
{ s.setsize(n) } -> std::same_as<void>;
42+
{ s.reserve(n) } -> std::same_as<void>;
43+
44+
{ s.push_back(ch) } -> std::same_as<void>;
45+
{ s.pop_back() } -> std::same_as<void>;
46+
47+
/* =========================
48+
Element access
49+
========================= */
50+
{ s[n] } -> std::same_as<typename S::value_type&>;
51+
{ cs[n] } -> std::same_as<typename S::value_type const&>;
52+
53+
/* =========================
54+
Iterators & data
55+
========================= */
56+
{ s.begin() } -> std::same_as<typename S::iterator>;
57+
{ s.end() } -> std::same_as<typename S::iterator>;
58+
{ cs.begin() } -> std::same_as<typename S::const_iterator>;
59+
{ cs.end() } -> std::same_as<typename S::const_iterator>;
60+
61+
{ s.data() } -> std::same_as<typename S::pointer_type>;
62+
{ cs.data() } -> std::same_as<typename S::const_pointer_type>;
63+
{ s.c_str() } -> std::same_as<typename S::const_pointer_type>;
64+
{ cs.c_str() } -> std::same_as<typename S::const_pointer_type>;
65+
66+
/* =========================
67+
String views & conversions
68+
========================= */
69+
{ cs.substr() } ->
70+
std::same_as<std::basic_string_view<typename S::value_type>>;
71+
72+
{ cs.str() } ->
73+
std::same_as<std::basic_string_view<typename S::value_type>>;
74+
75+
{ cs.ToString() } ->
76+
std::same_as<std::basic_string<typename S::value_type>>;
77+
78+
{ cs.ToStringView() } ->
79+
std::same_as<std::basic_string_view<typename S::value_type>>;
80+
81+
static_cast<std::basic_string<typename S::value_type>>(cs);
82+
static_cast<std::basic_string_view<typename S::value_type>>(cs);
83+
84+
/* =========================
85+
Comparisons
86+
========================= */
87+
{ cs == sv } -> std::same_as<bool>;
88+
{ cs != sv } -> std::same_as<bool>;
89+
};

src/tests/DataBinderTests.cpp

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -157,20 +157,6 @@ TEST_CASE_METHOD(SqlTestFixture, "SqlFixedString: push_back and pop_back", "[Sql
157157
REQUIRE(str.empty());
158158
}
159159

160-
TEST_CASE_METHOD(SqlTestFixture, "SqlFixedString: assign", "[SqlFixedString]")
161-
{
162-
SqlFixedString<12> str;
163-
str.assign("Hello, World");
164-
REQUIRE(str == "Hello, World");
165-
// str.assign("Hello, World!"); <-- would fail due to static_assert
166-
str.assign("Hello, World!"sv);
167-
REQUIRE(str == "Hello, World");
168-
169-
str = "Something";
170-
REQUIRE(str == "Something");
171-
// str = ("Hello, World!"); // <-- would fail due to static_assert
172-
}
173-
174160
TEST_CASE_METHOD(SqlTestFixture, "SqlFixedString: c_str", "[SqlFixedString]")
175161
{
176162
SqlFixedString<12> str { "Hello, World" };

0 commit comments

Comments
 (0)