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