diff options
author | Noel Grandin <noel.grandin@collabora.co.uk> | 2021-04-19 11:41:47 +0200 |
---|---|---|
committer | Noel Grandin <noel.grandin@collabora.co.uk> | 2021-04-20 15:30:50 +0200 |
commit | 21584b304b21bfe6b99b6f29018c6b754ea28fc0 (patch) | |
tree | 34dad49f040259e005422902b10cf1d8d9b81096 /include | |
parent | 0ae159cc40b837a6a47acaf9240dc350fe68d49d (diff) |
make OUString(OUStringLiteral) constructor constexpr
with the intent that we can declare
static const OUStringLiteral FOO = "bar";
static const struct {
OUString s;
} xxx = { FOO };
and have the xxx laid out at compile time.
Kudos to mikekaganski for coming up with the idea of using
the rtl_uString struct inside OUStringLiteral.
We are using a union to defeat the array bounds checking
that the compiler does when it evaluates constexpr values,
so this might be brittle.
Change-Id: I9a6247a17afab2eb28df139d532a8d864c49cd62
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/114196
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'include')
-rw-r--r-- | include/rtl/ustring.hxx | 52 |
1 files changed, 31 insertions, 21 deletions
diff --git a/include/rtl/ustring.hxx b/include/rtl/ustring.hxx index bb3390c19985..e1ae2d38f2d9 100644 --- a/include/rtl/ustring.hxx +++ b/include/rtl/ustring.hxx @@ -83,6 +83,7 @@ This class is not part of public API and is meant to be used only in LibreOffice template<std::size_t N> class SAL_WARN_UNUSED OUStringLiteral { static_assert(N != 0); static_assert(N - 1 <= std::numeric_limits<sal_Int32>::max(), "literal too long"); + friend class OUString; public: #if HAVE_CPP_CONSTEVAL @@ -95,35 +96,44 @@ public: assert(literal[N - 1] == '\0'); //TODO: Use C++20 constexpr std::copy_n (P0202R3): for (std::size_t i = 0; i != N; ++i) { - buffer[i] = literal[i]; + more.buffer[i] = literal[i]; } } - constexpr sal_Int32 getLength() const { return length; } + constexpr sal_Int32 getLength() const { return more.length; } - constexpr sal_Unicode const * getStr() const SAL_RETURNS_NONNULL { return buffer; } + constexpr sal_Unicode const * getStr() const SAL_RETURNS_NONNULL { return more.buffer; } - constexpr operator std::u16string_view() const { return {buffer, sal_uInt32(length)}; } + constexpr operator std::u16string_view() const { return {more.buffer, sal_uInt32(more.length)}; } private: static constexpr void assertLayout() { // These static_asserts verifying the layout compatibility with rtl_uString cannot be class // member declarations, as offsetof requires a complete type, so defer them to here: - static_assert(offsetof(OUStringLiteral, refCount) == offsetof(rtl_uString, refCount)); - static_assert(std::is_same_v<decltype(refCount), decltype(rtl_uString::refCount)>); - static_assert(offsetof(OUStringLiteral, length) == offsetof(rtl_uString, length)); - static_assert(std::is_same_v<decltype(length), decltype(rtl_uString::length)>); - static_assert(offsetof(OUStringLiteral, buffer) == offsetof(rtl_uString, buffer)); - static_assert( - std::is_same_v< - std::remove_extent_t<decltype(buffer)>, - std::remove_extent_t<decltype(rtl_uString::buffer)>>); - } - - // Same layout as rtl_uString (include/rtl/ustring.h): - oslInterlockedCount refCount = 0x40000000; // SAL_STRING_STATIC_FLAG (sal/rtl/strimp.hxx) - sal_Int32 length = N - 1; - sal_Unicode buffer[N] = {}; //TODO: drop initialization for C++20 (P1331R2) + static_assert(offsetof(OUStringLiteral, str.refCount) == offsetof(OUStringLiteral, more.refCount)); + static_assert(offsetof(OUStringLiteral, str.length) == offsetof(OUStringLiteral, more.length)); + static_assert(offsetof(OUStringLiteral, str.buffer) == offsetof(OUStringLiteral, more.buffer)); + } + +#if defined(_WIN32) +#pragma pack(push, 4) +#endif + union { + rtl_uString str; + struct { + oslInterlockedCount refCount; + sal_Int32 length; + sal_Unicode buffer[N]; + } more = + { + 0x40000000, // SAL_STRING_STATIC_FLAG (sal/rtl/strimp.hxx) + N - 1, + {} //TODO: drop initialization for C++20 (P1331R2) + }; + }; +#if defined(_WIN32) +#pragma pack(pop) +#endif }; #if defined RTL_STRING_UNITTEST @@ -385,8 +395,8 @@ public: @since LibreOffice 5.0 */ - template<std::size_t N> OUString(OUStringLiteral<N> const & literal): - pData(const_cast<rtl_uString *>(reinterpret_cast<rtl_uString const *>(&literal))) {} + template<std::size_t N> constexpr OUString(OUStringLiteral<N> const & literal): + pData(const_cast<rtl_uString *>(&literal.str)) {} template<std::size_t N> OUString(OUStringLiteral<N> &&) = delete; /// @endcond #endif |