OpenShot Audio Library | OpenShotAudio: juce_StringPairArray.cpp Source File

OpenShot Audio Library | OpenShotAudio 1.0.0

Loading...
Searching...
No Matches
juce_StringPairArray.cpp
1/*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 The code included in this file is provided under the terms of the ISC license
11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12 To use, copy, modify, and/or distribute this software for any purpose with or
13 without fee is hereby granted provided that the above copyright notice and
14 this permission notice appear in all copies.
15
16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18 DISCLAIMED.
19
20 ==============================================================================
21*/
22
23namespace juce
24{
25
26StringPairArray::StringPairArray (bool shouldIgnoreCase) : ignoreCase (shouldIgnoreCase)
27{
28}
29
30 StringPairArray::StringPairArray (const StringPairArray& other)
31 : keys (other.keys),
32 values (other.values),
33 ignoreCase (other.ignoreCase)
34{
35}
36
37 StringPairArray& StringPairArray::operator= (const StringPairArray& other)
38{
39 keys = other.keys;
40 values = other.values;
41 return *this;
42}
43
44 bool StringPairArray::operator== (const StringPairArray& other) const
45{
46 auto num = size();
47
48 if (num != other.size())
49 return false;
50
51 for (int i = 0; i < num; ++i)
52 {
53 if (keys[i] == other.keys[i]) // optimise for the case where the keys are in the same order
54 {
55 if (values[i] != other.values[i])
56 return false;
57 }
58 else
59 {
60 // if we encounter keys that are in a different order, search remaining items by brute force..
61 for (int j = i; j < num; ++j)
62 {
63 auto otherIndex = other.keys.indexOf (keys[j], other.ignoreCase);
64
65 if (otherIndex < 0 || values[j] != other.values[otherIndex])
66 return false;
67 }
68
69 return true;
70 }
71 }
72
73 return true;
74}
75
76 bool StringPairArray::operator!= (const StringPairArray& other) const
77{
78 return ! operator== (other);
79}
80
81 const String& StringPairArray::operator[] (StringRef key) const
82{
83 return values[keys.indexOf (key, ignoreCase)];
84}
85
86 String StringPairArray::getValue (StringRef key, const String& defaultReturnValue) const
87{
88 auto i = keys.indexOf (key, ignoreCase);
89
90 if (i >= 0)
91 return values[i];
92
93 return defaultReturnValue;
94}
95
96 bool StringPairArray::containsKey (StringRef key) const noexcept
97{
98 return keys.contains (key, ignoreCase);
99}
100
101 void StringPairArray::set (const String& key, const String& value)
102{
103 auto i = keys.indexOf (key, ignoreCase);
104
105 if (i >= 0)
106 {
107 values.set (i, value);
108 }
109 else
110 {
111 keys.add (key);
112 values.add (value);
113 }
114}
115
116 void StringPairArray::addArray (const StringPairArray& other)
117{
118 for (int i = 0; i < other.size(); ++i)
119 set (other.keys[i], other.values[i]);
120}
121
122 void StringPairArray::clear()
123{
124 keys.clear();
125 values.clear();
126}
127
128 void StringPairArray::remove (StringRef key)
129{
130 remove (keys.indexOf (key, ignoreCase));
131}
132
133 void StringPairArray::remove (int index)
134{
135 keys.remove (index);
136 values.remove (index);
137}
138
139 void StringPairArray::setIgnoresCase (bool shouldIgnoreCase)
140{
141 ignoreCase = shouldIgnoreCase;
142}
143
144 bool StringPairArray::getIgnoresCase() const noexcept
145{
146 return ignoreCase;
147}
148
149 String StringPairArray::getDescription() const
150{
151 String s;
152
153 for (int i = 0; i < keys.size(); ++i)
154 {
155 s << keys[i] << " = " << values[i];
156
157 if (i < keys.size())
158 s << ", ";
159 }
160
161 return s;
162}
163
164 void StringPairArray::minimiseStorageOverheads()
165{
166 keys.minimiseStorageOverheads();
167 values.minimiseStorageOverheads();
168}
169
170template <typename Map>
171void StringPairArray::addMapImpl (const Map& toAdd)
172{
173 // If we just called `set` for each item in `toAdd`, that would
174 // perform badly when adding to large StringPairArrays, as `set`
175 // has to loop through the whole container looking for matching keys.
176 // Instead, we use a temporary map to give us better lookup performance.
177 std::map<String, int> contents;
178
179 const auto normaliseKey = [this] (const String& key)
180 {
181 return ignoreCase ? key.toLowerCase() : key;
182 };
183
184 for (auto i = 0; i != size(); ++i)
185 contents.emplace (normaliseKey (getAllKeys().getReference (i)), i);
186
187 for (const auto& pair : toAdd)
188 {
189 const auto key = normaliseKey (pair.first);
190 const auto it = contents.find (key);
191
192 if (it != contents.cend())
193 {
194 values.getReference (it->second) = pair.second;
195 }
196 else
197 {
198 contents.emplace (key, static_cast<int> (contents.size()));
199 keys.add (pair.first);
200 values.add (pair.second);
201 }
202 }
203}
204
205 void StringPairArray::addUnorderedMap (const std::unordered_map<String, String>& toAdd) { addMapImpl (toAdd); }
206 void StringPairArray::addMap (const std::map<String, String>& toAdd) { addMapImpl (toAdd); }
207
208//==============================================================================
209//==============================================================================
210#if JUCE_UNIT_TESTS
211
212static String operator""_S (const char* chars, size_t)
213{
214 return String { chars };
215}
216
217class StringPairArrayTests final : public UnitTest
218{
219public:
220 StringPairArrayTests()
221 : UnitTest ("StringPairArray", UnitTestCategories::text)
222 {}
223
224 void runTest() override
225 {
226 beginTest ("addMap respects case sensitivity of StringPairArray");
227 {
228 StringPairArray insensitive { true };
229 insensitive.addMap ({ { "duplicate", "a" },
230 { "Duplicate", "b" } });
231
232 expect (insensitive.size() == 1);
233 expectEquals (insensitive["DUPLICATE"], "a"_S);
234
235 StringPairArray sensitive { false };
236 sensitive.addMap ({ { "duplicate", "a"_S },
237 { "Duplicate", "b"_S } });
238
239 expect (sensitive.size() == 2);
240 expectEquals (sensitive["duplicate"], "a"_S);
241 expectEquals (sensitive["Duplicate"], "b"_S);
242 expectEquals (sensitive["DUPLICATE"], ""_S);
243 }
244
245 beginTest ("addMap overwrites existing pairs");
246 {
247 StringPairArray insensitive { true };
248 insensitive.set ("key", "value");
249 insensitive.addMap ({ { "KEY", "VALUE" } });
250
251 expect (insensitive.size() == 1);
252 expectEquals (insensitive.getAllKeys()[0], "key"_S);
253 expectEquals (insensitive.getAllValues()[0], "VALUE"_S);
254
255 StringPairArray sensitive { false };
256 sensitive.set ("key", "value");
257 sensitive.addMap ({ { "KEY", "VALUE" },
258 { "key", "another value" } });
259
260 expect (sensitive.size() == 2);
261 expect (sensitive.getAllKeys() == StringArray { "key", "KEY" });
262 expect (sensitive.getAllValues() == StringArray { "another value", "VALUE" });
263 }
264
265 beginTest ("addMap doesn't change the order of existing keys");
266 {
267 StringPairArray array;
268 array.set ("a", "a");
269 array.set ("z", "z");
270 array.set ("b", "b");
271 array.set ("y", "y");
272 array.set ("c", "c");
273
274 array.addMap ({ { "B", "B" },
275 { "0", "0" },
276 { "Z", "Z" } });
277
278 expect (array.getAllKeys() == StringArray { "a", "z", "b", "y", "c", "0" });
279 expect (array.getAllValues() == StringArray { "a", "Z", "B", "y", "c", "0" });
280 }
281
282 beginTest ("addMap has equivalent behaviour to addArray");
283 {
284 StringPairArray initial;
285 initial.set ("aaa", "aaa");
286 initial.set ("zzz", "zzz");
287 initial.set ("bbb", "bbb");
288
289 auto withAddMap = initial;
290 withAddMap.addMap ({ { "ZZZ", "ZZZ" },
291 { "ddd", "ddd" } });
292
293 auto withAddArray = initial;
294 withAddArray.addArray ([]
295 {
296 StringPairArray toAdd;
297 toAdd.set ("ZZZ", "ZZZ");
298 toAdd.set ("ddd", "ddd");
299 return toAdd;
300 }());
301
302 expect (withAddMap == withAddArray);
303 }
304 }
305};
306
307static StringPairArrayTests stringPairArrayTests;
308
309#endif
310
311} // namespace juce
juce::StringArray::getReference
String & getReference(int index) noexcept
Definition juce_StringArray.cpp:126
juce::StringPairArray::setIgnoresCase
void setIgnoresCase(bool shouldIgnoreCase)
Definition juce_StringPairArray.cpp:139
juce::StringPairArray::getValue
String getValue(StringRef, const String &defaultReturnValue) const
Definition juce_StringPairArray.cpp:86
juce::StringPairArray::operator=
StringPairArray & operator=(const StringPairArray &other)
Definition juce_StringPairArray.cpp:37
juce::StringPairArray::containsKey
bool containsKey(StringRef key) const noexcept
Definition juce_StringPairArray.cpp:96
juce::StringPairArray::set
void set(const String &key, const String &value)
Definition juce_StringPairArray.cpp:101
juce::StringPairArray::clear
void clear()
Definition juce_StringPairArray.cpp:122
juce::StringPairArray::getDescription
String getDescription() const
Definition juce_StringPairArray.cpp:149
juce::StringPairArray::remove
void remove(StringRef key)
Definition juce_StringPairArray.cpp:128
juce::StringPairArray::StringPairArray
StringPairArray(bool ignoreCaseWhenComparingKeys=true)
Definition juce_StringPairArray.cpp:26
juce::StringPairArray::getIgnoresCase
bool getIgnoresCase() const noexcept
Definition juce_StringPairArray.cpp:144
juce::StringPairArray::operator[]
const String & operator[](StringRef key) const
Definition juce_StringPairArray.cpp:81
juce::StringPairArray::operator!=
bool operator!=(const StringPairArray &other) const
Definition juce_StringPairArray.cpp:76
juce::StringPairArray::minimiseStorageOverheads
void minimiseStorageOverheads()
Definition juce_StringPairArray.cpp:164
juce::StringPairArray::addMap
void addMap(const std::map< String, String > &mapToAdd)
Definition juce_StringPairArray.cpp:206
juce::StringPairArray::addArray
void addArray(const StringPairArray &other)
Definition juce_StringPairArray.cpp:116
juce::StringPairArray::addUnorderedMap
void addUnorderedMap(const std::unordered_map< String, String > &mapToAdd)
Definition juce_StringPairArray.cpp:205
juce::StringPairArray::size
int size() const noexcept
Definition juce_StringPairArray.h:93
juce::StringPairArray::operator==
bool operator==(const StringPairArray &other) const
Definition juce_StringPairArray.cpp:44
juce::StringPairArray::getAllKeys
const StringArray & getAllKeys() const noexcept
Definition juce_StringPairArray.h:87
juce::StringRef
Definition juce_StringRef.h:62
juce::String
Definition juce_String.h:53
juce::String::indexOf
int indexOf(StringRef textToLookFor) const noexcept
Definition juce_String.cpp:931
juce::UnitTest
Definition juce_UnitTest.h:70