Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <AK/ByteBuffer.h>
28#include <AK/String.h>
29#include <AK/StringView.h>
30#include <AK/Vector.h>
31
32namespace AK {
33
34StringView::StringView(const String& string)
35 : m_impl(string.impl())
36 , m_characters(string.characters())
37 , m_length(string.length())
38{
39}
40
41StringView::StringView(const ByteBuffer& buffer)
42 : m_characters((const char*)buffer.data())
43 , m_length((size_t)buffer.size())
44{
45}
46
47Vector<StringView> StringView::split_view(const char separator, bool keep_empty) const
48{
49 if (is_empty())
50 return {};
51
52 Vector<StringView> v;
53 size_t substart = 0;
54 for (size_t i = 0; i < length(); ++i) {
55 char ch = characters_without_null_termination()[i];
56 if (ch == separator) {
57 size_t sublen = i - substart;
58 if (sublen != 0 || keep_empty)
59 v.append(substring_view(substart, sublen));
60 substart = i + 1;
61 }
62 }
63 size_t taillen = length() - substart;
64 if (taillen != 0 || keep_empty)
65 v.append(substring_view(substart, taillen));
66 return v;
67}
68
69Vector<StringView> StringView::lines(bool consider_cr) const
70{
71 if (is_empty())
72 return {};
73
74 if (!consider_cr)
75 return split_view('\n', true);
76
77 Vector<StringView> v;
78 size_t substart = 0;
79 bool last_ch_was_cr = false;
80 bool split_view = false;
81 for (size_t i = 0; i < length(); ++i) {
82 char ch = characters_without_null_termination()[i];
83 if (ch == '\n') {
84 split_view = true;
85 if (last_ch_was_cr) {
86 substart = i + 1;
87 split_view = false;
88 last_ch_was_cr = false;
89 }
90 }
91 if (ch == '\r') {
92 split_view = true;
93 last_ch_was_cr = true;
94 }
95 if (split_view) {
96 size_t sublen = i - substart;
97 v.append(substring_view(substart, sublen));
98 substart = i + 1;
99 }
100 split_view = false;
101 }
102 size_t taillen = length() - substart;
103 if (taillen != 0)
104 v.append(substring_view(substart, taillen));
105 return v;
106}
107
108bool StringView::starts_with(char ch) const
109{
110 if (is_empty())
111 return false;
112 return ch == characters_without_null_termination()[0];
113}
114
115bool StringView::starts_with(const StringView& str) const
116{
117 if (str.is_empty())
118 return true;
119 if (is_empty())
120 return false;
121 if (str.length() > length())
122 return false;
123 if (characters_without_null_termination() == str.characters_without_null_termination())
124 return true;
125 return !memcmp(characters_without_null_termination(), str.characters_without_null_termination(), str.length());
126}
127
128bool StringView::ends_with(char ch) const
129{
130 if (is_empty())
131 return false;
132 return ch == characters_without_null_termination()[length() - 1];
133}
134
135bool StringView::ends_with(const StringView& str) const
136{
137 if (str.is_empty())
138 return true;
139 if (is_empty())
140 return false;
141 if (str.length() > length())
142 return false;
143 return !memcmp(characters_without_null_termination() + length() - str.length(), str.characters_without_null_termination(), str.length());
144}
145
146StringView StringView::substring_view(size_t start, size_t length) const
147{
148 ASSERT(start + length <= m_length);
149 return { m_characters + start, length };
150}
151
152StringView StringView::substring_view_starting_from_substring(const StringView& substring) const
153{
154 const char* remaining_characters = substring.characters_without_null_termination();
155 ASSERT(remaining_characters >= m_characters);
156 ASSERT(remaining_characters <= m_characters + m_length);
157 size_t remaining_length = m_length - (remaining_characters - m_characters);
158 return { remaining_characters, remaining_length };
159}
160
161StringView StringView::substring_view_starting_after_substring(const StringView& substring) const
162{
163 const char* remaining_characters = substring.characters_without_null_termination() + substring.length();
164 ASSERT(remaining_characters >= m_characters);
165 ASSERT(remaining_characters <= m_characters + m_length);
166 size_t remaining_length = m_length - (remaining_characters - m_characters);
167 return { remaining_characters, remaining_length };
168}
169
170int StringView::to_int(bool& ok) const
171{
172 bool negative = false;
173 int value = 0;
174 size_t i = 0;
175
176 if (is_empty()) {
177 ok = false;
178 return 0;
179 }
180
181 if (characters_without_null_termination()[0] == '-') {
182 i++;
183 negative = true;
184 }
185 for (; i < length(); i++) {
186 if (characters_without_null_termination()[i] < '0' || characters_without_null_termination()[i] > '9') {
187 ok = false;
188 return 0;
189 }
190 value = value * 10;
191 value += characters_without_null_termination()[i] - '0';
192 }
193 ok = true;
194
195 return negative ? -value : value;
196}
197
198unsigned StringView::to_uint(bool& ok) const
199{
200 unsigned value = 0;
201 for (size_t i = 0; i < length(); ++i) {
202 if (characters_without_null_termination()[i] < '0' || characters_without_null_termination()[i] > '9') {
203 ok = false;
204 return 0;
205 }
206 value = value * 10;
207 value += characters_without_null_termination()[i] - '0';
208 }
209 ok = true;
210 return value;
211}
212
213unsigned StringView::hash() const
214{
215 if (is_empty())
216 return 0;
217 if (m_impl)
218 return m_impl->hash();
219 return string_hash(characters_without_null_termination(), length());
220}
221
222}