diff --git a/Builds/MacOSX/Juce.xcodeproj/project.pbxproj b/Builds/MacOSX/Juce.xcodeproj/project.pbxproj
index bdc7a33f95..767a7c7bfb 100644
--- a/Builds/MacOSX/Juce.xcodeproj/project.pbxproj
+++ b/Builds/MacOSX/Juce.xcodeproj/project.pbxproj
@@ -510,6 +510,7 @@
F77C9170829579FABA5679AD = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_DynamicObject.cpp; path = ../../src/containers/juce_DynamicObject.cpp; sourceTree = SOURCE_ROOT; };
34C402EF9ADCAD34FB657D43 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_DynamicObject.h; path = ../../src/containers/juce_DynamicObject.h; sourceTree = SOURCE_ROOT; };
7DA9AC75A4D9227C8FC4B2F7 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ElementComparator.h; path = ../../src/containers/juce_ElementComparator.h; sourceTree = SOURCE_ROOT; };
+ 2767E1D082874D301D5D5F43 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_HashMap.h; path = ../../src/containers/juce_HashMap.h; sourceTree = SOURCE_ROOT; };
9289A1E6B141F24C57FF0927 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_LinkedListPointer.h; path = ../../src/containers/juce_LinkedListPointer.h; sourceTree = SOURCE_ROOT; };
70E5409425A76782B6188B31 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_NamedValueSet.cpp; path = ../../src/containers/juce_NamedValueSet.cpp; sourceTree = SOURCE_ROOT; };
BB4A73064B0FC74ECCA19116 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_NamedValueSet.h; path = ../../src/containers/juce_NamedValueSet.h; sourceTree = SOURCE_ROOT; };
@@ -1269,6 +1270,7 @@
F77C9170829579FABA5679AD,
34C402EF9ADCAD34FB657D43,
7DA9AC75A4D9227C8FC4B2F7,
+ 2767E1D082874D301D5D5F43,
9289A1E6B141F24C57FF0927,
70E5409425A76782B6188B31,
BB4A73064B0FC74ECCA19116,
diff --git a/Builds/VisualStudio2005/Juce.vcproj b/Builds/VisualStudio2005/Juce.vcproj
index fab14b0980..718236acc0 100644
--- a/Builds/VisualStudio2005/Juce.vcproj
+++ b/Builds/VisualStudio2005/Juce.vcproj
@@ -353,6 +353,7 @@
+
diff --git a/Builds/VisualStudio2008/Juce.vcproj b/Builds/VisualStudio2008/Juce.vcproj
index 9a0253d194..fb049700b8 100644
--- a/Builds/VisualStudio2008/Juce.vcproj
+++ b/Builds/VisualStudio2008/Juce.vcproj
@@ -353,6 +353,7 @@
+
diff --git a/Builds/VisualStudio2008_DLL/Juce.vcproj b/Builds/VisualStudio2008_DLL/Juce.vcproj
index 0fd36807c4..5a932605aa 100644
--- a/Builds/VisualStudio2008_DLL/Juce.vcproj
+++ b/Builds/VisualStudio2008_DLL/Juce.vcproj
@@ -355,6 +355,7 @@
+
diff --git a/Builds/VisualStudio2010/Juce.vcxproj b/Builds/VisualStudio2010/Juce.vcxproj
index 449e951090..ef5c42f028 100644
--- a/Builds/VisualStudio2010/Juce.vcxproj
+++ b/Builds/VisualStudio2010/Juce.vcxproj
@@ -529,6 +529,7 @@
+
diff --git a/Builds/VisualStudio2010/Juce.vcxproj.filters b/Builds/VisualStudio2010/Juce.vcxproj.filters
index 408e162fdf..e83bf457fd 100644
--- a/Builds/VisualStudio2010/Juce.vcxproj.filters
+++ b/Builds/VisualStudio2010/Juce.vcxproj.filters
@@ -1521,6 +1521,9 @@
Juce\Source\containers
+
+ Juce\Source\containers
+
Juce\Source\containers
diff --git a/Builds/iOS/Juce.xcodeproj/project.pbxproj b/Builds/iOS/Juce.xcodeproj/project.pbxproj
index af9fd39e91..6545f2ed28 100644
--- a/Builds/iOS/Juce.xcodeproj/project.pbxproj
+++ b/Builds/iOS/Juce.xcodeproj/project.pbxproj
@@ -510,6 +510,7 @@
F77C9170829579FABA5679AD = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_DynamicObject.cpp; path = ../../src/containers/juce_DynamicObject.cpp; sourceTree = SOURCE_ROOT; };
34C402EF9ADCAD34FB657D43 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_DynamicObject.h; path = ../../src/containers/juce_DynamicObject.h; sourceTree = SOURCE_ROOT; };
7DA9AC75A4D9227C8FC4B2F7 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_ElementComparator.h; path = ../../src/containers/juce_ElementComparator.h; sourceTree = SOURCE_ROOT; };
+ 2767E1D082874D301D5D5F43 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_HashMap.h; path = ../../src/containers/juce_HashMap.h; sourceTree = SOURCE_ROOT; };
9289A1E6B141F24C57FF0927 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_LinkedListPointer.h; path = ../../src/containers/juce_LinkedListPointer.h; sourceTree = SOURCE_ROOT; };
70E5409425A76782B6188B31 = { isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = juce_NamedValueSet.cpp; path = ../../src/containers/juce_NamedValueSet.cpp; sourceTree = SOURCE_ROOT; };
BB4A73064B0FC74ECCA19116 = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = juce_NamedValueSet.h; path = ../../src/containers/juce_NamedValueSet.h; sourceTree = SOURCE_ROOT; };
@@ -1269,6 +1270,7 @@
F77C9170829579FABA5679AD,
34C402EF9ADCAD34FB657D43,
7DA9AC75A4D9227C8FC4B2F7,
+ 2767E1D082874D301D5D5F43,
9289A1E6B141F24C57FF0927,
70E5409425A76782B6188B31,
BB4A73064B0FC74ECCA19116,
diff --git a/Juce.jucer b/Juce.jucer
index e5fa60c9d6..a72368e3a6 100644
--- a/Juce.jucer
+++ b/Juce.jucer
@@ -365,6 +365,7 @@
file="src/containers/juce_DynamicObject.h"/>
+
+class ScopedPointer
{
public:
- /** Creates an empty string array */
- StringArray() throw();
+ /** Creates a ScopedPointer containing a null pointer. */
+ inline ScopedPointer() throw() : object (0)
+ {
+ }
- /** Creates a copy of another string array */
- StringArray (const StringArray& other);
+ /** Creates a ScopedPointer that owns the specified object. */
+ inline ScopedPointer (ObjectType* const objectToTakePossessionOf) throw()
+ : object (objectToTakePossessionOf)
+ {
+ }
- /** Creates an array containing a single string. */
- explicit StringArray (const String& firstValue);
+ /** Creates a ScopedPointer that takes its pointer from another ScopedPointer.
- /** Creates a copy of an array of string literals.
- @param strings an array of strings to add. Null pointers in the array will be
- treated as empty strings
- @param numberOfStrings how many items there are in the array
+ Because a pointer can only belong to one ScopedPointer, this transfers
+ the pointer from the other object to this one, and the other object is reset to
+ be a null pointer.
*/
- StringArray (const char* const* strings, int numberOfStrings);
-
- /** Creates a copy of a null-terminated array of string literals.
+ ScopedPointer (ScopedPointer& objectToTransferFrom) throw()
+ : object (objectToTransferFrom.object)
+ {
+ objectToTransferFrom.object = 0;
+ }
- Each item from the array passed-in is added, until it encounters a null pointer,
- at which point it stops.
+ /** Destructor.
+ This will delete the object that this ScopedPointer currently refers to.
*/
- explicit StringArray (const char* const* strings);
+ inline ~ScopedPointer() { delete object; }
- /** Creates a copy of a null-terminated array of string literals.
- Each item from the array passed-in is added, until it encounters a null pointer,
- at which point it stops.
- */
- explicit StringArray (const wchar_t* const* strings);
+ /** Changes this ScopedPointer to point to a new object.
- /** Creates a copy of an array of string literals.
- @param strings an array of strings to add. Null pointers in the array will be
- treated as empty strings
- @param numberOfStrings how many items there are in the array
+ Because a pointer can only belong to one ScopedPointer, this transfers
+ the pointer from the other object to this one, and the other object is reset to
+ be a null pointer.
+
+ If this ScopedPointer already points to an object, that object
+ will first be deleted.
*/
- StringArray (const wchar_t* const* strings, int numberOfStrings);
+ ScopedPointer& operator= (ScopedPointer& objectToTransferFrom)
+ {
+ if (this != objectToTransferFrom.getAddress())
+ {
+ // Two ScopedPointers should never be able to refer to the same object - if
+ // this happens, you must have done something dodgy!
+ jassert (object == 0 || object != objectToTransferFrom.object);
- /** Destructor. */
- ~StringArray();
+ ObjectType* const oldObject = object;
+ object = objectToTransferFrom.object;
+ objectToTransferFrom.object = 0;
+ delete oldObject;
+ }
- /** Copies the contents of another string array into this one */
- StringArray& operator= (const StringArray& other);
+ return *this;
+ }
- /** Compares two arrays.
- Comparisons are case-sensitive.
- @returns true only if the other array contains exactly the same strings in the same order
- */
- bool operator== (const StringArray& other) const throw();
+ /** Changes this ScopedPointer to point to a new object.
- /** Compares two arrays.
- Comparisons are case-sensitive.
- @returns false if the other array contains exactly the same strings in the same order
+ If this ScopedPointer already points to an object, that object
+ will first be deleted.
+
+ The pointer that you pass is may be null.
*/
- bool operator!= (const StringArray& other) const throw();
+ ScopedPointer& operator= (ObjectType* const newObjectToTakePossessionOf)
+ {
+ if (object != newObjectToTakePossessionOf)
+ {
+ ObjectType* const oldObject = object;
+ object = newObjectToTakePossessionOf;
+ delete oldObject;
+ }
- /** Returns the number of strings in the array */
- inline int size() const throw() { return strings.size(); };
+ return *this;
+ }
- /** Returns one of the strings from the array.
+ /** Returns the object that this ScopedPointer refers to. */
+ inline operator ObjectType*() const throw() { return object; }
- If the index is out-of-range, an empty string is returned.
+ /** Returns the object that this ScopedPointer refers to. */
+ inline ObjectType& operator*() const throw() { return *object; }
- Obviously the reference returned shouldn't be stored for later use, as the
- string it refers to may disappear when the array changes.
- */
- const String& operator[] (int index) const throw();
+ /** Lets you access methods and properties of the object that this ScopedPointer refers to. */
+ inline ObjectType* operator->() const throw() { return object; }
- /** Returns a reference to one of the strings in the array.
- This lets you modify a string in-place in the array, but you must be sure that
- the index is in-range.
+ /** Removes the current object from this ScopedPointer without deleting it.
+ This will return the current object, and set the ScopedPointer to a null pointer.
*/
- String& getReference (int index) throw();
-
- /** Searches for a string in the array.
-
- The comparison will be case-insensitive if the ignoreCase parameter is true.
+ ObjectType* release() throw() { ObjectType* const o = object; object = 0; return o; }
- @returns true if the string is found inside the array
+ /** Swaps this object with that of another ScopedPointer.
+ The two objects simply exchange their pointers.
*/
- bool contains (const String& stringToLookFor,
- bool ignoreCase = false) const;
+ void swapWith (ScopedPointer & other) throw()
+ {
+ // Two ScopedPointers should never be able to refer to the same object - if
+ // this happens, you must have done something dodgy!
+ jassert (object != other.object);
- /** Searches for a string in the array.
+ swapVariables (object, other.object);
+ }
- The comparison will be case-insensitive if the ignoreCase parameter is true.
+private:
- @param stringToLookFor the string to try to find
- @param ignoreCase whether the comparison should be case-insensitive
- @param startIndex the first index to start searching from
- @returns the index of the first occurrence of the string in this array,
- or -1 if it isn't found.
- */
- int indexOf (const String& stringToLookFor,
- bool ignoreCase = false,
- int startIndex = 0) const;
+ ObjectType* object;
- /** Appends a string at the end of the array. */
- void add (const String& stringToAdd);
+ // (Required as an alternative to the overloaded & operator).
+ const ScopedPointer* getAddress() const throw() { return this; }
- /** Inserts a string into the array.
+ #if ! JUCE_MSVC // (MSVC can't deal with multiple copy constructors)
+ /* This is private to stop people accidentally copying a const ScopedPointer (the compiler
+ would let you do so by implicitly casting the source to its raw object pointer).
- This will insert a string into the array at the given index, moving
- up the other elements to make room for it.
- If the index is less than zero or greater than the size of the array,
- the new string will be added to the end of the array.
- */
- void insert (int index, const String& stringToAdd);
+ A side effect of this is that you may hit a puzzling compiler error when you write something
+ like this:
- /** Adds a string to the array as long as it's not already in there.
+ ScopedPointer m = new MyClass(); // Compile error: copy constructor is private.
- The search can optionally be case-insensitive.
- */
- void addIfNotAlreadyThere (const String& stringToAdd, bool ignoreCase = false);
+ Even though the compiler would normally ignore the assignment here, it can't do so when the
+ copy constructor is private. It's very easy to fis though - just write it like this:
- /** Replaces one of the strings in the array with another one.
+ ScopedPointer m (new MyClass()); // Compiles OK
- If the index is higher than the array's size, the new string will be
- added to the end of the array; if it's less than zero nothing happens.
+ It's good practice to always use the latter form when writing your object declarations anyway,
+ rather than writing them as assignments and assuming (or hoping) that the compiler will be
+ smart enough to replace your construction + assignment with a single constructor.
*/
- void set (int index, const String& newString);
+ ScopedPointer (const ScopedPointer&);
+ #endif
+};
- /** Appends some strings from another array to the end of this one.
+/** Compares a ScopedPointer with another pointer.
+ This can be handy for checking whether this is a null pointer.
+*/
+template
+bool operator== (const ScopedPointer& pointer1, ObjectType* const pointer2) throw()
+{
+ return static_cast (pointer1) == pointer2;
+}
- @param other the array to add
- @param startIndex the first element of the other array to add
- @param numElementsToAdd the maximum number of elements to add (if this is
- less than zero, they are all added)
- */
- void addArray (const StringArray& other,
- int startIndex = 0,
- int numElementsToAdd = -1);
+/** Compares a ScopedPointer with another pointer.
+ This can be handy for checking whether this is a null pointer.
+*/
+template
+bool operator!= (const ScopedPointer& pointer1, ObjectType* const pointer2) throw()
+{
+ return static_cast (pointer1) != pointer2;
+}
- /** Breaks up a string into tokens and adds them to this array.
+#endif // __JUCE_SCOPEDPOINTER_JUCEHEADER__
+/*** End of inlined file: juce_ScopedPointer.h ***/
- This will tokenise the given string using whitespace characters as the
- token delimiters, and will add these tokens to the end of the array.
+/**
+ A simple class to generate hash functions for some primitive types, intended for
+ use with the HashMap class.
+ @see HashMap
+*/
+class DefaultHashFunctions
+{
+public:
+ /** Generates a simple hash from an integer. */
+ static int generateHash (const int key, const int upperLimit) throw() { return std::abs (key) % upperLimit; }
+ /** Generates a simple hash from a string. */
+ static int generateHash (const String& key, const int upperLimit) throw() { return key.hashCode() % upperLimit; }
+ /** Generates a simple hash from a variant. */
+ static int generateHash (const var& key, const int upperLimit) throw() { return generateHash (key.toString(), upperLimit); }
+};
+
+/**
+ Holds a set of mappings between some key/value pairs.
+
+ The types of the key and value objects are set as template parameters.
+ You can also specify a class to supply a hash function that converts a key value
+ into an hashed integer. This class must have the form:
+
+ @code
+ struct MyHashGenerator
+ {
+ static int generateHash (MyKeyType key, int upperLimit)
+ {
+ // The function must return a value 0 <= x < upperLimit
+ return someFunctionOfMyKeyType (key) % upperLimit;
+ }
+ };
+ @endcode
+
+ Like the Array class, the key and value types are expected to be copy-by-value types, so
+ if you define them to be pointer types, this class won't delete the objects that they
+ point to.
+
+ If you don't supply a class for the HashFunctionToUse template parameter, the
+ default one provides some simple mappings for strings and ints.
+
+ @code
+ HashMap hash;
+ hash.set (1, "item1");
+ hash.set (2, "item2");
+
+ DBG (hash [1]); // prints "item1"
+ DBG (hash [2]); // prints "item2"
+
+ // This iterates the map, printing all of its key -> value pairs..
+ for (HashMap::Iterator i (hash); i.next();)
+ DBG (i.getKey() << " -> " << i.getValue());
+ @endcode
+
+ @see CriticalSection, DefaultHashFunctions, NamedValueSet, SortedSet
+*/
+template
+class HashMap
+{
+private:
+ typedef PARAMETER_TYPE (KeyType) KeyTypeParameter;
+ typedef PARAMETER_TYPE (ValueType) ValueTypeParameter;
+
+public:
+
+ /** Creates an empty hash-map.
+
+ The numberOfSlots parameter specifies the number of hash entries the map will use. This
+ will be the "upperLimit" parameter that is passed to your generateHash() function. The number
+ of hash slots will grow automatically if necessary, or it can be remapped manually using remapTable().
+ */
+ HashMap (const int numberOfSlots = defaultHashTableSize)
+ : totalNumItems (0)
+ {
+ slots.insertMultiple (0, 0, numberOfSlots);
+ }
+
+ /** Destructor. */
+ ~HashMap()
+ {
+ clear();
+ }
+
+ /** Removes all values from the map.
+ Note that this will clear the content, but won't affect the number of slots (see
+ remapTable and getNumSlots).
+ */
+ void clear()
+ {
+ const ScopedLockType sl (getLock());
+
+ for (int i = slots.size(); --i >= 0;)
+ {
+ HashEntry* h = slots.getUnchecked(i);
+
+ while (h != 0)
+ {
+ const ScopedPointer deleter (h);
+ h = h->nextEntry;
+ }
+
+ slots.set (i, 0);
+ }
+
+ totalNumItems = 0;
+ }
+
+ /** Returns the current number of items in the map. */
+ inline int size() const throw()
+ {
+ return totalNumItems;
+ }
+
+ /** Returns the value corresponding to a given key.
+ If the map doesn't contain the key, a default instance of the value type is returned.
+ @param keyToLookFor the key of the item being requested
+ */
+ inline const ValueType operator[] (KeyTypeParameter keyToLookFor) const
+ {
+ const ScopedLockType sl (getLock());
+
+ for (const HashEntry* entry = slots [generateHashFor (keyToLookFor)]; entry != 0; entry = entry->nextEntry)
+ if (entry->key == keyToLookFor)
+ return entry->value;
+
+ return ValueType();
+ }
+
+ /** Returns true if the map contains an item with the specied key. */
+ bool contains (KeyTypeParameter keyToLookFor) const
+ {
+ const ScopedLockType sl (getLock());
+
+ for (const HashEntry* entry = slots [generateHashFor (keyToLookFor)]; entry != 0; entry = entry->nextEntry)
+ if (entry->key == keyToLookFor)
+ return true;
+
+ return false;
+ }
+
+ /** Returns true if the hash contains at least one occurrence of a given value. */
+ bool containsValue (ValueTypeParameter valueToLookFor) const
+ {
+ const ScopedLockType sl (getLock());
+
+ for (int i = getNumSlots(); --i >= 0;)
+ for (const HashEntry* entry = slots.getUnchecked(i); entry != 0; entry = entry->nextEntry)
+ if (entry->value == valueToLookFor)
+ return true;
+
+ return false;
+ }
+
+ /** Adds or replaces an element in the hash-map.
+ If there's already an item with the given key, this will replace its value. Otherwise, a new item
+ will be added to the map.
+ */
+ void set (KeyTypeParameter newKey, ValueTypeParameter newValue)
+ {
+ const ScopedLockType sl (getLock());
+ const int hashIndex = generateHashFor (newKey);
+
+ if (isPositiveAndBelow (hashIndex, getNumSlots()))
+ {
+ HashEntry* const firstEntry = slots.getUnchecked (hashIndex);
+
+ for (HashEntry* entry = firstEntry; entry != 0; entry = entry->nextEntry)
+ {
+ if (entry->key == newKey)
+ {
+ entry->value = newValue;
+ return;
+ }
+ }
+
+ slots.set (hashIndex, new HashEntry (newKey, newValue, firstEntry));
+ ++totalNumItems;
+
+ if (totalNumItems > (getNumSlots() * 3) / 2)
+ remapTable (getNumSlots() * 2);
+ }
+ }
+
+ /** Removes an item with the given key. */
+ void remove (KeyTypeParameter keyToRemove)
+ {
+ const ScopedLockType sl (getLock());
+ const int hashIndex = generateHashFor (keyToRemove);
+ HashEntry* entry = slots [hashIndex];
+ HashEntry* previous = 0;
+
+ while (entry != 0)
+ {
+ if (entry->key == keyToRemove)
+ {
+ const ScopedPointer deleter (entry);
+
+ entry = entry->nextEntry;
+
+ if (previous != 0)
+ previous->nextEntry = entry;
+ else
+ slots.set (hashIndex, entry);
+
+ --totalNumItems;
+ }
+ else
+ {
+ previous = entry;
+ entry = entry->nextEntry;
+ }
+ }
+ }
+
+ /** Removes all items with the given value. */
+ void removeValue (ValueTypeParameter valueToRemove)
+ {
+ const ScopedLockType sl (getLock());
+
+ for (int i = getNumSlots(); --i >= 0;)
+ {
+ HashEntry* entry = slots.getUnchecked(i);
+ HashEntry* previous = 0;
+
+ while (entry != 0)
+ {
+ if (entry->value == valueToRemove)
+ {
+ const ScopedPointer deleter (entry);
+
+ entry = entry->nextEntry;
+
+ if (previous != 0)
+ previous->nextEntry = entry;
+ else
+ slots.set (i, entry);
+
+ --totalNumItems;
+ }
+ else
+ {
+ previous = entry;
+ entry = entry->nextEntry;
+ }
+ }
+ }
+ }
+
+ /** Remaps the hash-map to use a different number of slots for its hash function.
+ Each slot corresponds to a single hash-code, and each one can contain multiple items.
+ @see getNumSlots()
+ */
+ void remapTable (int newNumberOfSlots)
+ {
+ HashMap newTable (newNumberOfSlots);
+
+ for (int i = getNumSlots(); --i >= 0;)
+ for (const HashEntry* entry = slots.getUnchecked(i); entry != 0; entry = entry->nextEntry)
+ newTable.set (entry->key, entry->value);
+
+ swapWith (newTable);
+ }
+
+ /** Returns the number of slots which are available for hashing.
+ Each slot corresponds to a single hash-code, and each one can contain multiple items.
+ @see getNumSlots()
+ */
+ inline int getNumSlots() const throw()
+ {
+ return slots.size();
+ }
+
+ /** Efficiently swaps the contents of two hash-maps. */
+ void swapWith (HashMap& otherHashMap) throw()
+ {
+ const ScopedLockType lock1 (getLock());
+ const ScopedLockType lock2 (otherHashMap.getLock());
+
+ slots.swapWithArray (otherHashMap.slots);
+ swapVariables (totalNumItems, otherHashMap.totalNumItems);
+ }
+
+ /** Returns the CriticalSection that locks this structure.
+ To lock, you can call getLock().enter() and getLock().exit(), or preferably use
+ an object of ScopedLockType as an RAII lock for it.
+ */
+ inline const TypeOfCriticalSectionToUse& getLock() const throw() { return lock; }
+
+ /** Returns the type of scoped lock to use for locking this array */
+ typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
+
+private:
+
+ class HashEntry
+ {
+ public:
+ HashEntry (KeyTypeParameter key_, ValueTypeParameter value_, HashEntry* const nextEntry_)
+ : key (key_), value (value_), nextEntry (nextEntry_)
+ {}
+
+ const KeyType key;
+ ValueType value;
+ HashEntry* nextEntry;
+
+ JUCE_DECLARE_NON_COPYABLE (HashEntry);
+ };
+
+public:
+
+ /** Iterates over the items in a HashMap.
+
+ To use it, repeatedly call next() until it returns false, e.g.
+ @code
+ HashMap myMap;
+
+ HashMap::Iterator i (myMap);
+
+ while (i.next())
+ {
+ DBG (i.getKey() << " -> " << i.getValue());
+ }
+ @endcode
+
+ The order in which items are iterated bears no resemblence to the order in which
+ they were originally added!
+
+ Obviously as soon as you call any non-const methods on the original hash-map, any
+ iterators that were created beforehand will cease to be valid, and should not be used.
+
+ @see HashMap
+ */
+ class Iterator
+ {
+ public:
+
+ Iterator (const HashMap& hashMapToIterate)
+ : hashMap (hashMapToIterate), entry (0), index (0)
+ {}
+
+ /** Moves to the next item, if one is available.
+ When this returns true, you can get the item's key and value using getKey() and
+ getValue(). If it returns false, the iteration has finished and you should stop.
+ */
+ bool next()
+ {
+ if (entry != 0)
+ entry = entry->nextEntry;
+
+ while (entry == 0)
+ {
+ if (index >= hashMap.getNumSlots())
+ return false;
+
+ entry = hashMap.slots.getUnchecked (index++);
+ }
+
+ return true;
+ }
+
+ /** Returns the current item's key.
+ This should only be called when a call to next() has just returned true.
+ */
+ const KeyType getKey() const
+ {
+ return entry != 0 ? entry->key : KeyType();
+ }
+
+ /** Returns the current item's value.
+ This should only be called when a call to next() has just returned true.
+ */
+ const ValueType getValue() const
+ {
+ return entry != 0 ? entry->value : ValueType();
+ }
+
+ private:
+
+ const HashMap& hashMap;
+ HashEntry* entry;
+ int index;
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Iterator);
+ };
+
+private:
+
+ enum { defaultHashTableSize = 101 };
+ friend class Iterator;
+
+ Array slots;
+ int totalNumItems;
+ TypeOfCriticalSectionToUse lock;
+
+ int generateHashFor (KeyTypeParameter key) const
+ {
+ const int hash = HashFunctionToUse::generateHash (key, getNumSlots());
+ jassert (isPositiveAndBelow (hash, getNumSlots())); // your hash function is generating out-of-range numbers!
+ return hash;
+ }
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HashMap);
+};
+
+#endif // __JUCE_HASHMAP_JUCEHEADER__
+/*** End of inlined file: juce_HashMap.h ***/
+
+
+#endif
+#ifndef __JUCE_LINKEDLISTPOINTER_JUCEHEADER__
+
+#endif
+#ifndef __JUCE_NAMEDVALUESET_JUCEHEADER__
+
+#endif
+#ifndef __JUCE_OWNEDARRAY_JUCEHEADER__
+
+#endif
+#ifndef __JUCE_PROPERTYSET_JUCEHEADER__
+
+/*** Start of inlined file: juce_PropertySet.h ***/
+#ifndef __JUCE_PROPERTYSET_JUCEHEADER__
+#define __JUCE_PROPERTYSET_JUCEHEADER__
+
+
+/*** Start of inlined file: juce_StringPairArray.h ***/
+#ifndef __JUCE_STRINGPAIRARRAY_JUCEHEADER__
+#define __JUCE_STRINGPAIRARRAY_JUCEHEADER__
+
+
+/*** Start of inlined file: juce_StringArray.h ***/
+#ifndef __JUCE_STRINGARRAY_JUCEHEADER__
+#define __JUCE_STRINGARRAY_JUCEHEADER__
+
+/**
+ A special array for holding a list of strings.
+
+ @see String, StringPairArray
+*/
+class JUCE_API StringArray
+{
+public:
+
+ /** Creates an empty string array */
+ StringArray() throw();
+
+ /** Creates a copy of another string array */
+ StringArray (const StringArray& other);
+
+ /** Creates an array containing a single string. */
+ explicit StringArray (const String& firstValue);
+
+ /** Creates a copy of an array of string literals.
+ @param strings an array of strings to add. Null pointers in the array will be
+ treated as empty strings
+ @param numberOfStrings how many items there are in the array
+ */
+ StringArray (const char* const* strings, int numberOfStrings);
+
+ /** Creates a copy of a null-terminated array of string literals.
+
+ Each item from the array passed-in is added, until it encounters a null pointer,
+ at which point it stops.
+ */
+ explicit StringArray (const char* const* strings);
+
+ /** Creates a copy of a null-terminated array of string literals.
+ Each item from the array passed-in is added, until it encounters a null pointer,
+ at which point it stops.
+ */
+ explicit StringArray (const wchar_t* const* strings);
+
+ /** Creates a copy of an array of string literals.
+ @param strings an array of strings to add. Null pointers in the array will be
+ treated as empty strings
+ @param numberOfStrings how many items there are in the array
+ */
+ StringArray (const wchar_t* const* strings, int numberOfStrings);
+
+ /** Destructor. */
+ ~StringArray();
+
+ /** Copies the contents of another string array into this one */
+ StringArray& operator= (const StringArray& other);
+
+ /** Compares two arrays.
+ Comparisons are case-sensitive.
+ @returns true only if the other array contains exactly the same strings in the same order
+ */
+ bool operator== (const StringArray& other) const throw();
+
+ /** Compares two arrays.
+ Comparisons are case-sensitive.
+ @returns false if the other array contains exactly the same strings in the same order
+ */
+ bool operator!= (const StringArray& other) const throw();
+
+ /** Returns the number of strings in the array */
+ inline int size() const throw() { return strings.size(); };
+
+ /** Returns one of the strings from the array.
+
+ If the index is out-of-range, an empty string is returned.
+
+ Obviously the reference returned shouldn't be stored for later use, as the
+ string it refers to may disappear when the array changes.
+ */
+ const String& operator[] (int index) const throw();
+
+ /** Returns a reference to one of the strings in the array.
+ This lets you modify a string in-place in the array, but you must be sure that
+ the index is in-range.
+ */
+ String& getReference (int index) throw();
+
+ /** Searches for a string in the array.
+
+ The comparison will be case-insensitive if the ignoreCase parameter is true.
+
+ @returns true if the string is found inside the array
+ */
+ bool contains (const String& stringToLookFor,
+ bool ignoreCase = false) const;
+
+ /** Searches for a string in the array.
+
+ The comparison will be case-insensitive if the ignoreCase parameter is true.
+
+ @param stringToLookFor the string to try to find
+ @param ignoreCase whether the comparison should be case-insensitive
+ @param startIndex the first index to start searching from
+ @returns the index of the first occurrence of the string in this array,
+ or -1 if it isn't found.
+ */
+ int indexOf (const String& stringToLookFor,
+ bool ignoreCase = false,
+ int startIndex = 0) const;
+
+ /** Appends a string at the end of the array. */
+ void add (const String& stringToAdd);
+
+ /** Inserts a string into the array.
+
+ This will insert a string into the array at the given index, moving
+ up the other elements to make room for it.
+ If the index is less than zero or greater than the size of the array,
+ the new string will be added to the end of the array.
+ */
+ void insert (int index, const String& stringToAdd);
+
+ /** Adds a string to the array as long as it's not already in there.
+
+ The search can optionally be case-insensitive.
+ */
+ void addIfNotAlreadyThere (const String& stringToAdd, bool ignoreCase = false);
+
+ /** Replaces one of the strings in the array with another one.
+
+ If the index is higher than the array's size, the new string will be
+ added to the end of the array; if it's less than zero nothing happens.
+ */
+ void set (int index, const String& newString);
+
+ /** Appends some strings from another array to the end of this one.
+
+ @param other the array to add
+ @param startIndex the first element of the other array to add
+ @param numElementsToAdd the maximum number of elements to add (if this is
+ less than zero, they are all added)
+ */
+ void addArray (const StringArray& other,
+ int startIndex = 0,
+ int numElementsToAdd = -1);
+
+ /** Breaks up a string into tokens and adds them to this array.
+
+ This will tokenise the given string using whitespace characters as the
+ token delimiters, and will add these tokens to the end of the array.
@returns the number of tokens added
*/
@@ -11038,186 +11631,6 @@ JUCE_API bool operator>= (const Time& time1, const Time& time2);
#endif // __JUCE_TIME_JUCEHEADER__
/*** End of inlined file: juce_Time.h ***/
-
-/*** Start of inlined file: juce_ScopedPointer.h ***/
-#ifndef __JUCE_SCOPEDPOINTER_JUCEHEADER__
-#define __JUCE_SCOPEDPOINTER_JUCEHEADER__
-
-/**
- This class holds a pointer which is automatically deleted when this object goes
- out of scope.
-
- Once a pointer has been passed to a ScopedPointer, it will make sure that the pointer
- gets deleted when the ScopedPointer is deleted. Using the ScopedPointer on the stack or
- as member variables is a good way to use RAII to avoid accidentally leaking dynamically
- created objects.
-
- A ScopedPointer can be used in pretty much the same way that you'd use a normal pointer
- to an object. If you use the assignment operator to assign a different object to a
- ScopedPointer, the old one will be automatically deleted.
-
- A const ScopedPointer is guaranteed not to lose ownership of its object or change the
- object to which it points during its lifetime. This means that making a copy of a const
- ScopedPointer is impossible, as that would involve the new copy taking ownership from the
- old one.
-
- If you need to get a pointer out of a ScopedPointer without it being deleted, you
- can use the release() method.
-*/
-template
-class ScopedPointer
-{
-public:
-
- /** Creates a ScopedPointer containing a null pointer. */
- inline ScopedPointer() throw() : object (0)
- {
- }
-
- /** Creates a ScopedPointer that owns the specified object. */
- inline ScopedPointer (ObjectType* const objectToTakePossessionOf) throw()
- : object (objectToTakePossessionOf)
- {
- }
-
- /** Creates a ScopedPointer that takes its pointer from another ScopedPointer.
-
- Because a pointer can only belong to one ScopedPointer, this transfers
- the pointer from the other object to this one, and the other object is reset to
- be a null pointer.
- */
- ScopedPointer (ScopedPointer& objectToTransferFrom) throw()
- : object (objectToTransferFrom.object)
- {
- objectToTransferFrom.object = 0;
- }
-
- /** Destructor.
- This will delete the object that this ScopedPointer currently refers to.
- */
- inline ~ScopedPointer() { delete object; }
-
- /** Changes this ScopedPointer to point to a new object.
-
- Because a pointer can only belong to one ScopedPointer, this transfers
- the pointer from the other object to this one, and the other object is reset to
- be a null pointer.
-
- If this ScopedPointer already points to an object, that object
- will first be deleted.
- */
- ScopedPointer& operator= (ScopedPointer& objectToTransferFrom)
- {
- if (this != objectToTransferFrom.getAddress())
- {
- // Two ScopedPointers should never be able to refer to the same object - if
- // this happens, you must have done something dodgy!
- jassert (object == 0 || object != objectToTransferFrom.object);
-
- ObjectType* const oldObject = object;
- object = objectToTransferFrom.object;
- objectToTransferFrom.object = 0;
- delete oldObject;
- }
-
- return *this;
- }
-
- /** Changes this ScopedPointer to point to a new object.
-
- If this ScopedPointer already points to an object, that object
- will first be deleted.
-
- The pointer that you pass is may be null.
- */
- ScopedPointer& operator= (ObjectType* const newObjectToTakePossessionOf)
- {
- if (object != newObjectToTakePossessionOf)
- {
- ObjectType* const oldObject = object;
- object = newObjectToTakePossessionOf;
- delete oldObject;
- }
-
- return *this;
- }
-
- /** Returns the object that this ScopedPointer refers to. */
- inline operator ObjectType*() const throw() { return object; }
-
- /** Returns the object that this ScopedPointer refers to. */
- inline ObjectType& operator*() const throw() { return *object; }
-
- /** Lets you access methods and properties of the object that this ScopedPointer refers to. */
- inline ObjectType* operator->() const throw() { return object; }
-
- /** Removes the current object from this ScopedPointer without deleting it.
- This will return the current object, and set the ScopedPointer to a null pointer.
- */
- ObjectType* release() throw() { ObjectType* const o = object; object = 0; return o; }
-
- /** Swaps this object with that of another ScopedPointer.
- The two objects simply exchange their pointers.
- */
- void swapWith (ScopedPointer & other) throw()
- {
- // Two ScopedPointers should never be able to refer to the same object - if
- // this happens, you must have done something dodgy!
- jassert (object != other.object);
-
- swapVariables (object, other.object);
- }
-
-private:
-
- ObjectType* object;
-
- // (Required as an alternative to the overloaded & operator).
- const ScopedPointer* getAddress() const throw() { return this; }
-
- #if ! JUCE_MSVC // (MSVC can't deal with multiple copy constructors)
- /* This is private to stop people accidentally copying a const ScopedPointer (the compiler
- would let you do so by implicitly casting the source to its raw object pointer).
-
- A side effect of this is that you may hit a puzzling compiler error when you write something
- like this:
-
- ScopedPointer m = new MyClass(); // Compile error: copy constructor is private.
-
- Even though the compiler would normally ignore the assignment here, it can't do so when the
- copy constructor is private. It's very easy to fis though - just write it like this:
-
- ScopedPointer m (new MyClass()); // Compiles OK
-
- It's good practice to always use the latter form when writing your object declarations anyway,
- rather than writing them as assignments and assuming (or hoping) that the compiler will be
- smart enough to replace your construction + assignment with a single constructor.
- */
- ScopedPointer (const ScopedPointer&);
- #endif
-};
-
-/** Compares a ScopedPointer with another pointer.
- This can be handy for checking whether this is a null pointer.
-*/
-template
-bool operator== (const ScopedPointer& pointer1, ObjectType* const pointer2) throw()
-{
- return static_cast (pointer1) == pointer2;
-}
-
-/** Compares a ScopedPointer with another pointer.
- This can be handy for checking whether this is a null pointer.
-*/
-template
-bool operator!= (const ScopedPointer& pointer1, ObjectType* const pointer2) throw()
-{
- return static_cast (pointer1) != pointer2;
-}
-
-#endif // __JUCE_SCOPEDPOINTER_JUCEHEADER__
-/*** End of inlined file: juce_ScopedPointer.h ***/
-
class FileInputStream;
class FileOutputStream;
diff --git a/src/containers/juce_Array.h b/src/containers/juce_Array.h
index 231d450bdd..964c4cfcf0 100644
--- a/src/containers/juce_Array.h
+++ b/src/containers/juce_Array.h
@@ -60,11 +60,7 @@ template hash;
+ hash.set (1, "item1");
+ hash.set (2, "item2");
+
+ DBG (hash [1]); // prints "item1"
+ DBG (hash [2]); // prints "item2"
+
+ // This iterates the map, printing all of its key -> value pairs..
+ for (HashMap::Iterator i (hash); i.next();)
+ DBG (i.getKey() << " -> " << i.getValue());
+ @endcode
+
+ @see CriticalSection, DefaultHashFunctions, NamedValueSet, SortedSet
+*/
+template
+class HashMap
+{
+private:
+ typedef PARAMETER_TYPE (KeyType) KeyTypeParameter;
+ typedef PARAMETER_TYPE (ValueType) ValueTypeParameter;
+
+public:
+ //==============================================================================
+ /** Creates an empty hash-map.
+
+ The numberOfSlots parameter specifies the number of hash entries the map will use. This
+ will be the "upperLimit" parameter that is passed to your generateHash() function. The number
+ of hash slots will grow automatically if necessary, or it can be remapped manually using remapTable().
+ */
+ HashMap (const int numberOfSlots = defaultHashTableSize)
+ : totalNumItems (0)
+ {
+ slots.insertMultiple (0, 0, numberOfSlots);
+ }
+
+ /** Destructor. */
+ ~HashMap()
+ {
+ clear();
+ }
+
+ //==============================================================================
+ /** Removes all values from the map.
+ Note that this will clear the content, but won't affect the number of slots (see
+ remapTable and getNumSlots).
+ */
+ void clear()
+ {
+ const ScopedLockType sl (getLock());
+
+ for (int i = slots.size(); --i >= 0;)
+ {
+ HashEntry* h = slots.getUnchecked(i);
+
+ while (h != 0)
+ {
+ const ScopedPointer deleter (h);
+ h = h->nextEntry;
+ }
+
+ slots.set (i, 0);
+ }
+
+ totalNumItems = 0;
+ }
+
+ //==============================================================================
+ /** Returns the current number of items in the map. */
+ inline int size() const throw()
+ {
+ return totalNumItems;
+ }
+
+ /** Returns the value corresponding to a given key.
+ If the map doesn't contain the key, a default instance of the value type is returned.
+ @param keyToLookFor the key of the item being requested
+ */
+ inline const ValueType operator[] (KeyTypeParameter keyToLookFor) const
+ {
+ const ScopedLockType sl (getLock());
+
+ for (const HashEntry* entry = slots [generateHashFor (keyToLookFor)]; entry != 0; entry = entry->nextEntry)
+ if (entry->key == keyToLookFor)
+ return entry->value;
+
+ return ValueType();
+ }
+
+ //==============================================================================
+ /** Returns true if the map contains an item with the specied key. */
+ bool contains (KeyTypeParameter keyToLookFor) const
+ {
+ const ScopedLockType sl (getLock());
+
+ for (const HashEntry* entry = slots [generateHashFor (keyToLookFor)]; entry != 0; entry = entry->nextEntry)
+ if (entry->key == keyToLookFor)
+ return true;
+
+ return false;
+ }
+
+ /** Returns true if the hash contains at least one occurrence of a given value. */
+ bool containsValue (ValueTypeParameter valueToLookFor) const
+ {
+ const ScopedLockType sl (getLock());
+
+ for (int i = getNumSlots(); --i >= 0;)
+ for (const HashEntry* entry = slots.getUnchecked(i); entry != 0; entry = entry->nextEntry)
+ if (entry->value == valueToLookFor)
+ return true;
+
+ return false;
+ }
+
+ //==============================================================================
+ /** Adds or replaces an element in the hash-map.
+ If there's already an item with the given key, this will replace its value. Otherwise, a new item
+ will be added to the map.
+ */
+ void set (KeyTypeParameter newKey, ValueTypeParameter newValue)
+ {
+ const ScopedLockType sl (getLock());
+ const int hashIndex = generateHashFor (newKey);
+
+ if (isPositiveAndBelow (hashIndex, getNumSlots()))
+ {
+ HashEntry* const firstEntry = slots.getUnchecked (hashIndex);
+
+ for (HashEntry* entry = firstEntry; entry != 0; entry = entry->nextEntry)
+ {
+ if (entry->key == newKey)
+ {
+ entry->value = newValue;
+ return;
+ }
+ }
+
+ slots.set (hashIndex, new HashEntry (newKey, newValue, firstEntry));
+ ++totalNumItems;
+
+ if (totalNumItems > (getNumSlots() * 3) / 2)
+ remapTable (getNumSlots() * 2);
+ }
+ }
+
+ /** Removes an item with the given key. */
+ void remove (KeyTypeParameter keyToRemove)
+ {
+ const ScopedLockType sl (getLock());
+ const int hashIndex = generateHashFor (keyToRemove);
+ HashEntry* entry = slots [hashIndex];
+ HashEntry* previous = 0;
+
+ while (entry != 0)
+ {
+ if (entry->key == keyToRemove)
+ {
+ const ScopedPointer deleter (entry);
+
+ entry = entry->nextEntry;
+
+ if (previous != 0)
+ previous->nextEntry = entry;
+ else
+ slots.set (hashIndex, entry);
+
+ --totalNumItems;
+ }
+ else
+ {
+ previous = entry;
+ entry = entry->nextEntry;
+ }
+ }
+ }
+
+ /** Removes all items with the given value. */
+ void removeValue (ValueTypeParameter valueToRemove)
+ {
+ const ScopedLockType sl (getLock());
+
+ for (int i = getNumSlots(); --i >= 0;)
+ {
+ HashEntry* entry = slots.getUnchecked(i);
+ HashEntry* previous = 0;
+
+ while (entry != 0)
+ {
+ if (entry->value == valueToRemove)
+ {
+ const ScopedPointer deleter (entry);
+
+ entry = entry->nextEntry;
+
+ if (previous != 0)
+ previous->nextEntry = entry;
+ else
+ slots.set (i, entry);
+
+ --totalNumItems;
+ }
+ else
+ {
+ previous = entry;
+ entry = entry->nextEntry;
+ }
+ }
+ }
+ }
+
+ /** Remaps the hash-map to use a different number of slots for its hash function.
+ Each slot corresponds to a single hash-code, and each one can contain multiple items.
+ @see getNumSlots()
+ */
+ void remapTable (int newNumberOfSlots)
+ {
+ HashMap newTable (newNumberOfSlots);
+
+ for (int i = getNumSlots(); --i >= 0;)
+ for (const HashEntry* entry = slots.getUnchecked(i); entry != 0; entry = entry->nextEntry)
+ newTable.set (entry->key, entry->value);
+
+ swapWith (newTable);
+ }
+
+ /** Returns the number of slots which are available for hashing.
+ Each slot corresponds to a single hash-code, and each one can contain multiple items.
+ @see getNumSlots()
+ */
+ inline int getNumSlots() const throw()
+ {
+ return slots.size();
+ }
+
+ //==============================================================================
+ /** Efficiently swaps the contents of two hash-maps. */
+ void swapWith (HashMap& otherHashMap) throw()
+ {
+ const ScopedLockType lock1 (getLock());
+ const ScopedLockType lock2 (otherHashMap.getLock());
+
+ slots.swapWithArray (otherHashMap.slots);
+ swapVariables (totalNumItems, otherHashMap.totalNumItems);
+ }
+
+ //==============================================================================
+ /** Returns the CriticalSection that locks this structure.
+ To lock, you can call getLock().enter() and getLock().exit(), or preferably use
+ an object of ScopedLockType as an RAII lock for it.
+ */
+ inline const TypeOfCriticalSectionToUse& getLock() const throw() { return lock; }
+
+ /** Returns the type of scoped lock to use for locking this array */
+ typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
+
+private:
+ //==============================================================================
+ class HashEntry
+ {
+ public:
+ HashEntry (KeyTypeParameter key_, ValueTypeParameter value_, HashEntry* const nextEntry_)
+ : key (key_), value (value_), nextEntry (nextEntry_)
+ {}
+
+ const KeyType key;
+ ValueType value;
+ HashEntry* nextEntry;
+
+ JUCE_DECLARE_NON_COPYABLE (HashEntry);
+ };
+
+public:
+ //==============================================================================
+ /** Iterates over the items in a HashMap.
+
+ To use it, repeatedly call next() until it returns false, e.g.
+ @code
+ HashMap myMap;
+
+ HashMap::Iterator i (myMap);
+
+ while (i.next())
+ {
+ DBG (i.getKey() << " -> " << i.getValue());
+ }
+ @endcode
+
+ The order in which items are iterated bears no resemblence to the order in which
+ they were originally added!
+
+ Obviously as soon as you call any non-const methods on the original hash-map, any
+ iterators that were created beforehand will cease to be valid, and should not be used.
+
+ @see HashMap
+ */
+ class Iterator
+ {
+ public:
+ //==============================================================================
+ Iterator (const HashMap& hashMapToIterate)
+ : hashMap (hashMapToIterate), entry (0), index (0)
+ {}
+
+ /** Moves to the next item, if one is available.
+ When this returns true, you can get the item's key and value using getKey() and
+ getValue(). If it returns false, the iteration has finished and you should stop.
+ */
+ bool next()
+ {
+ if (entry != 0)
+ entry = entry->nextEntry;
+
+ while (entry == 0)
+ {
+ if (index >= hashMap.getNumSlots())
+ return false;
+
+ entry = hashMap.slots.getUnchecked (index++);
+ }
+
+ return true;
+ }
+
+ /** Returns the current item's key.
+ This should only be called when a call to next() has just returned true.
+ */
+ const KeyType getKey() const
+ {
+ return entry != 0 ? entry->key : KeyType();
+ }
+
+ /** Returns the current item's value.
+ This should only be called when a call to next() has just returned true.
+ */
+ const ValueType getValue() const
+ {
+ return entry != 0 ? entry->value : ValueType();
+ }
+
+ private:
+ //==============================================================================
+ const HashMap& hashMap;
+ HashEntry* entry;
+ int index;
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Iterator);
+ };
+
+private:
+ //==============================================================================
+ enum { defaultHashTableSize = 101 };
+ friend class Iterator;
+
+ Array slots;
+ int totalNumItems;
+ TypeOfCriticalSectionToUse lock;
+
+ int generateHashFor (KeyTypeParameter key) const
+ {
+ const int hash = HashFunctionToUse::generateHash (key, getNumSlots());
+ jassert (isPositiveAndBelow (hash, getNumSlots())); // your hash function is generating out-of-range numbers!
+ return hash;
+ }
+
+ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HashMap);
+};
+
+
+#endif // __JUCE_HASHMAP_JUCEHEADER__
diff --git a/src/core/juce_StandardHeader.h b/src/core/juce_StandardHeader.h
index 0701d66d33..574ea8a553 100644
--- a/src/core/juce_StandardHeader.h
+++ b/src/core/juce_StandardHeader.h
@@ -33,7 +33,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 53
-#define JUCE_BUILDNUMBER 53
+#define JUCE_BUILDNUMBER 54
/** Current Juce version number.
diff --git a/src/juce_core_includes.h b/src/juce_core_includes.h
index 8115d4c321..2fe2394fbf 100644
--- a/src/juce_core_includes.h
+++ b/src/juce_core_includes.h
@@ -41,6 +41,9 @@
#ifndef __JUCE_ELEMENTCOMPARATOR_JUCEHEADER__
#include "containers/juce_ElementComparator.h"
#endif
+#ifndef __JUCE_HASHMAP_JUCEHEADER__
+ #include "containers/juce_HashMap.h"
+#endif
#ifndef __JUCE_LINKEDLISTPOINTER_JUCEHEADER__
#include "containers/juce_LinkedListPointer.h"
#endif
diff --git a/src/maths/juce_MathsFunctions.h b/src/maths/juce_MathsFunctions.h
index a5d488d0c5..df31ae945b 100644
--- a/src/maths/juce_MathsFunctions.h
+++ b/src/maths/juce_MathsFunctions.h
@@ -425,7 +425,7 @@ inline int roundFloatToInt (const float value) throw()
namespace TypeHelpers
{
#if JUCE_VC8_OR_EARLIER
- #define PARAMETER_TYPE(a) a
+ #define PARAMETER_TYPE(type) const type&
#else
/** The ParameterType struct is used to find the best type to use when passing some kind
of object as a parameter.