@@ -23,6 +23,27 @@ namespace _QxPrivate
2323template <std::integral C>
2424class 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>
100121constexpr 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)
127132template <string_literal S, size_t N2>
128133constexpr 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 */
153144template <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