/* ============================================================================== This file is part of the JUCE library - "Jules' Utility Class Extensions" Copyright 2004-11 by Raw Material Software Ltd. ------------------------------------------------------------------------------ JUCE can be redistributed and/or modified under the terms of the GNU General Public License (Version 2), as published by the Free Software Foundation. A copy of the license is included in the JUCE distribution, or can be found online at www.gnu.org/licenses. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ------------------------------------------------------------------------------ To release a closed-source product which uses JUCE, commercial licenses are available: visit www.rawmaterialsoftware.com/juce for more information. ============================================================================== */ BEGIN_JUCE_NAMESPACE //============================================================================== StringArray::StringArray() noexcept { } StringArray::StringArray (const StringArray& other) : strings (other.strings) { } #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS StringArray::StringArray (StringArray&& other) noexcept : strings (static_cast &&> (other.strings)) { } #endif StringArray::StringArray (const String& firstValue) { strings.add (firstValue); } namespace StringArrayHelpers { template void addArray (Array& dest, const CharType* const* strings) { if (strings != nullptr) while (*strings != nullptr) dest.add (*strings++); } template void addArray (Array& dest, const CharType* const* const strings, const int numberOfStrings) { for (int i = 0; i < numberOfStrings; ++i) dest.add (strings [i]); } } StringArray::StringArray (const char* const* const initialStrings) { StringArrayHelpers::addArray (strings, initialStrings); } StringArray::StringArray (const char* const* const initialStrings, const int numberOfStrings) { StringArrayHelpers::addArray (strings, initialStrings, numberOfStrings); } StringArray::StringArray (const wchar_t* const* const initialStrings) { StringArrayHelpers::addArray (strings, initialStrings); } StringArray::StringArray (const wchar_t* const* const initialStrings, const int numberOfStrings) { StringArrayHelpers::addArray (strings, initialStrings, numberOfStrings); } StringArray& StringArray::operator= (const StringArray& other) { strings = other.strings; return *this; } #if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS StringArray& StringArray::operator= (StringArray&& other) noexcept { strings = static_cast &&> (other.strings); return *this; } #endif StringArray::~StringArray() { } bool StringArray::operator== (const StringArray& other) const noexcept { if (other.size() != size()) return false; for (int i = size(); --i >= 0;) if (other.strings.getReference(i) != strings.getReference(i)) return false; return true; } bool StringArray::operator!= (const StringArray& other) const noexcept { return ! operator== (other); } void StringArray::clear() { strings.clear(); } const String& StringArray::operator[] (const int index) const noexcept { if (isPositiveAndBelow (index, strings.size())) return strings.getReference (index); return String::empty; } String& StringArray::getReference (const int index) noexcept { jassert (isPositiveAndBelow (index, strings.size())); return strings.getReference (index); } void StringArray::add (const String& newString) { strings.add (newString); } void StringArray::insert (const int index, const String& newString) { strings.insert (index, newString); } void StringArray::addIfNotAlreadyThere (const String& newString, const bool ignoreCase) { if (! contains (newString, ignoreCase)) add (newString); } void StringArray::addArray (const StringArray& otherArray, int startIndex, int numElementsToAdd) { if (startIndex < 0) { jassertfalse; startIndex = 0; } if (numElementsToAdd < 0 || startIndex + numElementsToAdd > otherArray.size()) numElementsToAdd = otherArray.size() - startIndex; while (--numElementsToAdd >= 0) strings.add (otherArray.strings.getReference (startIndex++)); } void StringArray::set (const int index, const String& newString) { strings.set (index, newString); } bool StringArray::contains (const String& stringToLookFor, const bool ignoreCase) const { if (ignoreCase) { for (int i = size(); --i >= 0;) if (strings.getReference(i).equalsIgnoreCase (stringToLookFor)) return true; } else { for (int i = size(); --i >= 0;) if (stringToLookFor == strings.getReference(i)) return true; } return false; } int StringArray::indexOf (const String& stringToLookFor, const bool ignoreCase, int i) const { if (i < 0) i = 0; const int numElements = size(); if (ignoreCase) { while (i < numElements) { if (strings.getReference(i).equalsIgnoreCase (stringToLookFor)) return i; ++i; } } else { while (i < numElements) { if (stringToLookFor == strings.getReference (i)) return i; ++i; } } return -1; } //============================================================================== void StringArray::remove (const int index) { strings.remove (index); } void StringArray::removeString (const String& stringToRemove, const bool ignoreCase) { if (ignoreCase) { for (int i = size(); --i >= 0;) if (strings.getReference(i).equalsIgnoreCase (stringToRemove)) strings.remove (i); } else { for (int i = size(); --i >= 0;) if (stringToRemove == strings.getReference (i)) strings.remove (i); } } void StringArray::removeRange (int startIndex, int numberToRemove) { strings.removeRange (startIndex, numberToRemove); } //============================================================================== void StringArray::removeEmptyStrings (const bool removeWhitespaceStrings) { if (removeWhitespaceStrings) { for (int i = size(); --i >= 0;) if (! strings.getReference(i).containsNonWhitespaceChars()) strings.remove (i); } else { for (int i = size(); --i >= 0;) if (strings.getReference(i).isEmpty()) strings.remove (i); } } void StringArray::trim() { for (int i = size(); --i >= 0;) { String& s = strings.getReference(i); s = s.trim(); } } //============================================================================== class InternalStringArrayComparator_CaseSensitive { public: static int compareElements (String& first, String& second) { return first.compare (second); } }; class InternalStringArrayComparator_CaseInsensitive { public: static int compareElements (String& first, String& second) { return first.compareIgnoreCase (second); } }; void StringArray::sort (const bool ignoreCase) { if (ignoreCase) { InternalStringArrayComparator_CaseInsensitive comp; strings.sort (comp); } else { InternalStringArrayComparator_CaseSensitive comp; strings.sort (comp); } } void StringArray::move (const int currentIndex, int newIndex) noexcept { strings.move (currentIndex, newIndex); } //============================================================================== String StringArray::joinIntoString (const String& separator, int start, int numberToJoin) const { const int last = (numberToJoin < 0) ? size() : jmin (size(), start + numberToJoin); if (start < 0) start = 0; if (start >= last) return String::empty; if (start == last - 1) return strings.getReference (start); const size_t separatorBytes = separator.getCharPointer().sizeInBytes() - sizeof (String::CharPointerType::CharType); size_t bytesNeeded = separatorBytes * (last - start - 1); for (int i = start; i < last; ++i) bytesNeeded += strings.getReference(i).getCharPointer().sizeInBytes() - sizeof (String::CharPointerType::CharType); String result; result.preallocateBytes (bytesNeeded); String::CharPointerType dest (result.getCharPointer()); while (start < last) { const String& s = strings.getReference (start); if (! s.isEmpty()) dest.writeAll (s.getCharPointer()); if (++start < last && separatorBytes > 0) dest.writeAll (separator.getCharPointer()); } dest.writeNull(); return result; } int StringArray::addTokens (const String& text, const bool preserveQuotedStrings) { return addTokens (text, " \n\r\t", preserveQuotedStrings ? "\"" : ""); } int StringArray::addTokens (const String& text, const String& breakCharacters, const String& quoteCharacters) { int num = 0; String::CharPointerType t (text.getCharPointer()); while (! t.isEmpty()) { String::CharPointerType tokenEnd (CharacterFunctions::findEndOfToken (t, breakCharacters.getCharPointer(), quoteCharacters.getCharPointer())); add (String (t, tokenEnd)); ++num; if (tokenEnd.isEmpty()) break; t = ++tokenEnd; } return num; } int StringArray::addLines (const String& sourceText) { int numLines = 0; String::CharPointerType text (sourceText.getCharPointer()); bool finished = text.isEmpty(); while (! finished) { String::CharPointerType startOfLine (text); size_t numChars = 0; for (;;) { const juce_wchar c = text.getAndAdvance(); if (c == 0) { finished = true; break; } if (c == '\n') break; if (c == '\r') { if (*text == '\n') ++text; break; } ++numChars; } add (String (startOfLine, numChars)); ++numLines; } return numLines; } //============================================================================== void StringArray::removeDuplicates (const bool ignoreCase) { for (int i = 0; i < size() - 1; ++i) { const String s (strings.getReference(i)); int nextIndex = i + 1; for (;;) { nextIndex = indexOf (s, ignoreCase, nextIndex); if (nextIndex < 0) break; strings.remove (nextIndex); } } } void StringArray::appendNumbersToDuplicates (const bool ignoreCase, const bool appendNumberToFirstInstance, CharPointer_UTF8 preNumberString, CharPointer_UTF8 postNumberString) { CharPointer_UTF8 defaultPre (" ("), defaultPost (")"); if (preNumberString.getAddress() == nullptr) preNumberString = defaultPre; if (postNumberString.getAddress() == nullptr) postNumberString = defaultPost; for (int i = 0; i < size() - 1; ++i) { String& s = strings.getReference(i); int nextIndex = indexOf (s, ignoreCase, i + 1); if (nextIndex >= 0) { const String original (s); int number = 0; if (appendNumberToFirstInstance) s = original + String (preNumberString) + String (++number) + String (postNumberString); else ++number; while (nextIndex >= 0) { set (nextIndex, (*this)[nextIndex] + String (preNumberString) + String (++number) + String (postNumberString)); nextIndex = indexOf (original, ignoreCase, nextIndex + 1); } } } } void StringArray::minimiseStorageOverheads() { strings.minimiseStorageOverheads(); } END_JUCE_NAMESPACE