OpenShot Audio Library | OpenShotAudio  0.3.1
juce_StringPool.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2017 - ROLI Ltd.
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 
26 static const int minNumberOfStringsForGarbageCollection = 300;
27 static const uint32 garbageCollectionInterval = 30000;
28 
29 
30 StringPool::StringPool() noexcept : lastGarbageCollectionTime (0) {}
32 
33 struct StartEndString
34 {
35  StartEndString (String::CharPointerType s, String::CharPointerType e) noexcept : start (s), end (e) {}
36  operator String() const { return String (start, end); }
37 
38  String::CharPointerType start, end;
39 };
40 
41 static int compareStrings (const String& s1, const String& s2) noexcept { return s1.compare (s2); }
42 static int compareStrings (CharPointer_UTF8 s1, const String& s2) noexcept { return s1.compare (s2.getCharPointer()); }
43 
44 static int compareStrings (const StartEndString& string1, const String& string2) noexcept
45 {
46  String::CharPointerType s1 (string1.start), s2 (string2.getCharPointer());
47 
48  for (;;)
49  {
50  const int c1 = s1 < string1.end ? (int) s1.getAndAdvance() : 0;
51  const int c2 = (int) s2.getAndAdvance();
52  const int diff = c1 - c2;
53 
54  if (diff != 0) return diff < 0 ? -1 : 1;
55  if (c1 == 0) break;
56  }
57 
58  return 0;
59 }
60 
61 template <typename NewStringType>
62 static String addPooledString (Array<String>& strings, const NewStringType& newString)
63 {
64  int start = 0;
65  int end = strings.size();
66 
67  while (start < end)
68  {
69  const String& startString = strings.getReference (start);
70  const int startComp = compareStrings (newString, startString);
71 
72  if (startComp == 0)
73  return startString;
74 
75  const int halfway = (start + end) / 2;
76 
77  if (halfway == start)
78  {
79  if (startComp > 0)
80  ++start;
81 
82  break;
83  }
84 
85  const String& halfwayString = strings.getReference (halfway);
86  const int halfwayComp = compareStrings (newString, halfwayString);
87 
88  if (halfwayComp == 0)
89  return halfwayString;
90 
91  if (halfwayComp > 0)
92  start = halfway;
93  else
94  end = halfway;
95  }
96 
97  strings.insert (start, newString);
98  return strings.getReference (start);
99 }
100 
101 String StringPool::getPooledString (const char* const newString)
102 {
103  if (newString == nullptr || *newString == 0)
104  return {};
105 
106  const ScopedLock sl (lock);
107  garbageCollectIfNeeded();
108  return addPooledString (strings, CharPointer_UTF8 (newString));
109 }
110 
111 String StringPool::getPooledString (String::CharPointerType start, String::CharPointerType end)
112 {
113  if (start.isEmpty() || start == end)
114  return {};
115 
116  const ScopedLock sl (lock);
117  garbageCollectIfNeeded();
118  return addPooledString (strings, StartEndString (start, end));
119 }
120 
122 {
123  if (newString.isEmpty())
124  return {};
125 
126  const ScopedLock sl (lock);
127  garbageCollectIfNeeded();
128  return addPooledString (strings, newString.text);
129 }
130 
132 {
133  if (newString.isEmpty())
134  return {};
135 
136  const ScopedLock sl (lock);
137  garbageCollectIfNeeded();
138  return addPooledString (strings, newString);
139 }
140 
141 void StringPool::garbageCollectIfNeeded()
142 {
143  if (strings.size() > minNumberOfStringsForGarbageCollection
144  && Time::getApproximateMillisecondCounter() > lastGarbageCollectionTime + garbageCollectionInterval)
145  garbageCollect();
146 }
147 
149 {
150  const ScopedLock sl (lock);
151 
152  for (int i = strings.size(); --i >= 0;)
153  if (strings.getReference(i).getReferenceCount() == 1)
154  strings.remove (i);
155 
156  lastGarbageCollectionTime = Time::getApproximateMillisecondCounter();
157 }
158 
160 {
161  static StringPool pool;
162  return pool;
163 }
164 
165 } // namespace juce
static StringPool & getGlobalPool() noexcept
CharPointerType getCharPointer() const noexcept
Definition: juce_String.h:1198
static uint32 getApproximateMillisecondCounter() noexcept
Definition: juce_Time.cpp:246
void insert(int indexToInsertAt, ParameterType newElement)
Definition: juce_Array.h:462
bool isEmpty() const noexcept
juce_wchar getAndAdvance() noexcept
int size() const noexcept
Definition: juce_Array.h:215
bool isEmpty() const noexcept
Definition: juce_String.h:296
String::CharPointerType text
ElementType & getReference(int index) noexcept
Definition: juce_Array.h:267
int compare(const CharPointer other) const noexcept
String getPooledString(const String &original)
int compare(const String &other) const noexcept
void remove(int indexToRemove)
Definition: juce_Array.h:767