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#pragma once
28
29#include <AK/Forward.h>
30#include <AK/StdLibExtras.h>
31#include <AK/StringUtils.h>
32
33namespace AK {
34
35class StringView {
36public:
37 using ConstIterator = const char*;
38
39 StringView() {}
40 StringView(const char* characters, size_t length)
41 : m_characters(characters)
42 , m_length(length)
43 {
44 }
45 StringView(const unsigned char* characters, size_t length)
46 : m_characters((const char*)characters)
47 , m_length(length)
48 {
49 }
50 [[gnu::always_inline]] inline StringView(const char* cstring)
51 : m_characters(cstring)
52 , m_length(cstring ? __builtin_strlen(cstring) : 0)
53 {
54 }
55
56 StringView(const ByteBuffer&);
57 StringView(const String&);
58 StringView(const FlyString&);
59
60 bool is_null() const { return !m_characters; }
61 bool is_empty() const { return m_length == 0; }
62 const char* characters_without_null_termination() const { return m_characters; }
63 size_t length() const { return m_length; }
64 const char& operator[](size_t index) const { return m_characters[index]; }
65
66 ConstIterator begin() const { return characters_without_null_termination(); }
67 ConstIterator end() const { return begin() + length(); }
68
69 unsigned hash() const;
70
71 bool starts_with(const StringView&) const;
72 bool ends_with(const StringView&) const;
73 bool starts_with(char) const;
74 bool ends_with(char) const;
75 bool matches(const StringView& mask, CaseSensitivity = CaseSensitivity::CaseInsensitive) const;
76
77 StringView substring_view(size_t start, size_t length) const;
78 Vector<StringView> split_view(char, bool keep_empty = false) const;
79
80 // Create a Vector of StringViews split by line endings. As of CommonMark
81 // 0.29, the spec defines a line ending as "a newline (U+000A), a carriage
82 // return (U+000D) not followed by a newline, or a carriage return and a
83 // following newline.".
84 Vector<StringView> lines(bool consider_cr = true) const;
85
86 int to_int(bool& ok) const;
87 unsigned to_uint(bool& ok) const;
88
89 // Create a new substring view of this string view, starting either at the beginning of
90 // the given substring view, or after its end, and continuing until the end of this string
91 // view (that is, for the remaining part of its length). For example,
92 //
93 // StringView str { "foobar" };
94 // StringView substr = str.substring_view(1, 2); // "oo"
95 // StringView substr_from = str.substring_view_starting_from_substring(subst); // "oobar"
96 // StringView substr_after = str.substring_view_starting_after_substring(subst); // "bar"
97 //
98 // Note that this only works if the string view passed as an argument is indeed a substring
99 // view of this string view, such as one created by substring_view() and split_view(). It
100 // does not work for arbitrary strings; for example declaring substr in the example above as
101 //
102 // StringView substr { "oo" };
103 //
104 // would not work.
105 StringView substring_view_starting_from_substring(const StringView& substring) const;
106 StringView substring_view_starting_after_substring(const StringView& substring) const;
107
108 bool operator==(const char* cstring) const
109 {
110 if (is_null())
111 return !cstring;
112 if (!cstring)
113 return false;
114 size_t other_length = __builtin_strlen(cstring);
115 if (m_length != other_length)
116 return false;
117 return !__builtin_memcmp(m_characters, cstring, m_length);
118 }
119 bool operator!=(const char* cstring) const
120 {
121 return !(*this == cstring);
122 }
123
124 bool operator==(const String&) const;
125
126 bool operator==(const StringView& other) const
127 {
128 if (is_null())
129 return other.is_null();
130 if (other.is_null())
131 return false;
132 if (length() != other.length())
133 return false;
134 return !__builtin_memcmp(m_characters, other.m_characters, m_length);
135 }
136
137 bool operator!=(const StringView& other) const
138 {
139 return !(*this == other);
140 }
141
142 const StringImpl* impl() const { return m_impl; }
143
144private:
145 friend class String;
146 const StringImpl* m_impl { nullptr };
147 const char* m_characters { nullptr };
148 size_t m_length { 0 };
149};
150
151}
152
153using AK::StringView;