OpenShot Library | libopenshot-audio 0.2.0
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
23namespace juce
24{
25
26static const int minNumberOfStringsForGarbageCollection = 300;
27static const uint32 garbageCollectionInterval = 30000;
28
29
30StringPool::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
41static int compareStrings (const String& s1, const String& s2) noexcept { return s1.compare (s2); }
42static int compareStrings (CharPointer_UTF8 s1, const String& s2) noexcept { return s1.compare (s2.getCharPointer()); }
43
44static 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
61template <typename NewStringType>
62static 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
101String 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
141void StringPool::garbageCollectIfNeeded()
142{
143 if (strings.size() > minNumberOfStringsForGarbageCollection
144 && Time::getApproximateMillisecondCounter() > lastGarbageCollectionTime + garbageCollectionInterval)
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.
CharPointer_UTF8 CharPointerType
This is the character encoding type used internally to store the string.
static uint32 getApproximateMillisecondCounter() noexcept
Less-accurate but faster version of getMillisecondCounter().