1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-02-04 03:40:07 +00:00

New class: HashMap.

This commit is contained in:
Julian Storer 2011-03-16 18:26:50 +00:00
parent 5eb389342d
commit 8df744472d
14 changed files with 1071 additions and 197 deletions

View file

@ -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,

View file

@ -353,6 +353,7 @@
<File RelativePath="..\..\src\containers\juce_DynamicObject.cpp"/>
<File RelativePath="..\..\src\containers\juce_DynamicObject.h"/>
<File RelativePath="..\..\src\containers\juce_ElementComparator.h"/>
<File RelativePath="..\..\src\containers\juce_HashMap.h"/>
<File RelativePath="..\..\src\containers\juce_LinkedListPointer.h"/>
<File RelativePath="..\..\src\containers\juce_NamedValueSet.cpp"/>
<File RelativePath="..\..\src\containers\juce_NamedValueSet.h"/>

View file

@ -353,6 +353,7 @@
<File RelativePath="..\..\src\containers\juce_DynamicObject.cpp"/>
<File RelativePath="..\..\src\containers\juce_DynamicObject.h"/>
<File RelativePath="..\..\src\containers\juce_ElementComparator.h"/>
<File RelativePath="..\..\src\containers\juce_HashMap.h"/>
<File RelativePath="..\..\src\containers\juce_LinkedListPointer.h"/>
<File RelativePath="..\..\src\containers\juce_NamedValueSet.cpp"/>
<File RelativePath="..\..\src\containers\juce_NamedValueSet.h"/>

View file

@ -355,6 +355,7 @@
<File RelativePath="..\..\src\containers\juce_DynamicObject.cpp"/>
<File RelativePath="..\..\src\containers\juce_DynamicObject.h"/>
<File RelativePath="..\..\src\containers\juce_ElementComparator.h"/>
<File RelativePath="..\..\src\containers\juce_HashMap.h"/>
<File RelativePath="..\..\src\containers\juce_LinkedListPointer.h"/>
<File RelativePath="..\..\src\containers\juce_NamedValueSet.cpp"/>
<File RelativePath="..\..\src\containers\juce_NamedValueSet.h"/>

View file

@ -529,6 +529,7 @@
<ClInclude Include="..\..\src\containers\juce_ArrayAllocationBase.h"/>
<ClInclude Include="..\..\src\containers\juce_DynamicObject.h"/>
<ClInclude Include="..\..\src\containers\juce_ElementComparator.h"/>
<ClInclude Include="..\..\src\containers\juce_HashMap.h"/>
<ClInclude Include="..\..\src\containers\juce_LinkedListPointer.h"/>
<ClInclude Include="..\..\src\containers\juce_NamedValueSet.h"/>
<ClInclude Include="..\..\src\containers\juce_OwnedArray.h"/>

View file

@ -1521,6 +1521,9 @@
<ClInclude Include="..\..\src\containers\juce_ElementComparator.h">
<Filter>Juce\Source\containers</Filter>
</ClInclude>
<ClInclude Include="..\..\src\containers\juce_HashMap.h">
<Filter>Juce\Source\containers</Filter>
</ClInclude>
<ClInclude Include="..\..\src\containers\juce_LinkedListPointer.h">
<Filter>Juce\Source\containers</Filter>
</ClInclude>

View file

@ -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,

View file

@ -365,6 +365,7 @@
file="src/containers/juce_DynamicObject.h"/>
<FILE id="RNHQjBFmS" name="juce_ElementComparator.h" compile="0" resource="0"
file="src/containers/juce_ElementComparator.h"/>
<FILE id="KG5Z3O" name="juce_HashMap.h" compile="0" resource="0" file="src/containers/juce_HashMap.h"/>
<FILE id="pnNXeAf" name="juce_LinkedListPointer.h" compile="0" resource="0"
file="src/containers/juce_LinkedListPointer.h"/>
<FILE id="zy1yAvLC1" name="juce_NamedValueSet.cpp" compile="1" resource="0"

View file

@ -73,7 +73,7 @@ namespace JuceDummyNamespace {}
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 53
#define JUCE_BUILDNUMBER 53
#define JUCE_BUILDNUMBER 54
/** Current Juce version number.
@ -1399,7 +1399,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.
@ -6589,11 +6589,7 @@ template <typename ElementType,
class Array
{
private:
#if JUCE_VC8_OR_EARLIER
typedef const ElementType& ParameterType;
#else
typedef PARAMETER_TYPE (ElementType) ParameterType;
#endif
public:
@ -9313,13 +9309,12 @@ private:
#ifndef __JUCE_ELEMENTCOMPARATOR_JUCEHEADER__
#endif
#ifndef __JUCE_LINKEDLISTPOINTER_JUCEHEADER__
#ifndef __JUCE_HASHMAP_JUCEHEADER__
#endif
#ifndef __JUCE_NAMEDVALUESET_JUCEHEADER__
/*** Start of inlined file: juce_HashMap.h ***/
#ifndef __JUCE_HASHMAP_JUCEHEADER__
#define __JUCE_HASHMAP_JUCEHEADER__
#endif
#ifndef __JUCE_OWNEDARRAY_JUCEHEADER__
/*** Start of inlined file: juce_OwnedArray.h ***/
#ifndef __JUCE_OWNEDARRAY_JUCEHEADER__
@ -10081,6 +10076,604 @@ private:
/*** End of inlined file: juce_OwnedArray.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 ObjectType>
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 <ObjectType>& 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<MyClass> 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<MyClass> 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 <class ObjectType>
bool operator== (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) throw()
{
return static_cast <ObjectType*> (pointer1) == pointer2;
}
/** Compares a ScopedPointer with another pointer.
This can be handy for checking whether this is a null pointer.
*/
template <class ObjectType>
bool operator!= (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) throw()
{
return static_cast <ObjectType*> (pointer1) != pointer2;
}
#endif // __JUCE_SCOPEDPOINTER_JUCEHEADER__
/*** End of inlined file: juce_ScopedPointer.h ***/
/**
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<int, String> 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<int, String>::Iterator i (hash); i.next();)
DBG (i.getKey() << " -> " << i.getValue());
@endcode
@see CriticalSection, DefaultHashFunctions, NamedValueSet, SortedSet
*/
template <typename KeyType,
typename ValueType,
class HashFunctionToUse = DefaultHashFunctions,
class TypeOfCriticalSectionToUse = DummyCriticalSection>
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<HashEntry> 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<HashEntry> 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<HashEntry> 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 <String, String> myMap;
HashMap<String, String>::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 <HashEntry*> 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__
@ -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 ObjectType>
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 <ObjectType>& 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<MyClass> 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<MyClass> 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 <class ObjectType>
bool operator== (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) throw()
{
return static_cast <ObjectType*> (pointer1) == pointer2;
}
/** Compares a ScopedPointer with another pointer.
This can be handy for checking whether this is a null pointer.
*/
template <class ObjectType>
bool operator!= (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) throw()
{
return static_cast <ObjectType*> (pointer1) != pointer2;
}
#endif // __JUCE_SCOPEDPOINTER_JUCEHEADER__
/*** End of inlined file: juce_ScopedPointer.h ***/
class FileInputStream;
class FileOutputStream;

View file

@ -60,11 +60,7 @@ template <typename ElementType,
class Array
{
private:
#if JUCE_VC8_OR_EARLIER
typedef const ElementType& ParameterType;
#else
typedef PARAMETER_TYPE (ElementType) ParameterType;
#endif
public:
//==============================================================================

View file

@ -0,0 +1,450 @@
/*
==============================================================================
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.
==============================================================================
*/
#ifndef __JUCE_HASHMAP_JUCEHEADER__
#define __JUCE_HASHMAP_JUCEHEADER__
#include "juce_OwnedArray.h"
#include "juce_LinkedListPointer.h"
#include "../memory/juce_ScopedPointer.h"
//==============================================================================
/**
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<int, String> 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<int, String>::Iterator i (hash); i.next();)
DBG (i.getKey() << " -> " << i.getValue());
@endcode
@see CriticalSection, DefaultHashFunctions, NamedValueSet, SortedSet
*/
template <typename KeyType,
typename ValueType,
class HashFunctionToUse = DefaultHashFunctions,
class TypeOfCriticalSectionToUse = DummyCriticalSection>
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<HashEntry> 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<HashEntry> 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<HashEntry> 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 <String, String> myMap;
HashMap<String, String>::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 <HashEntry*> 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__

View file

@ -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.

View file

@ -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

View file

@ -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.