- Library code update

- project update (added Eigen)

git-svn-id: http://moon:8086/svn/software/trunk/projects/mpsk_rx_gui@94 b431acfa-c32f-4a4a-93f1-934dc6c82436
This commit is contained in:
2014-12-20 20:59:48 +00:00
parent 1b4d8e9f54
commit dc5560392f
312 changed files with 6349 additions and 4195 deletions
@@ -35,7 +35,7 @@ AbstractFifo::AbstractFifo (const int capacity) noexcept
AbstractFifo::~AbstractFifo() {}
int AbstractFifo::getTotalSize() const noexcept { return bufferSize; }
int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady(); }
int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady() - 1; }
int AbstractFifo::getNumReady() const noexcept
{
@@ -42,7 +42,7 @@
- it must be able to be relocated in memory by a memcpy without this causing any problems - so
objects whose functionality relies on external pointers or references to themselves can not be used.
You can of course have an array of pointers to any kind of object, e.g. Array <MyClass*>, but if
You can of course have an array of pointers to any kind of object, e.g. Array<MyClass*>, but if
you do this, the array doesn't take any ownership of the objects - see the OwnedArray class or the
ReferenceCountedArray class for more powerful ways of holding lists of objects.
@@ -65,8 +65,7 @@ private:
public:
//==============================================================================
/** Creates an empty array. */
Array() noexcept
: numUsed (0)
Array() noexcept : numUsed (0)
{
}
@@ -31,7 +31,7 @@ DynamicObject::DynamicObject()
}
DynamicObject::DynamicObject (const DynamicObject& other)
: properties (other.properties)
: ReferenceCountedObject(), properties (other.properties)
{
}
@@ -85,16 +85,9 @@ void DynamicObject::clear()
void DynamicObject::cloneAllProperties()
{
for (LinkedListPointer<NamedValueSet::NamedValue>* i = &(properties.values);;)
{
if (NamedValueSet::NamedValue* const v = i->get())
{
v->value = v->value.clone();
i = &(v->nextListItem);
}
else
break;
}
for (int i = properties.size(); --i >= 0;)
if (var* v = properties.getVarPointerAt (i))
*v = v->clone();
}
DynamicObject::Ptr DynamicObject::clone()
@@ -110,32 +103,27 @@ void DynamicObject::writeAsJSON (OutputStream& out, const int indentLevel, const
if (! allOnOneLine)
out << newLine;
for (LinkedListPointer<NamedValueSet::NamedValue>* i = &(properties.values);;)
const int numValues = properties.size();
for (int i = 0; i < numValues; ++i)
{
if (NamedValueSet::NamedValue* const v = i->get())
if (! allOnOneLine)
JSONFormatter::writeSpaces (out, indentLevel + JSONFormatter::indentSize);
out << '"';
JSONFormatter::writeString (out, properties.getName (i));
out << "\": ";
JSONFormatter::write (out, properties.getValueAt (i), indentLevel + JSONFormatter::indentSize, allOnOneLine);
if (i < numValues - 1)
{
if (! allOnOneLine)
JSONFormatter::writeSpaces (out, indentLevel + JSONFormatter::indentSize);
out << '"';
JSONFormatter::writeString (out, v->name);
out << "\": ";
JSONFormatter::write (out, v->value, indentLevel + JSONFormatter::indentSize, allOnOneLine);
if (v->nextListItem.get() != nullptr)
{
if (allOnOneLine)
out << ", ";
else
out << ',' << newLine;
}
else if (! allOnOneLine)
out << newLine;
i = &(v->nextListItem);
if (allOnOneLine)
out << ", ";
else
out << ',' << newLine;
}
else
break;
else if (! allOnOneLine)
out << newLine;
}
if (! allOnOneLine)
@@ -58,7 +58,7 @@ public:
virtual bool hasProperty (const Identifier& propertyName) const;
/** Returns a named property.
This returns a void if no such property exists.
This returns var::null if no such property exists.
*/
virtual var getProperty (const Identifier& propertyName) const;
@@ -26,53 +26,37 @@
==============================================================================
*/
NamedValueSet::NamedValue::NamedValue() noexcept
struct NamedValueSet::NamedValue
{
}
NamedValue() noexcept {}
NamedValue (Identifier n, const var& v) : name (n), value (v) {}
NamedValue (const NamedValue& other) : name (other.name), value (other.value) {}
inline NamedValueSet::NamedValue::NamedValue (Identifier n, const var& v)
: name (n), value (v)
{
}
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
NamedValue (NamedValue&& other) noexcept
: name (static_cast<Identifier&&> (other.name)),
value (static_cast<var&&> (other.value))
{
}
NamedValueSet::NamedValue::NamedValue (const NamedValue& other)
: name (other.name), value (other.value)
{
}
NamedValue (Identifier n, var&& v) : name (n), value (static_cast<var&&> (v))
{
}
NamedValueSet::NamedValue& NamedValueSet::NamedValue::operator= (const NamedValueSet::NamedValue& other)
{
name = other.name;
value = other.value;
return *this;
}
NamedValue& operator= (NamedValue&& other) noexcept
{
name = static_cast<Identifier&&> (other.name);
value = static_cast<var&&> (other.value);
return *this;
}
#endif
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
NamedValueSet::NamedValue::NamedValue (NamedValue&& other) noexcept
: nextListItem (static_cast<LinkedListPointer<NamedValue>&&> (other.nextListItem)),
name (static_cast<Identifier&&> (other.name)),
value (static_cast<var&&> (other.value))
{
}
bool operator== (const NamedValue& other) const noexcept { return name == other.name && value == other.value; }
bool operator!= (const NamedValue& other) const noexcept { return ! operator== (other); }
inline NamedValueSet::NamedValue::NamedValue (Identifier n, var&& v)
: name (n), value (static_cast<var&&> (v))
{
}
NamedValueSet::NamedValue& NamedValueSet::NamedValue::operator= (NamedValue&& other) noexcept
{
nextListItem = static_cast<LinkedListPointer<NamedValue>&&> (other.nextListItem);
name = static_cast<Identifier&&> (other.name);
value = static_cast<var&&> (other.value);
return *this;
}
#endif
bool NamedValueSet::NamedValue::operator== (const NamedValueSet::NamedValue& other) const noexcept
{
return name == other.name && value == other.value;
}
Identifier name;
var value;
};
//==============================================================================
NamedValueSet::NamedValueSet() noexcept
@@ -80,20 +64,20 @@ NamedValueSet::NamedValueSet() noexcept
}
NamedValueSet::NamedValueSet (const NamedValueSet& other)
: values (other.values)
{
values.addCopyOfList (other.values);
}
NamedValueSet& NamedValueSet::operator= (const NamedValueSet& other)
{
clear();
values.addCopyOfList (other.values);
values = other.values;
return *this;
}
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
NamedValueSet::NamedValueSet (NamedValueSet&& other) noexcept
: values (static_cast <LinkedListPointer<NamedValue>&&> (other.values))
: values (static_cast <Array<NamedValue>&&> (other.values))
{
}
@@ -104,31 +88,18 @@ NamedValueSet& NamedValueSet::operator= (NamedValueSet&& other) noexcept
}
#endif
NamedValueSet::~NamedValueSet()
NamedValueSet::~NamedValueSet() noexcept
{
clear();
}
void NamedValueSet::clear()
{
values.deleteAll();
values.clear();
}
bool NamedValueSet::operator== (const NamedValueSet& other) const
{
const NamedValue* i1 = values;
const NamedValue* i2 = other.values;
while (i1 != nullptr && i2 != nullptr)
{
if (! (*i1 == *i2))
return false;
i1 = i1->nextListItem;
i2 = i2->nextListItem;
}
return true;
return values == other.values;
}
bool NamedValueSet::operator!= (const NamedValueSet& other) const
@@ -141,16 +112,15 @@ int NamedValueSet::size() const noexcept
return values.size();
}
const var& NamedValueSet::operator[] (Identifier name) const
const var& NamedValueSet::operator[] (const Identifier& name) const noexcept
{
for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
if (i->name == name)
return i->value;
if (const var* v = getVarPointer (name))
return *v;
return var::null;
}
var NamedValueSet::getWithDefault (Identifier name, const var& defaultReturnValue) const
var NamedValueSet::getWithDefault (const Identifier& name, const var& defaultReturnValue) const
{
if (const var* const v = getVarPointer (name))
return *v;
@@ -158,9 +128,9 @@ var NamedValueSet::getWithDefault (Identifier name, const var& defaultReturnValu
return defaultReturnValue;
}
var* NamedValueSet::getVarPointer (Identifier name) const noexcept
var* NamedValueSet::getVarPointer (const Identifier& name) const noexcept
{
for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
for (NamedValue* e = values.end(), *i = values.begin(); i != e; ++i)
if (i->name == name)
return &(i->value);
@@ -170,145 +140,121 @@ var* NamedValueSet::getVarPointer (Identifier name) const noexcept
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
bool NamedValueSet::set (Identifier name, var&& newValue)
{
LinkedListPointer<NamedValue>* i = &values;
while (i->get() != nullptr)
if (var* const v = getVarPointer (name))
{
NamedValue* const v = i->get();
if (v->equalsWithSameType (newValue))
return false;
if (v->name == name)
{
if (v->value.equalsWithSameType (newValue))
return false;
v->value = static_cast <var&&> (newValue);
return true;
}
i = &(v->nextListItem);
*v = static_cast<var&&> (newValue);
return true;
}
i->insertNext (new NamedValue (name, static_cast <var&&> (newValue)));
values.add (NamedValue (name, static_cast<var&&> (newValue)));
return true;
}
#endif
bool NamedValueSet::set (Identifier name, const var& newValue)
{
LinkedListPointer<NamedValue>* i = &values;
while (i->get() != nullptr)
if (var* const v = getVarPointer (name))
{
NamedValue* const v = i->get();
if (v->equalsWithSameType (newValue))
return false;
if (v->name == name)
{
if (v->value.equalsWithSameType (newValue))
return false;
v->value = newValue;
return true;
}
i = &(v->nextListItem);
*v = newValue;
return true;
}
i->insertNext (new NamedValue (name, newValue));
values.add (NamedValue (name, newValue));
return true;
}
bool NamedValueSet::contains (Identifier name) const
bool NamedValueSet::contains (const Identifier& name) const noexcept
{
return getVarPointer (name) != nullptr;
}
int NamedValueSet::indexOf (Identifier name) const noexcept
int NamedValueSet::indexOf (const Identifier& name) const noexcept
{
int index = 0;
const int numValues = values.size();
for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
{
if (i->name == name)
return index;
++index;
}
for (int i = 0; i < numValues; ++i)
if (values.getReference(i).name == name)
return i;
return -1;
}
bool NamedValueSet::remove (Identifier name)
bool NamedValueSet::remove (const Identifier& name)
{
LinkedListPointer<NamedValue>* i = &values;
const int numValues = values.size();
for (;;)
for (int i = 0; i < numValues; ++i)
{
NamedValue* const v = i->get();
if (v == nullptr)
break;
if (v->name == name)
if (values.getReference(i).name == name)
{
delete i->removeNext();
values.remove (i);
return true;
}
i = &(v->nextListItem);
}
return false;
}
Identifier NamedValueSet::getName (const int index) const
Identifier NamedValueSet::getName (const int index) const noexcept
{
const NamedValue* const v = values[index];
jassert (v != nullptr);
return v->name;
if (isPositiveAndBelow (index, values.size()))
return values.getReference (index).name;
jassertfalse;
return Identifier();
}
const var& NamedValueSet::getValueAt (const int index) const
const var& NamedValueSet::getValueAt (const int index) const noexcept
{
const NamedValue* const v = values[index];
jassert (v != nullptr);
return v->value;
if (isPositiveAndBelow (index, values.size()))
return values.getReference (index).value;
jassertfalse;
return var::null;
}
var* NamedValueSet::getVarPointerAt (int index) const noexcept
{
if (isPositiveAndBelow (index, values.size()))
return &(values.getReference (index).value);
return nullptr;
}
void NamedValueSet::setFromXmlAttributes (const XmlElement& xml)
{
clear();
LinkedListPointer<NamedValue>::Appender appender (values);
values.clearQuick();
const int numAtts = xml.getNumAttributes(); // xxx inefficient - should write an att iterator..
for (int i = 0; i < numAtts; ++i)
for (const XmlElement::XmlAttributeNode* att = xml.attributes; att != nullptr; att = att->nextListItem)
{
const String& name = xml.getAttributeName (i);
const String& value = xml.getAttributeValue (i);
if (name.startsWith ("base64:"))
if (att->name.toString().startsWith ("base64:"))
{
MemoryBlock mb;
if (mb.fromBase64Encoding (value))
if (mb.fromBase64Encoding (att->value))
{
appender.append (new NamedValue (name.substring (7), var (mb)));
values.add (NamedValue (att->name.toString().substring (7), var (mb)));
continue;
}
}
appender.append (new NamedValue (name, var (value)));
values.add (NamedValue (att->name, var (att->value)));
}
}
void NamedValueSet::copyToXmlAttributes (XmlElement& xml) const
{
for (NamedValue* i = values; i != nullptr; i = i->nextListItem)
for (NamedValue* e = values.end(), *i = values.begin(); i != e; ++i)
{
if (const MemoryBlock* mb = i->value.getBinaryData())
{
xml.setAttribute ("base64:" + i->name.toString(),
mb->toBase64Encoding());
xml.setAttribute ("base64:" + i->name.toString(), mb->toBase64Encoding());
}
else
{
@@ -54,7 +54,7 @@ public:
#endif
/** Destructor. */
~NamedValueSet();
~NamedValueSet() noexcept;
bool operator== (const NamedValueSet&) const;
bool operator!= (const NamedValueSet&) const;
@@ -67,12 +67,12 @@ public:
If the name isn't found, this will return a void variant.
@see getProperty
*/
const var& operator[] (Identifier name) const;
const var& operator[] (const Identifier& name) const noexcept;
/** Tries to return the named value, but if no such value is found, this will
instead return the supplied default value.
*/
var getWithDefault (Identifier name, const var& defaultReturnValue) const;
var getWithDefault (const Identifier& name, const var& defaultReturnValue) const;
/** Changes or adds a named value.
@returns true if a value was changed or added; false if the
@@ -89,38 +89,42 @@ public:
#endif
/** Returns true if the set contains an item with the specified name. */
bool contains (Identifier name) const;
bool contains (const Identifier& name) const noexcept;
/** Removes a value from the set.
@returns true if a value was removed; false if there was no value
with the name that was given.
*/
bool remove (Identifier name);
bool remove (const Identifier& name);
/** Returns the name of the value at a given index.
The index must be between 0 and size() - 1.
*/
Identifier getName (int index) const;
Identifier getName (int index) const noexcept;
/** Returns the value of the item at a given index.
The index must be between 0 and size() - 1.
*/
const var& getValueAt (int index) const;
/** Returns the index of the given name, or -1 if it's not found. */
int indexOf (Identifier name) const noexcept;
/** Removes all values. */
void clear();
//==============================================================================
/** Returns a pointer to the var that holds a named value, or null if there is
no value with this name.
Do not use this method unless you really need access to the internal var object
for some reason - for normal reading and writing always prefer operator[]() and set().
*/
var* getVarPointer (Identifier name) const noexcept;
var* getVarPointer (const Identifier& name) const noexcept;
/** Returns the value of the item at a given index.
The index must be between 0 and size() - 1.
*/
const var& getValueAt (int index) const noexcept;
/** Returns the value of the item at a given index.
The index must be between 0 and size() - 1, or this will return a nullptr
*/
var* getVarPointerAt (int index) const noexcept;
/** Returns the index of the given name, or -1 if it's not found. */
int indexOf (const Identifier& name) const noexcept;
/** Removes all values. */
void clear();
//==============================================================================
/** Sets properties to the values of all of an XML element's attributes. */
@@ -133,32 +137,8 @@ public:
private:
//==============================================================================
class NamedValue
{
public:
NamedValue() noexcept;
NamedValue (const NamedValue&);
NamedValue (Identifier, const var&);
NamedValue& operator= (const NamedValue&);
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
NamedValue (NamedValue&&) noexcept;
NamedValue (Identifier, var&&);
NamedValue& operator= (NamedValue&&) noexcept;
#endif
bool operator== (const NamedValue&) const noexcept;
LinkedListPointer<NamedValue> nextListItem;
Identifier name;
var value;
private:
JUCE_LEAK_DETECTOR (NamedValue)
};
friend class LinkedListPointer<NamedValue>;
LinkedListPointer<NamedValue> values;
friend class DynamicObject;
struct NamedValue;
Array<NamedValue> values;
};
@@ -830,7 +830,7 @@ public:
This will use a comparator object to sort the elements into order. The object
passed must have a method of the form:
@code
int compareElements (ElementType first, ElementType second);
int compareElements (ElementType* first, ElementType* second);
@endcode
..and this method must return:
@@ -38,7 +38,7 @@
The template parameter specifies the class of the object you want to point to - the easiest
way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject
or SingleThreadedReferenceCountedObject, but if you need to, you can roll your own reference-countable
class by implementing a set of mathods called incReferenceCount(), decReferenceCount(), and
class by implementing a set of methods called incReferenceCount(), decReferenceCount(), and
decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods
should behave.
@@ -72,7 +72,7 @@ public:
const ScopedLockType lock (other.getLock());
numUsed = other.size();
data.setAllocatedSize (numUsed);
memcpy (data.elements, other.getRawDataPointer(), numUsed * sizeof (ObjectClass*));
memcpy (data.elements, other.getRawDataPointer(), (size_t) numUsed * sizeof (ObjectClass*));
for (int i = numUsed; --i >= 0;)
if (ObjectClass* o = data.elements[i])
@@ -476,7 +476,7 @@ bool File::loadFileAsData (MemoryBlock& destBlock) const
return false;
FileInputStream in (*this);
return in.openedOk() && getSize() == in.readIntoMemoryBlock (destBlock);
return in.openedOk() && getSize() == (int64) in.readIntoMemoryBlock (destBlock);
}
String File::loadFileAsString() const
@@ -361,6 +361,14 @@ public:
*/
File getLinkedTarget() const;
/** Returns a unique identifier for the file, if one is available.
Depending on the OS and file-system, this may be a unix inode number or
a win32 file identifier, or 0 if it fails to find one. The number will
be unique on the filesystem, but not globally.
*/
uint64 getFileIdentifier() const;
//==============================================================================
/** Returns the last modification time of this file.
@@ -836,6 +844,11 @@ public:
/** In a plugin, this will return the path of the host executable. */
hostApplicationPath,
#if JUCE_WINDOWS
/** On a Windows machine, returns the location of the Windows/System32 folder. */
windowsSystemDirectory,
#endif
/** The directory in which applications normally get installed.
So on windows, this would be something like "c:\program files", on the
Mac "/Applications", or "/usr" on linux.
@@ -28,41 +28,34 @@
int64 juce_fileSetPosition (void* handle, int64 pos);
//==============================================================================
FileInputStream::FileInputStream (const File& f)
: file (f),
fileHandle (nullptr),
currentPosition (0),
status (Result::ok()),
needToSeek (true)
status (Result::ok())
{
openHandle();
}
FileInputStream::~FileInputStream()
{
closeHandle();
}
//==============================================================================
int64 FileInputStream::getTotalLength()
{
// You should always check that a stream opened successfully before using it!
jassert (openedOk());
return file.getSize();
}
int FileInputStream::read (void* buffer, int bytesToRead)
{
// You should always check that a stream opened successfully before using it!
jassert (openedOk());
// The buffer should never be null, and a negative size is probably a
// sign that something is broken!
jassert (buffer != nullptr && bytesToRead >= 0);
if (needToSeek)
{
if (juce_fileSetPosition (fileHandle, currentPosition) < 0)
return 0;
needToSeek = false;
}
const size_t num = readInternal (buffer, (size_t) bytesToRead);
currentPosition += num;
@@ -81,15 +74,11 @@ int64 FileInputStream::getPosition()
bool FileInputStream::setPosition (int64 pos)
{
// You should always check that a stream opened successfully before using it!
jassert (openedOk());
if (pos != currentPosition)
{
pos = jlimit ((int64) 0, getTotalLength(), pos);
currentPosition = juce_fileSetPosition (fileHandle, pos);
needToSeek |= (currentPosition != pos);
currentPosition = pos;
}
return true;
return currentPosition == pos;
}
@@ -40,10 +40,11 @@ class JUCE_API FileInputStream : public InputStream
{
public:
//==============================================================================
/** Creates a FileInputStream.
/** Creates a FileInputStream to read from the given file.
@param fileToRead the file to read from - if the file can't be accessed for some
reason, then the stream will just contain no data
After creating a FileInputStream, you should use openedOk() or failedToOpen()
to make sure that it's OK before trying to read from it! If it failed, you
can call getStatus() to get more error information.
*/
explicit FileInputStream (const File& fileToRead);
@@ -73,24 +74,23 @@ public:
//==============================================================================
int64 getTotalLength() override;
int read (void* destBuffer, int maxBytesToRead) override;
int read (void*, int) override;
bool isExhausted() override;
int64 getPosition() override;
bool setPosition (int64 pos) override;
bool setPosition (int64) override;
private:
//==============================================================================
File file;
const File file;
void* fileHandle;
int64 currentPosition;
Result status;
bool needToSeek;
void openHandle();
void closeHandle();
size_t readInternal (void* buffer, size_t numBytes);
size_t readInternal (void*, size_t);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileInputStream)
};
#endif // JUCE_FILEINPUTSTREAM_H_INCLUDED
@@ -26,32 +26,7 @@
==============================================================================
*/
WildcardFileFilter::WildcardFileFilter (const String& fileWildcardPatterns,
const String& directoryWildcardPatterns,
const String& desc)
: FileFilter (desc.isEmpty() ? fileWildcardPatterns
: (desc + " (" + fileWildcardPatterns + ")"))
{
parse (fileWildcardPatterns, fileWildcards);
parse (directoryWildcardPatterns, directoryWildcards);
}
WildcardFileFilter::~WildcardFileFilter()
{
}
bool WildcardFileFilter::isFileSuitable (const File& file) const
{
return match (file, fileWildcards);
}
bool WildcardFileFilter::isDirectorySuitable (const File& file) const
{
return match (file, directoryWildcards);
}
//==============================================================================
void WildcardFileFilter::parse (const String& pattern, StringArray& result)
static void parseWildcard (const String& pattern, StringArray& result)
{
result.addTokens (pattern.toLowerCase(), ";,", "\"'");
@@ -65,7 +40,7 @@ void WildcardFileFilter::parse (const String& pattern, StringArray& result)
result.set (i, "*");
}
bool WildcardFileFilter::match (const File& file, const StringArray& wildcards)
static bool matchWildcard (const File& file, const StringArray& wildcards)
{
const String filename (file.getFileName());
@@ -75,3 +50,27 @@ bool WildcardFileFilter::match (const File& file, const StringArray& wildcards)
return false;
}
WildcardFileFilter::WildcardFileFilter (const String& fileWildcardPatterns,
const String& directoryWildcardPatterns,
const String& desc)
: FileFilter (desc.isEmpty() ? fileWildcardPatterns
: (desc + " (" + fileWildcardPatterns + ")"))
{
parseWildcard (fileWildcardPatterns, fileWildcards);
parseWildcard (directoryWildcardPatterns, directoryWildcards);
}
WildcardFileFilter::~WildcardFileFilter()
{
}
bool WildcardFileFilter::isFileSuitable (const File& file) const
{
return matchWildcard (file, fileWildcards);
}
bool WildcardFileFilter::isDirectorySuitable (const File& file) const
{
return matchWildcard (file, directoryWildcards);
}
@@ -75,12 +75,8 @@ private:
//==============================================================================
StringArray fileWildcards, directoryWildcards;
static void parse (const String& pattern, StringArray& result);
static bool match (const File& file, const StringArray& wildcards);
JUCE_LEAK_DETECTOR (WildcardFileFilter)
};
#endif // JUCE_WILDCARDFILEFILTER_H_INCLUDED
@@ -243,9 +243,9 @@ private:
if (r.failed())
return r;
const String propertyName (propertyNameVar.toString());
const Identifier propertyName (propertyNameVar.toString());
if (propertyName.isNotEmpty())
if (propertyName.isValid())
{
t = t.findEndOfWhitespace();
oldT = t;
@@ -102,6 +102,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
static bool isNumericOrUndefined (const var& v) { return v.isInt() || v.isDouble() || v.isInt64() || v.isBool() || v.isUndefined(); }
static int64 getOctalValue (const String& s) { BigInteger b; b.parseString (s, 8); return b.toInt64(); }
static Identifier getPrototypeIdentifier() { static const Identifier i ("prototype"); return i; }
static var* getPropertyPointer (DynamicObject* o, Identifier i) { return o->getProperties().getVarPointer (i); }
//==============================================================================
struct CodeLocation
@@ -139,13 +140,13 @@ struct JavascriptEngine::RootObject : public DynamicObject
{
if (DynamicObject* o = targetObject.getDynamicObject())
{
if (var* prop = o->getProperties().getVarPointer (functionName))
if (const var* prop = getPropertyPointer (o, functionName))
return *prop;
for (DynamicObject* p = o->getProperty (getPrototypeIdentifier()).getDynamicObject(); p != nullptr;
p = p->getProperty (getPrototypeIdentifier()).getDynamicObject())
{
if (var* prop = p->getProperties().getVarPointer (functionName))
if (const var* prop = getPropertyPointer (p, functionName))
return *prop;
}
}
@@ -168,14 +169,14 @@ struct JavascriptEngine::RootObject : public DynamicObject
var* findRootClassProperty (Identifier className, Identifier propName) const
{
if (DynamicObject* cls = root->getProperty (className).getDynamicObject())
return cls->getProperties().getVarPointer (propName);
return getPropertyPointer (cls, propName);
return nullptr;
}
var findSymbolInParentScopes (Identifier name) const
{
if (var* v = scope->getProperties().getVarPointer (name))
if (const var* v = getPropertyPointer (scope, name))
return *v;
return parent != nullptr ? parent->findSymbolInParentScopes (name)
@@ -184,13 +185,11 @@ struct JavascriptEngine::RootObject : public DynamicObject
bool findAndInvokeMethod (Identifier function, const var::NativeFunctionArgs& args, var& result) const
{
const NamedValueSet& props = scope->getProperties();
DynamicObject* target = args.thisObject.getDynamicObject();
if (target == nullptr || target == scope)
{
if (const var* m = props.getVarPointer (function))
if (const var* m = getPropertyPointer (scope, function))
{
if (FunctionObject* fo = dynamic_cast<FunctionObject*> (m->getObject()))
{
@@ -200,6 +199,8 @@ struct JavascriptEngine::RootObject : public DynamicObject
}
}
const NamedValueSet& props = scope->getProperties();
for (int i = 0; i < props.size(); ++i)
if (DynamicObject* o = props.getValueAt (i).getDynamicObject())
if (Scope (this, root, o).findAndInvokeMethod (function, args, result))
@@ -353,7 +354,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
void assign (const Scope& s, const var& newValue) const override
{
if (var* v = s.scope->getProperties().getVarPointer (name))
if (var* v = getPropertyPointer (s.scope, name))
*v = newValue;
else
s.root->setProperty (name, newValue);
@@ -378,7 +379,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
}
if (DynamicObject* o = p.getDynamicObject())
if (var* v = o->getProperties().getVarPointer (child))
if (const var* v = getPropertyPointer (o, child))
return *v;
return var::undefined();
@@ -543,14 +544,14 @@ struct JavascriptEngine::RootObject : public DynamicObject
struct DivideOp : public BinaryOperator
{
DivideOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::divide) {}
var getWithDoubles (double a, double b) const override { return a / b; }
var getWithInts (int64 a, int64 b) const override { return a / b; }
var getWithDoubles (double a, double b) const override { return b != 0 ? a / b : std::numeric_limits<double>::infinity(); }
var getWithInts (int64 a, int64 b) const override { return b != 0 ? var (a / (double) b) : var (std::numeric_limits<double>::infinity()); }
};
struct ModuloOp : public BinaryOperator
{
ModuloOp (const CodeLocation& l, ExpPtr& a, ExpPtr& b) noexcept : BinaryOperator (l, a, b, TokenTypes::modulo) {}
var getWithInts (int64 a, int64 b) const override { return a % b; }
var getWithInts (int64 a, int64 b) const override { return b != 0 ? var (a % b) : var (std::numeric_limits<double>::infinity()); }
};
struct BitwiseOrOp : public BinaryOperator
@@ -768,7 +769,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
{
FunctionObject() noexcept {}
FunctionObject (const FunctionObject& other) : functionCode (other.functionCode)
FunctionObject (const FunctionObject& other) : DynamicObject(), functionCode (other.functionCode)
{
ExpressionTreeBuilder tb (functionCode);
tb.parseFunctionParamsAndBody (*this);
@@ -843,7 +844,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
String::CharPointerType end (p);
while (isIdentifierBody (*++end)) {}
const size_t len = end - p;
const size_t len = (size_t) (end - p);
#define JUCE_JS_COMPARE_KEYWORD(name, str) if (len == sizeof (str) - 1 && matchToken (TokenTypes::name, len)) return TokenTypes::name;
JUCE_JS_KEYWORDS (JUCE_JS_COMPARE_KEYWORD)
@@ -1145,8 +1146,14 @@ struct JavascriptEngine::RootObject : public DynamicObject
match (TokenTypes::semicolon);
}
s->iterator = parseExpression();
match (TokenTypes::closeParen);
if (matchIf (TokenTypes::closeParen))
s->iterator = new Statement (location);
else
{
s->iterator = parseExpression();
match (TokenTypes::closeParen);
}
s->body = parseStatement();
return s.release();
}
@@ -1555,6 +1562,7 @@ struct JavascriptEngine::RootObject : public DynamicObject
setMethod ("log", Math_log); setMethod ("log10", Math_log10);
setMethod ("exp", Math_exp); setMethod ("pow", Math_pow);
setMethod ("sqr", Math_sqr); setMethod ("sqrt", Math_sqrt);
setMethod ("ceil", Math_ceil); setMethod ("floor", Math_floor);
}
static var Math_pi (Args) { return double_Pi; }
@@ -1587,6 +1595,8 @@ struct JavascriptEngine::RootObject : public DynamicObject
static var Math_pow (Args a) { return pow (getDouble (a, 0), getDouble (a, 1)); }
static var Math_sqr (Args a) { double x = getDouble (a, 0); return x * x; }
static var Math_sqrt (Args a) { return std::sqrt (getDouble (a, 0)); }
static var Math_ceil (Args a) { return std::ceil (getDouble (a, 0)); }
static var Math_floor (Args a) { return std::floor (getDouble (a, 0)); }
static Identifier getClassName() { static const Identifier i ("Math"); return i; }
template <typename Type> static Type sign (Type n) noexcept { return n > 0 ? (Type) 1 : (n < 0 ? (Type) -1 : 0); }
@@ -1649,7 +1659,7 @@ JavascriptEngine::JavascriptEngine() : maximumExecutionTime (15.0), root (new R
JavascriptEngine::~JavascriptEngine() {}
void JavascriptEngine::prepareTimeout() const { root->timeout = Time::getCurrentTime() + maximumExecutionTime; }
void JavascriptEngine::prepareTimeout() const noexcept { root->timeout = Time::getCurrentTime() + maximumExecutionTime; }
void JavascriptEngine::registerNativeObject (Identifier name, DynamicObject* object)
{
@@ -1705,6 +1715,11 @@ var JavascriptEngine::callFunction (Identifier function, const var::NativeFuncti
return returnVal;
}
const NamedValueSet& JavascriptEngine::getRootObjectProperties() const noexcept
{
return root->getProperties();
}
#if JUCE_MSVC
#pragma warning (pop)
#endif
@@ -96,10 +96,13 @@ public:
*/
RelativeTime maximumExecutionTime;
/** Provides access to the set of properties of the root namespace object. */
const NamedValueSet& getRootObjectProperties() const noexcept;
private:
JUCE_PUBLIC_IN_DLL_BUILD (struct RootObject)
ReferenceCountedObjectPtr<RootObject> root;
void prepareTimeout() const;
const ReferenceCountedObjectPtr<RootObject> root;
void prepareTimeout() const noexcept;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JavascriptEngine)
};
@@ -53,6 +53,8 @@
#if JUCE_WINDOWS
#include <ctime>
#define _WINSOCK_DEPRECATED_NO_WARNINGS 1
#include <winsock2.h>
#include <ws2tcpip.h>
@@ -79,6 +81,7 @@
#if JUCE_LINUX
#include <langinfo.h>
#include <ifaddrs.h>
#endif
#include <pwd.h>
@@ -194,6 +194,7 @@ extern JUCE_API void JUCE_CALLTYPE logAssertion (const char* file, int line) noe
#include "threads/juce_ScopedLock.h"
#include "threads/juce_CriticalSection.h"
#include "maths/juce_Range.h"
#include "maths/juce_NormalisableRange.h"
#include "containers/juce_ElementComparator.h"
#include "containers/juce_ArrayAllocationBase.h"
#include "containers/juce_Array.h"
@@ -244,6 +245,7 @@ extern JUCE_API void JUCE_CALLTYPE logAssertion (const char* file, int line) noe
#include "misc/juce_Uuid.h"
#include "misc/juce_WindowsRegistry.h"
#include "system/juce_PlatformDefs.h"
#include "system/juce_CompilerSupport.h"
#include "system/juce_SystemStats.h"
#include "threads/juce_ChildProcess.h"
#include "threads/juce_DynamicLibrary.h"
@@ -1,7 +1,7 @@
{
"id": "juce_core",
"name": "JUCE core classes",
"version": "3.0.5",
"version": "3.0.8",
"description": "The essential set of basic JUCE classes, as required by all the other JUCE modules. Includes text, container, memory, threading and i/o functionality.",
"website": "http://www.juce.com/juce",
"license": "ISC Permissive",
@@ -307,41 +307,28 @@ void BigInteger::negate() noexcept
negative = (! negative) && ! isZero();
}
#if JUCE_USE_INTRINSICS && ! defined (__INTEL_COMPILER)
#if JUCE_USE_MSVC_INTRINSICS && ! defined (__INTEL_COMPILER)
#pragma intrinsic (_BitScanReverse)
#endif
namespace BitFunctions
inline static int highestBitInInt (uint32 n) noexcept
{
inline int countBitsInInt32 (uint32 n) noexcept
{
n -= ((n >> 1) & 0x55555555);
n = (((n >> 2) & 0x33333333) + (n & 0x33333333));
n = (((n >> 4) + n) & 0x0f0f0f0f);
n += (n >> 8);
n += (n >> 16);
return (int) (n & 0x3f);
}
jassert (n != 0); // (the built-in functions may not work for n = 0)
inline int highestBitInInt (uint32 n) noexcept
{
jassert (n != 0); // (the built-in functions may not work for n = 0)
#if JUCE_GCC
return 31 - __builtin_clz (n);
#elif JUCE_USE_INTRINSICS
unsigned long highest;
_BitScanReverse (&highest, n);
return (int) highest;
#else
n |= (n >> 1);
n |= (n >> 2);
n |= (n >> 4);
n |= (n >> 8);
n |= (n >> 16);
return countBitsInInt32 (n >> 1);
#endif
}
#if JUCE_GCC
return 31 - __builtin_clz (n);
#elif JUCE_USE_MSVC_INTRINSICS
unsigned long highest;
_BitScanReverse (&highest, n);
return (int) highest;
#else
n |= (n >> 1);
n |= (n >> 2);
n |= (n >> 4);
n |= (n >> 8);
n |= (n >> 16);
return countBitsInInt32 (n >> 1);
#endif
}
int BigInteger::countNumberOfSetBits() const noexcept
@@ -349,7 +336,7 @@ int BigInteger::countNumberOfSetBits() const noexcept
int total = 0;
for (int i = (int) bitToIndex (highestBit) + 1; --i >= 0;)
total += BitFunctions::countBitsInInt32 (values[i]);
total += countNumberOfBits (values[i]);
return total;
}
@@ -361,7 +348,7 @@ int BigInteger::getHighestBit() const noexcept
const uint32 n = values[i];
if (n != 0)
return BitFunctions::highestBitInInt (n) + (i << 5);
return highestBitInInt (n) + (i << 5);
}
return -1;
@@ -364,6 +364,11 @@ inline int roundToInt (const FloatType value) noexcept
#endif
}
inline int roundToInt (int value) noexcept
{
return value;
}
#if JUCE_MSVC
#ifndef __INTEL_COMPILER
#pragma float_control (pop)
@@ -438,6 +443,23 @@ inline int nextPowerOfTwo (int n) noexcept
return n + 1;
}
/** Returns the number of bits in a 32-bit integer. */
inline int countNumberOfBits (uint32 n) noexcept
{
n -= ((n >> 1) & 0x55555555);
n = (((n >> 2) & 0x33333333) + (n & 0x33333333));
n = (((n >> 4) + n) & 0x0f0f0f0f);
n += (n >> 8);
n += (n >> 16);
return (int) (n & 0x3f);
}
/** Returns the number of bits in a 64-bit integer. */
inline int countNumberOfBits (uint64 n) noexcept
{
return countNumberOfBits ((uint32) n) + countNumberOfBits ((uint32) (n >> 32));
}
/** Performs a modulo operation, but can cope with the dividend being negative.
The divisor must be greater than zero.
*/
@@ -77,6 +77,13 @@ public:
: Range (position2, position1);
}
/** Returns a range with a given start and length. */
static Range withStartAndLength (const ValueType startValue, const ValueType length) noexcept
{
jassert (length >= ValueType());
return Range (startValue, startValue + length);
}
/** Returns a range with the specified start position and a length of zero. */
static Range emptyRange (const ValueType start) noexcept
{
@@ -218,7 +218,7 @@ private:
#else
#define JUCE_ATOMICS_WINDOWS 1 // Windows with intrinsics
#if JUCE_USE_INTRINSICS
#if JUCE_USE_MSVC_INTRINSICS
#ifndef __INTEL_COMPILER
#pragma intrinsic (_InterlockedExchange, _InterlockedIncrement, _InterlockedDecrement, _InterlockedCompareExchange, \
_InterlockedCompareExchange64, _InterlockedExchangeAdd, _ReadWriteBarrier)
@@ -87,16 +87,16 @@ public:
//==============================================================================
/** Converts 3 little-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
static int littleEndian24Bit (const char* bytes) noexcept;
static int littleEndian24Bit (const void* bytes) noexcept;
/** Converts 3 big-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
static int bigEndian24Bit (const char* bytes) noexcept;
static int bigEndian24Bit (const void* bytes) noexcept;
/** Copies a 24-bit number to 3 little-endian bytes. */
static void littleEndian24BitToChars (int value, char* destBytes) noexcept;
static void littleEndian24BitToChars (int value, void* destBytes) noexcept;
/** Copies a 24-bit number to 3 big-endian bytes. */
static void bigEndian24BitToChars (int value, char* destBytes) noexcept;
static void bigEndian24BitToChars (int value, void* destBytes) noexcept;
//==============================================================================
/** Returns true if the current CPU is big-endian. */
@@ -110,16 +110,16 @@ private:
//==============================================================================
#if JUCE_USE_INTRINSICS && ! defined (__INTEL_COMPILER)
#if JUCE_USE_MSVC_INTRINSICS && ! defined (__INTEL_COMPILER)
#pragma intrinsic (_byteswap_ulong)
#endif
inline uint16 ByteOrder::swap (uint16 n) noexcept
{
#if JUCE_USE_INTRINSICSxxx // agh - the MS compiler has an internal error when you try to use this intrinsic!
return static_cast <uint16> (_byteswap_ushort (n));
#if JUCE_USE_MSVC_INTRINSICSxxx // agh - the MS compiler has an internal error when you try to use this intrinsic!
return static_cast<uint16> (_byteswap_ushort (n));
#else
return static_cast <uint16> ((n << 8) | (n >> 8));
return static_cast<uint16> ((n << 8) | (n >> 8));
#endif
}
@@ -130,7 +130,7 @@ inline uint32 ByteOrder::swap (uint32 n) noexcept
#elif JUCE_GCC && JUCE_INTEL && ! JUCE_NO_INLINE_ASM
asm("bswap %%eax" : "=a"(n) : "a"(n));
return n;
#elif JUCE_USE_INTRINSICS
#elif JUCE_USE_MSVC_INTRINSICS
return _byteswap_ulong (n);
#elif JUCE_MSVC && ! JUCE_NO_INLINE_ASM
__asm {
@@ -150,7 +150,7 @@ inline uint64 ByteOrder::swap (uint64 value) noexcept
{
#if JUCE_MAC || JUCE_IOS
return OSSwapInt64 (value);
#elif JUCE_USE_INTRINSICS
#elif JUCE_USE_MSVC_INTRINSICS
return _byteswap_uint64 (value);
#else
return (((int64) swap ((uint32) value)) << 32) | swap ((uint32) (value >> 32));
@@ -164,12 +164,12 @@ inline uint64 ByteOrder::swap (uint64 value) noexcept
inline uint16 ByteOrder::swapIfLittleEndian (const uint16 v) noexcept { return swap (v); }
inline uint32 ByteOrder::swapIfLittleEndian (const uint32 v) noexcept { return swap (v); }
inline uint64 ByteOrder::swapIfLittleEndian (const uint64 v) noexcept { return swap (v); }
inline uint32 ByteOrder::littleEndianInt (const void* const bytes) noexcept { return *static_cast <const uint32*> (bytes); }
inline uint64 ByteOrder::littleEndianInt64 (const void* const bytes) noexcept { return *static_cast <const uint64*> (bytes); }
inline uint16 ByteOrder::littleEndianShort (const void* const bytes) noexcept { return *static_cast <const uint16*> (bytes); }
inline uint32 ByteOrder::bigEndianInt (const void* const bytes) noexcept { return swap (*static_cast <const uint32*> (bytes)); }
inline uint64 ByteOrder::bigEndianInt64 (const void* const bytes) noexcept { return swap (*static_cast <const uint64*> (bytes)); }
inline uint16 ByteOrder::bigEndianShort (const void* const bytes) noexcept { return swap (*static_cast <const uint16*> (bytes)); }
inline uint32 ByteOrder::littleEndianInt (const void* const bytes) noexcept { return *static_cast<const uint32*> (bytes); }
inline uint64 ByteOrder::littleEndianInt64 (const void* const bytes) noexcept { return *static_cast<const uint64*> (bytes); }
inline uint16 ByteOrder::littleEndianShort (const void* const bytes) noexcept { return *static_cast<const uint16*> (bytes); }
inline uint32 ByteOrder::bigEndianInt (const void* const bytes) noexcept { return swap (*static_cast<const uint32*> (bytes)); }
inline uint64 ByteOrder::bigEndianInt64 (const void* const bytes) noexcept { return swap (*static_cast<const uint64*> (bytes)); }
inline uint16 ByteOrder::bigEndianShort (const void* const bytes) noexcept { return swap (*static_cast<const uint16*> (bytes)); }
inline bool ByteOrder::isBigEndian() noexcept { return false; }
#else
inline uint16 ByteOrder::swapIfBigEndian (const uint16 v) noexcept { return swap (v); }
@@ -178,19 +178,19 @@ inline uint64 ByteOrder::swap (uint64 value) noexcept
inline uint16 ByteOrder::swapIfLittleEndian (const uint16 v) noexcept { return v; }
inline uint32 ByteOrder::swapIfLittleEndian (const uint32 v) noexcept { return v; }
inline uint64 ByteOrder::swapIfLittleEndian (const uint64 v) noexcept { return v; }
inline uint32 ByteOrder::littleEndianInt (const void* const bytes) noexcept { return swap (*static_cast <const uint32*> (bytes)); }
inline uint64 ByteOrder::littleEndianInt64 (const void* const bytes) noexcept { return swap (*static_cast <const uint64*> (bytes)); }
inline uint16 ByteOrder::littleEndianShort (const void* const bytes) noexcept { return swap (*static_cast <const uint16*> (bytes)); }
inline uint32 ByteOrder::bigEndianInt (const void* const bytes) noexcept { return *static_cast <const uint32*> (bytes); }
inline uint64 ByteOrder::bigEndianInt64 (const void* const bytes) noexcept { return *static_cast <const uint64*> (bytes); }
inline uint16 ByteOrder::bigEndianShort (const void* const bytes) noexcept { return *static_cast <const uint16*> (bytes); }
inline uint32 ByteOrder::littleEndianInt (const void* const bytes) noexcept { return swap (*static_cast<const uint32*> (bytes)); }
inline uint64 ByteOrder::littleEndianInt64 (const void* const bytes) noexcept { return swap (*static_cast<const uint64*> (bytes)); }
inline uint16 ByteOrder::littleEndianShort (const void* const bytes) noexcept { return swap (*static_cast<const uint16*> (bytes)); }
inline uint32 ByteOrder::bigEndianInt (const void* const bytes) noexcept { return *static_cast<const uint32*> (bytes); }
inline uint64 ByteOrder::bigEndianInt64 (const void* const bytes) noexcept { return *static_cast<const uint64*> (bytes); }
inline uint16 ByteOrder::bigEndianShort (const void* const bytes) noexcept { return *static_cast<const uint16*> (bytes); }
inline bool ByteOrder::isBigEndian() noexcept { return true; }
#endif
inline int ByteOrder::littleEndian24Bit (const char* const bytes) noexcept { return (((int) bytes[2]) << 16) | (((int) (uint8) bytes[1]) << 8) | ((int) (uint8) bytes[0]); }
inline int ByteOrder::bigEndian24Bit (const char* const bytes) noexcept { return (((int) bytes[0]) << 16) | (((int) (uint8) bytes[1]) << 8) | ((int) (uint8) bytes[2]); }
inline void ByteOrder::littleEndian24BitToChars (const int value, char* const destBytes) noexcept { destBytes[0] = (char)(value & 0xff); destBytes[1] = (char)((value >> 8) & 0xff); destBytes[2] = (char)((value >> 16) & 0xff); }
inline void ByteOrder::bigEndian24BitToChars (const int value, char* const destBytes) noexcept { destBytes[0] = (char)((value >> 16) & 0xff); destBytes[1] = (char)((value >> 8) & 0xff); destBytes[2] = (char)(value & 0xff); }
inline int ByteOrder::littleEndian24Bit (const void* const bytes) noexcept { return (((int) static_cast<const int8*> (bytes)[2]) << 16) | (((int) static_cast<const uint8*> (bytes)[1]) << 8) | ((int) static_cast<const uint8*> (bytes)[0]); }
inline int ByteOrder::bigEndian24Bit (const void* const bytes) noexcept { return (((int) static_cast<const int8*> (bytes)[0]) << 16) | (((int) static_cast<const uint8*> (bytes)[1]) << 8) | ((int) static_cast<const uint8*> (bytes)[2]); }
inline void ByteOrder::littleEndian24BitToChars (const int value, void* const destBytes) noexcept { static_cast<uint8*> (destBytes)[0] = (uint8) value; static_cast<uint8*> (destBytes)[1] = (uint8) (value >> 8); static_cast<uint8*> (destBytes)[2] = (uint8) (value >> 16); }
inline void ByteOrder::bigEndian24BitToChars (const int value, void* const destBytes) noexcept { static_cast<uint8*> (destBytes)[0] = (uint8) (value >> 16); static_cast<uint8*> (destBytes)[1] = (uint8) (value >> 8); static_cast<uint8*> (destBytes)[2] = (uint8) value; }
#endif // JUCE_BYTEORDER_H_INCLUDED
@@ -88,14 +88,14 @@ MemoryBlock& MemoryBlock::operator= (const MemoryBlock& other)
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
MemoryBlock::MemoryBlock (MemoryBlock&& other) noexcept
: data (static_cast <HeapBlock<char>&&> (other.data)),
: data (static_cast<HeapBlock<char>&&> (other.data)),
size (other.size)
{
}
MemoryBlock& MemoryBlock::operator= (MemoryBlock&& other) noexcept
{
data = static_cast <HeapBlock<char>&&> (other.data);
data = static_cast<HeapBlock<char>&&> (other.data);
size = other.size;
return *this;
}
@@ -346,7 +346,7 @@ void MemoryBlock::loadFromHexString (StringRef hex)
if (c == 0)
{
setSize (static_cast <size_t> (dest - data));
setSize (static_cast<size_t> (dest - data));
return;
}
}
@@ -208,7 +208,7 @@ private:
The template parameter specifies the class of the object you want to point to - the easiest
way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject
or SingleThreadedReferenceCountedObject, but if you need to, you can roll your own reference-countable
class by implementing a set of mathods called incReferenceCount(), decReferenceCount(), and
class by implementing a set of methods called incReferenceCount(), decReferenceCount(), and
decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods
should behave.
@@ -182,11 +182,11 @@ public:
/** Swaps this object with that of another ScopedPointer.
The two objects simply exchange their pointers.
*/
void swapWith (ScopedPointer <ObjectType>& other) noexcept
void swapWith (ScopedPointer<ObjectType>& other) noexcept
{
// 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 || this == other.getAddress());
jassert (object != other.object || this == other.getAddress() || object == nullptr);
std::swap (object, other.object);
}
@@ -231,7 +231,7 @@ private:
template <class ObjectType>
bool operator== (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
{
return static_cast <ObjectType*> (pointer1) == pointer2;
return static_cast<ObjectType*> (pointer1) == pointer2;
}
/** Compares a ScopedPointer with another pointer.
@@ -240,7 +240,7 @@ bool operator== (const ScopedPointer<ObjectType>& pointer1, ObjectType* const po
template <class ObjectType>
bool operator!= (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
{
return static_cast <ObjectType*> (pointer1) != pointer2;
return static_cast<ObjectType*> (pointer1) != pointer2;
}
//==============================================================================
@@ -139,7 +139,7 @@ private:
static SharedObjectHolder& getSharedObjectHolder() noexcept
{
static char holder [sizeof (SharedObjectHolder)] = { 0 };
static void* holder [(sizeof (SharedObjectHolder) + sizeof(void*) - 1) / sizeof(void*)] = { 0 };
return *reinterpret_cast<SharedObjectHolder*> (holder);
}
@@ -158,7 +158,7 @@ public:
public:
Master() noexcept {}
~Master()
~Master() noexcept
{
// You must remember to call clear() in your source object's destructor! See the notes
// for the WeakReference class for an example of how to do this.
@@ -187,7 +187,7 @@ public:
to zero all the references to this object that may be out there. See the WeakReference
class notes for an example of how to do this.
*/
void clear()
void clear() noexcept
{
if (sharedPointer != nullptr)
sharedPointer->clearPointer();
@@ -399,16 +399,21 @@ public final class JuceAppActivity extends Activity
private native void handleKeyDown (long host, int keycode, int textchar);
private native void handleKeyUp (long host, int keycode, int textchar);
public void showKeyboard (boolean shouldShow)
public void showKeyboard (String type)
{
InputMethodManager imm = (InputMethodManager) getSystemService (Context.INPUT_METHOD_SERVICE);
if (imm != null)
{
if (shouldShow)
imm.showSoftInput (this, InputMethodManager.SHOW_FORCED);
if (type.length() > 0)
{
imm.showSoftInput (this, android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT);
imm.setInputMethod (getWindowToken(), type);
}
else
{
imm.hideSoftInputFromWindow (getWindowToken(), 0);
}
}
}
@@ -271,26 +271,33 @@ public:
JNIEnv* attach() noexcept
{
if (JNIEnv* env = attachToCurrentThread())
if (android.activity != nullptr)
{
SpinLock::ScopedLockType sl (addRemoveLock);
return addEnv (env);
if (JNIEnv* env = attachToCurrentThread())
{
SpinLock::ScopedLockType sl (addRemoveLock);
return addEnv (env);
}
jassertfalse;
}
jassertfalse;
return nullptr;
}
void detach() noexcept
{
jvm->DetachCurrentThread();
if (android.activity != nullptr)
{
jvm->DetachCurrentThread();
const pthread_t thisThread = pthread_self();
const pthread_t thisThread = pthread_self();
SpinLock::ScopedLockType sl (addRemoveLock);
for (int i = 0; i < maxThreads; ++i)
if (threads[i] == thisThread)
threads[i] = 0;
SpinLock::ScopedLockType sl (addRemoveLock);
for (int i = 0; i < maxThreads; ++i)
if (threads[i] == thisThread)
threads[i] = 0;
}
}
JNIEnv* getOrAttach() noexcept
@@ -355,6 +362,12 @@ private:
extern ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder;
struct AndroidThreadScope
{
AndroidThreadScope() { threadLocalJNIEnvHolder.attach(); }
~AndroidThreadScope() { threadLocalJNIEnvHolder.detach(); }
};
//==============================================================================
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
METHOD (createNewView, "createNewView", "(ZJ)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView;") \
@@ -166,7 +166,7 @@ public:
int numBytes = stream.callIntMethod (HTTPStream.read, javaArray, (jint) bytesToRead);
if (numBytes > 0)
env->GetByteArrayRegion (javaArray, 0, numBytes, static_cast <jbyte*> (buffer));
env->GetByteArrayRegion (javaArray, 0, numBytes, static_cast<jbyte*> (buffer));
env->DeleteLocalRef (javaArray);
return numBytes;
@@ -179,6 +179,16 @@ namespace AndroidStatsHelpers
JuceAppActivity.getLocaleValue,
isRegion)));
}
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD)
DECLARE_JNI_CLASS (BuildClass, "android/os/Build");
#undef JNI_CLASS_MEMBERS
String getAndroidOsBuildValue (const char* fieldName)
{
return juceString (LocalRef<jstring> ((jstring) getEnv()->GetStaticObjectField (
BuildClass, getEnv()->GetStaticFieldID (BuildClass, fieldName, "Ljava/lang/String;"))));
}
}
//==============================================================================
@@ -194,7 +204,8 @@ String SystemStats::getOperatingSystemName()
String SystemStats::getDeviceDescription()
{
return String::empty;
return AndroidStatsHelpers::getAndroidOsBuildValue ("MODEL")
+ "-" + AndroidStatsHelpers::getAndroidOsBuildValue ("SERIAL");
}
bool SystemStats::isOperatingSystem64Bit()
@@ -262,7 +273,7 @@ String SystemStats::getComputerName()
String SystemStats::getUserLanguage() { return AndroidStatsHelpers::getLocaleValue (false); }
String SystemStats::getUserRegion() { return AndroidStatsHelpers::getLocaleValue (true); }
String SystemStats::getDisplayLanguage() { return getUserLanguage(); }
String SystemStats::getDisplayLanguage() { return getUserLanguage() + "-" + getUserRegion(); }
//==============================================================================
void CPUInformation::initialise() noexcept
@@ -31,23 +31,26 @@ void MACAddress::findAllAddresses (Array<MACAddress>& result)
const int s = socket (AF_INET, SOCK_DGRAM, 0);
if (s != -1)
{
char buf [1024];
struct ifconf ifc;
ifc.ifc_len = sizeof (buf);
ifc.ifc_buf = buf;
ioctl (s, SIOCGIFCONF, &ifc);
struct ifaddrs* addrs = nullptr;
for (unsigned int i = 0; i < ifc.ifc_len / sizeof (struct ifreq); ++i)
if (getifaddrs (&addrs) != -1)
{
struct ifreq ifr;
strcpy (ifr.ifr_name, ifc.ifc_req[i].ifr_name);
if (ioctl (s, SIOCGIFFLAGS, &ifr) == 0
&& (ifr.ifr_flags & IFF_LOOPBACK) == 0
&& ioctl (s, SIOCGIFHWADDR, &ifr) == 0)
for (struct ifaddrs* i = addrs; i != nullptr; i = i->ifa_next)
{
result.addIfNotAlreadyThere (MACAddress ((const uint8*) ifr.ifr_hwaddr.sa_data));
struct ifreq ifr;
strcpy (ifr.ifr_name, i->ifa_name);
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl (s, SIOCGIFHWADDR, &ifr) == 0)
{
MACAddress ma ((const uint8*) ifr.ifr_hwaddr.sa_data);
if (! ma.isNull())
result.addIfNotAlreadyThere (ma);
}
}
freeifaddrs (addrs);
}
close (s);
@@ -260,7 +263,7 @@ private:
}
}
String responseHeader (readResponse (socketHandle, timeOutTime));
String responseHeader (readResponse (timeOutTime));
position = 0;
if (responseHeader.isNotEmpty())
@@ -299,7 +302,7 @@ private:
}
//==============================================================================
String readResponse (const int socketHandle, const uint32 timeOutTime)
String readResponse (const uint32 timeOutTime)
{
int numConsecutiveLFs = 0;
MemoryOutputStream buffer;
@@ -335,7 +338,8 @@ private:
dest << "\r\n" << key << ' ' << value;
}
static void writeHost (MemoryOutputStream& dest, const bool isPost, const String& path, const String& host, const int port)
static void writeHost (MemoryOutputStream& dest, const bool isPost,
const String& path, const String& host, int /*port*/)
{
dest << (isPost ? "POST " : "GET ") << path << " HTTP/1.0\r\nHost: " << host;
}
@@ -139,7 +139,7 @@ static String getLocaleValue (nl_item key)
String SystemStats::getUserLanguage() { return getLocaleValue (_NL_IDENTIFICATION_LANGUAGE); }
String SystemStats::getUserRegion() { return getLocaleValue (_NL_IDENTIFICATION_TERRITORY); }
String SystemStats::getDisplayLanguage() { return getUserLanguage(); }
String SystemStats::getDisplayLanguage() { return getUserLanguage() + "-" + getUserRegion(); }
//==============================================================================
void CPUInformation::initialise() noexcept
@@ -79,10 +79,11 @@ JUCE_API bool JUCE_CALLTYPE Process::isRunningUnderDebugger()
return juce_isRunningUnderDebugger();
}
static void swapUserAndEffectiveUser()
static bool swapUserAndEffectiveUser()
{
(void) setreuid (geteuid(), getuid());
(void) setregid (getegid(), getgid());
int result1 = setreuid (geteuid(), getuid());
int result2 = setregid (getegid(), getgid());
return result1 == 0 && result2 == 0;
}
JUCE_API void JUCE_CALLTYPE Process::raisePrivilege() { if (geteuid() != 0 && getuid() == 0) swapUserAndEffectiveUser(); }
@@ -39,12 +39,17 @@ void MACAddress::findAllAddresses (Array<MACAddress>& result)
{
const sockaddr_dl* const sadd = (const sockaddr_dl*) cursor->ifa_addr;
#ifndef IFT_ETHER
#define IFT_ETHER 6
#endif
#ifndef IFT_ETHER
enum { IFT_ETHER = 6 };
#endif
if (sadd->sdl_type == IFT_ETHER)
result.addIfNotAlreadyThere (MACAddress (((const uint8*) sadd->sdl_data) + sadd->sdl_nlen));
{
MACAddress ma (MACAddress (((const uint8*) sadd->sdl_data) + sadd->sdl_nlen));
if (! ma.isNull())
result.addIfNotAlreadyThere (ma);
}
}
}
@@ -124,7 +124,7 @@ SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
return iOS;
#else
StringArray parts;
parts.addTokens (getOSXVersion(), ".", String());
parts.addTokens (getOSXVersion(), ".", StringRef());
jassert (parts[0].getIntValue() == 10);
const int major = parts[1].getIntValue();
@@ -241,35 +241,41 @@ String SystemStats::getDisplayLanguage()
}
//==============================================================================
class HiResCounterHandler
/* NB: these are kept outside the HiResCounterInfo struct and initialised to 1 to avoid
division-by-zero errors if some other static constructor calls us before this file's
static constructors have had a chance to fill them in correctly..
*/
static uint64 hiResCounterNumerator = 0, hiResCounterDenominator = 1;
class HiResCounterInfo
{
public:
HiResCounterHandler()
HiResCounterInfo()
{
mach_timebase_info_data_t timebase;
(void) mach_timebase_info (&timebase);
if (timebase.numer % 1000000 == 0)
{
numerator = timebase.numer / 1000000;
denominator = timebase.denom;
hiResCounterNumerator = timebase.numer / 1000000;
hiResCounterDenominator = timebase.denom;
}
else
{
numerator = timebase.numer;
denominator = timebase.denom * (uint64) 1000000;
hiResCounterNumerator = timebase.numer;
hiResCounterDenominator = timebase.denom * (uint64) 1000000;
}
highResTimerFrequency = (timebase.denom * (uint64) 1000000000) / timebase.numer;
highResTimerToMillisecRatio = numerator / (double) denominator;
highResTimerToMillisecRatio = hiResCounterNumerator / (double) hiResCounterDenominator;
}
inline uint32 millisecondsSinceStartup() const noexcept
uint32 millisecondsSinceStartup() const noexcept
{
return (uint32) ((mach_absolute_time() * numerator) / denominator);
return (uint32) ((mach_absolute_time() * hiResCounterNumerator) / hiResCounterDenominator);
}
inline double getMillisecondCounterHiRes() const noexcept
double getMillisecondCounterHiRes() const noexcept
{
return mach_absolute_time() * highResTimerToMillisecRatio;
}
@@ -277,15 +283,14 @@ public:
int64 highResTimerFrequency;
private:
uint64 numerator, denominator;
double highResTimerToMillisecRatio;
};
static HiResCounterHandler hiResCounterHandler;
static HiResCounterInfo hiResCounterInfo;
uint32 juce_millisecondsSinceStartup() noexcept { return hiResCounterHandler.millisecondsSinceStartup(); }
double Time::getMillisecondCounterHiRes() noexcept { return hiResCounterHandler.getMillisecondCounterHiRes(); }
int64 Time::getHighResolutionTicksPerSecond() noexcept { return hiResCounterHandler.highResTimerFrequency; }
uint32 juce_millisecondsSinceStartup() noexcept { return hiResCounterInfo.millisecondsSinceStartup(); }
double Time::getMillisecondCounterHiRes() noexcept { return hiResCounterInfo.getMillisecondCounterHiRes(); }
int64 Time::getHighResolutionTicksPerSecond() noexcept { return hiResCounterInfo.highResTimerFrequency; }
int64 Time::getHighResolutionTicks() noexcept { return (int64) mach_absolute_time(); }
bool Time::setSystemTimeToThisTime() const
@@ -223,6 +223,12 @@ namespace
return statfs (f.getFullPathName().toUTF8(), &result) == 0;
}
#if (JUCE_MAC && MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5) || JUCE_IOS
static int64 getCreationTime (const juce_statStruct& s) noexcept { return (int64) s.st_birthtime; }
#else
static int64 getCreationTime (const juce_statStruct& s) noexcept { return (int64) s.st_ctime; }
#endif
void updateStatInfoForFile (const String& path, bool* const isDir, int64* const fileSize,
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
{
@@ -232,9 +238,9 @@ namespace
const bool statOk = juce_stat (path, info);
if (isDir != nullptr) *isDir = statOk && ((info.st_mode & S_IFDIR) != 0);
if (fileSize != nullptr) *fileSize = statOk ? info.st_size : 0;
if (modTime != nullptr) *modTime = Time (statOk ? (int64) info.st_mtime * 1000 : 0);
if (creationTime != nullptr) *creationTime = Time (statOk ? (int64) info.st_ctime * 1000 : 0);
if (fileSize != nullptr) *fileSize = statOk ? (int64) info.st_size : 0;
if (modTime != nullptr) *modTime = Time (statOk ? (int64) info.st_mtime * 1000 : 0);
if (creationTime != nullptr) *creationTime = Time (statOk ? getCreationTime (info) * 1000 : 0);
}
if (isReadOnly != nullptr)
@@ -280,6 +286,12 @@ int64 File::getSize() const
return juce_stat (fullPath, info) ? info.st_size : 0;
}
uint64 File::getFileIdentifier() const
{
juce_statStruct info;
return juce_stat (fullPath, info) ? (uint64) info.st_ino : 0;
}
//==============================================================================
bool File::hasWriteAccess() const
{
@@ -391,13 +403,10 @@ void FileInputStream::openHandle()
status = getResultForErrno();
}
void FileInputStream::closeHandle()
FileInputStream::~FileInputStream()
{
if (fileHandle != 0)
{
close (getFD (fileHandle));
fileHandle = 0;
}
}
size_t FileInputStream::readInternal (void* const buffer, const size_t numBytes)
@@ -661,6 +670,7 @@ int File::getVolumeSerialNumber() const
}
//==============================================================================
#if ! JUCE_IOS
void juce_runSystemCommand (const String&);
void juce_runSystemCommand (const String& command)
{
@@ -681,7 +691,7 @@ String juce_getOutputFromCommand (const String& command)
tempFile.deleteFile();
return result;
}
#endif
//==============================================================================
#if JUCE_IOS
@@ -834,12 +844,6 @@ extern "C" void* threadEntryProc (void* userData)
JUCE_AUTORELEASEPOOL
{
#if JUCE_ANDROID
struct AndroidThreadScope
{
AndroidThreadScope() { threadLocalJNIEnvHolder.attach(); }
~AndroidThreadScope() { threadLocalJNIEnvHolder.detach(); }
};
const AndroidThreadScope androidEnv;
#endif
@@ -1017,12 +1021,12 @@ public:
// we're the child process..
close (pipeHandles[0]); // close the read handle
if ((streamFlags | wantStdOut) != 0)
if ((streamFlags & wantStdOut) != 0)
dup2 (pipeHandles[1], 1); // turns the pipe into stdout
else
close (STDOUT_FILENO);
if ((streamFlags | wantStdErr) != 0)
if ((streamFlags & wantStdErr) != 0)
dup2 (pipeHandles[1], 2);
else
close (STDERR_FILENO);
@@ -1032,7 +1036,7 @@ public:
Array<char*> argv;
for (int i = 0; i < arguments.size(); ++i)
if (arguments[i].isNotEmpty())
argv.add (arguments[i].toUTF8().getAddress());
argv.add (const_cast<char*> (arguments[i].toUTF8().getAddress()));
argv.add (nullptr);
@@ -1147,16 +1151,25 @@ struct HighResolutionTimer::Pimpl
void start (int newPeriod)
{
periodMs = newPeriod;
if (thread == 0)
if (periodMs != newPeriod)
{
shouldStop = false;
if (thread != pthread_self())
{
stop();
if (pthread_create (&thread, nullptr, timerThread, this) == 0)
setThreadToRealtime (thread, (uint64) newPeriod);
periodMs = newPeriod;
shouldStop = false;
if (pthread_create (&thread, nullptr, timerThread, this) == 0)
setThreadToRealtime (thread, (uint64) newPeriod);
else
jassertfalse;
}
else
jassertfalse;
{
periodMs = newPeriod;
shouldStop = false;
}
}
}
@@ -1180,7 +1193,9 @@ private:
static void* timerThread (void* param)
{
#if ! JUCE_ANDROID
#if JUCE_ANDROID
const AndroidThreadScope androidEnv;
#else
int dummy;
pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &dummy);
#endif
@@ -1191,12 +1206,19 @@ private:
void timerThread()
{
Clock clock (periodMs);
int lastPeriod = periodMs;
Clock clock (lastPeriod);
while (! shouldStop)
{
clock.wait();
owner.hiResTimerCallback();
if (lastPeriod != periodMs)
{
lastPeriod = periodMs;
clock = Clock (lastPeriod);
}
}
periodMs = 0;
@@ -1210,7 +1232,7 @@ private:
{
mach_timebase_info_data_t timebase;
(void) mach_timebase_info (&timebase);
delta = (((uint64_t) (millis * 1000000.0)) * timebase.numer) / timebase.denom;
delta = (((uint64_t) (millis * 1000000.0)) * timebase.denom) / timebase.numer;
time = mach_absolute_time();
}
@@ -234,7 +234,7 @@ void FileInputStream::openHandle()
status = WindowsFileHelpers::getResultForLastError();
}
void FileInputStream::closeHandle()
FileInputStream::~FileInputStream()
{
CloseHandle ((HANDLE) fileHandle);
}
@@ -474,6 +474,28 @@ int64 File::getVolumeTotalSize() const
return WindowsFileHelpers::getDiskSpaceInfo (getFullPathName(), true);
}
uint64 File::getFileIdentifier() const
{
uint64 result = 0;
HANDLE h = CreateFile (getFullPathName().toWideCharPointer(),
GENERIC_READ, FILE_SHARE_READ, nullptr,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
if (h != INVALID_HANDLE_VALUE)
{
BY_HANDLE_FILE_INFORMATION info;
zerostruct (info);
if (GetFileInformationByHandle (h, &info))
result = (((uint64) info.nFileIndexHigh) << 32) | info.nFileIndexLow;
CloseHandle (h);
}
return result;
}
//==============================================================================
bool File::isOnCDRomDrive() const
{
@@ -532,6 +554,14 @@ File JUCE_CALLTYPE File::getSpecialLocation (const SpecialLocationType type)
return File (String (dest));
}
case windowsSystemDirectory:
{
WCHAR dest [2048];
dest[0] = 0;
GetSystemDirectoryW (dest, (UINT) numElementsInArray (dest));
return File (String (dest));
}
case invokedExecutableFile:
case currentExecutableFile:
case currentApplicationFile:
@@ -45,13 +45,14 @@ public:
address (address_), headers (headers_), postData (postData_), position (0),
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
{
createConnection (progressCallback, progressCallbackContext);
if (! isError())
for (int maxRedirects = 10; --maxRedirects >= 0;)
{
if (responseHeaders != nullptr)
createConnection (progressCallback, progressCallbackContext);
if (! isError())
{
DWORD bufferSizeBytes = 4096;
StringPairArray headers (false);
for (;;)
{
@@ -65,11 +66,10 @@ public:
for (int i = 0; i < headersArray.size(); ++i)
{
const String& header = headersArray[i];
const String key (header.upToFirstOccurrenceOf (": ", false, false));
const String key (header.upToFirstOccurrenceOf (": ", false, false));
const String value (header.fromFirstOccurrenceOf (": ", false, false));
const String previousValue ((*responseHeaders) [key]);
responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
const String previousValue (headers[key]);
headers.set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
}
break;
@@ -77,14 +77,34 @@ public:
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
break;
bufferSizeBytes += 4096;
}
DWORD status = 0;
DWORD statusSize = sizeof (status);
if (HttpQueryInfo (request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &statusSize, 0))
{
statusCode = (int) status;
if (status == 301 || status == 302 || status == 303 || status == 307)
{
const String newLocation (headers["Location"]);
if (newLocation.isNotEmpty() && newLocation != address)
{
address = newLocation;
continue;
}
}
}
if (responseHeaders != nullptr)
responseHeaders->addArray (headers);
}
DWORD status = 0;
DWORD statusSize = sizeof (status);
if (HttpQueryInfo (request, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &statusSize, 0))
statusCode = (int) status;
break;
}
}
@@ -259,7 +279,8 @@ private:
{
const TCHAR* mimeTypes[] = { _T("*/*"), nullptr };
DWORD flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES;
DWORD flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES
| INTERNET_FLAG_NO_AUTO_REDIRECT | SECURITY_SET_MASK;
if (address.startsWithIgnoreCase ("https:"))
flags |= INTERNET_FLAG_SECURE; // (this flag only seems necessary if the OS is running IE6 -
@@ -270,6 +291,8 @@ private:
if (request != 0)
{
setSecurityFlags();
INTERNET_BUFFERS buffers = { 0 };
buffers.dwStructSize = sizeof (INTERNET_BUFFERS);
buffers.lpcszHeader = headers.toWideCharPointer();
@@ -287,7 +310,7 @@ private:
if (bytesToDo > 0
&& ! InternetWriteFile (request,
static_cast <const char*> (postData.getData()) + bytesSent,
static_cast<const char*> (postData.getData()) + bytesSent,
(DWORD) bytesToDo, &bytesDone))
{
break;
@@ -313,6 +336,14 @@ private:
close();
}
void setSecurityFlags()
{
DWORD dwFlags = 0, dwBuffLen = sizeof (DWORD);
InternetQueryOption (request, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, &dwBuffLen);
dwFlags |= SECURITY_FLAG_IGNORE_UNKNOWN_CA | SECURITY_SET_MASK;
InternetSetOption (request, INTERNET_OPTION_SECURITY_FLAGS, &dwFlags, sizeof (dwFlags));
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
};
@@ -342,7 +373,13 @@ struct GetAdaptersInfoHelper
namespace MACAddressHelpers
{
void getViaGetAdaptersInfo (Array<MACAddress>& result)
static void addAddress (Array<MACAddress>& result, const MACAddress& ma)
{
if (! ma.isNull())
result.addIfNotAlreadyThere (ma);
}
static void getViaGetAdaptersInfo (Array<MACAddress>& result)
{
GetAdaptersInfoHelper gah;
@@ -350,11 +387,11 @@ namespace MACAddressHelpers
{
for (PIP_ADAPTER_INFO adapter = gah.adapterInfo; adapter != nullptr; adapter = adapter->Next)
if (adapter->AddressLength >= 6)
result.addIfNotAlreadyThere (MACAddress (adapter->Address));
addAddress (result, MACAddress (adapter->Address));
}
}
void getViaNetBios (Array<MACAddress>& result)
static void getViaNetBios (Array<MACAddress>& result)
{
DynamicLibrary dll ("netapi32.dll");
JUCE_LOAD_WINAPI_FUNCTION (dll, Netbios, NetbiosCall, UCHAR, (PNCB))
@@ -396,7 +433,7 @@ namespace MACAddressHelpers
ncb.ncb_length = sizeof (ASTAT);
if (NetbiosCall (&ncb) == 0 && astat.adapt.adapter_type == 0xfe)
result.addIfNotAlreadyThere (MACAddress (astat.adapt.adapter_address));
addAddress (result, MACAddress (astat.adapt.adapter_address));
}
}
}
@@ -38,7 +38,7 @@ void Logger::outputDebugString (const String& text)
#endif
//==============================================================================
#if JUCE_USE_INTRINSICS
#if JUCE_USE_MSVC_INTRINSICS
// CPU info functions using intrinsics...
@@ -137,10 +137,11 @@ static bool isWindowsVersionOrLater (SystemStats::OperatingSystemType target)
switch (target)
{
case SystemStats::WinVista: info.dwMinorVersion = 0; break;
case SystemStats::Windows7: info.dwMinorVersion = 1; break;
case SystemStats::Windows8: info.dwMinorVersion = 2; break;
default: jassertfalse; break;
case SystemStats::WinVista: break;
case SystemStats::Windows7: info.dwMinorVersion = 1; break;
case SystemStats::Windows8_0: info.dwMinorVersion = 2; break;
case SystemStats::Windows8_1: info.dwMinorVersion = 3; break;
default: jassertfalse; break;
}
}
else
@@ -165,7 +166,7 @@ static bool isWindowsVersionOrLater (SystemStats::OperatingSystemType target)
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
{
const SystemStats::OperatingSystemType types[]
= { Windows8, Windows7, WinVista, WinXP, Win2000 };
= { Windows8_1, Windows8_0, Windows7, WinVista, WinXP, Win2000 };
for (int i = 0; i < numElementsInArray (types); ++i)
if (isWindowsVersionOrLater (types[i]))
@@ -181,8 +182,9 @@ String SystemStats::getOperatingSystemName()
switch (getOperatingSystemType())
{
case Windows8_1: name = "Windows 8.1"; break;
case Windows8_0: name = "Windows 8.0"; break;
case Windows7: name = "Windows 7"; break;
case Windows8: name = "Windows 8"; break;
case WinVista: name = "Windows Vista"; break;
case WinXP: name = "Windows XP"; break;
case Win2000: name = "Windows 2000"; break;
@@ -194,7 +196,7 @@ String SystemStats::getOperatingSystemName()
String SystemStats::getDeviceDescription()
{
return String::empty;
return String();
}
bool SystemStats::isOperatingSystem64Bit()
@@ -251,9 +253,23 @@ public:
HiResCounterHandler()
: hiResTicksOffset (0)
{
const MMRESULT res = timeBeginPeriod (1);
// This macro allows you to override the default timer-period
// used on Windows. By default this is set to 1, because that has
// always been the value used in JUCE apps, and changing it could
// affect the behaviour of existing code, but you may wish to make
// it larger (or set it to 0 to use the system default) to make your
// app less demanding on the CPU.
// For more info, see win32 documentation about the timeBeginPeriod
// function.
#ifndef JUCE_WIN32_TIMER_PERIOD
#define JUCE_WIN32_TIMER_PERIOD 1
#endif
#if JUCE_WIN32_TIMER_PERIOD > 0
const MMRESULT res = timeBeginPeriod (JUCE_WIN32_TIMER_PERIOD);
(void) res;
jassert (res == TIMERR_NOERROR);
#endif
LARGE_INTEGER f;
QueryPerformanceFrequency (&f);
@@ -297,7 +313,7 @@ double Time::getMillisecondCounterHiRes() noexcept { return hiResCounterHa
//==============================================================================
static int64 juce_getClockCycleCounter() noexcept
{
#if JUCE_USE_INTRINSICS
#if JUCE_USE_MSVC_INTRINSICS
// MS intrinsics version...
return (int64) __rdtsc();
@@ -428,8 +444,16 @@ String SystemStats::getDisplayLanguage()
DynamicLibrary dll ("kernel32.dll");
JUCE_LOAD_WINAPI_FUNCTION (dll, GetUserDefaultUILanguage, getUserDefaultUILanguage, LANGID, (void))
if (getUserDefaultUILanguage != nullptr)
return getLocaleValue (MAKELCID (getUserDefaultUILanguage(), SORT_DEFAULT), LOCALE_SISO639LANGNAME, "en");
if (getUserDefaultUILanguage == nullptr)
return "en";
return "en";
const DWORD langID = MAKELCID (getUserDefaultUILanguage(), SORT_DEFAULT);
String mainLang (getLocaleValue (langID, LOCALE_SISO639LANGNAME, "en"));
String region (getLocaleValue (langID, LOCALE_SISO3166CTRYNAME, nullptr));
if (region.isNotEmpty())
mainLang << '-' << region;
return mainLang;
}
@@ -36,7 +36,7 @@ void* getUser32Function (const char* functionName)
}
//==============================================================================
#if ! JUCE_USE_INTRINSICS
#if ! JUCE_USE_MSVC_INTRINSICS
// In newer compilers, the inline versions of these are used (in juce_Atomic.h), but in
// older ones we have to actually call the ops as win32 functions..
long juce_InterlockedExchange (volatile long* a, long b) noexcept { return InterlockedExchange (a, b); }
@@ -263,6 +263,12 @@ namespace SocketHelpers
return true;
}
static void makeReusable (int handle) noexcept
{
const int reuse = 1;
setsockopt (handle, SOL_SOCKET, SO_REUSEADDR, (const char*) &reuse, sizeof (reuse));
}
}
//==============================================================================
@@ -378,7 +384,7 @@ void StreamingSocket::close()
{
// need to do this to interrupt the accept() function..
StreamingSocket temp;
temp.connect ("localhost", portNumber, 1000);
temp.connect (IPAddress::local().toString(), portNumber, 1000);
}
}
@@ -418,8 +424,9 @@ bool StreamingSocket::createListener (const int newPortNumber, const String& loc
if (handle < 0)
return false;
const int reuse = 1;
setsockopt (handle, SOL_SOCKET, SO_REUSEADDR, (const char*) &reuse, sizeof (reuse));
#if ! JUCE_WINDOWS // on windows, adding this option produces behaviour different to posix
SocketHelpers::makeReusable (handle);
#endif
if (bind (handle, (struct sockaddr*) &servTmpAddr, sizeof (struct sockaddr_in)) < 0
|| listen (handle, SOMAXCONN) < 0)
@@ -470,6 +477,7 @@ DatagramSocket::DatagramSocket (const int localPortNumber, const bool canBroadca
SocketHelpers::initSockets();
handle = (int) socket (AF_INET, SOCK_DGRAM, 0);
SocketHelpers::makeReusable (handle);
bindToPort (localPortNumber);
}
@@ -179,6 +179,11 @@ String URL::toString (const bool includeGetParameters) const
return url;
}
bool URL::isEmpty() const noexcept
{
return url.isEmpty();
}
bool URL::isWellFormed() const
{
//xxx TODO
@@ -241,8 +246,6 @@ void URL::createHeadersAndPostData (String& headers, MemoryBlock& headersAndPost
{
MemoryOutputStream data (headersAndPostData, false);
data << URLHelpers::getMangledParameters (*this);
if (filesToUpload.size() > 0)
{
// (this doesn't currently support mixing custom post-data with uploads..)
@@ -285,7 +288,8 @@ void URL::createHeadersAndPostData (String& headers, MemoryBlock& headersAndPost
}
else
{
data << postData;
data << URLHelpers::getMangledParameters (*this)
<< postData;
// if the user-supplied headers didn't contain a content-type, add one now..
if (! headers.containsIgnoreCase ("Content-Type"))
@@ -76,6 +76,9 @@ public:
*/
String toString (bool includeGetParameters) const;
/** Returns true if the URL is an empty string. */
bool isEmpty() const noexcept;
/** True if it seems to be valid. */
bool isWellFormed() const;
@@ -209,10 +209,10 @@ String InputStream::readNextLine()
return String::fromUTF8 (data, (int) i);
}
int InputStream::readIntoMemoryBlock (MemoryBlock& block, ssize_t numBytes)
size_t InputStream::readIntoMemoryBlock (MemoryBlock& block, ssize_t numBytes)
{
MemoryOutputStream mo (block, true);
return mo.writeFromInputStream (*this, numBytes);
return (size_t) mo.writeFromInputStream (*this, numBytes);
}
String InputStream::readEntireStreamAsString()
@@ -211,7 +211,7 @@ public:
/** Tries to read the whole stream and turn it into a string.
This will read from the stream's current position until the end-of-stream.
It can read from either UTF-16 or UTF-8 formats.
It can read from UTF-8 data, or UTF-16 if it detects suitable header-bytes.
*/
virtual String readEntireStreamAsString();
@@ -223,8 +223,8 @@ public:
will be read until the stream is exhausted.
@returns the number of bytes that were added to the memory block
*/
virtual int readIntoMemoryBlock (MemoryBlock& destBlock,
ssize_t maxNumBytesToRead = -1);
virtual size_t readIntoMemoryBlock (MemoryBlock& destBlock,
ssize_t maxNumBytesToRead = -1);
//==============================================================================
/** Returns the offset of the next byte that will be read from the stream.
@@ -60,7 +60,7 @@ MemoryInputStream::~MemoryInputStream()
int64 MemoryInputStream::getTotalLength()
{
return dataSize;
return (int64) dataSize;
}
int MemoryInputStream::read (void* const buffer, const int howMany)
@@ -89,7 +89,7 @@ bool MemoryInputStream::setPosition (const int64 pos)
int64 MemoryInputStream::getPosition()
{
return position;
return (int64) position;
}
@@ -175,14 +175,14 @@ bool MemoryOutputStream::setPosition (int64 newPosition)
return false;
}
int MemoryOutputStream::writeFromInputStream (InputStream& source, int64 maxNumBytesToWrite)
int64 MemoryOutputStream::writeFromInputStream (InputStream& source, int64 maxNumBytesToWrite)
{
// before writing from an input, see if we can preallocate to make it more efficient..
int64 availableData = source.getTotalLength() - source.getPosition();
if (availableData > 0)
{
if (maxNumBytesToWrite > availableData)
if (maxNumBytesToWrite > availableData || maxNumBytesToWrite < 0)
maxNumBytesToWrite = availableData;
if (blockToUse != nullptr)
@@ -114,9 +114,9 @@ public:
void flush();
bool write (const void*, size_t) override;
int64 getPosition() override { return position; }
int64 getPosition() override { return (int64) position; }
bool setPosition (int64) override;
int writeFromInputStream (InputStream&, int64 maxNumBytesToWrite) override;
int64 writeFromInputStream (InputStream&, int64 maxNumBytesToWrite) override;
bool writeRepeatedByte (uint8 byte, size_t numTimesToRepeat) override;
private:
@@ -252,12 +252,12 @@ bool OutputStream::writeText (const String& text, const bool asUTF16,
return true;
}
int OutputStream::writeFromInputStream (InputStream& source, int64 numBytesToWrite)
int64 OutputStream::writeFromInputStream (InputStream& source, int64 numBytesToWrite)
{
if (numBytesToWrite < 0)
numBytesToWrite = std::numeric_limits<int64>::max();
int numWritten = 0;
int64 numWritten = 0;
while (numBytesToWrite > 0)
{
@@ -221,7 +221,7 @@ public:
is exhausted)
@returns the number of bytes written
*/
virtual int writeFromInputStream (InputStream& source, int64 maxNumBytesToWrite);
virtual int64 writeFromInputStream (InputStream& source, int64 maxNumBytesToWrite);
//==============================================================================
/** Sets the string that will be written to the stream when the writeNewLine()
@@ -68,7 +68,7 @@
@see jassert()
*/
#define juce_breakDebugger { ::kill (0, SIGTRAP); }
#elif JUCE_USE_INTRINSICS
#elif JUCE_USE_MSVC_INTRINSICS
#ifndef __INTEL_COMPILER
#pragma intrinsic (__debugbreak)
#endif
@@ -94,20 +94,34 @@
#define JUCE_ANALYZER_NORETURN
#endif
//==============================================================================
#if JUCE_MSVC && ! DOXYGEN
#define MACRO_WITH_FORCED_SEMICOLON(x) \
__pragma(warning(push)) \
__pragma(warning(disable:4127)) \
do { x } while (false) \
__pragma(warning(pop))
#else
/** This is the good old C++ trick for creating a macro that forces the user to put
a semicolon after it when they use it.
*/
#define MACRO_WITH_FORCED_SEMICOLON(x) do { x } while (false)
#endif
//==============================================================================
#if JUCE_DEBUG || DOXYGEN
/** Writes a string to the standard error stream.
This is only compiled in a debug build.
@see Logger::outputDebugString
*/
#define DBG(dbgtext) { juce::String tempDbgBuf; tempDbgBuf << dbgtext; juce::Logger::outputDebugString (tempDbgBuf); }
#define DBG(dbgtext) MACRO_WITH_FORCED_SEMICOLON (juce::String tempDbgBuf; tempDbgBuf << dbgtext; juce::Logger::outputDebugString (tempDbgBuf);)
//==============================================================================
/** This will always cause an assertion failure.
It is only compiled in a debug build, (unless JUCE_LOG_ASSERTIONS is enabled for your build).
@see jassert
*/
#define jassertfalse { juce_LogCurrentAssertion; if (juce::juce_isRunningUnderDebugger()) juce_breakDebugger; JUCE_ANALYZER_NORETURN }
#define jassertfalse MACRO_WITH_FORCED_SEMICOLON (juce_LogCurrentAssertion; if (juce::juce_isRunningUnderDebugger()) juce_breakDebugger; JUCE_ANALYZER_NORETURN)
//==============================================================================
/** Platform-independent assertion macro.
@@ -117,19 +131,19 @@
correct behaviour of your program!
@see jassertfalse
*/
#define jassert(expression) { if (! (expression)) jassertfalse; }
#define jassert(expression) MACRO_WITH_FORCED_SEMICOLON (if (! (expression)) jassertfalse;)
#else
//==============================================================================
// If debugging is disabled, these dummy debug and assertion macros are used..
#define DBG(dbgtext)
#define jassertfalse { juce_LogCurrentAssertion }
#define jassertfalse MACRO_WITH_FORCED_SEMICOLON (juce_LogCurrentAssertion)
#if JUCE_LOG_ASSERTIONS
#define jassert(expression) { if (! (expression)) jassertfalse; }
#define jassert(expression) MACRO_WITH_FORCED_SEMICOLON (if (! (expression)) jassertfalse;)
#else
#define jassert(a) {}
#define jassert(a) MACRO_WITH_FORCED_SEMICOLON ( ; )
#endif
#endif
@@ -139,7 +153,7 @@
namespace juce
{
template <bool b> struct JuceStaticAssert;
template <> struct JuceStaticAssert <true> { static void dummy() {} };
template <> struct JuceStaticAssert<true> { static void dummy() {} };
}
#endif
@@ -211,6 +225,26 @@ namespace juce
#define JUCE_STRINGIFY(item) JUCE_STRINGIFY_MACRO_HELPER (item)
//==============================================================================
#if JUCE_MSVC && ! defined (DOXYGEN)
#define JUCE_WARNING_HELPER(file, line, mess) message(file "(" JUCE_STRINGIFY (line) ") : Warning: " #mess)
#define JUCE_COMPILER_WARNING(message) __pragma(JUCE_WARNING_HELPER (__FILE__, __LINE__, message));
#else
#ifndef DOXYGEN
#define JUCE_WARNING_HELPER(mess) message(#mess)
#endif
/** This macro allows you to emit a custom compiler warning message.
Very handy for marking bits of code as "to-do" items, or for shaming
code written by your co-workers in a way that's hard to ignore.
GCC and Clang provide the \#warning directive, but MSVC doesn't, so this macro
is a cross-compiler way to get the same functionality as \#warning.
*/
#define JUCE_COMPILER_WARNING(message) _Pragma(JUCE_STRINGIFY (JUCE_WARNING_HELPER (message)));
#endif
//==============================================================================
#if JUCE_CATCH_UNHANDLED_EXCEPTIONS
@@ -302,84 +336,4 @@ namespace juce
#define JUCE_PACKED
#endif
//==============================================================================
// Here, we'll check for C++11 compiler support, and if it's not available, define
// a few workarounds, so that we can still use some of the newer language features.
#if (__cplusplus >= 201103L || defined (__GXX_EXPERIMENTAL_CXX0X__)) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
#define JUCE_COMPILER_SUPPORTS_NOEXCEPT 1
#define JUCE_COMPILER_SUPPORTS_NULLPTR 1
#define JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS 1
#if (__GNUC__ * 100 + __GNUC_MINOR__) >= 407 && ! defined (JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL)
#define JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL 1
#endif
#if (__GNUC__ * 100 + __GNUC_MINOR__) >= 407 && ! defined (JUCE_DELETED_FUNCTION)
#define JUCE_DELETED_FUNCTION = delete
#endif
#endif
#if JUCE_CLANG && defined (__has_feature)
#if __has_feature (cxx_nullptr)
#define JUCE_COMPILER_SUPPORTS_NULLPTR 1
#endif
#if __has_feature (cxx_noexcept)
#define JUCE_COMPILER_SUPPORTS_NOEXCEPT 1
#endif
#if __has_feature (cxx_rvalue_references)
#define JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS 1
#endif
#if __has_feature (cxx_deleted_functions)
#define JUCE_DELETED_FUNCTION = delete
#endif
#ifndef JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL
#define JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL 1
#endif
#ifndef JUCE_COMPILER_SUPPORTS_ARC
#define JUCE_COMPILER_SUPPORTS_ARC 1
#endif
#endif
#if defined (_MSC_VER) && _MSC_VER >= 1600
#define JUCE_COMPILER_SUPPORTS_NULLPTR 1
#define JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS 1
#endif
#if defined (_MSC_VER) && _MSC_VER >= 1700
#define JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL 1
#endif
#ifndef JUCE_DELETED_FUNCTION
#define JUCE_DELETED_FUNCTION
#endif
//==============================================================================
// Declare some fake versions of nullptr and noexcept, for older compilers:
#if ! (DOXYGEN || JUCE_COMPILER_SUPPORTS_NOEXCEPT)
#ifdef noexcept
#undef noexcept
#endif
#define noexcept throw()
#if defined (_MSC_VER) && _MSC_VER > 1600
#define _ALLOW_KEYWORD_MACROS 1 // (to stop VC2012 complaining)
#endif
#endif
#if ! (DOXYGEN || JUCE_COMPILER_SUPPORTS_NULLPTR)
#ifdef nullptr
#undef nullptr
#endif
#define nullptr (0)
#endif
#if ! (DOXYGEN || JUCE_COMPILER_SUPPORTS_OVERRIDE_AND_FINAL)
#undef override
#define override
#endif
#endif // JUCE_PLATFORMDEFS_H_INCLUDED
@@ -36,7 +36,7 @@
*/
#define JUCE_MAJOR_VERSION 3
#define JUCE_MINOR_VERSION 0
#define JUCE_BUILDNUMBER 5
#define JUCE_BUILDNUMBER 8
/** Current Juce version number.
@@ -51,6 +51,7 @@
//==============================================================================
#include "juce_PlatformDefs.h"
#include "juce_CompilerSupport.h"
//==============================================================================
// Now we'll include some common OS headers..
@@ -72,8 +73,9 @@
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
#if JUCE_USE_INTRINSICS
#if JUCE_USE_MSVC_INTRINSICS
#include <intrin.h>
#endif
@@ -64,7 +64,8 @@ public:
WinXP = 0x4106,
WinVista = 0x4107,
Windows7 = 0x4108,
Windows8 = 0x4109,
Windows8_0 = 0x4109,
Windows8_1 = 0x410a,
Windows = 0x4000, /**< To test whether any version of Windows is running,
you can use the expression ((getOperatingSystemType() & Windows) != 0). */
@@ -118,7 +119,9 @@ public:
static String getUserRegion();
/** Returns the user's display language.
The return value is a 2 or 3 letter language code (ISO 639-1 or ISO 639-2)
The return value is a 2 or 3 letter language code (ISO 639-1 or ISO 639-2).
Note that depending on the OS and region, this may also be followed by a dash
and a sub-region code, e.g "en-GB"
*/
static String getDisplayLanguage();
@@ -155,13 +155,13 @@
#define JUCE_BIG_ENDIAN 1
#endif
#if defined (__LP64__) || defined (_LP64)
#if defined (__LP64__) || defined (_LP64) || defined (__arm64__)
#define JUCE_64BIT 1
#else
#define JUCE_32BIT 1
#endif
#ifdef __arm__
#if defined (__arm__) || defined (__arm64__)
#define JUCE_ARM 1
#elif __MMX__ || __SSE__ || __amd64__
#define JUCE_INTEL 1
@@ -192,7 +192,7 @@
#endif
#if JUCE_64BIT || ! JUCE_VC7_OR_EARLIER
#define JUCE_USE_INTRINSICS 1
#define JUCE_USE_MSVC_INTRINSICS 1
#endif
#else
#error unknown compiler
@@ -26,21 +26,10 @@
==============================================================================
*/
StringPool& Identifier::getPool()
{
static StringPool pool;
return pool;
}
Identifier::Identifier() noexcept {}
Identifier::~Identifier() noexcept {}
Identifier::Identifier() noexcept
: name (nullptr)
{
}
Identifier::Identifier (const Identifier& other) noexcept
: name (other.name)
{
}
Identifier::Identifier (const Identifier& other) noexcept : name (other.name) {}
Identifier& Identifier::operator= (const Identifier other) noexcept
{
@@ -49,20 +38,27 @@ Identifier& Identifier::operator= (const Identifier other) noexcept
}
Identifier::Identifier (const String& nm)
: name (Identifier::getPool().getPooledString (nm))
{
}
Identifier::Identifier (const char* const nm)
: name (Identifier::getPool().getPooledString (nm))
: name (StringPool::getGlobalPool().getPooledString (nm))
{
/* An Identifier string must be suitable for use as a script variable or XML
attribute, so it can only contain this limited set of characters.. */
jassert (isValidIdentifier (toString()));
}
Identifier::~Identifier()
Identifier::Identifier (const char* nm)
: name (StringPool::getGlobalPool().getPooledString (nm))
{
/* An Identifier string must be suitable for use as a script variable or XML
attribute, so it can only contain this limited set of characters.. */
jassert (isValidIdentifier (toString()));
}
Identifier::Identifier (String::CharPointerType start, String::CharPointerType end)
: name (StringPool::getGlobalPool().getPooledString (start, end))
{
/* An Identifier string must be suitable for use as a script variable or XML
attribute, so it can only contain this limited set of characters.. */
jassert (isValidIdentifier (toString()));
}
Identifier Identifier::null;
@@ -34,9 +34,9 @@
/**
Represents a string identifier, designed for accessing properties by name.
Identifier objects are very light and fast to copy, but slower to initialise
from a string, so it's much faster to keep a static identifier object to refer
to frequently-used names, rather than constructing them each time you need it.
Comparing two Identifier objects is very fast (an O(1) operation), but creating
them can be slower than just using a String directly, so the optimal way to use them
is to keep some static Identifier objects for the things you use often.
@see NamedValueSet, ValueTree
*/
@@ -58,6 +58,12 @@ public:
*/
Identifier (const String& name);
/** Creates an identifier with a specified name.
Because this name may need to be used in contexts such as script variables or XML
tags, it must only contain ascii letters and digits, or the underscore character.
*/
Identifier (String::CharPointerType nameStart, String::CharPointerType nameEnd);
/** Creates a copy of another identifier. */
Identifier (const Identifier& other) noexcept;
@@ -65,37 +71,37 @@ public:
Identifier& operator= (const Identifier other) noexcept;
/** Destructor */
~Identifier();
~Identifier() noexcept;
/** Compares two identifiers. This is a very fast operation. */
inline bool operator== (Identifier other) const noexcept { return name == other.name; }
inline bool operator== (Identifier other) const noexcept { return name.getCharPointer() == other.name.getCharPointer(); }
/** Compares two identifiers. This is a very fast operation. */
inline bool operator!= (Identifier other) const noexcept { return name != other.name; }
inline bool operator!= (Identifier other) const noexcept { return name.getCharPointer() != other.name.getCharPointer(); }
/** Compares the identifier with a string. */
inline bool operator== (StringRef other) const noexcept { return name.compare (other.text) == 0; }
inline bool operator== (StringRef other) const noexcept { return name == other; }
/** Compares the identifier with a string. */
inline bool operator!= (StringRef other) const noexcept { return name.compare (other.text) != 0; }
inline bool operator!= (StringRef other) const noexcept { return name != other; }
/** Returns this identifier as a string. */
String toString() const { return name; }
const String& toString() const noexcept { return name; }
/** Returns this identifier's raw string pointer. */
operator String::CharPointerType() const noexcept { return name; }
operator String::CharPointerType() const noexcept { return name.getCharPointer(); }
/** Returns this identifier's raw string pointer. */
String::CharPointerType getCharPointer() const noexcept { return name; }
String::CharPointerType getCharPointer() const noexcept { return name.getCharPointer(); }
/** Returns this identifier as a StringRef. */
operator StringRef() const noexcept { return name; }
/** Returns true if this Identifier is not null */
bool isValid() const noexcept { return name.getAddress() != nullptr; }
bool isValid() const noexcept { return name.isNotEmpty(); }
/** Returns true if this Identifier is null */
bool isNull() const noexcept { return name.getAddress() == nullptr; }
bool isNull() const noexcept { return name.isEmpty(); }
/** A null identifier. */
static Identifier null;
@@ -106,12 +112,8 @@ public:
*/
static bool isValidIdentifier (const String& possibleIdentifier) noexcept;
private:
//==============================================================================
String::CharPointerType name;
static StringPool& getPool();
String name;
};
@@ -194,11 +194,11 @@ LocalisedStrings* LocalisedStrings::getCurrentMappings()
String LocalisedStrings::translateWithCurrentMappings (const String& text) { return juce::translate (text); }
String LocalisedStrings::translateWithCurrentMappings (const char* text) { return juce::translate (text); }
String translate (const String& text) { return juce::translate (text, text); }
String translate (const char* text) { return juce::translate (String (text)); }
String translate (CharPointer_UTF8 text) { return juce::translate (String (text)); }
JUCE_API String translate (const String& text) { return juce::translate (text, text); }
JUCE_API String translate (const char* text) { return juce::translate (String (text)); }
JUCE_API String translate (CharPointer_UTF8 text) { return juce::translate (String (text)); }
String translate (const String& text, const String& resultIfNotFound)
JUCE_API String translate (const String& text, const String& resultIfNotFound)
{
const SpinLock::ScopedLockType sl (currentMappingsLock);
@@ -226,22 +226,22 @@ private:
/** Uses the LocalisedStrings class to translate the given string literal.
@see LocalisedStrings
*/
String translate (const String& stringLiteral);
JUCE_API String translate (const String& stringLiteral);
/** Uses the LocalisedStrings class to translate the given string literal.
@see LocalisedStrings
*/
String translate (const char* stringLiteral);
JUCE_API String translate (const char* stringLiteral);
/** Uses the LocalisedStrings class to translate the given string literal.
@see LocalisedStrings
*/
String translate (CharPointer_UTF8 stringLiteral);
JUCE_API String translate (CharPointer_UTF8 stringLiteral);
/** Uses the LocalisedStrings class to translate the given string literal.
@see LocalisedStrings
*/
String translate (const String& stringLiteral, const String& resultIfNotFound);
JUCE_API String translate (const String& stringLiteral, const String& resultIfNotFound);
#endif // JUCE_LOCALISEDSTRINGS_H_INCLUDED
@@ -180,6 +180,11 @@ public:
release (bufferFromText (text));
}
static inline int getReferenceCount (const CharPointerType text) noexcept
{
return bufferFromText (text)->refCount.get() + 1;
}
//==============================================================================
static CharPointerType makeUniqueWithByteSize (const CharPointerType text, size_t numBytes)
{
@@ -216,8 +221,8 @@ private:
static inline StringHolder* bufferFromText (const CharPointerType text) noexcept
{
// (Can't use offsetof() here because of warnings about this not being a POD)
return reinterpret_cast <StringHolder*> (reinterpret_cast <char*> (text.getAddress())
- (reinterpret_cast <size_t> (reinterpret_cast <StringHolder*> (1)->text) - 1));
return reinterpret_cast<StringHolder*> (reinterpret_cast<char*> (text.getAddress())
- (reinterpret_cast<size_t> (reinterpret_cast<StringHolder*> (1)->text) - 1));
}
void compileTimeChecks()
@@ -285,7 +290,7 @@ String& String::operator= (String&& other) noexcept
}
#endif
inline String::PreallocationBytes::PreallocationBytes (const size_t numBytes_) : numBytes (numBytes_) {}
inline String::PreallocationBytes::PreallocationBytes (const size_t num) noexcept : numBytes (num) {}
String::String (const PreallocationBytes& preallocationSize)
: text (StringHolder::createUninitialisedBytes (preallocationSize.numBytes + sizeof (CharPointerType::CharType)))
@@ -297,6 +302,11 @@ void String::preallocateBytes (const size_t numBytesNeeded)
text = StringHolder::makeUniqueWithByteSize (text, numBytesNeeded + sizeof (CharPointerType::CharType));
}
int String::getReferenceCount() const noexcept
{
return StringHolder::getReferenceCount (text);
}
//==============================================================================
String::String (const char* const t)
: text (StringHolder::createFromCharPointer (CharPointer_ASCII (t)))
@@ -548,7 +558,7 @@ struct HashGenerator
Type result = Type();
while (! t.isEmpty())
result = multiplier * result + t.getAndAdvance();
result = ((Type) multiplier) * result + (Type) t.getAndAdvance();
return result;
}
@@ -608,19 +618,103 @@ int String::compare (const char* const other) const noexcept { return text
int String::compare (const wchar_t* const other) const noexcept { return text.compare (castToCharPointer_wchar_t (other)); }
int String::compareIgnoreCase (const String& other) const noexcept { return (text == other.text) ? 0 : text.compareIgnoreCase (other.text); }
int String::compareLexicographically (const String& other) const noexcept
static int stringCompareRight (String::CharPointerType s1, String::CharPointerType s2) noexcept
{
CharPointerType s1 (text);
for (int bias = 0;;)
{
const juce_wchar c1 = s1.getAndAdvance();
const bool isDigit1 = CharacterFunctions::isDigit (c1);
while (! (s1.isEmpty() || s1.isLetterOrDigit()))
++s1;
const juce_wchar c2 = s2.getAndAdvance();
const bool isDigit2 = CharacterFunctions::isDigit (c2);
CharPointerType s2 (other.text);
if (! (isDigit1 || isDigit2)) return bias;
if (! isDigit1) return -1;
if (! isDigit2) return 1;
while (! (s2.isEmpty() || s2.isLetterOrDigit()))
++s2;
if (c1 != c2 && bias == 0)
bias = c1 < c2 ? -1 : 1;
return s1.compareIgnoreCase (s2);
jassert (c1 != 0 && c2 != 0);
}
}
static int stringCompareLeft (String::CharPointerType s1, String::CharPointerType s2) noexcept
{
for (;;)
{
const juce_wchar c1 = s1.getAndAdvance();
const bool isDigit1 = CharacterFunctions::isDigit (c1);
const juce_wchar c2 = s2.getAndAdvance();
const bool isDigit2 = CharacterFunctions::isDigit (c2);
if (! (isDigit1 || isDigit2)) return 0;
if (! isDigit1) return -1;
if (! isDigit2) return 1;
if (c1 < c2) return -1;
if (c1 > c2) return 1;
}
}
static int naturalStringCompare (String::CharPointerType s1, String::CharPointerType s2) noexcept
{
bool firstLoop = true;
for (;;)
{
const bool hasSpace1 = s1.isWhitespace();
const bool hasSpace2 = s2.isWhitespace();
if ((! firstLoop) && (hasSpace1 ^ hasSpace2))
return hasSpace2 ? 1 : -1;
firstLoop = false;
if (hasSpace1) s1 = s1.findEndOfWhitespace();
if (hasSpace2) s2 = s2.findEndOfWhitespace();
if (s1.isDigit() && s2.isDigit())
{
const int result = (*s1 == '0' || *s2 == '0') ? stringCompareLeft (s1, s2)
: stringCompareRight (s1, s2);
if (result != 0)
return result;
}
juce_wchar c1 = s1.getAndAdvance();
juce_wchar c2 = s2.getAndAdvance();
if (c1 != c2)
{
c1 = CharacterFunctions::toUpperCase (c1);
c2 = CharacterFunctions::toUpperCase (c2);
}
if (c1 == c2)
{
if (c1 == 0)
return 0;
}
else
{
const bool isAlphaNum1 = CharacterFunctions::isLetterOrDigit (c1);
const bool isAlphaNum2 = CharacterFunctions::isLetterOrDigit (c2);
if (isAlphaNum2 && ! isAlphaNum1) return -1;
if (isAlphaNum1 && ! isAlphaNum2) return 1;
return c1 < c2 ? -1 : 1;
}
jassert (c1 != 0 && c2 != 0);
}
}
int String::compareNatural (StringRef other) const noexcept
{
return naturalStringCompare (getCharPointer(), other.text);
}
//==============================================================================
@@ -1750,13 +1844,13 @@ String String::formatted (const String pf, ... )
va_start (args, pf);
#if JUCE_WINDOWS
HeapBlock <wchar_t> temp (bufferSize);
HeapBlock<wchar_t> temp (bufferSize);
const int num = (int) _vsnwprintf (temp.getData(), bufferSize - 1, pf.toWideCharPointer(), args);
#elif JUCE_ANDROID
HeapBlock <char> temp (bufferSize);
HeapBlock<char> temp (bufferSize);
const int num = (int) vsnprintf (temp.getData(), bufferSize - 1, pf.toUTF8(), args);
#else
HeapBlock <wchar_t> temp (bufferSize);
HeapBlock<wchar_t> temp (bufferSize);
const int num = (int) vswprintf (temp.getData(), bufferSize - 1, pf.toWideCharPointer(), args);
#endif
@@ -1911,12 +2005,12 @@ struct StringEncodingConverter
{
static CharPointerType_Dest convert (const String& s)
{
String& source = const_cast <String&> (s);
String& source = const_cast<String&> (s);
typedef typename CharPointerType_Dest::CharType DestChar;
if (source.isEmpty())
return CharPointerType_Dest (reinterpret_cast <const DestChar*> (&emptyChar));
return CharPointerType_Dest (reinterpret_cast<const DestChar*> (&emptyChar));
CharPointerType_Src text (source.getCharPointer());
const size_t extraBytesNeeded = CharPointerType_Dest::getBytesRequiredFor (text) + sizeof (typename CharPointerType_Dest::CharType);
@@ -1926,7 +2020,7 @@ struct StringEncodingConverter
text = source.getCharPointer();
void* const newSpace = addBytesToPointer (text.getAddress(), (int) endOffset);
const CharPointerType_Dest extraSpace (static_cast <DestChar*> (newSpace));
const CharPointerType_Dest extraSpace (static_cast<DestChar*> (newSpace));
#if JUCE_DEBUG // (This just avoids spurious warnings from valgrind about the uninitialised bytes at the end of the buffer..)
const size_t bytesToClear = (size_t) jmin ((int) extraBytesNeeded, 4);
@@ -2179,6 +2273,12 @@ public:
expect (s.compare (String ("012345678")) == 0);
expect (s.compare (String ("012345679")) < 0);
expect (s.compare (String ("012345676")) > 0);
expect (String("a").compareNatural ("A") == 0);
expect (String("A").compareNatural ("B") < 0);
expect (String("a").compareNatural ("B") < 0);
expect (String("10").compareNatural ("2") > 0);
expect (String("Abc 10").compareNatural ("aBC 2") > 0);
expect (String("Abc 1").compareNatural ("aBC 2") < 0);
expect (s.substring (2, 3) == String::charToString (s[2]));
expect (s.substring (0, 1) == String::charToString (s[0]));
expect (s.getLastCharacter() == s [s.length() - 1]);
@@ -167,7 +167,7 @@ public:
typedef CharPointer_UTF32 CharPointerType;
#elif (JUCE_STRING_UTF_TYPE == 16)
typedef CharPointer_UTF16 CharPointerType;
#elif (JUCE_STRING_UTF_TYPE == 8)
#elif (DOXYGEN || JUCE_STRING_UTF_TYPE == 8)
typedef CharPointer_UTF8 CharPointerType;
#else
#error "You must set the value of JUCE_STRING_UTF_TYPE to be either 8, 16, or 32!"
@@ -346,15 +346,15 @@ public:
*/
int compareIgnoreCase (const String& other) const noexcept;
/** Lexicographic comparison with another string.
/** Compares two strings, taking into account textual characteristics like numbers and spaces.
The comparison used here is case-insensitive and ignores leading non-alphanumeric
characters, making it good for sorting human-readable strings.
This comparison is case-insensitive and can detect words and embedded numbers in the
strings, making it good for sorting human-readable lists of things like filenames.
@returns 0 if the two strings are identical; negative if this string comes before
the other one alphabetically, or positive if it comes after it.
*/
int compareLexicographically (const String& other) const noexcept;
int compareNatural (StringRef other) const noexcept;
/** Tests whether the string begins with another string.
If the parameter is an empty string, this will always return true.
@@ -1204,20 +1204,25 @@ public:
//==============================================================================
#if JUCE_MAC || JUCE_IOS || DOXYGEN
/** MAC ONLY - Creates a String from an OSX CFString. */
/** OSX ONLY - Creates a String from an OSX CFString. */
static String fromCFString (CFStringRef cfString);
/** MAC ONLY - Converts this string to a CFString.
/** OSX ONLY - Converts this string to a CFString.
Remember that you must use CFRelease() to free the returned string when you're
finished with it.
*/
CFStringRef toCFString() const;
/** MAC ONLY - Returns a copy of this string in which any decomposed unicode characters have
/** OSX ONLY - Returns a copy of this string in which any decomposed unicode characters have
been converted to their precomposed equivalents. */
String convertToPrecomposedUnicode() const;
#endif
/** Returns the number of String objects which are currently sharing the same internal
data as this one.
*/
int getReferenceCount() const noexcept;
private:
//==============================================================================
CharPointerType text;
@@ -1225,7 +1230,7 @@ private:
//==============================================================================
struct PreallocationBytes
{
explicit PreallocationBytes (size_t);
explicit PreallocationBytes (size_t) noexcept;
size_t numBytes;
};
@@ -199,6 +199,11 @@ int StringArray::indexOf (StringRef stringToLookFor, const bool ignoreCase, int
return -1;
}
void StringArray::move (const int currentIndex, const int newIndex) noexcept
{
strings.move (currentIndex, newIndex);
}
//==============================================================================
void StringArray::remove (const int index)
{
@@ -255,12 +260,17 @@ void StringArray::trim()
//==============================================================================
struct InternalStringArrayComparator_CaseSensitive
{
static int compareElements (String& first, String& second) { return first.compare (second); }
static int compareElements (String& s1, String& s2) noexcept { return s1.compare (s2); }
};
struct InternalStringArrayComparator_CaseInsensitive
{
static int compareElements (String& first, String& second) { return first.compareIgnoreCase (second); }
static int compareElements (String& s1, String& s2) noexcept { return s1.compareIgnoreCase (s2); }
};
struct InternalStringArrayComparator_Natural
{
static int compareElements (String& s1, String& s2) noexcept { return s1.compareNatural (s2); }
};
void StringArray::sort (const bool ignoreCase)
@@ -277,12 +287,12 @@ void StringArray::sort (const bool ignoreCase)
}
}
void StringArray::move (const int currentIndex, int newIndex) noexcept
void StringArray::sortNatural()
{
strings.move (currentIndex, newIndex);
InternalStringArrayComparator_Natural comp;
strings.sort (comp);
}
//==============================================================================
String StringArray::joinIntoString (StringRef separator, int start, int numberToJoin) const
{
@@ -134,18 +134,12 @@ public:
/** Returns a pointer to the first String in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline String* begin() const noexcept
{
return strings.begin();
}
inline String* begin() const noexcept { return strings.begin(); }
/** Returns a pointer to the String which follows the last element in the array.
This method is provided for compatibility with standard C++ iteration mechanisms.
*/
inline String* end() const noexcept
{
return strings.end();
}
inline String* end() const noexcept { return strings.end(); }
/** Searches for a string in the array.
@@ -387,11 +381,16 @@ public:
//==============================================================================
/** Sorts the array into alphabetical order.
@param ignoreCase if true, the comparisons used will be case-sensitive.
*/
void sort (bool ignoreCase);
/** Sorts the array using extra language-aware rules to do a better job of comparing
words containing spaces and numbers.
@see String::compareNatural()
*/
void sortNatural();
//==============================================================================
/** Increases the array's internal storage to hold a minimum number of elements.
@@ -26,88 +26,141 @@
==============================================================================
*/
StringPool::StringPool() noexcept {}
StringPool::~StringPool() {}
static const int minNumberOfStringsForGarbageCollection = 300;
static const uint32 garbageCollectionInterval = 30000;
namespace StringPoolHelpers
StringPool::StringPool() noexcept : lastGarbageCollectionTime (0) {}
StringPool::~StringPool() {}
struct StartEndString
{
template <class StringType>
String::CharPointerType getPooledStringFromArray (Array<String>& strings,
StringType newString,
const CriticalSection& lock)
StartEndString (String::CharPointerType s, String::CharPointerType e) noexcept : start (s), end (e) {}
operator String() const { return String (start, end); }
String::CharPointerType start, end;
};
static int compareStrings (const String& s1, const String& s2) noexcept { return s1.compare (s2); }
static int compareStrings (CharPointer_UTF8 s1, const String& s2) noexcept { return s1.compare (s2.getCharPointer()); }
static int compareStrings (const StartEndString& string1, const String& string2) noexcept
{
String::CharPointerType s1 (string1.start), s2 (string2.getCharPointer());
for (;;)
{
const ScopedLock sl (lock);
int start = 0;
int end = strings.size();
const int c1 = s1 < string1.end ? (int) s1.getAndAdvance() : 0;
const int c2 = (int) s2.getAndAdvance();
const int diff = c1 - c2;
for (;;)
{
if (start >= end)
{
jassert (start <= end);
strings.insert (start, newString);
return strings.getReference (start).getCharPointer();
}
const String& startString = strings.getReference (start);
if (startString == newString)
return startString.getCharPointer();
const int halfway = (start + end) >> 1;
if (halfway == start)
{
if (startString.compare (newString) < 0)
++start;
strings.insert (start, newString);
return strings.getReference (start).getCharPointer();
}
const int comp = strings.getReference (halfway).compare (newString);
if (comp == 0)
return strings.getReference (halfway).getCharPointer();
if (comp < 0)
start = halfway;
else
end = halfway;
}
if (diff != 0) return diff < 0 ? -1 : 1;
if (c1 == 0) break;
}
return 0;
}
String::CharPointerType StringPool::getPooledString (const String& s)
template <typename NewStringType>
static String addPooledString (Array<String>& strings, const NewStringType& newString)
{
if (s.isEmpty())
return String().getCharPointer();
int start = 0;
int end = strings.size();
return StringPoolHelpers::getPooledStringFromArray (strings, s, lock);
while (start < end)
{
const String& startString = strings.getReference (start);
const int startComp = compareStrings (newString, startString);
if (startComp == 0)
return startString;
const int halfway = (start + end) / 2;
if (halfway == start)
{
if (startComp > 0)
++start;
break;
}
const String& halfwayString = strings.getReference (halfway);
const int halfwayComp = compareStrings (newString, halfwayString);
if (halfwayComp == 0)
return halfwayString;
if (halfwayComp > 0)
start = halfway;
else
end = halfway;
}
strings.insert (start, newString);
return strings.getReference (start);
}
String::CharPointerType StringPool::getPooledString (const char* const s)
String StringPool::getPooledString (const char* const newString)
{
if (s == nullptr || *s == 0)
return String().getCharPointer();
if (newString == nullptr || *newString == 0)
return String();
return StringPoolHelpers::getPooledStringFromArray (strings, s, lock);
const ScopedLock sl (lock);
garbageCollectIfNeeded();
return addPooledString (strings, CharPointer_UTF8 (newString));
}
String::CharPointerType StringPool::getPooledString (const wchar_t* const s)
String StringPool::getPooledString (String::CharPointerType start, String::CharPointerType end)
{
if (s == nullptr || *s == 0)
return String().getCharPointer();
if (start.isEmpty() || start == end)
return String();
return StringPoolHelpers::getPooledStringFromArray (strings, s, lock);
const ScopedLock sl (lock);
garbageCollectIfNeeded();
return addPooledString (strings, StartEndString (start, end));
}
int StringPool::size() const noexcept
String StringPool::getPooledString (StringRef newString)
{
return strings.size();
if (newString.isEmpty())
return String();
const ScopedLock sl (lock);
garbageCollectIfNeeded();
return addPooledString (strings, newString.text);
}
String::CharPointerType StringPool::operator[] (const int index) const noexcept
String StringPool::getPooledString (const String& newString)
{
return strings [index].getCharPointer();
if (newString.isEmpty())
return String();
const ScopedLock sl (lock);
garbageCollectIfNeeded();
return addPooledString (strings, newString);
}
void StringPool::garbageCollectIfNeeded()
{
if (strings.size() > minNumberOfStringsForGarbageCollection
&& Time::getApproximateMillisecondCounter() > lastGarbageCollectionTime + garbageCollectionInterval)
garbageCollect();
}
void StringPool::garbageCollect()
{
const ScopedLock sl (lock);
for (int i = strings.size(); --i >= 0;)
if (strings.getReference(i).getReferenceCount() == 1)
strings.remove (i);
lastGarbageCollectionTime = Time::getApproximateMillisecondCounter();
}
StringPool& StringPool::getGlobalPool() noexcept
{
static StringPool pool;
return pool;
}
@@ -52,40 +52,42 @@ public:
~StringPool();
//==============================================================================
/** Returns a pointer to a copy of the string that is passed in.
The pool will always return the same pointer when asked for a string that matches it.
The pool will own all the pointers that it returns, deleting them when the pool itself
is deleted.
/** Returns a pointer to a shared copy of the string that is passed in.
The pool will always return the same String object when asked for a string that matches it.
*/
String::CharPointerType getPooledString (const String& original);
String getPooledString (const String& original);
/** Returns a pointer to a copy of the string that is passed in.
The pool will always return the same pointer when asked for a string that matches it.
The pool will own all the pointers that it returns, deleting them when the pool itself
is deleted.
The pool will always return the same String object when asked for a string that matches it.
*/
String::CharPointerType getPooledString (const char* original);
String getPooledString (const char* original);
/** Returns a pointer to a shared copy of the string that is passed in.
The pool will always return the same String object when asked for a string that matches it.
*/
String getPooledString (StringRef original);
/** Returns a pointer to a copy of the string that is passed in.
The pool will always return the same pointer when asked for a string that matches it.
The pool will own all the pointers that it returns, deleting them when the pool itself
is deleted.
The pool will always return the same String object when asked for a string that matches it.
*/
String::CharPointerType getPooledString (const wchar_t* original);
String getPooledString (String::CharPointerType start, String::CharPointerType end);
//==============================================================================
/** Returns the number of strings in the pool. */
int size() const noexcept;
/** Scans the pool, and removes any strings that are unreferenced.
You don't generally need to call this - it'll be called automatically when the pool grows
large enough to warrant it.
*/
void garbageCollect();
/** Returns one of the strings in the pool, by index. */
String::CharPointerType operator[] (int index) const noexcept;
/** Returns a shared global pool which is used for things like Identifiers, XML parsing. */
static StringPool& getGlobalPool() noexcept;
private:
Array <String> strings;
Array<String> strings;
CriticalSection lock;
uint32 lastGarbageCollectionTime;
void garbageCollectIfNeeded();
};
@@ -407,11 +407,11 @@ String Time::getWeekdayName (const bool threeLetterVersion) const
return getWeekdayName (getDayOfWeek(), threeLetterVersion);
}
static const char* const shortMonthNames[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
static const char* const longMonthNames[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
String Time::getMonthName (int monthNumber, const bool threeLetterVersion)
{
static const char* const shortMonthNames[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
static const char* const longMonthNames[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
monthNumber %= 12;
return TRANS (threeLetterVersion ? shortMonthNames [monthNumber]
@@ -430,17 +430,40 @@ String Time::getWeekdayName (int day, const bool threeLetterVersion)
}
//==============================================================================
Time& Time::operator+= (RelativeTime delta) { millisSinceEpoch += delta.inMilliseconds(); return *this; }
Time& Time::operator-= (RelativeTime delta) { millisSinceEpoch -= delta.inMilliseconds(); return *this; }
Time& Time::operator+= (RelativeTime delta) noexcept { millisSinceEpoch += delta.inMilliseconds(); return *this; }
Time& Time::operator-= (RelativeTime delta) noexcept { millisSinceEpoch -= delta.inMilliseconds(); return *this; }
Time operator+ (Time time, RelativeTime delta) { Time t (time); return t += delta; }
Time operator- (Time time, RelativeTime delta) { Time t (time); return t -= delta; }
Time operator+ (RelativeTime delta, Time time) { Time t (time); return t += delta; }
const RelativeTime operator- (Time time1, Time time2) { return RelativeTime::milliseconds (time1.toMilliseconds() - time2.toMilliseconds()); }
Time operator+ (Time time, RelativeTime delta) noexcept { Time t (time); return t += delta; }
Time operator- (Time time, RelativeTime delta) noexcept { Time t (time); return t -= delta; }
Time operator+ (RelativeTime delta, Time time) noexcept { Time t (time); return t += delta; }
const RelativeTime operator- (Time time1, Time time2) noexcept { return RelativeTime::milliseconds (time1.toMilliseconds() - time2.toMilliseconds()); }
bool operator== (Time time1, Time time2) { return time1.toMilliseconds() == time2.toMilliseconds(); }
bool operator!= (Time time1, Time time2) { return time1.toMilliseconds() != time2.toMilliseconds(); }
bool operator< (Time time1, Time time2) { return time1.toMilliseconds() < time2.toMilliseconds(); }
bool operator> (Time time1, Time time2) { return time1.toMilliseconds() > time2.toMilliseconds(); }
bool operator<= (Time time1, Time time2) { return time1.toMilliseconds() <= time2.toMilliseconds(); }
bool operator>= (Time time1, Time time2) { return time1.toMilliseconds() >= time2.toMilliseconds(); }
bool operator== (Time time1, Time time2) noexcept { return time1.toMilliseconds() == time2.toMilliseconds(); }
bool operator!= (Time time1, Time time2) noexcept { return time1.toMilliseconds() != time2.toMilliseconds(); }
bool operator< (Time time1, Time time2) noexcept { return time1.toMilliseconds() < time2.toMilliseconds(); }
bool operator> (Time time1, Time time2) noexcept { return time1.toMilliseconds() > time2.toMilliseconds(); }
bool operator<= (Time time1, Time time2) noexcept { return time1.toMilliseconds() <= time2.toMilliseconds(); }
bool operator>= (Time time1, Time time2) noexcept { return time1.toMilliseconds() >= time2.toMilliseconds(); }
static int getMonthNumberForCompileDate (const String& m) noexcept
{
for (int i = 0; i < 12; ++i)
if (m.equalsIgnoreCase (shortMonthNames[i]))
return i;
// If you hit this because your compiler has a non-standard __DATE__ format,
// let me know so we can add support for it!
jassertfalse;
return 0;
}
Time Time::getCompilationDate()
{
StringArray dateTokens;
dateTokens.addTokens (__DATE__, true);
dateTokens.removeEmptyStrings (true);
return Time (dateTokens[2].getIntValue(),
getMonthNumberForCompileDate (dateTokens[0]),
dateTokens[1].getIntValue(), 12, 0);
}
@@ -253,9 +253,9 @@ public:
//==============================================================================
/** Adds a RelativeTime to this time. */
Time& operator+= (RelativeTime delta);
Time& operator+= (RelativeTime delta) noexcept;
/** Subtracts a RelativeTime from this time. */
Time& operator-= (RelativeTime delta);
Time& operator-= (RelativeTime delta) noexcept;
//==============================================================================
/** Tries to set the computer's clock.
@@ -272,8 +272,7 @@ public:
@param threeLetterVersion if true, it'll return a 3-letter abbreviation, e.g. "Tue"; if
false, it'll return the full version, e.g. "Tuesday".
*/
static String getWeekdayName (int dayNumber,
bool threeLetterVersion);
static String getWeekdayName (int dayNumber, bool threeLetterVersion);
/** Returns the name of one of the months.
@@ -281,8 +280,7 @@ public:
@param threeLetterVersion if true, it'll be a 3-letter abbreviation, e.g. "Jan"; if false
it'll return the long form, e.g. "January"
*/
static String getMonthName (int monthNumber,
bool threeLetterVersion);
static String getMonthName (int monthNumber, bool threeLetterVersion);
//==============================================================================
// Static methods for getting system timers directly..
@@ -370,6 +368,8 @@ public:
*/
static int64 secondsToHighResolutionTicks (double seconds) noexcept;
/** Returns a Time based on the value of the __DATE__ macro when this module was compiled */
static Time getCompilationDate();
private:
//==============================================================================
@@ -378,27 +378,27 @@ private:
//==============================================================================
/** Adds a RelativeTime to a Time. */
JUCE_API Time operator+ (Time time, RelativeTime delta);
JUCE_API Time operator+ (Time time, RelativeTime delta) noexcept;
/** Adds a RelativeTime to a Time. */
JUCE_API Time operator+ (RelativeTime delta, Time time);
JUCE_API Time operator+ (RelativeTime delta, Time time) noexcept;
/** Subtracts a RelativeTime from a Time. */
JUCE_API Time operator- (Time time, RelativeTime delta);
JUCE_API Time operator- (Time time, RelativeTime delta) noexcept;
/** Returns the relative time difference between two times. */
JUCE_API const RelativeTime operator- (Time time1, Time time2);
JUCE_API const RelativeTime operator- (Time time1, Time time2) noexcept;
/** Compares two Time objects. */
JUCE_API bool operator== (Time time1, Time time2);
JUCE_API bool operator== (Time time1, Time time2) noexcept;
/** Compares two Time objects. */
JUCE_API bool operator!= (Time time1, Time time2);
JUCE_API bool operator!= (Time time1, Time time2) noexcept;
/** Compares two Time objects. */
JUCE_API bool operator< (Time time1, Time time2);
JUCE_API bool operator< (Time time1, Time time2) noexcept;
/** Compares two Time objects. */
JUCE_API bool operator<= (Time time1, Time time2);
JUCE_API bool operator<= (Time time1, Time time2) noexcept;
/** Compares two Time objects. */
JUCE_API bool operator> (Time time1, Time time2);
JUCE_API bool operator> (Time time1, Time time2) noexcept;
/** Compares two Time objects. */
JUCE_API bool operator>= (Time time1, Time time2);
JUCE_API bool operator>= (Time time1, Time time2) noexcept;
#endif // JUCE_TIME_H_INCLUDED
@@ -408,7 +408,7 @@ XmlElement* XmlDocument::readNextElement (const bool alsoParseSubElements)
}
}
node = new XmlElement (String (input, endOfToken));
node = new XmlElement (input, endOfToken);
input = endOfToken;
LinkedListPointer<XmlElement::XmlAttributeNode>::Appender attributeAppender (node->attributes);
@@ -458,8 +458,7 @@ XmlElement* XmlDocument::readNextElement (const bool alsoParseSubElements)
if (nextChar == '"' || nextChar == '\'')
{
XmlElement::XmlAttributeNode* const newAtt
= new XmlElement::XmlAttributeNode (String (attNameStart, attNameEnd),
String::empty);
= new XmlElement::XmlAttributeNode (attNameStart, attNameEnd);
readQuotedString (newAtt->value);
attributeAppender.append (newAtt);
@@ -32,7 +32,7 @@ XmlElement::XmlAttributeNode::XmlAttributeNode (const XmlAttributeNode& other) n
{
}
XmlElement::XmlAttributeNode::XmlAttributeNode (const String& n, const String& v) noexcept
XmlElement::XmlAttributeNode::XmlAttributeNode (const Identifier& n, const String& v) noexcept
: name (n), value (v)
{
#if JUCE_DEBUG
@@ -42,22 +42,53 @@ XmlElement::XmlAttributeNode::XmlAttributeNode (const String& n, const String& v
#endif
}
bool XmlElement::XmlAttributeNode::hasName (StringRef nameToMatch) const noexcept
XmlElement::XmlAttributeNode::XmlAttributeNode (String::CharPointerType nameStart, String::CharPointerType nameEnd)
: name (nameStart, nameEnd)
{
return name.equalsIgnoreCase (nameToMatch);
}
//==============================================================================
XmlElement::XmlElement (const String& tag) noexcept
: tagName (tag)
static void sanityCheckTagName (const String& tag)
{
(void) tag;
// the tag name mustn't be empty, or it'll look like a text element!
jassert (tag.containsNonWhitespaceChars())
jassert (tag.containsNonWhitespaceChars());
// The tag can't contain spaces or other characters that would create invalid XML!
jassert (! tag.containsAnyOf (" <>/&(){}"));
}
XmlElement::XmlElement (const String& tag)
: tagName (StringPool::getGlobalPool().getPooledString (tag))
{
sanityCheckTagName (tagName);
}
XmlElement::XmlElement (const char* tag)
: tagName (StringPool::getGlobalPool().getPooledString (tag))
{
sanityCheckTagName (tagName);
}
XmlElement::XmlElement (StringRef tag)
: tagName (StringPool::getGlobalPool().getPooledString (tag))
{
sanityCheckTagName (tagName);
}
XmlElement::XmlElement (const Identifier& tag)
: tagName (tag.toString())
{
sanityCheckTagName (tagName);
}
XmlElement::XmlElement (String::CharPointerType tagNameStart, String::CharPointerType tagNameEnd)
: tagName (StringPool::getGlobalPool().getPooledString (tagNameStart, tagNameEnd))
{
sanityCheckTagName (tagName);
}
XmlElement::XmlElement (int /*dummy*/) noexcept
{
}
@@ -407,7 +438,7 @@ int XmlElement::getNumAttributes() const noexcept
const String& XmlElement::getAttributeName (const int index) const noexcept
{
if (const XmlAttributeNode* const att = attributes [index])
return att->name;
return att->name.toString();
return String::empty;
}
@@ -423,7 +454,7 @@ const String& XmlElement::getAttributeValue (const int index) const noexcept
XmlElement::XmlAttributeNode* XmlElement::getAttribute (StringRef attributeName) const noexcept
{
for (XmlAttributeNode* att = attributes; att != nullptr; att = att->nextListItem)
if (att->hasName (attributeName))
if (att->name == attributeName)
return att;
return nullptr;
@@ -495,7 +526,7 @@ bool XmlElement::compareAttribute (StringRef attributeName,
}
//==============================================================================
void XmlElement::setAttribute (const String& attributeName, const String& value)
void XmlElement::setAttribute (const Identifier& attributeName, const String& value)
{
if (attributes == nullptr)
{
@@ -505,7 +536,7 @@ void XmlElement::setAttribute (const String& attributeName, const String& value)
{
for (XmlAttributeNode* att = attributes; ; att = att->nextListItem)
{
if (att->hasName (attributeName))
if (att->name == attributeName)
{
att->value = value;
break;
@@ -520,23 +551,23 @@ void XmlElement::setAttribute (const String& attributeName, const String& value)
}
}
void XmlElement::setAttribute (const String& attributeName, const int number)
void XmlElement::setAttribute (const Identifier& attributeName, const int number)
{
setAttribute (attributeName, String (number));
}
void XmlElement::setAttribute (const String& attributeName, const double number)
void XmlElement::setAttribute (const Identifier& attributeName, const double number)
{
setAttribute (attributeName, String (number, 20));
}
void XmlElement::removeAttribute (const String& attributeName) noexcept
void XmlElement::removeAttribute (const Identifier& attributeName) noexcept
{
for (LinkedListPointer<XmlAttributeNode>* att = &attributes;
att->get() != nullptr;
att = &(att->get()->nextListItem))
{
if (att->get()->hasName (attributeName))
if (att->get()->name == attributeName)
{
delete att->removeNext();
break;
@@ -615,7 +646,7 @@ void XmlElement::prependChildElement (XmlElement* newNode) noexcept
}
}
XmlElement* XmlElement::createNewChildElement (const String& childTagName)
XmlElement* XmlElement::createNewChildElement (StringRef childTagName)
{
XmlElement* const newElement = new XmlElement (childTagName);
addChildElement (newElement);
@@ -683,7 +714,7 @@ bool XmlElement::isEquivalentTo (const XmlElement* const other,
{
if (thisAtt == nullptr || otherAtt == nullptr)
{
if (thisAtt == otherAtt) // both 0, so it's a match
if (thisAtt == otherAtt) // both nullptr, so it's a match
break;
return false;
@@ -144,20 +144,32 @@ class JUCE_API XmlElement
public:
//==============================================================================
/** Creates an XmlElement with this tag name. */
explicit XmlElement (const String& tagName) noexcept;
explicit XmlElement (const String& tagName);
/** Creates an XmlElement with this tag name. */
explicit XmlElement (const char* tagName);
/** Creates an XmlElement with this tag name. */
explicit XmlElement (const Identifier& tagName);
/** Creates an XmlElement with this tag name. */
explicit XmlElement (StringRef tagName);
/** Creates an XmlElement with this tag name. */
XmlElement (String::CharPointerType tagNameBegin, String::CharPointerType tagNameEnd);
/** Creates a (deep) copy of another element. */
XmlElement (const XmlElement& other);
XmlElement (const XmlElement&);
/** Creates a (deep) copy of another element. */
XmlElement& operator= (const XmlElement& other);
XmlElement& operator= (const XmlElement&);
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
XmlElement (XmlElement&& other) noexcept;
XmlElement& operator= (XmlElement&& other) noexcept;
XmlElement (XmlElement&&) noexcept;
XmlElement& operator= (XmlElement&&) noexcept;
#endif
/** Deleting an XmlElement will also delete all its child elements. */
/** Deleting an XmlElement will also delete all of its child elements. */
~XmlElement() noexcept;
//==============================================================================
@@ -303,13 +315,11 @@ public:
bool hasAttribute (StringRef attributeName) const noexcept;
/** Returns the value of a named attribute.
@param attributeName the name of the attribute to look up
*/
const String& getStringAttribute (StringRef attributeName) const noexcept;
/** Returns the value of a named attribute.
@param attributeName the name of the attribute to look up
@param defaultReturnValue a value to return if the element doesn't have an attribute
with this name
@@ -377,7 +387,7 @@ public:
@param newValue the value to set it to
@see removeAttribute
*/
void setAttribute (const String& attributeName, const String& newValue);
void setAttribute (const Identifier& attributeName, const String& newValue);
/** Adds a named attribute to the element, setting it to an integer value.
@@ -391,7 +401,7 @@ public:
@param attributeName the name of the attribute to set
@param newValue the value to set it to
*/
void setAttribute (const String& attributeName, int newValue);
void setAttribute (const Identifier& attributeName, int newValue);
/** Adds a named attribute to the element, setting it to a floating-point value.
@@ -405,14 +415,14 @@ public:
@param attributeName the name of the attribute to set
@param newValue the value to set it to
*/
void setAttribute (const String& attributeName, double newValue);
void setAttribute (const Identifier& attributeName, double newValue);
/** Removes a named attribute from the element.
@param attributeName the name of the attribute to remove
@see removeAllAttributes
*/
void removeAttribute (const String& attributeName) noexcept;
void removeAttribute (const Identifier& attributeName) noexcept;
/** Removes all attributes from this element. */
void removeAllAttributes() noexcept;
@@ -555,7 +565,7 @@ public:
XmlElement* newElement = myParentElement->createNewChildElement ("foobar");
@endcode
*/
XmlElement* createNewChildElement (const String& tagName);
XmlElement* createNewChildElement (StringRef tagName);
/** Replaces one of this element's children with another node.
@@ -589,10 +599,17 @@ public:
/** Returns true if the given element is a child of this one. */
bool containsChildElement (const XmlElement* possibleChild) const noexcept;
/** Recursively searches all sub-elements to find one that contains the specified
child element.
/** Recursively searches all sub-elements of this one, looking for an element
which is the direct parent of the specified element.
Because elements don't store a pointer to their parent, if you have one
and need to find its parent, the only way to do so is to exhaustively
search the whole tree for it.
If the given child is found somewhere in this element's hierarchy, then
this method will return its parent. If not, it will return nullptr.
*/
XmlElement* findParentElementOf (const XmlElement* elementToLookFor) noexcept;
XmlElement* findParentElementOf (const XmlElement* childToSearchFor) noexcept;
//==============================================================================
/** Sorts the child elements using a comparator.
@@ -712,25 +729,26 @@ private:
struct XmlAttributeNode
{
XmlAttributeNode (const XmlAttributeNode&) noexcept;
XmlAttributeNode (const String& name, const String& value) noexcept;
XmlAttributeNode (const Identifier&, const String&) noexcept;
XmlAttributeNode (String::CharPointerType, String::CharPointerType);
LinkedListPointer<XmlAttributeNode> nextListItem;
String name, value;
bool hasName (StringRef) const noexcept;
Identifier name;
String value;
private:
XmlAttributeNode& operator= (const XmlAttributeNode&);
XmlAttributeNode& operator= (const XmlAttributeNode&) JUCE_DELETED_FUNCTION;
};
friend class XmlDocument;
friend class LinkedListPointer <XmlAttributeNode>;
friend class LinkedListPointer <XmlElement>;
friend class LinkedListPointer <XmlElement>::Appender;
friend class LinkedListPointer<XmlAttributeNode>;
friend class LinkedListPointer<XmlElement>;
friend class LinkedListPointer<XmlElement>::Appender;
friend class NamedValueSet;
LinkedListPointer <XmlElement> nextListItem;
LinkedListPointer <XmlElement> firstChildElement;
LinkedListPointer <XmlAttributeNode> attributes;
LinkedListPointer<XmlElement> nextListItem;
LinkedListPointer<XmlElement> firstChildElement;
LinkedListPointer<XmlAttributeNode> attributes;
String tagName;
XmlElement (int) noexcept;
@@ -740,6 +758,11 @@ private:
void reorderChildElements (XmlElement**, int) noexcept;
XmlAttributeNode* getAttribute (StringRef) const noexcept;
// Sigh.. L"" or _T("") string literals are problematic in general, and really inappropriate
// for XML tags. Use a UTF-8 encoded literal instead, or if you're really determined to use
// UTF-16, cast it to a String and use the other constructor.
XmlElement (const wchar_t*) JUCE_DELETED_FUNCTION;
JUCE_LEAK_DETECTOR (XmlElement)
};
@@ -135,7 +135,7 @@ public:
char buffer [30];
if (inputStream != nullptr
&& inputStream->setPosition (zei.streamOffset)
&& inputStream->setPosition ((int64) zei.streamOffset)
&& inputStream->read (buffer, 30) == 30
&& ByteOrder::littleEndianInt (buffer) == 0x04034b50)
{
@@ -154,7 +154,7 @@ public:
int64 getTotalLength()
{
return zipEntryHolder.compressedSize;
return (int64) zipEntryHolder.compressedSize;
}
int read (void* buffer, int howMany)
@@ -162,7 +162,7 @@ public:
if (headerSize <= 0)
return 0;
howMany = (int) jmin ((int64) howMany, (int64) (zipEntryHolder.compressedSize - pos));
howMany = (int) jmin ((int64) howMany, ((int64) zipEntryHolder.compressedSize) - pos);
if (inputStream == nullptr)
return 0;
@@ -172,12 +172,12 @@ public:
if (inputStream == file.inputStream)
{
const ScopedLock sl (file.lock);
inputStream->setPosition (pos + zipEntryHolder.streamOffset + headerSize);
inputStream->setPosition (pos + (int64) zipEntryHolder.streamOffset + headerSize);
num = inputStream->read (buffer, howMany);
}
else
{
inputStream->setPosition (pos + zipEntryHolder.streamOffset + headerSize);
inputStream->setPosition (pos + (int64) zipEntryHolder.streamOffset + headerSize);
num = inputStream->read (buffer, howMany);
}
@@ -298,8 +298,7 @@ InputStream* ZipFile::createStreamForEntry (const int index)
if (zei->compressed)
{
stream = new GZIPDecompressorInputStream (stream, true, true,
zei->entry.uncompressedSize);
stream = new GZIPDecompressorInputStream (stream, true, true, (int64) zei->entry.uncompressedSize);
// (much faster to unzip in big blocks using a buffer..)
stream = new BufferedInputStream (stream, 32768, true);
@@ -348,7 +347,7 @@ void ZipFile::init()
in->setPosition (pos);
MemoryBlock headerData;
if (in->readIntoMemoryBlock (headerData, size) == size)
if (in->readIntoMemoryBlock (headerData, size) == (size_t) size)
{
pos = 0;