OpenShot Audio Library | OpenShotAudio  0.6.0
juce_StringArray.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 
23 namespace juce
24 {
25 
27 {
28 }
29 
31  : strings (other.strings)
32 {
33 }
34 
36  : strings (std::move (other.strings))
37 {
38 }
39 
41  : strings (std::move (other))
42 {
43 }
44 
45 StringArray::StringArray (const String& firstValue)
46 {
47  strings.add (firstValue);
48 }
49 
50 StringArray::StringArray (const String* initialStrings, int numberOfStrings)
51 {
52  strings.addArray (initialStrings, numberOfStrings);
53 }
54 
55 StringArray::StringArray (const char* const* initialStrings)
56 {
57  strings.addNullTerminatedArray (initialStrings);
58 }
59 
60 StringArray::StringArray (const char* const* initialStrings, int numberOfStrings)
61 {
62  strings.addArray (initialStrings, numberOfStrings);
63 }
64 
65 StringArray::StringArray (const wchar_t* const* initialStrings)
66 {
67  strings.addNullTerminatedArray (initialStrings);
68 }
69 
70 StringArray::StringArray (const wchar_t* const* initialStrings, int numberOfStrings)
71 {
72  strings.addArray (initialStrings, numberOfStrings);
73 }
74 
75 StringArray::StringArray (const std::initializer_list<const char*>& stringList)
76 {
77  strings.addArray (stringList);
78 }
79 
81 {
82  strings = other.strings;
83  return *this;
84 }
85 
87 {
88  strings = std::move (other.strings);
89  return *this;
90 }
91 
92 bool StringArray::operator== (const StringArray& other) const noexcept
93 {
94  return strings == other.strings;
95 }
96 
97 bool StringArray::operator!= (const StringArray& other) const noexcept
98 {
99  return ! operator== (other);
100 }
101 
102 void StringArray::swapWith (StringArray& other) noexcept
103 {
104  strings.swapWith (other.strings);
105 }
106 
108 {
109  strings.clear();
110 }
111 
113 {
114  strings.clearQuick();
115 }
116 
117 const String& StringArray::operator[] (int index) const noexcept
118 {
119  if (isPositiveAndBelow (index, strings.size()))
120  return strings.getReference (index);
121 
122  static String empty;
123  return empty;
124 }
125 
126 String& StringArray::getReference (int index) noexcept
127 {
128  return strings.getReference (index);
129 }
130 
131 const String& StringArray::getReference (int index) const noexcept
132 {
133  return strings.getReference (index);
134 }
135 
136 void StringArray::add (String newString)
137 {
138  // NB: the local temp copy is to avoid a dangling pointer if the
139  // argument being passed-in is a reference into this array.
140  strings.add (std::move (newString));
141 }
142 
143 void StringArray::insert (int index, String newString)
144 {
145  // NB: the local temp copy is to avoid a dangling pointer if the
146  // argument being passed-in is a reference into this array.
147  strings.insert (index, std::move (newString));
148 }
149 
150 bool StringArray::addIfNotAlreadyThere (const String& newString, bool ignoreCase)
151 {
152  if (contains (newString, ignoreCase))
153  return false;
154 
155  add (newString);
156  return true;
157 }
158 
159 void StringArray::addArray (const StringArray& otherArray, int startIndex, int numElementsToAdd)
160 {
161  jassert (this != &otherArray); // can't add from our own elements!
162 
163  if (startIndex < 0)
164  {
165  jassertfalse;
166  startIndex = 0;
167  }
168 
169  if (numElementsToAdd < 0 || startIndex + numElementsToAdd > otherArray.size())
170  numElementsToAdd = otherArray.size() - startIndex;
171 
172  while (--numElementsToAdd >= 0)
173  strings.add (otherArray.strings.getReference (startIndex++));
174 }
175 
176 void StringArray::mergeArray (const StringArray& otherArray, bool ignoreCase)
177 {
178  jassert (this != &otherArray); // can't add from our own elements!
179 
180  for (auto& s : otherArray)
181  addIfNotAlreadyThere (s, ignoreCase);
182 }
183 
184 void StringArray::set (int index, String newString)
185 {
186  strings.set (index, std::move (newString));
187 }
188 
189 bool StringArray::contains (StringRef stringToLookFor, bool ignoreCase) const
190 {
191  return indexOf (stringToLookFor, ignoreCase) >= 0;
192 }
193 
194 int StringArray::indexOf (StringRef stringToLookFor, bool ignoreCase, int i) const
195 {
196  if (i < 0)
197  i = 0;
198 
199  auto numElements = size();
200 
201  if (ignoreCase)
202  {
203  for (; i < numElements; ++i)
204  if (strings.getReference (i).equalsIgnoreCase (stringToLookFor))
205  return i;
206  }
207  else
208  {
209  for (; i < numElements; ++i)
210  if (stringToLookFor == strings.getReference (i))
211  return i;
212  }
213 
214  return -1;
215 }
216 
217 void StringArray::move (int currentIndex, int newIndex) noexcept
218 {
219  strings.move (currentIndex, newIndex);
220 }
221 
222 //==============================================================================
223 void StringArray::remove (int index)
224 {
225  strings.remove (index);
226 }
227 
228 void StringArray::removeString (StringRef stringToRemove, bool ignoreCase)
229 {
230  if (ignoreCase)
231  {
232  for (int i = size(); --i >= 0;)
233  if (strings.getReference (i).equalsIgnoreCase (stringToRemove))
234  strings.remove (i);
235  }
236  else
237  {
238  for (int i = size(); --i >= 0;)
239  if (stringToRemove == strings.getReference (i))
240  strings.remove (i);
241  }
242 }
243 
244 void StringArray::removeRange (int startIndex, int numberToRemove)
245 {
246  strings.removeRange (startIndex, numberToRemove);
247 }
248 
249 //==============================================================================
250 void StringArray::removeEmptyStrings (bool removeWhitespaceStrings)
251 {
252  if (removeWhitespaceStrings)
253  {
254  for (int i = size(); --i >= 0;)
255  if (! strings.getReference (i).containsNonWhitespaceChars())
256  strings.remove (i);
257  }
258  else
259  {
260  for (int i = size(); --i >= 0;)
261  if (strings.getReference (i).isEmpty())
262  strings.remove (i);
263  }
264 }
265 
267 {
268  for (auto& s : strings)
269  s = s.trim();
270 }
271 
272 //==============================================================================
273 void StringArray::sort (bool ignoreCase)
274 {
275  if (ignoreCase)
276  std::sort (strings.begin(), strings.end(),
277  [] (const String& a, const String& b) { return a.compareIgnoreCase (b) < 0; });
278  else
279  std::sort (strings.begin(), strings.end());
280 }
281 
283 {
284  std::sort (strings.begin(), strings.end(),
285  [] (const String& a, const String& b) { return a.compareNatural (b) < 0; });
286 }
287 
288 //==============================================================================
289 String StringArray::joinIntoString (StringRef separator, int start, int numberToJoin) const
290 {
291  auto last = (numberToJoin < 0) ? size()
292  : jmin (size(), start + numberToJoin);
293 
294  if (start < 0)
295  start = 0;
296 
297  if (start >= last)
298  return {};
299 
300  if (start == last - 1)
301  return strings.getReference (start);
302 
303  auto separatorBytes = separator.text.sizeInBytes() - sizeof (String::CharPointerType::CharType);
304  auto bytesNeeded = (size_t) (last - start - 1) * separatorBytes;
305 
306  for (int i = start; i < last; ++i)
307  bytesNeeded += strings.getReference (i).getCharPointer().sizeInBytes() - sizeof (String::CharPointerType::CharType);
308 
309  String result;
310  result.preallocateBytes (bytesNeeded);
311 
312  auto dest = result.getCharPointer();
313 
314  while (start < last)
315  {
316  auto& s = strings.getReference (start);
317 
318  if (! s.isEmpty())
319  dest.writeAll (s.getCharPointer());
320 
321  if (++start < last && separatorBytes > 0)
322  dest.writeAll (separator.text);
323  }
324 
325  dest.writeNull();
326  return result;
327 }
328 
329 int StringArray::addTokens (StringRef text, const bool preserveQuotedStrings)
330 {
331  return addTokens (text, " \n\r\t", preserveQuotedStrings ? "\"" : "");
332 }
333 
334 int StringArray::addTokens (StringRef text, StringRef breakCharacters, StringRef quoteCharacters)
335 {
336  int num = 0;
337 
338  if (text.isNotEmpty())
339  {
340  for (auto t = text.text;;)
341  {
342  auto tokenEnd = CharacterFunctions::findEndOfToken (t,
343  breakCharacters.text,
344  quoteCharacters.text);
345  strings.add (String (t, tokenEnd));
346  ++num;
347 
348  if (tokenEnd.isEmpty())
349  break;
350 
351  t = ++tokenEnd;
352  }
353  }
354 
355  return num;
356 }
357 
359 {
360  int numLines = 0;
361  auto text = sourceText.text;
362  bool finished = text.isEmpty();
363 
364  while (! finished)
365  {
366  for (auto startOfLine = text;;)
367  {
368  auto endOfLine = text;
369 
370  switch (text.getAndAdvance())
371  {
372  case 0: finished = true; break;
373  case '\n': break;
374  case '\r': if (*text == '\n') ++text; break;
375  default: continue;
376  }
377 
378  strings.add (String (startOfLine, endOfLine));
379  ++numLines;
380  break;
381  }
382  }
383 
384  return numLines;
385 }
386 
387 StringArray StringArray::fromTokens (StringRef stringToTokenise, bool preserveQuotedStrings)
388 {
389  StringArray s;
390  s.addTokens (stringToTokenise, preserveQuotedStrings);
391  return s;
392 }
393 
395  StringRef breakCharacters,
396  StringRef quoteCharacters)
397 {
398  StringArray s;
399  s.addTokens (stringToTokenise, breakCharacters, quoteCharacters);
400  return s;
401 }
402 
404 {
405  StringArray s;
406  s.addLines (stringToBreakUp);
407  return s;
408 }
409 
410 //==============================================================================
411 void StringArray::removeDuplicates (bool ignoreCase)
412 {
413  for (int i = 0; i < size() - 1; ++i)
414  {
415  auto s = strings.getReference (i);
416 
417  for (int nextIndex = i + 1;;)
418  {
419  nextIndex = indexOf (s, ignoreCase, nextIndex);
420 
421  if (nextIndex < 0)
422  break;
423 
424  strings.remove (nextIndex);
425  }
426  }
427 }
428 
430  bool appendNumberToFirstInstance,
431  CharPointer_UTF8 preNumberString,
432  CharPointer_UTF8 postNumberString)
433 {
434  if (preNumberString.getAddress() == nullptr)
435  preNumberString = CharPointer_UTF8 (" (");
436 
437  if (postNumberString.getAddress() == nullptr)
438  postNumberString = CharPointer_UTF8 (")");
439 
440  for (int i = 0; i < size() - 1; ++i)
441  {
442  auto& s = strings.getReference (i);
443  auto nextIndex = indexOf (s, ignoreCase, i + 1);
444 
445  if (nextIndex >= 0)
446  {
447  auto original = s;
448  int number = 0;
449 
450  if (appendNumberToFirstInstance)
451  s = original + String (preNumberString) + String (++number) + String (postNumberString);
452  else
453  ++number;
454 
455  while (nextIndex >= 0)
456  {
457  set (nextIndex, (*this)[nextIndex] + String (preNumberString) + String (++number) + String (postNumberString));
458  nextIndex = indexOf (original, ignoreCase, nextIndex + 1);
459  }
460  }
461  }
462 }
463 
464 void StringArray::ensureStorageAllocated (int minNumElements)
465 {
466  strings.ensureStorageAllocated (minNumElements);
467 }
468 
470 {
471  strings.minimiseStorageOverheads();
472 }
473 
474 } // namespace juce
CharType * getAddress() const noexcept
static Type findEndOfToken(Type text, BreakType breakCharacters, Type quoteCharacters)
bool operator==(const StringArray &) const noexcept
String joinIntoString(StringRef separatorString, int startIndex=0, int numberOfElements=-1) const
void appendNumbersToDuplicates(bool ignoreCaseWhenComparing, bool appendNumberToFirstInstance, CharPointer_UTF8 preNumberString=CharPointer_UTF8(nullptr), CharPointer_UTF8 postNumberString=CharPointer_UTF8(nullptr))
String & getReference(int index) noexcept
void removeEmptyStrings(bool removeWhitespaceStrings=true)
void addArray(const StringArray &other, int startIndex=0, int numElementsToAdd=-1)
int indexOf(StringRef stringToLookFor, bool ignoreCase=false, int startIndex=0) const
bool contains(StringRef stringToLookFor, bool ignoreCase=false) const
void removeDuplicates(bool ignoreCase)
static StringArray fromTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
void insert(int index, String stringToAdd)
static StringArray fromLines(StringRef stringToBreakUp)
Array< String > strings
const String & operator[](int index) const noexcept
void removeString(StringRef stringToRemove, bool ignoreCase=false)
void sort(bool ignoreCase)
void move(int currentIndex, int newIndex) noexcept
void swapWith(StringArray &) noexcept
int size() const noexcept
bool operator!=(const StringArray &) const noexcept
void add(String stringToAdd)
int addLines(StringRef stringToBreakUp)
void mergeArray(const StringArray &other, bool ignoreCase=false)
bool addIfNotAlreadyThere(const String &stringToAdd, bool ignoreCase=false)
void removeRange(int startIndex, int numberToRemove)
StringArray & operator=(const StringArray &)
void set(int index, String newString)
void remove(int index)
void ensureStorageAllocated(int minNumElements)
int addTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
bool isNotEmpty() const noexcept
String::CharPointerType text
CharPointerType getCharPointer() const noexcept
Definition: juce_String.h:1153
void preallocateBytes(size_t numBytesNeeded)