OpenShot Library | OpenShotAudio  0.2.2
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 
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 
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
Wraps a pointer to a null-terminated UTF-8 character string, and provides various methods to operate ...
bool isEmpty() const noexcept
Returns true if this pointer is pointing to a null character.
Automatically locks and unlocks a mutex object.
A StringPool holds a set of shared strings, which reduces storage overheads and improves comparison s...
String getPooledString(const String &original)
Returns a pointer to a shared copy of the string that is passed in.
StringPool() noexcept
Creates an empty pool.
static StringPool & getGlobalPool() noexcept
Returns a shared global pool which is used for things like Identifiers, XML parsing.
void garbageCollect()
Scans the pool, and removes any strings that are unreferenced.
~StringPool()
Destructor.
A simple class for holding temporary references to a string literal or String.
String::CharPointerType text
The text that is referenced.
bool isEmpty() const noexcept
Returns true if the string is empty.
The JUCE String class!
Definition: juce_String.h:43
bool isEmpty() const noexcept
Returns true if the string contains no characters.
Definition: juce_String.h:300
CharPointer_UTF8 CharPointerType
This is the character encoding type used internally to store the string.
Definition: juce_String.h:164
static uint32 getApproximateMillisecondCounter() noexcept
Less-accurate but faster version of getMillisecondCounter().
Definition: juce_Time.cpp:246