From f71397426bf9c812283b6ea342aaca7019241d62 Mon Sep 17 00:00:00 2001 From: roker Date: Thu, 7 Oct 2021 18:26:18 +0200 Subject: [PATCH] std::basic_string has a FAT interface... I'll forward most of it to the embedded string. --- src/nfc.cc | 19 +++++++++++++ src/nfc.hh | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 99 insertions(+), 2 deletions(-) diff --git a/src/nfc.cc b/src/nfc.cc index 5a04436..3e6879c 100644 --- a/src/nfc.cc +++ b/src/nfc.cc @@ -554,6 +554,25 @@ std::u32string createNFC(std::u32string nfd) } +template<> +IsNFC UTF::isNFC(char c) +{ + if( c & 0x80 ) + throw illegal_utf("Single octet >0x80 is invalid UTF-8"); + + return IsNFC::Yes; // all ASCII characters are valid NFC. +} + + +template<> +IsNFC UTF::isNFC(char16_t c) +{ + if(NFC_No.count(c)) return IsNFC::No; + if(NFC_Maybe.count(c)) return IsNFC::Maybe; + return IsNFC::Yes; +} + + template IsNFC UTF::isNFC_quick_check(std::basic_string_view s) { diff --git a/src/nfc.hh b/src/nfc.hh index 93cfece..3139c3f 100644 --- a/src/nfc.hh +++ b/src/nfc.hh @@ -27,7 +27,6 @@ class illegal_utf : public std::runtime_error public: illegal_utf( std::string_view, unsigned position, const std::string& reason); illegal_utf(std::u16string_view, unsigned position, const std::string& reason); -protected: explicit illegal_utf(const std::string& message); }; @@ -48,7 +47,11 @@ public: void generate(const char32_t c, OutIter& out); - /// return No or Maybe, if at least one character with NFC_Quickcheck class is "No" or "Maybe" + /// returns the NFC class of a single character + static + IsNFC isNFC(CharT c); + + /// returns No or Maybe, if at least one character with NFC_Quickcheck class is "No" or "Maybe" /// might throw illegal_utf exception static IsNFC isNFC_quick_check(std::basic_string_view s); @@ -92,6 +95,8 @@ public: /// only forward iterator. Does a backward_iterator make sense in UTF-encoded strings? typedef typename String::const_iterator const_iterator; + static const size_t npos = String::npos; + explicit nfc_string(StringView src); explicit nfc_string(String && src); @@ -126,13 +131,86 @@ public: std::size_t size() const noexcept { return s.size(); } bool empty() const noexcept { return s.empty(); } + std::size_t capacity() const noexcept { return s.capacity(); } + void reserve(std::size_t new_capacity) { s.reserve(new_capacity); } + void shrink_to_fit() { s.shrink_to_fit(); } + + const_reference operator[](std::size_t ofs) const noexcept { return s[ofs]; } + const_reference at(std::size_t ofs) const { return s.at(ofs); } + const_reference front() const noexcept { return s.front(); } + const_reference back() const noexcept { return s.back(); } + operator StringView() const noexcept { return StringView{s}; } + const_iterator begin() const noexcept { return s.cbegin(); } const_iterator cbegin() const noexcept { return s.cbegin(); } /// r/o access only const_iterator end() const noexcept { return s.cend(); } const_iterator cend() const noexcept { return s.cend(); } /// r/o access only + void clear() { s.clear(); } + + /// I am lazy and delegate all the 10 different insert() overloads directly to s. + template + nfc_string& insert(Args&& ...args) + { + s.insert( std::forward(args)... ); + normalize(); + return *this; + } + + /// delegates all erase() overloads to s. + template + nfc_string& erase(Args&& ...args) + { + s.erase( std::forward(args)... ); + normalize(); + return *this; + } + + nfc_string& push_back(CharT c); + + /// delegates all 9 append() overloads to s. + template + nfc_string& append(Args&& ...args) + { + s.append( std::forward(args)... ); + normalize(); + return *this; + } + + nfc_string& operator+=(const StringView& s); + + /// optimization possible to avoid re-normalization in most cases. + nfc_string& operator+=(const nfc_string& s); + + /// optimization possible to avoid re-normalization in most cases. + nfc_string& operator+=(CharT c); + + /// delegates all 9 compare() overloads to s + template + int compare(Args&& ...args) const + { + return s.compare( std::forward(args)... ); + } + + /// stolen from C++20 + bool starts_with(StringView s) const; + + /// stolen from C++20 + bool ends_with(StringView s) const; + + /// delegates all 5 find() overloads to s + template + std::size_t find(Args&& ...args) const + { + return s.find( std::forward(args)... ); + } + + private: std::basic_string s; + + /// (re-)normalize the content string s. + void normalize(); }; };