/src/CMake/Source/cmString.cxx
Line | Count | Source |
1 | | /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying |
2 | | file LICENSE.rst or https://cmake.org/licensing for details. */ |
3 | | // NOLINTNEXTLINE(bugprone-reserved-identifier) |
4 | | #define _SCL_SECURE_NO_WARNINGS |
5 | | |
6 | | #include "cmString.hxx" |
7 | | |
8 | | #include <memory> |
9 | | #include <ostream> |
10 | | #include <stdexcept> |
11 | | #include <string> |
12 | | |
13 | | namespace cm { |
14 | | |
15 | | static std::string const empty_string_; |
16 | | |
17 | | void String::internally_mutate_to_stable_string() |
18 | 0 | { |
19 | | // We assume that only one thread mutates this instance at |
20 | | // a time even if we point to a shared string buffer referenced |
21 | | // by other threads. |
22 | 0 | *this = String(this->data(), this->size()); |
23 | 0 | } |
24 | | |
25 | | bool String::is_stable() const |
26 | 0 | { |
27 | 0 | return this->str_if_stable() != nullptr; |
28 | 0 | } |
29 | | |
30 | | void String::stabilize() |
31 | 0 | { |
32 | 0 | if (this->is_stable()) { |
33 | 0 | return; |
34 | 0 | } |
35 | 0 | this->internally_mutate_to_stable_string(); |
36 | 0 | } |
37 | | |
38 | | std::string const* String::str_if_stable() const |
39 | 6 | { |
40 | 6 | if (!this->data()) { |
41 | | // We view no string. |
42 | | // This is stable for the lifetime of our current value. |
43 | 0 | return &empty_string_; |
44 | 0 | } |
45 | | |
46 | 6 | if (this->string_ && this->data() == this->string_->data() && |
47 | 6 | this->size() == this->string_->size()) { |
48 | | // We view an entire string. |
49 | | // This is stable for the lifetime of our current value. |
50 | 6 | return this->string_.get(); |
51 | 6 | } |
52 | | |
53 | 0 | return nullptr; |
54 | 6 | } |
55 | | |
56 | | std::string const& String::str() |
57 | 0 | { |
58 | 0 | if (std::string const* s = this->str_if_stable()) { |
59 | 0 | return *s; |
60 | 0 | } |
61 | | // Mutate to hold a std::string that is stable for the lifetime |
62 | | // of our current value. |
63 | 0 | this->internally_mutate_to_stable_string(); |
64 | 0 | return *this->string_; |
65 | 0 | } |
66 | | |
67 | | char const* String::c_str() |
68 | 0 | { |
69 | 0 | char const* c = this->data(); |
70 | 0 | if (!c) { |
71 | 0 | return c; |
72 | 0 | } |
73 | | |
74 | | // We always point into a null-terminated string so it is safe to |
75 | | // access one past the end. If it is a null byte then we can use |
76 | | // the pointer directly. |
77 | 0 | if (c[this->size()] == '\0') { |
78 | 0 | return c; |
79 | 0 | } |
80 | | |
81 | | // Mutate to hold a std::string so we can get a null terminator. |
82 | 0 | this->internally_mutate_to_stable_string(); |
83 | 0 | c = this->string_->c_str(); |
84 | 0 | return c; |
85 | 0 | } |
86 | | |
87 | | String& String::insert(size_type index, size_type count, char ch) |
88 | 0 | { |
89 | 0 | std::string s; |
90 | 0 | s.reserve(this->size() + count); |
91 | 0 | s.assign(this->data(), this->size()); |
92 | 0 | s.insert(index, count, ch); |
93 | 0 | return *this = std::move(s); |
94 | 0 | } |
95 | | |
96 | | String& String::erase(size_type index, size_type count) |
97 | 0 | { |
98 | 0 | if (index > this->size()) { |
99 | 0 | throw std::out_of_range("Index out of range in String::erase"); |
100 | 0 | } |
101 | 0 | size_type const rcount = std::min(count, this->size() - index); |
102 | 0 | size_type const rindex = index + rcount; |
103 | 0 | std::string s; |
104 | 0 | s.reserve(this->size() - rcount); |
105 | 0 | s.assign(this->data(), index); |
106 | 0 | s.append(this->data() + rindex, this->size() - rindex); |
107 | 0 | return *this = std::move(s); |
108 | 0 | } |
109 | | |
110 | | String String::substr(size_type pos, size_type count) const |
111 | 0 | { |
112 | 0 | if (pos > this->size()) { |
113 | 0 | throw std::out_of_range("Index out of range in String::substr"); |
114 | 0 | } |
115 | 0 | return String(*this, pos, count); |
116 | 0 | } |
117 | | |
118 | | String::String(std::string&& s, Private) |
119 | 195 | : string_(std::make_shared<std::string>(std::move(s))) |
120 | 195 | , view_(this->string_->data(), this->string_->size()) |
121 | 195 | { |
122 | 195 | } |
123 | | |
124 | | String::size_type String::copy(char* dest, size_type count, |
125 | | size_type pos) const |
126 | 0 | { |
127 | 0 | return this->view_.copy(dest, count, pos); |
128 | 0 | } |
129 | | |
130 | | std::ostream& operator<<(std::ostream& os, String const& s) |
131 | 0 | { |
132 | 0 | return os.write(s.data(), s.size()); |
133 | 0 | } |
134 | | |
135 | | std::string& operator+=(std::string& self, String const& s) |
136 | 0 | { |
137 | 0 | return self += s.view(); |
138 | 0 | } |
139 | | |
140 | | String IntoString<char*>::into_string(char const* s) |
141 | 0 | { |
142 | 0 | if (!s) { |
143 | 0 | return String(); |
144 | 0 | } |
145 | 0 | return std::string(s); |
146 | 0 | } |
147 | | |
148 | | string_view AsStringView<String>::view(String const& s) |
149 | 0 | { |
150 | 0 | return s.view(); |
151 | 0 | } |
152 | | |
153 | | } // namespace cm |