Win some, lose some

Seeing recent LibreOffice commit static const to avoid re-init all the time + c++11 got me thinking. (What the code does is check whether a given rtl::OUString instance is among a statically known sequence of strings.) Clearly we can do even better. (Even ignoring the question whether std::binary_search on a sorted sequence would do a better job here than std::find on an unordered one.)

For one, a std::initializer_list provides all the functionality requested here, and is more obviously reduced by compilers than a std::vector. (Except when the compiler has a bug, Properly check for Clang with static initializer_list bug.)

For another, a rtl::OUStringLiteral is a trivial wrapper around a string literal and its length. So if we allow for comparison between rtl::OUString and rtl::OUStringLiteral, and make the latter’s constructor constexpr (which is still not available with MSVC&nbps;2013, though), the sequence of strings can be fully built into the data section at compile time. Make OUStringLiteral more useful.

(A remaining question is whether it would be better here to use a variant of rtl::OUStringLiteral that operates on char16_t rather than ordinary string literals. The advantages would be using simpler comparison code and no requirement for the sequence of strings to be ASCII-only. The disadvantages would be a bigger data section and the sad fact that MSVC 2013, while knowing char16_t, still does not understand u"..." syntax.)

However, how much “better” is that, actually? Pointers in compile-time data (as are utilized by rtl::OUStringLiteral) require load-time fixups (in relocatable load-objects). So they would ideally be avoided.

One trick, at least for a sequence of strings of fairly equal length, would be to use a std::initializer_list of fixed-size buffers like

template<std::size_t M> struct FixedSizeLiteral {
    template<std::size_t N> constexpr FixedSizeLiteral(char const (&s)[N]):
        string_(s), length_(N - 1) {}
    char string_[M];
    std::size_t length_;

where M would need to be computed at compile time. But that would require turning the sequence of string literals into a template parameter pack, and string literals are not allowed as template arguments.

Another trick would be to replace the pointer stored in rtl::OUStringLiteral with an offset, but generating that data structure at compile time looks like it would also be beyond the capabilities of today’s C++.

As always, no silver bullet.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s