diff options
author | Brad King <brad.king@kitware.com> | 2018-09-25 23:43:41 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2018-12-12 13:10:15 (GMT) |
commit | ff69763ca08fbd3a9831ec0c8adb32a7111b1a46 (patch) | |
tree | 2ed587456b95ba27ab334a6f19f5703620463736 /Source/cmString.cxx | |
parent | 410a3e4b22c72794d4f96e41c1d37d84d6e7e54d (diff) | |
download | CMake-ff69763ca08fbd3a9831ec0c8adb32a7111b1a46.zip CMake-ff69763ca08fbd3a9831ec0c8adb32a7111b1a46.tar.gz CMake-ff69763ca08fbd3a9831ec0c8adb32a7111b1a46.tar.bz2 |
String: Add a custom string type
Create a `cm::String` type that holds a view of a string buffer and
optionally shares ownership of the buffer. Instances can either
borrow longer-lived storage (e.g. static storage of string literals)
or internally own a `std::string` instance. In the latter case,
share ownership with copies and substrings. Allocate a new internal
string only on operations that require mutation.
This will allow us to recover string sharing semantics that we
used to get from C++98 std::string copy-on-write implementations.
Such implementations are not allowed by C++11 so code our own in
a custom string type instead.
Diffstat (limited to 'Source/cmString.cxx')
-rw-r--r-- | Source/cmString.cxx | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/Source/cmString.cxx b/Source/cmString.cxx new file mode 100644 index 0000000..e965bfb --- /dev/null +++ b/Source/cmString.cxx @@ -0,0 +1,131 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#define _SCL_SECURE_NO_WARNINGS + +#include "cmString.hxx" + +#include <memory> +#include <ostream> +#include <stdexcept> +#include <string> +#include <type_traits> + +namespace cm { + +static std::string const empty_string_; + +void String::internally_mutate_to_stable_string() +{ + // We assume that only one thread mutates this instance at + // a time even if we point to a shared string buffer refernced + // by other threads. + *this = String(data(), size()); +} + +std::string const& String::str() +{ + if (!data()) { + // We view no string. + // This is stable for the lifetime of our current value. + return empty_string_; + } + + if (string_ && data() == string_->data() && size() == string_->size()) { + // We view an entire string. + // This is stable for the lifetime of our current value. + return *string_; + } + + // Mutate to hold a std::string that is stable for the lifetime + // of our current value. + this->internally_mutate_to_stable_string(); + return *string_; +} + +const char* String::c_str() +{ + const char* c = data(); + if (c == nullptr) { + return c; + } + + // We always point into a null-terminated string so it is safe to + // access one past the end. If it is a null byte then we can use + // the pointer directly. + if (c[size()] == '\0') { + return c; + } + + // Mutate to hold a std::string so we can get a null terminator. + this->internally_mutate_to_stable_string(); + c = string_->c_str(); + return c; +} + +String& String::insert(size_type index, size_type count, char ch) +{ + std::string s; + s.reserve(size() + count); + s.assign(data(), size()); + s.insert(index, count, ch); + return *this = std::move(s); +} + +String& String::erase(size_type index, size_type count) +{ + if (index > size()) { + throw std::out_of_range("Index out of range in String::erase"); + } + size_type const rcount = std::min(count, size() - index); + size_type const rindex = index + rcount; + std::string s; + s.reserve(size() - rcount); + s.assign(data(), index); + s.append(data() + rindex, size() - rindex); + return *this = std::move(s); +} + +String String::substr(size_type pos, size_type count) const +{ + if (pos > size()) { + throw std::out_of_range("Index out of range in String::substr"); + } + return String(*this, pos, count); +} + +String::String(std::string&& s, Private) + : string_(std::make_shared<std::string>(std::move(s))) + , view_(string_->data(), string_->size()) +{ +} + +String::size_type String::copy(char* dest, size_type count, + size_type pos) const +{ + return view_.copy(dest, count, pos); +} + +std::ostream& operator<<(std::ostream& os, String const& s) +{ + return os.write(s.data(), s.size()); +} + +std::string& operator+=(std::string& self, String const& s) +{ + return self += s.view(); +} + +String IntoString<char*>::into_string(const char* s) +{ + if (!s) { + return String(); + } + return std::string(s); +} + +string_view AsStringView<String>::view(String const& s) +{ + return s.view(); +} + +} // namespace cm |