The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

493 lines
13KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. //==============================================================================
  19. StringArray::StringArray() noexcept
  20. {
  21. }
  22. StringArray::StringArray (const StringArray& other)
  23. : strings (other.strings)
  24. {
  25. }
  26. #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
  27. StringArray::StringArray (StringArray&& other) noexcept
  28. : strings (static_cast <Array <String>&&> (other.strings))
  29. {
  30. }
  31. #endif
  32. StringArray::StringArray (const String& firstValue)
  33. {
  34. strings.add (firstValue);
  35. }
  36. namespace StringArrayHelpers
  37. {
  38. template <typename CharType>
  39. void addArray (Array<String>& dest, const CharType* const* strings)
  40. {
  41. if (strings != nullptr)
  42. while (*strings != nullptr)
  43. dest.add (*strings++);
  44. }
  45. template <typename CharType>
  46. void addArray (Array<String>& dest, const CharType* const* const strings, const int numberOfStrings)
  47. {
  48. for (int i = 0; i < numberOfStrings; ++i)
  49. dest.add (strings [i]);
  50. }
  51. }
  52. StringArray::StringArray (const char* const* const initialStrings)
  53. {
  54. StringArrayHelpers::addArray (strings, initialStrings);
  55. }
  56. StringArray::StringArray (const char* const* const initialStrings, const int numberOfStrings)
  57. {
  58. StringArrayHelpers::addArray (strings, initialStrings, numberOfStrings);
  59. }
  60. StringArray::StringArray (const wchar_t* const* const initialStrings)
  61. {
  62. StringArrayHelpers::addArray (strings, initialStrings);
  63. }
  64. StringArray::StringArray (const wchar_t* const* const initialStrings, const int numberOfStrings)
  65. {
  66. StringArrayHelpers::addArray (strings, initialStrings, numberOfStrings);
  67. }
  68. StringArray& StringArray::operator= (const StringArray& other)
  69. {
  70. strings = other.strings;
  71. return *this;
  72. }
  73. #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
  74. StringArray& StringArray::operator= (StringArray&& other) noexcept
  75. {
  76. strings = static_cast <Array<String>&&> (other.strings);
  77. return *this;
  78. }
  79. #endif
  80. StringArray::~StringArray()
  81. {
  82. }
  83. bool StringArray::operator== (const StringArray& other) const noexcept
  84. {
  85. if (other.size() != size())
  86. return false;
  87. for (int i = size(); --i >= 0;)
  88. if (other.strings.getReference(i) != strings.getReference(i))
  89. return false;
  90. return true;
  91. }
  92. bool StringArray::operator!= (const StringArray& other) const noexcept
  93. {
  94. return ! operator== (other);
  95. }
  96. void StringArray::swapWith (StringArray& other) noexcept
  97. {
  98. strings.swapWithArray (other.strings);
  99. }
  100. void StringArray::clear()
  101. {
  102. strings.clear();
  103. }
  104. const String& StringArray::operator[] (const int index) const noexcept
  105. {
  106. if (isPositiveAndBelow (index, strings.size()))
  107. return strings.getReference (index);
  108. return String::empty;
  109. }
  110. String& StringArray::getReference (const int index) noexcept
  111. {
  112. jassert (isPositiveAndBelow (index, strings.size()));
  113. return strings.getReference (index);
  114. }
  115. void StringArray::add (const String& newString)
  116. {
  117. strings.add (newString);
  118. }
  119. void StringArray::insert (const int index, const String& newString)
  120. {
  121. strings.insert (index, newString);
  122. }
  123. void StringArray::addIfNotAlreadyThere (const String& newString, const bool ignoreCase)
  124. {
  125. if (! contains (newString, ignoreCase))
  126. add (newString);
  127. }
  128. void StringArray::addArray (const StringArray& otherArray, int startIndex, int numElementsToAdd)
  129. {
  130. if (startIndex < 0)
  131. {
  132. jassertfalse;
  133. startIndex = 0;
  134. }
  135. if (numElementsToAdd < 0 || startIndex + numElementsToAdd > otherArray.size())
  136. numElementsToAdd = otherArray.size() - startIndex;
  137. while (--numElementsToAdd >= 0)
  138. strings.add (otherArray.strings.getReference (startIndex++));
  139. }
  140. void StringArray::set (const int index, const String& newString)
  141. {
  142. strings.set (index, newString);
  143. }
  144. bool StringArray::contains (const String& stringToLookFor, const bool ignoreCase) const
  145. {
  146. if (ignoreCase)
  147. {
  148. for (int i = size(); --i >= 0;)
  149. if (strings.getReference(i).equalsIgnoreCase (stringToLookFor))
  150. return true;
  151. }
  152. else
  153. {
  154. for (int i = size(); --i >= 0;)
  155. if (stringToLookFor == strings.getReference(i))
  156. return true;
  157. }
  158. return false;
  159. }
  160. int StringArray::indexOf (const String& stringToLookFor, const bool ignoreCase, int i) const
  161. {
  162. if (i < 0)
  163. i = 0;
  164. const int numElements = size();
  165. if (ignoreCase)
  166. {
  167. while (i < numElements)
  168. {
  169. if (strings.getReference(i).equalsIgnoreCase (stringToLookFor))
  170. return i;
  171. ++i;
  172. }
  173. }
  174. else
  175. {
  176. while (i < numElements)
  177. {
  178. if (stringToLookFor == strings.getReference (i))
  179. return i;
  180. ++i;
  181. }
  182. }
  183. return -1;
  184. }
  185. //==============================================================================
  186. void StringArray::remove (const int index)
  187. {
  188. strings.remove (index);
  189. }
  190. void StringArray::removeString (const String& stringToRemove,
  191. const bool ignoreCase)
  192. {
  193. if (ignoreCase)
  194. {
  195. for (int i = size(); --i >= 0;)
  196. if (strings.getReference(i).equalsIgnoreCase (stringToRemove))
  197. strings.remove (i);
  198. }
  199. else
  200. {
  201. for (int i = size(); --i >= 0;)
  202. if (stringToRemove == strings.getReference (i))
  203. strings.remove (i);
  204. }
  205. }
  206. void StringArray::removeRange (int startIndex, int numberToRemove)
  207. {
  208. strings.removeRange (startIndex, numberToRemove);
  209. }
  210. //==============================================================================
  211. void StringArray::removeEmptyStrings (const bool removeWhitespaceStrings)
  212. {
  213. if (removeWhitespaceStrings)
  214. {
  215. for (int i = size(); --i >= 0;)
  216. if (! strings.getReference(i).containsNonWhitespaceChars())
  217. strings.remove (i);
  218. }
  219. else
  220. {
  221. for (int i = size(); --i >= 0;)
  222. if (strings.getReference(i).isEmpty())
  223. strings.remove (i);
  224. }
  225. }
  226. void StringArray::trim()
  227. {
  228. for (int i = size(); --i >= 0;)
  229. {
  230. String& s = strings.getReference(i);
  231. s = s.trim();
  232. }
  233. }
  234. //==============================================================================
  235. struct InternalStringArrayComparator_CaseSensitive
  236. {
  237. static int compareElements (String& first, String& second) { return first.compare (second); }
  238. };
  239. struct InternalStringArrayComparator_CaseInsensitive
  240. {
  241. static int compareElements (String& first, String& second) { return first.compareIgnoreCase (second); }
  242. };
  243. void StringArray::sort (const bool ignoreCase)
  244. {
  245. if (ignoreCase)
  246. {
  247. InternalStringArrayComparator_CaseInsensitive comp;
  248. strings.sort (comp);
  249. }
  250. else
  251. {
  252. InternalStringArrayComparator_CaseSensitive comp;
  253. strings.sort (comp);
  254. }
  255. }
  256. void StringArray::move (const int currentIndex, int newIndex) noexcept
  257. {
  258. strings.move (currentIndex, newIndex);
  259. }
  260. //==============================================================================
  261. String StringArray::joinIntoString (const String& separator, int start, int numberToJoin) const
  262. {
  263. const int last = (numberToJoin < 0) ? size()
  264. : jmin (size(), start + numberToJoin);
  265. if (start < 0)
  266. start = 0;
  267. if (start >= last)
  268. return String::empty;
  269. if (start == last - 1)
  270. return strings.getReference (start);
  271. const size_t separatorBytes = separator.getCharPointer().sizeInBytes() - sizeof (String::CharPointerType::CharType);
  272. size_t bytesNeeded = separatorBytes * (last - start - 1);
  273. for (int i = start; i < last; ++i)
  274. bytesNeeded += strings.getReference(i).getCharPointer().sizeInBytes() - sizeof (String::CharPointerType::CharType);
  275. String result;
  276. result.preallocateBytes (bytesNeeded);
  277. String::CharPointerType dest (result.getCharPointer());
  278. while (start < last)
  279. {
  280. const String& s = strings.getReference (start);
  281. if (! s.isEmpty())
  282. dest.writeAll (s.getCharPointer());
  283. if (++start < last && separatorBytes > 0)
  284. dest.writeAll (separator.getCharPointer());
  285. }
  286. dest.writeNull();
  287. return result;
  288. }
  289. int StringArray::addTokens (const String& text, const bool preserveQuotedStrings)
  290. {
  291. return addTokens (text, " \n\r\t", preserveQuotedStrings ? "\"" : "");
  292. }
  293. int StringArray::addTokens (const String& text, const String& breakCharacters, const String& quoteCharacters)
  294. {
  295. int num = 0;
  296. String::CharPointerType t (text.getCharPointer());
  297. if (! t.isEmpty())
  298. {
  299. for (;;)
  300. {
  301. String::CharPointerType tokenEnd (CharacterFunctions::findEndOfToken (t,
  302. breakCharacters.getCharPointer(),
  303. quoteCharacters.getCharPointer()));
  304. add (String (t, tokenEnd));
  305. ++num;
  306. if (tokenEnd.isEmpty())
  307. break;
  308. t = ++tokenEnd;
  309. }
  310. }
  311. return num;
  312. }
  313. int StringArray::addLines (const String& sourceText)
  314. {
  315. int numLines = 0;
  316. String::CharPointerType text (sourceText.getCharPointer());
  317. bool finished = text.isEmpty();
  318. while (! finished)
  319. {
  320. String::CharPointerType startOfLine (text);
  321. size_t numChars = 0;
  322. for (;;)
  323. {
  324. const juce_wchar c = text.getAndAdvance();
  325. if (c == 0)
  326. {
  327. finished = true;
  328. break;
  329. }
  330. if (c == '\n')
  331. break;
  332. if (c == '\r')
  333. {
  334. if (*text == '\n')
  335. ++text;
  336. break;
  337. }
  338. ++numChars;
  339. }
  340. add (String (startOfLine, numChars));
  341. ++numLines;
  342. }
  343. return numLines;
  344. }
  345. //==============================================================================
  346. void StringArray::removeDuplicates (const bool ignoreCase)
  347. {
  348. for (int i = 0; i < size() - 1; ++i)
  349. {
  350. const String s (strings.getReference(i));
  351. int nextIndex = i + 1;
  352. for (;;)
  353. {
  354. nextIndex = indexOf (s, ignoreCase, nextIndex);
  355. if (nextIndex < 0)
  356. break;
  357. strings.remove (nextIndex);
  358. }
  359. }
  360. }
  361. void StringArray::appendNumbersToDuplicates (const bool ignoreCase,
  362. const bool appendNumberToFirstInstance,
  363. CharPointer_UTF8 preNumberString,
  364. CharPointer_UTF8 postNumberString)
  365. {
  366. CharPointer_UTF8 defaultPre (" ("), defaultPost (")");
  367. if (preNumberString.getAddress() == nullptr)
  368. preNumberString = defaultPre;
  369. if (postNumberString.getAddress() == nullptr)
  370. postNumberString = defaultPost;
  371. for (int i = 0; i < size() - 1; ++i)
  372. {
  373. String& s = strings.getReference(i);
  374. int nextIndex = indexOf (s, ignoreCase, i + 1);
  375. if (nextIndex >= 0)
  376. {
  377. const String original (s);
  378. int number = 0;
  379. if (appendNumberToFirstInstance)
  380. s = original + String (preNumberString) + String (++number) + String (postNumberString);
  381. else
  382. ++number;
  383. while (nextIndex >= 0)
  384. {
  385. set (nextIndex, (*this)[nextIndex] + String (preNumberString) + String (++number) + String (postNumberString));
  386. nextIndex = indexOf (original, ignoreCase, nextIndex + 1);
  387. }
  388. }
  389. }
  390. }
  391. void StringArray::minimiseStorageOverheads()
  392. {
  393. strings.minimiseStorageOverheads();
  394. }