Skip to content

Commit 63caf8c

Browse files
committed
Completely fix StringLiteral operator+()
1 parent 30ea751 commit 63caf8c

File tree

1 file changed

+27
-33
lines changed

1 file changed

+27
-33
lines changed

lib/utility/include/qx/utility/qx-stringliteral.h

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,27 @@ namespace _QxPrivate
2323
template<std::integral C>
2424
class StringLiteralBase {};
2525

26+
template<typename O, size_t N1, size_t N2>
27+
constexpr auto concatNewStringLiteral(const typename O::data_t (&a)[N1], const typename O::data_t (&b)[N2])
28+
{
29+
using C = typename O::data_t;
30+
constexpr size_t L1 = N1 - 1;
31+
constexpr size_t return_n = N1 + N2 - 1;
32+
using result_t = typename O::template rebind<return_n>;
33+
34+
/* THIS ASSUMES THAT BOTH ARRAYS HAVE NULL TERMINATORS
35+
* Using a buffer here results in needing to copy twice, but is much simpler than
36+
* added a default ctor for each StringLiteral type, constructing, and copying in
37+
* there directly. It's compile time so the inefficiency is basically a non-issue.
38+
* Plus, this won't be an issue anyway once we can switch to aliases for the fixed
39+
* width variants.
40+
*/
41+
C buff[return_n];
42+
std::copy_n(a, L1, buff); // a chars (without '/0')
43+
std::copy_n(b, N2, buff + L1); // b chars (with '/0')
44+
return result_t(buff);
45+
}
46+
2647
}
2748
/*! @endcond */
2849

@@ -99,23 +120,7 @@ template<typename StringLiteralA, typename StringLiteralB>
99120
requires compatible_string_literals<StringLiteralA, StringLiteralB>
100121
constexpr auto operator+(const StringLiteralA& a, const StringLiteralA& b)
101122
{
102-
// It's important to note here than L1 and L2 are sizes without
103-
using C = typename StringLiteralA::data_t;
104-
constexpr size_t L1 = StringLiteralA::size_v;
105-
constexpr size_t L2 = StringLiteralB::size_v;
106-
constexpr size_t R = L1 + L2 +1;
107-
using result_t = typename StringLiteralA::template rebind<R>;
108-
/* Separate buffer is an extra copy, vs just making the result string and copying
109-
* into it directly, but this avoids the cruft of having to make these all friends
110-
* with the class and the speed loss is largely irrelevant since these are used
111-
* at compile time.
112-
*/
113-
114-
115-
C buff[R] ;
116-
std::copy_n(a._str, L1, buff); // a chars
117-
std::copy_n(b._str, L2 + 1, buff + L1); // b chars + '/0'
118-
return result_t(buff);
123+
return _QxPrivate::concatNewStringLiteral<StringLiteralA>(a._str, b._str);
119124
}
120125

121126
// Doc'ed here cause doxygen is finicky
@@ -127,21 +132,7 @@ constexpr auto operator+(const StringLiteralA& a, const StringLiteralA& b)
127132
template<string_literal S, size_t N2>
128133
constexpr auto operator+(const S& a, const typename S::data_t (&b)[N2])
129134
{
130-
// It's important to note here than N2 is a size including '/0' and L1 is a size without '/0'
131-
using C = typename S::data_t;
132-
constexpr size_t L1 = S::size_v;
133-
constexpr size_t R = L1 + N2;
134-
using result_t = typename S::template rebind<R>;
135-
136-
/* Separate buffer is an extra copy, vs just making the result string and copying
137-
* into it directly, but this avoids the cruft of having to make these all friends
138-
* with the class and the speed loss is largely irrelevant since these are used
139-
* at compile time.
140-
*/
141-
C buff[R] ; // a chars + (b chars + '/0')
142-
std::copy_n(a._str, L1, buff); // a chars
143-
std::copy_n(b, N2, buff + L1); // b chars + '/0'
144-
return result_t(buff);
135+
return _QxPrivate::concatNewStringLiteral<S>(a._str, b);
145136
}
146137

147138
// Doc'ed here cause doxygen is finicky
@@ -151,7 +142,10 @@ constexpr auto operator+(const S& a, const typename S::data_t (&b)[N2])
151142
* Returns a string which is the result of concatenating @a a and @a b.
152143
*/
153144
template<size_t N1, string_literal S>
154-
constexpr auto operator+(const typename S::data_t (&a)[N1], const S& b) { return b + a; }
145+
constexpr auto operator+(const typename S::data_t (&a)[N1], const S& b)
146+
{
147+
return _QxPrivate::concatNewStringLiteral<S>(a, b._str);
148+
}
155149

156150
// Doc'ed here cause doxygen is finicky
157151
/*!

0 commit comments

Comments
 (0)