diff --git a/src/nfc.cc b/src/nfc.cc index ae75d4b..61f2925 100644 --- a/src/nfc.cc +++ b/src/nfc.cc @@ -683,6 +683,12 @@ size_t UTF::utf_length(std::u32string_view s) } +template +UTF::nfc_string::nfc_string(std::basic_string_view src) +: s{ UTF::toNFC(src) } +{} + + // convenience function to avoid ::strdup(pEp::toNFC(text).c_str()); // and unecessary temporary std::string etc. char* strdup_NFC(std::string_view s) diff --git a/src/nfc.hh b/src/nfc.hh index 2d94976..f52fb2a 100644 --- a/src/nfc.hh +++ b/src/nfc.hh @@ -75,11 +75,63 @@ public: /// creates an NFD u32string from UTF-8/UTF-16 input string s static std::u32string fromUtf_decompose(std::basic_string_view s); + + + /// class holding a NFC-conform Unicode string. + /// content is mostly read-only, because arbitrary modifications might destroy NFC conformacy. + class nfc_string + { + public: + typedef std::basic_string String; + + /// only const_reference is supported. + typedef typename String::const_reference const_reference; + typedef typename String::const_pointer const_pointer; + + /// only forward iterator. Does a backward_iterator make sense in UTF-encoded strings? + typedef typename String::const_iterator const_iterator; + + + explicit nfc_string(std::basic_string_view src); + explicit nfc_string(std::basic_string && src); + + /// construct from a NUL-terminated src + explicit nfc_string(const CharT* src); + + nfc_string(const CharT* src, size_t length); + + nfc_string(const nfc_string& src) = default; + nfc_string( nfc_string&& src) = default; + + nfc_string& operator=(const nfc_string& src) = default; + nfc_string& operator=( nfc_string&& src) = default; + + nfc_string& assign(String&& src); + nfc_string& assign(std::basic_string_view src); + + + /// read-only: shares representation + operator const String&() const noexcept { return s; } + + /// read write: copy content + operator String() const { return s; } + + const CharT* c_str() const noexcept { return s.c_str(); } + const CharT* data() const noexcept { return s.data(); } + std::size_t size() const noexcept { return s.size(); } + bool empty() const noexcept { return s.empty(); } + + private: + std::basic_string s; + }; }; +/// convenient alias names: using UTF8 = UTF; using UTF16 = UTF; +using nfc_string = UTF8::nfc_string; +using nfc_u16string = UTF16::nfc_string; // throws illegal_utf8 exception if s is not valid UTF-8 void assert_utf8(std::string_view s);