- added JUCE library code
git-svn-id: http://moon:8086/svn/software/trunk/projects/FsTrack@357 b431acfa-c32f-4a4a-93f1-934dc6c82436
This commit is contained in:
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
IMPORTANT! This file is auto-generated each time you save your
|
||||||
|
project - if you alter its contents, your changes may be overwritten!
|
||||||
|
|
||||||
|
There's a section below where you can add your own custom code safely, and the
|
||||||
|
Introjucer will preserve the contents of that block, but the best way to change
|
||||||
|
any of these definitions is by using the Introjucer's project settings.
|
||||||
|
|
||||||
|
Any commented-out settings will assume their default values.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __JUCE_APPCONFIG_AK6XQK__
|
||||||
|
#define __JUCE_APPCONFIG_AK6XQK__
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// [BEGIN_USER_CODE_SECTION]
|
||||||
|
|
||||||
|
// (You can add your own code in this section, and the Introjucer will not overwrite it)
|
||||||
|
|
||||||
|
// [END_USER_CODE_SECTION]
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#define JUCE_MODULE_AVAILABLE_juce_core 1
|
||||||
|
#define JUCE_MODULE_AVAILABLE_juce_data_structures 1
|
||||||
|
#define JUCE_MODULE_AVAILABLE_juce_events 1
|
||||||
|
#define JUCE_MODULE_AVAILABLE_juce_graphics 1
|
||||||
|
#define JUCE_MODULE_AVAILABLE_juce_gui_basics 1
|
||||||
|
#define JUCE_MODULE_AVAILABLE_juce_gui_extra 1
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// juce_core flags:
|
||||||
|
|
||||||
|
#ifndef JUCE_FORCE_DEBUG
|
||||||
|
//#define JUCE_FORCE_DEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JUCE_LOG_ASSERTIONS
|
||||||
|
//#define JUCE_LOG_ASSERTIONS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JUCE_CHECK_MEMORY_LEAKS
|
||||||
|
//#define JUCE_CHECK_MEMORY_LEAKS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||||
|
//#define JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JUCE_INCLUDE_ZLIB_CODE
|
||||||
|
//#define JUCE_INCLUDE_ZLIB_CODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// juce_graphics flags:
|
||||||
|
|
||||||
|
#ifndef JUCE_USE_COREIMAGE_LOADER
|
||||||
|
//#define JUCE_USE_COREIMAGE_LOADER
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JUCE_USE_DIRECTWRITE
|
||||||
|
//#define JUCE_USE_DIRECTWRITE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// juce_gui_basics flags:
|
||||||
|
|
||||||
|
#ifndef JUCE_ENABLE_REPAINT_DEBUGGING
|
||||||
|
//#define JUCE_ENABLE_REPAINT_DEBUGGING
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JUCE_USE_XSHM
|
||||||
|
//#define JUCE_USE_XSHM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JUCE_USE_XRENDER
|
||||||
|
//#define JUCE_USE_XRENDER
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JUCE_USE_XCURSOR
|
||||||
|
//#define JUCE_USE_XCURSOR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// juce_gui_extra flags:
|
||||||
|
|
||||||
|
#ifndef JUCE_WEB_BROWSER
|
||||||
|
//#define JUCE_WEB_BROWSER
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JUCE_ENABLE_LIVE_CONSTANT_EDITOR
|
||||||
|
//#define JUCE_ENABLE_LIVE_CONSTANT_EDITOR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // __JUCE_APPCONFIG_AK6XQK__
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
IMPORTANT! This file is auto-generated each time you save your
|
||||||
|
project - if you alter its contents, your changes may be overwritten!
|
||||||
|
|
||||||
|
This is the header file that your files should include in order to get all the
|
||||||
|
JUCE library headers. You should avoid including the JUCE headers directly in
|
||||||
|
your own source files, because that wouldn't pick up the correct configuration
|
||||||
|
options for your app.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __APPHEADERFILE_AK6XQK__
|
||||||
|
#define __APPHEADERFILE_AK6XQK__
|
||||||
|
|
||||||
|
#include "AppConfig.h"
|
||||||
|
#include "modules/juce_core/juce_core.h"
|
||||||
|
#include "modules/juce_data_structures/juce_data_structures.h"
|
||||||
|
#include "modules/juce_events/juce_events.h"
|
||||||
|
#include "modules/juce_graphics/juce_graphics.h"
|
||||||
|
#include "modules/juce_gui_basics/juce_gui_basics.h"
|
||||||
|
#include "modules/juce_gui_extra/juce_gui_extra.h"
|
||||||
|
|
||||||
|
#if ! DONT_SET_USING_JUCE_NAMESPACE
|
||||||
|
// If your code uses a lot of JUCE classes, then this will obviously save you
|
||||||
|
// a lot of typing, but can be disabled by setting DONT_SET_USING_JUCE_NAMESPACE.
|
||||||
|
using namespace juce;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ProjectInfo
|
||||||
|
{
|
||||||
|
const char* const projectName = "FsTrack";
|
||||||
|
const char* const versionString = "1.0.0";
|
||||||
|
const int versionNumber = 0x10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __APPHEADERFILE_AK6XQK__
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
Important Note!!
|
||||||
|
================
|
||||||
|
|
||||||
|
The purpose of this folder is to contain files that are auto-generated by the Introjucer,
|
||||||
|
and ALL files in this folder will be mercilessly DELETED and completely re-written whenever
|
||||||
|
the Introjucer saves your project.
|
||||||
|
|
||||||
|
Therefore, it's a bad idea to make any manual changes to the files in here, or to
|
||||||
|
put any of your own files in here if you don't want to lose them. (Of course you may choose
|
||||||
|
to add the folder's contents to your version-control system so that you can re-merge your own
|
||||||
|
modifications after the Introjucer has saved its changes).
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
static char temp[16];
|
||||||
|
|
||||||
|
#define PRINT_WORD(buf, w)\
|
||||||
|
sprintf(temp, "%08X", w); \
|
||||||
|
strcat(buf, temp);
|
||||||
|
|
||||||
|
#define PRINT_BYTE(buf, b)\
|
||||||
|
sprintf(temp, "%02X", b); \
|
||||||
|
strcat(buf, temp)
|
||||||
|
|
||||||
|
#define PRINT_STRING(buf, s)\
|
||||||
|
sprintf(temp, "%s", s); \
|
||||||
|
strcat(buf, temp)
|
||||||
|
|
||||||
|
#define PRINT_CHAR(buf, c)\
|
||||||
|
sprintf(temp, "%c", c); \
|
||||||
|
strcat(buf, temp)
|
||||||
|
|
||||||
|
void memdump(uint8_t *pBuf, uint32_t base, int num_bytes_per_row, int len)
|
||||||
|
{
|
||||||
|
char buffer[1024] = {0};
|
||||||
|
int i, j, cnt_hex, cnt_asc;
|
||||||
|
uint8_t c;
|
||||||
|
|
||||||
|
i = j = 0;
|
||||||
|
cnt_hex = len;
|
||||||
|
cnt_asc = len;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
buffer[0] = 0;
|
||||||
|
PRINT_WORD(buffer, base + i);
|
||||||
|
PRINT_STRING(buffer, ": ");
|
||||||
|
for (j=0; j < num_bytes_per_row; j++)
|
||||||
|
{
|
||||||
|
if (cnt_hex)
|
||||||
|
{
|
||||||
|
PRINT_BYTE(buffer, pBuf[i+j]);
|
||||||
|
PRINT_STRING(buffer, " ");
|
||||||
|
cnt_hex--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PRINT_STRING(buffer, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINT_STRING(buffer, " ");
|
||||||
|
for (j=0; j < num_bytes_per_row; j++)
|
||||||
|
{
|
||||||
|
if (cnt_asc)
|
||||||
|
{
|
||||||
|
c = pBuf[i+j];
|
||||||
|
if((c < 0x20) || (c > 0x7F))
|
||||||
|
c = '.';
|
||||||
|
|
||||||
|
PRINT_CHAR(buffer, c);
|
||||||
|
cnt_asc--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PRINT_STRING(buffer, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("%s\n", buffer);
|
||||||
|
i += num_bytes_per_row;
|
||||||
|
|
||||||
|
} while (cnt_hex);
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* File: memdump.h
|
||||||
|
* Author: jens
|
||||||
|
*
|
||||||
|
* Created on 1. Februar 2015, 09:09
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MEMDUMP_H
|
||||||
|
#define MEMDUMP_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void memdump(uint8_t *pBuf, uint32_t base, int num_bytes_per_row, int len);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* MEMDUMP_H */
|
||||||
|
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
AbstractFifo::AbstractFifo (const int capacity) noexcept
|
||||||
|
: bufferSize (capacity)
|
||||||
|
{
|
||||||
|
jassert (bufferSize > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractFifo::~AbstractFifo() {}
|
||||||
|
|
||||||
|
int AbstractFifo::getTotalSize() const noexcept { return bufferSize; }
|
||||||
|
int AbstractFifo::getFreeSpace() const noexcept { return bufferSize - getNumReady() - 1; }
|
||||||
|
|
||||||
|
int AbstractFifo::getNumReady() const noexcept
|
||||||
|
{
|
||||||
|
const int vs = validStart.get();
|
||||||
|
const int ve = validEnd.get();
|
||||||
|
return ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractFifo::reset() noexcept
|
||||||
|
{
|
||||||
|
validEnd = 0;
|
||||||
|
validStart = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractFifo::setTotalSize (int newSize) noexcept
|
||||||
|
{
|
||||||
|
jassert (newSize > 0);
|
||||||
|
reset();
|
||||||
|
bufferSize = newSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void AbstractFifo::prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept
|
||||||
|
{
|
||||||
|
const int vs = validStart.get();
|
||||||
|
const int ve = validEnd.value;
|
||||||
|
|
||||||
|
const int freeSpace = ve >= vs ? (bufferSize - (ve - vs)) : (vs - ve);
|
||||||
|
numToWrite = jmin (numToWrite, freeSpace - 1);
|
||||||
|
|
||||||
|
if (numToWrite <= 0)
|
||||||
|
{
|
||||||
|
startIndex1 = 0;
|
||||||
|
startIndex2 = 0;
|
||||||
|
blockSize1 = 0;
|
||||||
|
blockSize2 = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
startIndex1 = ve;
|
||||||
|
startIndex2 = 0;
|
||||||
|
blockSize1 = jmin (bufferSize - ve, numToWrite);
|
||||||
|
numToWrite -= blockSize1;
|
||||||
|
blockSize2 = numToWrite <= 0 ? 0 : jmin (numToWrite, vs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractFifo::finishedWrite (int numWritten) noexcept
|
||||||
|
{
|
||||||
|
jassert (numWritten >= 0 && numWritten < bufferSize);
|
||||||
|
int newEnd = validEnd.value + numWritten;
|
||||||
|
if (newEnd >= bufferSize)
|
||||||
|
newEnd -= bufferSize;
|
||||||
|
|
||||||
|
validEnd = newEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractFifo::prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept
|
||||||
|
{
|
||||||
|
const int vs = validStart.value;
|
||||||
|
const int ve = validEnd.get();
|
||||||
|
|
||||||
|
const int numReady = ve >= vs ? (ve - vs) : (bufferSize - (vs - ve));
|
||||||
|
numWanted = jmin (numWanted, numReady);
|
||||||
|
|
||||||
|
if (numWanted <= 0)
|
||||||
|
{
|
||||||
|
startIndex1 = 0;
|
||||||
|
startIndex2 = 0;
|
||||||
|
blockSize1 = 0;
|
||||||
|
blockSize2 = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
startIndex1 = vs;
|
||||||
|
startIndex2 = 0;
|
||||||
|
blockSize1 = jmin (bufferSize - vs, numWanted);
|
||||||
|
numWanted -= blockSize1;
|
||||||
|
blockSize2 = numWanted <= 0 ? 0 : jmin (numWanted, ve);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractFifo::finishedRead (int numRead) noexcept
|
||||||
|
{
|
||||||
|
jassert (numRead >= 0 && numRead <= bufferSize);
|
||||||
|
|
||||||
|
int newStart = validStart.value + numRead;
|
||||||
|
if (newStart >= bufferSize)
|
||||||
|
newStart -= bufferSize;
|
||||||
|
|
||||||
|
validStart = newStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
//==============================================================================
|
||||||
|
#if JUCE_UNIT_TESTS
|
||||||
|
|
||||||
|
class AbstractFifoTests : public UnitTest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AbstractFifoTests() : UnitTest ("Abstract Fifo") {}
|
||||||
|
|
||||||
|
class WriteThread : public Thread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WriteThread (AbstractFifo& f, int* b, Random rng)
|
||||||
|
: Thread ("fifo writer"), fifo (f), buffer (b), random (rng)
|
||||||
|
{
|
||||||
|
startThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
~WriteThread()
|
||||||
|
{
|
||||||
|
stopThread (5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void run()
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
while (! threadShouldExit())
|
||||||
|
{
|
||||||
|
int num = random.nextInt (2000) + 1;
|
||||||
|
|
||||||
|
int start1, size1, start2, size2;
|
||||||
|
fifo.prepareToWrite (num, start1, size1, start2, size2);
|
||||||
|
|
||||||
|
jassert (size1 >= 0 && size2 >= 0);
|
||||||
|
jassert (size1 == 0 || (start1 >= 0 && start1 < fifo.getTotalSize()));
|
||||||
|
jassert (size2 == 0 || (start2 >= 0 && start2 < fifo.getTotalSize()));
|
||||||
|
|
||||||
|
for (int i = 0; i < size1; ++i)
|
||||||
|
buffer [start1 + i] = n++;
|
||||||
|
|
||||||
|
for (int i = 0; i < size2; ++i)
|
||||||
|
buffer [start2 + i] = n++;
|
||||||
|
|
||||||
|
fifo.finishedWrite (size1 + size2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AbstractFifo& fifo;
|
||||||
|
int* buffer;
|
||||||
|
Random random;
|
||||||
|
};
|
||||||
|
|
||||||
|
void runTest()
|
||||||
|
{
|
||||||
|
beginTest ("AbstractFifo");
|
||||||
|
|
||||||
|
int buffer [5000];
|
||||||
|
AbstractFifo fifo (numElementsInArray (buffer));
|
||||||
|
|
||||||
|
WriteThread writer (fifo, buffer, getRandom());
|
||||||
|
|
||||||
|
int n = 0;
|
||||||
|
Random r = getRandom();
|
||||||
|
r.combineSeed (12345);
|
||||||
|
|
||||||
|
for (int count = 100000; --count >= 0;)
|
||||||
|
{
|
||||||
|
int num = r.nextInt (6000) + 1;
|
||||||
|
|
||||||
|
int start1, size1, start2, size2;
|
||||||
|
fifo.prepareToRead (num, start1, size1, start2, size2);
|
||||||
|
|
||||||
|
if (! (size1 >= 0 && size2 >= 0)
|
||||||
|
&& (size1 == 0 || (start1 >= 0 && start1 < fifo.getTotalSize()))
|
||||||
|
&& (size2 == 0 || (start2 >= 0 && start2 < fifo.getTotalSize())))
|
||||||
|
{
|
||||||
|
expect (false, "prepareToRead returned -ve values");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool failed = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < size1; ++i)
|
||||||
|
failed = (buffer [start1 + i] != n++) || failed;
|
||||||
|
|
||||||
|
for (int i = 0; i < size2; ++i)
|
||||||
|
failed = (buffer [start2 + i] != n++) || failed;
|
||||||
|
|
||||||
|
if (failed)
|
||||||
|
{
|
||||||
|
expect (false, "read values were incorrect");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fifo.finishedRead (size1 + size2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static AbstractFifoTests fifoUnitTests;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,220 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_ABSTRACTFIFO_H_INCLUDED
|
||||||
|
#define JUCE_ABSTRACTFIFO_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Encapsulates the logic required to implement a lock-free FIFO.
|
||||||
|
|
||||||
|
This class handles the logic needed when building a single-reader, single-writer FIFO.
|
||||||
|
|
||||||
|
It doesn't actually hold any data itself, but your FIFO class can use one of these to manage
|
||||||
|
its position and status when reading or writing to it.
|
||||||
|
|
||||||
|
To use it, you can call prepareToWrite() to determine the position within your own buffer that
|
||||||
|
an incoming block of data should be stored, and prepareToRead() to find out when the next
|
||||||
|
outgoing block should be read from.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
@code
|
||||||
|
class MyFifo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MyFifo() : abstractFifo (1024)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void addToFifo (const int* someData, int numItems)
|
||||||
|
{
|
||||||
|
int start1, size1, start2, size2;
|
||||||
|
abstractFifo.prepareToWrite (numItems, start1, size1, start2, size2);
|
||||||
|
|
||||||
|
if (size1 > 0)
|
||||||
|
copySomeData (myBuffer + start1, someData, size1);
|
||||||
|
|
||||||
|
if (size2 > 0)
|
||||||
|
copySomeData (myBuffer + start2, someData + size1, size2);
|
||||||
|
|
||||||
|
abstractFifo.finishedWrite (size1 + size2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void readFromFifo (int* someData, int numItems)
|
||||||
|
{
|
||||||
|
int start1, size1, start2, size2;
|
||||||
|
abstractFifo.prepareToRead (numSamples, start1, size1, start2, size2);
|
||||||
|
|
||||||
|
if (size1 > 0)
|
||||||
|
copySomeData (someData, myBuffer + start1, size1);
|
||||||
|
|
||||||
|
if (size2 > 0)
|
||||||
|
copySomeData (someData + size1, myBuffer + start2, size2);
|
||||||
|
|
||||||
|
abstractFifo.finishedRead (size1 + size2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AbstractFifo abstractFifo;
|
||||||
|
int myBuffer [1024];
|
||||||
|
};
|
||||||
|
@endcode
|
||||||
|
*/
|
||||||
|
class JUCE_API AbstractFifo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a FIFO to manage a buffer with the specified capacity. */
|
||||||
|
AbstractFifo (int capacity) noexcept;
|
||||||
|
|
||||||
|
/** Destructor */
|
||||||
|
~AbstractFifo();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the total size of the buffer being managed. */
|
||||||
|
int getTotalSize() const noexcept;
|
||||||
|
|
||||||
|
/** Returns the number of items that can currently be added to the buffer without it overflowing. */
|
||||||
|
int getFreeSpace() const noexcept;
|
||||||
|
|
||||||
|
/** Returns the number of items that can currently be read from the buffer. */
|
||||||
|
int getNumReady() const noexcept;
|
||||||
|
|
||||||
|
/** Clears the buffer positions, so that it appears empty. */
|
||||||
|
void reset() noexcept;
|
||||||
|
|
||||||
|
/** Changes the buffer's total size.
|
||||||
|
Note that this isn't thread-safe, so don't call it if there's any danger that it
|
||||||
|
might overlap with a call to any other method in this class!
|
||||||
|
*/
|
||||||
|
void setTotalSize (int newSize) noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the location within the buffer at which an incoming block of data should be written.
|
||||||
|
|
||||||
|
Because the section of data that you want to add to the buffer may overlap the end
|
||||||
|
and wrap around to the start, two blocks within your buffer are returned, and you
|
||||||
|
should copy your data into the first one, with any remaining data spilling over into
|
||||||
|
the second.
|
||||||
|
|
||||||
|
If the number of items you ask for is too large to fit within the buffer's free space, then
|
||||||
|
blockSize1 + blockSize2 may add up to a lower value than numToWrite. If this happens, you
|
||||||
|
may decide to keep waiting and re-trying the method until there's enough space available.
|
||||||
|
|
||||||
|
After calling this method, if you choose to write your data into the blocks returned, you
|
||||||
|
must call finishedWrite() to tell the FIFO how much data you actually added.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
@code
|
||||||
|
void addToFifo (const int* someData, int numItems)
|
||||||
|
{
|
||||||
|
int start1, size1, start2, size2;
|
||||||
|
prepareToWrite (numItems, start1, size1, start2, size2);
|
||||||
|
|
||||||
|
if (size1 > 0)
|
||||||
|
copySomeData (myBuffer + start1, someData, size1);
|
||||||
|
|
||||||
|
if (size2 > 0)
|
||||||
|
copySomeData (myBuffer + start2, someData + size1, size2);
|
||||||
|
|
||||||
|
finishedWrite (size1 + size2);
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@param numToWrite indicates how many items you'd like to add to the buffer
|
||||||
|
@param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
|
||||||
|
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
|
||||||
|
@param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
|
||||||
|
the first block should be written
|
||||||
|
@param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2
|
||||||
|
@see finishedWrite
|
||||||
|
*/
|
||||||
|
void prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
|
||||||
|
|
||||||
|
/** Called after writing from the FIFO, to indicate that this many items have been added.
|
||||||
|
@see prepareToWrite
|
||||||
|
*/
|
||||||
|
void finishedWrite (int numWritten) noexcept;
|
||||||
|
|
||||||
|
/** Returns the location within the buffer from which the next block of data should be read.
|
||||||
|
|
||||||
|
Because the section of data that you want to read from the buffer may overlap the end
|
||||||
|
and wrap around to the start, two blocks within your buffer are returned, and you
|
||||||
|
should read from both of them.
|
||||||
|
|
||||||
|
If the number of items you ask for is greater than the amount of data available, then
|
||||||
|
blockSize1 + blockSize2 may add up to a lower value than numWanted. If this happens, you
|
||||||
|
may decide to keep waiting and re-trying the method until there's enough data available.
|
||||||
|
|
||||||
|
After calling this method, if you choose to read the data, you must call finishedRead() to
|
||||||
|
tell the FIFO how much data you have consumed.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
@code
|
||||||
|
void readFromFifo (int* someData, int numItems)
|
||||||
|
{
|
||||||
|
int start1, size1, start2, size2;
|
||||||
|
prepareToRead (numSamples, start1, size1, start2, size2);
|
||||||
|
|
||||||
|
if (size1 > 0)
|
||||||
|
copySomeData (someData, myBuffer + start1, size1);
|
||||||
|
|
||||||
|
if (size2 > 0)
|
||||||
|
copySomeData (someData + size1, myBuffer + start2, size2);
|
||||||
|
|
||||||
|
finishedRead (size1 + size2);
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@param numWanted indicates how many items you'd like to add to the buffer
|
||||||
|
@param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written
|
||||||
|
@param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1
|
||||||
|
@param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into
|
||||||
|
the first block should be written
|
||||||
|
@param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2
|
||||||
|
@see finishedRead
|
||||||
|
*/
|
||||||
|
void prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const noexcept;
|
||||||
|
|
||||||
|
/** Called after reading from the FIFO, to indicate that this many items have now been consumed.
|
||||||
|
@see prepareToRead
|
||||||
|
*/
|
||||||
|
void finishedRead (int numRead) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
int bufferSize;
|
||||||
|
Atomic <int> validStart, validEnd;
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AbstractFifo)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_ABSTRACTFIFO_H_INCLUDED
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_ARRAYALLOCATIONBASE_H_INCLUDED
|
||||||
|
#define JUCE_ARRAYALLOCATIONBASE_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Implements some basic array storage allocation functions.
|
||||||
|
|
||||||
|
This class isn't really for public use - it's used by the other
|
||||||
|
array classes, but might come in handy for some purposes.
|
||||||
|
|
||||||
|
It inherits from a critical section class to allow the arrays to use
|
||||||
|
the "empty base class optimisation" pattern to reduce their footprint.
|
||||||
|
|
||||||
|
@see Array, OwnedArray, ReferenceCountedArray
|
||||||
|
*/
|
||||||
|
template <class ElementType, class TypeOfCriticalSectionToUse>
|
||||||
|
class ArrayAllocationBase : public TypeOfCriticalSectionToUse
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an empty array. */
|
||||||
|
ArrayAllocationBase() noexcept
|
||||||
|
: numAllocated (0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~ArrayAllocationBase() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
ArrayAllocationBase (ArrayAllocationBase<ElementType, TypeOfCriticalSectionToUse>&& other) noexcept
|
||||||
|
: elements (static_cast <HeapBlock <ElementType>&&> (other.elements)),
|
||||||
|
numAllocated (other.numAllocated)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayAllocationBase& operator= (ArrayAllocationBase<ElementType, TypeOfCriticalSectionToUse>&& other) noexcept
|
||||||
|
{
|
||||||
|
elements = static_cast <HeapBlock <ElementType>&&> (other.elements);
|
||||||
|
numAllocated = other.numAllocated;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Changes the amount of storage allocated.
|
||||||
|
|
||||||
|
This will retain any data currently held in the array, and either add or
|
||||||
|
remove extra space at the end.
|
||||||
|
|
||||||
|
@param numElements the number of elements that are needed
|
||||||
|
*/
|
||||||
|
void setAllocatedSize (const int numElements)
|
||||||
|
{
|
||||||
|
if (numAllocated != numElements)
|
||||||
|
{
|
||||||
|
if (numElements > 0)
|
||||||
|
elements.realloc ((size_t) numElements);
|
||||||
|
else
|
||||||
|
elements.free();
|
||||||
|
|
||||||
|
numAllocated = numElements;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Increases the amount of storage allocated if it is less than a given amount.
|
||||||
|
|
||||||
|
This will retain any data currently held in the array, but will add
|
||||||
|
extra space at the end to make sure there it's at least as big as the size
|
||||||
|
passed in. If it's already bigger, no action is taken.
|
||||||
|
|
||||||
|
@param minNumElements the minimum number of elements that are needed
|
||||||
|
*/
|
||||||
|
void ensureAllocatedSize (const int minNumElements)
|
||||||
|
{
|
||||||
|
if (minNumElements > numAllocated)
|
||||||
|
setAllocatedSize ((minNumElements + minNumElements / 2 + 8) & ~7);
|
||||||
|
|
||||||
|
jassert (numAllocated <= 0 || elements != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Minimises the amount of storage allocated so that it's no more than
|
||||||
|
the given number of elements.
|
||||||
|
*/
|
||||||
|
void shrinkToNoMoreThan (const int maxNumElements)
|
||||||
|
{
|
||||||
|
if (maxNumElements < numAllocated)
|
||||||
|
setAllocatedSize (maxNumElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Swap the contents of two objects. */
|
||||||
|
void swapWith (ArrayAllocationBase <ElementType, TypeOfCriticalSectionToUse>& other) noexcept
|
||||||
|
{
|
||||||
|
elements.swapWith (other.elements);
|
||||||
|
std::swap (numAllocated, other.numAllocated);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
HeapBlock <ElementType> elements;
|
||||||
|
int numAllocated;
|
||||||
|
|
||||||
|
private:
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (ArrayAllocationBase)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_ARRAYALLOCATIONBASE_H_INCLUDED
|
||||||
@@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
DynamicObject::DynamicObject()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicObject::DynamicObject (const DynamicObject& other)
|
||||||
|
: ReferenceCountedObject(), properties (other.properties)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicObject::~DynamicObject()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DynamicObject::hasProperty (const Identifier& propertyName) const
|
||||||
|
{
|
||||||
|
const var* const v = properties.getVarPointer (propertyName);
|
||||||
|
return v != nullptr && ! v->isMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
var DynamicObject::getProperty (const Identifier& propertyName) const
|
||||||
|
{
|
||||||
|
return properties [propertyName];
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicObject::setProperty (const Identifier& propertyName, const var& newValue)
|
||||||
|
{
|
||||||
|
properties.set (propertyName, newValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicObject::removeProperty (const Identifier& propertyName)
|
||||||
|
{
|
||||||
|
properties.remove (propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DynamicObject::hasMethod (const Identifier& methodName) const
|
||||||
|
{
|
||||||
|
return getProperty (methodName).isMethod();
|
||||||
|
}
|
||||||
|
|
||||||
|
var DynamicObject::invokeMethod (Identifier method, const var::NativeFunctionArgs& args)
|
||||||
|
{
|
||||||
|
if (var::NativeFunction function = properties [method].getNativeFunction())
|
||||||
|
return function (args);
|
||||||
|
|
||||||
|
return var();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicObject::setMethod (Identifier name, var::NativeFunction function)
|
||||||
|
{
|
||||||
|
properties.set (name, var (function));
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicObject::clear()
|
||||||
|
{
|
||||||
|
properties.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicObject::cloneAllProperties()
|
||||||
|
{
|
||||||
|
for (int i = properties.size(); --i >= 0;)
|
||||||
|
if (var* v = properties.getVarPointerAt (i))
|
||||||
|
*v = v->clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicObject::Ptr DynamicObject::clone()
|
||||||
|
{
|
||||||
|
Ptr d (new DynamicObject (*this));
|
||||||
|
d->cloneAllProperties();
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicObject::writeAsJSON (OutputStream& out, const int indentLevel, const bool allOnOneLine)
|
||||||
|
{
|
||||||
|
out << '{';
|
||||||
|
if (! allOnOneLine)
|
||||||
|
out << newLine;
|
||||||
|
|
||||||
|
const int numValues = properties.size();
|
||||||
|
|
||||||
|
for (int i = 0; i < numValues; ++i)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
out << ", ";
|
||||||
|
else
|
||||||
|
out << ',' << newLine;
|
||||||
|
}
|
||||||
|
else if (! allOnOneLine)
|
||||||
|
out << newLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! allOnOneLine)
|
||||||
|
JSONFormatter::writeSpaces (out, indentLevel);
|
||||||
|
|
||||||
|
out << '}';
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_DYNAMICOBJECT_H_INCLUDED
|
||||||
|
#define JUCE_DYNAMICOBJECT_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Represents a dynamically implemented object.
|
||||||
|
|
||||||
|
This class is primarily intended for wrapping scripting language objects,
|
||||||
|
but could be used for other purposes.
|
||||||
|
|
||||||
|
An instance of a DynamicObject can be used to store named properties, and
|
||||||
|
by subclassing hasMethod() and invokeMethod(), you can give your object
|
||||||
|
methods.
|
||||||
|
*/
|
||||||
|
class JUCE_API DynamicObject : public ReferenceCountedObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
DynamicObject();
|
||||||
|
DynamicObject (const DynamicObject&);
|
||||||
|
~DynamicObject();
|
||||||
|
|
||||||
|
typedef ReferenceCountedObjectPtr<DynamicObject> Ptr;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns true if the object has a property with this name.
|
||||||
|
Note that if the property is actually a method, this will return false.
|
||||||
|
*/
|
||||||
|
virtual bool hasProperty (const Identifier& propertyName) const;
|
||||||
|
|
||||||
|
/** Returns a named property.
|
||||||
|
This returns var::null if no such property exists.
|
||||||
|
*/
|
||||||
|
virtual var getProperty (const Identifier& propertyName) const;
|
||||||
|
|
||||||
|
/** Sets a named property. */
|
||||||
|
virtual void setProperty (const Identifier& propertyName, const var& newValue);
|
||||||
|
|
||||||
|
/** Removes a named property. */
|
||||||
|
virtual void removeProperty (const Identifier& propertyName);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Checks whether this object has the specified method.
|
||||||
|
|
||||||
|
The default implementation of this just checks whether there's a property
|
||||||
|
with this name that's actually a method, but this can be overridden for
|
||||||
|
building objects with dynamic invocation.
|
||||||
|
*/
|
||||||
|
virtual bool hasMethod (const Identifier& methodName) const;
|
||||||
|
|
||||||
|
/** Invokes a named method on this object.
|
||||||
|
|
||||||
|
The default implementation looks up the named property, and if it's a method
|
||||||
|
call, then it invokes it.
|
||||||
|
|
||||||
|
This method is virtual to allow more dynamic invocation to used for objects
|
||||||
|
where the methods may not already be set as properies.
|
||||||
|
*/
|
||||||
|
virtual var invokeMethod (Identifier methodName,
|
||||||
|
const var::NativeFunctionArgs& args);
|
||||||
|
|
||||||
|
/** Adds a method to the class.
|
||||||
|
|
||||||
|
This is basically the same as calling setProperty (methodName, (var::NativeFunction) myFunction), but
|
||||||
|
helps to avoid accidentally invoking the wrong type of var constructor. It also makes
|
||||||
|
the code easier to read,
|
||||||
|
*/
|
||||||
|
void setMethod (Identifier methodName, var::NativeFunction function);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Removes all properties and methods from the object. */
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
/** Returns the NamedValueSet that holds the object's properties. */
|
||||||
|
NamedValueSet& getProperties() noexcept { return properties; }
|
||||||
|
|
||||||
|
/** Calls var::clone() on all the properties that this object contains. */
|
||||||
|
void cloneAllProperties();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a clone of this object.
|
||||||
|
The default implementation of this method just returns a new DynamicObject
|
||||||
|
with a (deep) copy of all of its properties. Subclasses can override this to
|
||||||
|
implement their own custom copy routines.
|
||||||
|
*/
|
||||||
|
virtual Ptr clone();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Writes this object to a text stream in JSON format.
|
||||||
|
This method is used by JSON::toString and JSON::writeToStream, and you should
|
||||||
|
never need to call it directly, but it's virtual so that custom object types
|
||||||
|
can stringify themselves appropriately.
|
||||||
|
*/
|
||||||
|
virtual void writeAsJSON (OutputStream&, int indentLevel, bool allOnOneLine);
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
NamedValueSet properties;
|
||||||
|
|
||||||
|
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
|
||||||
|
// These methods have been deprecated - use var::invoke instead
|
||||||
|
virtual void invokeMethod (const Identifier&, const var*, int) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
JUCE_LEAK_DETECTOR (DynamicObject)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_DYNAMICOBJECT_H_INCLUDED
|
||||||
@@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_ELEMENTCOMPARATOR_H_INCLUDED
|
||||||
|
#define JUCE_ELEMENTCOMPARATOR_H_INCLUDED
|
||||||
|
|
||||||
|
#ifndef DOXYGEN
|
||||||
|
|
||||||
|
/** This is an internal helper class which converts a juce ElementComparator style
|
||||||
|
class (using a "compareElements" method) into a class that's compatible with
|
||||||
|
std::sort (i.e. using an operator() to compare the elements)
|
||||||
|
*/
|
||||||
|
template <typename ElementComparator>
|
||||||
|
struct SortFunctionConverter
|
||||||
|
{
|
||||||
|
SortFunctionConverter (ElementComparator& e) : comparator (e) {}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
bool operator() (Type a, Type b) { return comparator.compareElements (a, b) < 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ElementComparator& comparator;
|
||||||
|
SortFunctionConverter& operator= (const SortFunctionConverter&) JUCE_DELETED_FUNCTION;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Sorts a range of elements in an array.
|
||||||
|
|
||||||
|
The comparator object that is passed-in must define a public method with the following
|
||||||
|
signature:
|
||||||
|
@code
|
||||||
|
int compareElements (ElementType first, ElementType second);
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
..and this method must return:
|
||||||
|
- a value of < 0 if the first comes before the second
|
||||||
|
- a value of 0 if the two objects are equivalent
|
||||||
|
- a value of > 0 if the second comes before the first
|
||||||
|
|
||||||
|
To improve performance, the compareElements() method can be declared as static or const.
|
||||||
|
|
||||||
|
@param comparator an object which defines a compareElements() method
|
||||||
|
@param array the array to sort
|
||||||
|
@param firstElement the index of the first element of the range to be sorted
|
||||||
|
@param lastElement the index of the last element in the range that needs
|
||||||
|
sorting (this is inclusive)
|
||||||
|
@param retainOrderOfEquivalentItems if true, the order of items that the
|
||||||
|
comparator deems the same will be maintained - this will be
|
||||||
|
a slower algorithm than if they are allowed to be moved around.
|
||||||
|
|
||||||
|
@see sortArrayRetainingOrder
|
||||||
|
*/
|
||||||
|
template <class ElementType, class ElementComparator>
|
||||||
|
static void sortArray (ElementComparator& comparator,
|
||||||
|
ElementType* const array,
|
||||||
|
int firstElement,
|
||||||
|
int lastElement,
|
||||||
|
const bool retainOrderOfEquivalentItems)
|
||||||
|
{
|
||||||
|
SortFunctionConverter<ElementComparator> converter (comparator);
|
||||||
|
|
||||||
|
if (retainOrderOfEquivalentItems)
|
||||||
|
std::stable_sort (array + firstElement, array + lastElement + 1, converter);
|
||||||
|
else
|
||||||
|
std::sort (array + firstElement, array + lastElement + 1, converter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Searches a sorted array of elements, looking for the index at which a specified value
|
||||||
|
should be inserted for it to be in the correct order.
|
||||||
|
|
||||||
|
The comparator object that is passed-in must define a public method with the following
|
||||||
|
signature:
|
||||||
|
@code
|
||||||
|
int compareElements (ElementType first, ElementType second);
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
..and this method must return:
|
||||||
|
- a value of < 0 if the first comes before the second
|
||||||
|
- a value of 0 if the two objects are equivalent
|
||||||
|
- a value of > 0 if the second comes before the first
|
||||||
|
|
||||||
|
To improve performance, the compareElements() method can be declared as static or const.
|
||||||
|
|
||||||
|
@param comparator an object which defines a compareElements() method
|
||||||
|
@param array the array to search
|
||||||
|
@param newElement the value that is going to be inserted
|
||||||
|
@param firstElement the index of the first element to search
|
||||||
|
@param lastElement the index of the last element in the range (this is non-inclusive)
|
||||||
|
*/
|
||||||
|
template <class ElementType, class ElementComparator>
|
||||||
|
static int findInsertIndexInSortedArray (ElementComparator& comparator,
|
||||||
|
ElementType* const array,
|
||||||
|
const ElementType newElement,
|
||||||
|
int firstElement,
|
||||||
|
int lastElement)
|
||||||
|
{
|
||||||
|
jassert (firstElement <= lastElement);
|
||||||
|
|
||||||
|
(void) comparator; // if you pass in an object with a static compareElements() method, this
|
||||||
|
// avoids getting warning messages about the parameter being unused
|
||||||
|
|
||||||
|
while (firstElement < lastElement)
|
||||||
|
{
|
||||||
|
if (comparator.compareElements (newElement, array [firstElement]) == 0)
|
||||||
|
{
|
||||||
|
++firstElement;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const int halfway = (firstElement + lastElement) >> 1;
|
||||||
|
|
||||||
|
if (halfway == firstElement)
|
||||||
|
{
|
||||||
|
if (comparator.compareElements (newElement, array [halfway]) >= 0)
|
||||||
|
++firstElement;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (comparator.compareElements (newElement, array [halfway]) >= 0)
|
||||||
|
{
|
||||||
|
firstElement = halfway;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lastElement = halfway;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return firstElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A simple ElementComparator class that can be used to sort an array of
|
||||||
|
objects that support the '<' operator.
|
||||||
|
|
||||||
|
This will work for primitive types and objects that implement operator<().
|
||||||
|
|
||||||
|
Example: @code
|
||||||
|
Array <int> myArray;
|
||||||
|
DefaultElementComparator<int> sorter;
|
||||||
|
myArray.sort (sorter);
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@see ElementComparator
|
||||||
|
*/
|
||||||
|
template <class ElementType>
|
||||||
|
class DefaultElementComparator
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef PARAMETER_TYPE (ElementType) ParameterType;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static int compareElements (ParameterType first, ParameterType second)
|
||||||
|
{
|
||||||
|
return (first < second) ? -1 : ((second < first) ? 1 : 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_ELEMENTCOMPARATOR_H_INCLUDED
|
||||||
@@ -0,0 +1,455 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_HASHMAP_H_INCLUDED
|
||||||
|
#define JUCE_HASHMAP_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A simple class to generate hash functions for some primitive types, intended for
|
||||||
|
use with the HashMap class.
|
||||||
|
@see HashMap
|
||||||
|
*/
|
||||||
|
struct DefaultHashFunctions
|
||||||
|
{
|
||||||
|
/** Generates a simple hash from an integer. */
|
||||||
|
int generateHash (const int key, const int upperLimit) const noexcept { return std::abs (key) % upperLimit; }
|
||||||
|
/** Generates a simple hash from an int64. */
|
||||||
|
int generateHash (const int64 key, const int upperLimit) const noexcept { return std::abs ((int) key) % upperLimit; }
|
||||||
|
/** Generates a simple hash from a string. */
|
||||||
|
int generateHash (const String& key, const int upperLimit) const noexcept { return (int) (((uint32) key.hashCode()) % (uint32) upperLimit); }
|
||||||
|
/** Generates a simple hash from a variant. */
|
||||||
|
int generateHash (const var& key, const int upperLimit) const noexcept { return generateHash (key.toString(), upperLimit); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Holds a set of mappings between some key/value pairs.
|
||||||
|
|
||||||
|
The types of the key and value objects are set as template parameters.
|
||||||
|
You can also specify a class to supply a hash function that converts a key value
|
||||||
|
into an hashed integer. This class must have the form:
|
||||||
|
|
||||||
|
@code
|
||||||
|
struct MyHashGenerator
|
||||||
|
{
|
||||||
|
int generateHash (MyKeyType key, int upperLimit) const
|
||||||
|
{
|
||||||
|
// The function must return a value 0 <= x < upperLimit
|
||||||
|
return someFunctionOfMyKeyType (key) % upperLimit;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
Like the Array class, the key and value types are expected to be copy-by-value
|
||||||
|
types, so if you define them to be pointer types, this class won't delete the
|
||||||
|
objects that they point to.
|
||||||
|
|
||||||
|
If you don't supply a class for the HashFunctionType template parameter, the
|
||||||
|
default one provides some simple mappings for strings and ints.
|
||||||
|
|
||||||
|
@code
|
||||||
|
HashMap<int, String> hash;
|
||||||
|
hash.set (1, "item1");
|
||||||
|
hash.set (2, "item2");
|
||||||
|
|
||||||
|
DBG (hash [1]); // prints "item1"
|
||||||
|
DBG (hash [2]); // prints "item2"
|
||||||
|
|
||||||
|
// This iterates the map, printing all of its key -> value pairs..
|
||||||
|
for (HashMap<int, String>::Iterator i (hash); i.next();)
|
||||||
|
DBG (i.getKey() << " -> " << i.getValue());
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@tparam HashFunctionType The class of hash function, which must be copy-constructible.
|
||||||
|
@see CriticalSection, DefaultHashFunctions, NamedValueSet, SortedSet
|
||||||
|
*/
|
||||||
|
template <typename KeyType,
|
||||||
|
typename ValueType,
|
||||||
|
class HashFunctionType = DefaultHashFunctions,
|
||||||
|
class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
||||||
|
class HashMap
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef PARAMETER_TYPE (KeyType) KeyTypeParameter;
|
||||||
|
typedef PARAMETER_TYPE (ValueType) ValueTypeParameter;
|
||||||
|
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an empty hash-map.
|
||||||
|
|
||||||
|
@param numberOfSlots Specifies the number of hash entries the map will use. This will be
|
||||||
|
the "upperLimit" parameter that is passed to your generateHash()
|
||||||
|
function. The number of hash slots will grow automatically if necessary,
|
||||||
|
or it can be remapped manually using remapTable().
|
||||||
|
@param hashFunction An instance of HashFunctionType, which will be copied and
|
||||||
|
stored to use with the HashMap. This parameter can be omitted
|
||||||
|
if HashFunctionType has a default constructor.
|
||||||
|
*/
|
||||||
|
explicit HashMap (int numberOfSlots = defaultHashTableSize,
|
||||||
|
HashFunctionType hashFunction = HashFunctionType())
|
||||||
|
: hashFunctionToUse (hashFunction), totalNumItems (0)
|
||||||
|
{
|
||||||
|
hashSlots.insertMultiple (0, nullptr, numberOfSlots);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~HashMap()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Removes all values from the map.
|
||||||
|
Note that this will clear the content, but won't affect the number of slots (see
|
||||||
|
remapTable and getNumSlots).
|
||||||
|
*/
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
const ScopedLockType sl (getLock());
|
||||||
|
|
||||||
|
for (int i = hashSlots.size(); --i >= 0;)
|
||||||
|
{
|
||||||
|
HashEntry* h = hashSlots.getUnchecked(i);
|
||||||
|
|
||||||
|
while (h != nullptr)
|
||||||
|
{
|
||||||
|
const ScopedPointer<HashEntry> deleter (h);
|
||||||
|
h = h->nextEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
hashSlots.set (i, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
totalNumItems = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the current number of items in the map. */
|
||||||
|
inline int size() const noexcept
|
||||||
|
{
|
||||||
|
return totalNumItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the value corresponding to a given key.
|
||||||
|
If the map doesn't contain the key, a default instance of the value type is returned.
|
||||||
|
@param keyToLookFor the key of the item being requested
|
||||||
|
*/
|
||||||
|
inline ValueType operator[] (KeyTypeParameter keyToLookFor) const
|
||||||
|
{
|
||||||
|
const ScopedLockType sl (getLock());
|
||||||
|
|
||||||
|
for (const HashEntry* entry = hashSlots.getUnchecked (generateHashFor (keyToLookFor)); entry != nullptr; entry = entry->nextEntry)
|
||||||
|
if (entry->key == keyToLookFor)
|
||||||
|
return entry->value;
|
||||||
|
|
||||||
|
return ValueType();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns true if the map contains an item with the specied key. */
|
||||||
|
bool contains (KeyTypeParameter keyToLookFor) const
|
||||||
|
{
|
||||||
|
const ScopedLockType sl (getLock());
|
||||||
|
|
||||||
|
for (const HashEntry* entry = hashSlots.getUnchecked (generateHashFor (keyToLookFor)); entry != nullptr; entry = entry->nextEntry)
|
||||||
|
if (entry->key == keyToLookFor)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the hash contains at least one occurrence of a given value. */
|
||||||
|
bool containsValue (ValueTypeParameter valueToLookFor) const
|
||||||
|
{
|
||||||
|
const ScopedLockType sl (getLock());
|
||||||
|
|
||||||
|
for (int i = getNumSlots(); --i >= 0;)
|
||||||
|
for (const HashEntry* entry = hashSlots.getUnchecked(i); entry != nullptr; entry = entry->nextEntry)
|
||||||
|
if (entry->value == valueToLookFor)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Adds or replaces an element in the hash-map.
|
||||||
|
If there's already an item with the given key, this will replace its value. Otherwise, a new item
|
||||||
|
will be added to the map.
|
||||||
|
*/
|
||||||
|
void set (KeyTypeParameter newKey, ValueTypeParameter newValue)
|
||||||
|
{
|
||||||
|
const ScopedLockType sl (getLock());
|
||||||
|
const int hashIndex = generateHashFor (newKey);
|
||||||
|
|
||||||
|
HashEntry* const firstEntry = hashSlots.getUnchecked (hashIndex);
|
||||||
|
|
||||||
|
for (HashEntry* entry = firstEntry; entry != nullptr; entry = entry->nextEntry)
|
||||||
|
{
|
||||||
|
if (entry->key == newKey)
|
||||||
|
{
|
||||||
|
entry->value = newValue;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hashSlots.set (hashIndex, new HashEntry (newKey, newValue, firstEntry));
|
||||||
|
++totalNumItems;
|
||||||
|
|
||||||
|
if (totalNumItems > (getNumSlots() * 3) / 2)
|
||||||
|
remapTable (getNumSlots() * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes an item with the given key. */
|
||||||
|
void remove (KeyTypeParameter keyToRemove)
|
||||||
|
{
|
||||||
|
const ScopedLockType sl (getLock());
|
||||||
|
const int hashIndex = generateHashFor (keyToRemove);
|
||||||
|
HashEntry* entry = hashSlots.getUnchecked (hashIndex);
|
||||||
|
HashEntry* previous = nullptr;
|
||||||
|
|
||||||
|
while (entry != nullptr)
|
||||||
|
{
|
||||||
|
if (entry->key == keyToRemove)
|
||||||
|
{
|
||||||
|
const ScopedPointer<HashEntry> deleter (entry);
|
||||||
|
|
||||||
|
entry = entry->nextEntry;
|
||||||
|
|
||||||
|
if (previous != nullptr)
|
||||||
|
previous->nextEntry = entry;
|
||||||
|
else
|
||||||
|
hashSlots.set (hashIndex, entry);
|
||||||
|
|
||||||
|
--totalNumItems;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
previous = entry;
|
||||||
|
entry = entry->nextEntry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes all items with the given value. */
|
||||||
|
void removeValue (ValueTypeParameter valueToRemove)
|
||||||
|
{
|
||||||
|
const ScopedLockType sl (getLock());
|
||||||
|
|
||||||
|
for (int i = getNumSlots(); --i >= 0;)
|
||||||
|
{
|
||||||
|
HashEntry* entry = hashSlots.getUnchecked(i);
|
||||||
|
HashEntry* previous = nullptr;
|
||||||
|
|
||||||
|
while (entry != nullptr)
|
||||||
|
{
|
||||||
|
if (entry->value == valueToRemove)
|
||||||
|
{
|
||||||
|
const ScopedPointer<HashEntry> deleter (entry);
|
||||||
|
|
||||||
|
entry = entry->nextEntry;
|
||||||
|
|
||||||
|
if (previous != nullptr)
|
||||||
|
previous->nextEntry = entry;
|
||||||
|
else
|
||||||
|
hashSlots.set (i, entry);
|
||||||
|
|
||||||
|
--totalNumItems;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
previous = entry;
|
||||||
|
entry = entry->nextEntry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Remaps the hash-map to use a different number of slots for its hash function.
|
||||||
|
Each slot corresponds to a single hash-code, and each one can contain multiple items.
|
||||||
|
@see getNumSlots()
|
||||||
|
*/
|
||||||
|
void remapTable (int newNumberOfSlots)
|
||||||
|
{
|
||||||
|
HashMap newTable (newNumberOfSlots);
|
||||||
|
|
||||||
|
for (int i = getNumSlots(); --i >= 0;)
|
||||||
|
for (const HashEntry* entry = hashSlots.getUnchecked(i); entry != nullptr; entry = entry->nextEntry)
|
||||||
|
newTable.set (entry->key, entry->value);
|
||||||
|
|
||||||
|
swapWith (newTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the number of slots which are available for hashing.
|
||||||
|
Each slot corresponds to a single hash-code, and each one can contain multiple items.
|
||||||
|
@see getNumSlots()
|
||||||
|
*/
|
||||||
|
inline int getNumSlots() const noexcept
|
||||||
|
{
|
||||||
|
return hashSlots.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Efficiently swaps the contents of two hash-maps. */
|
||||||
|
template <class OtherHashMapType>
|
||||||
|
void swapWith (OtherHashMapType& otherHashMap) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock1 (getLock());
|
||||||
|
const typename OtherHashMapType::ScopedLockType lock2 (otherHashMap.getLock());
|
||||||
|
|
||||||
|
hashSlots.swapWith (otherHashMap.hashSlots);
|
||||||
|
std::swap (totalNumItems, otherHashMap.totalNumItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the CriticalSection that locks this structure.
|
||||||
|
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
|
||||||
|
an object of ScopedLockType as an RAII lock for it.
|
||||||
|
*/
|
||||||
|
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return lock; }
|
||||||
|
|
||||||
|
/** Returns the type of scoped lock to use for locking this array */
|
||||||
|
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
class HashEntry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HashEntry (KeyTypeParameter k, ValueTypeParameter val, HashEntry* const next)
|
||||||
|
: key (k), value (val), nextEntry (next)
|
||||||
|
{}
|
||||||
|
|
||||||
|
const KeyType key;
|
||||||
|
ValueType value;
|
||||||
|
HashEntry* nextEntry;
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (HashEntry)
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Iterates over the items in a HashMap.
|
||||||
|
|
||||||
|
To use it, repeatedly call next() until it returns false, e.g.
|
||||||
|
@code
|
||||||
|
HashMap <String, String> myMap;
|
||||||
|
|
||||||
|
HashMap<String, String>::Iterator i (myMap);
|
||||||
|
|
||||||
|
while (i.next())
|
||||||
|
{
|
||||||
|
DBG (i.getKey() << " -> " << i.getValue());
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
The order in which items are iterated bears no resemblence to the order in which
|
||||||
|
they were originally added!
|
||||||
|
|
||||||
|
Obviously as soon as you call any non-const methods on the original hash-map, any
|
||||||
|
iterators that were created beforehand will cease to be valid, and should not be used.
|
||||||
|
|
||||||
|
@see HashMap
|
||||||
|
*/
|
||||||
|
class Iterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
Iterator (const HashMap& hashMapToIterate)
|
||||||
|
: hashMap (hashMapToIterate), entry (nullptr), index (0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/** Moves to the next item, if one is available.
|
||||||
|
When this returns true, you can get the item's key and value using getKey() and
|
||||||
|
getValue(). If it returns false, the iteration has finished and you should stop.
|
||||||
|
*/
|
||||||
|
bool next()
|
||||||
|
{
|
||||||
|
if (entry != nullptr)
|
||||||
|
entry = entry->nextEntry;
|
||||||
|
|
||||||
|
while (entry == nullptr)
|
||||||
|
{
|
||||||
|
if (index >= hashMap.getNumSlots())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
entry = hashMap.hashSlots.getUnchecked (index++);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the current item's key.
|
||||||
|
This should only be called when a call to next() has just returned true.
|
||||||
|
*/
|
||||||
|
KeyType getKey() const
|
||||||
|
{
|
||||||
|
return entry != nullptr ? entry->key : KeyType();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the current item's value.
|
||||||
|
This should only be called when a call to next() has just returned true.
|
||||||
|
*/
|
||||||
|
ValueType getValue() const
|
||||||
|
{
|
||||||
|
return entry != nullptr ? entry->value : ValueType();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
const HashMap& hashMap;
|
||||||
|
HashEntry* entry;
|
||||||
|
int index;
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Iterator)
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
enum { defaultHashTableSize = 101 };
|
||||||
|
friend class Iterator;
|
||||||
|
|
||||||
|
HashFunctionType hashFunctionToUse;
|
||||||
|
Array<HashEntry*> hashSlots;
|
||||||
|
int totalNumItems;
|
||||||
|
TypeOfCriticalSectionToUse lock;
|
||||||
|
|
||||||
|
int generateHashFor (KeyTypeParameter key) const
|
||||||
|
{
|
||||||
|
const int hash = hashFunctionToUse.generateHash (key, getNumSlots());
|
||||||
|
jassert (isPositiveAndBelow (hash, getNumSlots())); // your hash function is generating out-of-range numbers!
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HashMap)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_HASHMAP_H_INCLUDED
|
||||||
@@ -0,0 +1,371 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_LINKEDLISTPOINTER_H_INCLUDED
|
||||||
|
#define JUCE_LINKEDLISTPOINTER_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Helps to manipulate singly-linked lists of objects.
|
||||||
|
|
||||||
|
For objects that are designed to contain a pointer to the subsequent item in the
|
||||||
|
list, this class contains methods to deal with the list. To use it, the ObjectType
|
||||||
|
class that it points to must contain a LinkedListPointer called nextListItem, e.g.
|
||||||
|
|
||||||
|
@code
|
||||||
|
struct MyObject
|
||||||
|
{
|
||||||
|
int x, y, z;
|
||||||
|
|
||||||
|
// A linkable object must contain a member with this name and type, which must be
|
||||||
|
// accessible by the LinkedListPointer class. (This doesn't mean it has to be public -
|
||||||
|
// you could make your class a friend of a LinkedListPointer<MyObject> instead).
|
||||||
|
LinkedListPointer<MyObject> nextListItem;
|
||||||
|
};
|
||||||
|
|
||||||
|
LinkedListPointer<MyObject> myList;
|
||||||
|
myList.append (new MyObject());
|
||||||
|
myList.append (new MyObject());
|
||||||
|
|
||||||
|
int numItems = myList.size(); // returns 2
|
||||||
|
MyObject* lastInList = myList.getLast();
|
||||||
|
@endcode
|
||||||
|
*/
|
||||||
|
template <class ObjectType>
|
||||||
|
class LinkedListPointer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a null pointer to an empty list. */
|
||||||
|
LinkedListPointer() noexcept
|
||||||
|
: item (nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a pointer to a list whose head is the item provided. */
|
||||||
|
explicit LinkedListPointer (ObjectType* const headItem) noexcept
|
||||||
|
: item (headItem)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets this pointer to point to a new list. */
|
||||||
|
LinkedListPointer& operator= (ObjectType* const newItem) noexcept
|
||||||
|
{
|
||||||
|
item = newItem;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
LinkedListPointer (LinkedListPointer&& other) noexcept
|
||||||
|
: item (other.item)
|
||||||
|
{
|
||||||
|
other.item = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkedListPointer& operator= (LinkedListPointer&& other) noexcept
|
||||||
|
{
|
||||||
|
jassert (this != &other); // hopefully the compiler should make this situation impossible!
|
||||||
|
|
||||||
|
item = other.item;
|
||||||
|
other.item = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the item which this pointer points to. */
|
||||||
|
inline operator ObjectType*() const noexcept
|
||||||
|
{
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the item which this pointer points to. */
|
||||||
|
inline ObjectType* get() const noexcept
|
||||||
|
{
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the last item in the list which this pointer points to.
|
||||||
|
This will iterate the list and return the last item found. Obviously the speed
|
||||||
|
of this operation will be proportional to the size of the list. If the list is
|
||||||
|
empty the return value will be this object.
|
||||||
|
If you're planning on appending a number of items to your list, it's much more
|
||||||
|
efficient to use the Appender class than to repeatedly call getLast() to find the end.
|
||||||
|
*/
|
||||||
|
LinkedListPointer& getLast() noexcept
|
||||||
|
{
|
||||||
|
LinkedListPointer* l = this;
|
||||||
|
|
||||||
|
while (l->item != nullptr)
|
||||||
|
l = &(l->item->nextListItem);
|
||||||
|
|
||||||
|
return *l;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the number of items in the list.
|
||||||
|
Obviously with a simple linked list, getting the size involves iterating the list, so
|
||||||
|
this can be a lengthy operation - be careful when using this method in your code.
|
||||||
|
*/
|
||||||
|
int size() const noexcept
|
||||||
|
{
|
||||||
|
int total = 0;
|
||||||
|
|
||||||
|
for (ObjectType* i = item; i != nullptr; i = i->nextListItem)
|
||||||
|
++total;
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the item at a given index in the list.
|
||||||
|
Since the only way to find an item is to iterate the list, this operation can obviously
|
||||||
|
be slow, depending on its size, so you should be careful when using this in algorithms.
|
||||||
|
*/
|
||||||
|
LinkedListPointer& operator[] (int index) noexcept
|
||||||
|
{
|
||||||
|
LinkedListPointer* l = this;
|
||||||
|
|
||||||
|
while (--index >= 0 && l->item != nullptr)
|
||||||
|
l = &(l->item->nextListItem);
|
||||||
|
|
||||||
|
return *l;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the item at a given index in the list.
|
||||||
|
Since the only way to find an item is to iterate the list, this operation can obviously
|
||||||
|
be slow, depending on its size, so you should be careful when using this in algorithms.
|
||||||
|
*/
|
||||||
|
const LinkedListPointer& operator[] (int index) const noexcept
|
||||||
|
{
|
||||||
|
const LinkedListPointer* l = this;
|
||||||
|
|
||||||
|
while (--index >= 0 && l->item != nullptr)
|
||||||
|
l = &(l->item->nextListItem);
|
||||||
|
|
||||||
|
return *l;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the list contains the given item. */
|
||||||
|
bool contains (const ObjectType* const itemToLookFor) const noexcept
|
||||||
|
{
|
||||||
|
for (ObjectType* i = item; i != nullptr; i = i->nextListItem)
|
||||||
|
if (itemToLookFor == i)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Inserts an item into the list, placing it before the item that this pointer
|
||||||
|
currently points to.
|
||||||
|
*/
|
||||||
|
void insertNext (ObjectType* const newItem)
|
||||||
|
{
|
||||||
|
jassert (newItem != nullptr);
|
||||||
|
jassert (newItem->nextListItem == nullptr);
|
||||||
|
newItem->nextListItem = item;
|
||||||
|
item = newItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Inserts an item at a numeric index in the list.
|
||||||
|
Obviously this will involve iterating the list to find the item at the given index,
|
||||||
|
so be careful about the impact this may have on execution time.
|
||||||
|
*/
|
||||||
|
void insertAtIndex (int index, ObjectType* newItem)
|
||||||
|
{
|
||||||
|
jassert (newItem != nullptr);
|
||||||
|
LinkedListPointer* l = this;
|
||||||
|
|
||||||
|
while (index != 0 && l->item != nullptr)
|
||||||
|
{
|
||||||
|
l = &(l->item->nextListItem);
|
||||||
|
--index;
|
||||||
|
}
|
||||||
|
|
||||||
|
l->insertNext (newItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Replaces the object that this pointer points to, appending the rest of the list to
|
||||||
|
the new object, and returning the old one.
|
||||||
|
*/
|
||||||
|
ObjectType* replaceNext (ObjectType* const newItem) noexcept
|
||||||
|
{
|
||||||
|
jassert (newItem != nullptr);
|
||||||
|
jassert (newItem->nextListItem == nullptr);
|
||||||
|
|
||||||
|
ObjectType* const oldItem = item;
|
||||||
|
item = newItem;
|
||||||
|
item->nextListItem = oldItem->nextListItem.item;
|
||||||
|
oldItem->nextListItem.item = nullptr;
|
||||||
|
return oldItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds an item to the end of the list.
|
||||||
|
|
||||||
|
This operation involves iterating the whole list, so can be slow - if you need to
|
||||||
|
append a number of items to your list, it's much more efficient to use the Appender
|
||||||
|
class than to repeatedly call append().
|
||||||
|
*/
|
||||||
|
void append (ObjectType* const newItem)
|
||||||
|
{
|
||||||
|
getLast().item = newItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates copies of all the items in another list and adds them to this one.
|
||||||
|
This will use the ObjectType's copy constructor to try to create copies of each
|
||||||
|
item in the other list, and appends them to this list.
|
||||||
|
*/
|
||||||
|
void addCopyOfList (const LinkedListPointer& other)
|
||||||
|
{
|
||||||
|
LinkedListPointer* insertPoint = this;
|
||||||
|
|
||||||
|
for (ObjectType* i = other.item; i != nullptr; i = i->nextListItem)
|
||||||
|
{
|
||||||
|
insertPoint->insertNext (new ObjectType (*i));
|
||||||
|
insertPoint = &(insertPoint->item->nextListItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes the head item from the list.
|
||||||
|
This won't delete the object that is removed, but returns it, so the caller can
|
||||||
|
delete it if necessary.
|
||||||
|
*/
|
||||||
|
ObjectType* removeNext() noexcept
|
||||||
|
{
|
||||||
|
ObjectType* const oldItem = item;
|
||||||
|
|
||||||
|
if (oldItem != nullptr)
|
||||||
|
{
|
||||||
|
item = oldItem->nextListItem;
|
||||||
|
oldItem->nextListItem.item = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return oldItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes a specific item from the list.
|
||||||
|
Note that this will not delete the item, it simply unlinks it from the list.
|
||||||
|
*/
|
||||||
|
void remove (ObjectType* const itemToRemove)
|
||||||
|
{
|
||||||
|
if (LinkedListPointer* const l = findPointerTo (itemToRemove))
|
||||||
|
l->removeNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Iterates the list, calling the delete operator on all of its elements and
|
||||||
|
leaving this pointer empty.
|
||||||
|
*/
|
||||||
|
void deleteAll()
|
||||||
|
{
|
||||||
|
while (item != nullptr)
|
||||||
|
{
|
||||||
|
ObjectType* const oldItem = item;
|
||||||
|
item = oldItem->nextListItem;
|
||||||
|
delete oldItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Finds a pointer to a given item.
|
||||||
|
If the item is found in the list, this returns the pointer that points to it. If
|
||||||
|
the item isn't found, this returns null.
|
||||||
|
*/
|
||||||
|
LinkedListPointer* findPointerTo (ObjectType* const itemToLookFor) noexcept
|
||||||
|
{
|
||||||
|
LinkedListPointer* l = this;
|
||||||
|
|
||||||
|
while (l->item != nullptr)
|
||||||
|
{
|
||||||
|
if (l->item == itemToLookFor)
|
||||||
|
return l;
|
||||||
|
|
||||||
|
l = &(l->item->nextListItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copies the items in the list to an array.
|
||||||
|
The destArray must contain enough elements to hold the entire list - no checks are
|
||||||
|
made for this!
|
||||||
|
*/
|
||||||
|
void copyToArray (ObjectType** destArray) const noexcept
|
||||||
|
{
|
||||||
|
jassert (destArray != nullptr);
|
||||||
|
|
||||||
|
for (ObjectType* i = item; i != nullptr; i = i->nextListItem)
|
||||||
|
*destArray++ = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Swaps this pointer with another one */
|
||||||
|
void swapWith (LinkedListPointer& other) noexcept
|
||||||
|
{
|
||||||
|
std::swap (item, other.item);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Allows efficient repeated insertions into a list.
|
||||||
|
|
||||||
|
You can create an Appender object which points to the last element in your
|
||||||
|
list, and then repeatedly call Appender::append() to add items to the end
|
||||||
|
of the list in O(1) time.
|
||||||
|
*/
|
||||||
|
class Appender
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Creates an appender which will add items to the given list.
|
||||||
|
*/
|
||||||
|
Appender (LinkedListPointer& endOfListPointer) noexcept
|
||||||
|
: endOfList (&endOfListPointer)
|
||||||
|
{
|
||||||
|
// This can only be used to add to the end of a list.
|
||||||
|
jassert (endOfListPointer.item == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Appends an item to the list. */
|
||||||
|
void append (ObjectType* const newItem) noexcept
|
||||||
|
{
|
||||||
|
*endOfList = newItem;
|
||||||
|
endOfList = &(newItem->nextListItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
LinkedListPointer* endOfList;
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (Appender)
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
ObjectType* item;
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (LinkedListPointer)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_LINKEDLISTPOINTER_H_INCLUDED
|
||||||
@@ -0,0 +1,270 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
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) {}
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
NamedValue (NamedValue&& other) noexcept
|
||||||
|
: name (static_cast<Identifier&&> (other.name)),
|
||||||
|
value (static_cast<var&&> (other.value))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NamedValue (Identifier n, var&& v) : name (n), value (static_cast<var&&> (v))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NamedValue& operator= (NamedValue&& other) noexcept
|
||||||
|
{
|
||||||
|
name = static_cast<Identifier&&> (other.name);
|
||||||
|
value = static_cast<var&&> (other.value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool operator== (const NamedValue& other) const noexcept { return name == other.name && value == other.value; }
|
||||||
|
bool operator!= (const NamedValue& other) const noexcept { return ! operator== (other); }
|
||||||
|
|
||||||
|
Identifier name;
|
||||||
|
var value;
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
NamedValueSet::NamedValueSet() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NamedValueSet::NamedValueSet (const NamedValueSet& other)
|
||||||
|
: values (other.values)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NamedValueSet& NamedValueSet::operator= (const NamedValueSet& other)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
values = other.values;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
NamedValueSet::NamedValueSet (NamedValueSet&& other) noexcept
|
||||||
|
: values (static_cast <Array<NamedValue>&&> (other.values))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
NamedValueSet& NamedValueSet::operator= (NamedValueSet&& other) noexcept
|
||||||
|
{
|
||||||
|
other.values.swapWith (values);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NamedValueSet::~NamedValueSet() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void NamedValueSet::clear()
|
||||||
|
{
|
||||||
|
values.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NamedValueSet::operator== (const NamedValueSet& other) const
|
||||||
|
{
|
||||||
|
return values == other.values;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NamedValueSet::operator!= (const NamedValueSet& other) const
|
||||||
|
{
|
||||||
|
return ! operator== (other);
|
||||||
|
}
|
||||||
|
|
||||||
|
int NamedValueSet::size() const noexcept
|
||||||
|
{
|
||||||
|
return values.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
const var& NamedValueSet::operator[] (const Identifier& name) const noexcept
|
||||||
|
{
|
||||||
|
if (const var* v = getVarPointer (name))
|
||||||
|
return *v;
|
||||||
|
|
||||||
|
return var::null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var NamedValueSet::getWithDefault (const Identifier& name, const var& defaultReturnValue) const
|
||||||
|
{
|
||||||
|
if (const var* const v = getVarPointer (name))
|
||||||
|
return *v;
|
||||||
|
|
||||||
|
return defaultReturnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var* NamedValueSet::getVarPointer (const Identifier& name) const noexcept
|
||||||
|
{
|
||||||
|
for (NamedValue* e = values.end(), *i = values.begin(); i != e; ++i)
|
||||||
|
if (i->name == name)
|
||||||
|
return &(i->value);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
bool NamedValueSet::set (Identifier name, var&& newValue)
|
||||||
|
{
|
||||||
|
if (var* const v = getVarPointer (name))
|
||||||
|
{
|
||||||
|
if (v->equalsWithSameType (newValue))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*v = static_cast<var&&> (newValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
values.add (NamedValue (name, static_cast<var&&> (newValue)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool NamedValueSet::set (Identifier name, const var& newValue)
|
||||||
|
{
|
||||||
|
if (var* const v = getVarPointer (name))
|
||||||
|
{
|
||||||
|
if (v->equalsWithSameType (newValue))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
*v = newValue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
values.add (NamedValue (name, newValue));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NamedValueSet::contains (const Identifier& name) const noexcept
|
||||||
|
{
|
||||||
|
return getVarPointer (name) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int NamedValueSet::indexOf (const Identifier& name) const noexcept
|
||||||
|
{
|
||||||
|
const int numValues = values.size();
|
||||||
|
|
||||||
|
for (int i = 0; i < numValues; ++i)
|
||||||
|
if (values.getReference(i).name == name)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NamedValueSet::remove (const Identifier& name)
|
||||||
|
{
|
||||||
|
const int numValues = values.size();
|
||||||
|
|
||||||
|
for (int i = 0; i < numValues; ++i)
|
||||||
|
{
|
||||||
|
if (values.getReference(i).name == name)
|
||||||
|
{
|
||||||
|
values.remove (i);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Identifier NamedValueSet::getName (const int index) const noexcept
|
||||||
|
{
|
||||||
|
if (isPositiveAndBelow (index, values.size()))
|
||||||
|
return values.getReference (index).name;
|
||||||
|
|
||||||
|
jassertfalse;
|
||||||
|
return Identifier();
|
||||||
|
}
|
||||||
|
|
||||||
|
const var& NamedValueSet::getValueAt (const int index) const noexcept
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
values.clearQuick();
|
||||||
|
|
||||||
|
for (const XmlElement::XmlAttributeNode* att = xml.attributes; att != nullptr; att = att->nextListItem)
|
||||||
|
{
|
||||||
|
if (att->name.toString().startsWith ("base64:"))
|
||||||
|
{
|
||||||
|
MemoryBlock mb;
|
||||||
|
|
||||||
|
if (mb.fromBase64Encoding (att->value))
|
||||||
|
{
|
||||||
|
values.add (NamedValue (att->name.toString().substring (7), var (mb)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
values.add (NamedValue (att->name, var (att->value)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NamedValueSet::copyToXmlAttributes (XmlElement& xml) const
|
||||||
|
{
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// These types can't be stored as XML!
|
||||||
|
jassert (! i->value.isObject());
|
||||||
|
jassert (! i->value.isMethod());
|
||||||
|
jassert (! i->value.isArray());
|
||||||
|
|
||||||
|
xml.setAttribute (i->name.toString(),
|
||||||
|
i->value.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_NAMEDVALUESET_H_INCLUDED
|
||||||
|
#define JUCE_NAMEDVALUESET_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Holds a set of named var objects.
|
||||||
|
|
||||||
|
This can be used as a basic structure to hold a set of var object, which can
|
||||||
|
be retrieved by using their identifier.
|
||||||
|
*/
|
||||||
|
class JUCE_API NamedValueSet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Creates an empty set. */
|
||||||
|
NamedValueSet() noexcept;
|
||||||
|
|
||||||
|
/** Creates a copy of another set. */
|
||||||
|
NamedValueSet (const NamedValueSet&);
|
||||||
|
|
||||||
|
/** Replaces this set with a copy of another set. */
|
||||||
|
NamedValueSet& operator= (const NamedValueSet&);
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
NamedValueSet (NamedValueSet&&) noexcept;
|
||||||
|
NamedValueSet& operator= (NamedValueSet&&) noexcept;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~NamedValueSet() noexcept;
|
||||||
|
|
||||||
|
bool operator== (const NamedValueSet&) const;
|
||||||
|
bool operator!= (const NamedValueSet&) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the total number of values that the set contains. */
|
||||||
|
int size() const noexcept;
|
||||||
|
|
||||||
|
/** Returns the value of a named item.
|
||||||
|
If the name isn't found, this will return a void variant.
|
||||||
|
@see getProperty
|
||||||
|
*/
|
||||||
|
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 (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
|
||||||
|
value was already set the value passed-in.
|
||||||
|
*/
|
||||||
|
bool set (Identifier name, const var& newValue);
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
/** Changes or adds a named value.
|
||||||
|
@returns true if a value was changed or added; false if the
|
||||||
|
value was already set the value passed-in.
|
||||||
|
*/
|
||||||
|
bool set (Identifier name, var&& newValue);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Returns true if the set contains an item with the specified name. */
|
||||||
|
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 (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 noexcept;
|
||||||
|
|
||||||
|
/** 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 (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. */
|
||||||
|
void setFromXmlAttributes (const XmlElement& xml);
|
||||||
|
|
||||||
|
/** Sets attributes in an XML element corresponding to each of this object's
|
||||||
|
properties.
|
||||||
|
*/
|
||||||
|
void copyToXmlAttributes (XmlElement& xml) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
struct NamedValue;
|
||||||
|
Array<NamedValue> values;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_NAMEDVALUESET_H_INCLUDED
|
||||||
@@ -0,0 +1,897 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_OWNEDARRAY_H_INCLUDED
|
||||||
|
#define JUCE_OWNEDARRAY_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** An array designed for holding objects.
|
||||||
|
|
||||||
|
This holds a list of pointers to objects, and will automatically
|
||||||
|
delete the objects when they are removed from the array, or when the
|
||||||
|
array is itself deleted.
|
||||||
|
|
||||||
|
Declare it in the form: OwnedArray<MyObjectClass>
|
||||||
|
|
||||||
|
..and then add new objects, e.g. myOwnedArray.add (new MyObjectClass());
|
||||||
|
|
||||||
|
After adding objects, they are 'owned' by the array and will be deleted when
|
||||||
|
removed or replaced.
|
||||||
|
|
||||||
|
To make all the array's methods thread-safe, pass in "CriticalSection" as the templated
|
||||||
|
TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
|
||||||
|
|
||||||
|
@see Array, ReferenceCountedArray, StringArray, CriticalSection
|
||||||
|
*/
|
||||||
|
template <class ObjectClass,
|
||||||
|
class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
||||||
|
|
||||||
|
class OwnedArray
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an empty array. */
|
||||||
|
OwnedArray() noexcept
|
||||||
|
: numUsed (0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Deletes the array and also deletes any objects inside it.
|
||||||
|
|
||||||
|
To get rid of the array without deleting its objects, use its
|
||||||
|
clear (false) method before deleting it.
|
||||||
|
*/
|
||||||
|
~OwnedArray()
|
||||||
|
{
|
||||||
|
deleteAllObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
OwnedArray (OwnedArray&& other) noexcept
|
||||||
|
: data (static_cast <ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse>&&> (other.data)),
|
||||||
|
numUsed (other.numUsed)
|
||||||
|
{
|
||||||
|
other.numUsed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OwnedArray& operator= (OwnedArray&& other) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
deleteAllObjects();
|
||||||
|
|
||||||
|
data = static_cast <ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse>&&> (other.data);
|
||||||
|
numUsed = other.numUsed;
|
||||||
|
other.numUsed = 0;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Clears the array, optionally deleting the objects inside it first. */
|
||||||
|
void clear (bool deleteObjects = true)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (deleteObjects)
|
||||||
|
deleteAllObjects();
|
||||||
|
|
||||||
|
data.setAllocatedSize (0);
|
||||||
|
numUsed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Clears the array, optionally deleting the objects inside it first. */
|
||||||
|
void clearQuick (bool deleteObjects)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (deleteObjects)
|
||||||
|
deleteAllObjects();
|
||||||
|
|
||||||
|
numUsed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the number of items currently in the array.
|
||||||
|
@see operator[]
|
||||||
|
*/
|
||||||
|
inline int size() const noexcept
|
||||||
|
{
|
||||||
|
return numUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the object at this index in the array.
|
||||||
|
|
||||||
|
If the index is out-of-range, this will return a null pointer, (and
|
||||||
|
it could be null anyway, because it's ok for the array to hold null
|
||||||
|
pointers as well as objects).
|
||||||
|
|
||||||
|
@see getUnchecked
|
||||||
|
*/
|
||||||
|
inline ObjectClass* operator[] (const int index) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
if (isPositiveAndBelow (index, numUsed))
|
||||||
|
{
|
||||||
|
jassert (data.elements != nullptr);
|
||||||
|
return data.elements [index];
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the object at this index in the array, without checking whether the index is in-range.
|
||||||
|
|
||||||
|
This is a faster and less safe version of operator[] which doesn't check the index passed in, so
|
||||||
|
it can be used when you're sure the index is always going to be legal.
|
||||||
|
*/
|
||||||
|
inline ObjectClass* getUnchecked (const int index) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
jassert (isPositiveAndBelow (index, numUsed) && data.elements != nullptr);
|
||||||
|
return data.elements [index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the first object in the array.
|
||||||
|
|
||||||
|
This will return a null pointer if the array's empty.
|
||||||
|
@see getLast
|
||||||
|
*/
|
||||||
|
inline ObjectClass* getFirst() const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (numUsed > 0)
|
||||||
|
{
|
||||||
|
jassert (data.elements != nullptr);
|
||||||
|
return data.elements [0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the last object in the array.
|
||||||
|
|
||||||
|
This will return a null pointer if the array's empty.
|
||||||
|
@see getFirst
|
||||||
|
*/
|
||||||
|
inline ObjectClass* getLast() const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (numUsed > 0)
|
||||||
|
{
|
||||||
|
jassert (data.elements != nullptr);
|
||||||
|
return data.elements [numUsed - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the actual array data.
|
||||||
|
This pointer will only be valid until the next time a non-const method
|
||||||
|
is called on the array.
|
||||||
|
*/
|
||||||
|
inline ObjectClass** getRawDataPointer() noexcept
|
||||||
|
{
|
||||||
|
return data.elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a pointer to the first element in the array.
|
||||||
|
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||||
|
*/
|
||||||
|
inline ObjectClass** begin() const noexcept
|
||||||
|
{
|
||||||
|
return data.elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the element which follows the last element in the array.
|
||||||
|
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||||
|
*/
|
||||||
|
inline ObjectClass** end() const noexcept
|
||||||
|
{
|
||||||
|
#if JUCE_DEBUG
|
||||||
|
if (data.elements == nullptr || numUsed <= 0) // (to keep static analysers happy)
|
||||||
|
return data.elements;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return data.elements + numUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Finds the index of an object which might be in the array.
|
||||||
|
|
||||||
|
@param objectToLookFor the object to look for
|
||||||
|
@returns the index at which the object was found, or -1 if it's not found
|
||||||
|
*/
|
||||||
|
int indexOf (const ObjectClass* objectToLookFor) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
ObjectClass* const* e = data.elements.getData();
|
||||||
|
ObjectClass* const* const end_ = e + numUsed;
|
||||||
|
|
||||||
|
for (; e != end_; ++e)
|
||||||
|
if (objectToLookFor == *e)
|
||||||
|
return static_cast <int> (e - data.elements.getData());
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the array contains a specified object.
|
||||||
|
|
||||||
|
@param objectToLookFor the object to look for
|
||||||
|
@returns true if the object is in the array
|
||||||
|
*/
|
||||||
|
bool contains (const ObjectClass* objectToLookFor) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
ObjectClass* const* e = data.elements.getData();
|
||||||
|
ObjectClass* const* const end_ = e + numUsed;
|
||||||
|
|
||||||
|
for (; e != end_; ++e)
|
||||||
|
if (objectToLookFor == *e)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Appends a new object to the end of the array.
|
||||||
|
|
||||||
|
Note that the this object will be deleted by the OwnedArray when it
|
||||||
|
is removed, so be careful not to delete it somewhere else.
|
||||||
|
|
||||||
|
Also be careful not to add the same object to the array more than once,
|
||||||
|
as this will obviously cause deletion of dangling pointers.
|
||||||
|
|
||||||
|
@param newObject the new object to add to the array
|
||||||
|
@returns the new object that was added
|
||||||
|
@see set, insert, addIfNotAlreadyThere, addSorted
|
||||||
|
*/
|
||||||
|
ObjectClass* add (ObjectClass* newObject) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
data.ensureAllocatedSize (numUsed + 1);
|
||||||
|
jassert (data.elements != nullptr);
|
||||||
|
data.elements [numUsed++] = newObject;
|
||||||
|
return newObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Inserts a new object into the array at the given index.
|
||||||
|
|
||||||
|
Note that the this object will be deleted by the OwnedArray when it
|
||||||
|
is removed, so be careful not to delete it somewhere else.
|
||||||
|
|
||||||
|
If the index is less than 0 or greater than the size of the array, the
|
||||||
|
element will be added to the end of the array.
|
||||||
|
Otherwise, it will be inserted into the array, moving all the later elements
|
||||||
|
along to make room.
|
||||||
|
|
||||||
|
Be careful not to add the same object to the array more than once,
|
||||||
|
as this will obviously cause deletion of dangling pointers.
|
||||||
|
|
||||||
|
@param indexToInsertAt the index at which the new element should be inserted
|
||||||
|
@param newObject the new object to add to the array
|
||||||
|
@returns the new object that was added
|
||||||
|
@see add, addSorted, addIfNotAlreadyThere, set
|
||||||
|
*/
|
||||||
|
ObjectClass* insert (int indexToInsertAt, ObjectClass* newObject) noexcept
|
||||||
|
{
|
||||||
|
if (indexToInsertAt < 0)
|
||||||
|
return add (newObject);
|
||||||
|
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (indexToInsertAt > numUsed)
|
||||||
|
indexToInsertAt = numUsed;
|
||||||
|
|
||||||
|
data.ensureAllocatedSize (numUsed + 1);
|
||||||
|
jassert (data.elements != nullptr);
|
||||||
|
|
||||||
|
ObjectClass** const e = data.elements + indexToInsertAt;
|
||||||
|
const int numToMove = numUsed - indexToInsertAt;
|
||||||
|
|
||||||
|
if (numToMove > 0)
|
||||||
|
memmove (e + 1, e, sizeof (ObjectClass*) * (size_t) numToMove);
|
||||||
|
|
||||||
|
*e = newObject;
|
||||||
|
++numUsed;
|
||||||
|
return newObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Inserts an array of values into this array at a given position.
|
||||||
|
|
||||||
|
If the index is less than 0 or greater than the size of the array, the
|
||||||
|
new elements will be added to the end of the array.
|
||||||
|
Otherwise, they will be inserted into the array, moving all the later elements
|
||||||
|
along to make room.
|
||||||
|
|
||||||
|
@param indexToInsertAt the index at which the first new element should be inserted
|
||||||
|
@param newObjects the new values to add to the array
|
||||||
|
@param numberOfElements how many items are in the array
|
||||||
|
@see insert, add, addSorted, set
|
||||||
|
*/
|
||||||
|
void insertArray (int indexToInsertAt,
|
||||||
|
ObjectClass* const* newObjects,
|
||||||
|
int numberOfElements)
|
||||||
|
{
|
||||||
|
if (numberOfElements > 0)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
data.ensureAllocatedSize (numUsed + numberOfElements);
|
||||||
|
ObjectClass** insertPos = data.elements;
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (indexToInsertAt, numUsed))
|
||||||
|
{
|
||||||
|
insertPos += indexToInsertAt;
|
||||||
|
const size_t numberToMove = (size_t) (numUsed - indexToInsertAt);
|
||||||
|
memmove (insertPos + numberOfElements, insertPos, numberToMove * sizeof (ObjectClass*));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
insertPos += numUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
numUsed += numberOfElements;
|
||||||
|
|
||||||
|
while (--numberOfElements >= 0)
|
||||||
|
*insertPos++ = *newObjects++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Appends a new object at the end of the array as long as the array doesn't
|
||||||
|
already contain it.
|
||||||
|
|
||||||
|
If the array already contains a matching object, nothing will be done.
|
||||||
|
|
||||||
|
@param newObject the new object to add to the array
|
||||||
|
@returns the new object that was added
|
||||||
|
*/
|
||||||
|
ObjectClass* addIfNotAlreadyThere (ObjectClass* newObject) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (! contains (newObject))
|
||||||
|
add (newObject);
|
||||||
|
|
||||||
|
return newObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Replaces an object in the array with a different one.
|
||||||
|
|
||||||
|
If the index is less than zero, this method does nothing.
|
||||||
|
If the index is beyond the end of the array, the new object is added to the end of the array.
|
||||||
|
|
||||||
|
Be careful not to add the same object to the array more than once,
|
||||||
|
as this will obviously cause deletion of dangling pointers.
|
||||||
|
|
||||||
|
@param indexToChange the index whose value you want to change
|
||||||
|
@param newObject the new value to set for this index.
|
||||||
|
@param deleteOldElement whether to delete the object that's being replaced with the new one
|
||||||
|
@see add, insert, remove
|
||||||
|
*/
|
||||||
|
ObjectClass* set (int indexToChange, ObjectClass* newObject, bool deleteOldElement = true)
|
||||||
|
{
|
||||||
|
if (indexToChange >= 0)
|
||||||
|
{
|
||||||
|
ScopedPointer<ObjectClass> toDelete;
|
||||||
|
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (indexToChange < numUsed)
|
||||||
|
{
|
||||||
|
if (deleteOldElement)
|
||||||
|
{
|
||||||
|
toDelete = data.elements [indexToChange];
|
||||||
|
|
||||||
|
if (toDelete == newObject)
|
||||||
|
toDelete.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
data.elements [indexToChange] = newObject;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.ensureAllocatedSize (numUsed + 1);
|
||||||
|
data.elements [numUsed++] = newObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jassertfalse; // you're trying to set an object at a negative index, which doesn't have
|
||||||
|
// any effect - but since the object is not being added, it may be leaking..
|
||||||
|
}
|
||||||
|
|
||||||
|
return newObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds elements from another array to the end of this array.
|
||||||
|
|
||||||
|
@param arrayToAddFrom the array from which to copy the elements
|
||||||
|
@param startIndex the first element of the other array to start copying from
|
||||||
|
@param numElementsToAdd how many elements to add from the other array. If this
|
||||||
|
value is negative or greater than the number of available elements,
|
||||||
|
all available elements will be copied.
|
||||||
|
@see add
|
||||||
|
*/
|
||||||
|
template <class OtherArrayType>
|
||||||
|
void addArray (const OtherArrayType& arrayToAddFrom,
|
||||||
|
int startIndex = 0,
|
||||||
|
int numElementsToAdd = -1)
|
||||||
|
{
|
||||||
|
const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock());
|
||||||
|
const ScopedLockType lock2 (getLock());
|
||||||
|
|
||||||
|
if (startIndex < 0)
|
||||||
|
{
|
||||||
|
jassertfalse;
|
||||||
|
startIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
|
||||||
|
numElementsToAdd = arrayToAddFrom.size() - startIndex;
|
||||||
|
|
||||||
|
data.ensureAllocatedSize (numUsed + numElementsToAdd);
|
||||||
|
jassert (numElementsToAdd <= 0 || data.elements != nullptr);
|
||||||
|
|
||||||
|
while (--numElementsToAdd >= 0)
|
||||||
|
{
|
||||||
|
data.elements [numUsed] = arrayToAddFrom.getUnchecked (startIndex++);
|
||||||
|
++numUsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds copies of the elements in another array to the end of this array.
|
||||||
|
|
||||||
|
The other array must be either an OwnedArray of a compatible type of object, or an Array
|
||||||
|
containing pointers to the same kind of object. The objects involved must provide
|
||||||
|
a copy constructor, and this will be used to create new copies of each element, and
|
||||||
|
add them to this array.
|
||||||
|
|
||||||
|
@param arrayToAddFrom the array from which to copy the elements
|
||||||
|
@param startIndex the first element of the other array to start copying from
|
||||||
|
@param numElementsToAdd how many elements to add from the other array. If this
|
||||||
|
value is negative or greater than the number of available elements,
|
||||||
|
all available elements will be copied.
|
||||||
|
@see add
|
||||||
|
*/
|
||||||
|
template <class OtherArrayType>
|
||||||
|
void addCopiesOf (const OtherArrayType& arrayToAddFrom,
|
||||||
|
int startIndex = 0,
|
||||||
|
int numElementsToAdd = -1)
|
||||||
|
{
|
||||||
|
const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock());
|
||||||
|
const ScopedLockType lock2 (getLock());
|
||||||
|
|
||||||
|
if (startIndex < 0)
|
||||||
|
{
|
||||||
|
jassertfalse;
|
||||||
|
startIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
|
||||||
|
numElementsToAdd = arrayToAddFrom.size() - startIndex;
|
||||||
|
|
||||||
|
data.ensureAllocatedSize (numUsed + numElementsToAdd);
|
||||||
|
jassert (numElementsToAdd <= 0 || data.elements != nullptr);
|
||||||
|
|
||||||
|
while (--numElementsToAdd >= 0)
|
||||||
|
data.elements [numUsed++] = createCopyIfNotNull (arrayToAddFrom.getUnchecked (startIndex++));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Inserts a new object into the array assuming that the array is sorted.
|
||||||
|
|
||||||
|
This will use a comparator to find the position at which the new object
|
||||||
|
should go. If the array isn't sorted, the behaviour of this
|
||||||
|
method will be unpredictable.
|
||||||
|
|
||||||
|
@param comparator the comparator to use to compare the elements - see the sort method
|
||||||
|
for details about this object's structure
|
||||||
|
@param newObject the new object to insert to the array
|
||||||
|
@returns the index at which the new object was added
|
||||||
|
@see add, sort, indexOfSorted
|
||||||
|
*/
|
||||||
|
template <class ElementComparator>
|
||||||
|
int addSorted (ElementComparator& comparator, ObjectClass* const newObject) noexcept
|
||||||
|
{
|
||||||
|
(void) comparator; // if you pass in an object with a static compareElements() method, this
|
||||||
|
// avoids getting warning messages about the parameter being unused
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newObject, 0, numUsed);
|
||||||
|
insert (index, newObject);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Finds the index of an object in the array, assuming that the array is sorted.
|
||||||
|
|
||||||
|
This will use a comparator to do a binary-chop to find the index of the given
|
||||||
|
element, if it exists. If the array isn't sorted, the behaviour of this
|
||||||
|
method will be unpredictable.
|
||||||
|
|
||||||
|
@param comparator the comparator to use to compare the elements - see the sort()
|
||||||
|
method for details about the form this object should take
|
||||||
|
@param objectToLookFor the object to search for
|
||||||
|
@returns the index of the element, or -1 if it's not found
|
||||||
|
@see addSorted, sort
|
||||||
|
*/
|
||||||
|
template <typename ElementComparator>
|
||||||
|
int indexOfSorted (ElementComparator& comparator, const ObjectClass* const objectToLookFor) const noexcept
|
||||||
|
{
|
||||||
|
(void) comparator;
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
int s = 0, e = numUsed;
|
||||||
|
|
||||||
|
while (s < e)
|
||||||
|
{
|
||||||
|
if (comparator.compareElements (objectToLookFor, data.elements [s]) == 0)
|
||||||
|
return s;
|
||||||
|
|
||||||
|
const int halfway = (s + e) / 2;
|
||||||
|
if (halfway == s)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (comparator.compareElements (objectToLookFor, data.elements [halfway]) >= 0)
|
||||||
|
s = halfway;
|
||||||
|
else
|
||||||
|
e = halfway;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Removes an object from the array.
|
||||||
|
|
||||||
|
This will remove the object at a given index (optionally also
|
||||||
|
deleting it) and move back all the subsequent objects to close the gap.
|
||||||
|
If the index passed in is out-of-range, nothing will happen.
|
||||||
|
|
||||||
|
@param indexToRemove the index of the element to remove
|
||||||
|
@param deleteObject whether to delete the object that is removed
|
||||||
|
@see removeObject, removeRange
|
||||||
|
*/
|
||||||
|
void remove (int indexToRemove, bool deleteObject = true)
|
||||||
|
{
|
||||||
|
ScopedPointer<ObjectClass> toDelete;
|
||||||
|
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (indexToRemove, numUsed))
|
||||||
|
{
|
||||||
|
ObjectClass** const e = data.elements + indexToRemove;
|
||||||
|
|
||||||
|
if (deleteObject)
|
||||||
|
toDelete = *e;
|
||||||
|
|
||||||
|
--numUsed;
|
||||||
|
const int numToShift = numUsed - indexToRemove;
|
||||||
|
|
||||||
|
if (numToShift > 0)
|
||||||
|
memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numToShift);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((numUsed << 1) < data.numAllocated)
|
||||||
|
minimiseStorageOverheads();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes and returns an object from the array without deleting it.
|
||||||
|
|
||||||
|
This will remove the object at a given index and return it, moving back all
|
||||||
|
the subsequent objects to close the gap. If the index passed in is out-of-range,
|
||||||
|
nothing will happen.
|
||||||
|
|
||||||
|
@param indexToRemove the index of the element to remove
|
||||||
|
@see remove, removeObject, removeRange
|
||||||
|
*/
|
||||||
|
ObjectClass* removeAndReturn (int indexToRemove)
|
||||||
|
{
|
||||||
|
ObjectClass* removedItem = nullptr;
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (indexToRemove, numUsed))
|
||||||
|
{
|
||||||
|
ObjectClass** const e = data.elements + indexToRemove;
|
||||||
|
removedItem = *e;
|
||||||
|
|
||||||
|
--numUsed;
|
||||||
|
const int numToShift = numUsed - indexToRemove;
|
||||||
|
|
||||||
|
if (numToShift > 0)
|
||||||
|
memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numToShift);
|
||||||
|
|
||||||
|
if ((numUsed << 1) < data.numAllocated)
|
||||||
|
minimiseStorageOverheads();
|
||||||
|
}
|
||||||
|
|
||||||
|
return removedItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes a specified object from the array.
|
||||||
|
|
||||||
|
If the item isn't found, no action is taken.
|
||||||
|
|
||||||
|
@param objectToRemove the object to try to remove
|
||||||
|
@param deleteObject whether to delete the object (if it's found)
|
||||||
|
@see remove, removeRange
|
||||||
|
*/
|
||||||
|
void removeObject (const ObjectClass* objectToRemove, bool deleteObject = true)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
ObjectClass** const e = data.elements.getData();
|
||||||
|
|
||||||
|
for (int i = 0; i < numUsed; ++i)
|
||||||
|
{
|
||||||
|
if (objectToRemove == e[i])
|
||||||
|
{
|
||||||
|
remove (i, deleteObject);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes a range of objects from the array.
|
||||||
|
|
||||||
|
This will remove a set of objects, starting from the given index,
|
||||||
|
and move any subsequent elements down to close the gap.
|
||||||
|
|
||||||
|
If the range extends beyond the bounds of the array, it will
|
||||||
|
be safely clipped to the size of the array.
|
||||||
|
|
||||||
|
@param startIndex the index of the first object to remove
|
||||||
|
@param numberToRemove how many objects should be removed
|
||||||
|
@param deleteObjects whether to delete the objects that get removed
|
||||||
|
@see remove, removeObject
|
||||||
|
*/
|
||||||
|
void removeRange (int startIndex, int numberToRemove, bool deleteObjects = true)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
const int endIndex = jlimit (0, numUsed, startIndex + numberToRemove);
|
||||||
|
startIndex = jlimit (0, numUsed, startIndex);
|
||||||
|
|
||||||
|
if (endIndex > startIndex)
|
||||||
|
{
|
||||||
|
if (deleteObjects)
|
||||||
|
{
|
||||||
|
for (int i = startIndex; i < endIndex; ++i)
|
||||||
|
{
|
||||||
|
ContainerDeletePolicy<ObjectClass>::destroy (data.elements [i]);
|
||||||
|
data.elements [i] = nullptr; // (in case one of the destructors accesses this array and hits a dangling pointer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int rangeSize = endIndex - startIndex;
|
||||||
|
ObjectClass** e = data.elements + startIndex;
|
||||||
|
int numToShift = numUsed - endIndex;
|
||||||
|
numUsed -= rangeSize;
|
||||||
|
|
||||||
|
while (--numToShift >= 0)
|
||||||
|
{
|
||||||
|
*e = e [rangeSize];
|
||||||
|
++e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((numUsed << 1) < data.numAllocated)
|
||||||
|
minimiseStorageOverheads();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes the last n objects from the array.
|
||||||
|
|
||||||
|
@param howManyToRemove how many objects to remove from the end of the array
|
||||||
|
@param deleteObjects whether to also delete the objects that are removed
|
||||||
|
@see remove, removeObject, removeRange
|
||||||
|
*/
|
||||||
|
void removeLast (int howManyToRemove = 1,
|
||||||
|
bool deleteObjects = true)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (howManyToRemove >= numUsed)
|
||||||
|
clear (deleteObjects);
|
||||||
|
else
|
||||||
|
removeRange (numUsed - howManyToRemove, howManyToRemove, deleteObjects);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Swaps a pair of objects in the array.
|
||||||
|
|
||||||
|
If either of the indexes passed in is out-of-range, nothing will happen,
|
||||||
|
otherwise the two objects at these positions will be exchanged.
|
||||||
|
*/
|
||||||
|
void swap (int index1,
|
||||||
|
int index2) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (index1, numUsed)
|
||||||
|
&& isPositiveAndBelow (index2, numUsed))
|
||||||
|
{
|
||||||
|
std::swap (data.elements [index1],
|
||||||
|
data.elements [index2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Moves one of the objects to a different position.
|
||||||
|
|
||||||
|
This will move the object to a specified index, shuffling along
|
||||||
|
any intervening elements as required.
|
||||||
|
|
||||||
|
So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling
|
||||||
|
move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
|
||||||
|
|
||||||
|
@param currentIndex the index of the object to be moved. If this isn't a
|
||||||
|
valid index, then nothing will be done
|
||||||
|
@param newIndex the index at which you'd like this object to end up. If this
|
||||||
|
is less than zero, it will be moved to the end of the array
|
||||||
|
*/
|
||||||
|
void move (int currentIndex, int newIndex) noexcept
|
||||||
|
{
|
||||||
|
if (currentIndex != newIndex)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (currentIndex, numUsed))
|
||||||
|
{
|
||||||
|
if (! isPositiveAndBelow (newIndex, numUsed))
|
||||||
|
newIndex = numUsed - 1;
|
||||||
|
|
||||||
|
ObjectClass* const value = data.elements [currentIndex];
|
||||||
|
|
||||||
|
if (newIndex > currentIndex)
|
||||||
|
{
|
||||||
|
memmove (data.elements + currentIndex,
|
||||||
|
data.elements + currentIndex + 1,
|
||||||
|
sizeof (ObjectClass*) * (size_t) (newIndex - currentIndex));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memmove (data.elements + newIndex + 1,
|
||||||
|
data.elements + newIndex,
|
||||||
|
sizeof (ObjectClass*) * (size_t) (currentIndex - newIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
data.elements [newIndex] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This swaps the contents of this array with those of another array.
|
||||||
|
|
||||||
|
If you need to exchange two arrays, this is vastly quicker than using copy-by-value
|
||||||
|
because it just swaps their internal pointers.
|
||||||
|
*/
|
||||||
|
template <class OtherArrayType>
|
||||||
|
void swapWith (OtherArrayType& otherArray) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock1 (getLock());
|
||||||
|
const typename OtherArrayType::ScopedLockType lock2 (otherArray.getLock());
|
||||||
|
data.swapWith (otherArray.data);
|
||||||
|
std::swap (numUsed, otherArray.numUsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Reduces the amount of storage being used by the array.
|
||||||
|
|
||||||
|
Arrays typically allocate slightly more storage than they need, and after
|
||||||
|
removing elements, they may have quite a lot of unused space allocated.
|
||||||
|
This method will reduce the amount of allocated storage to a minimum.
|
||||||
|
*/
|
||||||
|
void minimiseStorageOverheads() noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
data.shrinkToNoMoreThan (numUsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Increases the array's internal storage to hold a minimum number of elements.
|
||||||
|
|
||||||
|
Calling this before adding a large known number of elements means that
|
||||||
|
the array won't have to keep dynamically resizing itself as the elements
|
||||||
|
are added, and it'll therefore be more efficient.
|
||||||
|
*/
|
||||||
|
void ensureStorageAllocated (const int minNumElements) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
data.ensureAllocatedSize (minNumElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Sorts the elements in the array.
|
||||||
|
|
||||||
|
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);
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
..and this method must return:
|
||||||
|
- a value of < 0 if the first comes before the second
|
||||||
|
- a value of 0 if the two objects are equivalent
|
||||||
|
- a value of > 0 if the second comes before the first
|
||||||
|
|
||||||
|
To improve performance, the compareElements() method can be declared as static or const.
|
||||||
|
|
||||||
|
@param comparator the comparator to use for comparing elements.
|
||||||
|
@param retainOrderOfEquivalentItems if this is true, then items
|
||||||
|
which the comparator says are equivalent will be
|
||||||
|
kept in the order in which they currently appear
|
||||||
|
in the array. This is slower to perform, but may
|
||||||
|
be important in some cases. If it's false, a faster
|
||||||
|
algorithm is used, but equivalent elements may be
|
||||||
|
rearranged.
|
||||||
|
@see sortArray, indexOfSorted
|
||||||
|
*/
|
||||||
|
template <class ElementComparator>
|
||||||
|
void sort (ElementComparator& comparator,
|
||||||
|
bool retainOrderOfEquivalentItems = false) const noexcept
|
||||||
|
{
|
||||||
|
(void) comparator; // if you pass in an object with a static compareElements() method, this
|
||||||
|
// avoids getting warning messages about the parameter being unused
|
||||||
|
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
sortArray (comparator, data.elements.getData(), 0, size() - 1, retainOrderOfEquivalentItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the CriticalSection that locks this array.
|
||||||
|
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
|
||||||
|
an object of ScopedLockType as an RAII lock for it.
|
||||||
|
*/
|
||||||
|
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return data; }
|
||||||
|
|
||||||
|
/** Returns the type of scoped lock to use for locking this array */
|
||||||
|
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#ifndef DOXYGEN
|
||||||
|
// Note that the swapWithArray method has been replaced by a more flexible templated version,
|
||||||
|
// and renamed "swapWith" to be more consistent with the names used in other classes.
|
||||||
|
JUCE_DEPRECATED_WITH_BODY (void swapWithArray (OwnedArray& other) noexcept, { swapWith (other); })
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse> data;
|
||||||
|
int numUsed;
|
||||||
|
|
||||||
|
void deleteAllObjects()
|
||||||
|
{
|
||||||
|
while (numUsed > 0)
|
||||||
|
ContainerDeletePolicy<ObjectClass>::destroy (data.elements [--numUsed]);
|
||||||
|
}
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OwnedArray)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_OWNEDARRAY_H_INCLUDED
|
||||||
@@ -0,0 +1,219 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
PropertySet::PropertySet (const bool ignoreCaseOfKeyNames)
|
||||||
|
: properties (ignoreCaseOfKeyNames),
|
||||||
|
fallbackProperties (nullptr),
|
||||||
|
ignoreCaseOfKeys (ignoreCaseOfKeyNames)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertySet::PropertySet (const PropertySet& other)
|
||||||
|
: properties (other.properties),
|
||||||
|
fallbackProperties (other.fallbackProperties),
|
||||||
|
ignoreCaseOfKeys (other.ignoreCaseOfKeys)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertySet& PropertySet::operator= (const PropertySet& other)
|
||||||
|
{
|
||||||
|
properties = other.properties;
|
||||||
|
fallbackProperties = other.fallbackProperties;
|
||||||
|
ignoreCaseOfKeys = other.ignoreCaseOfKeys;
|
||||||
|
|
||||||
|
propertyChanged();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertySet::~PropertySet()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertySet::clear()
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
|
||||||
|
if (properties.size() > 0)
|
||||||
|
{
|
||||||
|
properties.clear();
|
||||||
|
propertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String PropertySet::getValue (StringRef keyName, const String& defaultValue) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
|
||||||
|
const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||||
|
|
||||||
|
if (index >= 0)
|
||||||
|
return properties.getAllValues() [index];
|
||||||
|
|
||||||
|
return fallbackProperties != nullptr ? fallbackProperties->getValue (keyName, defaultValue)
|
||||||
|
: defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PropertySet::getIntValue (StringRef keyName, const int defaultValue) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||||
|
|
||||||
|
if (index >= 0)
|
||||||
|
return properties.getAllValues() [index].getIntValue();
|
||||||
|
|
||||||
|
return fallbackProperties != nullptr ? fallbackProperties->getIntValue (keyName, defaultValue)
|
||||||
|
: defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
double PropertySet::getDoubleValue (StringRef keyName, const double defaultValue) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||||
|
|
||||||
|
if (index >= 0)
|
||||||
|
return properties.getAllValues()[index].getDoubleValue();
|
||||||
|
|
||||||
|
return fallbackProperties != nullptr ? fallbackProperties->getDoubleValue (keyName, defaultValue)
|
||||||
|
: defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PropertySet::getBoolValue (StringRef keyName, const bool defaultValue) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||||
|
|
||||||
|
if (index >= 0)
|
||||||
|
return properties.getAllValues() [index].getIntValue() != 0;
|
||||||
|
|
||||||
|
return fallbackProperties != nullptr ? fallbackProperties->getBoolValue (keyName, defaultValue)
|
||||||
|
: defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlElement* PropertySet::getXmlValue (StringRef keyName) const
|
||||||
|
{
|
||||||
|
return XmlDocument::parse (getValue (keyName));
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertySet::setValue (const String& keyName, const var& v)
|
||||||
|
{
|
||||||
|
jassert (keyName.isNotEmpty()); // shouldn't use an empty key name!
|
||||||
|
|
||||||
|
if (keyName.isNotEmpty())
|
||||||
|
{
|
||||||
|
const String value (v.toString());
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
|
||||||
|
const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||||
|
|
||||||
|
if (index < 0 || properties.getAllValues() [index] != value)
|
||||||
|
{
|
||||||
|
properties.set (keyName, value);
|
||||||
|
propertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertySet::removeValue (StringRef keyName)
|
||||||
|
{
|
||||||
|
if (keyName.isNotEmpty())
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
const int index = properties.getAllKeys().indexOf (keyName, ignoreCaseOfKeys);
|
||||||
|
|
||||||
|
if (index >= 0)
|
||||||
|
{
|
||||||
|
properties.remove (keyName);
|
||||||
|
propertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertySet::setValue (const String& keyName, const XmlElement* const xml)
|
||||||
|
{
|
||||||
|
setValue (keyName, xml == nullptr ? var()
|
||||||
|
: var (xml->createDocument ("", true)));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PropertySet::containsKey (StringRef keyName) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
return properties.getAllKeys().contains (keyName, ignoreCaseOfKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertySet::addAllPropertiesFrom (const PropertySet& source)
|
||||||
|
{
|
||||||
|
const ScopedLock sl (source.getLock());
|
||||||
|
|
||||||
|
for (int i = 0; i < source.properties.size(); ++i)
|
||||||
|
setValue (source.properties.getAllKeys() [i],
|
||||||
|
source.properties.getAllValues() [i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertySet::setFallbackPropertySet (PropertySet* fallbackProperties_) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
fallbackProperties = fallbackProperties_;
|
||||||
|
}
|
||||||
|
|
||||||
|
XmlElement* PropertySet::createXml (const String& nodeName) const
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
XmlElement* const xml = new XmlElement (nodeName);
|
||||||
|
|
||||||
|
for (int i = 0; i < properties.getAllKeys().size(); ++i)
|
||||||
|
{
|
||||||
|
XmlElement* const e = xml->createNewChildElement ("VALUE");
|
||||||
|
e->setAttribute ("name", properties.getAllKeys()[i]);
|
||||||
|
e->setAttribute ("val", properties.getAllValues()[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertySet::restoreFromXml (const XmlElement& xml)
|
||||||
|
{
|
||||||
|
const ScopedLock sl (lock);
|
||||||
|
clear();
|
||||||
|
|
||||||
|
forEachXmlChildElementWithTagName (xml, e, "VALUE")
|
||||||
|
{
|
||||||
|
if (e->hasAttribute ("name")
|
||||||
|
&& e->hasAttribute ("val"))
|
||||||
|
{
|
||||||
|
properties.set (e->getStringAttribute ("name"),
|
||||||
|
e->getStringAttribute ("val"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (properties.size() > 0)
|
||||||
|
propertyChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PropertySet::propertyChanged()
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_PROPERTYSET_H_INCLUDED
|
||||||
|
#define JUCE_PROPERTYSET_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A set of named property values, which can be strings, integers, floating point, etc.
|
||||||
|
|
||||||
|
Effectively, this just wraps a StringPairArray in an interface that makes it easier
|
||||||
|
to load and save types other than strings.
|
||||||
|
|
||||||
|
See the PropertiesFile class for a subclass of this, which automatically broadcasts change
|
||||||
|
messages and saves/loads the list from a file.
|
||||||
|
*/
|
||||||
|
class JUCE_API PropertySet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an empty PropertySet.
|
||||||
|
@param ignoreCaseOfKeyNames if true, the names of properties are compared in a
|
||||||
|
case-insensitive way
|
||||||
|
*/
|
||||||
|
PropertySet (bool ignoreCaseOfKeyNames = false);
|
||||||
|
|
||||||
|
/** Creates a copy of another PropertySet. */
|
||||||
|
PropertySet (const PropertySet& other);
|
||||||
|
|
||||||
|
/** Copies another PropertySet over this one. */
|
||||||
|
PropertySet& operator= (const PropertySet& other);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
virtual ~PropertySet();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns one of the properties as a string.
|
||||||
|
|
||||||
|
If the value isn't found in this set, then this will look for it in a fallback
|
||||||
|
property set (if you've specified one with the setFallbackPropertySet() method),
|
||||||
|
and if it can't find one there, it'll return the default value passed-in.
|
||||||
|
|
||||||
|
@param keyName the name of the property to retrieve
|
||||||
|
@param defaultReturnValue a value to return if the named property doesn't actually exist
|
||||||
|
*/
|
||||||
|
String getValue (StringRef keyName, const String& defaultReturnValue = String()) const noexcept;
|
||||||
|
|
||||||
|
/** Returns one of the properties as an integer.
|
||||||
|
|
||||||
|
If the value isn't found in this set, then this will look for it in a fallback
|
||||||
|
property set (if you've specified one with the setFallbackPropertySet() method),
|
||||||
|
and if it can't find one there, it'll return the default value passed-in.
|
||||||
|
|
||||||
|
@param keyName the name of the property to retrieve
|
||||||
|
@param defaultReturnValue a value to return if the named property doesn't actually exist
|
||||||
|
*/
|
||||||
|
int getIntValue (StringRef keyName, int defaultReturnValue = 0) const noexcept;
|
||||||
|
|
||||||
|
/** Returns one of the properties as an double.
|
||||||
|
|
||||||
|
If the value isn't found in this set, then this will look for it in a fallback
|
||||||
|
property set (if you've specified one with the setFallbackPropertySet() method),
|
||||||
|
and if it can't find one there, it'll return the default value passed-in.
|
||||||
|
|
||||||
|
@param keyName the name of the property to retrieve
|
||||||
|
@param defaultReturnValue a value to return if the named property doesn't actually exist
|
||||||
|
*/
|
||||||
|
double getDoubleValue (StringRef keyName, double defaultReturnValue = 0.0) const noexcept;
|
||||||
|
|
||||||
|
/** Returns one of the properties as an boolean.
|
||||||
|
|
||||||
|
The result will be true if the string found for this key name can be parsed as a non-zero
|
||||||
|
integer.
|
||||||
|
|
||||||
|
If the value isn't found in this set, then this will look for it in a fallback
|
||||||
|
property set (if you've specified one with the setFallbackPropertySet() method),
|
||||||
|
and if it can't find one there, it'll return the default value passed-in.
|
||||||
|
|
||||||
|
@param keyName the name of the property to retrieve
|
||||||
|
@param defaultReturnValue a value to return if the named property doesn't actually exist
|
||||||
|
*/
|
||||||
|
bool getBoolValue (StringRef keyName, bool defaultReturnValue = false) const noexcept;
|
||||||
|
|
||||||
|
/** Returns one of the properties as an XML element.
|
||||||
|
|
||||||
|
The result will a new XMLElement object that the caller must delete. If may return nullptr
|
||||||
|
if the key isn't found, or if the entry contains an string that isn't valid XML.
|
||||||
|
|
||||||
|
If the value isn't found in this set, then this will look for it in a fallback
|
||||||
|
property set (if you've specified one with the setFallbackPropertySet() method),
|
||||||
|
and if it can't find one there, it'll return the default value passed-in.
|
||||||
|
|
||||||
|
@param keyName the name of the property to retrieve
|
||||||
|
*/
|
||||||
|
XmlElement* getXmlValue (StringRef keyName) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Sets a named property.
|
||||||
|
|
||||||
|
@param keyName the name of the property to set. (This mustn't be an empty string)
|
||||||
|
@param value the new value to set it to
|
||||||
|
*/
|
||||||
|
void setValue (const String& keyName, const var& value);
|
||||||
|
|
||||||
|
/** Sets a named property to an XML element.
|
||||||
|
|
||||||
|
@param keyName the name of the property to set. (This mustn't be an empty string)
|
||||||
|
@param xml the new element to set it to. If this is zero, the value will be set to
|
||||||
|
an empty string
|
||||||
|
@see getXmlValue
|
||||||
|
*/
|
||||||
|
void setValue (const String& keyName, const XmlElement* xml);
|
||||||
|
|
||||||
|
/** This copies all the values from a source PropertySet to this one.
|
||||||
|
This won't remove any existing settings, it just adds any that it finds in the source set.
|
||||||
|
*/
|
||||||
|
void addAllPropertiesFrom (const PropertySet& source);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Deletes a property.
|
||||||
|
@param keyName the name of the property to delete. (This mustn't be an empty string)
|
||||||
|
*/
|
||||||
|
void removeValue (StringRef keyName);
|
||||||
|
|
||||||
|
/** Returns true if the properies include the given key. */
|
||||||
|
bool containsKey (StringRef keyName) const noexcept;
|
||||||
|
|
||||||
|
/** Removes all values. */
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the keys/value pair array containing all the properties. */
|
||||||
|
StringPairArray& getAllProperties() noexcept { return properties; }
|
||||||
|
|
||||||
|
/** Returns the lock used when reading or writing to this set */
|
||||||
|
const CriticalSection& getLock() const noexcept { return lock; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns an XML element which encapsulates all the items in this property set.
|
||||||
|
The string parameter is the tag name that should be used for the node.
|
||||||
|
@see restoreFromXml
|
||||||
|
*/
|
||||||
|
XmlElement* createXml (const String& nodeName) const;
|
||||||
|
|
||||||
|
/** Reloads a set of properties that were previously stored as XML.
|
||||||
|
The node passed in must have been created by the createXml() method.
|
||||||
|
@see createXml
|
||||||
|
*/
|
||||||
|
void restoreFromXml (const XmlElement& xml);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Sets up a second PopertySet that will be used to look up any values that aren't
|
||||||
|
set in this one.
|
||||||
|
|
||||||
|
If you set this up to be a pointer to a second property set, then whenever one
|
||||||
|
of the getValue() methods fails to find an entry in this set, it will look up that
|
||||||
|
value in the fallback set, and if it finds it, it will return that.
|
||||||
|
|
||||||
|
Make sure that you don't delete the fallback set while it's still being used by
|
||||||
|
another set! To remove the fallback set, just call this method with a null pointer.
|
||||||
|
|
||||||
|
@see getFallbackPropertySet
|
||||||
|
*/
|
||||||
|
void setFallbackPropertySet (PropertySet* fallbackProperties) noexcept;
|
||||||
|
|
||||||
|
/** Returns the fallback property set.
|
||||||
|
@see setFallbackPropertySet
|
||||||
|
*/
|
||||||
|
PropertySet* getFallbackPropertySet() const noexcept { return fallbackProperties; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** Subclasses can override this to be told when one of the properies has been changed. */
|
||||||
|
virtual void propertyChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
StringPairArray properties;
|
||||||
|
PropertySet* fallbackProperties;
|
||||||
|
CriticalSection lock;
|
||||||
|
bool ignoreCaseOfKeys;
|
||||||
|
|
||||||
|
JUCE_LEAK_DETECTOR (PropertySet)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_PROPERTYSET_H_INCLUDED
|
||||||
@@ -0,0 +1,897 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_REFERENCECOUNTEDARRAY_H_INCLUDED
|
||||||
|
#define JUCE_REFERENCECOUNTEDARRAY_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Holds a list of objects derived from ReferenceCountedObject, or which implement basic
|
||||||
|
reference-count handling methods.
|
||||||
|
|
||||||
|
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 methods called incReferenceCount(), decReferenceCount(), and
|
||||||
|
decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods
|
||||||
|
should behave.
|
||||||
|
|
||||||
|
A ReferenceCountedArray holds objects derived from ReferenceCountedObject,
|
||||||
|
and takes care of incrementing and decrementing their ref counts when they
|
||||||
|
are added and removed from the array.
|
||||||
|
|
||||||
|
To make all the array's methods thread-safe, pass in "CriticalSection" as the templated
|
||||||
|
TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
|
||||||
|
|
||||||
|
@see Array, OwnedArray, StringArray
|
||||||
|
*/
|
||||||
|
template <class ObjectClass, class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
||||||
|
class ReferenceCountedArray
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef ReferenceCountedObjectPtr<ObjectClass> ObjectClassPtr;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an empty array.
|
||||||
|
@see ReferenceCountedObject, Array, OwnedArray
|
||||||
|
*/
|
||||||
|
ReferenceCountedArray() noexcept
|
||||||
|
: numUsed (0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a copy of another array */
|
||||||
|
ReferenceCountedArray (const ReferenceCountedArray& other) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (other.getLock());
|
||||||
|
numUsed = other.size();
|
||||||
|
data.setAllocatedSize (numUsed);
|
||||||
|
memcpy (data.elements, other.getRawDataPointer(), (size_t) numUsed * sizeof (ObjectClass*));
|
||||||
|
|
||||||
|
for (int i = numUsed; --i >= 0;)
|
||||||
|
if (ObjectClass* o = data.elements[i])
|
||||||
|
o->incReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a copy of another array */
|
||||||
|
template <class OtherObjectClass, class OtherCriticalSection>
|
||||||
|
ReferenceCountedArray (const ReferenceCountedArray<OtherObjectClass, OtherCriticalSection>& other) noexcept
|
||||||
|
{
|
||||||
|
const typename ReferenceCountedArray<OtherObjectClass, OtherCriticalSection>::ScopedLockType lock (other.getLock());
|
||||||
|
numUsed = other.size();
|
||||||
|
data.setAllocatedSize (numUsed);
|
||||||
|
memcpy (data.elements, other.getRawDataPointer(), numUsed * sizeof (ObjectClass*));
|
||||||
|
|
||||||
|
for (int i = numUsed; --i >= 0;)
|
||||||
|
if (ObjectClass* o = data.elements[i])
|
||||||
|
o->incReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copies another array into this one.
|
||||||
|
Any existing objects in this array will first be released.
|
||||||
|
*/
|
||||||
|
ReferenceCountedArray& operator= (const ReferenceCountedArray& other) noexcept
|
||||||
|
{
|
||||||
|
ReferenceCountedArray otherCopy (other);
|
||||||
|
swapWith (otherCopy);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copies another array into this one.
|
||||||
|
Any existing objects in this array will first be released.
|
||||||
|
*/
|
||||||
|
template <class OtherObjectClass>
|
||||||
|
ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& operator= (const ReferenceCountedArray<OtherObjectClass, TypeOfCriticalSectionToUse>& other) noexcept
|
||||||
|
{
|
||||||
|
ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse> otherCopy (other);
|
||||||
|
swapWith (otherCopy);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Destructor.
|
||||||
|
Any objects in the array will be released, and may be deleted if not referenced from elsewhere.
|
||||||
|
*/
|
||||||
|
~ReferenceCountedArray()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Removes all objects from the array.
|
||||||
|
|
||||||
|
Any objects in the array that are not referenced from elsewhere will be deleted.
|
||||||
|
*/
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
while (numUsed > 0)
|
||||||
|
if (ObjectClass* o = data.elements [--numUsed])
|
||||||
|
releaseObject (o);
|
||||||
|
|
||||||
|
jassert (numUsed == 0);
|
||||||
|
data.setAllocatedSize (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the current number of objects in the array. */
|
||||||
|
inline int size() const noexcept
|
||||||
|
{
|
||||||
|
return numUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the object at this index in the array.
|
||||||
|
|
||||||
|
If the index is out-of-range, this will return a null pointer, (and
|
||||||
|
it could be null anyway, because it's ok for the array to hold null
|
||||||
|
pointers as well as objects).
|
||||||
|
|
||||||
|
@see getUnchecked
|
||||||
|
*/
|
||||||
|
inline ObjectClassPtr operator[] (const int index) const noexcept
|
||||||
|
{
|
||||||
|
return getObjectPointer (index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the object at this index in the array, without checking
|
||||||
|
whether the index is in-range.
|
||||||
|
|
||||||
|
This is a faster and less safe version of operator[] which doesn't check the index passed in, so
|
||||||
|
it can be used when you're sure the index is always going to be legal.
|
||||||
|
*/
|
||||||
|
inline ObjectClassPtr getUnchecked (const int index) const noexcept
|
||||||
|
{
|
||||||
|
return getObjectPointerUnchecked (index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a raw pointer to the object at this index in the array.
|
||||||
|
|
||||||
|
If the index is out-of-range, this will return a null pointer, (and
|
||||||
|
it could be null anyway, because it's ok for the array to hold null
|
||||||
|
pointers as well as objects).
|
||||||
|
|
||||||
|
@see getUnchecked
|
||||||
|
*/
|
||||||
|
inline ObjectClass* getObjectPointer (const int index) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (index, numUsed))
|
||||||
|
{
|
||||||
|
jassert (data.elements != nullptr);
|
||||||
|
return data.elements [index];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ObjectClassPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a raw pointer to the object at this index in the array, without checking
|
||||||
|
whether the index is in-range.
|
||||||
|
*/
|
||||||
|
inline ObjectClass* getObjectPointerUnchecked (const int index) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
jassert (isPositiveAndBelow (index, numUsed) && data.elements != nullptr);
|
||||||
|
return data.elements [index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the first object in the array.
|
||||||
|
|
||||||
|
This will return a null pointer if the array's empty.
|
||||||
|
@see getLast
|
||||||
|
*/
|
||||||
|
inline ObjectClassPtr getFirst() const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (numUsed > 0)
|
||||||
|
{
|
||||||
|
jassert (data.elements != nullptr);
|
||||||
|
return data.elements [0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ObjectClassPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the last object in the array.
|
||||||
|
|
||||||
|
This will return a null pointer if the array's empty.
|
||||||
|
@see getFirst
|
||||||
|
*/
|
||||||
|
inline ObjectClassPtr getLast() const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (numUsed > 0)
|
||||||
|
{
|
||||||
|
jassert (data.elements != nullptr);
|
||||||
|
return data.elements [numUsed - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ObjectClassPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the actual array data.
|
||||||
|
This pointer will only be valid until the next time a non-const method
|
||||||
|
is called on the array.
|
||||||
|
*/
|
||||||
|
inline ObjectClass** getRawDataPointer() const noexcept
|
||||||
|
{
|
||||||
|
return data.elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a pointer to the first element in the array.
|
||||||
|
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||||
|
*/
|
||||||
|
inline ObjectClass** begin() const noexcept
|
||||||
|
{
|
||||||
|
return data.elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the element which follows the last element in the array.
|
||||||
|
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||||
|
*/
|
||||||
|
inline ObjectClass** end() const noexcept
|
||||||
|
{
|
||||||
|
return data.elements + numUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Finds the index of the first occurrence of an object in the array.
|
||||||
|
|
||||||
|
@param objectToLookFor the object to look for
|
||||||
|
@returns the index at which the object was found, or -1 if it's not found
|
||||||
|
*/
|
||||||
|
int indexOf (const ObjectClass* const objectToLookFor) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
ObjectClass** e = data.elements.getData();
|
||||||
|
ObjectClass** const endPointer = e + numUsed;
|
||||||
|
|
||||||
|
while (e != endPointer)
|
||||||
|
{
|
||||||
|
if (objectToLookFor == *e)
|
||||||
|
return static_cast <int> (e - data.elements.getData());
|
||||||
|
|
||||||
|
++e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the array contains a specified object.
|
||||||
|
|
||||||
|
@param objectToLookFor the object to look for
|
||||||
|
@returns true if the object is in the array
|
||||||
|
*/
|
||||||
|
bool contains (const ObjectClass* const objectToLookFor) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
ObjectClass** e = data.elements.getData();
|
||||||
|
ObjectClass** const endPointer = e + numUsed;
|
||||||
|
|
||||||
|
while (e != endPointer)
|
||||||
|
{
|
||||||
|
if (objectToLookFor == *e)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
++e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Appends a new object to the end of the array.
|
||||||
|
|
||||||
|
This will increase the new object's reference count.
|
||||||
|
|
||||||
|
@param newObject the new object to add to the array
|
||||||
|
@see set, insert, addIfNotAlreadyThere, addSorted, addArray
|
||||||
|
*/
|
||||||
|
ObjectClass* add (ObjectClass* const newObject) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
data.ensureAllocatedSize (numUsed + 1);
|
||||||
|
jassert (data.elements != nullptr);
|
||||||
|
data.elements [numUsed++] = newObject;
|
||||||
|
|
||||||
|
if (newObject != nullptr)
|
||||||
|
newObject->incReferenceCount();
|
||||||
|
|
||||||
|
return newObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Inserts a new object into the array at the given index.
|
||||||
|
|
||||||
|
If the index is less than 0 or greater than the size of the array, the
|
||||||
|
element will be added to the end of the array.
|
||||||
|
Otherwise, it will be inserted into the array, moving all the later elements
|
||||||
|
along to make room.
|
||||||
|
|
||||||
|
This will increase the new object's reference count.
|
||||||
|
|
||||||
|
@param indexToInsertAt the index at which the new element should be inserted
|
||||||
|
@param newObject the new object to add to the array
|
||||||
|
@see add, addSorted, addIfNotAlreadyThere, set
|
||||||
|
*/
|
||||||
|
ObjectClass* insert (int indexToInsertAt,
|
||||||
|
ObjectClass* const newObject) noexcept
|
||||||
|
{
|
||||||
|
if (indexToInsertAt < 0)
|
||||||
|
return add (newObject);
|
||||||
|
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (indexToInsertAt > numUsed)
|
||||||
|
indexToInsertAt = numUsed;
|
||||||
|
|
||||||
|
data.ensureAllocatedSize (numUsed + 1);
|
||||||
|
jassert (data.elements != nullptr);
|
||||||
|
|
||||||
|
ObjectClass** const e = data.elements + indexToInsertAt;
|
||||||
|
const int numToMove = numUsed - indexToInsertAt;
|
||||||
|
|
||||||
|
if (numToMove > 0)
|
||||||
|
memmove (e + 1, e, sizeof (ObjectClass*) * (size_t) numToMove);
|
||||||
|
|
||||||
|
*e = newObject;
|
||||||
|
|
||||||
|
if (newObject != nullptr)
|
||||||
|
newObject->incReferenceCount();
|
||||||
|
|
||||||
|
++numUsed;
|
||||||
|
|
||||||
|
return newObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Appends a new object at the end of the array as long as the array doesn't
|
||||||
|
already contain it.
|
||||||
|
|
||||||
|
If the array already contains a matching object, nothing will be done.
|
||||||
|
|
||||||
|
@param newObject the new object to add to the array
|
||||||
|
*/
|
||||||
|
void addIfNotAlreadyThere (ObjectClass* const newObject) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
if (! contains (newObject))
|
||||||
|
add (newObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Replaces an object in the array with a different one.
|
||||||
|
|
||||||
|
If the index is less than zero, this method does nothing.
|
||||||
|
If the index is beyond the end of the array, the new object is added to the end of the array.
|
||||||
|
|
||||||
|
The object being added has its reference count increased, and if it's replacing
|
||||||
|
another object, then that one has its reference count decreased, and may be deleted.
|
||||||
|
|
||||||
|
@param indexToChange the index whose value you want to change
|
||||||
|
@param newObject the new value to set for this index.
|
||||||
|
@see add, insert, remove
|
||||||
|
*/
|
||||||
|
void set (const int indexToChange,
|
||||||
|
ObjectClass* const newObject)
|
||||||
|
{
|
||||||
|
if (indexToChange >= 0)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (newObject != nullptr)
|
||||||
|
newObject->incReferenceCount();
|
||||||
|
|
||||||
|
if (indexToChange < numUsed)
|
||||||
|
{
|
||||||
|
if (ObjectClass* o = data.elements [indexToChange])
|
||||||
|
releaseObject (o);
|
||||||
|
|
||||||
|
data.elements [indexToChange] = newObject;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.ensureAllocatedSize (numUsed + 1);
|
||||||
|
jassert (data.elements != nullptr);
|
||||||
|
data.elements [numUsed++] = newObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds elements from another array to the end of this array.
|
||||||
|
|
||||||
|
@param arrayToAddFrom the array from which to copy the elements
|
||||||
|
@param startIndex the first element of the other array to start copying from
|
||||||
|
@param numElementsToAdd how many elements to add from the other array. If this
|
||||||
|
value is negative or greater than the number of available elements,
|
||||||
|
all available elements will be copied.
|
||||||
|
@see add
|
||||||
|
*/
|
||||||
|
void addArray (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& arrayToAddFrom,
|
||||||
|
int startIndex = 0,
|
||||||
|
int numElementsToAdd = -1) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock1 (arrayToAddFrom.getLock());
|
||||||
|
|
||||||
|
{
|
||||||
|
const ScopedLockType lock2 (getLock());
|
||||||
|
|
||||||
|
if (startIndex < 0)
|
||||||
|
{
|
||||||
|
jassertfalse;
|
||||||
|
startIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size())
|
||||||
|
numElementsToAdd = arrayToAddFrom.size() - startIndex;
|
||||||
|
|
||||||
|
if (numElementsToAdd > 0)
|
||||||
|
{
|
||||||
|
data.ensureAllocatedSize (numUsed + numElementsToAdd);
|
||||||
|
|
||||||
|
while (--numElementsToAdd >= 0)
|
||||||
|
add (arrayToAddFrom.getUnchecked (startIndex++));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Inserts a new object into the array assuming that the array is sorted.
|
||||||
|
|
||||||
|
This will use a comparator to find the position at which the new object
|
||||||
|
should go. If the array isn't sorted, the behaviour of this
|
||||||
|
method will be unpredictable.
|
||||||
|
|
||||||
|
@param comparator the comparator object to use to compare the elements - see the
|
||||||
|
sort() method for details about this object's form
|
||||||
|
@param newObject the new object to insert to the array
|
||||||
|
@returns the index at which the new object was added
|
||||||
|
@see add, sort
|
||||||
|
*/
|
||||||
|
template <class ElementComparator>
|
||||||
|
int addSorted (ElementComparator& comparator, ObjectClass* newObject) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newObject, 0, numUsed);
|
||||||
|
insert (index, newObject);
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Inserts or replaces an object in the array, assuming it is sorted.
|
||||||
|
|
||||||
|
This is similar to addSorted, but if a matching element already exists, then it will be
|
||||||
|
replaced by the new one, rather than the new one being added as well.
|
||||||
|
*/
|
||||||
|
template <class ElementComparator>
|
||||||
|
void addOrReplaceSorted (ElementComparator& comparator,
|
||||||
|
ObjectClass* newObject) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newObject, 0, numUsed);
|
||||||
|
|
||||||
|
if (index > 0 && comparator.compareElements (newObject, data.elements [index - 1]) == 0)
|
||||||
|
set (index - 1, newObject); // replace an existing object that matches
|
||||||
|
else
|
||||||
|
insert (index, newObject); // no match, so insert the new one
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Finds the index of an object in the array, assuming that the array is sorted.
|
||||||
|
|
||||||
|
This will use a comparator to do a binary-chop to find the index of the given
|
||||||
|
element, if it exists. If the array isn't sorted, the behaviour of this
|
||||||
|
method will be unpredictable.
|
||||||
|
|
||||||
|
@param comparator the comparator to use to compare the elements - see the sort()
|
||||||
|
method for details about the form this object should take
|
||||||
|
@param objectToLookFor the object to search for
|
||||||
|
@returns the index of the element, or -1 if it's not found
|
||||||
|
@see addSorted, sort
|
||||||
|
*/
|
||||||
|
template <class ElementComparator>
|
||||||
|
int indexOfSorted (ElementComparator& comparator,
|
||||||
|
const ObjectClass* const objectToLookFor) const noexcept
|
||||||
|
{
|
||||||
|
(void) comparator;
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
int s = 0, e = numUsed;
|
||||||
|
|
||||||
|
while (s < e)
|
||||||
|
{
|
||||||
|
if (comparator.compareElements (objectToLookFor, data.elements [s]) == 0)
|
||||||
|
return s;
|
||||||
|
|
||||||
|
const int halfway = (s + e) / 2;
|
||||||
|
if (halfway == s)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (comparator.compareElements (objectToLookFor, data.elements [halfway]) >= 0)
|
||||||
|
s = halfway;
|
||||||
|
else
|
||||||
|
e = halfway;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Removes an object from the array.
|
||||||
|
|
||||||
|
This will remove the object at a given index and move back all the
|
||||||
|
subsequent objects to close the gap.
|
||||||
|
|
||||||
|
If the index passed in is out-of-range, nothing will happen.
|
||||||
|
|
||||||
|
The object that is removed will have its reference count decreased,
|
||||||
|
and may be deleted if not referenced from elsewhere.
|
||||||
|
|
||||||
|
@param indexToRemove the index of the element to remove
|
||||||
|
@see removeObject, removeRange
|
||||||
|
*/
|
||||||
|
void remove (const int indexToRemove)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (indexToRemove, numUsed))
|
||||||
|
{
|
||||||
|
ObjectClass** const e = data.elements + indexToRemove;
|
||||||
|
|
||||||
|
if (ObjectClass* o = *e)
|
||||||
|
releaseObject (o);
|
||||||
|
|
||||||
|
--numUsed;
|
||||||
|
const int numberToShift = numUsed - indexToRemove;
|
||||||
|
|
||||||
|
if (numberToShift > 0)
|
||||||
|
memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numberToShift);
|
||||||
|
|
||||||
|
if ((numUsed << 1) < data.numAllocated)
|
||||||
|
minimiseStorageOverheads();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes and returns an object from the array.
|
||||||
|
|
||||||
|
This will remove the object at a given index and return it, moving back all
|
||||||
|
the subsequent objects to close the gap. If the index passed in is out-of-range,
|
||||||
|
nothing will happen and a null pointer will be returned.
|
||||||
|
|
||||||
|
@param indexToRemove the index of the element to remove
|
||||||
|
@see remove, removeObject, removeRange
|
||||||
|
*/
|
||||||
|
ObjectClassPtr removeAndReturn (const int indexToRemove)
|
||||||
|
{
|
||||||
|
ObjectClassPtr removedItem;
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (indexToRemove, numUsed))
|
||||||
|
{
|
||||||
|
ObjectClass** const e = data.elements + indexToRemove;
|
||||||
|
|
||||||
|
if (ObjectClass* o = *e)
|
||||||
|
{
|
||||||
|
removedItem = o;
|
||||||
|
releaseObject (o);
|
||||||
|
}
|
||||||
|
|
||||||
|
--numUsed;
|
||||||
|
const int numberToShift = numUsed - indexToRemove;
|
||||||
|
|
||||||
|
if (numberToShift > 0)
|
||||||
|
memmove (e, e + 1, sizeof (ObjectClass*) * (size_t) numberToShift);
|
||||||
|
|
||||||
|
if ((numUsed << 1) < data.numAllocated)
|
||||||
|
minimiseStorageOverheads();
|
||||||
|
}
|
||||||
|
|
||||||
|
return removedItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes the first occurrence of a specified object from the array.
|
||||||
|
|
||||||
|
If the item isn't found, no action is taken. If it is found, it is
|
||||||
|
removed and has its reference count decreased.
|
||||||
|
|
||||||
|
@param objectToRemove the object to try to remove
|
||||||
|
@see remove, removeRange
|
||||||
|
*/
|
||||||
|
void removeObject (ObjectClass* const objectToRemove)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
remove (indexOf (objectToRemove));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes a range of objects from the array.
|
||||||
|
|
||||||
|
This will remove a set of objects, starting from the given index,
|
||||||
|
and move any subsequent elements down to close the gap.
|
||||||
|
|
||||||
|
If the range extends beyond the bounds of the array, it will
|
||||||
|
be safely clipped to the size of the array.
|
||||||
|
|
||||||
|
The objects that are removed will have their reference counts decreased,
|
||||||
|
and may be deleted if not referenced from elsewhere.
|
||||||
|
|
||||||
|
@param startIndex the index of the first object to remove
|
||||||
|
@param numberToRemove how many objects should be removed
|
||||||
|
@see remove, removeObject
|
||||||
|
*/
|
||||||
|
void removeRange (const int startIndex,
|
||||||
|
const int numberToRemove)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
const int start = jlimit (0, numUsed, startIndex);
|
||||||
|
const int endIndex = jlimit (0, numUsed, startIndex + numberToRemove);
|
||||||
|
|
||||||
|
if (endIndex > start)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = start; i < endIndex; ++i)
|
||||||
|
{
|
||||||
|
if (ObjectClass* o = data.elements[i])
|
||||||
|
{
|
||||||
|
releaseObject (o);
|
||||||
|
data.elements[i] = nullptr; // (in case one of the destructors accesses this array and hits a dangling pointer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int rangeSize = endIndex - start;
|
||||||
|
ObjectClass** e = data.elements + start;
|
||||||
|
i = numUsed - endIndex;
|
||||||
|
numUsed -= rangeSize;
|
||||||
|
|
||||||
|
while (--i >= 0)
|
||||||
|
{
|
||||||
|
*e = e [rangeSize];
|
||||||
|
++e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((numUsed << 1) < data.numAllocated)
|
||||||
|
minimiseStorageOverheads();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes the last n objects from the array.
|
||||||
|
|
||||||
|
The objects that are removed will have their reference counts decreased,
|
||||||
|
and may be deleted if not referenced from elsewhere.
|
||||||
|
|
||||||
|
@param howManyToRemove how many objects to remove from the end of the array
|
||||||
|
@see remove, removeObject, removeRange
|
||||||
|
*/
|
||||||
|
void removeLast (int howManyToRemove = 1)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (howManyToRemove > numUsed)
|
||||||
|
howManyToRemove = numUsed;
|
||||||
|
|
||||||
|
while (--howManyToRemove >= 0)
|
||||||
|
remove (numUsed - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Swaps a pair of objects in the array.
|
||||||
|
|
||||||
|
If either of the indexes passed in is out-of-range, nothing will happen,
|
||||||
|
otherwise the two objects at these positions will be exchanged.
|
||||||
|
*/
|
||||||
|
void swap (const int index1,
|
||||||
|
const int index2) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (index1, numUsed)
|
||||||
|
&& isPositiveAndBelow (index2, numUsed))
|
||||||
|
{
|
||||||
|
std::swap (data.elements [index1],
|
||||||
|
data.elements [index2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Moves one of the objects to a different position.
|
||||||
|
|
||||||
|
This will move the object to a specified index, shuffling along
|
||||||
|
any intervening elements as required.
|
||||||
|
|
||||||
|
So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling
|
||||||
|
move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }.
|
||||||
|
|
||||||
|
@param currentIndex the index of the object to be moved. If this isn't a
|
||||||
|
valid index, then nothing will be done
|
||||||
|
@param newIndex the index at which you'd like this object to end up. If this
|
||||||
|
is less than zero, it will be moved to the end of the array
|
||||||
|
*/
|
||||||
|
void move (const int currentIndex,
|
||||||
|
int newIndex) noexcept
|
||||||
|
{
|
||||||
|
if (currentIndex != newIndex)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (currentIndex, numUsed))
|
||||||
|
{
|
||||||
|
if (! isPositiveAndBelow (newIndex, numUsed))
|
||||||
|
newIndex = numUsed - 1;
|
||||||
|
|
||||||
|
ObjectClass* const value = data.elements [currentIndex];
|
||||||
|
|
||||||
|
if (newIndex > currentIndex)
|
||||||
|
{
|
||||||
|
memmove (data.elements + currentIndex,
|
||||||
|
data.elements + currentIndex + 1,
|
||||||
|
sizeof (ObjectClass*) * (size_t) (newIndex - currentIndex));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memmove (data.elements + newIndex + 1,
|
||||||
|
data.elements + newIndex,
|
||||||
|
sizeof (ObjectClass*) * (size_t) (currentIndex - newIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
data.elements [newIndex] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** This swaps the contents of this array with those of another array.
|
||||||
|
|
||||||
|
If you need to exchange two arrays, this is vastly quicker than using copy-by-value
|
||||||
|
because it just swaps their internal pointers.
|
||||||
|
*/
|
||||||
|
template <class OtherArrayType>
|
||||||
|
void swapWith (OtherArrayType& otherArray) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock1 (getLock());
|
||||||
|
const typename OtherArrayType::ScopedLockType lock2 (otherArray.getLock());
|
||||||
|
data.swapWith (otherArray.data);
|
||||||
|
std::swap (numUsed, otherArray.numUsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Compares this array to another one.
|
||||||
|
|
||||||
|
@returns true only if the other array contains the same objects in the same order
|
||||||
|
*/
|
||||||
|
bool operator== (const ReferenceCountedArray& other) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock2 (other.getLock());
|
||||||
|
const ScopedLockType lock1 (getLock());
|
||||||
|
|
||||||
|
if (numUsed != other.numUsed)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = numUsed; --i >= 0;)
|
||||||
|
if (data.elements [i] != other.data.elements [i])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compares this array to another one.
|
||||||
|
|
||||||
|
@see operator==
|
||||||
|
*/
|
||||||
|
bool operator!= (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& other) const noexcept
|
||||||
|
{
|
||||||
|
return ! operator== (other);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Sorts the elements in the array.
|
||||||
|
|
||||||
|
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);
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
..and this method must return:
|
||||||
|
- a value of < 0 if the first comes before the second
|
||||||
|
- a value of 0 if the two objects are equivalent
|
||||||
|
- a value of > 0 if the second comes before the first
|
||||||
|
|
||||||
|
To improve performance, the compareElements() method can be declared as static or const.
|
||||||
|
|
||||||
|
@param comparator the comparator to use for comparing elements.
|
||||||
|
@param retainOrderOfEquivalentItems if this is true, then items
|
||||||
|
which the comparator says are equivalent will be
|
||||||
|
kept in the order in which they currently appear
|
||||||
|
in the array. This is slower to perform, but may
|
||||||
|
be important in some cases. If it's false, a faster
|
||||||
|
algorithm is used, but equivalent elements may be
|
||||||
|
rearranged.
|
||||||
|
|
||||||
|
@see sortArray
|
||||||
|
*/
|
||||||
|
template <class ElementComparator>
|
||||||
|
void sort (ElementComparator& comparator,
|
||||||
|
const bool retainOrderOfEquivalentItems = false) const noexcept
|
||||||
|
{
|
||||||
|
(void) comparator; // if you pass in an object with a static compareElements() method, this
|
||||||
|
// avoids getting warning messages about the parameter being unused
|
||||||
|
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
sortArray (comparator, data.elements.getData(), 0, size() - 1, retainOrderOfEquivalentItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Reduces the amount of storage being used by the array.
|
||||||
|
|
||||||
|
Arrays typically allocate slightly more storage than they need, and after
|
||||||
|
removing elements, they may have quite a lot of unused space allocated.
|
||||||
|
This method will reduce the amount of allocated storage to a minimum.
|
||||||
|
*/
|
||||||
|
void minimiseStorageOverheads() noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
data.shrinkToNoMoreThan (numUsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Increases the array's internal storage to hold a minimum number of elements.
|
||||||
|
|
||||||
|
Calling this before adding a large known number of elements means that
|
||||||
|
the array won't have to keep dynamically resizing itself as the elements
|
||||||
|
are added, and it'll therefore be more efficient.
|
||||||
|
*/
|
||||||
|
void ensureStorageAllocated (const int minNumElements)
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
data.ensureAllocatedSize (minNumElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the CriticalSection that locks this array.
|
||||||
|
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
|
||||||
|
an object of ScopedLockType as an RAII lock for it.
|
||||||
|
*/
|
||||||
|
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return data; }
|
||||||
|
|
||||||
|
/** Returns the type of scoped lock to use for locking this array */
|
||||||
|
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#ifndef DOXYGEN
|
||||||
|
// Note that the swapWithArray method has been replaced by a more flexible templated version,
|
||||||
|
// and renamed "swapWith" to be more consistent with the names used in other classes.
|
||||||
|
JUCE_DEPRECATED_WITH_BODY (void swapWithArray (ReferenceCountedArray& other) noexcept, { swapWith (other); })
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse> data;
|
||||||
|
int numUsed;
|
||||||
|
|
||||||
|
static void releaseObject (ObjectClass* o)
|
||||||
|
{
|
||||||
|
if (o->decReferenceCountWithoutDeleting())
|
||||||
|
ContainerDeletePolicy<ObjectClass>::destroy (o);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_REFERENCECOUNTEDARRAY_H_INCLUDED
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_SCOPEDVALUESETTER_H_INCLUDED
|
||||||
|
#define JUCE_SCOPEDVALUESETTER_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Helper class providing an RAII-based mechanism for temporarily setting and
|
||||||
|
then re-setting a value.
|
||||||
|
|
||||||
|
E.g. @code
|
||||||
|
int x = 1;
|
||||||
|
|
||||||
|
{
|
||||||
|
ScopedValueSetter setter (x, 2);
|
||||||
|
|
||||||
|
// x is now 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// x is now 1 again
|
||||||
|
|
||||||
|
{
|
||||||
|
ScopedValueSetter setter (x, 3, 4);
|
||||||
|
|
||||||
|
// x is now 3
|
||||||
|
}
|
||||||
|
|
||||||
|
// x is now 4
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
*/
|
||||||
|
template <typename ValueType>
|
||||||
|
class ScopedValueSetter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Creates a ScopedValueSetter that will immediately change the specified value to the
|
||||||
|
given new value, and will then reset it to its original value when this object is deleted.
|
||||||
|
*/
|
||||||
|
ScopedValueSetter (ValueType& valueToSet,
|
||||||
|
ValueType newValue)
|
||||||
|
: value (valueToSet),
|
||||||
|
originalValue (valueToSet)
|
||||||
|
{
|
||||||
|
valueToSet = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a ScopedValueSetter that will immediately change the specified value to the
|
||||||
|
given new value, and will then reset it to be valueWhenDeleted when this object is deleted.
|
||||||
|
*/
|
||||||
|
ScopedValueSetter (ValueType& valueToSet,
|
||||||
|
ValueType newValue,
|
||||||
|
ValueType valueWhenDeleted)
|
||||||
|
: value (valueToSet),
|
||||||
|
originalValue (valueWhenDeleted)
|
||||||
|
{
|
||||||
|
valueToSet = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
~ScopedValueSetter()
|
||||||
|
{
|
||||||
|
value = originalValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
ValueType& value;
|
||||||
|
const ValueType originalValue;
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (ScopedValueSetter)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_SCOPEDVALUESETTER_H_INCLUDED
|
||||||
@@ -0,0 +1,494 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_SORTEDSET_H_INCLUDED
|
||||||
|
#define JUCE_SORTEDSET_H_INCLUDED
|
||||||
|
|
||||||
|
#if JUCE_MSVC
|
||||||
|
#pragma warning (push)
|
||||||
|
#pragma warning (disable: 4512)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Holds a set of unique primitive objects, such as ints or doubles.
|
||||||
|
|
||||||
|
A set can only hold one item with a given value, so if for example it's a
|
||||||
|
set of integers, attempting to add the same integer twice will do nothing
|
||||||
|
the second time.
|
||||||
|
|
||||||
|
Internally, the list of items is kept sorted (which means that whatever
|
||||||
|
kind of primitive type is used must support the ==, <, >, <= and >= operators
|
||||||
|
to determine the order), and searching the set for known values is very fast
|
||||||
|
because it uses a binary-chop method.
|
||||||
|
|
||||||
|
Note that if you're using a class or struct as the element type, it must be
|
||||||
|
capable of being copied or moved with a straightforward memcpy, rather than
|
||||||
|
needing construction and destruction code.
|
||||||
|
|
||||||
|
To make all the set's methods thread-safe, pass in "CriticalSection" as the templated
|
||||||
|
TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection.
|
||||||
|
|
||||||
|
@see Array, OwnedArray, ReferenceCountedArray, StringArray, CriticalSection
|
||||||
|
*/
|
||||||
|
template <class ElementType, class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
||||||
|
class SortedSet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an empty set. */
|
||||||
|
SortedSet() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a copy of another set.
|
||||||
|
@param other the set to copy
|
||||||
|
*/
|
||||||
|
SortedSet (const SortedSet& other)
|
||||||
|
: data (other.data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~SortedSet() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copies another set over this one.
|
||||||
|
@param other the set to copy
|
||||||
|
*/
|
||||||
|
SortedSet& operator= (const SortedSet& other) noexcept
|
||||||
|
{
|
||||||
|
data = other.data;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Compares this set to another one.
|
||||||
|
Two sets are considered equal if they both contain the same set of elements.
|
||||||
|
@param other the other set to compare with
|
||||||
|
*/
|
||||||
|
bool operator== (const SortedSet<ElementType>& other) const noexcept
|
||||||
|
{
|
||||||
|
return data == other.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compares this set to another one.
|
||||||
|
Two sets are considered equal if they both contain the same set of elements.
|
||||||
|
@param other the other set to compare with
|
||||||
|
*/
|
||||||
|
bool operator!= (const SortedSet<ElementType>& other) const noexcept
|
||||||
|
{
|
||||||
|
return ! operator== (other);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Removes all elements from the set.
|
||||||
|
|
||||||
|
This will remove all the elements, and free any storage that the set is
|
||||||
|
using. To clear it without freeing the storage, use the clearQuick()
|
||||||
|
method instead.
|
||||||
|
|
||||||
|
@see clearQuick
|
||||||
|
*/
|
||||||
|
void clear() noexcept
|
||||||
|
{
|
||||||
|
data.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes all elements from the set without freeing the array's allocated storage.
|
||||||
|
@see clear
|
||||||
|
*/
|
||||||
|
void clearQuick() noexcept
|
||||||
|
{
|
||||||
|
data.clearQuick();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the current number of elements in the set. */
|
||||||
|
inline int size() const noexcept
|
||||||
|
{
|
||||||
|
return data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns one of the elements in the set.
|
||||||
|
|
||||||
|
If the index passed in is beyond the range of valid elements, this
|
||||||
|
will return zero.
|
||||||
|
|
||||||
|
If you're certain that the index will always be a valid element, you
|
||||||
|
can call getUnchecked() instead, which is faster.
|
||||||
|
|
||||||
|
@param index the index of the element being requested (0 is the first element in the set)
|
||||||
|
@see getUnchecked, getFirst, getLast
|
||||||
|
*/
|
||||||
|
inline ElementType operator[] (const int index) const noexcept
|
||||||
|
{
|
||||||
|
return data [index];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns one of the elements in the set, without checking the index passed in.
|
||||||
|
Unlike the operator[] method, this will try to return an element without
|
||||||
|
checking that the index is within the bounds of the set, so should only
|
||||||
|
be used when you're confident that it will always be a valid index.
|
||||||
|
|
||||||
|
@param index the index of the element being requested (0 is the first element in the set)
|
||||||
|
@see operator[], getFirst, getLast
|
||||||
|
*/
|
||||||
|
inline ElementType getUnchecked (const int index) const noexcept
|
||||||
|
{
|
||||||
|
return data.getUnchecked (index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a direct reference to one of the elements in the set, without checking the index passed in.
|
||||||
|
|
||||||
|
This is like getUnchecked, but returns a direct reference to the element, so that
|
||||||
|
you can alter it directly. Obviously this can be dangerous, so only use it when
|
||||||
|
absolutely necessary.
|
||||||
|
|
||||||
|
@param index the index of the element being requested (0 is the first element in the array)
|
||||||
|
*/
|
||||||
|
inline ElementType& getReference (const int index) const noexcept
|
||||||
|
{
|
||||||
|
return data.getReference (index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the first element in the set, or 0 if the set is empty.
|
||||||
|
@see operator[], getUnchecked, getLast
|
||||||
|
*/
|
||||||
|
inline ElementType getFirst() const noexcept
|
||||||
|
{
|
||||||
|
return data.getFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the last element in the set, or 0 if the set is empty.
|
||||||
|
@see operator[], getUnchecked, getFirst
|
||||||
|
*/
|
||||||
|
inline ElementType getLast() const noexcept
|
||||||
|
{
|
||||||
|
return data.getLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a pointer to the first element in the set.
|
||||||
|
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||||
|
*/
|
||||||
|
inline ElementType* begin() const noexcept
|
||||||
|
{
|
||||||
|
return data.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a pointer to the element which follows the last element in the set.
|
||||||
|
This method is provided for compatibility with standard C++ iteration mechanisms.
|
||||||
|
*/
|
||||||
|
inline ElementType* end() const noexcept
|
||||||
|
{
|
||||||
|
return data.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Finds the index of the first element which matches the value passed in.
|
||||||
|
|
||||||
|
This will search the set for the given object, and return the index
|
||||||
|
of its first occurrence. If the object isn't found, the method will return -1.
|
||||||
|
|
||||||
|
@param elementToLookFor the value or object to look for
|
||||||
|
@returns the index of the object, or -1 if it's not found
|
||||||
|
*/
|
||||||
|
int indexOf (const ElementType& elementToLookFor) const noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (data.getLock());
|
||||||
|
|
||||||
|
int s = 0;
|
||||||
|
int e = data.size();
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (s >= e)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (elementToLookFor == data.getReference (s))
|
||||||
|
return s;
|
||||||
|
|
||||||
|
const int halfway = (s + e) / 2;
|
||||||
|
|
||||||
|
if (halfway == s)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (elementToLookFor < data.getReference (halfway))
|
||||||
|
e = halfway;
|
||||||
|
else
|
||||||
|
s = halfway;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the set contains at least one occurrence of an object.
|
||||||
|
|
||||||
|
@param elementToLookFor the value or object to look for
|
||||||
|
@returns true if the item is found
|
||||||
|
*/
|
||||||
|
bool contains (const ElementType& elementToLookFor) const noexcept
|
||||||
|
{
|
||||||
|
return indexOf (elementToLookFor) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Adds a new element to the set, (as long as it's not already in there).
|
||||||
|
|
||||||
|
Note that if a matching element already exists, the new value will be assigned
|
||||||
|
to the existing one using operator=, so that if there are any differences between
|
||||||
|
the objects which were not recognised by the object's operator==, then the
|
||||||
|
set will always contain a copy of the most recently added one.
|
||||||
|
|
||||||
|
@param newElement the new object to add to the set
|
||||||
|
@returns true if the value was added, or false if it already existed
|
||||||
|
@see set, insert, addIfNotAlreadyThere, addSorted, addSet, addArray
|
||||||
|
*/
|
||||||
|
bool add (const ElementType& newElement) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
int s = 0;
|
||||||
|
int e = data.size();
|
||||||
|
|
||||||
|
while (s < e)
|
||||||
|
{
|
||||||
|
ElementType& elem = data.getReference (s);
|
||||||
|
if (newElement == elem)
|
||||||
|
{
|
||||||
|
elem = newElement; // force an update in case operator== permits differences.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int halfway = (s + e) / 2;
|
||||||
|
const bool isBeforeHalfway = (newElement < data.getReference (halfway));
|
||||||
|
|
||||||
|
if (halfway == s)
|
||||||
|
{
|
||||||
|
if (! isBeforeHalfway)
|
||||||
|
++s;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBeforeHalfway)
|
||||||
|
e = halfway;
|
||||||
|
else
|
||||||
|
s = halfway;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.insert (s, newElement);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds elements from an array to this set.
|
||||||
|
|
||||||
|
@param elementsToAdd the array of elements to add
|
||||||
|
@param numElementsToAdd how many elements are in this other array
|
||||||
|
@see add
|
||||||
|
*/
|
||||||
|
void addArray (const ElementType* elementsToAdd,
|
||||||
|
int numElementsToAdd) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
|
||||||
|
while (--numElementsToAdd >= 0)
|
||||||
|
add (*elementsToAdd++);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Adds elements from another set to this one.
|
||||||
|
|
||||||
|
@param setToAddFrom the set from which to copy the elements
|
||||||
|
@param startIndex the first element of the other set to start copying from
|
||||||
|
@param numElementsToAdd how many elements to add from the other set. If this
|
||||||
|
value is negative or greater than the number of available elements,
|
||||||
|
all available elements will be copied.
|
||||||
|
@see add
|
||||||
|
*/
|
||||||
|
template <class OtherSetType>
|
||||||
|
void addSet (const OtherSetType& setToAddFrom,
|
||||||
|
int startIndex = 0,
|
||||||
|
int numElementsToAdd = -1) noexcept
|
||||||
|
{
|
||||||
|
const typename OtherSetType::ScopedLockType lock1 (setToAddFrom.getLock());
|
||||||
|
|
||||||
|
{
|
||||||
|
const ScopedLockType lock2 (getLock());
|
||||||
|
jassert (this != &setToAddFrom);
|
||||||
|
|
||||||
|
if (this != &setToAddFrom)
|
||||||
|
{
|
||||||
|
if (startIndex < 0)
|
||||||
|
{
|
||||||
|
jassertfalse;
|
||||||
|
startIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numElementsToAdd < 0 || startIndex + numElementsToAdd > setToAddFrom.size())
|
||||||
|
numElementsToAdd = setToAddFrom.size() - startIndex;
|
||||||
|
|
||||||
|
if (numElementsToAdd > 0)
|
||||||
|
addArray (&setToAddFrom.data.getReference (startIndex), numElementsToAdd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Removes an element from the set.
|
||||||
|
|
||||||
|
This will remove the element at a given index.
|
||||||
|
If the index passed in is out-of-range, nothing will happen.
|
||||||
|
|
||||||
|
@param indexToRemove the index of the element to remove
|
||||||
|
@returns the element that has been removed
|
||||||
|
@see removeValue, removeRange
|
||||||
|
*/
|
||||||
|
ElementType remove (const int indexToRemove) noexcept
|
||||||
|
{
|
||||||
|
return data.remove (indexToRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes an item from the set.
|
||||||
|
|
||||||
|
This will remove the given element from the set, if it's there.
|
||||||
|
|
||||||
|
@param valueToRemove the object to try to remove
|
||||||
|
@see remove, removeRange
|
||||||
|
*/
|
||||||
|
void removeValue (const ElementType valueToRemove) noexcept
|
||||||
|
{
|
||||||
|
const ScopedLockType lock (getLock());
|
||||||
|
data.remove (indexOf (valueToRemove));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes any elements which are also in another set.
|
||||||
|
|
||||||
|
@param otherSet the other set in which to look for elements to remove
|
||||||
|
@see removeValuesNotIn, remove, removeValue, removeRange
|
||||||
|
*/
|
||||||
|
template <class OtherSetType>
|
||||||
|
void removeValuesIn (const OtherSetType& otherSet) noexcept
|
||||||
|
{
|
||||||
|
const typename OtherSetType::ScopedLockType lock1 (otherSet.getLock());
|
||||||
|
const ScopedLockType lock2 (getLock());
|
||||||
|
|
||||||
|
if (this == &otherSet)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
else if (otherSet.size() > 0)
|
||||||
|
{
|
||||||
|
for (int i = data.size(); --i >= 0;)
|
||||||
|
if (otherSet.contains (data.getReference (i)))
|
||||||
|
remove (i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes any elements which are not found in another set.
|
||||||
|
|
||||||
|
Only elements which occur in this other set will be retained.
|
||||||
|
|
||||||
|
@param otherSet the set in which to look for elements NOT to remove
|
||||||
|
@see removeValuesIn, remove, removeValue, removeRange
|
||||||
|
*/
|
||||||
|
template <class OtherSetType>
|
||||||
|
void removeValuesNotIn (const OtherSetType& otherSet) noexcept
|
||||||
|
{
|
||||||
|
const typename OtherSetType::ScopedLockType lock1 (otherSet.getLock());
|
||||||
|
const ScopedLockType lock2 (getLock());
|
||||||
|
|
||||||
|
if (this != &otherSet)
|
||||||
|
{
|
||||||
|
if (otherSet.size() <= 0)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = data.size(); --i >= 0;)
|
||||||
|
if (! otherSet.contains (data.getReference (i)))
|
||||||
|
remove (i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This swaps the contents of this array with those of another array.
|
||||||
|
|
||||||
|
If you need to exchange two arrays, this is vastly quicker than using copy-by-value
|
||||||
|
because it just swaps their internal pointers.
|
||||||
|
*/
|
||||||
|
template <class OtherSetType>
|
||||||
|
void swapWith (OtherSetType& otherSet) noexcept
|
||||||
|
{
|
||||||
|
data.swapWith (otherSet.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Reduces the amount of storage being used by the set.
|
||||||
|
|
||||||
|
Sets typically allocate slightly more storage than they need, and after
|
||||||
|
removing elements, they may have quite a lot of unused space allocated.
|
||||||
|
This method will reduce the amount of allocated storage to a minimum.
|
||||||
|
*/
|
||||||
|
void minimiseStorageOverheads() noexcept
|
||||||
|
{
|
||||||
|
data.minimiseStorageOverheads();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Increases the set's internal storage to hold a minimum number of elements.
|
||||||
|
|
||||||
|
Calling this before adding a large known number of elements means that
|
||||||
|
the set won't have to keep dynamically resizing itself as the elements
|
||||||
|
are added, and it'll therefore be more efficient.
|
||||||
|
*/
|
||||||
|
void ensureStorageAllocated (const int minNumElements)
|
||||||
|
{
|
||||||
|
data.ensureStorageAllocated (minNumElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the CriticalSection that locks this array.
|
||||||
|
To lock, you can call getLock().enter() and getLock().exit(), or preferably use
|
||||||
|
an object of ScopedLockType as an RAII lock for it.
|
||||||
|
*/
|
||||||
|
inline const TypeOfCriticalSectionToUse& getLock() const noexcept { return data.getLock(); }
|
||||||
|
|
||||||
|
/** Returns the type of scoped lock to use for locking this array */
|
||||||
|
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
Array<ElementType, TypeOfCriticalSectionToUse> data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#if JUCE_MSVC
|
||||||
|
#pragma warning (pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // JUCE_SORTEDSET_H_INCLUDED
|
||||||
@@ -0,0 +1,298 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_SPARSESET_H_INCLUDED
|
||||||
|
#define JUCE_SPARSESET_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Holds a set of primitive values, storing them as a set of ranges.
|
||||||
|
|
||||||
|
This container acts like an array, but can efficiently hold large contiguous
|
||||||
|
ranges of values. It's quite a specialised class, mostly useful for things
|
||||||
|
like keeping the set of selected rows in a listbox.
|
||||||
|
|
||||||
|
The type used as a template parameter must be an integer type, such as int, short,
|
||||||
|
int64, etc.
|
||||||
|
*/
|
||||||
|
template <class Type>
|
||||||
|
class SparseSet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a new empty set. */
|
||||||
|
SparseSet()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a copy of another SparseSet. */
|
||||||
|
SparseSet (const SparseSet<Type>& other)
|
||||||
|
: values (other.values)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Clears the set. */
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
values.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Checks whether the set is empty.
|
||||||
|
|
||||||
|
This is much quicker than using (size() == 0).
|
||||||
|
*/
|
||||||
|
bool isEmpty() const noexcept
|
||||||
|
{
|
||||||
|
return values.size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the number of values in the set.
|
||||||
|
|
||||||
|
Because of the way the data is stored, this method can take longer if there
|
||||||
|
are a lot of items in the set. Use isEmpty() for a quick test of whether there
|
||||||
|
are any items.
|
||||||
|
*/
|
||||||
|
Type size() const
|
||||||
|
{
|
||||||
|
Type total (0);
|
||||||
|
|
||||||
|
for (int i = 0; i < values.size(); i += 2)
|
||||||
|
total += values.getUnchecked (i + 1) - values.getUnchecked (i);
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns one of the values in the set.
|
||||||
|
|
||||||
|
@param index the index of the value to retrieve, in the range 0 to (size() - 1).
|
||||||
|
@returns the value at this index, or 0 if it's out-of-range
|
||||||
|
*/
|
||||||
|
Type operator[] (Type index) const
|
||||||
|
{
|
||||||
|
for (int i = 0; i < values.size(); i += 2)
|
||||||
|
{
|
||||||
|
const Type start (values.getUnchecked (i));
|
||||||
|
const Type len (values.getUnchecked (i + 1) - start);
|
||||||
|
|
||||||
|
if (index < len)
|
||||||
|
return start + index;
|
||||||
|
|
||||||
|
index -= len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Type();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Checks whether a particular value is in the set. */
|
||||||
|
bool contains (const Type valueToLookFor) const
|
||||||
|
{
|
||||||
|
for (int i = 0; i < values.size(); ++i)
|
||||||
|
if (valueToLookFor < values.getUnchecked(i))
|
||||||
|
return (i & 1) != 0;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the number of contiguous blocks of values.
|
||||||
|
@see getRange
|
||||||
|
*/
|
||||||
|
int getNumRanges() const noexcept
|
||||||
|
{
|
||||||
|
return values.size() >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns one of the contiguous ranges of values stored.
|
||||||
|
@param rangeIndex the index of the range to look up, between 0
|
||||||
|
and (getNumRanges() - 1)
|
||||||
|
@see getTotalRange
|
||||||
|
*/
|
||||||
|
const Range<Type> getRange (const int rangeIndex) const
|
||||||
|
{
|
||||||
|
if (isPositiveAndBelow (rangeIndex, getNumRanges()))
|
||||||
|
return Range<Type> (values.getUnchecked (rangeIndex << 1),
|
||||||
|
values.getUnchecked ((rangeIndex << 1) + 1));
|
||||||
|
|
||||||
|
return Range<Type>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the range between the lowest and highest values in the set.
|
||||||
|
@see getRange
|
||||||
|
*/
|
||||||
|
Range<Type> getTotalRange() const
|
||||||
|
{
|
||||||
|
if (values.size() > 0)
|
||||||
|
{
|
||||||
|
jassert ((values.size() & 1) == 0);
|
||||||
|
return Range<Type> (values.getUnchecked (0),
|
||||||
|
values.getUnchecked (values.size() - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Range<Type>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Adds a range of contiguous values to the set.
|
||||||
|
e.g. addRange (Range \<int\> (10, 14)) will add (10, 11, 12, 13) to the set.
|
||||||
|
*/
|
||||||
|
void addRange (const Range<Type> range)
|
||||||
|
{
|
||||||
|
jassert (range.getLength() >= 0);
|
||||||
|
if (range.getLength() > 0)
|
||||||
|
{
|
||||||
|
removeRange (range);
|
||||||
|
|
||||||
|
values.addUsingDefaultSort (range.getStart());
|
||||||
|
values.addUsingDefaultSort (range.getEnd());
|
||||||
|
|
||||||
|
simplify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Removes a range of values from the set.
|
||||||
|
e.g. removeRange (Range\<int\> (10, 14)) will remove (10, 11, 12, 13) from the set.
|
||||||
|
*/
|
||||||
|
void removeRange (const Range<Type> rangeToRemove)
|
||||||
|
{
|
||||||
|
jassert (rangeToRemove.getLength() >= 0);
|
||||||
|
|
||||||
|
if (rangeToRemove.getLength() > 0
|
||||||
|
&& values.size() > 0
|
||||||
|
&& rangeToRemove.getStart() < values.getUnchecked (values.size() - 1)
|
||||||
|
&& values.getUnchecked(0) < rangeToRemove.getEnd())
|
||||||
|
{
|
||||||
|
const bool onAtStart = contains (rangeToRemove.getStart() - 1);
|
||||||
|
const Type lastValue (jmin (rangeToRemove.getEnd(), values.getLast()));
|
||||||
|
const bool onAtEnd = contains (lastValue);
|
||||||
|
|
||||||
|
for (int i = values.size(); --i >= 0;)
|
||||||
|
{
|
||||||
|
if (values.getUnchecked(i) <= lastValue)
|
||||||
|
{
|
||||||
|
while (values.getUnchecked(i) >= rangeToRemove.getStart())
|
||||||
|
{
|
||||||
|
values.remove (i);
|
||||||
|
|
||||||
|
if (--i < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onAtStart) values.addUsingDefaultSort (rangeToRemove.getStart());
|
||||||
|
if (onAtEnd) values.addUsingDefaultSort (lastValue);
|
||||||
|
|
||||||
|
simplify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Does an XOR of the values in a given range. */
|
||||||
|
void invertRange (const Range<Type> range)
|
||||||
|
{
|
||||||
|
SparseSet newItems;
|
||||||
|
newItems.addRange (range);
|
||||||
|
|
||||||
|
for (int i = getNumRanges(); --i >= 0;)
|
||||||
|
newItems.removeRange (getRange (i));
|
||||||
|
|
||||||
|
removeRange (range);
|
||||||
|
|
||||||
|
for (int i = newItems.getNumRanges(); --i >= 0;)
|
||||||
|
addRange (newItems.getRange(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Checks whether any part of a given range overlaps any part of this set. */
|
||||||
|
bool overlapsRange (const Range<Type> range)
|
||||||
|
{
|
||||||
|
if (range.getLength() > 0)
|
||||||
|
{
|
||||||
|
for (int i = getNumRanges(); --i >= 0;)
|
||||||
|
{
|
||||||
|
if (values.getUnchecked ((i << 1) + 1) <= range.getStart())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (values.getUnchecked (i << 1) < range.getEnd())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Checks whether the whole of a given range is contained within this one. */
|
||||||
|
bool containsRange (const Range<Type> range)
|
||||||
|
{
|
||||||
|
if (range.getLength() > 0)
|
||||||
|
{
|
||||||
|
for (int i = getNumRanges(); --i >= 0;)
|
||||||
|
{
|
||||||
|
if (values.getUnchecked ((i << 1) + 1) <= range.getStart())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (values.getUnchecked (i << 1) <= range.getStart()
|
||||||
|
&& range.getEnd() <= values.getUnchecked ((i << 1) + 1))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool operator== (const SparseSet<Type>& other) noexcept
|
||||||
|
{
|
||||||
|
return values == other.values;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!= (const SparseSet<Type>& other) noexcept
|
||||||
|
{
|
||||||
|
return values != other.values;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
// alternating start/end values of ranges of values that are present.
|
||||||
|
Array<Type, DummyCriticalSection> values;
|
||||||
|
|
||||||
|
void simplify()
|
||||||
|
{
|
||||||
|
jassert ((values.size() & 1) == 0);
|
||||||
|
|
||||||
|
for (int i = values.size(); --i > 0;)
|
||||||
|
if (values.getUnchecked(i) == values.getUnchecked (i - 1))
|
||||||
|
values.removeRange (--i, 2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_SPARSESET_H_INCLUDED
|
||||||
@@ -0,0 +1,780 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum VariantStreamMarkers
|
||||||
|
{
|
||||||
|
varMarker_Int = 1,
|
||||||
|
varMarker_BoolTrue = 2,
|
||||||
|
varMarker_BoolFalse = 3,
|
||||||
|
varMarker_Double = 4,
|
||||||
|
varMarker_String = 5,
|
||||||
|
varMarker_Int64 = 6,
|
||||||
|
varMarker_Array = 7,
|
||||||
|
varMarker_Binary = 8,
|
||||||
|
varMarker_Undefined = 9
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType() noexcept {}
|
||||||
|
virtual ~VariantType() noexcept {}
|
||||||
|
|
||||||
|
virtual int toInt (const ValueUnion&) const noexcept { return 0; }
|
||||||
|
virtual int64 toInt64 (const ValueUnion&) const noexcept { return 0; }
|
||||||
|
virtual double toDouble (const ValueUnion&) const noexcept { return 0; }
|
||||||
|
virtual String toString (const ValueUnion&) const { return String::empty; }
|
||||||
|
virtual bool toBool (const ValueUnion&) const noexcept { return false; }
|
||||||
|
virtual ReferenceCountedObject* toObject (const ValueUnion&) const noexcept { return nullptr; }
|
||||||
|
virtual Array<var>* toArray (const ValueUnion&) const noexcept { return nullptr; }
|
||||||
|
virtual MemoryBlock* toBinary (const ValueUnion&) const noexcept { return nullptr; }
|
||||||
|
virtual var clone (const var& original) const { return original; }
|
||||||
|
|
||||||
|
virtual bool isVoid() const noexcept { return false; }
|
||||||
|
virtual bool isUndefined() const noexcept { return false; }
|
||||||
|
virtual bool isInt() const noexcept { return false; }
|
||||||
|
virtual bool isInt64() const noexcept { return false; }
|
||||||
|
virtual bool isBool() const noexcept { return false; }
|
||||||
|
virtual bool isDouble() const noexcept { return false; }
|
||||||
|
virtual bool isString() const noexcept { return false; }
|
||||||
|
virtual bool isObject() const noexcept { return false; }
|
||||||
|
virtual bool isArray() const noexcept { return false; }
|
||||||
|
virtual bool isBinary() const noexcept { return false; }
|
||||||
|
virtual bool isMethod() const noexcept { return false; }
|
||||||
|
|
||||||
|
virtual void cleanUp (ValueUnion&) const noexcept {}
|
||||||
|
virtual void createCopy (ValueUnion& dest, const ValueUnion& source) const { dest = source; }
|
||||||
|
virtual bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept = 0;
|
||||||
|
virtual void writeToStream (const ValueUnion& data, OutputStream& output) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_Void : public var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_Void() noexcept {}
|
||||||
|
static const VariantType_Void instance;
|
||||||
|
|
||||||
|
bool isVoid() const noexcept override { return true; }
|
||||||
|
bool equals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) const noexcept override { return otherType.isVoid() || otherType.isUndefined(); }
|
||||||
|
void writeToStream (const ValueUnion&, OutputStream& output) const override { output.writeCompressedInt (0); }
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_Undefined : public var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_Undefined() noexcept {}
|
||||||
|
static const VariantType_Undefined instance;
|
||||||
|
|
||||||
|
bool isUndefined() const noexcept override { return true; }
|
||||||
|
String toString (const ValueUnion&) const override { return "undefined"; }
|
||||||
|
bool equals (const ValueUnion&, const ValueUnion&, const VariantType& otherType) const noexcept override { return otherType.isVoid() || otherType.isUndefined(); }
|
||||||
|
|
||||||
|
void writeToStream (const ValueUnion&, OutputStream& output) const override
|
||||||
|
{
|
||||||
|
output.writeCompressedInt (1);
|
||||||
|
output.writeByte (varMarker_Undefined);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_Int : public var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_Int() noexcept {}
|
||||||
|
static const VariantType_Int instance;
|
||||||
|
|
||||||
|
int toInt (const ValueUnion& data) const noexcept override { return data.intValue; };
|
||||||
|
int64 toInt64 (const ValueUnion& data) const noexcept override { return (int64) data.intValue; };
|
||||||
|
double toDouble (const ValueUnion& data) const noexcept override { return (double) data.intValue; }
|
||||||
|
String toString (const ValueUnion& data) const override { return String (data.intValue); }
|
||||||
|
bool toBool (const ValueUnion& data) const noexcept override { return data.intValue != 0; }
|
||||||
|
bool isInt() const noexcept override { return true; }
|
||||||
|
|
||||||
|
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
|
||||||
|
{
|
||||||
|
if (otherType.isDouble() || otherType.isInt64() || otherType.isString())
|
||||||
|
return otherType.equals (otherData, data, *this);
|
||||||
|
|
||||||
|
return otherType.toInt (otherData) == data.intValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToStream (const ValueUnion& data, OutputStream& output) const override
|
||||||
|
{
|
||||||
|
output.writeCompressedInt (5);
|
||||||
|
output.writeByte (varMarker_Int);
|
||||||
|
output.writeInt (data.intValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_Int64 : public var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_Int64() noexcept {}
|
||||||
|
static const VariantType_Int64 instance;
|
||||||
|
|
||||||
|
int toInt (const ValueUnion& data) const noexcept override { return (int) data.int64Value; };
|
||||||
|
int64 toInt64 (const ValueUnion& data) const noexcept override { return data.int64Value; };
|
||||||
|
double toDouble (const ValueUnion& data) const noexcept override { return (double) data.int64Value; }
|
||||||
|
String toString (const ValueUnion& data) const override { return String (data.int64Value); }
|
||||||
|
bool toBool (const ValueUnion& data) const noexcept override { return data.int64Value != 0; }
|
||||||
|
bool isInt64() const noexcept override { return true; }
|
||||||
|
|
||||||
|
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
|
||||||
|
{
|
||||||
|
if (otherType.isDouble() || otherType.isString())
|
||||||
|
return otherType.equals (otherData, data, *this);
|
||||||
|
|
||||||
|
return otherType.toInt64 (otherData) == data.int64Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToStream (const ValueUnion& data, OutputStream& output) const override
|
||||||
|
{
|
||||||
|
output.writeCompressedInt (9);
|
||||||
|
output.writeByte (varMarker_Int64);
|
||||||
|
output.writeInt64 (data.int64Value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_Double : public var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_Double() noexcept {}
|
||||||
|
static const VariantType_Double instance;
|
||||||
|
|
||||||
|
int toInt (const ValueUnion& data) const noexcept override { return (int) data.doubleValue; };
|
||||||
|
int64 toInt64 (const ValueUnion& data) const noexcept override { return (int64) data.doubleValue; };
|
||||||
|
double toDouble (const ValueUnion& data) const noexcept override { return data.doubleValue; }
|
||||||
|
String toString (const ValueUnion& data) const override { return String (data.doubleValue); }
|
||||||
|
bool toBool (const ValueUnion& data) const noexcept override { return data.doubleValue != 0; }
|
||||||
|
bool isDouble() const noexcept override { return true; }
|
||||||
|
|
||||||
|
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
|
||||||
|
{
|
||||||
|
return std::abs (otherType.toDouble (otherData) - data.doubleValue) < std::numeric_limits<double>::epsilon();
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToStream (const ValueUnion& data, OutputStream& output) const override
|
||||||
|
{
|
||||||
|
output.writeCompressedInt (9);
|
||||||
|
output.writeByte (varMarker_Double);
|
||||||
|
output.writeDouble (data.doubleValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_Bool : public var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_Bool() noexcept {}
|
||||||
|
static const VariantType_Bool instance;
|
||||||
|
|
||||||
|
int toInt (const ValueUnion& data) const noexcept override { return data.boolValue ? 1 : 0; };
|
||||||
|
int64 toInt64 (const ValueUnion& data) const noexcept override { return data.boolValue ? 1 : 0; };
|
||||||
|
double toDouble (const ValueUnion& data) const noexcept override { return data.boolValue ? 1.0 : 0.0; }
|
||||||
|
String toString (const ValueUnion& data) const override { return String::charToString (data.boolValue ? (juce_wchar) '1' : (juce_wchar) '0'); }
|
||||||
|
bool toBool (const ValueUnion& data) const noexcept override { return data.boolValue; }
|
||||||
|
bool isBool() const noexcept override { return true; }
|
||||||
|
|
||||||
|
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
|
||||||
|
{
|
||||||
|
return otherType.toBool (otherData) == data.boolValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToStream (const ValueUnion& data, OutputStream& output) const override
|
||||||
|
{
|
||||||
|
output.writeCompressedInt (1);
|
||||||
|
output.writeByte (data.boolValue ? (char) varMarker_BoolTrue : (char) varMarker_BoolFalse);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_String : public var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_String() noexcept {}
|
||||||
|
static const VariantType_String instance;
|
||||||
|
|
||||||
|
void cleanUp (ValueUnion& data) const noexcept override { getString (data)-> ~String(); }
|
||||||
|
void createCopy (ValueUnion& dest, const ValueUnion& source) const override { new (dest.stringValue) String (*getString (source)); }
|
||||||
|
|
||||||
|
bool isString() const noexcept override { return true; }
|
||||||
|
int toInt (const ValueUnion& data) const noexcept override { return getString (data)->getIntValue(); };
|
||||||
|
int64 toInt64 (const ValueUnion& data) const noexcept override { return getString (data)->getLargeIntValue(); };
|
||||||
|
double toDouble (const ValueUnion& data) const noexcept override { return getString (data)->getDoubleValue(); }
|
||||||
|
String toString (const ValueUnion& data) const override { return *getString (data); }
|
||||||
|
bool toBool (const ValueUnion& data) const noexcept override { return getString (data)->getIntValue() != 0
|
||||||
|
|| getString (data)->trim().equalsIgnoreCase ("true")
|
||||||
|
|| getString (data)->trim().equalsIgnoreCase ("yes"); }
|
||||||
|
|
||||||
|
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
|
||||||
|
{
|
||||||
|
return otherType.toString (otherData) == *getString (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToStream (const ValueUnion& data, OutputStream& output) const override
|
||||||
|
{
|
||||||
|
const String* const s = getString (data);
|
||||||
|
const size_t len = s->getNumBytesAsUTF8() + 1;
|
||||||
|
HeapBlock<char> temp (len);
|
||||||
|
s->copyToUTF8 (temp, len);
|
||||||
|
output.writeCompressedInt ((int) (len + 1));
|
||||||
|
output.writeByte (varMarker_String);
|
||||||
|
output.write (temp, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static inline const String* getString (const ValueUnion& data) noexcept { return reinterpret_cast <const String*> (data.stringValue); }
|
||||||
|
static inline String* getString (ValueUnion& data) noexcept { return reinterpret_cast <String*> (data.stringValue); }
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_Object : public var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_Object() noexcept {}
|
||||||
|
static const VariantType_Object instance;
|
||||||
|
|
||||||
|
void cleanUp (ValueUnion& data) const noexcept override { if (data.objectValue != nullptr) data.objectValue->decReferenceCount(); }
|
||||||
|
|
||||||
|
void createCopy (ValueUnion& dest, const ValueUnion& source) const override
|
||||||
|
{
|
||||||
|
dest.objectValue = source.objectValue;
|
||||||
|
if (dest.objectValue != nullptr)
|
||||||
|
dest.objectValue->incReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
String toString (const ValueUnion& data) const override { return "Object 0x" + String::toHexString ((int) (pointer_sized_int) data.objectValue); }
|
||||||
|
bool toBool (const ValueUnion& data) const noexcept override { return data.objectValue != 0; }
|
||||||
|
ReferenceCountedObject* toObject (const ValueUnion& data) const noexcept override { return data.objectValue; }
|
||||||
|
bool isObject() const noexcept override { return true; }
|
||||||
|
|
||||||
|
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
|
||||||
|
{
|
||||||
|
return otherType.toObject (otherData) == data.objectValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var clone (const var& original) const override
|
||||||
|
{
|
||||||
|
if (DynamicObject* d = original.getDynamicObject())
|
||||||
|
return d->clone().get();
|
||||||
|
|
||||||
|
jassertfalse; // can only clone DynamicObjects!
|
||||||
|
return var();
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToStream (const ValueUnion&, OutputStream& output) const override
|
||||||
|
{
|
||||||
|
jassertfalse; // Can't write an object to a stream!
|
||||||
|
output.writeCompressedInt (0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_Array : public var::VariantType_Object
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_Array() noexcept {}
|
||||||
|
static const VariantType_Array instance;
|
||||||
|
|
||||||
|
String toString (const ValueUnion&) const override { return "[Array]"; }
|
||||||
|
ReferenceCountedObject* toObject (const ValueUnion&) const noexcept override { return nullptr; }
|
||||||
|
bool isArray() const noexcept override { return true; }
|
||||||
|
|
||||||
|
Array<var>* toArray (const ValueUnion& data) const noexcept override
|
||||||
|
{
|
||||||
|
if (RefCountedArray* a = dynamic_cast<RefCountedArray*> (data.objectValue))
|
||||||
|
return &(a->array);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
|
||||||
|
{
|
||||||
|
const Array<var>* const thisArray = toArray (data);
|
||||||
|
const Array<var>* const otherArray = otherType.toArray (otherData);
|
||||||
|
return thisArray == otherArray || (thisArray != nullptr && otherArray != nullptr && *otherArray == *thisArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
var clone (const var& original) const override
|
||||||
|
{
|
||||||
|
Array<var> arrayCopy;
|
||||||
|
|
||||||
|
if (const Array<var>* array = toArray (original.value))
|
||||||
|
for (int i = 0; i < array->size(); ++i)
|
||||||
|
arrayCopy.add (array->getReference(i).clone());
|
||||||
|
|
||||||
|
return var (arrayCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToStream (const ValueUnion& data, OutputStream& output) const override
|
||||||
|
{
|
||||||
|
if (const Array<var>* array = toArray (data))
|
||||||
|
{
|
||||||
|
MemoryOutputStream buffer (512);
|
||||||
|
const int numItems = array->size();
|
||||||
|
buffer.writeCompressedInt (numItems);
|
||||||
|
|
||||||
|
for (int i = 0; i < numItems; ++i)
|
||||||
|
array->getReference(i).writeToStream (buffer);
|
||||||
|
|
||||||
|
output.writeCompressedInt (1 + (int) buffer.getDataSize());
|
||||||
|
output.writeByte (varMarker_Array);
|
||||||
|
output << buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RefCountedArray : public ReferenceCountedObject
|
||||||
|
{
|
||||||
|
RefCountedArray (const Array<var>& a) : array (a) { incReferenceCount(); }
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
RefCountedArray (Array<var>&& a) : array (static_cast<Array<var>&&> (a)) { incReferenceCount(); }
|
||||||
|
#endif
|
||||||
|
Array<var> array;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_Binary : public var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_Binary() noexcept {}
|
||||||
|
|
||||||
|
static const VariantType_Binary instance;
|
||||||
|
|
||||||
|
void cleanUp (ValueUnion& data) const noexcept override { delete data.binaryValue; }
|
||||||
|
void createCopy (ValueUnion& dest, const ValueUnion& source) const override { dest.binaryValue = new MemoryBlock (*source.binaryValue); }
|
||||||
|
|
||||||
|
String toString (const ValueUnion& data) const override { return data.binaryValue->toBase64Encoding(); }
|
||||||
|
bool isBinary() const noexcept override { return true; }
|
||||||
|
MemoryBlock* toBinary (const ValueUnion& data) const noexcept override { return data.binaryValue; }
|
||||||
|
|
||||||
|
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
|
||||||
|
{
|
||||||
|
const MemoryBlock* const otherBlock = otherType.toBinary (otherData);
|
||||||
|
return otherBlock != nullptr && *otherBlock == *data.binaryValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToStream (const ValueUnion& data, OutputStream& output) const override
|
||||||
|
{
|
||||||
|
output.writeCompressedInt (1 + (int) data.binaryValue->getSize());
|
||||||
|
output.writeByte (varMarker_Binary);
|
||||||
|
output << *data.binaryValue;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class var::VariantType_Method : public var::VariantType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariantType_Method() noexcept {}
|
||||||
|
static const VariantType_Method instance;
|
||||||
|
|
||||||
|
String toString (const ValueUnion&) const override { return "Method"; }
|
||||||
|
bool toBool (const ValueUnion& data) const noexcept override { return data.methodValue != nullptr; }
|
||||||
|
bool isMethod() const noexcept override { return true; }
|
||||||
|
|
||||||
|
bool equals (const ValueUnion& data, const ValueUnion& otherData, const VariantType& otherType) const noexcept override
|
||||||
|
{
|
||||||
|
return otherType.isMethod() && otherData.methodValue == data.methodValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeToStream (const ValueUnion&, OutputStream& output) const override
|
||||||
|
{
|
||||||
|
jassertfalse; // Can't write a method to a stream!
|
||||||
|
output.writeCompressedInt (0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
const var::VariantType_Void var::VariantType_Void::instance;
|
||||||
|
const var::VariantType_Undefined var::VariantType_Undefined::instance;
|
||||||
|
const var::VariantType_Int var::VariantType_Int::instance;
|
||||||
|
const var::VariantType_Int64 var::VariantType_Int64::instance;
|
||||||
|
const var::VariantType_Bool var::VariantType_Bool::instance;
|
||||||
|
const var::VariantType_Double var::VariantType_Double::instance;
|
||||||
|
const var::VariantType_String var::VariantType_String::instance;
|
||||||
|
const var::VariantType_Object var::VariantType_Object::instance;
|
||||||
|
const var::VariantType_Array var::VariantType_Array::instance;
|
||||||
|
const var::VariantType_Binary var::VariantType_Binary::instance;
|
||||||
|
const var::VariantType_Method var::VariantType_Method::instance;
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
var::var() noexcept : type (&VariantType_Void::instance) {}
|
||||||
|
var::var (const VariantType& t) noexcept : type (&t) {}
|
||||||
|
var::~var() noexcept { type->cleanUp (value); }
|
||||||
|
|
||||||
|
const var var::null;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
var::var (const var& valueToCopy) : type (valueToCopy.type)
|
||||||
|
{
|
||||||
|
type->createCopy (value, valueToCopy.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
var::var (const int v) noexcept : type (&VariantType_Int::instance) { value.intValue = v; }
|
||||||
|
var::var (const int64 v) noexcept : type (&VariantType_Int64::instance) { value.int64Value = v; }
|
||||||
|
var::var (const bool v) noexcept : type (&VariantType_Bool::instance) { value.boolValue = v; }
|
||||||
|
var::var (const double v) noexcept : type (&VariantType_Double::instance) { value.doubleValue = v; }
|
||||||
|
var::var (NativeFunction m) noexcept : type (&VariantType_Method::instance) { value.methodValue = m; }
|
||||||
|
var::var (const Array<var>& v) : type (&VariantType_Array::instance) { value.objectValue = new VariantType_Array::RefCountedArray(v); }
|
||||||
|
var::var (const String& v) : type (&VariantType_String::instance) { new (value.stringValue) String (v); }
|
||||||
|
var::var (const char* const v) : type (&VariantType_String::instance) { new (value.stringValue) String (v); }
|
||||||
|
var::var (const wchar_t* const v) : type (&VariantType_String::instance) { new (value.stringValue) String (v); }
|
||||||
|
var::var (const void* v, size_t sz) : type (&VariantType_Binary::instance) { value.binaryValue = new MemoryBlock (v, sz); }
|
||||||
|
var::var (const MemoryBlock& v) : type (&VariantType_Binary::instance) { value.binaryValue = new MemoryBlock (v); }
|
||||||
|
|
||||||
|
var::var (ReferenceCountedObject* const object) : type (&VariantType_Object::instance)
|
||||||
|
{
|
||||||
|
value.objectValue = object;
|
||||||
|
|
||||||
|
if (object != nullptr)
|
||||||
|
object->incReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::undefined() noexcept { return var (VariantType_Undefined::instance); }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool var::isVoid() const noexcept { return type->isVoid(); }
|
||||||
|
bool var::isUndefined() const noexcept { return type->isUndefined(); }
|
||||||
|
bool var::isInt() const noexcept { return type->isInt(); }
|
||||||
|
bool var::isInt64() const noexcept { return type->isInt64(); }
|
||||||
|
bool var::isBool() const noexcept { return type->isBool(); }
|
||||||
|
bool var::isDouble() const noexcept { return type->isDouble(); }
|
||||||
|
bool var::isString() const noexcept { return type->isString(); }
|
||||||
|
bool var::isObject() const noexcept { return type->isObject(); }
|
||||||
|
bool var::isArray() const noexcept { return type->isArray(); }
|
||||||
|
bool var::isBinaryData() const noexcept { return type->isBinary(); }
|
||||||
|
bool var::isMethod() const noexcept { return type->isMethod(); }
|
||||||
|
|
||||||
|
var::operator int() const noexcept { return type->toInt (value); }
|
||||||
|
var::operator int64() const noexcept { return type->toInt64 (value); }
|
||||||
|
var::operator bool() const noexcept { return type->toBool (value); }
|
||||||
|
var::operator float() const noexcept { return (float) type->toDouble (value); }
|
||||||
|
var::operator double() const noexcept { return type->toDouble (value); }
|
||||||
|
String var::toString() const { return type->toString (value); }
|
||||||
|
var::operator String() const { return type->toString (value); }
|
||||||
|
ReferenceCountedObject* var::getObject() const noexcept { return type->toObject (value); }
|
||||||
|
Array<var>* var::getArray() const noexcept { return type->toArray (value); }
|
||||||
|
MemoryBlock* var::getBinaryData() const noexcept { return type->toBinary (value); }
|
||||||
|
DynamicObject* var::getDynamicObject() const noexcept { return dynamic_cast <DynamicObject*> (getObject()); }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void var::swapWith (var& other) noexcept
|
||||||
|
{
|
||||||
|
std::swap (type, other.type);
|
||||||
|
std::swap (value, other.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
var& var::operator= (const var& v) { type->cleanUp (value); type = v.type; type->createCopy (value, v.value); return *this; }
|
||||||
|
var& var::operator= (const int v) { type->cleanUp (value); type = &VariantType_Int::instance; value.intValue = v; return *this; }
|
||||||
|
var& var::operator= (const int64 v) { type->cleanUp (value); type = &VariantType_Int64::instance; value.int64Value = v; return *this; }
|
||||||
|
var& var::operator= (const bool v) { type->cleanUp (value); type = &VariantType_Bool::instance; value.boolValue = v; return *this; }
|
||||||
|
var& var::operator= (const double v) { type->cleanUp (value); type = &VariantType_Double::instance; value.doubleValue = v; return *this; }
|
||||||
|
var& var::operator= (const char* const v) { type->cleanUp (value); type = &VariantType_String::instance; new (value.stringValue) String (v); return *this; }
|
||||||
|
var& var::operator= (const wchar_t* const v) { type->cleanUp (value); type = &VariantType_String::instance; new (value.stringValue) String (v); return *this; }
|
||||||
|
var& var::operator= (const String& v) { type->cleanUp (value); type = &VariantType_String::instance; new (value.stringValue) String (v); return *this; }
|
||||||
|
var& var::operator= (const Array<var>& v) { var v2 (v); swapWith (v2); return *this; }
|
||||||
|
var& var::operator= (ReferenceCountedObject* v) { var v2 (v); swapWith (v2); return *this; }
|
||||||
|
var& var::operator= (NativeFunction v) { var v2 (v); swapWith (v2); return *this; }
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
var::var (var&& other) noexcept
|
||||||
|
: type (other.type),
|
||||||
|
value (other.value)
|
||||||
|
{
|
||||||
|
other.type = &VariantType_Void::instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
var& var::operator= (var&& other) noexcept
|
||||||
|
{
|
||||||
|
swapWith (other);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
var::var (String&& v) : type (&VariantType_String::instance)
|
||||||
|
{
|
||||||
|
new (value.stringValue) String (static_cast<String&&> (v));
|
||||||
|
}
|
||||||
|
|
||||||
|
var::var (MemoryBlock&& v) : type (&VariantType_Binary::instance)
|
||||||
|
{
|
||||||
|
value.binaryValue = new MemoryBlock (static_cast<MemoryBlock&&> (v));
|
||||||
|
}
|
||||||
|
|
||||||
|
var::var (Array<var>&& v) : type (&VariantType_Array::instance)
|
||||||
|
{
|
||||||
|
value.objectValue = new VariantType_Array::RefCountedArray (static_cast<Array<var>&&> (v));
|
||||||
|
}
|
||||||
|
|
||||||
|
var& var::operator= (String&& v)
|
||||||
|
{
|
||||||
|
type->cleanUp (value);
|
||||||
|
type = &VariantType_String::instance;
|
||||||
|
new (value.stringValue) String (static_cast<String&&> (v));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool var::equals (const var& other) const noexcept
|
||||||
|
{
|
||||||
|
return type->equals (value, other.value, *other.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool var::equalsWithSameType (const var& other) const noexcept
|
||||||
|
{
|
||||||
|
return type == other.type && equals (other);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool var::hasSameTypeAs (const var& other) const noexcept
|
||||||
|
{
|
||||||
|
return type == other.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator== (const var& v1, const var& v2) noexcept { return v1.equals (v2); }
|
||||||
|
bool operator!= (const var& v1, const var& v2) noexcept { return ! v1.equals (v2); }
|
||||||
|
bool operator== (const var& v1, const String& v2) { return v1.toString() == v2; }
|
||||||
|
bool operator!= (const var& v1, const String& v2) { return v1.toString() != v2; }
|
||||||
|
bool operator== (const var& v1, const char* const v2) { return v1.toString() == v2; }
|
||||||
|
bool operator!= (const var& v1, const char* const v2) { return v1.toString() != v2; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
var var::clone() const noexcept
|
||||||
|
{
|
||||||
|
return type->clone (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
var var::operator[] (const Identifier propertyName) const
|
||||||
|
{
|
||||||
|
if (DynamicObject* const o = getDynamicObject())
|
||||||
|
return o->getProperty (propertyName);
|
||||||
|
|
||||||
|
return var();
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::operator[] (const char* const propertyName) const
|
||||||
|
{
|
||||||
|
return operator[] (Identifier (propertyName));
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::getProperty (const Identifier propertyName, const var& defaultReturnValue) const
|
||||||
|
{
|
||||||
|
if (DynamicObject* const o = getDynamicObject())
|
||||||
|
return o->getProperties().getWithDefault (propertyName, defaultReturnValue);
|
||||||
|
|
||||||
|
return defaultReturnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var::NativeFunction var::getNativeFunction() const
|
||||||
|
{
|
||||||
|
return isMethod() ? value.methodValue : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::invoke (Identifier method, const var* arguments, int numArguments) const
|
||||||
|
{
|
||||||
|
if (DynamicObject* const o = getDynamicObject())
|
||||||
|
return o->invokeMethod (method, var::NativeFunctionArgs (*this, arguments, numArguments));
|
||||||
|
|
||||||
|
return var();
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::call (const Identifier method) const
|
||||||
|
{
|
||||||
|
return invoke (method, nullptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::call (const Identifier method, const var& arg1) const
|
||||||
|
{
|
||||||
|
return invoke (method, &arg1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::call (const Identifier method, const var& arg1, const var& arg2) const
|
||||||
|
{
|
||||||
|
var args[] = { arg1, arg2 };
|
||||||
|
return invoke (method, args, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::call (const Identifier method, const var& arg1, const var& arg2, const var& arg3)
|
||||||
|
{
|
||||||
|
var args[] = { arg1, arg2, arg3 };
|
||||||
|
return invoke (method, args, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::call (const Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const
|
||||||
|
{
|
||||||
|
var args[] = { arg1, arg2, arg3, arg4 };
|
||||||
|
return invoke (method, args, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::call (const Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const
|
||||||
|
{
|
||||||
|
var args[] = { arg1, arg2, arg3, arg4, arg5 };
|
||||||
|
return invoke (method, args, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
int var::size() const
|
||||||
|
{
|
||||||
|
if (const Array<var>* const array = getArray())
|
||||||
|
return array->size();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const var& var::operator[] (int arrayIndex) const
|
||||||
|
{
|
||||||
|
const Array<var>* const array = getArray();
|
||||||
|
|
||||||
|
// When using this method, the var must actually be an array, and the index
|
||||||
|
// must be in-range!
|
||||||
|
jassert (array != nullptr && isPositiveAndBelow (arrayIndex, array->size()));
|
||||||
|
|
||||||
|
return array->getReference (arrayIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
var& var::operator[] (int arrayIndex)
|
||||||
|
{
|
||||||
|
const Array<var>* const array = getArray();
|
||||||
|
|
||||||
|
// When using this method, the var must actually be an array, and the index
|
||||||
|
// must be in-range!
|
||||||
|
jassert (array != nullptr && isPositiveAndBelow (arrayIndex, array->size()));
|
||||||
|
|
||||||
|
return array->getReference (arrayIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
Array<var>* var::convertToArray()
|
||||||
|
{
|
||||||
|
if (Array<var>* array = getArray())
|
||||||
|
return array;
|
||||||
|
|
||||||
|
Array<var> tempVar;
|
||||||
|
if (! isVoid())
|
||||||
|
tempVar.add (*this);
|
||||||
|
|
||||||
|
*this = tempVar;
|
||||||
|
return getArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
void var::append (const var& n)
|
||||||
|
{
|
||||||
|
convertToArray()->add (n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void var::remove (const int index)
|
||||||
|
{
|
||||||
|
if (Array<var>* const array = getArray())
|
||||||
|
array->remove (index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void var::insert (const int index, const var& n)
|
||||||
|
{
|
||||||
|
convertToArray()->insert (index, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void var::resize (const int numArrayElementsWanted)
|
||||||
|
{
|
||||||
|
convertToArray()->resize (numArrayElementsWanted);
|
||||||
|
}
|
||||||
|
|
||||||
|
int var::indexOf (const var& n) const
|
||||||
|
{
|
||||||
|
if (const Array<var>* const array = getArray())
|
||||||
|
return array->indexOf (n);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void var::writeToStream (OutputStream& output) const
|
||||||
|
{
|
||||||
|
type->writeToStream (value, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
var var::readFromStream (InputStream& input)
|
||||||
|
{
|
||||||
|
const int numBytes = input.readCompressedInt();
|
||||||
|
|
||||||
|
if (numBytes > 0)
|
||||||
|
{
|
||||||
|
switch (input.readByte())
|
||||||
|
{
|
||||||
|
case varMarker_Int: return var (input.readInt());
|
||||||
|
case varMarker_Int64: return var (input.readInt64());
|
||||||
|
case varMarker_BoolTrue: return var (true);
|
||||||
|
case varMarker_BoolFalse: return var (false);
|
||||||
|
case varMarker_Double: return var (input.readDouble());
|
||||||
|
case varMarker_String:
|
||||||
|
{
|
||||||
|
MemoryOutputStream mo;
|
||||||
|
mo.writeFromInputStream (input, numBytes - 1);
|
||||||
|
return var (mo.toUTF8());
|
||||||
|
}
|
||||||
|
|
||||||
|
case varMarker_Binary:
|
||||||
|
{
|
||||||
|
MemoryBlock mb ((size_t) numBytes - 1);
|
||||||
|
|
||||||
|
if (numBytes > 1)
|
||||||
|
{
|
||||||
|
const int numRead = input.read (mb.getData(), numBytes - 1);
|
||||||
|
mb.setSize ((size_t) numRead);
|
||||||
|
}
|
||||||
|
|
||||||
|
return var (mb);
|
||||||
|
}
|
||||||
|
|
||||||
|
case varMarker_Array:
|
||||||
|
{
|
||||||
|
var v;
|
||||||
|
Array<var>* const destArray = v.convertToArray();
|
||||||
|
|
||||||
|
for (int i = input.readCompressedInt(); --i >= 0;)
|
||||||
|
destArray->add (readFromStream (input));
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
input.skipNextBytes (numBytes - 1); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return var();
|
||||||
|
}
|
||||||
|
|
||||||
|
var::NativeFunctionArgs::NativeFunctionArgs (const var& t, const var* args, int numArgs) noexcept
|
||||||
|
: thisObject (t), arguments (args), numArguments (numArgs)
|
||||||
|
{}
|
||||||
@@ -0,0 +1,327 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_VARIANT_H_INCLUDED
|
||||||
|
#define JUCE_VARIANT_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A variant class, that can be used to hold a range of primitive values.
|
||||||
|
|
||||||
|
A var object can hold a range of simple primitive values, strings, or
|
||||||
|
any kind of ReferenceCountedObject. The var class is intended to act like
|
||||||
|
the kind of values used in dynamic scripting languages.
|
||||||
|
|
||||||
|
You can save/load var objects either in a small, proprietary binary format
|
||||||
|
using writeToStream()/readFromStream(), or as JSON by using the JSON class.
|
||||||
|
|
||||||
|
@see JSON, DynamicObject
|
||||||
|
*/
|
||||||
|
class JUCE_API var
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** This structure is passed to a NativeFunction callback, and contains invocation
|
||||||
|
details about the function's arguments and context.
|
||||||
|
*/
|
||||||
|
struct NativeFunctionArgs
|
||||||
|
{
|
||||||
|
NativeFunctionArgs (const var& thisObject, const var* args, int numArgs) noexcept;
|
||||||
|
|
||||||
|
const var& thisObject;
|
||||||
|
const var* arguments;
|
||||||
|
int numArguments;
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (NativeFunctionArgs)
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef var (*NativeFunction) (const NativeFunctionArgs&);
|
||||||
|
typedef Identifier identifier;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a void variant. */
|
||||||
|
var() noexcept;
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~var() noexcept;
|
||||||
|
|
||||||
|
/** A static var object that can be used where you need an empty variant object. */
|
||||||
|
static const var null;
|
||||||
|
|
||||||
|
var (const var& valueToCopy);
|
||||||
|
var (int value) noexcept;
|
||||||
|
var (int64 value) noexcept;
|
||||||
|
var (bool value) noexcept;
|
||||||
|
var (double value) noexcept;
|
||||||
|
var (const char* value);
|
||||||
|
var (const wchar_t* value);
|
||||||
|
var (const String& value);
|
||||||
|
var (const Array<var>& value);
|
||||||
|
var (ReferenceCountedObject* object);
|
||||||
|
var (NativeFunction method) noexcept;
|
||||||
|
var (const void* binaryData, size_t dataSize);
|
||||||
|
var (const MemoryBlock& binaryData);
|
||||||
|
|
||||||
|
var& operator= (const var& valueToCopy);
|
||||||
|
var& operator= (int value);
|
||||||
|
var& operator= (int64 value);
|
||||||
|
var& operator= (bool value);
|
||||||
|
var& operator= (double value);
|
||||||
|
var& operator= (const char* value);
|
||||||
|
var& operator= (const wchar_t* value);
|
||||||
|
var& operator= (const String& value);
|
||||||
|
var& operator= (const Array<var>& value);
|
||||||
|
var& operator= (ReferenceCountedObject* object);
|
||||||
|
var& operator= (NativeFunction method);
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
var (var&& other) noexcept;
|
||||||
|
var (String&& value);
|
||||||
|
var (MemoryBlock&& binaryData);
|
||||||
|
var (Array<var>&& value);
|
||||||
|
var& operator= (var&& other) noexcept;
|
||||||
|
var& operator= (String&& value);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void swapWith (var& other) noexcept;
|
||||||
|
|
||||||
|
/** Returns a var object that can be used where you need the javascript "undefined" value. */
|
||||||
|
static var undefined() noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
operator int() const noexcept;
|
||||||
|
operator int64() const noexcept;
|
||||||
|
operator bool() const noexcept;
|
||||||
|
operator float() const noexcept;
|
||||||
|
operator double() const noexcept;
|
||||||
|
operator String() const;
|
||||||
|
String toString() const;
|
||||||
|
|
||||||
|
/** If this variant holds an array, this provides access to it.
|
||||||
|
NOTE: Beware when you use this - the array pointer is only valid for the lifetime
|
||||||
|
of the variant that returned it, so be very careful not to call this method on temporary
|
||||||
|
var objects that are the return-value of a function, and which may go out of scope before
|
||||||
|
you use the array!
|
||||||
|
*/
|
||||||
|
Array<var>* getArray() const noexcept;
|
||||||
|
|
||||||
|
/** If this variant holds a memory block, this provides access to it.
|
||||||
|
NOTE: Beware when you use this - the MemoryBlock pointer is only valid for the lifetime
|
||||||
|
of the variant that returned it, so be very careful not to call this method on temporary
|
||||||
|
var objects that are the return-value of a function, and which may go out of scope before
|
||||||
|
you use the MemoryBlock!
|
||||||
|
*/
|
||||||
|
MemoryBlock* getBinaryData() const noexcept;
|
||||||
|
|
||||||
|
ReferenceCountedObject* getObject() const noexcept;
|
||||||
|
DynamicObject* getDynamicObject() const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool isVoid() const noexcept;
|
||||||
|
bool isUndefined() const noexcept;
|
||||||
|
bool isInt() const noexcept;
|
||||||
|
bool isInt64() const noexcept;
|
||||||
|
bool isBool() const noexcept;
|
||||||
|
bool isDouble() const noexcept;
|
||||||
|
bool isString() const noexcept;
|
||||||
|
bool isObject() const noexcept;
|
||||||
|
bool isArray() const noexcept;
|
||||||
|
bool isBinaryData() const noexcept;
|
||||||
|
bool isMethod() const noexcept;
|
||||||
|
|
||||||
|
/** Returns true if this var has the same value as the one supplied.
|
||||||
|
Note that this ignores the type, so a string var "123" and an integer var with the
|
||||||
|
value 123 are considered to be equal.
|
||||||
|
@see equalsWithSameType
|
||||||
|
*/
|
||||||
|
bool equals (const var& other) const noexcept;
|
||||||
|
|
||||||
|
/** Returns true if this var has the same value and type as the one supplied.
|
||||||
|
This differs from equals() because e.g. "123" and 123 will be considered different.
|
||||||
|
@see equals
|
||||||
|
*/
|
||||||
|
bool equalsWithSameType (const var& other) const noexcept;
|
||||||
|
|
||||||
|
/** Returns true if this var has the same type as the one supplied. */
|
||||||
|
bool hasSameTypeAs (const var& other) const noexcept;
|
||||||
|
|
||||||
|
/** Returns a deep copy of this object.
|
||||||
|
For simple types this just returns a copy, but if the object contains any arrays
|
||||||
|
or DynamicObjects, they will be cloned (recursively).
|
||||||
|
*/
|
||||||
|
var clone() const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** If the var is an array, this returns the number of elements.
|
||||||
|
If the var isn't actually an array, this will return 0.
|
||||||
|
*/
|
||||||
|
int size() const;
|
||||||
|
|
||||||
|
/** If the var is an array, this can be used to return one of its elements.
|
||||||
|
To call this method, you must make sure that the var is actually an array, and
|
||||||
|
that the index is a valid number. If these conditions aren't met, behaviour is
|
||||||
|
undefined.
|
||||||
|
For more control over the array's contents, you can call getArray() and manipulate
|
||||||
|
it directly as an Array\<var\>.
|
||||||
|
*/
|
||||||
|
const var& operator[] (int arrayIndex) const;
|
||||||
|
|
||||||
|
/** If the var is an array, this can be used to return one of its elements.
|
||||||
|
To call this method, you must make sure that the var is actually an array, and
|
||||||
|
that the index is a valid number. If these conditions aren't met, behaviour is
|
||||||
|
undefined.
|
||||||
|
For more control over the array's contents, you can call getArray() and manipulate
|
||||||
|
it directly as an Array\<var\>.
|
||||||
|
*/
|
||||||
|
var& operator[] (int arrayIndex);
|
||||||
|
|
||||||
|
/** Appends an element to the var, converting it to an array if it isn't already one.
|
||||||
|
If the var isn't an array, it will be converted to one, and if its value was non-void,
|
||||||
|
this value will be kept as the first element of the new array. The parameter value
|
||||||
|
will then be appended to it.
|
||||||
|
For more control over the array's contents, you can call getArray() and manipulate
|
||||||
|
it directly as an Array\<var\>.
|
||||||
|
*/
|
||||||
|
void append (const var& valueToAppend);
|
||||||
|
|
||||||
|
/** Inserts an element to the var, converting it to an array if it isn't already one.
|
||||||
|
If the var isn't an array, it will be converted to one, and if its value was non-void,
|
||||||
|
this value will be kept as the first element of the new array. The parameter value
|
||||||
|
will then be inserted into it.
|
||||||
|
For more control over the array's contents, you can call getArray() and manipulate
|
||||||
|
it directly as an Array\<var\>.
|
||||||
|
*/
|
||||||
|
void insert (int index, const var& value);
|
||||||
|
|
||||||
|
/** If the var is an array, this removes one of its elements.
|
||||||
|
If the index is out-of-range or the var isn't an array, nothing will be done.
|
||||||
|
For more control over the array's contents, you can call getArray() and manipulate
|
||||||
|
it directly as an Array\<var\>.
|
||||||
|
*/
|
||||||
|
void remove (int index);
|
||||||
|
|
||||||
|
/** Treating the var as an array, this resizes it to contain the specified number of elements.
|
||||||
|
If the var isn't an array, it will be converted to one, and if its value was non-void,
|
||||||
|
this value will be kept as the first element of the new array before resizing.
|
||||||
|
For more control over the array's contents, you can call getArray() and manipulate
|
||||||
|
it directly as an Array\<var\>.
|
||||||
|
*/
|
||||||
|
void resize (int numArrayElementsWanted);
|
||||||
|
|
||||||
|
/** If the var is an array, this searches it for the first occurrence of the specified value,
|
||||||
|
and returns its index.
|
||||||
|
If the var isn't an array, or if the value isn't found, this returns -1.
|
||||||
|
*/
|
||||||
|
int indexOf (const var& value) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** If this variant is an object, this returns one of its properties. */
|
||||||
|
var operator[] (Identifier propertyName) const;
|
||||||
|
/** If this variant is an object, this returns one of its properties. */
|
||||||
|
var operator[] (const char* propertyName) const;
|
||||||
|
/** If this variant is an object, this returns one of its properties, or a default
|
||||||
|
fallback value if the property is not set. */
|
||||||
|
var getProperty (Identifier propertyName, const var& defaultReturnValue) const;
|
||||||
|
|
||||||
|
/** Invokes a named method call with no arguments. */
|
||||||
|
var call (Identifier method) const;
|
||||||
|
/** Invokes a named method call with one argument. */
|
||||||
|
var call (Identifier method, const var& arg1) const;
|
||||||
|
/** Invokes a named method call with 2 arguments. */
|
||||||
|
var call (Identifier method, const var& arg1, const var& arg2) const;
|
||||||
|
/** Invokes a named method call with 3 arguments. */
|
||||||
|
var call (Identifier method, const var& arg1, const var& arg2, const var& arg3);
|
||||||
|
/** Invokes a named method call with 4 arguments. */
|
||||||
|
var call (Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const;
|
||||||
|
/** Invokes a named method call with 5 arguments. */
|
||||||
|
var call (Identifier method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const;
|
||||||
|
/** Invokes a named method call with a list of arguments. */
|
||||||
|
var invoke (Identifier method, const var* arguments, int numArguments) const;
|
||||||
|
/** If this object is a method, this returns the function pointer. */
|
||||||
|
NativeFunction getNativeFunction() const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Writes a binary representation of this value to a stream.
|
||||||
|
The data can be read back later using readFromStream().
|
||||||
|
@see JSON
|
||||||
|
*/
|
||||||
|
void writeToStream (OutputStream& output) const;
|
||||||
|
|
||||||
|
/** Reads back a stored binary representation of a value.
|
||||||
|
The data in the stream must have been written using writeToStream(), or this
|
||||||
|
will have unpredictable results.
|
||||||
|
@see JSON
|
||||||
|
*/
|
||||||
|
static var readFromStream (InputStream& input);
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
class VariantType; friend class VariantType;
|
||||||
|
class VariantType_Void; friend class VariantType_Void;
|
||||||
|
class VariantType_Undefined; friend class VariantType_Undefined;
|
||||||
|
class VariantType_Int; friend class VariantType_Int;
|
||||||
|
class VariantType_Int64; friend class VariantType_Int64;
|
||||||
|
class VariantType_Double; friend class VariantType_Double;
|
||||||
|
class VariantType_Bool; friend class VariantType_Bool;
|
||||||
|
class VariantType_String; friend class VariantType_String;
|
||||||
|
class VariantType_Object; friend class VariantType_Object;
|
||||||
|
class VariantType_Array; friend class VariantType_Array;
|
||||||
|
class VariantType_Binary; friend class VariantType_Binary;
|
||||||
|
class VariantType_Method; friend class VariantType_Method;
|
||||||
|
|
||||||
|
union ValueUnion
|
||||||
|
{
|
||||||
|
int intValue;
|
||||||
|
int64 int64Value;
|
||||||
|
bool boolValue;
|
||||||
|
double doubleValue;
|
||||||
|
char stringValue [sizeof (String)];
|
||||||
|
ReferenceCountedObject* objectValue;
|
||||||
|
MemoryBlock* binaryValue;
|
||||||
|
NativeFunction methodValue;
|
||||||
|
};
|
||||||
|
|
||||||
|
const VariantType* type;
|
||||||
|
ValueUnion value;
|
||||||
|
|
||||||
|
Array<var>* convertToArray();
|
||||||
|
var (const VariantType&) noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Compares the values of two var objects, using the var::equals() comparison. */
|
||||||
|
bool operator== (const var& v1, const var& v2) noexcept;
|
||||||
|
/** Compares the values of two var objects, using the var::equals() comparison. */
|
||||||
|
bool operator!= (const var& v1, const var& v2) noexcept;
|
||||||
|
bool operator== (const var& v1, const String& v2);
|
||||||
|
bool operator!= (const var& v1, const String& v2);
|
||||||
|
bool operator== (const var& v1, const char* v2);
|
||||||
|
bool operator!= (const var& v1, const char* v2);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_VARIANT_H_INCLUDED
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
DirectoryIterator::DirectoryIterator (const File& directory, bool recursive,
|
||||||
|
const String& pattern, const int type)
|
||||||
|
: wildCards (parseWildcards (pattern)),
|
||||||
|
fileFinder (directory, (recursive || wildCards.size() > 1) ? "*" : pattern),
|
||||||
|
wildCard (pattern),
|
||||||
|
path (File::addTrailingSeparator (directory.getFullPathName())),
|
||||||
|
index (-1),
|
||||||
|
totalNumFiles (-1),
|
||||||
|
whatToLookFor (type),
|
||||||
|
isRecursive (recursive),
|
||||||
|
hasBeenAdvanced (false)
|
||||||
|
{
|
||||||
|
// you have to specify the type of files you're looking for!
|
||||||
|
jassert ((type & (File::findFiles | File::findDirectories)) != 0);
|
||||||
|
jassert (type > 0 && type <= 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectoryIterator::~DirectoryIterator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
StringArray DirectoryIterator::parseWildcards (const String& pattern)
|
||||||
|
{
|
||||||
|
StringArray s;
|
||||||
|
s.addTokens (pattern, ";,", "\"'");
|
||||||
|
s.trim();
|
||||||
|
s.removeEmptyStrings();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DirectoryIterator::fileMatches (const StringArray& wildCards, const String& filename)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < wildCards.size(); ++i)
|
||||||
|
if (filename.matchesWildcard (wildCards[i], ! File::areFileNamesCaseSensitive()))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DirectoryIterator::next()
|
||||||
|
{
|
||||||
|
return next (nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DirectoryIterator::next (bool* const isDirResult, bool* const isHiddenResult, int64* const fileSize,
|
||||||
|
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
hasBeenAdvanced = true;
|
||||||
|
|
||||||
|
if (subIterator != nullptr)
|
||||||
|
{
|
||||||
|
if (subIterator->next (isDirResult, isHiddenResult, fileSize, modTime, creationTime, isReadOnly))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
subIterator = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
String filename;
|
||||||
|
bool isDirectory, isHidden = false, shouldContinue = false;
|
||||||
|
|
||||||
|
while (fileFinder.next (filename, &isDirectory,
|
||||||
|
(isHiddenResult != nullptr || (whatToLookFor & File::ignoreHiddenFiles) != 0) ? &isHidden : nullptr,
|
||||||
|
fileSize, modTime, creationTime, isReadOnly))
|
||||||
|
{
|
||||||
|
++index;
|
||||||
|
|
||||||
|
if (! filename.containsOnly ("."))
|
||||||
|
{
|
||||||
|
bool matches = false;
|
||||||
|
|
||||||
|
if (isDirectory)
|
||||||
|
{
|
||||||
|
if (isRecursive && ((whatToLookFor & File::ignoreHiddenFiles) == 0 || ! isHidden))
|
||||||
|
subIterator = new DirectoryIterator (File::createFileWithoutCheckingPath (path + filename),
|
||||||
|
true, wildCard, whatToLookFor);
|
||||||
|
|
||||||
|
matches = (whatToLookFor & File::findDirectories) != 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
matches = (whatToLookFor & File::findFiles) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we're not relying on the OS iterator to do the wildcard match, do it now..
|
||||||
|
if (matches && (isRecursive || wildCards.size() > 1))
|
||||||
|
matches = fileMatches (wildCards, filename);
|
||||||
|
|
||||||
|
if (matches && (whatToLookFor & File::ignoreHiddenFiles) != 0)
|
||||||
|
matches = ! isHidden;
|
||||||
|
|
||||||
|
if (matches)
|
||||||
|
{
|
||||||
|
currentFile = File::createFileWithoutCheckingPath (path + filename);
|
||||||
|
if (isHiddenResult != nullptr) *isHiddenResult = isHidden;
|
||||||
|
if (isDirResult != nullptr) *isDirResult = isDirectory;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subIterator != nullptr)
|
||||||
|
{
|
||||||
|
shouldContinue = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! shouldContinue)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const File& DirectoryIterator::getFile() const
|
||||||
|
{
|
||||||
|
if (subIterator != nullptr && subIterator->hasBeenAdvanced)
|
||||||
|
return subIterator->getFile();
|
||||||
|
|
||||||
|
// You need to call DirectoryIterator::next() before asking it for the file that it found!
|
||||||
|
jassert (hasBeenAdvanced);
|
||||||
|
|
||||||
|
return currentFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
float DirectoryIterator::getEstimatedProgress() const
|
||||||
|
{
|
||||||
|
if (totalNumFiles < 0)
|
||||||
|
totalNumFiles = File (path).getNumberOfChildFiles (File::findFilesAndDirectories);
|
||||||
|
|
||||||
|
if (totalNumFiles <= 0)
|
||||||
|
return 0.0f;
|
||||||
|
|
||||||
|
const float detailedIndex = (subIterator != nullptr) ? index + subIterator->getEstimatedProgress()
|
||||||
|
: (float) index;
|
||||||
|
|
||||||
|
return detailedIndex / totalNumFiles;
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_DIRECTORYITERATOR_H_INCLUDED
|
||||||
|
#define JUCE_DIRECTORYITERATOR_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Searches through the files in a directory, returning each file that is found.
|
||||||
|
|
||||||
|
A DirectoryIterator will search through a directory and its subdirectories using
|
||||||
|
a wildcard filepattern match.
|
||||||
|
|
||||||
|
If you may be scanning a large number of files, it's usually smarter to use this
|
||||||
|
class than File::findChildFiles() because it allows you to stop at any time, rather
|
||||||
|
than having to wait for the entire scan to finish before getting the results.
|
||||||
|
|
||||||
|
It also provides an estimate of its progress, using a (highly inaccurate!) algorithm.
|
||||||
|
*/
|
||||||
|
class JUCE_API DirectoryIterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a DirectoryIterator for a given directory.
|
||||||
|
|
||||||
|
After creating one of these, call its next() method to get the
|
||||||
|
first file - e.g. @code
|
||||||
|
|
||||||
|
DirectoryIterator iter (File ("/animals/mooses"), true, "*.moose");
|
||||||
|
|
||||||
|
while (iter.next())
|
||||||
|
{
|
||||||
|
File theFileItFound (iter.getFile());
|
||||||
|
|
||||||
|
... etc
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@param directory the directory to search in
|
||||||
|
@param isRecursive whether all the subdirectories should also be searched
|
||||||
|
@param wildCard the file pattern to match. This may contain multiple patterns
|
||||||
|
separated by a semi-colon or comma, e.g. "*.jpg;*.png"
|
||||||
|
@param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying
|
||||||
|
whether to look for files, directories, or both.
|
||||||
|
*/
|
||||||
|
DirectoryIterator (const File& directory,
|
||||||
|
bool isRecursive,
|
||||||
|
const String& wildCard = "*",
|
||||||
|
int whatToLookFor = File::findFiles);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~DirectoryIterator();
|
||||||
|
|
||||||
|
/** Moves the iterator along to the next file.
|
||||||
|
|
||||||
|
@returns true if a file was found (you can then use getFile() to see what it was) - or
|
||||||
|
false if there are no more matching files.
|
||||||
|
*/
|
||||||
|
bool next();
|
||||||
|
|
||||||
|
/** Moves the iterator along to the next file, and returns various properties of that file.
|
||||||
|
|
||||||
|
If you need to find out details about the file, it's more efficient to call this method than
|
||||||
|
to call the normal next() method and then find out the details afterwards.
|
||||||
|
|
||||||
|
All the parameters are optional, so pass null pointers for any items that you're not
|
||||||
|
interested in.
|
||||||
|
|
||||||
|
@returns true if a file was found (you can then use getFile() to see what it was) - or
|
||||||
|
false if there are no more matching files. If it returns false, then none of the
|
||||||
|
parameters will be filled-in.
|
||||||
|
*/
|
||||||
|
bool next (bool* isDirectory,
|
||||||
|
bool* isHidden,
|
||||||
|
int64* fileSize,
|
||||||
|
Time* modTime,
|
||||||
|
Time* creationTime,
|
||||||
|
bool* isReadOnly);
|
||||||
|
|
||||||
|
/** Returns the file that the iterator is currently pointing at.
|
||||||
|
|
||||||
|
The result of this call is only valid after a call to next() has returned true.
|
||||||
|
*/
|
||||||
|
const File& getFile() const;
|
||||||
|
|
||||||
|
/** Returns a guess of how far through the search the iterator has got.
|
||||||
|
|
||||||
|
@returns a value 0.0 to 1.0 to show the progress, although this won't be
|
||||||
|
very accurate.
|
||||||
|
*/
|
||||||
|
float getEstimatedProgress() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
class NativeIterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NativeIterator (const File& directory, const String& wildCard);
|
||||||
|
~NativeIterator();
|
||||||
|
|
||||||
|
bool next (String& filenameFound,
|
||||||
|
bool* isDirectory, bool* isHidden, int64* fileSize,
|
||||||
|
Time* modTime, Time* creationTime, bool* isReadOnly);
|
||||||
|
|
||||||
|
class Pimpl;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class DirectoryIterator;
|
||||||
|
friend struct ContainerDeletePolicy<Pimpl>;
|
||||||
|
ScopedPointer<Pimpl> pimpl;
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeIterator)
|
||||||
|
};
|
||||||
|
|
||||||
|
friend struct ContainerDeletePolicy<NativeIterator::Pimpl>;
|
||||||
|
StringArray wildCards;
|
||||||
|
NativeIterator fileFinder;
|
||||||
|
String wildCard, path;
|
||||||
|
int index;
|
||||||
|
mutable int totalNumFiles;
|
||||||
|
const int whatToLookFor;
|
||||||
|
const bool isRecursive;
|
||||||
|
bool hasBeenAdvanced;
|
||||||
|
ScopedPointer<DirectoryIterator> subIterator;
|
||||||
|
File currentFile;
|
||||||
|
|
||||||
|
static StringArray parseWildcards (const String& pattern);
|
||||||
|
static bool fileMatches (const StringArray& wildCards, const String& filename);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectoryIterator)
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // JUCE_DIRECTORYITERATOR_H_INCLUDED
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,981 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_FILE_H_INCLUDED
|
||||||
|
#define JUCE_FILE_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Represents a local file or directory.
|
||||||
|
|
||||||
|
This class encapsulates the absolute pathname of a file or directory, and
|
||||||
|
has methods for finding out about the file and changing its properties.
|
||||||
|
|
||||||
|
To read or write to the file, there are methods for returning an input or
|
||||||
|
output stream.
|
||||||
|
|
||||||
|
@see FileInputStream, FileOutputStream
|
||||||
|
*/
|
||||||
|
class JUCE_API File
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an (invalid) file object.
|
||||||
|
|
||||||
|
The file is initially set to an empty path, so getFullPath() will return
|
||||||
|
an empty string, and comparing the file to File::nonexistent will return
|
||||||
|
true.
|
||||||
|
|
||||||
|
You can use its operator= method to point it at a proper file.
|
||||||
|
*/
|
||||||
|
File() noexcept {}
|
||||||
|
|
||||||
|
/** Creates a file from an absolute path.
|
||||||
|
|
||||||
|
If the path supplied is a relative path, it is taken to be relative
|
||||||
|
to the current working directory (see File::getCurrentWorkingDirectory()),
|
||||||
|
but this isn't a recommended way of creating a file, because you
|
||||||
|
never know what the CWD is going to be.
|
||||||
|
|
||||||
|
On the Mac/Linux, the path can include "~" notation for referring to
|
||||||
|
user home directories.
|
||||||
|
*/
|
||||||
|
File (const String& absolutePath);
|
||||||
|
|
||||||
|
/** Creates a copy of another file object. */
|
||||||
|
File (const File&);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~File() noexcept {}
|
||||||
|
|
||||||
|
/** Sets the file based on an absolute pathname.
|
||||||
|
|
||||||
|
If the path supplied is a relative path, it is taken to be relative
|
||||||
|
to the current working directory (see File::getCurrentWorkingDirectory()),
|
||||||
|
but this isn't a recommended way of creating a file, because you
|
||||||
|
never know what the CWD is going to be.
|
||||||
|
|
||||||
|
On the Mac/Linux, the path can include "~" notation for referring to
|
||||||
|
user home directories.
|
||||||
|
*/
|
||||||
|
File& operator= (const String& newAbsolutePath);
|
||||||
|
|
||||||
|
/** Copies from another file object. */
|
||||||
|
File& operator= (const File& otherFile);
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
File (File&&) noexcept;
|
||||||
|
File& operator= (File&&) noexcept;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** This static constant is used for referring to an 'invalid' file. */
|
||||||
|
static const File nonexistent;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Checks whether the file actually exists.
|
||||||
|
|
||||||
|
@returns true if the file exists, either as a file or a directory.
|
||||||
|
@see existsAsFile, isDirectory
|
||||||
|
*/
|
||||||
|
bool exists() const;
|
||||||
|
|
||||||
|
/** Checks whether the file exists and is a file rather than a directory.
|
||||||
|
|
||||||
|
@returns true only if this is a real file, false if it's a directory
|
||||||
|
or doesn't exist
|
||||||
|
@see exists, isDirectory
|
||||||
|
*/
|
||||||
|
bool existsAsFile() const;
|
||||||
|
|
||||||
|
/** Checks whether the file is a directory that exists.
|
||||||
|
|
||||||
|
@returns true only if the file is a directory which actually exists, so
|
||||||
|
false if it's a file or doesn't exist at all
|
||||||
|
@see exists, existsAsFile
|
||||||
|
*/
|
||||||
|
bool isDirectory() const;
|
||||||
|
|
||||||
|
/** Returns the size of the file in bytes.
|
||||||
|
|
||||||
|
@returns the number of bytes in the file, or 0 if it doesn't exist.
|
||||||
|
*/
|
||||||
|
int64 getSize() const;
|
||||||
|
|
||||||
|
/** Utility function to convert a file size in bytes to a neat string description.
|
||||||
|
|
||||||
|
So for example 100 would return "100 bytes", 2000 would return "2 KB",
|
||||||
|
2000000 would produce "2 MB", etc.
|
||||||
|
*/
|
||||||
|
static String descriptionOfSizeInBytes (int64 bytes);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the complete, absolute path of this file.
|
||||||
|
|
||||||
|
This includes the filename and all its parent folders. On Windows it'll
|
||||||
|
also include the drive letter prefix; on Mac or Linux it'll be a complete
|
||||||
|
path starting from the root folder.
|
||||||
|
|
||||||
|
If you just want the file's name, you should use getFileName() or
|
||||||
|
getFileNameWithoutExtension().
|
||||||
|
|
||||||
|
@see getFileName, getRelativePathFrom
|
||||||
|
*/
|
||||||
|
const String& getFullPathName() const noexcept { return fullPath; }
|
||||||
|
|
||||||
|
/** Returns the last section of the pathname.
|
||||||
|
|
||||||
|
Returns just the final part of the path - e.g. if the whole path
|
||||||
|
is "/moose/fish/foo.txt" this will return "foo.txt".
|
||||||
|
|
||||||
|
For a directory, it returns the final part of the path - e.g. for the
|
||||||
|
directory "/moose/fish" it'll return "fish".
|
||||||
|
|
||||||
|
If the filename begins with a dot, it'll return the whole filename, e.g. for
|
||||||
|
"/moose/.fish", it'll return ".fish"
|
||||||
|
|
||||||
|
@see getFullPathName, getFileNameWithoutExtension
|
||||||
|
*/
|
||||||
|
String getFileName() const;
|
||||||
|
|
||||||
|
/** Creates a relative path that refers to a file relatively to a given directory.
|
||||||
|
|
||||||
|
e.g. File ("/moose/foo.txt").getRelativePathFrom (File ("/moose/fish/haddock"))
|
||||||
|
would return "../../foo.txt".
|
||||||
|
|
||||||
|
If it's not possible to navigate from one file to the other, an absolute
|
||||||
|
path is returned. If the paths are invalid, an empty string may also be
|
||||||
|
returned.
|
||||||
|
|
||||||
|
@param directoryToBeRelativeTo the directory which the resultant string will
|
||||||
|
be relative to. If this is actually a file rather than
|
||||||
|
a directory, its parent directory will be used instead.
|
||||||
|
If it doesn't exist, it's assumed to be a directory.
|
||||||
|
@see getChildFile, isAbsolutePath
|
||||||
|
*/
|
||||||
|
String getRelativePathFrom (const File& directoryToBeRelativeTo) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the file's extension.
|
||||||
|
|
||||||
|
Returns the file extension of this file, also including the dot.
|
||||||
|
|
||||||
|
e.g. "/moose/fish/foo.txt" would return ".txt"
|
||||||
|
|
||||||
|
@see hasFileExtension, withFileExtension, getFileNameWithoutExtension
|
||||||
|
*/
|
||||||
|
String getFileExtension() const;
|
||||||
|
|
||||||
|
/** Checks whether the file has a given extension.
|
||||||
|
|
||||||
|
@param extensionToTest the extension to look for - it doesn't matter whether or
|
||||||
|
not this string has a dot at the start, so ".wav" and "wav"
|
||||||
|
will have the same effect. To compare with multiple extensions, this
|
||||||
|
parameter can contain multiple strings, separated by semi-colons -
|
||||||
|
so, for example: hasFileExtension (".jpeg;png;gif") would return
|
||||||
|
true if the file has any of those three extensions.
|
||||||
|
|
||||||
|
@see getFileExtension, withFileExtension, getFileNameWithoutExtension
|
||||||
|
*/
|
||||||
|
bool hasFileExtension (StringRef extensionToTest) const;
|
||||||
|
|
||||||
|
/** Returns a version of this file with a different file extension.
|
||||||
|
|
||||||
|
e.g. File ("/moose/fish/foo.txt").withFileExtension ("html") returns "/moose/fish/foo.html"
|
||||||
|
|
||||||
|
@param newExtension the new extension, either with or without a dot at the start (this
|
||||||
|
doesn't make any difference). To get remove a file's extension altogether,
|
||||||
|
pass an empty string into this function.
|
||||||
|
|
||||||
|
@see getFileName, getFileExtension, hasFileExtension, getFileNameWithoutExtension
|
||||||
|
*/
|
||||||
|
File withFileExtension (StringRef newExtension) const;
|
||||||
|
|
||||||
|
/** Returns the last part of the filename, without its file extension.
|
||||||
|
|
||||||
|
e.g. for "/moose/fish/foo.txt" this will return "foo".
|
||||||
|
|
||||||
|
@see getFileName, getFileExtension, hasFileExtension, withFileExtension
|
||||||
|
*/
|
||||||
|
String getFileNameWithoutExtension() const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a 32-bit hash-code that identifies this file.
|
||||||
|
|
||||||
|
This is based on the filename. Obviously it's possible, although unlikely, that
|
||||||
|
two files will have the same hash-code.
|
||||||
|
*/
|
||||||
|
int hashCode() const;
|
||||||
|
|
||||||
|
/** Returns a 64-bit hash-code that identifies this file.
|
||||||
|
|
||||||
|
This is based on the filename. Obviously it's possible, although unlikely, that
|
||||||
|
two files will have the same hash-code.
|
||||||
|
*/
|
||||||
|
int64 hashCode64() const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a file that represents a relative (or absolute) sub-path of the current one.
|
||||||
|
|
||||||
|
This will find a child file or directory of the current object.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
File ("/moose/fish").getChildFile ("foo.txt") will produce "/moose/fish/foo.txt".
|
||||||
|
File ("/moose/fish").getChildFile ("haddock/foo.txt") will produce "/moose/fish/haddock/foo.txt".
|
||||||
|
File ("/moose/fish").getChildFile ("../foo.txt") will produce "/moose/foo.txt".
|
||||||
|
|
||||||
|
If the string is actually an absolute path, it will be treated as such, e.g.
|
||||||
|
File ("/moose/fish").getChildFile ("/foo.txt") will produce "/foo.txt"
|
||||||
|
|
||||||
|
@see getSiblingFile, getParentDirectory, getRelativePathFrom, isAChildOf
|
||||||
|
*/
|
||||||
|
File getChildFile (StringRef relativeOrAbsolutePath) const;
|
||||||
|
|
||||||
|
/** Returns a file which is in the same directory as this one.
|
||||||
|
|
||||||
|
This is equivalent to getParentDirectory().getChildFile (name).
|
||||||
|
|
||||||
|
@see getChildFile, getParentDirectory
|
||||||
|
*/
|
||||||
|
File getSiblingFile (StringRef siblingFileName) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the directory that contains this file or directory.
|
||||||
|
|
||||||
|
e.g. for "/moose/fish/foo.txt" this will return "/moose/fish".
|
||||||
|
*/
|
||||||
|
File getParentDirectory() const;
|
||||||
|
|
||||||
|
/** Checks whether a file is somewhere inside a directory.
|
||||||
|
|
||||||
|
Returns true if this file is somewhere inside a subdirectory of the directory
|
||||||
|
that is passed in. Neither file actually has to exist, because the function
|
||||||
|
just checks the paths for similarities.
|
||||||
|
|
||||||
|
e.g. File ("/moose/fish/foo.txt").isAChildOf ("/moose") is true.
|
||||||
|
File ("/moose/fish/foo.txt").isAChildOf ("/moose/fish") is also true.
|
||||||
|
*/
|
||||||
|
bool isAChildOf (const File& potentialParentDirectory) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Chooses a filename relative to this one that doesn't already exist.
|
||||||
|
|
||||||
|
If this file is a directory, this will return a child file of this
|
||||||
|
directory that doesn't exist, by adding numbers to a prefix and suffix until
|
||||||
|
it finds one that isn't already there.
|
||||||
|
|
||||||
|
If the prefix + the suffix doesn't exist, it won't bother adding a number.
|
||||||
|
|
||||||
|
e.g. File ("/moose/fish").getNonexistentChildFile ("foo", ".txt", true) might
|
||||||
|
return "/moose/fish/foo(2).txt" if there's already a file called "foo.txt".
|
||||||
|
|
||||||
|
@param prefix the string to use for the filename before the number
|
||||||
|
@param suffix the string to add to the filename after the number
|
||||||
|
@param putNumbersInBrackets if true, this will create filenames in the
|
||||||
|
format "prefix(number)suffix", if false, it will leave the
|
||||||
|
brackets out.
|
||||||
|
*/
|
||||||
|
File getNonexistentChildFile (const String& prefix,
|
||||||
|
const String& suffix,
|
||||||
|
bool putNumbersInBrackets = true) const;
|
||||||
|
|
||||||
|
/** Chooses a filename for a sibling file to this one that doesn't already exist.
|
||||||
|
|
||||||
|
If this file doesn't exist, this will just return itself, otherwise it
|
||||||
|
will return an appropriate sibling that doesn't exist, e.g. if a file
|
||||||
|
"/moose/fish/foo.txt" exists, this might return "/moose/fish/foo(2).txt".
|
||||||
|
|
||||||
|
@param putNumbersInBrackets whether to add brackets around the numbers that
|
||||||
|
get appended to the new filename.
|
||||||
|
*/
|
||||||
|
File getNonexistentSibling (bool putNumbersInBrackets = true) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Compares the pathnames for two files. */
|
||||||
|
bool operator== (const File&) const;
|
||||||
|
/** Compares the pathnames for two files. */
|
||||||
|
bool operator!= (const File&) const;
|
||||||
|
/** Compares the pathnames for two files. */
|
||||||
|
bool operator< (const File&) const;
|
||||||
|
/** Compares the pathnames for two files. */
|
||||||
|
bool operator> (const File&) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Checks whether a file can be created or written to.
|
||||||
|
|
||||||
|
@returns true if it's possible to create and write to this file. If the file
|
||||||
|
doesn't already exist, this will check its parent directory to
|
||||||
|
see if writing is allowed.
|
||||||
|
@see setReadOnly
|
||||||
|
*/
|
||||||
|
bool hasWriteAccess() const;
|
||||||
|
|
||||||
|
/** Changes the write-permission of a file or directory.
|
||||||
|
|
||||||
|
@param shouldBeReadOnly whether to add or remove write-permission
|
||||||
|
@param applyRecursively if the file is a directory and this is true, it will
|
||||||
|
recurse through all the subfolders changing the permissions
|
||||||
|
of all files
|
||||||
|
@returns true if it manages to change the file's permissions.
|
||||||
|
@see hasWriteAccess
|
||||||
|
*/
|
||||||
|
bool setReadOnly (bool shouldBeReadOnly,
|
||||||
|
bool applyRecursively = false) const;
|
||||||
|
|
||||||
|
/** Changes the execute-permissions of a file.
|
||||||
|
|
||||||
|
@param shouldBeExecutable whether to add or remove execute-permission
|
||||||
|
@returns true if it manages to change the file's permissions.
|
||||||
|
*/
|
||||||
|
bool setExecutePermission (bool shouldBeExecutable) const;
|
||||||
|
|
||||||
|
/** Returns true if this file is a hidden or system file.
|
||||||
|
The criteria for deciding whether a file is hidden are platform-dependent.
|
||||||
|
*/
|
||||||
|
bool isHidden() const;
|
||||||
|
|
||||||
|
/** Returns true if this file is a link or alias that can be followed using getLinkedTarget(). */
|
||||||
|
bool isLink() const;
|
||||||
|
|
||||||
|
/** If this file is a link or alias, this returns the file that it points to.
|
||||||
|
If the file isn't actually link, it'll just return itself.
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
|
||||||
|
@returns the time, or an invalid time if the file doesn't exist.
|
||||||
|
@see setLastModificationTime, getLastAccessTime, getCreationTime
|
||||||
|
*/
|
||||||
|
Time getLastModificationTime() const;
|
||||||
|
|
||||||
|
/** Returns the last time this file was accessed.
|
||||||
|
|
||||||
|
@returns the time, or an invalid time if the file doesn't exist.
|
||||||
|
@see setLastAccessTime, getLastModificationTime, getCreationTime
|
||||||
|
*/
|
||||||
|
Time getLastAccessTime() const;
|
||||||
|
|
||||||
|
/** Returns the time that this file was created.
|
||||||
|
|
||||||
|
@returns the time, or an invalid time if the file doesn't exist.
|
||||||
|
@see getLastModificationTime, getLastAccessTime
|
||||||
|
*/
|
||||||
|
Time getCreationTime() const;
|
||||||
|
|
||||||
|
/** Changes the modification time for this file.
|
||||||
|
|
||||||
|
@param newTime the time to apply to the file
|
||||||
|
@returns true if it manages to change the file's time.
|
||||||
|
@see getLastModificationTime, setLastAccessTime, setCreationTime
|
||||||
|
*/
|
||||||
|
bool setLastModificationTime (Time newTime) const;
|
||||||
|
|
||||||
|
/** Changes the last-access time for this file.
|
||||||
|
|
||||||
|
@param newTime the time to apply to the file
|
||||||
|
@returns true if it manages to change the file's time.
|
||||||
|
@see getLastAccessTime, setLastModificationTime, setCreationTime
|
||||||
|
*/
|
||||||
|
bool setLastAccessTime (Time newTime) const;
|
||||||
|
|
||||||
|
/** Changes the creation date for this file.
|
||||||
|
|
||||||
|
@param newTime the time to apply to the file
|
||||||
|
@returns true if it manages to change the file's time.
|
||||||
|
@see getCreationTime, setLastModificationTime, setLastAccessTime
|
||||||
|
*/
|
||||||
|
bool setCreationTime (Time newTime) const;
|
||||||
|
|
||||||
|
/** If possible, this will try to create a version string for the given file.
|
||||||
|
|
||||||
|
The OS may be able to look at the file and give a version for it - e.g. with
|
||||||
|
executables, bundles, dlls, etc. If no version is available, this will
|
||||||
|
return an empty string.
|
||||||
|
*/
|
||||||
|
String getVersion() const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an empty file if it doesn't already exist.
|
||||||
|
|
||||||
|
If the file that this object refers to doesn't exist, this will create a file
|
||||||
|
of zero size.
|
||||||
|
|
||||||
|
If it already exists or is a directory, this method will do nothing.
|
||||||
|
|
||||||
|
@returns true if the file has been created (or if it already existed).
|
||||||
|
@see createDirectory
|
||||||
|
*/
|
||||||
|
Result create() const;
|
||||||
|
|
||||||
|
/** Creates a new directory for this filename.
|
||||||
|
|
||||||
|
This will try to create the file as a directory, and fill also create
|
||||||
|
any parent directories it needs in order to complete the operation.
|
||||||
|
|
||||||
|
@returns a result to indicate whether the directory was created successfully, or
|
||||||
|
an error message if it failed.
|
||||||
|
@see create
|
||||||
|
*/
|
||||||
|
Result createDirectory() const;
|
||||||
|
|
||||||
|
/** Deletes a file.
|
||||||
|
|
||||||
|
If this file is actually a directory, it may not be deleted correctly if it
|
||||||
|
contains files. See deleteRecursively() as a better way of deleting directories.
|
||||||
|
|
||||||
|
@returns true if the file has been successfully deleted (or if it didn't exist to
|
||||||
|
begin with).
|
||||||
|
@see deleteRecursively
|
||||||
|
*/
|
||||||
|
bool deleteFile() const;
|
||||||
|
|
||||||
|
/** Deletes a file or directory and all its subdirectories.
|
||||||
|
|
||||||
|
If this file is a directory, this will try to delete it and all its subfolders. If
|
||||||
|
it's just a file, it will just try to delete the file.
|
||||||
|
|
||||||
|
@returns true if the file and all its subfolders have been successfully deleted
|
||||||
|
(or if it didn't exist to begin with).
|
||||||
|
@see deleteFile
|
||||||
|
*/
|
||||||
|
bool deleteRecursively() const;
|
||||||
|
|
||||||
|
/** Moves this file or folder to the trash.
|
||||||
|
|
||||||
|
@returns true if the operation succeeded. It could fail if the trash is full, or
|
||||||
|
if the file is write-protected, so you should check the return value
|
||||||
|
and act appropriately.
|
||||||
|
*/
|
||||||
|
bool moveToTrash() const;
|
||||||
|
|
||||||
|
/** Moves or renames a file.
|
||||||
|
|
||||||
|
Tries to move a file to a different location.
|
||||||
|
If the target file already exists, this will attempt to delete it first, and
|
||||||
|
will fail if this can't be done.
|
||||||
|
|
||||||
|
Note that the destination file isn't the directory to put it in, it's the actual
|
||||||
|
filename that you want the new file to have.
|
||||||
|
|
||||||
|
@returns true if the operation succeeds
|
||||||
|
*/
|
||||||
|
bool moveFileTo (const File& targetLocation) const;
|
||||||
|
|
||||||
|
/** Copies a file.
|
||||||
|
|
||||||
|
Tries to copy a file to a different location.
|
||||||
|
If the target file already exists, this will attempt to delete it first, and
|
||||||
|
will fail if this can't be done.
|
||||||
|
|
||||||
|
@returns true if the operation succeeds
|
||||||
|
*/
|
||||||
|
bool copyFileTo (const File& targetLocation) const;
|
||||||
|
|
||||||
|
/** Copies a directory.
|
||||||
|
|
||||||
|
Tries to copy an entire directory, recursively.
|
||||||
|
|
||||||
|
If this file isn't a directory or if any target files can't be created, this
|
||||||
|
will return false.
|
||||||
|
|
||||||
|
@param newDirectory the directory that this one should be copied to. Note that this
|
||||||
|
is the name of the actual directory to create, not the directory
|
||||||
|
into which the new one should be placed, so there must be enough
|
||||||
|
write privileges to create it if it doesn't exist. Any files inside
|
||||||
|
it will be overwritten by similarly named ones that are copied.
|
||||||
|
*/
|
||||||
|
bool copyDirectoryTo (const File& newDirectory) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Used in file searching, to specify whether to return files, directories, or both.
|
||||||
|
*/
|
||||||
|
enum TypesOfFileToFind
|
||||||
|
{
|
||||||
|
findDirectories = 1, /**< Use this flag to indicate that you want to find directories. */
|
||||||
|
findFiles = 2, /**< Use this flag to indicate that you want to find files. */
|
||||||
|
findFilesAndDirectories = 3, /**< Use this flag to indicate that you want to find both files and directories. */
|
||||||
|
ignoreHiddenFiles = 4 /**< Add this flag to avoid returning any hidden files in the results. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Searches inside a directory for files matching a wildcard pattern.
|
||||||
|
|
||||||
|
Assuming that this file is a directory, this method will search it
|
||||||
|
for either files or subdirectories whose names match a filename pattern.
|
||||||
|
|
||||||
|
@param results an array to which File objects will be added for the
|
||||||
|
files that the search comes up with
|
||||||
|
@param whatToLookFor a value from the TypesOfFileToFind enum, specifying whether to
|
||||||
|
return files, directories, or both. If the ignoreHiddenFiles flag
|
||||||
|
is also added to this value, hidden files won't be returned
|
||||||
|
@param searchRecursively if true, all subdirectories will be recursed into to do
|
||||||
|
an exhaustive search
|
||||||
|
@param wildCardPattern the filename pattern to search for, e.g. "*.txt"
|
||||||
|
@returns the number of results that have been found
|
||||||
|
|
||||||
|
@see getNumberOfChildFiles, DirectoryIterator
|
||||||
|
*/
|
||||||
|
int findChildFiles (Array<File>& results,
|
||||||
|
int whatToLookFor,
|
||||||
|
bool searchRecursively,
|
||||||
|
const String& wildCardPattern = "*") const;
|
||||||
|
|
||||||
|
/** Searches inside a directory and counts how many files match a wildcard pattern.
|
||||||
|
|
||||||
|
Assuming that this file is a directory, this method will search it
|
||||||
|
for either files or subdirectories whose names match a filename pattern,
|
||||||
|
and will return the number of matches found.
|
||||||
|
|
||||||
|
This isn't a recursive call, and will only search this directory, not
|
||||||
|
its children.
|
||||||
|
|
||||||
|
@param whatToLookFor a value from the TypesOfFileToFind enum, specifying whether to
|
||||||
|
count files, directories, or both. If the ignoreHiddenFiles flag
|
||||||
|
is also added to this value, hidden files won't be counted
|
||||||
|
@param wildCardPattern the filename pattern to search for, e.g. "*.txt"
|
||||||
|
@returns the number of matches found
|
||||||
|
@see findChildFiles, DirectoryIterator
|
||||||
|
*/
|
||||||
|
int getNumberOfChildFiles (int whatToLookFor,
|
||||||
|
const String& wildCardPattern = "*") const;
|
||||||
|
|
||||||
|
/** Returns true if this file is a directory that contains one or more subdirectories.
|
||||||
|
@see isDirectory, findChildFiles
|
||||||
|
*/
|
||||||
|
bool containsSubDirectories() const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a stream to read from this file.
|
||||||
|
|
||||||
|
@returns a stream that will read from this file (initially positioned at the
|
||||||
|
start of the file), or nullptr if the file can't be opened for some reason
|
||||||
|
@see createOutputStream, loadFileAsData
|
||||||
|
*/
|
||||||
|
FileInputStream* createInputStream() const;
|
||||||
|
|
||||||
|
/** Creates a stream to write to this file.
|
||||||
|
|
||||||
|
If the file exists, the stream that is returned will be positioned ready for
|
||||||
|
writing at the end of the file, so you might want to use deleteFile() first
|
||||||
|
to write to an empty file.
|
||||||
|
|
||||||
|
@returns a stream that will write to this file (initially positioned at the
|
||||||
|
end of the file), or nullptr if the file can't be opened for some reason
|
||||||
|
@see createInputStream, appendData, appendText
|
||||||
|
*/
|
||||||
|
FileOutputStream* createOutputStream (size_t bufferSize = 0x8000) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Loads a file's contents into memory as a block of binary data.
|
||||||
|
|
||||||
|
Of course, trying to load a very large file into memory will blow up, so
|
||||||
|
it's better to check first.
|
||||||
|
|
||||||
|
@param result the data block to which the file's contents should be appended - note
|
||||||
|
that if the memory block might already contain some data, you
|
||||||
|
might want to clear it first
|
||||||
|
@returns true if the file could all be read into memory
|
||||||
|
*/
|
||||||
|
bool loadFileAsData (MemoryBlock& result) const;
|
||||||
|
|
||||||
|
/** Reads a file into memory as a string.
|
||||||
|
|
||||||
|
Attempts to load the entire file as a zero-terminated string.
|
||||||
|
|
||||||
|
This makes use of InputStream::readEntireStreamAsString, which can
|
||||||
|
read either UTF-16 or UTF-8 file formats.
|
||||||
|
*/
|
||||||
|
String loadFileAsString() const;
|
||||||
|
|
||||||
|
/** Reads the contents of this file as text and splits it into lines, which are
|
||||||
|
appended to the given StringArray.
|
||||||
|
*/
|
||||||
|
void readLines (StringArray& destLines) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Appends a block of binary data to the end of the file.
|
||||||
|
|
||||||
|
This will try to write the given buffer to the end of the file.
|
||||||
|
|
||||||
|
@returns false if it can't write to the file for some reason
|
||||||
|
*/
|
||||||
|
bool appendData (const void* dataToAppend,
|
||||||
|
size_t numberOfBytes) const;
|
||||||
|
|
||||||
|
/** Replaces this file's contents with a given block of data.
|
||||||
|
|
||||||
|
This will delete the file and replace it with the given data.
|
||||||
|
|
||||||
|
A nice feature of this method is that it's safe - instead of deleting
|
||||||
|
the file first and then re-writing it, it creates a new temporary file,
|
||||||
|
writes the data to that, and then moves the new file to replace the existing
|
||||||
|
file. This means that if the power gets pulled out or something crashes,
|
||||||
|
you're a lot less likely to end up with a corrupted or unfinished file..
|
||||||
|
|
||||||
|
Returns true if the operation succeeds, or false if it fails.
|
||||||
|
|
||||||
|
@see appendText
|
||||||
|
*/
|
||||||
|
bool replaceWithData (const void* dataToWrite,
|
||||||
|
size_t numberOfBytes) const;
|
||||||
|
|
||||||
|
/** Appends a string to the end of the file.
|
||||||
|
|
||||||
|
This will try to append a text string to the file, as either 16-bit unicode
|
||||||
|
or 8-bit characters in the default system encoding.
|
||||||
|
|
||||||
|
It can also write the 'ff fe' unicode header bytes before the text to indicate
|
||||||
|
the endianness of the file.
|
||||||
|
|
||||||
|
Any single \\n characters in the string are replaced with \\r\\n before it is written.
|
||||||
|
|
||||||
|
@see replaceWithText
|
||||||
|
*/
|
||||||
|
bool appendText (const String& textToAppend,
|
||||||
|
bool asUnicode = false,
|
||||||
|
bool writeUnicodeHeaderBytes = false) const;
|
||||||
|
|
||||||
|
/** Replaces this file's contents with a given text string.
|
||||||
|
|
||||||
|
This will delete the file and replace it with the given text.
|
||||||
|
|
||||||
|
A nice feature of this method is that it's safe - instead of deleting
|
||||||
|
the file first and then re-writing it, it creates a new temporary file,
|
||||||
|
writes the text to that, and then moves the new file to replace the existing
|
||||||
|
file. This means that if the power gets pulled out or something crashes,
|
||||||
|
you're a lot less likely to end up with an empty file..
|
||||||
|
|
||||||
|
For an explanation of the parameters here, see the appendText() method.
|
||||||
|
|
||||||
|
Returns true if the operation succeeds, or false if it fails.
|
||||||
|
|
||||||
|
@see appendText
|
||||||
|
*/
|
||||||
|
bool replaceWithText (const String& textToWrite,
|
||||||
|
bool asUnicode = false,
|
||||||
|
bool writeUnicodeHeaderBytes = false) const;
|
||||||
|
|
||||||
|
/** Attempts to scan the contents of this file and compare it to another file, returning
|
||||||
|
true if this is possible and they match byte-for-byte.
|
||||||
|
*/
|
||||||
|
bool hasIdenticalContentTo (const File& other) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a set of files to represent each file root.
|
||||||
|
|
||||||
|
e.g. on Windows this will create files for "c:\", "d:\" etc according
|
||||||
|
to which ones are available. On the Mac/Linux, this will probably
|
||||||
|
just add a single entry for "/".
|
||||||
|
*/
|
||||||
|
static void findFileSystemRoots (Array<File>& results);
|
||||||
|
|
||||||
|
/** Finds the name of the drive on which this file lives.
|
||||||
|
@returns the volume label of the drive, or an empty string if this isn't possible
|
||||||
|
*/
|
||||||
|
String getVolumeLabel() const;
|
||||||
|
|
||||||
|
/** Returns the serial number of the volume on which this file lives.
|
||||||
|
@returns the serial number, or zero if there's a problem doing this
|
||||||
|
*/
|
||||||
|
int getVolumeSerialNumber() const;
|
||||||
|
|
||||||
|
/** Returns the number of bytes free on the drive that this file lives on.
|
||||||
|
|
||||||
|
@returns the number of bytes free, or 0 if there's a problem finding this out
|
||||||
|
@see getVolumeTotalSize
|
||||||
|
*/
|
||||||
|
int64 getBytesFreeOnVolume() const;
|
||||||
|
|
||||||
|
/** Returns the total size of the drive that contains this file.
|
||||||
|
|
||||||
|
@returns the total number of bytes that the volume can hold
|
||||||
|
@see getBytesFreeOnVolume
|
||||||
|
*/
|
||||||
|
int64 getVolumeTotalSize() const;
|
||||||
|
|
||||||
|
/** Returns true if this file is on a CD or DVD drive. */
|
||||||
|
bool isOnCDRomDrive() const;
|
||||||
|
|
||||||
|
/** Returns true if this file is on a hard disk.
|
||||||
|
|
||||||
|
This will fail if it's a network drive, but will still be true for
|
||||||
|
removable hard-disks.
|
||||||
|
*/
|
||||||
|
bool isOnHardDisk() const;
|
||||||
|
|
||||||
|
/** Returns true if this file is on a removable disk drive.
|
||||||
|
|
||||||
|
This might be a usb-drive, a CD-rom, or maybe a network drive.
|
||||||
|
*/
|
||||||
|
bool isOnRemovableDrive() const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Launches the file as a process.
|
||||||
|
|
||||||
|
- if the file is executable, this will run it.
|
||||||
|
|
||||||
|
- if it's a document of some kind, it will launch the document with its
|
||||||
|
default viewer application.
|
||||||
|
|
||||||
|
- if it's a folder, it will be opened in Explorer, Finder, or equivalent.
|
||||||
|
|
||||||
|
@see revealToUser
|
||||||
|
*/
|
||||||
|
bool startAsProcess (const String& parameters = String()) const;
|
||||||
|
|
||||||
|
/** Opens Finder, Explorer, or whatever the OS uses, to show the user this file's location.
|
||||||
|
@see startAsProcess
|
||||||
|
*/
|
||||||
|
void revealToUser() const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** A set of types of location that can be passed to the getSpecialLocation() method.
|
||||||
|
*/
|
||||||
|
enum SpecialLocationType
|
||||||
|
{
|
||||||
|
/** The user's home folder. This is the same as using File ("~"). */
|
||||||
|
userHomeDirectory,
|
||||||
|
|
||||||
|
/** The user's default documents folder. On Windows, this might be the user's
|
||||||
|
"My Documents" folder. On the Mac it'll be their "Documents" folder. Linux
|
||||||
|
doesn't tend to have one of these, so it might just return their home folder.
|
||||||
|
*/
|
||||||
|
userDocumentsDirectory,
|
||||||
|
|
||||||
|
/** The folder that contains the user's desktop objects. */
|
||||||
|
userDesktopDirectory,
|
||||||
|
|
||||||
|
/** The most likely place where a user might store their music files. */
|
||||||
|
userMusicDirectory,
|
||||||
|
|
||||||
|
/** The most likely place where a user might store their movie files. */
|
||||||
|
userMoviesDirectory,
|
||||||
|
|
||||||
|
/** The most likely place where a user might store their picture files. */
|
||||||
|
userPicturesDirectory,
|
||||||
|
|
||||||
|
/** The folder in which applications store their persistent user-specific settings.
|
||||||
|
On Windows, this might be "\Documents and Settings\username\Application Data".
|
||||||
|
On the Mac, it might be "~/Library". If you're going to store your settings in here,
|
||||||
|
always create your own sub-folder to put them in, to avoid making a mess.
|
||||||
|
*/
|
||||||
|
userApplicationDataDirectory,
|
||||||
|
|
||||||
|
/** An equivalent of the userApplicationDataDirectory folder that is shared by all users
|
||||||
|
of the computer, rather than just the current user.
|
||||||
|
|
||||||
|
On the Mac it'll be "/Library", on Windows, it could be something like
|
||||||
|
"\Documents and Settings\All Users\Application Data".
|
||||||
|
|
||||||
|
Depending on the setup, this folder may be read-only.
|
||||||
|
*/
|
||||||
|
commonApplicationDataDirectory,
|
||||||
|
|
||||||
|
/** A place to put documents which are shared by all users of the machine.
|
||||||
|
On Windows this may be somewhere like "C:\Users\Public\Documents", on OSX it
|
||||||
|
will be something like "/Users/Shared". Other OSes may have no such concept
|
||||||
|
though, so be careful.
|
||||||
|
*/
|
||||||
|
commonDocumentsDirectory,
|
||||||
|
|
||||||
|
/** The folder that should be used for temporary files.
|
||||||
|
Always delete them when you're finished, to keep the user's computer tidy!
|
||||||
|
*/
|
||||||
|
tempDirectory,
|
||||||
|
|
||||||
|
/** Returns this application's executable file.
|
||||||
|
|
||||||
|
If running as a plug-in or DLL, this will (where possible) be the DLL rather than the
|
||||||
|
host app.
|
||||||
|
|
||||||
|
On the mac this will return the unix binary, not the package folder - see
|
||||||
|
currentApplicationFile for that.
|
||||||
|
|
||||||
|
See also invokedExecutableFile, which is similar, but if the exe was launched from a
|
||||||
|
file link, invokedExecutableFile will return the name of the link.
|
||||||
|
*/
|
||||||
|
currentExecutableFile,
|
||||||
|
|
||||||
|
/** Returns this application's location.
|
||||||
|
|
||||||
|
If running as a plug-in or DLL, this will (where possible) be the DLL rather than the
|
||||||
|
host app.
|
||||||
|
|
||||||
|
On the mac this will return the package folder (if it's in one), not the unix binary
|
||||||
|
that's inside it - compare with currentExecutableFile.
|
||||||
|
*/
|
||||||
|
currentApplicationFile,
|
||||||
|
|
||||||
|
/** Returns the file that was invoked to launch this executable.
|
||||||
|
This may differ from currentExecutableFile if the app was started from e.g. a link - this
|
||||||
|
will return the name of the link that was used, whereas currentExecutableFile will return
|
||||||
|
the actual location of the target executable.
|
||||||
|
*/
|
||||||
|
invokedExecutableFile,
|
||||||
|
|
||||||
|
/** 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.
|
||||||
|
*/
|
||||||
|
globalApplicationsDirectory
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Finds the location of a special type of file or directory, such as a home folder or
|
||||||
|
documents folder.
|
||||||
|
|
||||||
|
@see SpecialLocationType
|
||||||
|
*/
|
||||||
|
static File JUCE_CALLTYPE getSpecialLocation (const SpecialLocationType type);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a temporary file in the system's temp directory.
|
||||||
|
This will try to return the name of a non-existent temp file.
|
||||||
|
To get the temp folder, you can use getSpecialLocation (File::tempDirectory).
|
||||||
|
*/
|
||||||
|
static File createTempFile (StringRef fileNameEnding);
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the current working directory.
|
||||||
|
@see setAsCurrentWorkingDirectory
|
||||||
|
*/
|
||||||
|
static File getCurrentWorkingDirectory();
|
||||||
|
|
||||||
|
/** Sets the current working directory to be this file.
|
||||||
|
|
||||||
|
For this to work the file must point to a valid directory.
|
||||||
|
|
||||||
|
@returns true if the current directory has been changed.
|
||||||
|
@see getCurrentWorkingDirectory
|
||||||
|
*/
|
||||||
|
bool setAsCurrentWorkingDirectory() const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** The system-specific file separator character.
|
||||||
|
On Windows, this will be '\', on Mac/Linux, it'll be '/'
|
||||||
|
*/
|
||||||
|
static const juce_wchar separator;
|
||||||
|
|
||||||
|
/** The system-specific file separator character, as a string.
|
||||||
|
On Windows, this will be '\', on Mac/Linux, it'll be '/'
|
||||||
|
*/
|
||||||
|
static const String separatorString;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a version of a filename with any illegal characters removed.
|
||||||
|
|
||||||
|
This will return a copy of the given string after removing characters
|
||||||
|
that are not allowed in a legal filename, and possibly shortening the
|
||||||
|
string if it's too long.
|
||||||
|
|
||||||
|
Because this will remove slashes, don't use it on an absolute pathname - use
|
||||||
|
createLegalPathName() for that.
|
||||||
|
|
||||||
|
@see createLegalPathName
|
||||||
|
*/
|
||||||
|
static String createLegalFileName (const String& fileNameToFix);
|
||||||
|
|
||||||
|
/** Returns a version of a path with any illegal characters removed.
|
||||||
|
|
||||||
|
Similar to createLegalFileName(), but this won't remove slashes, so can
|
||||||
|
be used on a complete pathname.
|
||||||
|
|
||||||
|
@see createLegalFileName
|
||||||
|
*/
|
||||||
|
static String createLegalPathName (const String& pathNameToFix);
|
||||||
|
|
||||||
|
/** Indicates whether filenames are case-sensitive on the current operating system. */
|
||||||
|
static bool areFileNamesCaseSensitive();
|
||||||
|
|
||||||
|
/** Returns true if the string seems to be a fully-specified absolute path. */
|
||||||
|
static bool isAbsolutePath (StringRef path);
|
||||||
|
|
||||||
|
/** Creates a file that simply contains this string, without doing the sanity-checking
|
||||||
|
that the normal constructors do.
|
||||||
|
|
||||||
|
Best to avoid this unless you really know what you're doing.
|
||||||
|
*/
|
||||||
|
static File createFileWithoutCheckingPath (const String& absolutePath) noexcept;
|
||||||
|
|
||||||
|
/** Adds a separator character to the end of a path if it doesn't already have one. */
|
||||||
|
static String addTrailingSeparator (const String& path);
|
||||||
|
|
||||||
|
#if JUCE_MAC || JUCE_IOS || DOXYGEN
|
||||||
|
//==============================================================================
|
||||||
|
/** OSX ONLY - Finds the OSType of a file from the its resources. */
|
||||||
|
OSType getMacOSType() const;
|
||||||
|
|
||||||
|
/** OSX ONLY - Returns true if this file is actually a bundle. */
|
||||||
|
bool isBundle() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JUCE_MAC || DOXYGEN
|
||||||
|
/** OSX ONLY - Adds this file to the OSX dock */
|
||||||
|
void addToDock() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JUCE_WINDOWS
|
||||||
|
/** Windows ONLY - Creates a win32 .LNK shortcut file that links to this file. */
|
||||||
|
bool createLink (const String& description, const File& linkFileToCreate) const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
String fullPath;
|
||||||
|
|
||||||
|
static String parseAbsolutePath (const String&);
|
||||||
|
String getPathUpToLastSlash() const;
|
||||||
|
|
||||||
|
Result createDirectoryInternal (const String&) const;
|
||||||
|
bool copyInternal (const File&) const;
|
||||||
|
bool moveInternal (const File&) const;
|
||||||
|
bool setFileTimesInternal (int64 m, int64 a, int64 c) const;
|
||||||
|
void getFileTimesInternal (int64& m, int64& a, int64& c) const;
|
||||||
|
bool setFileReadOnlyInternal (bool) const;
|
||||||
|
bool setFileExecutableInternal (bool) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // JUCE_FILE_H_INCLUDED
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
FileFilter::FileFilter (const String& filterDescription)
|
||||||
|
: description (filterDescription)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FileFilter::~FileFilter()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const String& FileFilter::getDescription() const noexcept
|
||||||
|
{
|
||||||
|
return description;
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_FILEFILTER_H_INCLUDED
|
||||||
|
#define JUCE_FILEFILTER_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Interface for deciding which files are suitable for something.
|
||||||
|
|
||||||
|
For example, this is used by DirectoryContentsList to select which files
|
||||||
|
go into the list.
|
||||||
|
|
||||||
|
@see WildcardFileFilter, DirectoryContentsList, FileListComponent, FileBrowserComponent
|
||||||
|
*/
|
||||||
|
class JUCE_API FileFilter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a filter with the given description.
|
||||||
|
|
||||||
|
The description can be returned later with the getDescription() method.
|
||||||
|
*/
|
||||||
|
FileFilter (const String& filterDescription);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
virtual ~FileFilter();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the description that the filter was created with. */
|
||||||
|
const String& getDescription() const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Should return true if this file is suitable for inclusion in whatever context
|
||||||
|
the object is being used.
|
||||||
|
*/
|
||||||
|
virtual bool isFileSuitable (const File& file) const = 0;
|
||||||
|
|
||||||
|
/** Should return true if this directory is suitable for inclusion in whatever context
|
||||||
|
the object is being used.
|
||||||
|
*/
|
||||||
|
virtual bool isDirectorySuitable (const File& file) const = 0;
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//==============================================================================
|
||||||
|
String description;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_FILEFILTER_H_INCLUDED
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
int64 juce_fileSetPosition (void* handle, int64 pos);
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
FileInputStream::FileInputStream (const File& f)
|
||||||
|
: file (f),
|
||||||
|
fileHandle (nullptr),
|
||||||
|
currentPosition (0),
|
||||||
|
status (Result::ok())
|
||||||
|
{
|
||||||
|
openHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
const size_t num = readInternal (buffer, (size_t) bytesToRead);
|
||||||
|
currentPosition += num;
|
||||||
|
|
||||||
|
return (int) num;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileInputStream::isExhausted()
|
||||||
|
{
|
||||||
|
return currentPosition >= getTotalLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 FileInputStream::getPosition()
|
||||||
|
{
|
||||||
|
return currentPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileInputStream::setPosition (int64 pos)
|
||||||
|
{
|
||||||
|
// You should always check that a stream opened successfully before using it!
|
||||||
|
jassert (openedOk());
|
||||||
|
|
||||||
|
if (pos != currentPosition)
|
||||||
|
currentPosition = juce_fileSetPosition (fileHandle, pos);
|
||||||
|
|
||||||
|
return currentPosition == pos;
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_FILEINPUTSTREAM_H_INCLUDED
|
||||||
|
#define JUCE_FILEINPUTSTREAM_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
An input stream that reads from a local file.
|
||||||
|
|
||||||
|
@see InputStream, FileOutputStream, File::createInputStream
|
||||||
|
*/
|
||||||
|
class JUCE_API FileInputStream : public InputStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a FileInputStream to read from the given file.
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~FileInputStream();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the file that this stream is reading from. */
|
||||||
|
const File& getFile() const noexcept { return file; }
|
||||||
|
|
||||||
|
/** Returns the status of the file stream.
|
||||||
|
The result will be ok if the file opened successfully. If an error occurs while
|
||||||
|
opening or reading from the file, this will contain an error message.
|
||||||
|
*/
|
||||||
|
const Result& getStatus() const noexcept { return status; }
|
||||||
|
|
||||||
|
/** Returns true if the stream couldn't be opened for some reason.
|
||||||
|
@see getResult()
|
||||||
|
*/
|
||||||
|
bool failedToOpen() const noexcept { return status.failed(); }
|
||||||
|
|
||||||
|
/** Returns true if the stream opened without problems.
|
||||||
|
@see getResult()
|
||||||
|
*/
|
||||||
|
bool openedOk() const noexcept { return status.wasOk(); }
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
int64 getTotalLength() override;
|
||||||
|
int read (void*, int) override;
|
||||||
|
bool isExhausted() override;
|
||||||
|
int64 getPosition() override;
|
||||||
|
bool setPosition (int64) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
const File file;
|
||||||
|
void* fileHandle;
|
||||||
|
int64 currentPosition;
|
||||||
|
Result status;
|
||||||
|
|
||||||
|
void openHandle();
|
||||||
|
size_t readInternal (void*, size_t);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileInputStream)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_FILEINPUTSTREAM_H_INCLUDED
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
int64 juce_fileSetPosition (void* handle, int64 pos);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
FileOutputStream::FileOutputStream (const File& f, const size_t bufferSizeToUse)
|
||||||
|
: file (f),
|
||||||
|
fileHandle (nullptr),
|
||||||
|
status (Result::ok()),
|
||||||
|
currentPosition (0),
|
||||||
|
bufferSize (bufferSizeToUse),
|
||||||
|
bytesInBuffer (0),
|
||||||
|
buffer (jmax (bufferSizeToUse, (size_t) 16))
|
||||||
|
{
|
||||||
|
openHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileOutputStream::~FileOutputStream()
|
||||||
|
{
|
||||||
|
flushBuffer();
|
||||||
|
closeHandle();
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 FileOutputStream::getPosition()
|
||||||
|
{
|
||||||
|
return currentPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileOutputStream::setPosition (int64 newPosition)
|
||||||
|
{
|
||||||
|
if (newPosition != currentPosition)
|
||||||
|
{
|
||||||
|
flushBuffer();
|
||||||
|
currentPosition = juce_fileSetPosition (fileHandle, newPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newPosition == currentPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileOutputStream::flushBuffer()
|
||||||
|
{
|
||||||
|
bool ok = true;
|
||||||
|
|
||||||
|
if (bytesInBuffer > 0)
|
||||||
|
{
|
||||||
|
ok = (writeInternal (buffer, bytesInBuffer) == (ssize_t) bytesInBuffer);
|
||||||
|
bytesInBuffer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileOutputStream::flush()
|
||||||
|
{
|
||||||
|
flushBuffer();
|
||||||
|
flushInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileOutputStream::write (const void* const src, const size_t numBytes)
|
||||||
|
{
|
||||||
|
jassert (src != nullptr && ((ssize_t) numBytes) >= 0);
|
||||||
|
|
||||||
|
if (bytesInBuffer + numBytes < bufferSize)
|
||||||
|
{
|
||||||
|
memcpy (buffer + bytesInBuffer, src, numBytes);
|
||||||
|
bytesInBuffer += numBytes;
|
||||||
|
currentPosition += numBytes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (! flushBuffer())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (numBytes < bufferSize)
|
||||||
|
{
|
||||||
|
memcpy (buffer + bytesInBuffer, src, numBytes);
|
||||||
|
bytesInBuffer += numBytes;
|
||||||
|
currentPosition += numBytes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const ssize_t bytesWritten = writeInternal (src, numBytes);
|
||||||
|
|
||||||
|
if (bytesWritten < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
currentPosition += bytesWritten;
|
||||||
|
return bytesWritten == (ssize_t) numBytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileOutputStream::writeRepeatedByte (uint8 byte, size_t numBytes)
|
||||||
|
{
|
||||||
|
jassert (((ssize_t) numBytes) >= 0);
|
||||||
|
|
||||||
|
if (bytesInBuffer + numBytes < bufferSize)
|
||||||
|
{
|
||||||
|
memset (buffer + bytesInBuffer, byte, numBytes);
|
||||||
|
bytesInBuffer += numBytes;
|
||||||
|
currentPosition += numBytes;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OutputStream::writeRepeatedByte (byte, numBytes);
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_FILEOUTPUTSTREAM_H_INCLUDED
|
||||||
|
#define JUCE_FILEOUTPUTSTREAM_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
An output stream that writes into a local file.
|
||||||
|
|
||||||
|
@see OutputStream, FileInputStream, File::createOutputStream
|
||||||
|
*/
|
||||||
|
class JUCE_API FileOutputStream : public OutputStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a FileOutputStream.
|
||||||
|
|
||||||
|
If the file doesn't exist, it will first be created. If the file can't be
|
||||||
|
created or opened, the failedToOpen() method will return
|
||||||
|
true.
|
||||||
|
|
||||||
|
If the file already exists when opened, the stream's write-postion will
|
||||||
|
be set to the end of the file. To overwrite an existing file,
|
||||||
|
use File::deleteFile() before opening the stream, or use setPosition(0)
|
||||||
|
after it's opened (although this won't truncate the file).
|
||||||
|
|
||||||
|
@see TemporaryFile
|
||||||
|
*/
|
||||||
|
FileOutputStream (const File& fileToWriteTo,
|
||||||
|
size_t bufferSizeToUse = 16384);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~FileOutputStream();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the file that this stream is writing to.
|
||||||
|
*/
|
||||||
|
const File& getFile() const { return file; }
|
||||||
|
|
||||||
|
/** Returns the status of the file stream.
|
||||||
|
The result will be ok if the file opened successfully. If an error occurs while
|
||||||
|
opening or writing to the file, this will contain an error message.
|
||||||
|
*/
|
||||||
|
const Result& getStatus() const noexcept { return status; }
|
||||||
|
|
||||||
|
/** Returns true if the stream couldn't be opened for some reason.
|
||||||
|
@see getResult()
|
||||||
|
*/
|
||||||
|
bool failedToOpen() const noexcept { return status.failed(); }
|
||||||
|
|
||||||
|
/** Returns true if the stream opened without problems.
|
||||||
|
@see getResult()
|
||||||
|
*/
|
||||||
|
bool openedOk() const noexcept { return status.wasOk(); }
|
||||||
|
|
||||||
|
/** Attempts to truncate the file to the current write position.
|
||||||
|
To truncate a file to a specific size, first use setPosition() to seek to the
|
||||||
|
appropriate location, and then call this method.
|
||||||
|
*/
|
||||||
|
Result truncate();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void flush() override;
|
||||||
|
int64 getPosition() override;
|
||||||
|
bool setPosition (int64) override;
|
||||||
|
bool write (const void*, size_t) override;
|
||||||
|
bool writeRepeatedByte (uint8 byte, size_t numTimesToRepeat) override;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
File file;
|
||||||
|
void* fileHandle;
|
||||||
|
Result status;
|
||||||
|
int64 currentPosition;
|
||||||
|
size_t bufferSize, bytesInBuffer;
|
||||||
|
HeapBlock <char> buffer;
|
||||||
|
|
||||||
|
void openHandle();
|
||||||
|
void closeHandle();
|
||||||
|
void flushInternal();
|
||||||
|
bool flushBuffer();
|
||||||
|
int64 setPositionInternal (int64);
|
||||||
|
ssize_t writeInternal (const void*, size_t);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileOutputStream)
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // JUCE_FILEOUTPUTSTREAM_H_INCLUDED
|
||||||
@@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
FileSearchPath::FileSearchPath() {}
|
||||||
|
FileSearchPath::~FileSearchPath() {}
|
||||||
|
|
||||||
|
FileSearchPath::FileSearchPath (const String& path)
|
||||||
|
{
|
||||||
|
init (path);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSearchPath::FileSearchPath (const FileSearchPath& other)
|
||||||
|
: directories (other.directories)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSearchPath& FileSearchPath::operator= (const FileSearchPath& other)
|
||||||
|
{
|
||||||
|
directories = other.directories;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSearchPath& FileSearchPath::operator= (const String& path)
|
||||||
|
{
|
||||||
|
init (path);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSearchPath::init (const String& path)
|
||||||
|
{
|
||||||
|
directories.clear();
|
||||||
|
directories.addTokens (path, ";", "\"");
|
||||||
|
directories.trim();
|
||||||
|
directories.removeEmptyStrings();
|
||||||
|
|
||||||
|
for (int i = directories.size(); --i >= 0;)
|
||||||
|
directories.set (i, directories[i].unquoted());
|
||||||
|
}
|
||||||
|
|
||||||
|
int FileSearchPath::getNumPaths() const
|
||||||
|
{
|
||||||
|
return directories.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
File FileSearchPath::operator[] (const int index) const
|
||||||
|
{
|
||||||
|
return File (directories [index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
String FileSearchPath::toString() const
|
||||||
|
{
|
||||||
|
StringArray directories2 (directories);
|
||||||
|
for (int i = directories2.size(); --i >= 0;)
|
||||||
|
if (directories2[i].containsChar (';'))
|
||||||
|
directories2.set (i, directories2[i].quoted());
|
||||||
|
|
||||||
|
return directories2.joinIntoString (";");
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSearchPath::add (const File& dir, const int insertIndex)
|
||||||
|
{
|
||||||
|
directories.insert (insertIndex, dir.getFullPathName());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSearchPath::addIfNotAlreadyThere (const File& dir)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < directories.size(); ++i)
|
||||||
|
if (File (directories[i]) == dir)
|
||||||
|
return;
|
||||||
|
|
||||||
|
add (dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSearchPath::remove (const int index)
|
||||||
|
{
|
||||||
|
directories.remove (index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSearchPath::addPath (const FileSearchPath& other)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < other.getNumPaths(); ++i)
|
||||||
|
addIfNotAlreadyThere (other[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSearchPath::removeRedundantPaths()
|
||||||
|
{
|
||||||
|
for (int i = directories.size(); --i >= 0;)
|
||||||
|
{
|
||||||
|
const File d1 (directories[i]);
|
||||||
|
|
||||||
|
for (int j = directories.size(); --j >= 0;)
|
||||||
|
{
|
||||||
|
const File d2 (directories[j]);
|
||||||
|
|
||||||
|
if ((i != j) && (d1.isAChildOf (d2) || d1 == d2))
|
||||||
|
{
|
||||||
|
directories.remove (i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSearchPath::removeNonExistentPaths()
|
||||||
|
{
|
||||||
|
for (int i = directories.size(); --i >= 0;)
|
||||||
|
if (! File (directories[i]).isDirectory())
|
||||||
|
directories.remove (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int FileSearchPath::findChildFiles (Array<File>& results,
|
||||||
|
const int whatToLookFor,
|
||||||
|
const bool searchRecursively,
|
||||||
|
const String& wildCardPattern) const
|
||||||
|
{
|
||||||
|
int total = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < directories.size(); ++i)
|
||||||
|
total += operator[] (i).findChildFiles (results,
|
||||||
|
whatToLookFor,
|
||||||
|
searchRecursively,
|
||||||
|
wildCardPattern);
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileSearchPath::isFileInPath (const File& fileToCheck,
|
||||||
|
const bool checkRecursively) const
|
||||||
|
{
|
||||||
|
for (int i = directories.size(); --i >= 0;)
|
||||||
|
{
|
||||||
|
const File d (directories[i]);
|
||||||
|
|
||||||
|
if (checkRecursively)
|
||||||
|
{
|
||||||
|
if (fileToCheck.isAChildOf (d))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (fileToCheck.getParentDirectory() == d)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_FILESEARCHPATH_H_INCLUDED
|
||||||
|
#define JUCE_FILESEARCHPATH_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Represents a set of folders that make up a search path.
|
||||||
|
|
||||||
|
@see File
|
||||||
|
*/
|
||||||
|
class JUCE_API FileSearchPath
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an empty search path. */
|
||||||
|
FileSearchPath();
|
||||||
|
|
||||||
|
/** Creates a search path from a string of pathnames.
|
||||||
|
|
||||||
|
The path can be semicolon- or comma-separated, e.g.
|
||||||
|
"/foo/bar;/foo/moose;/fish/moose"
|
||||||
|
|
||||||
|
The separate folders are tokenised and added to the search path.
|
||||||
|
*/
|
||||||
|
FileSearchPath (const String& path);
|
||||||
|
|
||||||
|
/** Creates a copy of another search path. */
|
||||||
|
FileSearchPath (const FileSearchPath&);
|
||||||
|
|
||||||
|
/** Copies another search path. */
|
||||||
|
FileSearchPath& operator= (const FileSearchPath&);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~FileSearchPath();
|
||||||
|
|
||||||
|
/** Uses a string containing a list of pathnames to re-initialise this list.
|
||||||
|
|
||||||
|
This search path is cleared and the semicolon- or comma-separated folders
|
||||||
|
in this string are added instead. e.g. "/foo/bar;/foo/moose;/fish/moose"
|
||||||
|
*/
|
||||||
|
FileSearchPath& operator= (const String& path);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the number of folders in this search path.
|
||||||
|
@see operator[]
|
||||||
|
*/
|
||||||
|
int getNumPaths() const;
|
||||||
|
|
||||||
|
/** Returns one of the folders in this search path.
|
||||||
|
The file returned isn't guaranteed to actually be a valid directory.
|
||||||
|
@see getNumPaths
|
||||||
|
*/
|
||||||
|
File operator[] (int index) const;
|
||||||
|
|
||||||
|
/** Returns the search path as a semicolon-separated list of directories. */
|
||||||
|
String toString() const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Adds a new directory to the search path.
|
||||||
|
|
||||||
|
The new directory is added to the end of the list if the insertIndex parameter is
|
||||||
|
less than zero, otherwise it is inserted at the given index.
|
||||||
|
*/
|
||||||
|
void add (const File& directoryToAdd,
|
||||||
|
int insertIndex = -1);
|
||||||
|
|
||||||
|
/** Adds a new directory to the search path if it's not already in there. */
|
||||||
|
void addIfNotAlreadyThere (const File& directoryToAdd);
|
||||||
|
|
||||||
|
/** Removes a directory from the search path. */
|
||||||
|
void remove (int indexToRemove);
|
||||||
|
|
||||||
|
/** Merges another search path into this one.
|
||||||
|
This will remove any duplicate directories.
|
||||||
|
*/
|
||||||
|
void addPath (const FileSearchPath&);
|
||||||
|
|
||||||
|
/** Removes any directories that are actually subdirectories of one of the other directories in the search path.
|
||||||
|
|
||||||
|
If the search is intended to be recursive, there's no point having nested folders in the search
|
||||||
|
path, because they'll just get searched twice and you'll get duplicate results.
|
||||||
|
|
||||||
|
e.g. if the path is "c:\abc\de;c:\abc", this method will simplify it to "c:\abc"
|
||||||
|
*/
|
||||||
|
void removeRedundantPaths();
|
||||||
|
|
||||||
|
/** Removes any directories that don't actually exist. */
|
||||||
|
void removeNonExistentPaths();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Searches the path for a wildcard.
|
||||||
|
|
||||||
|
This will search all the directories in the search path in order, adding any
|
||||||
|
matching files to the results array.
|
||||||
|
|
||||||
|
@param results an array to append the results to
|
||||||
|
@param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying whether to
|
||||||
|
return files, directories, or both.
|
||||||
|
@param searchRecursively whether to recursively search the subdirectories too
|
||||||
|
@param wildCardPattern a pattern to match against the filenames
|
||||||
|
@returns the number of files added to the array
|
||||||
|
@see File::findChildFiles
|
||||||
|
*/
|
||||||
|
int findChildFiles (Array<File>& results,
|
||||||
|
int whatToLookFor,
|
||||||
|
bool searchRecursively,
|
||||||
|
const String& wildCardPattern = "*") const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Finds out whether a file is inside one of the path's directories.
|
||||||
|
|
||||||
|
This will return true if the specified file is a child of one of the
|
||||||
|
directories specified by this path. Note that this doesn't actually do any
|
||||||
|
searching or check that the files exist - it just looks at the pathnames
|
||||||
|
to work out whether the file would be inside a directory.
|
||||||
|
|
||||||
|
@param fileToCheck the file to look for
|
||||||
|
@param checkRecursively if true, then this will return true if the file is inside a
|
||||||
|
subfolder of one of the path's directories (at any depth). If false
|
||||||
|
it will only return true if the file is actually a direct child
|
||||||
|
of one of the directories.
|
||||||
|
@see File::isAChildOf
|
||||||
|
|
||||||
|
*/
|
||||||
|
bool isFileInPath (const File& fileToCheck,
|
||||||
|
bool checkRecursively) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
StringArray directories;
|
||||||
|
|
||||||
|
void init (const String&);
|
||||||
|
|
||||||
|
JUCE_LEAK_DETECTOR (FileSearchPath)
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // JUCE_FILESEARCHPATH_H_INCLUDED
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_MEMORYMAPPEDFILE_H_INCLUDED
|
||||||
|
#define JUCE_MEMORYMAPPEDFILE_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Maps a file into virtual memory for easy reading and/or writing.
|
||||||
|
*/
|
||||||
|
class JUCE_API MemoryMappedFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** The read/write flags used when opening a memory mapped file. */
|
||||||
|
enum AccessMode
|
||||||
|
{
|
||||||
|
readOnly, /**< Indicates that the memory can only be read. */
|
||||||
|
readWrite /**< Indicates that the memory can be read and written to - changes that are
|
||||||
|
made will be flushed back to disk at the whim of the OS. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Opens a file and maps it to an area of virtual memory.
|
||||||
|
|
||||||
|
The file should already exist, and should already be the size that you want to work with
|
||||||
|
when you call this. If the file is resized after being opened, the behaviour is undefined.
|
||||||
|
|
||||||
|
If the file exists and the operation succeeds, the getData() and getSize() methods will
|
||||||
|
return the location and size of the data that can be read or written. Note that the entire
|
||||||
|
file is not read into memory immediately - the OS simply creates a virtual mapping, which
|
||||||
|
will lazily pull the data into memory when blocks are accessed.
|
||||||
|
|
||||||
|
If the file can't be opened for some reason, the getData() method will return a null pointer.
|
||||||
|
*/
|
||||||
|
MemoryMappedFile (const File& file, AccessMode mode);
|
||||||
|
|
||||||
|
/** Opens a section of a file and maps it to an area of virtual memory.
|
||||||
|
|
||||||
|
The file should already exist, and should already be the size that you want to work with
|
||||||
|
when you call this. If the file is resized after being opened, the behaviour is undefined.
|
||||||
|
|
||||||
|
If the file exists and the operation succeeds, the getData() and getSize() methods will
|
||||||
|
return the location and size of the data that can be read or written. Note that the entire
|
||||||
|
file is not read into memory immediately - the OS simply creates a virtual mapping, which
|
||||||
|
will lazily pull the data into memory when blocks are accessed.
|
||||||
|
|
||||||
|
If the file can't be opened for some reason, the getData() method will return a null pointer.
|
||||||
|
|
||||||
|
NOTE: the start of the actual range used may be rounded-down to a multiple of the OS's page-size,
|
||||||
|
so do not assume that the mapped memory will begin at exactly the position you requested - always
|
||||||
|
use getRange() to check the actual range that is being used.
|
||||||
|
*/
|
||||||
|
MemoryMappedFile (const File& file,
|
||||||
|
const Range<int64>& fileRange,
|
||||||
|
AccessMode mode);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~MemoryMappedFile();
|
||||||
|
|
||||||
|
/** Returns the address at which this file has been mapped, or a null pointer if
|
||||||
|
the file couldn't be successfully mapped.
|
||||||
|
*/
|
||||||
|
void* getData() const noexcept { return address; }
|
||||||
|
|
||||||
|
/** Returns the number of bytes of data that are available for reading or writing.
|
||||||
|
This will normally be the size of the file.
|
||||||
|
*/
|
||||||
|
size_t getSize() const noexcept { return (size_t) range.getLength(); }
|
||||||
|
|
||||||
|
/** Returns the section of the file at which the mapped memory represents. */
|
||||||
|
Range<int64> getRange() const noexcept { return range; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
void* address;
|
||||||
|
Range<int64> range;
|
||||||
|
|
||||||
|
#if JUCE_WINDOWS
|
||||||
|
void* fileHandle;
|
||||||
|
#else
|
||||||
|
int fileHandle;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void openInternal (const File&, AccessMode);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryMappedFile)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_MEMORYMAPPEDFILE_H_INCLUDED
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
static File createTempFile (const File& parentDirectory, String name,
|
||||||
|
const String& suffix, const int optionFlags)
|
||||||
|
{
|
||||||
|
if ((optionFlags & TemporaryFile::useHiddenFile) != 0)
|
||||||
|
name = "." + name;
|
||||||
|
|
||||||
|
return parentDirectory.getNonexistentChildFile (name, suffix, (optionFlags & TemporaryFile::putNumbersInBrackets) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TemporaryFile::TemporaryFile (const String& suffix, const int optionFlags)
|
||||||
|
: temporaryFile (createTempFile (File::getSpecialLocation (File::tempDirectory),
|
||||||
|
"temp_" + String::toHexString (Random::getSystemRandom().nextInt()),
|
||||||
|
suffix, optionFlags))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TemporaryFile::TemporaryFile (const File& target, const int optionFlags)
|
||||||
|
: temporaryFile (createTempFile (target.getParentDirectory(),
|
||||||
|
target.getFileNameWithoutExtension()
|
||||||
|
+ "_temp" + String::toHexString (Random::getSystemRandom().nextInt()),
|
||||||
|
target.getFileExtension(), optionFlags)),
|
||||||
|
targetFile (target)
|
||||||
|
{
|
||||||
|
// If you use this constructor, you need to give it a valid target file!
|
||||||
|
jassert (targetFile != File());
|
||||||
|
}
|
||||||
|
|
||||||
|
TemporaryFile::TemporaryFile (const File& target, const File& temporary)
|
||||||
|
: temporaryFile (temporary), targetFile (target)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TemporaryFile::~TemporaryFile()
|
||||||
|
{
|
||||||
|
if (! deleteTemporaryFile())
|
||||||
|
{
|
||||||
|
/* Failed to delete our temporary file! The most likely reason for this would be
|
||||||
|
that you've not closed an output stream that was being used to write to file.
|
||||||
|
|
||||||
|
If you find that something beyond your control is changing permissions on
|
||||||
|
your temporary files and preventing them from being deleted, you may want to
|
||||||
|
call TemporaryFile::deleteTemporaryFile() to detect those error cases and
|
||||||
|
handle them appropriately.
|
||||||
|
*/
|
||||||
|
jassertfalse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool TemporaryFile::overwriteTargetFileWithTemporary() const
|
||||||
|
{
|
||||||
|
// This method only works if you created this object with the constructor
|
||||||
|
// that takes a target file!
|
||||||
|
jassert (targetFile != File());
|
||||||
|
|
||||||
|
if (temporaryFile.exists())
|
||||||
|
{
|
||||||
|
// Have a few attempts at overwriting the file before giving up..
|
||||||
|
for (int i = 5; --i >= 0;)
|
||||||
|
{
|
||||||
|
if (temporaryFile.moveFileTo (targetFile))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Thread::sleep (100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// There's no temporary file to use. If your write failed, you should
|
||||||
|
// probably check, and not bother calling this method.
|
||||||
|
jassertfalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TemporaryFile::deleteTemporaryFile() const
|
||||||
|
{
|
||||||
|
// Have a few attempts at deleting the file before giving up..
|
||||||
|
for (int i = 5; --i >= 0;)
|
||||||
|
{
|
||||||
|
if (temporaryFile.deleteFile())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
Thread::sleep (50);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_TEMPORARYFILE_H_INCLUDED
|
||||||
|
#define JUCE_TEMPORARYFILE_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Manages a temporary file, which will be deleted when this object is deleted.
|
||||||
|
|
||||||
|
This object is intended to be used as a stack based object, using its scope
|
||||||
|
to make sure the temporary file isn't left lying around.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
File myTargetFile ("~/myfile.txt");
|
||||||
|
|
||||||
|
// this will choose a file called something like "~/myfile_temp239348.txt"
|
||||||
|
// which definitely doesn't exist at the time the constructor is called.
|
||||||
|
TemporaryFile temp (myTargetFile);
|
||||||
|
|
||||||
|
// create a stream to the temporary file, and write some data to it...
|
||||||
|
ScopedPointer <FileOutputStream> out (temp.getFile().createOutputStream());
|
||||||
|
|
||||||
|
if (out != nullptr)
|
||||||
|
{
|
||||||
|
out->write ( ...etc )
|
||||||
|
out = nullptr; // (deletes the stream)
|
||||||
|
|
||||||
|
// ..now we've finished writing, this will rename the temp file to
|
||||||
|
// make it replace the target file we specified above.
|
||||||
|
bool succeeded = temp.overwriteTargetFileWithTemporary();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ..and even if something went wrong and our overwrite failed,
|
||||||
|
// as the TemporaryFile object goes out of scope here, it'll make sure
|
||||||
|
// that the temp file gets deleted.
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@see File, FileOutputStream
|
||||||
|
*/
|
||||||
|
class JUCE_API TemporaryFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
enum OptionFlags
|
||||||
|
{
|
||||||
|
useHiddenFile = 1, /**< Indicates that the temporary file should be hidden -
|
||||||
|
i.e. its name should start with a dot. */
|
||||||
|
putNumbersInBrackets = 2 /**< Indicates that when numbers are appended to make sure
|
||||||
|
the file is unique, they should go in brackets rather
|
||||||
|
than just being appended (see File::getNonexistentSibling() )*/
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a randomly-named temporary file in the default temp directory.
|
||||||
|
|
||||||
|
@param suffix a file suffix to use for the file
|
||||||
|
@param optionFlags a combination of the values listed in the OptionFlags enum
|
||||||
|
The file will not be created until you write to it. And remember that when
|
||||||
|
this object is deleted, the file will also be deleted!
|
||||||
|
*/
|
||||||
|
TemporaryFile (const String& suffix = String(),
|
||||||
|
int optionFlags = 0);
|
||||||
|
|
||||||
|
/** Creates a temporary file in the same directory as a specified file.
|
||||||
|
|
||||||
|
This is useful if you have a file that you want to overwrite, but don't
|
||||||
|
want to harm the original file if the write operation fails. You can
|
||||||
|
use this to create a temporary file next to the target file, then
|
||||||
|
write to the temporary file, and finally use overwriteTargetFileWithTemporary()
|
||||||
|
to replace the target file with the one you've just written.
|
||||||
|
|
||||||
|
This class won't create any files until you actually write to them. And remember
|
||||||
|
that when this object is deleted, the temporary file will also be deleted!
|
||||||
|
|
||||||
|
@param targetFile the file that you intend to overwrite - the temporary
|
||||||
|
file will be created in the same directory as this
|
||||||
|
@param optionFlags a combination of the values listed in the OptionFlags enum
|
||||||
|
*/
|
||||||
|
TemporaryFile (const File& targetFile,
|
||||||
|
int optionFlags = 0);
|
||||||
|
|
||||||
|
/** Creates a temporary file using an explicit filename.
|
||||||
|
The other constructors are a better choice than this one, unless for some reason
|
||||||
|
you need to explicitly specify the temporary file you want to use.
|
||||||
|
|
||||||
|
@param targetFile the file that you intend to overwrite
|
||||||
|
@param temporaryFile the temporary file to be used
|
||||||
|
*/
|
||||||
|
TemporaryFile (const File& targetFile,
|
||||||
|
const File& temporaryFile);
|
||||||
|
|
||||||
|
/** Destructor.
|
||||||
|
|
||||||
|
When this object is deleted it will make sure that its temporary file is
|
||||||
|
also deleted! If the operation fails, it'll throw an assertion in debug
|
||||||
|
mode.
|
||||||
|
*/
|
||||||
|
~TemporaryFile();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the temporary file. */
|
||||||
|
const File& getFile() const noexcept { return temporaryFile; }
|
||||||
|
|
||||||
|
/** Returns the target file that was specified in the constructor. */
|
||||||
|
const File& getTargetFile() const noexcept { return targetFile; }
|
||||||
|
|
||||||
|
/** Tries to move the temporary file to overwrite the target file that was
|
||||||
|
specified in the constructor.
|
||||||
|
|
||||||
|
If you used the constructor that specified a target file, this will attempt
|
||||||
|
to replace that file with the temporary one.
|
||||||
|
|
||||||
|
Before calling this, make sure:
|
||||||
|
- that you've actually written to the temporary file
|
||||||
|
- that you've closed any open streams that you were using to write to it
|
||||||
|
- and that you don't have any streams open to the target file, which would
|
||||||
|
prevent it being overwritten
|
||||||
|
|
||||||
|
If the file move succeeds, this returns false, and the temporary file will
|
||||||
|
have disappeared. If it fails, the temporary file will probably still exist,
|
||||||
|
but will be deleted when this object is destroyed.
|
||||||
|
*/
|
||||||
|
bool overwriteTargetFileWithTemporary() const;
|
||||||
|
|
||||||
|
/** Attempts to delete the temporary file, if it exists.
|
||||||
|
@returns true if the file is successfully deleted (or if it didn't exist).
|
||||||
|
*/
|
||||||
|
bool deleteTemporaryFile() const;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
const File temporaryFile, targetFile;
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TemporaryFile)
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // JUCE_TEMPORARYFILE_H_INCLUDED
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void parseWildcard (const String& pattern, StringArray& result)
|
||||||
|
{
|
||||||
|
result.addTokens (pattern.toLowerCase(), ";,", "\"'");
|
||||||
|
|
||||||
|
result.trim();
|
||||||
|
result.removeEmptyStrings();
|
||||||
|
|
||||||
|
// special case for *.*, because people use it to mean "any file", but it
|
||||||
|
// would actually ignore files with no extension.
|
||||||
|
for (int i = result.size(); --i >= 0;)
|
||||||
|
if (result[i] == "*.*")
|
||||||
|
result.set (i, "*");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool matchWildcard (const File& file, const StringArray& wildcards)
|
||||||
|
{
|
||||||
|
const String filename (file.getFileName());
|
||||||
|
|
||||||
|
for (int i = wildcards.size(); --i >= 0;)
|
||||||
|
if (filename.matchesWildcard (wildcards[i], true))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_WILDCARDFILEFILTER_H_INCLUDED
|
||||||
|
#define JUCE_WILDCARDFILEFILTER_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A type of FileFilter that works by wildcard pattern matching.
|
||||||
|
|
||||||
|
This filter only allows files that match one of the specified patterns, but
|
||||||
|
allows all directories through.
|
||||||
|
|
||||||
|
@see FileFilter, DirectoryContentsList, FileListComponent, FileBrowserComponent
|
||||||
|
*/
|
||||||
|
class JUCE_API WildcardFileFilter : public FileFilter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Creates a wildcard filter for one or more patterns.
|
||||||
|
|
||||||
|
The wildcardPatterns parameter is a comma or semicolon-delimited set of
|
||||||
|
patterns, e.g. "*.wav;*.aiff" would look for files ending in either .wav
|
||||||
|
or .aiff.
|
||||||
|
|
||||||
|
Passing an empty string as a pattern will fail to match anything, so by leaving
|
||||||
|
either the file or directory pattern parameter empty means you can control
|
||||||
|
whether files or directories are found.
|
||||||
|
|
||||||
|
The description is a name to show the user in a list of possible patterns, so
|
||||||
|
for the wav/aiff example, your description might be "audio files".
|
||||||
|
*/
|
||||||
|
WildcardFileFilter (const String& fileWildcardPatterns,
|
||||||
|
const String& directoryWildcardPatterns,
|
||||||
|
const String& description);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~WildcardFileFilter();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns true if the filename matches one of the patterns specified. */
|
||||||
|
bool isFileSuitable (const File& file) const;
|
||||||
|
|
||||||
|
/** This always returns true. */
|
||||||
|
bool isDirectorySuitable (const File& file) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
StringArray fileWildcards, directoryWildcards;
|
||||||
|
|
||||||
|
JUCE_LEAK_DETECTOR (WildcardFileFilter)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_WILDCARDFILEFILTER_H_INCLUDED
|
||||||
@@ -0,0 +1,643 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
class JSONParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static Result parseObjectOrArray (String::CharPointerType t, var& result)
|
||||||
|
{
|
||||||
|
t = t.findEndOfWhitespace();
|
||||||
|
|
||||||
|
switch (t.getAndAdvance())
|
||||||
|
{
|
||||||
|
case 0: result = var(); return Result::ok();
|
||||||
|
case '{': return parseObject (t, result);
|
||||||
|
case '[': return parseArray (t, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return createFail ("Expected '{' or '['", &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result parseString (const juce_wchar quoteChar, String::CharPointerType& t, var& result)
|
||||||
|
{
|
||||||
|
MemoryOutputStream buffer (256);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
juce_wchar c = t.getAndAdvance();
|
||||||
|
|
||||||
|
if (c == quoteChar)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (c == '\\')
|
||||||
|
{
|
||||||
|
c = t.getAndAdvance();
|
||||||
|
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '"':
|
||||||
|
case '\'':
|
||||||
|
case '\\':
|
||||||
|
case '/': break;
|
||||||
|
|
||||||
|
case 'a': c = '\a'; break;
|
||||||
|
case 'b': c = '\b'; break;
|
||||||
|
case 'f': c = '\f'; break;
|
||||||
|
case 'n': c = '\n'; break;
|
||||||
|
case 'r': c = '\r'; break;
|
||||||
|
case 't': c = '\t'; break;
|
||||||
|
|
||||||
|
case 'u':
|
||||||
|
{
|
||||||
|
c = 0;
|
||||||
|
|
||||||
|
for (int i = 4; --i >= 0;)
|
||||||
|
{
|
||||||
|
const int digitValue = CharacterFunctions::getHexDigitValue (t.getAndAdvance());
|
||||||
|
if (digitValue < 0)
|
||||||
|
return createFail ("Syntax error in unicode escape sequence");
|
||||||
|
|
||||||
|
c = (juce_wchar) ((c << 4) + digitValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 0)
|
||||||
|
return createFail ("Unexpected end-of-input in string constant");
|
||||||
|
|
||||||
|
buffer.appendUTF8Char (c);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = buffer.toUTF8();
|
||||||
|
return Result::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result parseAny (String::CharPointerType& t, var& result)
|
||||||
|
{
|
||||||
|
t = t.findEndOfWhitespace();
|
||||||
|
String::CharPointerType t2 (t);
|
||||||
|
|
||||||
|
switch (t2.getAndAdvance())
|
||||||
|
{
|
||||||
|
case '{': t = t2; return parseObject (t, result);
|
||||||
|
case '[': t = t2; return parseArray (t, result);
|
||||||
|
case '"': t = t2; return parseString ('"', t, result);
|
||||||
|
case '\'': t = t2; return parseString ('\'', t, result);
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
t2 = t2.findEndOfWhitespace();
|
||||||
|
if (! CharacterFunctions::isDigit (*t2))
|
||||||
|
break;
|
||||||
|
|
||||||
|
t = t2;
|
||||||
|
return parseNumber (t, result, true);
|
||||||
|
|
||||||
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
|
return parseNumber (t, result, false);
|
||||||
|
|
||||||
|
case 't': // "true"
|
||||||
|
if (t2.getAndAdvance() == 'r' && t2.getAndAdvance() == 'u' && t2.getAndAdvance() == 'e')
|
||||||
|
{
|
||||||
|
t = t2;
|
||||||
|
result = var (true);
|
||||||
|
return Result::ok();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'f': // "false"
|
||||||
|
if (t2.getAndAdvance() == 'a' && t2.getAndAdvance() == 'l'
|
||||||
|
&& t2.getAndAdvance() == 's' && t2.getAndAdvance() == 'e')
|
||||||
|
{
|
||||||
|
t = t2;
|
||||||
|
result = var (false);
|
||||||
|
return Result::ok();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'n': // "null"
|
||||||
|
if (t2.getAndAdvance() == 'u' && t2.getAndAdvance() == 'l' && t2.getAndAdvance() == 'l')
|
||||||
|
{
|
||||||
|
t = t2;
|
||||||
|
result = var();
|
||||||
|
return Result::ok();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return createFail ("Syntax error", &t);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Result createFail (const char* const message, const String::CharPointerType* location = nullptr)
|
||||||
|
{
|
||||||
|
String m (message);
|
||||||
|
if (location != nullptr)
|
||||||
|
m << ": \"" << String (*location, 20) << '"';
|
||||||
|
|
||||||
|
return Result::fail (m);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result parseNumber (String::CharPointerType& t, var& result, const bool isNegative)
|
||||||
|
{
|
||||||
|
String::CharPointerType oldT (t);
|
||||||
|
|
||||||
|
int64 intValue = t.getAndAdvance() - '0';
|
||||||
|
jassert (intValue >= 0 && intValue < 10);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
String::CharPointerType previousChar (t);
|
||||||
|
const juce_wchar c = t.getAndAdvance();
|
||||||
|
const int digit = ((int) c) - '0';
|
||||||
|
|
||||||
|
if (isPositiveAndBelow (digit, 10))
|
||||||
|
{
|
||||||
|
intValue = intValue * 10 + digit;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == 'e' || c == 'E' || c == '.')
|
||||||
|
{
|
||||||
|
t = oldT;
|
||||||
|
const double asDouble = CharacterFunctions::readDoubleValue (t);
|
||||||
|
result = isNegative ? -asDouble : asDouble;
|
||||||
|
return Result::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CharacterFunctions::isWhitespace (c)
|
||||||
|
|| c == ',' || c == '}' || c == ']' || c == 0)
|
||||||
|
{
|
||||||
|
t = previousChar;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return createFail ("Syntax error in number", &oldT);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int64 correctedValue = isNegative ? -intValue : intValue;
|
||||||
|
|
||||||
|
if ((intValue >> 31) != 0)
|
||||||
|
result = correctedValue;
|
||||||
|
else
|
||||||
|
result = (int) correctedValue;
|
||||||
|
|
||||||
|
return Result::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result parseObject (String::CharPointerType& t, var& result)
|
||||||
|
{
|
||||||
|
DynamicObject* const resultObject = new DynamicObject();
|
||||||
|
result = resultObject;
|
||||||
|
NamedValueSet& resultProperties = resultObject->getProperties();
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
t = t.findEndOfWhitespace();
|
||||||
|
|
||||||
|
String::CharPointerType oldT (t);
|
||||||
|
const juce_wchar c = t.getAndAdvance();
|
||||||
|
|
||||||
|
if (c == '}')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (c == 0)
|
||||||
|
return createFail ("Unexpected end-of-input in object declaration");
|
||||||
|
|
||||||
|
if (c == '"')
|
||||||
|
{
|
||||||
|
var propertyNameVar;
|
||||||
|
Result r (parseString ('"', t, propertyNameVar));
|
||||||
|
|
||||||
|
if (r.failed())
|
||||||
|
return r;
|
||||||
|
|
||||||
|
const Identifier propertyName (propertyNameVar.toString());
|
||||||
|
|
||||||
|
if (propertyName.isValid())
|
||||||
|
{
|
||||||
|
t = t.findEndOfWhitespace();
|
||||||
|
oldT = t;
|
||||||
|
|
||||||
|
const juce_wchar c2 = t.getAndAdvance();
|
||||||
|
if (c2 != ':')
|
||||||
|
return createFail ("Expected ':', but found", &oldT);
|
||||||
|
|
||||||
|
resultProperties.set (propertyName, var());
|
||||||
|
var* propertyValue = resultProperties.getVarPointer (propertyName);
|
||||||
|
|
||||||
|
Result r2 (parseAny (t, *propertyValue));
|
||||||
|
|
||||||
|
if (r2.failed())
|
||||||
|
return r2;
|
||||||
|
|
||||||
|
t = t.findEndOfWhitespace();
|
||||||
|
oldT = t;
|
||||||
|
|
||||||
|
const juce_wchar nextChar = t.getAndAdvance();
|
||||||
|
|
||||||
|
if (nextChar == ',')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (nextChar == '}')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return createFail ("Expected object member declaration, but found", &oldT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result::ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result parseArray (String::CharPointerType& t, var& result)
|
||||||
|
{
|
||||||
|
result = var (Array<var>());
|
||||||
|
Array<var>* const destArray = result.getArray();
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
t = t.findEndOfWhitespace();
|
||||||
|
|
||||||
|
String::CharPointerType oldT (t);
|
||||||
|
const juce_wchar c = t.getAndAdvance();
|
||||||
|
|
||||||
|
if (c == ']')
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (c == 0)
|
||||||
|
return createFail ("Unexpected end-of-input in array declaration");
|
||||||
|
|
||||||
|
t = oldT;
|
||||||
|
destArray->add (var());
|
||||||
|
Result r (parseAny (t, destArray->getReference (destArray->size() - 1)));
|
||||||
|
|
||||||
|
if (r.failed())
|
||||||
|
return r;
|
||||||
|
|
||||||
|
t = t.findEndOfWhitespace();
|
||||||
|
oldT = t;
|
||||||
|
|
||||||
|
const juce_wchar nextChar = t.getAndAdvance();
|
||||||
|
|
||||||
|
if (nextChar == ',')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (nextChar == ']')
|
||||||
|
break;
|
||||||
|
|
||||||
|
return createFail ("Expected object array item, but found", &oldT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Result::ok();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class JSONFormatter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void write (OutputStream& out, const var& v,
|
||||||
|
const int indentLevel, const bool allOnOneLine)
|
||||||
|
{
|
||||||
|
if (v.isString())
|
||||||
|
{
|
||||||
|
out << '"';
|
||||||
|
writeString (out, v.toString().getCharPointer());
|
||||||
|
out << '"';
|
||||||
|
}
|
||||||
|
else if (v.isVoid())
|
||||||
|
{
|
||||||
|
out << "null";
|
||||||
|
}
|
||||||
|
else if (v.isUndefined())
|
||||||
|
{
|
||||||
|
out << "undefined";
|
||||||
|
}
|
||||||
|
else if (v.isBool())
|
||||||
|
{
|
||||||
|
out << (static_cast<bool> (v) ? "true" : "false");
|
||||||
|
}
|
||||||
|
else if (v.isArray())
|
||||||
|
{
|
||||||
|
writeArray (out, *v.getArray(), indentLevel, allOnOneLine);
|
||||||
|
}
|
||||||
|
else if (v.isObject())
|
||||||
|
{
|
||||||
|
if (DynamicObject* object = v.getDynamicObject())
|
||||||
|
object->writeAsJSON (out, indentLevel, allOnOneLine);
|
||||||
|
else
|
||||||
|
jassertfalse; // Only DynamicObjects can be converted to JSON!
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Can't convert these other types of object to JSON!
|
||||||
|
jassert (! (v.isMethod() || v.isBinaryData()));
|
||||||
|
|
||||||
|
out << v.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeEscapedChar (OutputStream& out, const unsigned short value)
|
||||||
|
{
|
||||||
|
out << "\\u" << String::toHexString ((int) value).paddedLeft ('0', 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeString (OutputStream& out, String::CharPointerType t)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const juce_wchar c (t.getAndAdvance());
|
||||||
|
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 0: return;
|
||||||
|
|
||||||
|
case '\"': out << "\\\""; break;
|
||||||
|
case '\\': out << "\\\\"; break;
|
||||||
|
case '\a': out << "\\a"; break;
|
||||||
|
case '\b': out << "\\b"; break;
|
||||||
|
case '\f': out << "\\f"; break;
|
||||||
|
case '\t': out << "\\t"; break;
|
||||||
|
case '\r': out << "\\r"; break;
|
||||||
|
case '\n': out << "\\n"; break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (c >= 32 && c < 127)
|
||||||
|
{
|
||||||
|
out << (char) c;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (CharPointer_UTF16::getBytesRequiredFor (c) > 2)
|
||||||
|
{
|
||||||
|
CharPointer_UTF16::CharType chars[2];
|
||||||
|
CharPointer_UTF16 utf16 (chars);
|
||||||
|
utf16.write (c);
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; ++i)
|
||||||
|
writeEscapedChar (out, (unsigned short) chars[i]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writeEscapedChar (out, (unsigned short) c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeSpaces (OutputStream& out, int numSpaces)
|
||||||
|
{
|
||||||
|
out.writeRepeatedByte (' ', (size_t) numSpaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeArray (OutputStream& out, const Array<var>& array,
|
||||||
|
const int indentLevel, const bool allOnOneLine)
|
||||||
|
{
|
||||||
|
out << '[';
|
||||||
|
|
||||||
|
if (array.size() > 0)
|
||||||
|
{
|
||||||
|
if (! allOnOneLine)
|
||||||
|
out << newLine;
|
||||||
|
|
||||||
|
for (int i = 0; i < array.size(); ++i)
|
||||||
|
{
|
||||||
|
if (! allOnOneLine)
|
||||||
|
writeSpaces (out, indentLevel + indentSize);
|
||||||
|
|
||||||
|
write (out, array.getReference(i), indentLevel + indentSize, allOnOneLine);
|
||||||
|
|
||||||
|
if (i < array.size() - 1)
|
||||||
|
{
|
||||||
|
if (allOnOneLine)
|
||||||
|
out << ", ";
|
||||||
|
else
|
||||||
|
out << ',' << newLine;
|
||||||
|
}
|
||||||
|
else if (! allOnOneLine)
|
||||||
|
out << newLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! allOnOneLine)
|
||||||
|
writeSpaces (out, indentLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
out << ']';
|
||||||
|
}
|
||||||
|
|
||||||
|
enum { indentSize = 2 };
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
var JSON::parse (const String& text)
|
||||||
|
{
|
||||||
|
var result;
|
||||||
|
|
||||||
|
if (! parse (text, result))
|
||||||
|
result = var();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
var JSON::fromString (StringRef text)
|
||||||
|
{
|
||||||
|
var result;
|
||||||
|
|
||||||
|
if (! JSONParser::parseAny (text.text, result))
|
||||||
|
result = var();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
var JSON::parse (InputStream& input)
|
||||||
|
{
|
||||||
|
return parse (input.readEntireStreamAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
var JSON::parse (const File& file)
|
||||||
|
{
|
||||||
|
return parse (file.loadFileAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
Result JSON::parse (const String& text, var& result)
|
||||||
|
{
|
||||||
|
return JSONParser::parseObjectOrArray (text.getCharPointer(), result);
|
||||||
|
}
|
||||||
|
|
||||||
|
String JSON::toString (const var& data, const bool allOnOneLine)
|
||||||
|
{
|
||||||
|
MemoryOutputStream mo (1024);
|
||||||
|
JSONFormatter::write (mo, data, 0, allOnOneLine);
|
||||||
|
return mo.toUTF8();
|
||||||
|
}
|
||||||
|
|
||||||
|
void JSON::writeToStream (OutputStream& output, const var& data, const bool allOnOneLine)
|
||||||
|
{
|
||||||
|
JSONFormatter::write (output, data, 0, allOnOneLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
String JSON::escapeString (StringRef s)
|
||||||
|
{
|
||||||
|
MemoryOutputStream mo;
|
||||||
|
JSONFormatter::writeString (mo, s.text);
|
||||||
|
return mo.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result JSON::parseQuotedString (String::CharPointerType& t, var& result)
|
||||||
|
{
|
||||||
|
const juce_wchar quote = t.getAndAdvance();
|
||||||
|
|
||||||
|
if (quote == '"' || quote == '\'')
|
||||||
|
return JSONParser::parseString (quote, t, result);
|
||||||
|
|
||||||
|
return Result::fail ("Not a quoted string!");
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
//==============================================================================
|
||||||
|
#if JUCE_UNIT_TESTS
|
||||||
|
|
||||||
|
class JSONTests : public UnitTest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
JSONTests() : UnitTest ("JSON") {}
|
||||||
|
|
||||||
|
static String createRandomWideCharString (Random& r)
|
||||||
|
{
|
||||||
|
juce_wchar buffer[40] = { 0 };
|
||||||
|
|
||||||
|
for (int i = 0; i < numElementsInArray (buffer) - 1; ++i)
|
||||||
|
{
|
||||||
|
if (r.nextBool())
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
buffer[i] = (juce_wchar) (1 + r.nextInt (0x10ffff - 1));
|
||||||
|
}
|
||||||
|
while (! CharPointer_UTF16::canRepresent (buffer[i]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
buffer[i] = (juce_wchar) (1 + r.nextInt (0xff));
|
||||||
|
}
|
||||||
|
|
||||||
|
return CharPointer_UTF32 (buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static String createRandomIdentifier (Random& r)
|
||||||
|
{
|
||||||
|
char buffer[30] = { 0 };
|
||||||
|
|
||||||
|
for (int i = 0; i < numElementsInArray (buffer) - 1; ++i)
|
||||||
|
{
|
||||||
|
static const char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-:";
|
||||||
|
buffer[i] = chars [r.nextInt (sizeof (chars) - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return CharPointer_ASCII (buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static var createRandomVar (Random& r, int depth)
|
||||||
|
{
|
||||||
|
switch (r.nextInt (depth > 3 ? 6 : 8))
|
||||||
|
{
|
||||||
|
case 0: return var();
|
||||||
|
case 1: return r.nextInt();
|
||||||
|
case 2: return r.nextInt64();
|
||||||
|
case 3: return r.nextBool();
|
||||||
|
case 4: return r.nextDouble();
|
||||||
|
case 5: return createRandomWideCharString (r);
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
{
|
||||||
|
var v (createRandomVar (r, depth + 1));
|
||||||
|
|
||||||
|
for (int i = 1 + r.nextInt (30); --i >= 0;)
|
||||||
|
v.append (createRandomVar (r, depth + 1));
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
{
|
||||||
|
DynamicObject* o = new DynamicObject();
|
||||||
|
|
||||||
|
for (int i = r.nextInt (30); --i >= 0;)
|
||||||
|
o->setProperty (createRandomIdentifier (r), createRandomVar (r, depth + 1));
|
||||||
|
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return var();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void runTest()
|
||||||
|
{
|
||||||
|
beginTest ("JSON");
|
||||||
|
Random r = getRandom();
|
||||||
|
|
||||||
|
expect (JSON::parse (String::empty) == var::null);
|
||||||
|
expect (JSON::parse ("{}").isObject());
|
||||||
|
expect (JSON::parse ("[]").isArray());
|
||||||
|
expect (JSON::parse ("[ 1234 ]")[0].isInt());
|
||||||
|
expect (JSON::parse ("[ 12345678901234 ]")[0].isInt64());
|
||||||
|
expect (JSON::parse ("[ 1.123e3 ]")[0].isDouble());
|
||||||
|
expect (JSON::parse ("[ -1234]")[0].isInt());
|
||||||
|
expect (JSON::parse ("[-12345678901234]")[0].isInt64());
|
||||||
|
expect (JSON::parse ("[-1.123e3]")[0].isDouble());
|
||||||
|
|
||||||
|
for (int i = 100; --i >= 0;)
|
||||||
|
{
|
||||||
|
var v;
|
||||||
|
|
||||||
|
if (i > 0)
|
||||||
|
v = createRandomVar (r, 0);
|
||||||
|
|
||||||
|
const bool oneLine = r.nextBool();
|
||||||
|
String asString (JSON::toString (v, oneLine));
|
||||||
|
var parsed = JSON::parse ("[" + asString + "]")[0];
|
||||||
|
String parsedString (JSON::toString (parsed, oneLine));
|
||||||
|
expect (asString.isNotEmpty() && parsedString == asString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static JSONTests JSONUnitTests;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_JSON_H_INCLUDED
|
||||||
|
#define JUCE_JSON_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Contains static methods for converting JSON-formatted text to and from var objects.
|
||||||
|
|
||||||
|
The var class is structurally compatible with JSON-formatted data, so these
|
||||||
|
functions allow you to parse JSON into a var object, and to convert a var
|
||||||
|
object to JSON-formatted text.
|
||||||
|
|
||||||
|
@see var
|
||||||
|
*/
|
||||||
|
class JUCE_API JSON
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Parses a string of JSON-formatted text, and returns a result code containing
|
||||||
|
any parse errors.
|
||||||
|
|
||||||
|
This will return the parsed structure in the parsedResult parameter, and will
|
||||||
|
return a Result object to indicate whether parsing was successful, and if not,
|
||||||
|
it will contain an error message.
|
||||||
|
|
||||||
|
If you're not interested in the error message, you can use one of the other
|
||||||
|
shortcut parse methods, which simply return a var::null if the parsing fails.
|
||||||
|
|
||||||
|
Note that this will only parse valid JSON, which means that the item given must
|
||||||
|
be either an object or an array definition. If you want to also be able to parse
|
||||||
|
any kind of primitive JSON object, use the fromString() method.
|
||||||
|
*/
|
||||||
|
static Result parse (const String& text, var& parsedResult);
|
||||||
|
|
||||||
|
/** Attempts to parse some JSON-formatted text, and returns the result as a var object.
|
||||||
|
|
||||||
|
If the parsing fails, this simply returns var::null - if you need to find out more
|
||||||
|
detail about the parse error, use the alternative parse() method which returns a Result.
|
||||||
|
|
||||||
|
Note that this will only parse valid JSON, which means that the item given must
|
||||||
|
be either an object or an array definition. If you want to also be able to parse
|
||||||
|
any kind of primitive JSON object, use the fromString() method.
|
||||||
|
*/
|
||||||
|
static var parse (const String& text);
|
||||||
|
|
||||||
|
/** Attempts to parse some JSON-formatted text from a file, and returns the result
|
||||||
|
as a var object.
|
||||||
|
|
||||||
|
Note that this is just a short-cut for reading the entire file into a string and
|
||||||
|
parsing the result.
|
||||||
|
|
||||||
|
If the parsing fails, this simply returns var::null - if you need to find out more
|
||||||
|
detail about the parse error, use the alternative parse() method which returns a Result.
|
||||||
|
*/
|
||||||
|
static var parse (const File& file);
|
||||||
|
|
||||||
|
/** Attempts to parse some JSON-formatted text from a stream, and returns the result
|
||||||
|
as a var object.
|
||||||
|
|
||||||
|
Note that this is just a short-cut for reading the entire stream into a string and
|
||||||
|
parsing the result.
|
||||||
|
|
||||||
|
If the parsing fails, this simply returns var::null - if you need to find out more
|
||||||
|
detail about the parse error, use the alternative parse() method which returns a Result.
|
||||||
|
*/
|
||||||
|
static var parse (InputStream& input);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a string which contains a JSON-formatted representation of the var object.
|
||||||
|
If allOnOneLine is true, the result will be compacted into a single line of text
|
||||||
|
with no carriage-returns. If false, it will be laid-out in a more human-readable format.
|
||||||
|
@see writeToStream
|
||||||
|
*/
|
||||||
|
static String toString (const var& objectToFormat,
|
||||||
|
bool allOnOneLine = false);
|
||||||
|
|
||||||
|
/** Parses a string that was created with the toString() method.
|
||||||
|
This is slightly different to the parse() methods because they will reject primitive
|
||||||
|
values and only accept array or object definitions, whereas this method will handle
|
||||||
|
either.
|
||||||
|
*/
|
||||||
|
static var fromString (StringRef);
|
||||||
|
|
||||||
|
/** Writes a JSON-formatted representation of the var object to the given stream.
|
||||||
|
If allOnOneLine is true, the result will be compacted into a single line of text
|
||||||
|
with no carriage-returns. If false, it will be laid-out in a more human-readable format.
|
||||||
|
@see toString
|
||||||
|
*/
|
||||||
|
static void writeToStream (OutputStream& output,
|
||||||
|
const var& objectToFormat,
|
||||||
|
bool allOnOneLine = false);
|
||||||
|
|
||||||
|
/** Returns a version of a string with any extended characters escaped. */
|
||||||
|
static String escapeString (StringRef);
|
||||||
|
|
||||||
|
/** Parses a quoted string-literal in JSON format, returning the un-escaped result in the
|
||||||
|
result parameter, and an error message in case the content was illegal.
|
||||||
|
This advances the text parameter, leaving it positioned after the closing quote.
|
||||||
|
*/
|
||||||
|
static Result parseQuotedString (String::CharPointerType& text, var& result);
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
JSON() JUCE_DELETED_FUNCTION; // This class can't be instantiated - just use its static methods.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_JSON_H_INCLUDED
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
A simple javascript interpreter!
|
||||||
|
|
||||||
|
It's not fully standards-compliant, and won't be as fast as the fancy JIT-compiled
|
||||||
|
engines that you get in browsers, but this is an extremely compact, low-overhead javascript
|
||||||
|
interpreter, which is integrated with the juce var and DynamicObject classes. If you need
|
||||||
|
a few simple bits of scripting in your app, and want to be able to easily let the JS
|
||||||
|
work with native objects defined as DynamicObject subclasses, then this might do the job.
|
||||||
|
|
||||||
|
To use, simply create an instance of this class and call execute() to run your code.
|
||||||
|
Variables that the script sets can be retrieved with evaluate(), and if you need to provide
|
||||||
|
native objects for the script to use, you can add them with registerNativeObject().
|
||||||
|
|
||||||
|
One caveat: Because the values and objects that the engine works with are DynamicObject
|
||||||
|
and var objects, they use reference-counting rather than garbage-collection, so if your
|
||||||
|
script creates complex connections between objects, you run the risk of creating cyclic
|
||||||
|
dependencies and hence leaking.
|
||||||
|
*/
|
||||||
|
class JavascriptEngine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Creates an instance of the engine.
|
||||||
|
This creates a root namespace and defines some basic Object, String, Array
|
||||||
|
and Math library methods.
|
||||||
|
*/
|
||||||
|
JavascriptEngine();
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~JavascriptEngine();
|
||||||
|
|
||||||
|
/** Attempts to parse and run a block of javascript code.
|
||||||
|
If there's a parse or execution error, the error description is returned in
|
||||||
|
the result.
|
||||||
|
You can specify a maximum time for which the program is allowed to run, and
|
||||||
|
it'll return with an error message if this time is exceeded.
|
||||||
|
*/
|
||||||
|
Result execute (const String& javascriptCode);
|
||||||
|
|
||||||
|
/** Attempts to parse and run a javascript expression, and returns the result.
|
||||||
|
If there's a syntax error, or the expression can't be evaluated, the return value
|
||||||
|
will be var::undefined(). The errorMessage parameter gives you a way to find out
|
||||||
|
any parsing errors.
|
||||||
|
You can specify a maximum time for which the program is allowed to run, and
|
||||||
|
it'll return with an error message if this time is exceeded.
|
||||||
|
*/
|
||||||
|
var evaluate (const String& javascriptCode,
|
||||||
|
Result* errorMessage = nullptr);
|
||||||
|
|
||||||
|
/** Calls a function in the root namespace, and returns the result.
|
||||||
|
The function arguments are passed in the same format as used by native
|
||||||
|
methods in the var class.
|
||||||
|
*/
|
||||||
|
var callFunction (Identifier function,
|
||||||
|
const var::NativeFunctionArgs& args,
|
||||||
|
Result* errorMessage = nullptr);
|
||||||
|
|
||||||
|
/** Adds a native object to the root namespace.
|
||||||
|
The object passed-in is reference-counted, and will be retained by the
|
||||||
|
engine until the engine is deleted. The name must be a simple JS identifier,
|
||||||
|
without any dots.
|
||||||
|
*/
|
||||||
|
void registerNativeObject (Identifier objectName, DynamicObject* object);
|
||||||
|
|
||||||
|
/** This value indicates how long a call to one of the evaluate methods is permitted
|
||||||
|
to run before timing-out and failing.
|
||||||
|
The default value is a number of seconds, but you can change this to whatever value
|
||||||
|
suits your application.
|
||||||
|
*/
|
||||||
|
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)
|
||||||
|
const ReferenceCountedObjectPtr<RootObject> root;
|
||||||
|
void prepareTimeout() const noexcept;
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JavascriptEngine)
|
||||||
|
};
|
||||||
@@ -0,0 +1,226 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined (JUCE_CORE_H_INCLUDED) && ! JUCE_AMALGAMATED_INCLUDE
|
||||||
|
/* When you add this cpp file to your project, you mustn't include it in a file where you've
|
||||||
|
already included any other headers - just put it inside a file on its own, possibly with your config
|
||||||
|
flags preceding it, but don't include anything else. That also includes avoiding any automatic prefix
|
||||||
|
header files that the compiler may be using.
|
||||||
|
*/
|
||||||
|
#error "Incorrect use of JUCE cpp file"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Your project must contain an AppConfig.h file with your project-specific settings in it,
|
||||||
|
// and your header search path must make it accessible to the module's files.
|
||||||
|
#include "AppConfig.h"
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#include "native/juce_BasicNativeHeaders.h"
|
||||||
|
#include "juce_core.h"
|
||||||
|
|
||||||
|
#include <locale>
|
||||||
|
#include <cctype>
|
||||||
|
#include <sys/timeb.h>
|
||||||
|
|
||||||
|
#if ! JUCE_ANDROID
|
||||||
|
#include <cwctype>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JUCE_WINDOWS
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
#define _WINSOCK_DEPRECATED_NO_WARNINGS 1
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
|
||||||
|
#if ! JUCE_MINGW
|
||||||
|
#include <Dbghelp.h>
|
||||||
|
|
||||||
|
#if ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||||
|
#pragma comment (lib, "DbgHelp.lib")
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JUCE_MINGW
|
||||||
|
#include <ws2spi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
#if JUCE_LINUX || JUCE_ANDROID
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JUCE_LINUX
|
||||||
|
#include <langinfo.h>
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#if ! JUCE_ANDROID
|
||||||
|
#include <execinfo.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JUCE_MAC || JUCE_IOS
|
||||||
|
#include <xlocale.h>
|
||||||
|
#include <mach/mach.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JUCE_ANDROID
|
||||||
|
#include <android/log.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
namespace juce
|
||||||
|
{
|
||||||
|
|
||||||
|
#include "containers/juce_AbstractFifo.cpp"
|
||||||
|
#include "containers/juce_NamedValueSet.cpp"
|
||||||
|
#include "containers/juce_PropertySet.cpp"
|
||||||
|
#include "containers/juce_Variant.cpp"
|
||||||
|
#include "files/juce_DirectoryIterator.cpp"
|
||||||
|
#include "files/juce_File.cpp"
|
||||||
|
#include "files/juce_FileInputStream.cpp"
|
||||||
|
#include "files/juce_FileOutputStream.cpp"
|
||||||
|
#include "files/juce_FileSearchPath.cpp"
|
||||||
|
#include "files/juce_TemporaryFile.cpp"
|
||||||
|
#include "javascript/juce_JSON.cpp"
|
||||||
|
#include "javascript/juce_Javascript.cpp"
|
||||||
|
#include "containers/juce_DynamicObject.cpp"
|
||||||
|
#include "logging/juce_FileLogger.cpp"
|
||||||
|
#include "logging/juce_Logger.cpp"
|
||||||
|
#include "maths/juce_BigInteger.cpp"
|
||||||
|
#include "maths/juce_Expression.cpp"
|
||||||
|
#include "maths/juce_Random.cpp"
|
||||||
|
#include "memory/juce_MemoryBlock.cpp"
|
||||||
|
#include "misc/juce_Result.cpp"
|
||||||
|
#include "misc/juce_Uuid.cpp"
|
||||||
|
#include "network/juce_MACAddress.cpp"
|
||||||
|
#include "network/juce_NamedPipe.cpp"
|
||||||
|
#include "network/juce_Socket.cpp"
|
||||||
|
#include "network/juce_IPAddress.cpp"
|
||||||
|
#include "streams/juce_BufferedInputStream.cpp"
|
||||||
|
#include "streams/juce_FileInputSource.cpp"
|
||||||
|
#include "streams/juce_InputStream.cpp"
|
||||||
|
#include "streams/juce_MemoryInputStream.cpp"
|
||||||
|
#include "streams/juce_MemoryOutputStream.cpp"
|
||||||
|
#include "streams/juce_SubregionStream.cpp"
|
||||||
|
#include "system/juce_SystemStats.cpp"
|
||||||
|
#include "text/juce_CharacterFunctions.cpp"
|
||||||
|
#include "text/juce_Identifier.cpp"
|
||||||
|
#include "text/juce_LocalisedStrings.cpp"
|
||||||
|
#include "text/juce_String.cpp"
|
||||||
|
#include "streams/juce_OutputStream.cpp"
|
||||||
|
#include "text/juce_StringArray.cpp"
|
||||||
|
#include "text/juce_StringPairArray.cpp"
|
||||||
|
#include "text/juce_StringPool.cpp"
|
||||||
|
#include "text/juce_TextDiff.cpp"
|
||||||
|
#include "threads/juce_ReadWriteLock.cpp"
|
||||||
|
#include "threads/juce_Thread.cpp"
|
||||||
|
#include "threads/juce_ThreadPool.cpp"
|
||||||
|
#include "threads/juce_TimeSliceThread.cpp"
|
||||||
|
#include "time/juce_PerformanceCounter.cpp"
|
||||||
|
#include "time/juce_RelativeTime.cpp"
|
||||||
|
#include "time/juce_Time.cpp"
|
||||||
|
#include "unit_tests/juce_UnitTest.cpp"
|
||||||
|
#include "xml/juce_XmlDocument.cpp"
|
||||||
|
#include "xml/juce_XmlElement.cpp"
|
||||||
|
#include "zip/juce_GZIPDecompressorInputStream.cpp"
|
||||||
|
#include "zip/juce_GZIPCompressorOutputStream.cpp"
|
||||||
|
#include "zip/juce_ZipFile.cpp"
|
||||||
|
#include "files/juce_FileFilter.cpp"
|
||||||
|
#include "files/juce_WildcardFileFilter.cpp"
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if JUCE_MAC || JUCE_IOS
|
||||||
|
#include "native/juce_osx_ObjCHelpers.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JUCE_ANDROID
|
||||||
|
#include "native/juce_android_JNIHelpers.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ! JUCE_WINDOWS
|
||||||
|
#include "native/juce_posix_SharedCode.h"
|
||||||
|
#include "native/juce_posix_NamedPipe.cpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if JUCE_MAC || JUCE_IOS
|
||||||
|
#include "native/juce_mac_Files.mm"
|
||||||
|
#include "native/juce_mac_Network.mm"
|
||||||
|
#include "native/juce_mac_Strings.mm"
|
||||||
|
#include "native/juce_mac_SystemStats.mm"
|
||||||
|
#include "native/juce_mac_Threads.mm"
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#elif JUCE_WINDOWS
|
||||||
|
#include "native/juce_win32_ComSmartPtr.h"
|
||||||
|
#include "native/juce_win32_Files.cpp"
|
||||||
|
#include "native/juce_win32_Network.cpp"
|
||||||
|
#include "native/juce_win32_Registry.cpp"
|
||||||
|
#include "native/juce_win32_SystemStats.cpp"
|
||||||
|
#include "native/juce_win32_Threads.cpp"
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#elif JUCE_LINUX
|
||||||
|
#include "native/juce_linux_CommonFile.cpp"
|
||||||
|
#include "native/juce_linux_Files.cpp"
|
||||||
|
#include "native/juce_linux_Network.cpp"
|
||||||
|
#include "native/juce_linux_SystemStats.cpp"
|
||||||
|
#include "native/juce_linux_Threads.cpp"
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#elif JUCE_ANDROID
|
||||||
|
#include "native/juce_linux_CommonFile.cpp"
|
||||||
|
#include "native/juce_android_Files.cpp"
|
||||||
|
#include "native/juce_android_Misc.cpp"
|
||||||
|
#include "native/juce_android_Network.cpp"
|
||||||
|
#include "native/juce_android_SystemStats.cpp"
|
||||||
|
#include "native/juce_android_Threads.cpp"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "threads/juce_ChildProcess.cpp"
|
||||||
|
#include "threads/juce_HighResolutionTimer.cpp"
|
||||||
|
#include "network/juce_URL.cpp"
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,285 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_CORE_H_INCLUDED
|
||||||
|
#define JUCE_CORE_H_INCLUDED
|
||||||
|
|
||||||
|
#ifndef JUCE_MODULE_AVAILABLE_juce_core
|
||||||
|
/* If you fail to make sure that all your compile units are building JUCE with the same set of
|
||||||
|
option flags, then there's a risk that different compile units will treat the classes as having
|
||||||
|
different memory layouts, leading to very nasty memory corruption errors when they all get
|
||||||
|
linked together. That's why it's best to always include the Introjucer-generated AppConfig.h
|
||||||
|
file before any juce headers.
|
||||||
|
|
||||||
|
Note that if you do have an AppConfig.h file and hit this warning, it means that it doesn't
|
||||||
|
contain the JUCE_MODULE_AVAILABLE_xxx flags, which are necessary for some inter-module
|
||||||
|
functionality to work correctly. In that case, you should either rebuild your AppConfig.h with
|
||||||
|
the latest introjucer, or fix it manually to contain these flags.
|
||||||
|
*/
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma message ("Have you included your AppConfig.h file before including the JUCE headers?")
|
||||||
|
#else
|
||||||
|
#warning "Have you included your AppConfig.h file before including the JUCE headers?"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#include "system/juce_TargetPlatform.h"
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
/** Config: JUCE_FORCE_DEBUG
|
||||||
|
|
||||||
|
Normally, JUCE_DEBUG is set to 1 or 0 based on compiler and project settings,
|
||||||
|
but if you define this value, you can override this to force it to be true or false.
|
||||||
|
*/
|
||||||
|
#ifndef JUCE_FORCE_DEBUG
|
||||||
|
//#define JUCE_FORCE_DEBUG 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
/** Config: JUCE_LOG_ASSERTIONS
|
||||||
|
|
||||||
|
If this flag is enabled, the jassert and jassertfalse macros will always use Logger::writeToLog()
|
||||||
|
to write a message when an assertion happens.
|
||||||
|
|
||||||
|
Enabling it will also leave this turned on in release builds. When it's disabled,
|
||||||
|
however, the jassert and jassertfalse macros will not be compiled in a
|
||||||
|
release build.
|
||||||
|
|
||||||
|
@see jassert, jassertfalse, Logger
|
||||||
|
*/
|
||||||
|
#ifndef JUCE_LOG_ASSERTIONS
|
||||||
|
#if JUCE_ANDROID
|
||||||
|
#define JUCE_LOG_ASSERTIONS 1
|
||||||
|
#else
|
||||||
|
#define JUCE_LOG_ASSERTIONS 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
/** Config: JUCE_CHECK_MEMORY_LEAKS
|
||||||
|
|
||||||
|
Enables a memory-leak check for certain objects when the app terminates. See the LeakedObjectDetector
|
||||||
|
class and the JUCE_LEAK_DETECTOR macro for more details about enabling leak checking for specific classes.
|
||||||
|
*/
|
||||||
|
#if JUCE_DEBUG && ! defined (JUCE_CHECK_MEMORY_LEAKS)
|
||||||
|
#define JUCE_CHECK_MEMORY_LEAKS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
/** Config: JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||||
|
|
||||||
|
In a Visual C++ build, this can be used to stop the required system libs being
|
||||||
|
automatically added to the link stage.
|
||||||
|
*/
|
||||||
|
#ifndef JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||||
|
#define JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Config: JUCE_INCLUDE_ZLIB_CODE
|
||||||
|
This can be used to disable Juce's embedded 3rd-party zlib code.
|
||||||
|
You might need to tweak this if you're linking to an external zlib library in your app,
|
||||||
|
but for normal apps, this option should be left alone.
|
||||||
|
|
||||||
|
If you disable this, you might also want to set a value for JUCE_ZLIB_INCLUDE_PATH, to
|
||||||
|
specify the path where your zlib headers live.
|
||||||
|
*/
|
||||||
|
#ifndef JUCE_INCLUDE_ZLIB_CODE
|
||||||
|
#define JUCE_INCLUDE_ZLIB_CODE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JUCE_ZLIB_INCLUDE_PATH
|
||||||
|
#define JUCE_ZLIB_INCLUDE_PATH <zlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Config: JUCE_CATCH_UNHANDLED_EXCEPTIONS
|
||||||
|
If enabled, this will add some exception-catching code to forward unhandled exceptions
|
||||||
|
to your JUCEApplicationBase::unhandledException() callback.
|
||||||
|
*/
|
||||||
|
#ifndef JUCE_CATCH_UNHANDLED_EXCEPTIONS
|
||||||
|
//#define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef JUCE_STRING_UTF_TYPE
|
||||||
|
#define JUCE_STRING_UTF_TYPE 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//=============================================================================
|
||||||
|
#if JUCE_MSVC
|
||||||
|
#pragma warning (disable: 4251) // (DLL build warning, must be disabled before pushing the warning state)
|
||||||
|
#pragma warning (push)
|
||||||
|
#pragma warning (disable: 4786) // (long class name warning)
|
||||||
|
#ifdef __INTEL_COMPILER
|
||||||
|
#pragma warning (disable: 1125)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "system/juce_StandardHeader.h"
|
||||||
|
|
||||||
|
namespace juce
|
||||||
|
{
|
||||||
|
|
||||||
|
class StringRef;
|
||||||
|
class MemoryBlock;
|
||||||
|
class File;
|
||||||
|
class InputStream;
|
||||||
|
class OutputStream;
|
||||||
|
class DynamicObject;
|
||||||
|
class FileInputStream;
|
||||||
|
class FileOutputStream;
|
||||||
|
class XmlElement;
|
||||||
|
class JSONFormatter;
|
||||||
|
|
||||||
|
extern JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger();
|
||||||
|
extern JUCE_API void JUCE_CALLTYPE logAssertion (const char* file, int line) noexcept;
|
||||||
|
|
||||||
|
#include "memory/juce_Memory.h"
|
||||||
|
#include "maths/juce_MathsFunctions.h"
|
||||||
|
#include "memory/juce_ByteOrder.h"
|
||||||
|
#include "memory/juce_Atomic.h"
|
||||||
|
#include "text/juce_CharacterFunctions.h"
|
||||||
|
|
||||||
|
#if JUCE_MSVC
|
||||||
|
#pragma warning (push)
|
||||||
|
#pragma warning (disable: 4514 4996)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "text/juce_CharPointer_UTF8.h"
|
||||||
|
#include "text/juce_CharPointer_UTF16.h"
|
||||||
|
#include "text/juce_CharPointer_UTF32.h"
|
||||||
|
#include "text/juce_CharPointer_ASCII.h"
|
||||||
|
|
||||||
|
#if JUCE_MSVC
|
||||||
|
#pragma warning (pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "text/juce_String.h"
|
||||||
|
#include "text/juce_StringRef.h"
|
||||||
|
#include "logging/juce_Logger.h"
|
||||||
|
#include "memory/juce_LeakedObjectDetector.h"
|
||||||
|
#include "memory/juce_ContainerDeletePolicy.h"
|
||||||
|
#include "memory/juce_HeapBlock.h"
|
||||||
|
#include "memory/juce_MemoryBlock.h"
|
||||||
|
#include "memory/juce_ReferenceCountedObject.h"
|
||||||
|
#include "memory/juce_ScopedPointer.h"
|
||||||
|
#include "memory/juce_OptionalScopedPointer.h"
|
||||||
|
#include "memory/juce_Singleton.h"
|
||||||
|
#include "memory/juce_WeakReference.h"
|
||||||
|
#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"
|
||||||
|
#include "containers/juce_LinkedListPointer.h"
|
||||||
|
#include "containers/juce_OwnedArray.h"
|
||||||
|
#include "containers/juce_ReferenceCountedArray.h"
|
||||||
|
#include "containers/juce_ScopedValueSetter.h"
|
||||||
|
#include "containers/juce_SortedSet.h"
|
||||||
|
#include "containers/juce_SparseSet.h"
|
||||||
|
#include "containers/juce_AbstractFifo.h"
|
||||||
|
#include "text/juce_NewLine.h"
|
||||||
|
#include "text/juce_StringPool.h"
|
||||||
|
#include "text/juce_Identifier.h"
|
||||||
|
#include "text/juce_StringArray.h"
|
||||||
|
#include "text/juce_StringPairArray.h"
|
||||||
|
#include "text/juce_TextDiff.h"
|
||||||
|
#include "text/juce_LocalisedStrings.h"
|
||||||
|
#include "misc/juce_Result.h"
|
||||||
|
#include "containers/juce_Variant.h"
|
||||||
|
#include "containers/juce_NamedValueSet.h"
|
||||||
|
#include "containers/juce_DynamicObject.h"
|
||||||
|
#include "containers/juce_HashMap.h"
|
||||||
|
#include "time/juce_RelativeTime.h"
|
||||||
|
#include "time/juce_Time.h"
|
||||||
|
#include "streams/juce_InputStream.h"
|
||||||
|
#include "streams/juce_OutputStream.h"
|
||||||
|
#include "streams/juce_BufferedInputStream.h"
|
||||||
|
#include "streams/juce_MemoryInputStream.h"
|
||||||
|
#include "streams/juce_MemoryOutputStream.h"
|
||||||
|
#include "streams/juce_SubregionStream.h"
|
||||||
|
#include "streams/juce_InputSource.h"
|
||||||
|
#include "files/juce_File.h"
|
||||||
|
#include "files/juce_DirectoryIterator.h"
|
||||||
|
#include "files/juce_FileInputStream.h"
|
||||||
|
#include "files/juce_FileOutputStream.h"
|
||||||
|
#include "files/juce_FileSearchPath.h"
|
||||||
|
#include "files/juce_MemoryMappedFile.h"
|
||||||
|
#include "files/juce_TemporaryFile.h"
|
||||||
|
#include "files/juce_FileFilter.h"
|
||||||
|
#include "files/juce_WildcardFileFilter.h"
|
||||||
|
#include "streams/juce_FileInputSource.h"
|
||||||
|
#include "logging/juce_FileLogger.h"
|
||||||
|
#include "javascript/juce_JSON.h"
|
||||||
|
#include "javascript/juce_Javascript.h"
|
||||||
|
#include "maths/juce_BigInteger.h"
|
||||||
|
#include "maths/juce_Expression.h"
|
||||||
|
#include "maths/juce_Random.h"
|
||||||
|
#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"
|
||||||
|
#include "threads/juce_HighResolutionTimer.h"
|
||||||
|
#include "threads/juce_InterProcessLock.h"
|
||||||
|
#include "threads/juce_Process.h"
|
||||||
|
#include "threads/juce_SpinLock.h"
|
||||||
|
#include "threads/juce_WaitableEvent.h"
|
||||||
|
#include "threads/juce_Thread.h"
|
||||||
|
#include "threads/juce_ThreadLocalValue.h"
|
||||||
|
#include "threads/juce_ThreadPool.h"
|
||||||
|
#include "threads/juce_TimeSliceThread.h"
|
||||||
|
#include "threads/juce_ReadWriteLock.h"
|
||||||
|
#include "threads/juce_ScopedReadLock.h"
|
||||||
|
#include "threads/juce_ScopedWriteLock.h"
|
||||||
|
#include "network/juce_IPAddress.h"
|
||||||
|
#include "network/juce_MACAddress.h"
|
||||||
|
#include "network/juce_NamedPipe.h"
|
||||||
|
#include "network/juce_Socket.h"
|
||||||
|
#include "network/juce_URL.h"
|
||||||
|
#include "time/juce_PerformanceCounter.h"
|
||||||
|
#include "unit_tests/juce_UnitTest.h"
|
||||||
|
#include "xml/juce_XmlDocument.h"
|
||||||
|
#include "xml/juce_XmlElement.h"
|
||||||
|
#include "zip/juce_GZIPCompressorOutputStream.h"
|
||||||
|
#include "zip/juce_GZIPDecompressorInputStream.h"
|
||||||
|
#include "zip/juce_ZipFile.h"
|
||||||
|
#include "containers/juce_PropertySet.h"
|
||||||
|
#include "memory/juce_SharedResourcePointer.h"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JUCE_MSVC
|
||||||
|
#pragma warning (pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // JUCE_CORE_H_INCLUDED
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "juce_core.cpp"
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"id": "juce_core",
|
||||||
|
"name": "JUCE core classes",
|
||||||
|
"version": "3.1.1",
|
||||||
|
"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",
|
||||||
|
|
||||||
|
"dependencies": [],
|
||||||
|
|
||||||
|
"include": "juce_core.h",
|
||||||
|
|
||||||
|
"compile": [ { "file": "juce_core.cpp", "target": "! xcode" },
|
||||||
|
{ "file": "juce_core.mm", "target": "xcode" } ],
|
||||||
|
|
||||||
|
"browse": [ "text/*",
|
||||||
|
"maths/*",
|
||||||
|
"memory/*",
|
||||||
|
"containers/*",
|
||||||
|
"threads/*",
|
||||||
|
"time/*",
|
||||||
|
"files/*",
|
||||||
|
"network/*",
|
||||||
|
"streams/*",
|
||||||
|
"logging/*",
|
||||||
|
"system/*",
|
||||||
|
"xml/*",
|
||||||
|
"javascript/*",
|
||||||
|
"zip/*",
|
||||||
|
"unit_tests/*",
|
||||||
|
"misc/*",
|
||||||
|
"native/*" ],
|
||||||
|
|
||||||
|
"OSXFrameworks": "Cocoa IOKit",
|
||||||
|
"iOSFrameworks": "Foundation",
|
||||||
|
"LinuxLibs": "rt dl pthread",
|
||||||
|
"mingwLibs": "uuid wsock32 wininet version ole32 ws2_32 oleaut32 imm32 comdlg32 shlwapi rpcrt4 winmm"
|
||||||
|
}
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
FileLogger::FileLogger (const File& file,
|
||||||
|
const String& welcomeMessage,
|
||||||
|
const int64 maxInitialFileSizeBytes)
|
||||||
|
: logFile (file)
|
||||||
|
{
|
||||||
|
if (maxInitialFileSizeBytes >= 0)
|
||||||
|
trimFileSize (logFile, maxInitialFileSizeBytes);
|
||||||
|
|
||||||
|
if (! file.exists())
|
||||||
|
file.create(); // (to create the parent directories)
|
||||||
|
|
||||||
|
String welcome;
|
||||||
|
welcome << newLine
|
||||||
|
<< "**********************************************************" << newLine
|
||||||
|
<< welcomeMessage << newLine
|
||||||
|
<< "Log started: " << Time::getCurrentTime().toString (true, true) << newLine;
|
||||||
|
|
||||||
|
FileLogger::logMessage (welcome);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileLogger::~FileLogger() {}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void FileLogger::logMessage (const String& message)
|
||||||
|
{
|
||||||
|
const ScopedLock sl (logLock);
|
||||||
|
DBG (message);
|
||||||
|
FileOutputStream out (logFile, 256);
|
||||||
|
out << message << newLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileLogger::trimFileSize (const File& file, int64 maxFileSizeBytes)
|
||||||
|
{
|
||||||
|
if (maxFileSizeBytes <= 0)
|
||||||
|
{
|
||||||
|
file.deleteFile();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const int64 fileSize = file.getSize();
|
||||||
|
|
||||||
|
if (fileSize > maxFileSizeBytes)
|
||||||
|
{
|
||||||
|
TemporaryFile tempFile (file);
|
||||||
|
|
||||||
|
{
|
||||||
|
FileOutputStream out (tempFile.getFile());
|
||||||
|
FileInputStream in (file);
|
||||||
|
|
||||||
|
if (! (out.openedOk() && in.openedOk()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
in.setPosition (fileSize - maxFileSizeBytes);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const char c = in.readByte();
|
||||||
|
if (c == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (c == '\n' || c == '\r')
|
||||||
|
{
|
||||||
|
out << c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out.writeFromInputStream (in, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
tempFile.overwriteTargetFileWithTemporary();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
File FileLogger::getSystemLogFileFolder()
|
||||||
|
{
|
||||||
|
#if JUCE_MAC
|
||||||
|
return File ("~/Library/Logs");
|
||||||
|
#else
|
||||||
|
return File::getSpecialLocation (File::userApplicationDataDirectory);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
FileLogger* FileLogger::createDefaultAppLogger (const String& logFileSubDirectoryName,
|
||||||
|
const String& logFileName,
|
||||||
|
const String& welcomeMessage,
|
||||||
|
const int64 maxInitialFileSizeBytes)
|
||||||
|
{
|
||||||
|
return new FileLogger (getSystemLogFileFolder().getChildFile (logFileSubDirectoryName)
|
||||||
|
.getChildFile (logFileName),
|
||||||
|
welcomeMessage, maxInitialFileSizeBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileLogger* FileLogger::createDateStampedLogger (const String& logFileSubDirectoryName,
|
||||||
|
const String& logFileNameRoot,
|
||||||
|
const String& logFileNameSuffix,
|
||||||
|
const String& welcomeMessage)
|
||||||
|
{
|
||||||
|
return new FileLogger (getSystemLogFileFolder().getChildFile (logFileSubDirectoryName)
|
||||||
|
.getChildFile (logFileNameRoot + Time::getCurrentTime().formatted ("%Y-%m-%d_%H-%M-%S"))
|
||||||
|
.withFileExtension (logFileNameSuffix)
|
||||||
|
.getNonexistentSibling(),
|
||||||
|
welcomeMessage, 0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_FILELOGGER_H_INCLUDED
|
||||||
|
#define JUCE_FILELOGGER_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A simple implementation of a Logger that writes to a file.
|
||||||
|
|
||||||
|
@see Logger
|
||||||
|
*/
|
||||||
|
class JUCE_API FileLogger : public Logger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a FileLogger for a given file.
|
||||||
|
|
||||||
|
@param fileToWriteTo the file that to use - new messages will be appended
|
||||||
|
to the file. If the file doesn't exist, it will be created,
|
||||||
|
along with any parent directories that are needed.
|
||||||
|
@param welcomeMessage when opened, the logger will write a header to the log, along
|
||||||
|
with the current date and time, and this welcome message
|
||||||
|
@param maxInitialFileSizeBytes if this is zero or greater, then if the file already exists
|
||||||
|
but is larger than this number of bytes, then the start of the
|
||||||
|
file will be truncated to keep the size down. This prevents a log
|
||||||
|
file getting ridiculously large over time. The file will be truncated
|
||||||
|
at a new-line boundary. If this value is less than zero, no size limit
|
||||||
|
will be imposed; if it's zero, the file will always be deleted. Note that
|
||||||
|
the size is only checked once when this object is created - any logging
|
||||||
|
that is done later will be appended without any checking
|
||||||
|
*/
|
||||||
|
FileLogger (const File& fileToWriteTo,
|
||||||
|
const String& welcomeMessage,
|
||||||
|
const int64 maxInitialFileSizeBytes = 128 * 1024);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~FileLogger();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the file that this logger is writing to. */
|
||||||
|
const File& getLogFile() const noexcept { return logFile; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Helper function to create a log file in the correct place for this platform.
|
||||||
|
|
||||||
|
The method might return nullptr if the file can't be created for some reason.
|
||||||
|
|
||||||
|
@param logFileSubDirectoryName the name of the subdirectory to create inside the logs folder (as
|
||||||
|
returned by getSystemLogFileFolder). It's best to use something
|
||||||
|
like the name of your application here.
|
||||||
|
@param logFileName the name of the file to create, e.g. "MyAppLog.txt".
|
||||||
|
@param welcomeMessage a message that will be written to the log when it's opened.
|
||||||
|
@param maxInitialFileSizeBytes (see the FileLogger constructor for more info on this)
|
||||||
|
*/
|
||||||
|
static FileLogger* createDefaultAppLogger (const String& logFileSubDirectoryName,
|
||||||
|
const String& logFileName,
|
||||||
|
const String& welcomeMessage,
|
||||||
|
const int64 maxInitialFileSizeBytes = 128 * 1024);
|
||||||
|
|
||||||
|
/** Helper function to create a log file in the correct place for this platform.
|
||||||
|
|
||||||
|
The filename used is based on the root and suffix strings provided, along with a
|
||||||
|
time and date string, meaning that a new, empty log file will be always be created
|
||||||
|
rather than appending to an exising one.
|
||||||
|
|
||||||
|
The method might return nullptr if the file can't be created for some reason.
|
||||||
|
|
||||||
|
@param logFileSubDirectoryName the name of the subdirectory to create inside the logs folder (as
|
||||||
|
returned by getSystemLogFileFolder). It's best to use something
|
||||||
|
like the name of your application here.
|
||||||
|
@param logFileNameRoot the start of the filename to use, e.g. "MyAppLog_". This will have
|
||||||
|
a timestamp and the logFileNameSuffix appended to it
|
||||||
|
@param logFileNameSuffix the file suffix to use, e.g. ".txt"
|
||||||
|
@param welcomeMessage a message that will be written to the log when it's opened.
|
||||||
|
*/
|
||||||
|
static FileLogger* createDateStampedLogger (const String& logFileSubDirectoryName,
|
||||||
|
const String& logFileNameRoot,
|
||||||
|
const String& logFileNameSuffix,
|
||||||
|
const String& welcomeMessage);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns an OS-specific folder where log-files should be stored.
|
||||||
|
|
||||||
|
On Windows this will return a logger with a path such as:
|
||||||
|
c:\\Documents and Settings\\username\\Application Data\\[logFileSubDirectoryName]\\[logFileName]
|
||||||
|
|
||||||
|
On the Mac it'll create something like:
|
||||||
|
~/Library/Logs/[logFileSubDirectoryName]/[logFileName]
|
||||||
|
|
||||||
|
@see createDefaultAppLogger
|
||||||
|
*/
|
||||||
|
static File getSystemLogFileFolder();
|
||||||
|
|
||||||
|
// (implementation of the Logger virtual method)
|
||||||
|
void logMessage (const String&);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** This is a utility function which removes lines from the start of a text
|
||||||
|
file to make sure that its total size is below the given size.
|
||||||
|
*/
|
||||||
|
static void trimFileSize (const File& file, int64 maxFileSize);
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
File logFile;
|
||||||
|
CriticalSection logLock;
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileLogger)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_FILELOGGER_H_INCLUDED
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
Logger::Logger() {}
|
||||||
|
|
||||||
|
Logger::~Logger()
|
||||||
|
{
|
||||||
|
// You're deleting this logger while it's still being used!
|
||||||
|
// Always call Logger::setCurrentLogger (nullptr) before deleting the active logger.
|
||||||
|
jassert (currentLogger != this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger* Logger::currentLogger = nullptr;
|
||||||
|
|
||||||
|
void Logger::setCurrentLogger (Logger* const newLogger) noexcept { currentLogger = newLogger; }
|
||||||
|
Logger* Logger::getCurrentLogger() noexcept { return currentLogger; }
|
||||||
|
|
||||||
|
void Logger::writeToLog (const String& message)
|
||||||
|
{
|
||||||
|
if (currentLogger != nullptr)
|
||||||
|
currentLogger->logMessage (message);
|
||||||
|
else
|
||||||
|
outputDebugString (message);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JUCE_LOG_ASSERTIONS || JUCE_DEBUG
|
||||||
|
void JUCE_API JUCE_CALLTYPE logAssertion (const char* const filename, const int lineNum) noexcept
|
||||||
|
{
|
||||||
|
String m ("JUCE Assertion failure in ");
|
||||||
|
m << File::createFileWithoutCheckingPath (filename).getFileName() << ':' << lineNum;
|
||||||
|
|
||||||
|
#if JUCE_LOG_ASSERTIONS
|
||||||
|
Logger::writeToLog (m);
|
||||||
|
#else
|
||||||
|
DBG (m);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_LOGGER_H_INCLUDED
|
||||||
|
#define JUCE_LOGGER_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Acts as an application-wide logging class.
|
||||||
|
|
||||||
|
A subclass of Logger can be created and passed into the Logger::setCurrentLogger
|
||||||
|
method and this will then be used by all calls to writeToLog.
|
||||||
|
|
||||||
|
The logger class also contains methods for writing messages to the debugger's
|
||||||
|
output stream.
|
||||||
|
|
||||||
|
@see FileLogger
|
||||||
|
*/
|
||||||
|
class JUCE_API Logger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Destructor. */
|
||||||
|
virtual ~Logger();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Sets the current logging class to use.
|
||||||
|
|
||||||
|
Note that the object passed in will not be owned or deleted by the logger, so
|
||||||
|
the caller must make sure that it is not deleted while still being used.
|
||||||
|
A null pointer can be passed-in to disable any logging.
|
||||||
|
*/
|
||||||
|
static void JUCE_CALLTYPE setCurrentLogger (Logger* newLogger) noexcept;
|
||||||
|
|
||||||
|
/** Returns the current logger, or nullptr if none has been set. */
|
||||||
|
static Logger* getCurrentLogger() noexcept;
|
||||||
|
|
||||||
|
/** Writes a string to the current logger.
|
||||||
|
|
||||||
|
This will pass the string to the logger's logMessage() method if a logger
|
||||||
|
has been set.
|
||||||
|
|
||||||
|
@see logMessage
|
||||||
|
*/
|
||||||
|
static void JUCE_CALLTYPE writeToLog (const String& message);
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Writes a message to the standard error stream.
|
||||||
|
|
||||||
|
This can be called directly, or by using the DBG() macro in
|
||||||
|
juce_PlatformDefs.h (which will avoid calling the method in non-debug builds).
|
||||||
|
*/
|
||||||
|
static void JUCE_CALLTYPE outputDebugString (const String& text);
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//==============================================================================
|
||||||
|
Logger();
|
||||||
|
|
||||||
|
/** This is overloaded by subclasses to implement custom logging behaviour.
|
||||||
|
@see setCurrentLogger
|
||||||
|
*/
|
||||||
|
virtual void logMessage (const String& message) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Logger* currentLogger;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_LOGGER_H_INCLUDED
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,334 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_BIGINTEGER_H_INCLUDED
|
||||||
|
#define JUCE_BIGINTEGER_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
An arbitrarily large integer class.
|
||||||
|
|
||||||
|
A BigInteger can be used in a similar way to a normal integer, but has no size
|
||||||
|
limit (except for memory and performance constraints).
|
||||||
|
|
||||||
|
Negative values are possible, but the value isn't stored as 2s-complement, so
|
||||||
|
be careful if you use negative values and look at the values of individual bits.
|
||||||
|
*/
|
||||||
|
class JUCE_API BigInteger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an empty BigInteger */
|
||||||
|
BigInteger();
|
||||||
|
|
||||||
|
/** Creates a BigInteger containing an integer value in its low bits.
|
||||||
|
The low 32 bits of the number are initialised with this value.
|
||||||
|
*/
|
||||||
|
BigInteger (uint32 value);
|
||||||
|
|
||||||
|
/** Creates a BigInteger containing an integer value in its low bits.
|
||||||
|
The low 32 bits of the number are initialised with the absolute value
|
||||||
|
passed in, and its sign is set to reflect the sign of the number.
|
||||||
|
*/
|
||||||
|
BigInteger (int32 value);
|
||||||
|
|
||||||
|
/** Creates a BigInteger containing an integer value in its low bits.
|
||||||
|
The low 64 bits of the number are initialised with the absolute value
|
||||||
|
passed in, and its sign is set to reflect the sign of the number.
|
||||||
|
*/
|
||||||
|
BigInteger (int64 value);
|
||||||
|
|
||||||
|
/** Creates a copy of another BigInteger. */
|
||||||
|
BigInteger (const BigInteger&);
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
BigInteger (BigInteger&&) noexcept;
|
||||||
|
BigInteger& operator= (BigInteger&&) noexcept;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~BigInteger();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Copies another BigInteger onto this one. */
|
||||||
|
BigInteger& operator= (const BigInteger&);
|
||||||
|
|
||||||
|
/** Swaps the internal contents of this with another object. */
|
||||||
|
void swapWith (BigInteger&) noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the value of a specified bit in the number.
|
||||||
|
If the index is out-of-range, the result will be false.
|
||||||
|
*/
|
||||||
|
bool operator[] (int bit) const noexcept;
|
||||||
|
|
||||||
|
/** Returns true if no bits are set. */
|
||||||
|
bool isZero() const noexcept;
|
||||||
|
|
||||||
|
/** Returns true if the value is 1. */
|
||||||
|
bool isOne() const noexcept;
|
||||||
|
|
||||||
|
/** Attempts to get the lowest 32 bits of the value as an integer.
|
||||||
|
If the value is bigger than the integer limits, this will return only the lower bits.
|
||||||
|
*/
|
||||||
|
int toInteger() const noexcept;
|
||||||
|
|
||||||
|
/** Attempts to get the lowest 64 bits of the value as an integer.
|
||||||
|
If the value is bigger than the integer limits, this will return only the lower bits.
|
||||||
|
*/
|
||||||
|
int64 toInt64() const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Resets the value to 0. */
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
/** Clears a particular bit in the number. */
|
||||||
|
void clearBit (int bitNumber) noexcept;
|
||||||
|
|
||||||
|
/** Sets a specified bit to 1. */
|
||||||
|
void setBit (int bitNumber);
|
||||||
|
|
||||||
|
/** Sets or clears a specified bit. */
|
||||||
|
void setBit (int bitNumber, bool shouldBeSet);
|
||||||
|
|
||||||
|
/** Sets a range of bits to be either on or off.
|
||||||
|
|
||||||
|
@param startBit the first bit to change
|
||||||
|
@param numBits the number of bits to change
|
||||||
|
@param shouldBeSet whether to turn these bits on or off
|
||||||
|
*/
|
||||||
|
void setRange (int startBit, int numBits, bool shouldBeSet);
|
||||||
|
|
||||||
|
/** Inserts a bit an a given position, shifting up any bits above it. */
|
||||||
|
void insertBit (int bitNumber, bool shouldBeSet);
|
||||||
|
|
||||||
|
/** Returns a range of bits as a new BigInteger.
|
||||||
|
|
||||||
|
e.g. getBitRangeAsInt (0, 64) would return the lowest 64 bits.
|
||||||
|
@see getBitRangeAsInt
|
||||||
|
*/
|
||||||
|
BigInteger getBitRange (int startBit, int numBits) const;
|
||||||
|
|
||||||
|
/** Returns a range of bits as an integer value.
|
||||||
|
|
||||||
|
e.g. getBitRangeAsInt (0, 32) would return the lowest 32 bits.
|
||||||
|
|
||||||
|
Asking for more than 32 bits isn't allowed (obviously) - for that, use
|
||||||
|
getBitRange().
|
||||||
|
*/
|
||||||
|
uint32 getBitRangeAsInt (int startBit, int numBits) const noexcept;
|
||||||
|
|
||||||
|
/** Sets a range of bits to an integer value.
|
||||||
|
|
||||||
|
Copies the given integer onto a range of bits, starting at startBit,
|
||||||
|
and using up to numBits of the available bits.
|
||||||
|
*/
|
||||||
|
void setBitRangeAsInt (int startBit, int numBits, uint32 valueToSet);
|
||||||
|
|
||||||
|
/** Shifts a section of bits left or right.
|
||||||
|
|
||||||
|
@param howManyBitsLeft how far to move the bits (+ve numbers shift it left, -ve numbers shift it right).
|
||||||
|
@param startBit the first bit to affect - if this is > 0, only bits above that index will be affected.
|
||||||
|
*/
|
||||||
|
void shiftBits (int howManyBitsLeft, int startBit);
|
||||||
|
|
||||||
|
/** Returns the total number of set bits in the value. */
|
||||||
|
int countNumberOfSetBits() const noexcept;
|
||||||
|
|
||||||
|
/** Looks for the index of the next set bit after a given starting point.
|
||||||
|
|
||||||
|
This searches from startIndex (inclusive) upwards for the first set bit,
|
||||||
|
and returns its index. If no set bits are found, it returns -1.
|
||||||
|
*/
|
||||||
|
int findNextSetBit (int startIndex) const noexcept;
|
||||||
|
|
||||||
|
/** Looks for the index of the next clear bit after a given starting point.
|
||||||
|
|
||||||
|
This searches from startIndex (inclusive) upwards for the first clear bit,
|
||||||
|
and returns its index.
|
||||||
|
*/
|
||||||
|
int findNextClearBit (int startIndex) const noexcept;
|
||||||
|
|
||||||
|
/** Returns the index of the highest set bit in the number.
|
||||||
|
If the value is zero, this will return -1.
|
||||||
|
*/
|
||||||
|
int getHighestBit() const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// All the standard arithmetic ops...
|
||||||
|
|
||||||
|
BigInteger& operator+= (const BigInteger&);
|
||||||
|
BigInteger& operator-= (const BigInteger&);
|
||||||
|
BigInteger& operator*= (const BigInteger&);
|
||||||
|
BigInteger& operator/= (const BigInteger&);
|
||||||
|
BigInteger& operator|= (const BigInteger&);
|
||||||
|
BigInteger& operator&= (const BigInteger&);
|
||||||
|
BigInteger& operator^= (const BigInteger&);
|
||||||
|
BigInteger& operator%= (const BigInteger&);
|
||||||
|
BigInteger& operator<<= (int numBitsToShift);
|
||||||
|
BigInteger& operator>>= (int numBitsToShift);
|
||||||
|
BigInteger& operator++();
|
||||||
|
BigInteger& operator--();
|
||||||
|
BigInteger operator++ (int);
|
||||||
|
BigInteger operator-- (int);
|
||||||
|
|
||||||
|
BigInteger operator-() const;
|
||||||
|
BigInteger operator+ (const BigInteger&) const;
|
||||||
|
BigInteger operator- (const BigInteger&) const;
|
||||||
|
BigInteger operator* (const BigInteger&) const;
|
||||||
|
BigInteger operator/ (const BigInteger&) const;
|
||||||
|
BigInteger operator| (const BigInteger&) const;
|
||||||
|
BigInteger operator& (const BigInteger&) const;
|
||||||
|
BigInteger operator^ (const BigInteger&) const;
|
||||||
|
BigInteger operator% (const BigInteger&) const;
|
||||||
|
BigInteger operator<< (int numBitsToShift) const;
|
||||||
|
BigInteger operator>> (int numBitsToShift) const;
|
||||||
|
|
||||||
|
bool operator== (const BigInteger&) const noexcept;
|
||||||
|
bool operator!= (const BigInteger&) const noexcept;
|
||||||
|
bool operator< (const BigInteger&) const noexcept;
|
||||||
|
bool operator<= (const BigInteger&) const noexcept;
|
||||||
|
bool operator> (const BigInteger&) const noexcept;
|
||||||
|
bool operator>= (const BigInteger&) const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Does a signed comparison of two BigIntegers.
|
||||||
|
|
||||||
|
Return values are:
|
||||||
|
- 0 if the numbers are the same
|
||||||
|
- < 0 if this number is smaller than the other
|
||||||
|
- > 0 if this number is bigger than the other
|
||||||
|
*/
|
||||||
|
int compare (const BigInteger& other) const noexcept;
|
||||||
|
|
||||||
|
/** Compares the magnitudes of two BigIntegers, ignoring their signs.
|
||||||
|
|
||||||
|
Return values are:
|
||||||
|
- 0 if the numbers are the same
|
||||||
|
- < 0 if this number is smaller than the other
|
||||||
|
- > 0 if this number is bigger than the other
|
||||||
|
*/
|
||||||
|
int compareAbsolute (const BigInteger& other) const noexcept;
|
||||||
|
|
||||||
|
/** Divides this value by another one and returns the remainder.
|
||||||
|
|
||||||
|
This number is divided by other, leaving the quotient in this number,
|
||||||
|
with the remainder being copied to the other BigInteger passed in.
|
||||||
|
*/
|
||||||
|
void divideBy (const BigInteger& divisor, BigInteger& remainder);
|
||||||
|
|
||||||
|
/** Returns the largest value that will divide both this value and the one passed-in. */
|
||||||
|
BigInteger findGreatestCommonDivisor (BigInteger other) const;
|
||||||
|
|
||||||
|
/** Performs a combined exponent and modulo operation.
|
||||||
|
This BigInteger's value becomes (this ^ exponent) % modulus.
|
||||||
|
*/
|
||||||
|
void exponentModulo (const BigInteger& exponent, const BigInteger& modulus);
|
||||||
|
|
||||||
|
/** Performs an inverse modulo on the value.
|
||||||
|
i.e. the result is (this ^ -1) mod (modulus).
|
||||||
|
*/
|
||||||
|
void inverseModulo (const BigInteger& modulus);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns true if the value is less than zero.
|
||||||
|
@see setNegative, negate
|
||||||
|
*/
|
||||||
|
bool isNegative() const noexcept;
|
||||||
|
|
||||||
|
/** Changes the sign of the number to be positive or negative.
|
||||||
|
@see isNegative, negate
|
||||||
|
*/
|
||||||
|
void setNegative (bool shouldBeNegative) noexcept;
|
||||||
|
|
||||||
|
/** Inverts the sign of the number.
|
||||||
|
@see isNegative, setNegative
|
||||||
|
*/
|
||||||
|
void negate() noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Converts the number to a string.
|
||||||
|
|
||||||
|
Specify a base such as 2 (binary), 8 (octal), 10 (decimal), 16 (hex).
|
||||||
|
If minimumNumCharacters is greater than 0, the returned string will be
|
||||||
|
padded with leading zeros to reach at least that length.
|
||||||
|
*/
|
||||||
|
String toString (int base, int minimumNumCharacters = 1) const;
|
||||||
|
|
||||||
|
/** Reads the numeric value from a string.
|
||||||
|
|
||||||
|
Specify a base such as 2 (binary), 8 (octal), 10 (decimal), 16 (hex).
|
||||||
|
Any invalid characters will be ignored.
|
||||||
|
*/
|
||||||
|
void parseString (StringRef text, int base);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Turns the number into a block of binary data.
|
||||||
|
|
||||||
|
The data is arranged as little-endian, so the first byte of data is the low 8 bits
|
||||||
|
of the number, and so on.
|
||||||
|
|
||||||
|
@see loadFromMemoryBlock
|
||||||
|
*/
|
||||||
|
MemoryBlock toMemoryBlock() const;
|
||||||
|
|
||||||
|
/** Converts a block of raw data into a number.
|
||||||
|
|
||||||
|
The data is arranged as little-endian, so the first byte of data is the low 8 bits
|
||||||
|
of the number, and so on.
|
||||||
|
|
||||||
|
@see toMemoryBlock
|
||||||
|
*/
|
||||||
|
void loadFromMemoryBlock (const MemoryBlock& data);
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
HeapBlock<uint32> values;
|
||||||
|
size_t numValues;
|
||||||
|
int highestBit;
|
||||||
|
bool negative;
|
||||||
|
|
||||||
|
void ensureSize (size_t);
|
||||||
|
void shiftLeft (int bits, int startBit);
|
||||||
|
void shiftRight (int bits, int startBit);
|
||||||
|
|
||||||
|
JUCE_LEAK_DETECTOR (BigInteger)
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Writes a BigInteger to an OutputStream as a UTF8 decimal string. */
|
||||||
|
OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const BigInteger& value);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#ifndef DOXYGEN
|
||||||
|
// For backwards compatibility, BitArray is defined as an alias for BigInteger.
|
||||||
|
typedef BigInteger BitArray;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_BIGINTEGER_H_INCLUDED
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,270 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_EXPRESSION_H_INCLUDED
|
||||||
|
#define JUCE_EXPRESSION_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A class for dynamically evaluating simple numeric expressions.
|
||||||
|
|
||||||
|
This class can parse a simple C-style string expression involving floating point
|
||||||
|
numbers, named symbols and functions. The basic arithmetic operations of +, -, *, /
|
||||||
|
are supported, as well as parentheses, and any alphanumeric identifiers are
|
||||||
|
assumed to be named symbols which will be resolved when the expression is
|
||||||
|
evaluated.
|
||||||
|
|
||||||
|
Expressions which use identifiers and functions require a subclass of
|
||||||
|
Expression::Scope to be supplied when evaluating them, and this object
|
||||||
|
is expected to be able to resolve the symbol names and perform the functions that
|
||||||
|
are used.
|
||||||
|
*/
|
||||||
|
class JUCE_API Expression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a simple expression with a value of 0. */
|
||||||
|
Expression();
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~Expression();
|
||||||
|
|
||||||
|
/** Creates a simple expression with a specified constant value. */
|
||||||
|
explicit Expression (double constant);
|
||||||
|
|
||||||
|
/** Creates a copy of an expression. */
|
||||||
|
Expression (const Expression&);
|
||||||
|
|
||||||
|
/** Copies another expression. */
|
||||||
|
Expression& operator= (const Expression&);
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
Expression (Expression&&) noexcept;
|
||||||
|
Expression& operator= (Expression&&) noexcept;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Creates an expression by parsing a string.
|
||||||
|
If there's a syntax error in the string, this will throw a ParseError exception.
|
||||||
|
@throws ParseError
|
||||||
|
*/
|
||||||
|
explicit Expression (const String& stringToParse);
|
||||||
|
|
||||||
|
/** Returns a string version of the expression. */
|
||||||
|
String toString() const;
|
||||||
|
|
||||||
|
/** Returns an expression which is an addition operation of two existing expressions. */
|
||||||
|
Expression operator+ (const Expression&) const;
|
||||||
|
/** Returns an expression which is a subtraction operation of two existing expressions. */
|
||||||
|
Expression operator- (const Expression&) const;
|
||||||
|
/** Returns an expression which is a multiplication operation of two existing expressions. */
|
||||||
|
Expression operator* (const Expression&) const;
|
||||||
|
/** Returns an expression which is a division operation of two existing expressions. */
|
||||||
|
Expression operator/ (const Expression&) const;
|
||||||
|
/** Returns an expression which performs a negation operation on an existing expression. */
|
||||||
|
Expression operator-() const;
|
||||||
|
|
||||||
|
/** Returns an Expression which is an identifier reference. */
|
||||||
|
static Expression symbol (const String& symbol);
|
||||||
|
|
||||||
|
/** Returns an Expression which is a function call. */
|
||||||
|
static Expression function (const String& functionName, const Array<Expression>& parameters);
|
||||||
|
|
||||||
|
/** Returns an Expression which parses a string from a character pointer, and updates the pointer
|
||||||
|
to indicate where it finished.
|
||||||
|
|
||||||
|
The pointer is incremented so that on return, it indicates the character that follows
|
||||||
|
the end of the expression that was parsed.
|
||||||
|
|
||||||
|
If there's a syntax error in the string, this will throw a ParseError exception.
|
||||||
|
@throws ParseError
|
||||||
|
*/
|
||||||
|
static Expression parse (String::CharPointerType& stringToParse);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** When evaluating an Expression object, this class is used to resolve symbols and
|
||||||
|
perform functions that the expression uses.
|
||||||
|
*/
|
||||||
|
class JUCE_API Scope
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Scope();
|
||||||
|
virtual ~Scope();
|
||||||
|
|
||||||
|
/** Returns some kind of globally unique ID that identifies this scope. */
|
||||||
|
virtual String getScopeUID() const;
|
||||||
|
|
||||||
|
/** Returns the value of a symbol.
|
||||||
|
If the symbol is unknown, this can throw an Expression::EvaluationError exception.
|
||||||
|
The member value is set to the part of the symbol that followed the dot, if there is
|
||||||
|
one, e.g. for "foo.bar", symbol = "foo" and member = "bar".
|
||||||
|
@throws Expression::EvaluationError
|
||||||
|
*/
|
||||||
|
virtual Expression getSymbolValue (const String& symbol) const;
|
||||||
|
|
||||||
|
/** Executes a named function.
|
||||||
|
If the function name is unknown, this can throw an Expression::EvaluationError exception.
|
||||||
|
@throws Expression::EvaluationError
|
||||||
|
*/
|
||||||
|
virtual double evaluateFunction (const String& functionName,
|
||||||
|
const double* parameters, int numParameters) const;
|
||||||
|
|
||||||
|
/** Used as a callback by the Scope::visitRelativeScope() method.
|
||||||
|
You should never create an instance of this class yourself, it's used by the
|
||||||
|
expression evaluation code.
|
||||||
|
*/
|
||||||
|
class Visitor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Visitor() {}
|
||||||
|
virtual void visit (const Scope&) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Creates a Scope object for a named scope, and then calls a visitor
|
||||||
|
to do some kind of processing with this new scope.
|
||||||
|
|
||||||
|
If the name is valid, this method must create a suitable (temporary) Scope
|
||||||
|
object to represent it, and must call the Visitor::visit() method with this
|
||||||
|
new scope.
|
||||||
|
*/
|
||||||
|
virtual void visitRelativeScope (const String& scopeName, Visitor& visitor) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Evaluates this expression, without using a Scope.
|
||||||
|
Without a Scope, no symbols can be used, and only basic functions such as sin, cos, tan,
|
||||||
|
min, max are available.
|
||||||
|
To find out about any errors during evaluation, use the other version of this method which
|
||||||
|
takes a String parameter.
|
||||||
|
*/
|
||||||
|
double evaluate() const;
|
||||||
|
|
||||||
|
/** Evaluates this expression, providing a scope that should be able to evaluate any symbols
|
||||||
|
or functions that it uses.
|
||||||
|
To find out about any errors during evaluation, use the other version of this method which
|
||||||
|
takes a String parameter.
|
||||||
|
*/
|
||||||
|
double evaluate (const Scope& scope) const;
|
||||||
|
|
||||||
|
/** Evaluates this expression, providing a scope that should be able to evaluate any symbols
|
||||||
|
or functions that it uses.
|
||||||
|
*/
|
||||||
|
double evaluate (const Scope& scope, String& evaluationError) const;
|
||||||
|
|
||||||
|
/** Attempts to return an expression which is a copy of this one, but with a constant adjusted
|
||||||
|
to make the expression resolve to a target value.
|
||||||
|
|
||||||
|
E.g. if the expression is "x + 10" and x is 5, then asking for a target value of 8 will return
|
||||||
|
the expression "x + 3". Obviously some expressions can't be reversed in this way, in which
|
||||||
|
case they might just be adjusted by adding a constant to the original expression.
|
||||||
|
|
||||||
|
@throws Expression::EvaluationError
|
||||||
|
*/
|
||||||
|
Expression adjustedToGiveNewResult (double targetValue, const Scope& scope) const;
|
||||||
|
|
||||||
|
/** Represents a symbol that is used in an Expression. */
|
||||||
|
struct Symbol
|
||||||
|
{
|
||||||
|
Symbol (const String& scopeUID, const String& symbolName);
|
||||||
|
bool operator== (const Symbol&) const noexcept;
|
||||||
|
bool operator!= (const Symbol&) const noexcept;
|
||||||
|
|
||||||
|
String scopeUID; /**< The unique ID of the Scope that contains this symbol. */
|
||||||
|
String symbolName; /**< The name of the symbol. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Returns a copy of this expression in which all instances of a given symbol have been renamed. */
|
||||||
|
Expression withRenamedSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope) const;
|
||||||
|
|
||||||
|
/** Returns true if this expression makes use of the specified symbol.
|
||||||
|
If a suitable scope is supplied, the search will dereference and recursively check
|
||||||
|
all symbols, so that it can be determined whether this expression relies on the given
|
||||||
|
symbol at any level in its evaluation. If the scope parameter is null, this just checks
|
||||||
|
whether the expression contains any direct references to the symbol.
|
||||||
|
|
||||||
|
@throws Expression::EvaluationError
|
||||||
|
*/
|
||||||
|
bool referencesSymbol (const Symbol& symbol, const Scope& scope) const;
|
||||||
|
|
||||||
|
/** Returns true if this expression contains any symbols. */
|
||||||
|
bool usesAnySymbols() const;
|
||||||
|
|
||||||
|
/** Returns a list of all symbols that may be needed to resolve this expression in the given scope. */
|
||||||
|
void findReferencedSymbols (Array<Symbol>& results, const Scope& scope) const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** An exception that can be thrown by Expression::parse(). */
|
||||||
|
class ParseError : public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ParseError (const String& message);
|
||||||
|
|
||||||
|
String description;
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Expression type.
|
||||||
|
@see Expression::getType()
|
||||||
|
*/
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
constantType,
|
||||||
|
functionType,
|
||||||
|
operatorType,
|
||||||
|
symbolType
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Returns the type of this expression. */
|
||||||
|
Type getType() const noexcept;
|
||||||
|
|
||||||
|
/** If this expression is a symbol, function or operator, this returns its identifier. */
|
||||||
|
String getSymbolOrFunction() const;
|
||||||
|
|
||||||
|
/** Returns the number of inputs to this expression.
|
||||||
|
@see getInput
|
||||||
|
*/
|
||||||
|
int getNumInputs() const;
|
||||||
|
|
||||||
|
/** Retrieves one of the inputs to this expression.
|
||||||
|
@see getNumInputs
|
||||||
|
*/
|
||||||
|
Expression getInput (int index) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
class Term;
|
||||||
|
struct Helpers;
|
||||||
|
friend class Term;
|
||||||
|
friend struct Helpers;
|
||||||
|
friend struct ContainerDeletePolicy<Term>;
|
||||||
|
friend class ReferenceCountedObjectPtr<Term>;
|
||||||
|
ReferenceCountedObjectPtr<Term> term;
|
||||||
|
|
||||||
|
explicit Expression (Term*);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // JUCE_EXPRESSION_H_INCLUDED
|
||||||
@@ -0,0 +1,549 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_MATHSFUNCTIONS_H_INCLUDED
|
||||||
|
#define JUCE_MATHSFUNCTIONS_H_INCLUDED
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/*
|
||||||
|
This file sets up some handy mathematical typdefs and functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// Definitions for the int8, int16, int32, int64 and pointer_sized_int types.
|
||||||
|
|
||||||
|
/** A platform-independent 8-bit signed integer type. */
|
||||||
|
typedef signed char int8;
|
||||||
|
/** A platform-independent 8-bit unsigned integer type. */
|
||||||
|
typedef unsigned char uint8;
|
||||||
|
/** A platform-independent 16-bit signed integer type. */
|
||||||
|
typedef signed short int16;
|
||||||
|
/** A platform-independent 16-bit unsigned integer type. */
|
||||||
|
typedef unsigned short uint16;
|
||||||
|
/** A platform-independent 32-bit signed integer type. */
|
||||||
|
typedef signed int int32;
|
||||||
|
/** A platform-independent 32-bit unsigned integer type. */
|
||||||
|
typedef unsigned int uint32;
|
||||||
|
|
||||||
|
#if JUCE_MSVC
|
||||||
|
/** A platform-independent 64-bit integer type. */
|
||||||
|
typedef __int64 int64;
|
||||||
|
/** A platform-independent 64-bit unsigned integer type. */
|
||||||
|
typedef unsigned __int64 uint64;
|
||||||
|
#else
|
||||||
|
/** A platform-independent 64-bit integer type. */
|
||||||
|
typedef long long int64;
|
||||||
|
/** A platform-independent 64-bit unsigned integer type. */
|
||||||
|
typedef unsigned long long uint64;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DOXYGEN
|
||||||
|
/** A macro for creating 64-bit literals.
|
||||||
|
Historically, this was needed to support portability with MSVC6, and is kept here
|
||||||
|
so that old code will still compile, but nowadays every compiler will support the
|
||||||
|
LL and ULL suffixes, so you should use those in preference to this macro.
|
||||||
|
*/
|
||||||
|
#define literal64bit(longLiteral) (longLiteral##LL)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JUCE_64BIT
|
||||||
|
/** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||||
|
typedef int64 pointer_sized_int;
|
||||||
|
/** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||||
|
typedef uint64 pointer_sized_uint;
|
||||||
|
#elif JUCE_MSVC
|
||||||
|
/** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||||
|
typedef _W64 int pointer_sized_int;
|
||||||
|
/** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||||
|
typedef _W64 unsigned int pointer_sized_uint;
|
||||||
|
#else
|
||||||
|
/** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||||
|
typedef int pointer_sized_int;
|
||||||
|
/** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */
|
||||||
|
typedef unsigned int pointer_sized_uint;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JUCE_MSVC
|
||||||
|
typedef pointer_sized_int ssize_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// Some indispensible min/max functions
|
||||||
|
|
||||||
|
/** Returns the larger of two values. */
|
||||||
|
template <typename Type>
|
||||||
|
inline Type jmax (const Type a, const Type b) { return (a < b) ? b : a; }
|
||||||
|
|
||||||
|
/** Returns the larger of three values. */
|
||||||
|
template <typename Type>
|
||||||
|
inline Type jmax (const Type a, const Type b, const Type c) { return (a < b) ? ((b < c) ? c : b) : ((a < c) ? c : a); }
|
||||||
|
|
||||||
|
/** Returns the larger of four values. */
|
||||||
|
template <typename Type>
|
||||||
|
inline Type jmax (const Type a, const Type b, const Type c, const Type d) { return jmax (a, jmax (b, c, d)); }
|
||||||
|
|
||||||
|
/** Returns the smaller of two values. */
|
||||||
|
template <typename Type>
|
||||||
|
inline Type jmin (const Type a, const Type b) { return (b < a) ? b : a; }
|
||||||
|
|
||||||
|
/** Returns the smaller of three values. */
|
||||||
|
template <typename Type>
|
||||||
|
inline Type jmin (const Type a, const Type b, const Type c) { return (b < a) ? ((c < b) ? c : b) : ((c < a) ? c : a); }
|
||||||
|
|
||||||
|
/** Returns the smaller of four values. */
|
||||||
|
template <typename Type>
|
||||||
|
inline Type jmin (const Type a, const Type b, const Type c, const Type d) { return jmin (a, jmin (b, c, d)); }
|
||||||
|
|
||||||
|
/** Scans an array of values, returning the minimum value that it contains. */
|
||||||
|
template <typename Type>
|
||||||
|
const Type findMinimum (const Type* data, int numValues)
|
||||||
|
{
|
||||||
|
if (numValues <= 0)
|
||||||
|
return Type();
|
||||||
|
|
||||||
|
Type result (*data++);
|
||||||
|
|
||||||
|
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
|
||||||
|
{
|
||||||
|
const Type& v = *data++;
|
||||||
|
if (v < result) result = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Scans an array of values, returning the maximum value that it contains. */
|
||||||
|
template <typename Type>
|
||||||
|
const Type findMaximum (const Type* values, int numValues)
|
||||||
|
{
|
||||||
|
if (numValues <= 0)
|
||||||
|
return Type();
|
||||||
|
|
||||||
|
Type result (*values++);
|
||||||
|
|
||||||
|
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
|
||||||
|
{
|
||||||
|
const Type& v = *values++;
|
||||||
|
if (result < v) result = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Scans an array of values, returning the minimum and maximum values that it contains. */
|
||||||
|
template <typename Type>
|
||||||
|
void findMinAndMax (const Type* values, int numValues, Type& lowest, Type& highest)
|
||||||
|
{
|
||||||
|
if (numValues <= 0)
|
||||||
|
{
|
||||||
|
lowest = Type();
|
||||||
|
highest = Type();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Type mn (*values++);
|
||||||
|
Type mx (mn);
|
||||||
|
|
||||||
|
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
|
||||||
|
{
|
||||||
|
const Type& v = *values++;
|
||||||
|
|
||||||
|
if (mx < v) mx = v;
|
||||||
|
if (v < mn) mn = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
lowest = mn;
|
||||||
|
highest = mx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Constrains a value to keep it within a given range.
|
||||||
|
|
||||||
|
This will check that the specified value lies between the lower and upper bounds
|
||||||
|
specified, and if not, will return the nearest value that would be in-range. Effectively,
|
||||||
|
it's like calling jmax (lowerLimit, jmin (upperLimit, value)).
|
||||||
|
|
||||||
|
Note that it expects that lowerLimit <= upperLimit. If this isn't true,
|
||||||
|
the results will be unpredictable.
|
||||||
|
|
||||||
|
@param lowerLimit the minimum value to return
|
||||||
|
@param upperLimit the maximum value to return
|
||||||
|
@param valueToConstrain the value to try to return
|
||||||
|
@returns the closest value to valueToConstrain which lies between lowerLimit
|
||||||
|
and upperLimit (inclusive)
|
||||||
|
@see jlimit0To, jmin, jmax
|
||||||
|
*/
|
||||||
|
template <typename Type>
|
||||||
|
inline Type jlimit (const Type lowerLimit,
|
||||||
|
const Type upperLimit,
|
||||||
|
const Type valueToConstrain) noexcept
|
||||||
|
{
|
||||||
|
jassert (lowerLimit <= upperLimit); // if these are in the wrong order, results are unpredictable..
|
||||||
|
|
||||||
|
return (valueToConstrain < lowerLimit) ? lowerLimit
|
||||||
|
: ((upperLimit < valueToConstrain) ? upperLimit
|
||||||
|
: valueToConstrain);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if a value is at least zero, and also below a specified upper limit.
|
||||||
|
This is basically a quicker way to write:
|
||||||
|
@code valueToTest >= 0 && valueToTest < upperLimit
|
||||||
|
@endcode
|
||||||
|
*/
|
||||||
|
template <typename Type>
|
||||||
|
inline bool isPositiveAndBelow (Type valueToTest, Type upperLimit) noexcept
|
||||||
|
{
|
||||||
|
jassert (Type() <= upperLimit); // makes no sense to call this if the upper limit is itself below zero..
|
||||||
|
return Type() <= valueToTest && valueToTest < upperLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline bool isPositiveAndBelow (const int valueToTest, const int upperLimit) noexcept
|
||||||
|
{
|
||||||
|
jassert (upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero..
|
||||||
|
return static_cast <unsigned int> (valueToTest) < static_cast <unsigned int> (upperLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if a value is at least zero, and also less than or equal to a specified upper limit.
|
||||||
|
This is basically a quicker way to write:
|
||||||
|
@code valueToTest >= 0 && valueToTest <= upperLimit
|
||||||
|
@endcode
|
||||||
|
*/
|
||||||
|
template <typename Type>
|
||||||
|
inline bool isPositiveAndNotGreaterThan (Type valueToTest, Type upperLimit) noexcept
|
||||||
|
{
|
||||||
|
jassert (Type() <= upperLimit); // makes no sense to call this if the upper limit is itself below zero..
|
||||||
|
return Type() <= valueToTest && valueToTest <= upperLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline bool isPositiveAndNotGreaterThan (const int valueToTest, const int upperLimit) noexcept
|
||||||
|
{
|
||||||
|
jassert (upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero..
|
||||||
|
return static_cast <unsigned int> (valueToTest) <= static_cast <unsigned int> (upperLimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Handy function to swap two values. */
|
||||||
|
template <typename Type>
|
||||||
|
inline void swapVariables (Type& variable1, Type& variable2)
|
||||||
|
{
|
||||||
|
std::swap (variable1, variable2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Handy function for getting the number of elements in a simple const C array.
|
||||||
|
E.g.
|
||||||
|
@code
|
||||||
|
static int myArray[] = { 1, 2, 3 };
|
||||||
|
|
||||||
|
int numElements = numElementsInArray (myArray) // returns 3
|
||||||
|
@endcode
|
||||||
|
*/
|
||||||
|
template <typename Type, int N>
|
||||||
|
inline int numElementsInArray (Type (&array)[N])
|
||||||
|
{
|
||||||
|
(void) array; // (required to avoid a spurious warning in MS compilers)
|
||||||
|
(void) sizeof (0[array]); // This line should cause an error if you pass an object with a user-defined subscript operator
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// Some useful maths functions that aren't always present with all compilers and build settings.
|
||||||
|
|
||||||
|
/** Using juce_hypot is easier than dealing with the different types of hypot function
|
||||||
|
that are provided by the various platforms and compilers. */
|
||||||
|
template <typename Type>
|
||||||
|
inline Type juce_hypot (Type a, Type b) noexcept
|
||||||
|
{
|
||||||
|
#if JUCE_MSVC
|
||||||
|
return static_cast <Type> (_hypot (a, b));
|
||||||
|
#else
|
||||||
|
return static_cast <Type> (hypot (a, b));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 64-bit abs function. */
|
||||||
|
inline int64 abs64 (const int64 n) noexcept
|
||||||
|
{
|
||||||
|
return (n >= 0) ? n : -n;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JUCE_MSVC && ! defined (DOXYGEN) // The MSVC libraries omit these functions for some reason...
|
||||||
|
template<typename Type> Type asinh (Type x) noexcept { return std::log (x + std::sqrt (x * x + (Type) 1)); }
|
||||||
|
template<typename Type> Type acosh (Type x) noexcept { return std::log (x + std::sqrt (x * x - (Type) 1)); }
|
||||||
|
template<typename Type> Type atanh (Type x) noexcept { return (std::log (x + (Type) 1) - std::log (((Type) 1) - x)) / (Type) 2; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** A predefined value for Pi, at double-precision.
|
||||||
|
@see float_Pi
|
||||||
|
*/
|
||||||
|
const double double_Pi = 3.1415926535897932384626433832795;
|
||||||
|
|
||||||
|
/** A predefined value for Pi, at single-precision.
|
||||||
|
@see double_Pi
|
||||||
|
*/
|
||||||
|
const float float_Pi = 3.14159265358979323846f;
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** The isfinite() method seems to vary between platforms, so this is a
|
||||||
|
platform-independent function for it.
|
||||||
|
*/
|
||||||
|
template <typename FloatingPointType>
|
||||||
|
inline bool juce_isfinite (FloatingPointType value)
|
||||||
|
{
|
||||||
|
#if JUCE_WINDOWS
|
||||||
|
return _finite (value);
|
||||||
|
#elif JUCE_ANDROID
|
||||||
|
return isfinite (value);
|
||||||
|
#else
|
||||||
|
return std::isfinite (value);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if JUCE_MSVC
|
||||||
|
#pragma optimize ("t", off)
|
||||||
|
#ifndef __INTEL_COMPILER
|
||||||
|
#pragma float_control (precise, on, push)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Fast floating-point-to-integer conversion.
|
||||||
|
|
||||||
|
This is faster than using the normal c++ cast to convert a float to an int, and
|
||||||
|
it will round the value to the nearest integer, rather than rounding it down
|
||||||
|
like the normal cast does.
|
||||||
|
|
||||||
|
Note that this routine gets its speed at the expense of some accuracy, and when
|
||||||
|
rounding values whose floating point component is exactly 0.5, odd numbers and
|
||||||
|
even numbers will be rounded up or down differently.
|
||||||
|
*/
|
||||||
|
template <typename FloatType>
|
||||||
|
inline int roundToInt (const FloatType value) noexcept
|
||||||
|
{
|
||||||
|
#ifdef __INTEL_COMPILER
|
||||||
|
#pragma float_control (precise, on, push)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
union { int asInt[2]; double asDouble; } n;
|
||||||
|
n.asDouble = ((double) value) + 6755399441055744.0;
|
||||||
|
|
||||||
|
#if JUCE_BIG_ENDIAN
|
||||||
|
return n.asInt [1];
|
||||||
|
#else
|
||||||
|
return n.asInt [0];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int roundToInt (int value) noexcept
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JUCE_MSVC
|
||||||
|
#ifndef __INTEL_COMPILER
|
||||||
|
#pragma float_control (pop)
|
||||||
|
#endif
|
||||||
|
#pragma optimize ("", on) // resets optimisations to the project defaults
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Fast floating-point-to-integer conversion.
|
||||||
|
|
||||||
|
This is a slightly slower and slightly more accurate version of roundDoubleToInt(). It works
|
||||||
|
fine for values above zero, but negative numbers are rounded the wrong way.
|
||||||
|
*/
|
||||||
|
inline int roundToIntAccurate (const double value) noexcept
|
||||||
|
{
|
||||||
|
#ifdef __INTEL_COMPILER
|
||||||
|
#pragma float_control (pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return roundToInt (value + 1.5e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Fast floating-point-to-integer conversion.
|
||||||
|
|
||||||
|
This is faster than using the normal c++ cast to convert a double to an int, and
|
||||||
|
it will round the value to the nearest integer, rather than rounding it down
|
||||||
|
like the normal cast does.
|
||||||
|
|
||||||
|
Note that this routine gets its speed at the expense of some accuracy, and when
|
||||||
|
rounding values whose floating point component is exactly 0.5, odd numbers and
|
||||||
|
even numbers will be rounded up or down differently. For a more accurate conversion,
|
||||||
|
see roundDoubleToIntAccurate().
|
||||||
|
*/
|
||||||
|
inline int roundDoubleToInt (const double value) noexcept
|
||||||
|
{
|
||||||
|
return roundToInt (value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Fast floating-point-to-integer conversion.
|
||||||
|
|
||||||
|
This is faster than using the normal c++ cast to convert a float to an int, and
|
||||||
|
it will round the value to the nearest integer, rather than rounding it down
|
||||||
|
like the normal cast does.
|
||||||
|
|
||||||
|
Note that this routine gets its speed at the expense of some accuracy, and when
|
||||||
|
rounding values whose floating point component is exactly 0.5, odd numbers and
|
||||||
|
even numbers will be rounded up or down differently.
|
||||||
|
*/
|
||||||
|
inline int roundFloatToInt (const float value) noexcept
|
||||||
|
{
|
||||||
|
return roundToInt (value);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns true if the specified integer is a power-of-two.
|
||||||
|
*/
|
||||||
|
template <typename IntegerType>
|
||||||
|
bool isPowerOfTwo (IntegerType value)
|
||||||
|
{
|
||||||
|
return (value & (value - 1)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the smallest power-of-two which is equal to or greater than the given integer.
|
||||||
|
*/
|
||||||
|
inline int nextPowerOfTwo (int n) noexcept
|
||||||
|
{
|
||||||
|
--n;
|
||||||
|
n |= (n >> 1);
|
||||||
|
n |= (n >> 2);
|
||||||
|
n |= (n >> 4);
|
||||||
|
n |= (n >> 8);
|
||||||
|
n |= (n >> 16);
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
template <typename IntegerType>
|
||||||
|
IntegerType negativeAwareModulo (IntegerType dividend, const IntegerType divisor) noexcept
|
||||||
|
{
|
||||||
|
jassert (divisor > 0);
|
||||||
|
dividend %= divisor;
|
||||||
|
return (dividend < 0) ? (dividend + divisor) : dividend;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the square of its argument. */
|
||||||
|
template <typename NumericType>
|
||||||
|
NumericType square (NumericType n) noexcept
|
||||||
|
{
|
||||||
|
return n * n;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if (JUCE_INTEL && JUCE_32BIT) || defined (DOXYGEN)
|
||||||
|
/** This macro can be applied to a float variable to check whether it contains a denormalised
|
||||||
|
value, and to normalise it if necessary.
|
||||||
|
On CPUs that aren't vulnerable to denormalisation problems, this will have no effect.
|
||||||
|
*/
|
||||||
|
#define JUCE_UNDENORMALISE(x) x += 1.0f; x -= 1.0f;
|
||||||
|
#else
|
||||||
|
#define JUCE_UNDENORMALISE(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** This namespace contains a few template classes for helping work out class type variations.
|
||||||
|
*/
|
||||||
|
namespace TypeHelpers
|
||||||
|
{
|
||||||
|
#if JUCE_VC8_OR_EARLIER
|
||||||
|
#define PARAMETER_TYPE(type) const type&
|
||||||
|
#else
|
||||||
|
/** The ParameterType struct is used to find the best type to use when passing some kind
|
||||||
|
of object as a parameter.
|
||||||
|
|
||||||
|
Of course, this is only likely to be useful in certain esoteric template situations.
|
||||||
|
|
||||||
|
Because "typename TypeHelpers::ParameterType<SomeClass>::type" is a bit of a mouthful, there's
|
||||||
|
a PARAMETER_TYPE(SomeClass) macro that you can use to get the same effect.
|
||||||
|
|
||||||
|
E.g. "myFunction (PARAMETER_TYPE (int), PARAMETER_TYPE (MyObject))"
|
||||||
|
would evaluate to "myfunction (int, const MyObject&)", keeping any primitive types as
|
||||||
|
pass-by-value, but passing objects as a const reference, to avoid copying.
|
||||||
|
*/
|
||||||
|
template <typename Type> struct ParameterType { typedef const Type& type; };
|
||||||
|
|
||||||
|
#if ! DOXYGEN
|
||||||
|
template <typename Type> struct ParameterType <Type&> { typedef Type& type; };
|
||||||
|
template <typename Type> struct ParameterType <Type*> { typedef Type* type; };
|
||||||
|
template <> struct ParameterType <char> { typedef char type; };
|
||||||
|
template <> struct ParameterType <unsigned char> { typedef unsigned char type; };
|
||||||
|
template <> struct ParameterType <short> { typedef short type; };
|
||||||
|
template <> struct ParameterType <unsigned short> { typedef unsigned short type; };
|
||||||
|
template <> struct ParameterType <int> { typedef int type; };
|
||||||
|
template <> struct ParameterType <unsigned int> { typedef unsigned int type; };
|
||||||
|
template <> struct ParameterType <long> { typedef long type; };
|
||||||
|
template <> struct ParameterType <unsigned long> { typedef unsigned long type; };
|
||||||
|
template <> struct ParameterType <int64> { typedef int64 type; };
|
||||||
|
template <> struct ParameterType <uint64> { typedef uint64 type; };
|
||||||
|
template <> struct ParameterType <bool> { typedef bool type; };
|
||||||
|
template <> struct ParameterType <float> { typedef float type; };
|
||||||
|
template <> struct ParameterType <double> { typedef double type; };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** A helpful macro to simplify the use of the ParameterType template.
|
||||||
|
@see ParameterType
|
||||||
|
*/
|
||||||
|
#define PARAMETER_TYPE(a) typename TypeHelpers::ParameterType<a>::type
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/** These templates are designed to take a type, and if it's a double, they return a double
|
||||||
|
type; for anything else, they return a float type.
|
||||||
|
*/
|
||||||
|
template <typename Type> struct SmallestFloatType { typedef float type; };
|
||||||
|
template <> struct SmallestFloatType <double> { typedef double type; };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#endif // JUCE_MATHSFUNCTIONS_H_INCLUDED
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_NORMALISABLERANGE_H_INCLUDED
|
||||||
|
#define JUCE_NORMALISABLERANGE_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Represents a mapping between an arbitrary range of values and a
|
||||||
|
normalised 0->1 range.
|
||||||
|
|
||||||
|
The properties of the mapping also include an optional snapping interval
|
||||||
|
and skew-factor.
|
||||||
|
|
||||||
|
@see Range
|
||||||
|
*/
|
||||||
|
template<typename ValueType>
|
||||||
|
class NormalisableRange
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Creates a continuous range that performs a dummy mapping. */
|
||||||
|
NormalisableRange() noexcept : start(), end (1), interval(), skew (static_cast<ValueType> (1)) {}
|
||||||
|
|
||||||
|
/** Creates a copy of another range. */
|
||||||
|
NormalisableRange (const NormalisableRange& other) noexcept
|
||||||
|
: start (other.start), end (other.end),
|
||||||
|
interval (other.interval), skew (other.skew)
|
||||||
|
{
|
||||||
|
checkInvariants();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a copy of another range. */
|
||||||
|
NormalisableRange& operator= (const NormalisableRange& other) noexcept
|
||||||
|
{
|
||||||
|
start = other.start;
|
||||||
|
end = other.end;
|
||||||
|
interval = other.interval;
|
||||||
|
skew = other.skew;
|
||||||
|
checkInvariants();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a NormalisableRange with a given range, interval and skew factor. */
|
||||||
|
NormalisableRange (ValueType rangeStart,
|
||||||
|
ValueType rangeEnd,
|
||||||
|
ValueType intervalValue,
|
||||||
|
ValueType skewFactor) noexcept
|
||||||
|
: start (rangeStart), end (rangeEnd),
|
||||||
|
interval (intervalValue), skew (skewFactor)
|
||||||
|
{
|
||||||
|
checkInvariants();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a NormalisableRange with a given range and interval, but a dummy skew-factor. */
|
||||||
|
NormalisableRange (ValueType rangeStart,
|
||||||
|
ValueType rangeEnd,
|
||||||
|
ValueType intervalValue) noexcept
|
||||||
|
: start (rangeStart), end (rangeEnd),
|
||||||
|
interval (intervalValue), skew (static_cast<ValueType> (1))
|
||||||
|
{
|
||||||
|
checkInvariants();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a NormalisableRange with a given range, continuous interval, but a dummy skew-factor. */
|
||||||
|
NormalisableRange (ValueType rangeStart,
|
||||||
|
ValueType rangeEnd) noexcept
|
||||||
|
: start (rangeStart), end (rangeEnd),
|
||||||
|
interval(), skew (static_cast<ValueType> (1))
|
||||||
|
{
|
||||||
|
checkInvariants();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Uses the properties of this mapping to convert a non-normalised value to
|
||||||
|
its 0->1 representation.
|
||||||
|
*/
|
||||||
|
ValueType convertTo0to1 (ValueType v) const noexcept
|
||||||
|
{
|
||||||
|
ValueType proportion = (v - start) / (end - start);
|
||||||
|
|
||||||
|
if (skew != static_cast<ValueType> (1))
|
||||||
|
proportion = std::pow (proportion, skew);
|
||||||
|
|
||||||
|
return proportion;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Uses the properties of this mapping to convert a normalised 0->1 value to
|
||||||
|
its full-range representation.
|
||||||
|
*/
|
||||||
|
ValueType convertFrom0to1 (ValueType proportion) const noexcept
|
||||||
|
{
|
||||||
|
if (skew != static_cast<ValueType> (1) && proportion > ValueType())
|
||||||
|
proportion = std::exp (std::log (proportion) / skew);
|
||||||
|
|
||||||
|
return start + (end - start) * proportion;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Takes a non-normalised value and snaps it based on the interval property of
|
||||||
|
this NormalisedRange. */
|
||||||
|
ValueType snapToLegalValue (ValueType v) const noexcept
|
||||||
|
{
|
||||||
|
if (interval > ValueType())
|
||||||
|
v = start + interval * std::floor ((v - start) / interval + static_cast<ValueType> (0.5));
|
||||||
|
|
||||||
|
if (v <= start || end <= start)
|
||||||
|
return start;
|
||||||
|
|
||||||
|
if (v >= end)
|
||||||
|
return end;
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The start of the non-normalised range. */
|
||||||
|
ValueType start;
|
||||||
|
|
||||||
|
/** The end of the non-normalised range. */
|
||||||
|
ValueType end;
|
||||||
|
|
||||||
|
/** The snapping interval that should be used (in non-normalised value). Use 0 for a continuous range. */
|
||||||
|
ValueType interval;
|
||||||
|
|
||||||
|
/** An optional skew factor that alters the way values are distribute across the range.
|
||||||
|
|
||||||
|
The skew factor lets you skew the mapping logarithmically so that larger or smaller
|
||||||
|
values are given a larger proportion of the avilable space.
|
||||||
|
|
||||||
|
A factor of 1.0 has no skewing effect at all. If the factor is < 1.0, the lower end
|
||||||
|
of the range will fill more of the slider's length; if the factor is > 1.0, the upper
|
||||||
|
end of the range will be expanded.
|
||||||
|
*/
|
||||||
|
ValueType skew;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void checkInvariants() const
|
||||||
|
{
|
||||||
|
jassert (end > start);
|
||||||
|
jassert (interval >= ValueType());
|
||||||
|
jassert (skew > ValueType());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_NORMALISABLERANGE_H_INCLUDED
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
Random::Random (const int64 seedValue) noexcept : seed (seedValue)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Random::Random() : seed (1)
|
||||||
|
{
|
||||||
|
setSeedRandomly();
|
||||||
|
}
|
||||||
|
|
||||||
|
Random::~Random() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Random::setSeed (const int64 newSeed) noexcept
|
||||||
|
{
|
||||||
|
seed = newSeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Random::combineSeed (const int64 seedValue) noexcept
|
||||||
|
{
|
||||||
|
seed ^= nextInt64() ^ seedValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Random::setSeedRandomly()
|
||||||
|
{
|
||||||
|
static int64 globalSeed = 0;
|
||||||
|
|
||||||
|
combineSeed (globalSeed ^ (int64) (pointer_sized_int) this);
|
||||||
|
combineSeed (Time::getMillisecondCounter());
|
||||||
|
combineSeed (Time::getHighResolutionTicks());
|
||||||
|
combineSeed (Time::getHighResolutionTicksPerSecond());
|
||||||
|
combineSeed (Time::currentTimeMillis());
|
||||||
|
globalSeed ^= seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
Random& Random::getSystemRandom() noexcept
|
||||||
|
{
|
||||||
|
static Random sysRand;
|
||||||
|
return sysRand;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
int Random::nextInt() noexcept
|
||||||
|
{
|
||||||
|
seed = (seed * 0x5deece66dLL + 11) & 0xffffffffffffLL;
|
||||||
|
|
||||||
|
return (int) (seed >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Random::nextInt (const int maxValue) noexcept
|
||||||
|
{
|
||||||
|
jassert (maxValue > 0);
|
||||||
|
return (int) ((((unsigned int) nextInt()) * (uint64) maxValue) >> 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Random::nextInt (Range<int> range) noexcept
|
||||||
|
{
|
||||||
|
return range.getStart() + nextInt (range.getLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 Random::nextInt64() noexcept
|
||||||
|
{
|
||||||
|
return (((int64) nextInt()) << 32) | (int64) (uint64) (uint32) nextInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Random::nextBool() noexcept
|
||||||
|
{
|
||||||
|
return (nextInt() & 0x40000000) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Random::nextFloat() noexcept
|
||||||
|
{
|
||||||
|
return static_cast<uint32> (nextInt()) / (std::numeric_limits<uint32>::max() + 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Random::nextDouble() noexcept
|
||||||
|
{
|
||||||
|
return static_cast<uint32> (nextInt()) / (std::numeric_limits<uint32>::max() + 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger Random::nextLargeNumber (const BigInteger& maximumValue)
|
||||||
|
{
|
||||||
|
BigInteger n;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
fillBitsRandomly (n, 0, maximumValue.getHighestBit() + 1);
|
||||||
|
}
|
||||||
|
while (n >= maximumValue);
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Random::fillBitsRandomly (void* const buffer, size_t bytes)
|
||||||
|
{
|
||||||
|
int* d = static_cast<int*> (buffer);
|
||||||
|
|
||||||
|
for (; bytes >= sizeof (int); bytes -= sizeof (int))
|
||||||
|
*d++ = nextInt();
|
||||||
|
|
||||||
|
if (bytes > 0)
|
||||||
|
{
|
||||||
|
const int lastBytes = nextInt();
|
||||||
|
memcpy (d, &lastBytes, bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Random::fillBitsRandomly (BigInteger& arrayToChange, int startBit, int numBits)
|
||||||
|
{
|
||||||
|
arrayToChange.setBit (startBit + numBits - 1, true); // to force the array to pre-allocate space
|
||||||
|
|
||||||
|
while ((startBit & 31) != 0 && numBits > 0)
|
||||||
|
{
|
||||||
|
arrayToChange.setBit (startBit++, nextBool());
|
||||||
|
--numBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (numBits >= 32)
|
||||||
|
{
|
||||||
|
arrayToChange.setBitRangeAsInt (startBit, 32, (unsigned int) nextInt());
|
||||||
|
startBit += 32;
|
||||||
|
numBits -= 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (--numBits >= 0)
|
||||||
|
arrayToChange.setBit (startBit + numBits, nextBool());
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if JUCE_UNIT_TESTS
|
||||||
|
|
||||||
|
class RandomTests : public UnitTest
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RandomTests() : UnitTest ("Random") {}
|
||||||
|
|
||||||
|
void runTest()
|
||||||
|
{
|
||||||
|
beginTest ("Random");
|
||||||
|
|
||||||
|
Random r = getRandom();
|
||||||
|
|
||||||
|
for (int i = 2000; --i >= 0;)
|
||||||
|
{
|
||||||
|
expect (r.nextDouble() >= 0.0 && r.nextDouble() < 1.0);
|
||||||
|
expect (r.nextFloat() >= 0.0f && r.nextFloat() < 1.0f);
|
||||||
|
expect (r.nextInt (5) >= 0 && r.nextInt (5) < 5);
|
||||||
|
expect (r.nextInt (1) == 0);
|
||||||
|
|
||||||
|
int n = r.nextInt (50) + 1;
|
||||||
|
expect (r.nextInt (n) >= 0 && r.nextInt (n) < n);
|
||||||
|
|
||||||
|
n = r.nextInt (0x7ffffffe) + 1;
|
||||||
|
expect (r.nextInt (n) >= 0 && r.nextInt (n) < n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static RandomTests randomTests;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_RANDOM_H_INCLUDED
|
||||||
|
#define JUCE_RANDOM_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A random number generator.
|
||||||
|
|
||||||
|
You can create a Random object and use it to generate a sequence of random numbers.
|
||||||
|
*/
|
||||||
|
class JUCE_API Random
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a Random object based on a seed value.
|
||||||
|
|
||||||
|
For a given seed value, the subsequent numbers generated by this object
|
||||||
|
will be predictable, so a good idea is to set this value based
|
||||||
|
on the time, e.g.
|
||||||
|
|
||||||
|
new Random (Time::currentTimeMillis())
|
||||||
|
*/
|
||||||
|
explicit Random (int64 seedValue) noexcept;
|
||||||
|
|
||||||
|
/** Creates a Random object using a random seed value.
|
||||||
|
Internally, this calls setSeedRandomly() to randomise the seed.
|
||||||
|
*/
|
||||||
|
Random();
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~Random() noexcept;
|
||||||
|
|
||||||
|
/** Returns the next random 32 bit integer.
|
||||||
|
@returns a random integer from the full range 0x80000000 to 0x7fffffff
|
||||||
|
*/
|
||||||
|
int nextInt() noexcept;
|
||||||
|
|
||||||
|
/** Returns the next random number, limited to a given range.
|
||||||
|
The maxValue parameter may not be negative, or zero.
|
||||||
|
@returns a random integer between 0 (inclusive) and maxValue (exclusive).
|
||||||
|
*/
|
||||||
|
int nextInt (int maxValue) noexcept;
|
||||||
|
|
||||||
|
/** Returns the next random number, limited to a given range.
|
||||||
|
@returns a random integer between the range start (inclusive) and its end (exclusive).
|
||||||
|
*/
|
||||||
|
int nextInt (Range<int> range) noexcept;
|
||||||
|
|
||||||
|
/** Returns the next 64-bit random number.
|
||||||
|
@returns a random integer from the full range 0x8000000000000000 to 0x7fffffffffffffff
|
||||||
|
*/
|
||||||
|
int64 nextInt64() noexcept;
|
||||||
|
|
||||||
|
/** Returns the next random floating-point number.
|
||||||
|
@returns a random value in the range 0 to 1.0
|
||||||
|
*/
|
||||||
|
float nextFloat() noexcept;
|
||||||
|
|
||||||
|
/** Returns the next random floating-point number.
|
||||||
|
@returns a random value in the range 0 to 1.0
|
||||||
|
*/
|
||||||
|
double nextDouble() noexcept;
|
||||||
|
|
||||||
|
/** Returns the next random boolean value. */
|
||||||
|
bool nextBool() noexcept;
|
||||||
|
|
||||||
|
/** Returns a BigInteger containing a random number.
|
||||||
|
@returns a random value in the range 0 to (maximumValue - 1).
|
||||||
|
*/
|
||||||
|
BigInteger nextLargeNumber (const BigInteger& maximumValue);
|
||||||
|
|
||||||
|
/** Fills a block of memory with random values. */
|
||||||
|
void fillBitsRandomly (void* bufferToFill, size_t sizeInBytes);
|
||||||
|
|
||||||
|
/** Sets a range of bits in a BigInteger to random values. */
|
||||||
|
void fillBitsRandomly (BigInteger& arrayToChange, int startBit, int numBits);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Resets this Random object to a given seed value. */
|
||||||
|
void setSeed (int64 newSeed) noexcept;
|
||||||
|
|
||||||
|
/** Returns the RNG's current seed. */
|
||||||
|
int64 getSeed() const noexcept { return seed; }
|
||||||
|
|
||||||
|
/** Merges this object's seed with another value.
|
||||||
|
This sets the seed to be a value created by combining the current seed and this
|
||||||
|
new value.
|
||||||
|
*/
|
||||||
|
void combineSeed (int64 seedValue) noexcept;
|
||||||
|
|
||||||
|
/** Reseeds this generator using a value generated from various semi-random system
|
||||||
|
properties like the current time, etc.
|
||||||
|
|
||||||
|
Because this function convolves the time with the last seed value, calling
|
||||||
|
it repeatedly will increase the randomness of the final result.
|
||||||
|
*/
|
||||||
|
void setSeedRandomly();
|
||||||
|
|
||||||
|
/** The overhead of creating a new Random object is fairly small, but if you want to avoid
|
||||||
|
it, you can call this method to get a global shared Random object.
|
||||||
|
|
||||||
|
It's not thread-safe though, so threads should use their own Random object, otherwise
|
||||||
|
you run the risk of your random numbers becoming.. erm.. randomly corrupted..
|
||||||
|
*/
|
||||||
|
static Random& getSystemRandom() noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
int64 seed;
|
||||||
|
|
||||||
|
JUCE_LEAK_DETECTOR (Random)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_RANDOM_H_INCLUDED
|
||||||
@@ -0,0 +1,304 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_RANGE_H_INCLUDED
|
||||||
|
#define JUCE_RANGE_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** A general-purpose range object, that simply represents any linear range with
|
||||||
|
a start and end point.
|
||||||
|
|
||||||
|
Note that when checking whether values fall within the range, the start value is
|
||||||
|
considered to be inclusive, and the end of the range exclusive.
|
||||||
|
|
||||||
|
The templated parameter is expected to be a primitive integer or floating point
|
||||||
|
type, though class types could also be used if they behave in a number-like way.
|
||||||
|
*/
|
||||||
|
template <typename ValueType>
|
||||||
|
class Range
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Constructs an empty range. */
|
||||||
|
Range() noexcept : start(), end()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Constructs a range with given start and end values. */
|
||||||
|
Range (const ValueType startValue, const ValueType endValue) noexcept
|
||||||
|
: start (startValue), end (jmax (startValue, endValue))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Constructs a copy of another range. */
|
||||||
|
Range (const Range& other) noexcept
|
||||||
|
: start (other.start), end (other.end)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copies another range object. */
|
||||||
|
Range& operator= (Range other) noexcept
|
||||||
|
{
|
||||||
|
start = other.start;
|
||||||
|
end = other.end;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the range that lies between two positions (in either order). */
|
||||||
|
static Range between (const ValueType position1, const ValueType position2) noexcept
|
||||||
|
{
|
||||||
|
return position1 < position2 ? Range (position1, position2)
|
||||||
|
: 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
|
||||||
|
{
|
||||||
|
return Range (start, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the start of the range. */
|
||||||
|
inline ValueType getStart() const noexcept { return start; }
|
||||||
|
|
||||||
|
/** Returns the length of the range. */
|
||||||
|
inline ValueType getLength() const noexcept { return end - start; }
|
||||||
|
|
||||||
|
/** Returns the end of the range. */
|
||||||
|
inline ValueType getEnd() const noexcept { return end; }
|
||||||
|
|
||||||
|
/** Returns true if the range has a length of zero. */
|
||||||
|
inline bool isEmpty() const noexcept { return start == end; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Changes the start position of the range, leaving the end position unchanged.
|
||||||
|
If the new start position is higher than the current end of the range, the end point
|
||||||
|
will be pushed along to equal it, leaving an empty range at the new position.
|
||||||
|
*/
|
||||||
|
void setStart (const ValueType newStart) noexcept
|
||||||
|
{
|
||||||
|
start = newStart;
|
||||||
|
if (end < newStart)
|
||||||
|
end = newStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a range with the same end as this one, but a different start.
|
||||||
|
If the new start position is higher than the current end of the range, the end point
|
||||||
|
will be pushed along to equal it, returning an empty range at the new position.
|
||||||
|
*/
|
||||||
|
Range withStart (const ValueType newStart) const noexcept
|
||||||
|
{
|
||||||
|
return Range (newStart, jmax (newStart, end));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a range with the same length as this one, but moved to have the given start position. */
|
||||||
|
Range movedToStartAt (const ValueType newStart) const noexcept
|
||||||
|
{
|
||||||
|
return Range (newStart, end + (newStart - start));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Changes the end position of the range, leaving the start unchanged.
|
||||||
|
If the new end position is below the current start of the range, the start point
|
||||||
|
will be pushed back to equal the new end point.
|
||||||
|
*/
|
||||||
|
void setEnd (const ValueType newEnd) noexcept
|
||||||
|
{
|
||||||
|
end = newEnd;
|
||||||
|
if (newEnd < start)
|
||||||
|
start = newEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a range with the same start position as this one, but a different end.
|
||||||
|
If the new end position is below the current start of the range, the start point
|
||||||
|
will be pushed back to equal the new end point.
|
||||||
|
*/
|
||||||
|
Range withEnd (const ValueType newEnd) const noexcept
|
||||||
|
{
|
||||||
|
return Range (jmin (start, newEnd), newEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a range with the same length as this one, but moved to have the given end position. */
|
||||||
|
Range movedToEndAt (const ValueType newEnd) const noexcept
|
||||||
|
{
|
||||||
|
return Range (start + (newEnd - end), newEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Changes the length of the range.
|
||||||
|
Lengths less than zero are treated as zero.
|
||||||
|
*/
|
||||||
|
void setLength (const ValueType newLength) noexcept
|
||||||
|
{
|
||||||
|
end = start + jmax (ValueType(), newLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a range with the same start as this one, but a different length.
|
||||||
|
Lengths less than zero are treated as zero.
|
||||||
|
*/
|
||||||
|
Range withLength (const ValueType newLength) const noexcept
|
||||||
|
{
|
||||||
|
return Range (start, start + newLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Adds an amount to the start and end of the range. */
|
||||||
|
inline Range operator+= (const ValueType amountToAdd) noexcept
|
||||||
|
{
|
||||||
|
start += amountToAdd;
|
||||||
|
end += amountToAdd;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Subtracts an amount from the start and end of the range. */
|
||||||
|
inline Range operator-= (const ValueType amountToSubtract) noexcept
|
||||||
|
{
|
||||||
|
start -= amountToSubtract;
|
||||||
|
end -= amountToSubtract;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a range that is equal to this one with an amount added to its
|
||||||
|
start and end.
|
||||||
|
*/
|
||||||
|
Range operator+ (const ValueType amountToAdd) const noexcept
|
||||||
|
{
|
||||||
|
return Range (start + amountToAdd, end + amountToAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a range that is equal to this one with the specified amount
|
||||||
|
subtracted from its start and end. */
|
||||||
|
Range operator- (const ValueType amountToSubtract) const noexcept
|
||||||
|
{
|
||||||
|
return Range (start - amountToSubtract, end - amountToSubtract);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator== (Range other) const noexcept { return start == other.start && end == other.end; }
|
||||||
|
bool operator!= (Range other) const noexcept { return start != other.start || end != other.end; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns true if the given position lies inside this range. */
|
||||||
|
bool contains (const ValueType position) const noexcept
|
||||||
|
{
|
||||||
|
return start <= position && position < end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the nearest value to the one supplied, which lies within the range. */
|
||||||
|
ValueType clipValue (const ValueType value) const noexcept
|
||||||
|
{
|
||||||
|
return jlimit (start, end, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the given range lies entirely inside this range.
|
||||||
|
When making this comparison, the start value is considered to be inclusive,
|
||||||
|
and the end of the range exclusive.
|
||||||
|
*/
|
||||||
|
bool contains (Range other) const noexcept
|
||||||
|
{
|
||||||
|
return start <= other.start && end >= other.end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the given range intersects this one. */
|
||||||
|
bool intersects (Range other) const noexcept
|
||||||
|
{
|
||||||
|
return other.start < end && start < other.end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the range that is the intersection of the two ranges, or an empty range
|
||||||
|
with an undefined start position if they don't overlap. */
|
||||||
|
Range getIntersectionWith (Range other) const noexcept
|
||||||
|
{
|
||||||
|
return Range (jmax (start, other.start),
|
||||||
|
jmin (end, other.end));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the smallest range that contains both this one and the other one. */
|
||||||
|
Range getUnionWith (Range other) const noexcept
|
||||||
|
{
|
||||||
|
return Range (jmin (start, other.start),
|
||||||
|
jmax (end, other.end));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the smallest range that contains both this one and the given value. */
|
||||||
|
Range getUnionWith (const ValueType valueToInclude) const noexcept
|
||||||
|
{
|
||||||
|
return Range (jmin (valueToInclude, start),
|
||||||
|
jmax (valueToInclude, end));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a given range, after moving it forwards or backwards to fit it
|
||||||
|
within this range.
|
||||||
|
|
||||||
|
If the supplied range has a greater length than this one, the return value
|
||||||
|
will be this range.
|
||||||
|
|
||||||
|
Otherwise, if the supplied range is smaller than this one, the return value
|
||||||
|
will be the new range, shifted forwards or backwards so that it doesn't extend
|
||||||
|
beyond this one, but keeping its original length.
|
||||||
|
*/
|
||||||
|
Range constrainRange (Range rangeToConstrain) const noexcept
|
||||||
|
{
|
||||||
|
const ValueType otherLen = rangeToConstrain.getLength();
|
||||||
|
return getLength() <= otherLen
|
||||||
|
? *this
|
||||||
|
: rangeToConstrain.movedToStartAt (jlimit (start, end - otherLen, rangeToConstrain.getStart()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Scans an array of values for its min and max, and returns these as a Range. */
|
||||||
|
static Range findMinAndMax (const ValueType* values, int numValues) noexcept
|
||||||
|
{
|
||||||
|
if (numValues <= 0)
|
||||||
|
return Range();
|
||||||
|
|
||||||
|
const ValueType first (*values++);
|
||||||
|
Range r (first, first);
|
||||||
|
|
||||||
|
while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample)
|
||||||
|
{
|
||||||
|
const ValueType v (*values++);
|
||||||
|
|
||||||
|
if (r.end < v) r.end = v;
|
||||||
|
if (v < r.start) r.start = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
ValueType start, end;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_RANGE_H_INCLUDED
|
||||||
@@ -0,0 +1,399 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_ATOMIC_H_INCLUDED
|
||||||
|
#define JUCE_ATOMIC_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Simple class to hold a primitive value and perform atomic operations on it.
|
||||||
|
|
||||||
|
The type used must be a 32 or 64 bit primitive, like an int, pointer, etc.
|
||||||
|
There are methods to perform most of the basic atomic operations.
|
||||||
|
*/
|
||||||
|
template <typename Type>
|
||||||
|
class Atomic
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Creates a new value, initialised to zero. */
|
||||||
|
inline Atomic() noexcept
|
||||||
|
: value (0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a new value, with a given initial value. */
|
||||||
|
inline explicit Atomic (const Type initialValue) noexcept
|
||||||
|
: value (initialValue)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copies another value (atomically). */
|
||||||
|
inline Atomic (const Atomic& other) noexcept
|
||||||
|
: value (other.get())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
inline ~Atomic() noexcept
|
||||||
|
{
|
||||||
|
// This class can only be used for types which are 32 or 64 bits in size.
|
||||||
|
static_jassert (sizeof (Type) == 4 || sizeof (Type) == 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Atomically reads and returns the current value. */
|
||||||
|
Type get() const noexcept;
|
||||||
|
|
||||||
|
/** Copies another value onto this one (atomically). */
|
||||||
|
inline Atomic& operator= (const Atomic& other) noexcept { exchange (other.get()); return *this; }
|
||||||
|
|
||||||
|
/** Copies another value onto this one (atomically). */
|
||||||
|
inline Atomic& operator= (const Type newValue) noexcept { exchange (newValue); return *this; }
|
||||||
|
|
||||||
|
/** Atomically sets the current value. */
|
||||||
|
void set (Type newValue) noexcept { exchange (newValue); }
|
||||||
|
|
||||||
|
/** Atomically sets the current value, returning the value that was replaced. */
|
||||||
|
Type exchange (Type value) noexcept;
|
||||||
|
|
||||||
|
/** Atomically adds a number to this value, returning the new value. */
|
||||||
|
Type operator+= (Type amountToAdd) noexcept;
|
||||||
|
|
||||||
|
/** Atomically subtracts a number from this value, returning the new value. */
|
||||||
|
Type operator-= (Type amountToSubtract) noexcept;
|
||||||
|
|
||||||
|
/** Atomically increments this value, returning the new value. */
|
||||||
|
Type operator++() noexcept;
|
||||||
|
|
||||||
|
/** Atomically decrements this value, returning the new value. */
|
||||||
|
Type operator--() noexcept;
|
||||||
|
|
||||||
|
/** Atomically compares this value with a target value, and if it is equal, sets
|
||||||
|
this to be equal to a new value.
|
||||||
|
|
||||||
|
This operation is the atomic equivalent of doing this:
|
||||||
|
@code
|
||||||
|
bool compareAndSetBool (Type newValue, Type valueToCompare)
|
||||||
|
{
|
||||||
|
if (get() == valueToCompare)
|
||||||
|
{
|
||||||
|
set (newValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@returns true if the comparison was true and the value was replaced; false if
|
||||||
|
the comparison failed and the value was left unchanged.
|
||||||
|
@see compareAndSetValue
|
||||||
|
*/
|
||||||
|
bool compareAndSetBool (Type newValue, Type valueToCompare) noexcept;
|
||||||
|
|
||||||
|
/** Atomically compares this value with a target value, and if it is equal, sets
|
||||||
|
this to be equal to a new value.
|
||||||
|
|
||||||
|
This operation is the atomic equivalent of doing this:
|
||||||
|
@code
|
||||||
|
Type compareAndSetValue (Type newValue, Type valueToCompare)
|
||||||
|
{
|
||||||
|
Type oldValue = get();
|
||||||
|
if (oldValue == valueToCompare)
|
||||||
|
set (newValue);
|
||||||
|
|
||||||
|
return oldValue;
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@returns the old value before it was changed.
|
||||||
|
@see compareAndSetBool
|
||||||
|
*/
|
||||||
|
Type compareAndSetValue (Type newValue, Type valueToCompare) noexcept;
|
||||||
|
|
||||||
|
/** Implements a memory read/write barrier. */
|
||||||
|
static void memoryBarrier() noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if JUCE_64BIT
|
||||||
|
JUCE_ALIGN (8)
|
||||||
|
#else
|
||||||
|
JUCE_ALIGN (4)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** The raw value that this class operates on.
|
||||||
|
This is exposed publically in case you need to manipulate it directly
|
||||||
|
for performance reasons.
|
||||||
|
*/
|
||||||
|
volatile Type value;
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename Dest, typename Source>
|
||||||
|
static inline Dest castTo (Source value) noexcept { union { Dest d; Source s; } u; u.s = value; return u.d; }
|
||||||
|
|
||||||
|
static inline Type castFrom32Bit (int32 value) noexcept { return castTo <Type, int32> (value); }
|
||||||
|
static inline Type castFrom64Bit (int64 value) noexcept { return castTo <Type, int64> (value); }
|
||||||
|
static inline int32 castTo32Bit (Type value) noexcept { return castTo <int32, Type> (value); }
|
||||||
|
static inline int64 castTo64Bit (Type value) noexcept { return castTo <int64, Type> (value); }
|
||||||
|
|
||||||
|
Type operator++ (int); // better to just use pre-increment with atomics..
|
||||||
|
Type operator-- (int);
|
||||||
|
|
||||||
|
/** This templated negate function will negate pointers as well as integers */
|
||||||
|
template <typename ValueType>
|
||||||
|
inline ValueType negateValue (ValueType n) noexcept
|
||||||
|
{
|
||||||
|
return sizeof (ValueType) == 1 ? (ValueType) -(signed char) n
|
||||||
|
: (sizeof (ValueType) == 2 ? (ValueType) -(short) n
|
||||||
|
: (sizeof (ValueType) == 4 ? (ValueType) -(int) n
|
||||||
|
: ((ValueType) -(int64) n)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This templated negate function will negate pointers as well as integers */
|
||||||
|
template <typename PointerType>
|
||||||
|
inline PointerType* negateValue (PointerType* n) noexcept
|
||||||
|
{
|
||||||
|
return reinterpret_cast <PointerType*> (-reinterpret_cast <pointer_sized_int> (n));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/*
|
||||||
|
The following code is in the header so that the atomics can be inlined where possible...
|
||||||
|
*/
|
||||||
|
#if JUCE_MAC && (JUCE_PPC || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2))
|
||||||
|
#define JUCE_ATOMICS_MAC_LEGACY 1 // Older OSX builds using gcc4.1 or earlier
|
||||||
|
|
||||||
|
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
|
||||||
|
#define JUCE_MAC_ATOMICS_VOLATILE
|
||||||
|
#else
|
||||||
|
#define JUCE_MAC_ATOMICS_VOLATILE volatile
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JUCE_PPC
|
||||||
|
// None of these atomics are available for PPC or for iOS 3.1 or earlier!!
|
||||||
|
template <typename Type> static Type OSAtomicAdd64Barrier (Type b, JUCE_MAC_ATOMICS_VOLATILE Type* a) noexcept { jassertfalse; return *a += b; }
|
||||||
|
template <typename Type> static Type OSAtomicIncrement64Barrier (JUCE_MAC_ATOMICS_VOLATILE Type* a) noexcept { jassertfalse; return ++*a; }
|
||||||
|
template <typename Type> static Type OSAtomicDecrement64Barrier (JUCE_MAC_ATOMICS_VOLATILE Type* a) noexcept { jassertfalse; return --*a; }
|
||||||
|
template <typename Type> static bool OSAtomicCompareAndSwap64Barrier (Type old, Type newValue, JUCE_MAC_ATOMICS_VOLATILE Type* value) noexcept
|
||||||
|
{ jassertfalse; if (old == *value) { *value = newValue; return true; } return false; }
|
||||||
|
#define JUCE_64BIT_ATOMICS_UNAVAILABLE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#elif JUCE_GCC || JUCE_CLANG
|
||||||
|
#define JUCE_ATOMICS_GCC 1 // GCC with intrinsics
|
||||||
|
|
||||||
|
#if JUCE_IOS || JUCE_ANDROID // (64-bit ops will compile but not link on these mobile OSes)
|
||||||
|
#define JUCE_64BIT_ATOMICS_UNAVAILABLE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#else
|
||||||
|
#define JUCE_ATOMICS_WINDOWS 1 // Windows with intrinsics
|
||||||
|
|
||||||
|
#if JUCE_USE_MSVC_INTRINSICS
|
||||||
|
#ifndef __INTEL_COMPILER
|
||||||
|
#pragma intrinsic (_InterlockedExchange, _InterlockedIncrement, _InterlockedDecrement, _InterlockedCompareExchange, \
|
||||||
|
_InterlockedCompareExchange64, _InterlockedExchangeAdd, _ReadWriteBarrier)
|
||||||
|
#endif
|
||||||
|
#define juce_InterlockedExchange(a, b) _InterlockedExchange(a, b)
|
||||||
|
#define juce_InterlockedIncrement(a) _InterlockedIncrement(a)
|
||||||
|
#define juce_InterlockedDecrement(a) _InterlockedDecrement(a)
|
||||||
|
#define juce_InterlockedExchangeAdd(a, b) _InterlockedExchangeAdd(a, b)
|
||||||
|
#define juce_InterlockedCompareExchange(a, b, c) _InterlockedCompareExchange(a, b, c)
|
||||||
|
#define juce_InterlockedCompareExchange64(a, b, c) _InterlockedCompareExchange64(a, b, c)
|
||||||
|
#define juce_MemoryBarrier _ReadWriteBarrier
|
||||||
|
#else
|
||||||
|
long juce_InterlockedExchange (volatile long* a, long b) noexcept;
|
||||||
|
long juce_InterlockedIncrement (volatile long* a) noexcept;
|
||||||
|
long juce_InterlockedDecrement (volatile long* a) noexcept;
|
||||||
|
long juce_InterlockedExchangeAdd (volatile long* a, long b) noexcept;
|
||||||
|
long juce_InterlockedCompareExchange (volatile long* a, long b, long c) noexcept;
|
||||||
|
__int64 juce_InterlockedCompareExchange64 (volatile __int64* a, __int64 b, __int64 c) noexcept;
|
||||||
|
inline void juce_MemoryBarrier() noexcept { long x = 0; juce_InterlockedIncrement (&x); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JUCE_64BIT
|
||||||
|
#ifndef __INTEL_COMPILER
|
||||||
|
#pragma intrinsic (_InterlockedExchangeAdd64, _InterlockedExchange64, _InterlockedIncrement64, _InterlockedDecrement64)
|
||||||
|
#endif
|
||||||
|
#define juce_InterlockedExchangeAdd64(a, b) _InterlockedExchangeAdd64(a, b)
|
||||||
|
#define juce_InterlockedExchange64(a, b) _InterlockedExchange64(a, b)
|
||||||
|
#define juce_InterlockedIncrement64(a) _InterlockedIncrement64(a)
|
||||||
|
#define juce_InterlockedDecrement64(a) _InterlockedDecrement64(a)
|
||||||
|
#else
|
||||||
|
// None of these atomics are available in a 32-bit Windows build!!
|
||||||
|
template <typename Type> static Type juce_InterlockedExchangeAdd64 (volatile Type* a, Type b) noexcept { jassertfalse; Type old = *a; *a += b; return old; }
|
||||||
|
template <typename Type> static Type juce_InterlockedExchange64 (volatile Type* a, Type b) noexcept { jassertfalse; Type old = *a; *a = b; return old; }
|
||||||
|
template <typename Type> static Type juce_InterlockedIncrement64 (volatile Type* a) noexcept { jassertfalse; return ++*a; }
|
||||||
|
template <typename Type> static Type juce_InterlockedDecrement64 (volatile Type* a) noexcept { jassertfalse; return --*a; }
|
||||||
|
#define JUCE_64BIT_ATOMICS_UNAVAILABLE 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if JUCE_MSVC
|
||||||
|
#pragma warning (push)
|
||||||
|
#pragma warning (disable: 4311) // (truncation warning)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
template <typename Type>
|
||||||
|
inline Type Atomic<Type>::get() const noexcept
|
||||||
|
{
|
||||||
|
#if JUCE_ATOMICS_MAC_LEGACY
|
||||||
|
return sizeof (Type) == 4 ? castFrom32Bit ((int32) OSAtomicAdd32Barrier ((int32_t) 0, (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value))
|
||||||
|
: castFrom64Bit ((int64) OSAtomicAdd64Barrier ((int64_t) 0, (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value));
|
||||||
|
#elif JUCE_ATOMICS_WINDOWS
|
||||||
|
return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedExchangeAdd ((volatile long*) &value, (long) 0))
|
||||||
|
: castFrom64Bit ((int64) juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) 0));
|
||||||
|
#elif JUCE_ATOMICS_GCC
|
||||||
|
return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_add_and_fetch ((volatile int32*) &value, 0))
|
||||||
|
: castFrom64Bit ((int64) __sync_add_and_fetch ((volatile int64*) &value, 0));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
inline Type Atomic<Type>::exchange (const Type newValue) noexcept
|
||||||
|
{
|
||||||
|
#if JUCE_ATOMICS_MAC_LEGACY || JUCE_ATOMICS_GCC
|
||||||
|
Type currentVal = value;
|
||||||
|
while (! compareAndSetBool (newValue, currentVal)) { currentVal = value; }
|
||||||
|
return currentVal;
|
||||||
|
#elif JUCE_ATOMICS_WINDOWS
|
||||||
|
return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedExchange ((volatile long*) &value, (long) castTo32Bit (newValue)))
|
||||||
|
: castFrom64Bit ((int64) juce_InterlockedExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue)));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
inline Type Atomic<Type>::operator+= (const Type amountToAdd) noexcept
|
||||||
|
{
|
||||||
|
#if JUCE_ATOMICS_MAC_LEGACY
|
||||||
|
return sizeof (Type) == 4 ? (Type) OSAtomicAdd32Barrier ((int32_t) castTo32Bit (amountToAdd), (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||||
|
: (Type) OSAtomicAdd64Barrier ((int64_t) amountToAdd, (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||||
|
#elif JUCE_ATOMICS_WINDOWS
|
||||||
|
return sizeof (Type) == 4 ? (Type) (juce_InterlockedExchangeAdd ((volatile long*) &value, (long) amountToAdd) + (long) amountToAdd)
|
||||||
|
: (Type) (juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) amountToAdd) + (__int64) amountToAdd);
|
||||||
|
#elif JUCE_ATOMICS_GCC
|
||||||
|
return (Type) __sync_add_and_fetch (&value, amountToAdd);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
inline Type Atomic<Type>::operator-= (const Type amountToSubtract) noexcept
|
||||||
|
{
|
||||||
|
return operator+= (negateValue (amountToSubtract));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
inline Type Atomic<Type>::operator++() noexcept
|
||||||
|
{
|
||||||
|
#if JUCE_ATOMICS_MAC_LEGACY
|
||||||
|
return sizeof (Type) == 4 ? (Type) OSAtomicIncrement32Barrier ((JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||||
|
: (Type) OSAtomicIncrement64Barrier ((JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||||
|
#elif JUCE_ATOMICS_WINDOWS
|
||||||
|
return sizeof (Type) == 4 ? (Type) juce_InterlockedIncrement ((volatile long*) &value)
|
||||||
|
: (Type) juce_InterlockedIncrement64 ((volatile __int64*) &value);
|
||||||
|
#elif JUCE_ATOMICS_GCC
|
||||||
|
return sizeof (Type) == 4 ? (Type) __sync_add_and_fetch (&value, (Type) 1)
|
||||||
|
: (Type) __sync_add_and_fetch ((int64_t*) &value, 1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
inline Type Atomic<Type>::operator--() noexcept
|
||||||
|
{
|
||||||
|
#if JUCE_ATOMICS_MAC_LEGACY
|
||||||
|
return sizeof (Type) == 4 ? (Type) OSAtomicDecrement32Barrier ((JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||||
|
: (Type) OSAtomicDecrement64Barrier ((JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||||
|
#elif JUCE_ATOMICS_WINDOWS
|
||||||
|
return sizeof (Type) == 4 ? (Type) juce_InterlockedDecrement ((volatile long*) &value)
|
||||||
|
: (Type) juce_InterlockedDecrement64 ((volatile __int64*) &value);
|
||||||
|
#elif JUCE_ATOMICS_GCC
|
||||||
|
return sizeof (Type) == 4 ? (Type) __sync_add_and_fetch (&value, (Type) -1)
|
||||||
|
: (Type) __sync_add_and_fetch ((int64_t*) &value, -1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
inline bool Atomic<Type>::compareAndSetBool (const Type newValue, const Type valueToCompare) noexcept
|
||||||
|
{
|
||||||
|
#if JUCE_ATOMICS_MAC_LEGACY
|
||||||
|
return sizeof (Type) == 4 ? OSAtomicCompareAndSwap32Barrier ((int32_t) castTo32Bit (valueToCompare), (int32_t) castTo32Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)
|
||||||
|
: OSAtomicCompareAndSwap64Barrier ((int64_t) castTo64Bit (valueToCompare), (int64_t) castTo64Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value);
|
||||||
|
#elif JUCE_ATOMICS_WINDOWS
|
||||||
|
return compareAndSetValue (newValue, valueToCompare) == valueToCompare;
|
||||||
|
#elif JUCE_ATOMICS_GCC
|
||||||
|
return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))
|
||||||
|
: __sync_bool_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
inline Type Atomic<Type>::compareAndSetValue (const Type newValue, const Type valueToCompare) noexcept
|
||||||
|
{
|
||||||
|
#if JUCE_ATOMICS_MAC_LEGACY
|
||||||
|
for (;;) // Annoying workaround for only having a bool CAS operation..
|
||||||
|
{
|
||||||
|
if (compareAndSetBool (newValue, valueToCompare))
|
||||||
|
return valueToCompare;
|
||||||
|
|
||||||
|
const Type result = value;
|
||||||
|
if (result != valueToCompare)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif JUCE_ATOMICS_WINDOWS
|
||||||
|
return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedCompareExchange ((volatile long*) &value, (long) castTo32Bit (newValue), (long) castTo32Bit (valueToCompare)))
|
||||||
|
: castFrom64Bit ((int64) juce_InterlockedCompareExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue), (__int64) castTo64Bit (valueToCompare)));
|
||||||
|
#elif JUCE_ATOMICS_GCC
|
||||||
|
return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_val_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue)))
|
||||||
|
: castFrom64Bit ((int64) __sync_val_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue)));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
inline void Atomic<Type>::memoryBarrier() noexcept
|
||||||
|
{
|
||||||
|
#if JUCE_ATOMICS_MAC_LEGACY
|
||||||
|
OSMemoryBarrier();
|
||||||
|
#elif JUCE_ATOMICS_GCC
|
||||||
|
__sync_synchronize();
|
||||||
|
#elif JUCE_ATOMICS_WINDOWS
|
||||||
|
juce_MemoryBarrier();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JUCE_MSVC
|
||||||
|
#pragma warning (pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // JUCE_ATOMIC_H_INCLUDED
|
||||||
@@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_BYTEORDER_H_INCLUDED
|
||||||
|
#define JUCE_BYTEORDER_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Contains static methods for converting the byte order between different
|
||||||
|
endiannesses.
|
||||||
|
*/
|
||||||
|
class JUCE_API ByteOrder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Swaps the upper and lower bytes of a 16-bit integer. */
|
||||||
|
static uint16 swap (uint16 value) noexcept;
|
||||||
|
|
||||||
|
/** Reverses the order of the 4 bytes in a 32-bit integer. */
|
||||||
|
static uint32 swap (uint32 value) noexcept;
|
||||||
|
|
||||||
|
/** Reverses the order of the 8 bytes in a 64-bit integer. */
|
||||||
|
static uint64 swap (uint64 value) noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Swaps the byte order of a 16-bit int if the CPU is big-endian */
|
||||||
|
static uint16 swapIfBigEndian (uint16 value) noexcept;
|
||||||
|
|
||||||
|
/** Swaps the byte order of a 32-bit int if the CPU is big-endian */
|
||||||
|
static uint32 swapIfBigEndian (uint32 value) noexcept;
|
||||||
|
|
||||||
|
/** Swaps the byte order of a 64-bit int if the CPU is big-endian */
|
||||||
|
static uint64 swapIfBigEndian (uint64 value) noexcept;
|
||||||
|
|
||||||
|
/** Swaps the byte order of a 16-bit int if the CPU is little-endian */
|
||||||
|
static uint16 swapIfLittleEndian (uint16 value) noexcept;
|
||||||
|
|
||||||
|
/** Swaps the byte order of a 32-bit int if the CPU is little-endian */
|
||||||
|
static uint32 swapIfLittleEndian (uint32 value) noexcept;
|
||||||
|
|
||||||
|
/** Swaps the byte order of a 64-bit int if the CPU is little-endian */
|
||||||
|
static uint64 swapIfLittleEndian (uint64 value) noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Turns 4 bytes into a little-endian integer. */
|
||||||
|
static uint32 littleEndianInt (const void* bytes) noexcept;
|
||||||
|
|
||||||
|
/** Turns 8 bytes into a little-endian integer. */
|
||||||
|
static uint64 littleEndianInt64 (const void* bytes) noexcept;
|
||||||
|
|
||||||
|
/** Turns 2 bytes into a little-endian integer. */
|
||||||
|
static uint16 littleEndianShort (const void* bytes) noexcept;
|
||||||
|
|
||||||
|
/** Turns 4 bytes into a big-endian integer. */
|
||||||
|
static uint32 bigEndianInt (const void* bytes) noexcept;
|
||||||
|
|
||||||
|
/** Turns 8 bytes into a big-endian integer. */
|
||||||
|
static uint64 bigEndianInt64 (const void* bytes) noexcept;
|
||||||
|
|
||||||
|
/** Turns 2 bytes into a big-endian integer. */
|
||||||
|
static uint16 bigEndianShort (const void* bytes) noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Converts 3 little-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */
|
||||||
|
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 void* bytes) noexcept;
|
||||||
|
|
||||||
|
/** Copies a 24-bit number to 3 little-endian bytes. */
|
||||||
|
static void littleEndian24BitToChars (int value, void* destBytes) noexcept;
|
||||||
|
|
||||||
|
/** Copies a 24-bit number to 3 big-endian bytes. */
|
||||||
|
static void bigEndian24BitToChars (int value, void* destBytes) noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns true if the current CPU is big-endian. */
|
||||||
|
static bool isBigEndian() noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ByteOrder() JUCE_DELETED_FUNCTION;
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (ByteOrder)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if JUCE_USE_MSVC_INTRINSICS && ! defined (__INTEL_COMPILER)
|
||||||
|
#pragma intrinsic (_byteswap_ulong)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline uint16 ByteOrder::swap (uint16 n) noexcept
|
||||||
|
{
|
||||||
|
#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));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32 ByteOrder::swap (uint32 n) noexcept
|
||||||
|
{
|
||||||
|
#if JUCE_MAC || JUCE_IOS
|
||||||
|
return OSSwapInt32 (n);
|
||||||
|
#elif JUCE_GCC && JUCE_INTEL && ! JUCE_NO_INLINE_ASM
|
||||||
|
asm("bswap %%eax" : "=a"(n) : "a"(n));
|
||||||
|
return n;
|
||||||
|
#elif JUCE_USE_MSVC_INTRINSICS
|
||||||
|
return _byteswap_ulong (n);
|
||||||
|
#elif JUCE_MSVC && ! JUCE_NO_INLINE_ASM
|
||||||
|
__asm {
|
||||||
|
mov eax, n
|
||||||
|
bswap eax
|
||||||
|
mov n, eax
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
#elif JUCE_ANDROID
|
||||||
|
return bswap_32 (n);
|
||||||
|
#else
|
||||||
|
return (n << 24) | (n >> 24) | ((n & 0xff00) << 8) | ((n & 0xff0000) >> 8);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64 ByteOrder::swap (uint64 value) noexcept
|
||||||
|
{
|
||||||
|
#if JUCE_MAC || JUCE_IOS
|
||||||
|
return OSSwapInt64 (value);
|
||||||
|
#elif JUCE_USE_MSVC_INTRINSICS
|
||||||
|
return _byteswap_uint64 (value);
|
||||||
|
#else
|
||||||
|
return (((int64) swap ((uint32) value)) << 32) | swap ((uint32) (value >> 32));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JUCE_LITTLE_ENDIAN
|
||||||
|
inline uint16 ByteOrder::swapIfBigEndian (const uint16 v) noexcept { return v; }
|
||||||
|
inline uint32 ByteOrder::swapIfBigEndian (const uint32 v) noexcept { return v; }
|
||||||
|
inline uint64 ByteOrder::swapIfBigEndian (const uint64 v) noexcept { return v; }
|
||||||
|
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 bool ByteOrder::isBigEndian() noexcept { return false; }
|
||||||
|
#else
|
||||||
|
inline uint16 ByteOrder::swapIfBigEndian (const uint16 v) noexcept { return swap (v); }
|
||||||
|
inline uint32 ByteOrder::swapIfBigEndian (const uint32 v) noexcept { return swap (v); }
|
||||||
|
inline uint64 ByteOrder::swapIfBigEndian (const uint64 v) noexcept { return swap (v); }
|
||||||
|
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 bool ByteOrder::isBigEndian() noexcept { return true; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_CONTAINERDELETEPOLICY_H_INCLUDED
|
||||||
|
#define JUCE_CONTAINERDELETEPOLICY_H_INCLUDED
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Used by container classes as an indirect way to delete an object of a
|
||||||
|
particular type.
|
||||||
|
|
||||||
|
The generic implementation of this class simply calls 'delete', but you can
|
||||||
|
create a specialised version of it for a particular class if you need to
|
||||||
|
delete that type of object in a more appropriate way.
|
||||||
|
|
||||||
|
@see ScopedPointer, OwnedArray
|
||||||
|
*/
|
||||||
|
template <typename ObjectType>
|
||||||
|
struct ContainerDeletePolicy
|
||||||
|
{
|
||||||
|
static void destroy (ObjectType* object)
|
||||||
|
{
|
||||||
|
delete object;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_CONTAINERDELETEPOLICY_H_INCLUDED
|
||||||
@@ -0,0 +1,308 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_HEAPBLOCK_H_INCLUDED
|
||||||
|
#define JUCE_HEAPBLOCK_H_INCLUDED
|
||||||
|
|
||||||
|
#ifndef DOXYGEN
|
||||||
|
namespace HeapBlockHelper
|
||||||
|
{
|
||||||
|
template <bool shouldThrow>
|
||||||
|
struct ThrowOnFail { static void check (void*) {} };
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct ThrowOnFail <true> { static void check (void* data) { if (data == nullptr) throw std::bad_alloc(); } };
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Very simple container class to hold a pointer to some data on the heap.
|
||||||
|
|
||||||
|
When you need to allocate some heap storage for something, always try to use
|
||||||
|
this class instead of allocating the memory directly using malloc/free.
|
||||||
|
|
||||||
|
A HeapBlock<char> object can be treated in pretty much exactly the same way
|
||||||
|
as an char*, but as long as you allocate it on the stack or as a class member,
|
||||||
|
it's almost impossible for it to leak memory.
|
||||||
|
|
||||||
|
It also makes your code much more concise and readable than doing the same thing
|
||||||
|
using direct allocations,
|
||||||
|
|
||||||
|
E.g. instead of this:
|
||||||
|
@code
|
||||||
|
int* temp = (int*) malloc (1024 * sizeof (int));
|
||||||
|
memcpy (temp, xyz, 1024 * sizeof (int));
|
||||||
|
free (temp);
|
||||||
|
temp = (int*) calloc (2048 * sizeof (int));
|
||||||
|
temp[0] = 1234;
|
||||||
|
memcpy (foobar, temp, 2048 * sizeof (int));
|
||||||
|
free (temp);
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
..you could just write this:
|
||||||
|
@code
|
||||||
|
HeapBlock <int> temp (1024);
|
||||||
|
memcpy (temp, xyz, 1024 * sizeof (int));
|
||||||
|
temp.calloc (2048);
|
||||||
|
temp[0] = 1234;
|
||||||
|
memcpy (foobar, temp, 2048 * sizeof (int));
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
The class is extremely lightweight, containing only a pointer to the
|
||||||
|
data, and exposes malloc/realloc/calloc/free methods that do the same jobs
|
||||||
|
as their less object-oriented counterparts. Despite adding safety, you probably
|
||||||
|
won't sacrifice any performance by using this in place of normal pointers.
|
||||||
|
|
||||||
|
The throwOnFailure template parameter can be set to true if you'd like the class
|
||||||
|
to throw a std::bad_alloc exception when an allocation fails. If this is false,
|
||||||
|
then a failed allocation will just leave the heapblock with a null pointer (assuming
|
||||||
|
that the system's malloc() function doesn't throw).
|
||||||
|
|
||||||
|
@see Array, OwnedArray, MemoryBlock
|
||||||
|
*/
|
||||||
|
template <class ElementType, bool throwOnFailure = false>
|
||||||
|
class HeapBlock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a HeapBlock which is initially just a null pointer.
|
||||||
|
|
||||||
|
After creation, you can resize the array using the malloc(), calloc(),
|
||||||
|
or realloc() methods.
|
||||||
|
*/
|
||||||
|
HeapBlock() noexcept : data (nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a HeapBlock containing a number of elements.
|
||||||
|
|
||||||
|
The contents of the block are undefined, as it will have been created by a
|
||||||
|
malloc call.
|
||||||
|
|
||||||
|
If you want an array of zero values, you can use the calloc() method or the
|
||||||
|
other constructor that takes an InitialisationState parameter.
|
||||||
|
*/
|
||||||
|
explicit HeapBlock (const size_t numElements)
|
||||||
|
: data (static_cast <ElementType*> (std::malloc (numElements * sizeof (ElementType))))
|
||||||
|
{
|
||||||
|
throwOnAllocationFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a HeapBlock containing a number of elements.
|
||||||
|
|
||||||
|
The initialiseToZero parameter determines whether the new memory should be cleared,
|
||||||
|
or left uninitialised.
|
||||||
|
*/
|
||||||
|
HeapBlock (const size_t numElements, const bool initialiseToZero)
|
||||||
|
: data (static_cast <ElementType*> (initialiseToZero
|
||||||
|
? std::calloc (numElements, sizeof (ElementType))
|
||||||
|
: std::malloc (numElements * sizeof (ElementType))))
|
||||||
|
{
|
||||||
|
throwOnAllocationFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Destructor.
|
||||||
|
This will free the data, if any has been allocated.
|
||||||
|
*/
|
||||||
|
~HeapBlock()
|
||||||
|
{
|
||||||
|
std::free (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
HeapBlock (HeapBlock&& other) noexcept
|
||||||
|
: data (other.data)
|
||||||
|
{
|
||||||
|
other.data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HeapBlock& operator= (HeapBlock&& other) noexcept
|
||||||
|
{
|
||||||
|
std::swap (data, other.data);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a raw pointer to the allocated data.
|
||||||
|
This may be a null pointer if the data hasn't yet been allocated, or if it has been
|
||||||
|
freed by calling the free() method.
|
||||||
|
*/
|
||||||
|
inline operator ElementType*() const noexcept { return data; }
|
||||||
|
|
||||||
|
/** Returns a raw pointer to the allocated data.
|
||||||
|
This may be a null pointer if the data hasn't yet been allocated, or if it has been
|
||||||
|
freed by calling the free() method.
|
||||||
|
*/
|
||||||
|
inline ElementType* getData() const noexcept { return data; }
|
||||||
|
|
||||||
|
/** Returns a void pointer to the allocated data.
|
||||||
|
This may be a null pointer if the data hasn't yet been allocated, or if it has been
|
||||||
|
freed by calling the free() method.
|
||||||
|
*/
|
||||||
|
inline operator void*() const noexcept { return static_cast <void*> (data); }
|
||||||
|
|
||||||
|
/** Returns a void pointer to the allocated data.
|
||||||
|
This may be a null pointer if the data hasn't yet been allocated, or if it has been
|
||||||
|
freed by calling the free() method.
|
||||||
|
*/
|
||||||
|
inline operator const void*() const noexcept { return static_cast <const void*> (data); }
|
||||||
|
|
||||||
|
/** Lets you use indirect calls to the first element in the array.
|
||||||
|
Obviously this will cause problems if the array hasn't been initialised, because it'll
|
||||||
|
be referencing a null pointer.
|
||||||
|
*/
|
||||||
|
inline ElementType* operator->() const noexcept { return data; }
|
||||||
|
|
||||||
|
/** Returns a reference to one of the data elements.
|
||||||
|
Obviously there's no bounds-checking here, as this object is just a dumb pointer and
|
||||||
|
has no idea of the size it currently has allocated.
|
||||||
|
*/
|
||||||
|
template <typename IndexType>
|
||||||
|
inline ElementType& operator[] (IndexType index) const noexcept { return data [index]; }
|
||||||
|
|
||||||
|
/** Returns a pointer to a data element at an offset from the start of the array.
|
||||||
|
This is the same as doing pointer arithmetic on the raw pointer itself.
|
||||||
|
*/
|
||||||
|
template <typename IndexType>
|
||||||
|
inline ElementType* operator+ (IndexType index) const noexcept { return data + index; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Compares the pointer with another pointer.
|
||||||
|
This can be handy for checking whether this is a null pointer.
|
||||||
|
*/
|
||||||
|
inline bool operator== (const ElementType* const otherPointer) const noexcept { return otherPointer == data; }
|
||||||
|
|
||||||
|
/** Compares the pointer with another pointer.
|
||||||
|
This can be handy for checking whether this is a null pointer.
|
||||||
|
*/
|
||||||
|
inline bool operator!= (const ElementType* const otherPointer) const noexcept { return otherPointer != data; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Allocates a specified amount of memory.
|
||||||
|
|
||||||
|
This uses the normal malloc to allocate an amount of memory for this object.
|
||||||
|
Any previously allocated memory will be freed by this method.
|
||||||
|
|
||||||
|
The number of bytes allocated will be (newNumElements * elementSize). Normally
|
||||||
|
you wouldn't need to specify the second parameter, but it can be handy if you need
|
||||||
|
to allocate a size in bytes rather than in terms of the number of elements.
|
||||||
|
|
||||||
|
The data that is allocated will be freed when this object is deleted, or when you
|
||||||
|
call free() or any of the allocation methods.
|
||||||
|
*/
|
||||||
|
void malloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType))
|
||||||
|
{
|
||||||
|
std::free (data);
|
||||||
|
data = static_cast <ElementType*> (std::malloc (newNumElements * elementSize));
|
||||||
|
throwOnAllocationFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Allocates a specified amount of memory and clears it.
|
||||||
|
This does the same job as the malloc() method, but clears the memory that it allocates.
|
||||||
|
*/
|
||||||
|
void calloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType))
|
||||||
|
{
|
||||||
|
std::free (data);
|
||||||
|
data = static_cast <ElementType*> (std::calloc (newNumElements, elementSize));
|
||||||
|
throwOnAllocationFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Allocates a specified amount of memory and optionally clears it.
|
||||||
|
This does the same job as either malloc() or calloc(), depending on the
|
||||||
|
initialiseToZero parameter.
|
||||||
|
*/
|
||||||
|
void allocate (const size_t newNumElements, bool initialiseToZero)
|
||||||
|
{
|
||||||
|
std::free (data);
|
||||||
|
data = static_cast <ElementType*> (initialiseToZero
|
||||||
|
? std::calloc (newNumElements, sizeof (ElementType))
|
||||||
|
: std::malloc (newNumElements * sizeof (ElementType)));
|
||||||
|
throwOnAllocationFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Re-allocates a specified amount of memory.
|
||||||
|
|
||||||
|
The semantics of this method are the same as malloc() and calloc(), but it
|
||||||
|
uses realloc() to keep as much of the existing data as possible.
|
||||||
|
*/
|
||||||
|
void realloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType))
|
||||||
|
{
|
||||||
|
data = static_cast <ElementType*> (data == nullptr ? std::malloc (newNumElements * elementSize)
|
||||||
|
: std::realloc (data, newNumElements * elementSize));
|
||||||
|
throwOnAllocationFailure();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Frees any currently-allocated data.
|
||||||
|
This will free the data and reset this object to be a null pointer.
|
||||||
|
*/
|
||||||
|
void free()
|
||||||
|
{
|
||||||
|
std::free (data);
|
||||||
|
data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Swaps this object's data with the data of another HeapBlock.
|
||||||
|
The two objects simply exchange their data pointers.
|
||||||
|
*/
|
||||||
|
template <bool otherBlockThrows>
|
||||||
|
void swapWith (HeapBlock <ElementType, otherBlockThrows>& other) noexcept
|
||||||
|
{
|
||||||
|
std::swap (data, other.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This fills the block with zeros, up to the number of elements specified.
|
||||||
|
Since the block has no way of knowing its own size, you must make sure that the number of
|
||||||
|
elements you specify doesn't exceed the allocated size.
|
||||||
|
*/
|
||||||
|
void clear (size_t numElements) noexcept
|
||||||
|
{
|
||||||
|
zeromem (data, sizeof (ElementType) * numElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** This typedef can be used to get the type of the heapblock's elements. */
|
||||||
|
typedef ElementType Type;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
ElementType* data;
|
||||||
|
|
||||||
|
void throwOnAllocationFailure() const
|
||||||
|
{
|
||||||
|
HeapBlockHelper::ThrowOnFail<throwOnFailure>::check (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if ! (defined (JUCE_DLL) || defined (JUCE_DLL_BUILD))
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (HeapBlock)
|
||||||
|
JUCE_PREVENT_HEAP_ALLOCATION // Creating a 'new HeapBlock' would be missing the point!
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_HEAPBLOCK_H_INCLUDED
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_LEAKEDOBJECTDETECTOR_H_INCLUDED
|
||||||
|
#define JUCE_LEAKEDOBJECTDETECTOR_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Embedding an instance of this class inside another class can be used as a low-overhead
|
||||||
|
way of detecting leaked instances.
|
||||||
|
|
||||||
|
This class keeps an internal static count of the number of instances that are
|
||||||
|
active, so that when the app is shutdown and the static destructors are called,
|
||||||
|
it can check whether there are any left-over instances that may have been leaked.
|
||||||
|
|
||||||
|
To use it, use the JUCE_LEAK_DETECTOR macro as a simple way to put one in your
|
||||||
|
class declaration. Have a look through the juce codebase for examples, it's used
|
||||||
|
in most of the classes.
|
||||||
|
*/
|
||||||
|
template <class OwnerClass>
|
||||||
|
class LeakedObjectDetector
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
LeakedObjectDetector() noexcept { ++(getCounter().numObjects); }
|
||||||
|
LeakedObjectDetector (const LeakedObjectDetector&) noexcept { ++(getCounter().numObjects); }
|
||||||
|
|
||||||
|
~LeakedObjectDetector()
|
||||||
|
{
|
||||||
|
if (--(getCounter().numObjects) < 0)
|
||||||
|
{
|
||||||
|
DBG ("*** Dangling pointer deletion! Class: " << getLeakedObjectClassName());
|
||||||
|
|
||||||
|
/** If you hit this, then you've managed to delete more instances of this class than you've
|
||||||
|
created.. That indicates that you're deleting some dangling pointers.
|
||||||
|
|
||||||
|
Note that although this assertion will have been triggered during a destructor, it might
|
||||||
|
not be this particular deletion that's at fault - the incorrect one may have happened
|
||||||
|
at an earlier point in the program, and simply not been detected until now.
|
||||||
|
|
||||||
|
Most errors like this are caused by using old-fashioned, non-RAII techniques for
|
||||||
|
your object management. Tut, tut. Always, always use ScopedPointers, OwnedArrays,
|
||||||
|
ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs!
|
||||||
|
*/
|
||||||
|
jassertfalse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
class LeakCounter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LeakCounter() noexcept {}
|
||||||
|
|
||||||
|
~LeakCounter()
|
||||||
|
{
|
||||||
|
if (numObjects.value > 0)
|
||||||
|
{
|
||||||
|
DBG ("*** Leaked objects detected: " << numObjects.value << " instance(s) of class " << getLeakedObjectClassName());
|
||||||
|
|
||||||
|
/** If you hit this, then you've leaked one or more objects of the type specified by
|
||||||
|
the 'OwnerClass' template parameter - the name should have been printed by the line above.
|
||||||
|
|
||||||
|
If you're leaking, it's probably because you're using old-fashioned, non-RAII techniques for
|
||||||
|
your object management. Tut, tut. Always, always use ScopedPointers, OwnedArrays,
|
||||||
|
ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs!
|
||||||
|
*/
|
||||||
|
jassertfalse;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Atomic<int> numObjects;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char* getLeakedObjectClassName()
|
||||||
|
{
|
||||||
|
return OwnerClass::getLeakedObjectClassName();
|
||||||
|
}
|
||||||
|
|
||||||
|
static LeakCounter& getCounter() noexcept
|
||||||
|
{
|
||||||
|
static LeakCounter counter;
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if DOXYGEN || ! defined (JUCE_LEAK_DETECTOR)
|
||||||
|
#if (DOXYGEN || JUCE_CHECK_MEMORY_LEAKS)
|
||||||
|
/** This macro lets you embed a leak-detecting object inside a class.
|
||||||
|
|
||||||
|
To use it, simply declare a JUCE_LEAK_DETECTOR(YourClassName) inside a private section
|
||||||
|
of the class declaration. E.g.
|
||||||
|
|
||||||
|
@code
|
||||||
|
class MyClass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MyClass();
|
||||||
|
void blahBlah();
|
||||||
|
|
||||||
|
private:
|
||||||
|
JUCE_LEAK_DETECTOR (MyClass)
|
||||||
|
};
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@see JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR, LeakedObjectDetector
|
||||||
|
*/
|
||||||
|
#define JUCE_LEAK_DETECTOR(OwnerClass) \
|
||||||
|
friend class juce::LeakedObjectDetector<OwnerClass>; \
|
||||||
|
static const char* getLeakedObjectClassName() noexcept { return #OwnerClass; } \
|
||||||
|
juce::LeakedObjectDetector<OwnerClass> JUCE_JOIN_MACRO (leakDetector, __LINE__);
|
||||||
|
#else
|
||||||
|
#define JUCE_LEAK_DETECTOR(OwnerClass)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_LEAKEDOBJECTDETECTOR_H_INCLUDED
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_MEMORY_H_INCLUDED
|
||||||
|
#define JUCE_MEMORY_H_INCLUDED
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Fills a block of memory with zeros. */
|
||||||
|
inline void zeromem (void* memory, size_t numBytes) noexcept { memset (memory, 0, numBytes); }
|
||||||
|
|
||||||
|
/** Overwrites a structure or object with zeros. */
|
||||||
|
template <typename Type>
|
||||||
|
inline void zerostruct (Type& structure) noexcept { memset (&structure, 0, sizeof (structure)); }
|
||||||
|
|
||||||
|
/** Delete an object pointer, and sets the pointer to null.
|
||||||
|
|
||||||
|
Remember that it's not good c++ practice to use delete directly - always try to use a ScopedPointer
|
||||||
|
or other automatic lifetime-management system rather than resorting to deleting raw pointers!
|
||||||
|
*/
|
||||||
|
template <typename Type>
|
||||||
|
inline void deleteAndZero (Type& pointer) { delete pointer; pointer = nullptr; }
|
||||||
|
|
||||||
|
/** A handy function which adds a number of bytes to any type of pointer and returns the result.
|
||||||
|
This can be useful to avoid casting pointers to a char* and back when you want to move them by
|
||||||
|
a specific number of bytes,
|
||||||
|
*/
|
||||||
|
template <typename Type, typename IntegerType>
|
||||||
|
inline Type* addBytesToPointer (Type* pointer, IntegerType bytes) noexcept { return (Type*) (((char*) pointer) + bytes); }
|
||||||
|
|
||||||
|
/** A handy function which returns the difference between any two pointers, in bytes.
|
||||||
|
The address of the second pointer is subtracted from the first, and the difference in bytes is returned.
|
||||||
|
*/
|
||||||
|
template <typename Type1, typename Type2>
|
||||||
|
inline int getAddressDifference (Type1* pointer1, Type2* pointer2) noexcept { return (int) (((const char*) pointer1) - (const char*) pointer2); }
|
||||||
|
|
||||||
|
/** If a pointer is non-null, this returns a new copy of the object that it points to, or safely returns
|
||||||
|
nullptr if the pointer is null.
|
||||||
|
*/
|
||||||
|
template <class Type>
|
||||||
|
inline Type* createCopyIfNotNull (const Type* pointer) { return pointer != nullptr ? new Type (*pointer) : nullptr; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if JUCE_MAC || JUCE_IOS || DOXYGEN
|
||||||
|
|
||||||
|
/** A handy C++ wrapper that creates and deletes an NSAutoreleasePool object using RAII.
|
||||||
|
You should use the JUCE_AUTORELEASEPOOL macro to create a local auto-release pool on the stack.
|
||||||
|
*/
|
||||||
|
class JUCE_API ScopedAutoReleasePool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ScopedAutoReleasePool();
|
||||||
|
~ScopedAutoReleasePool();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void* pool;
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (ScopedAutoReleasePool)
|
||||||
|
};
|
||||||
|
|
||||||
|
/** A macro that can be used to easily declare a local ScopedAutoReleasePool
|
||||||
|
object for RAII-based obj-C autoreleasing.
|
||||||
|
Because this may use the \@autoreleasepool syntax, you must follow the macro with
|
||||||
|
a set of braces to mark the scope of the pool.
|
||||||
|
*/
|
||||||
|
#if (JUCE_COMPILER_SUPPORTS_ARC && defined (__OBJC__)) || DOXYGEN
|
||||||
|
#define JUCE_AUTORELEASEPOOL @autoreleasepool
|
||||||
|
#else
|
||||||
|
#define JUCE_AUTORELEASEPOOL const juce::ScopedAutoReleasePool JUCE_JOIN_MACRO (autoReleasePool_, __LINE__);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define JUCE_AUTORELEASEPOOL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/* In a Windows DLL build, we'll expose some malloc/free functions that live inside the DLL, and use these for
|
||||||
|
allocating all the objects - that way all juce objects in the DLL and in the host will live in the same heap,
|
||||||
|
avoiding problems when an object is created in one module and passed across to another where it is deleted.
|
||||||
|
By piggy-backing on the JUCE_LEAK_DETECTOR macro, these allocators can be injected into most juce classes.
|
||||||
|
*/
|
||||||
|
#if JUCE_MSVC && (defined (JUCE_DLL) || defined (JUCE_DLL_BUILD)) && ! (JUCE_DISABLE_DLL_ALLOCATORS || DOXYGEN)
|
||||||
|
extern JUCE_API void* juceDLL_malloc (size_t);
|
||||||
|
extern JUCE_API void juceDLL_free (void*);
|
||||||
|
|
||||||
|
#define JUCE_LEAK_DETECTOR(OwnerClass) public:\
|
||||||
|
static void* operator new (size_t sz) { return juce::juceDLL_malloc (sz); } \
|
||||||
|
static void* operator new (size_t, void* p) { return p; } \
|
||||||
|
static void operator delete (void* p) { juce::juceDLL_free (p); } \
|
||||||
|
static void operator delete (void*, void*) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** (Deprecated) This was a Windows-specific way of checking for object leaks - now please
|
||||||
|
use the JUCE_LEAK_DETECTOR instead.
|
||||||
|
*/
|
||||||
|
#ifndef juce_UseDebuggingNewOperator
|
||||||
|
#define juce_UseDebuggingNewOperator
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_MEMORY_H_INCLUDED
|
||||||
@@ -0,0 +1,416 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
MemoryBlock::MemoryBlock() noexcept
|
||||||
|
: size (0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock::MemoryBlock (const size_t initialSize, const bool initialiseToZero)
|
||||||
|
{
|
||||||
|
if (initialSize > 0)
|
||||||
|
{
|
||||||
|
size = initialSize;
|
||||||
|
data.allocate (initialSize, initialiseToZero);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock::MemoryBlock (const MemoryBlock& other)
|
||||||
|
: size (other.size)
|
||||||
|
{
|
||||||
|
if (size > 0)
|
||||||
|
{
|
||||||
|
jassert (other.data != nullptr);
|
||||||
|
data.malloc (size);
|
||||||
|
memcpy (data, other.data, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock::MemoryBlock (const void* const dataToInitialiseFrom, const size_t sizeInBytes)
|
||||||
|
: size (sizeInBytes)
|
||||||
|
{
|
||||||
|
jassert (((ssize_t) sizeInBytes) >= 0);
|
||||||
|
|
||||||
|
if (size > 0)
|
||||||
|
{
|
||||||
|
jassert (dataToInitialiseFrom != nullptr); // non-zero size, but a zero pointer passed-in?
|
||||||
|
|
||||||
|
data.malloc (size);
|
||||||
|
|
||||||
|
if (dataToInitialiseFrom != nullptr)
|
||||||
|
memcpy (data, dataToInitialiseFrom, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock::~MemoryBlock() noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock& MemoryBlock::operator= (const MemoryBlock& other)
|
||||||
|
{
|
||||||
|
if (this != &other)
|
||||||
|
{
|
||||||
|
setSize (other.size, false);
|
||||||
|
memcpy (data, other.data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
MemoryBlock::MemoryBlock (MemoryBlock&& other) noexcept
|
||||||
|
: data (static_cast<HeapBlock<char>&&> (other.data)),
|
||||||
|
size (other.size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlock& MemoryBlock::operator= (MemoryBlock&& other) noexcept
|
||||||
|
{
|
||||||
|
data = static_cast<HeapBlock<char>&&> (other.data);
|
||||||
|
size = other.size;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool MemoryBlock::operator== (const MemoryBlock& other) const noexcept
|
||||||
|
{
|
||||||
|
return matches (other.data, other.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemoryBlock::operator!= (const MemoryBlock& other) const noexcept
|
||||||
|
{
|
||||||
|
return ! operator== (other);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemoryBlock::matches (const void* dataToCompare, size_t dataSize) const noexcept
|
||||||
|
{
|
||||||
|
return size == dataSize
|
||||||
|
&& memcmp (data, dataToCompare, size) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// this will resize the block to this size
|
||||||
|
void MemoryBlock::setSize (const size_t newSize, const bool initialiseToZero)
|
||||||
|
{
|
||||||
|
if (size != newSize)
|
||||||
|
{
|
||||||
|
if (newSize <= 0)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (data != nullptr)
|
||||||
|
{
|
||||||
|
data.realloc (newSize);
|
||||||
|
|
||||||
|
if (initialiseToZero && (newSize > size))
|
||||||
|
zeromem (data + size, newSize - size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.allocate (newSize, initialiseToZero);
|
||||||
|
}
|
||||||
|
|
||||||
|
size = newSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::reset()
|
||||||
|
{
|
||||||
|
data.free();
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::ensureSize (const size_t minimumSize, const bool initialiseToZero)
|
||||||
|
{
|
||||||
|
if (size < minimumSize)
|
||||||
|
setSize (minimumSize, initialiseToZero);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::swapWith (MemoryBlock& other) noexcept
|
||||||
|
{
|
||||||
|
std::swap (size, other.size);
|
||||||
|
data.swapWith (other.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void MemoryBlock::fillWith (const uint8 value) noexcept
|
||||||
|
{
|
||||||
|
memset (data, (int) value, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::append (const void* const srcData, const size_t numBytes)
|
||||||
|
{
|
||||||
|
if (numBytes > 0)
|
||||||
|
{
|
||||||
|
jassert (srcData != nullptr); // this must not be null!
|
||||||
|
const size_t oldSize = size;
|
||||||
|
setSize (size + numBytes);
|
||||||
|
memcpy (data + oldSize, srcData, numBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::replaceWith (const void* const srcData, const size_t numBytes)
|
||||||
|
{
|
||||||
|
if (numBytes > 0)
|
||||||
|
{
|
||||||
|
jassert (srcData != nullptr); // this must not be null!
|
||||||
|
setSize (numBytes);
|
||||||
|
memcpy (data, srcData, numBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::insert (const void* const srcData, const size_t numBytes, size_t insertPosition)
|
||||||
|
{
|
||||||
|
if (numBytes > 0)
|
||||||
|
{
|
||||||
|
jassert (srcData != nullptr); // this must not be null!
|
||||||
|
insertPosition = jmin (size, insertPosition);
|
||||||
|
const size_t trailingDataSize = size - insertPosition;
|
||||||
|
setSize (size + numBytes, false);
|
||||||
|
|
||||||
|
if (trailingDataSize > 0)
|
||||||
|
memmove (data + insertPosition + numBytes,
|
||||||
|
data + insertPosition,
|
||||||
|
trailingDataSize);
|
||||||
|
|
||||||
|
memcpy (data + insertPosition, srcData, numBytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::removeSection (const size_t startByte, const size_t numBytesToRemove)
|
||||||
|
{
|
||||||
|
if (startByte + numBytesToRemove >= size)
|
||||||
|
{
|
||||||
|
setSize (startByte);
|
||||||
|
}
|
||||||
|
else if (numBytesToRemove > 0)
|
||||||
|
{
|
||||||
|
memmove (data + startByte,
|
||||||
|
data + startByte + numBytesToRemove,
|
||||||
|
size - (startByte + numBytesToRemove));
|
||||||
|
|
||||||
|
setSize (size - numBytesToRemove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::copyFrom (const void* const src, int offset, size_t num) noexcept
|
||||||
|
{
|
||||||
|
const char* d = static_cast<const char*> (src);
|
||||||
|
|
||||||
|
if (offset < 0)
|
||||||
|
{
|
||||||
|
d -= offset;
|
||||||
|
num += (size_t) -offset;
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((size_t) offset + num > size)
|
||||||
|
num = size - (size_t) offset;
|
||||||
|
|
||||||
|
if (num > 0)
|
||||||
|
memcpy (data + offset, d, num);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::copyTo (void* const dst, int offset, size_t num) const noexcept
|
||||||
|
{
|
||||||
|
char* d = static_cast<char*> (dst);
|
||||||
|
|
||||||
|
if (offset < 0)
|
||||||
|
{
|
||||||
|
zeromem (d, (size_t) -offset);
|
||||||
|
d -= offset;
|
||||||
|
num -= (size_t) -offset;
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((size_t) offset + num > size)
|
||||||
|
{
|
||||||
|
const size_t newNum = size - (size_t) offset;
|
||||||
|
zeromem (d + newNum, num - newNum);
|
||||||
|
num = newNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num > 0)
|
||||||
|
memcpy (d, data + offset, num);
|
||||||
|
}
|
||||||
|
|
||||||
|
String MemoryBlock::toString() const
|
||||||
|
{
|
||||||
|
return String::fromUTF8 (data, (int) size);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
int MemoryBlock::getBitRange (const size_t bitRangeStart, size_t numBits) const noexcept
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
size_t byte = bitRangeStart >> 3;
|
||||||
|
size_t offsetInByte = bitRangeStart & 7;
|
||||||
|
size_t bitsSoFar = 0;
|
||||||
|
|
||||||
|
while (numBits > 0 && (size_t) byte < size)
|
||||||
|
{
|
||||||
|
const size_t bitsThisTime = jmin (numBits, 8 - offsetInByte);
|
||||||
|
const int mask = (0xff >> (8 - bitsThisTime)) << offsetInByte;
|
||||||
|
|
||||||
|
res |= (((data[byte] & mask) >> offsetInByte) << bitsSoFar);
|
||||||
|
|
||||||
|
bitsSoFar += bitsThisTime;
|
||||||
|
numBits -= bitsThisTime;
|
||||||
|
++byte;
|
||||||
|
offsetInByte = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBlock::setBitRange (const size_t bitRangeStart, size_t numBits, int bitsToSet) noexcept
|
||||||
|
{
|
||||||
|
size_t byte = bitRangeStart >> 3;
|
||||||
|
size_t offsetInByte = bitRangeStart & 7;
|
||||||
|
uint32 mask = ~((((uint32) 0xffffffff) << (32 - numBits)) >> (32 - numBits));
|
||||||
|
|
||||||
|
while (numBits > 0 && (size_t) byte < size)
|
||||||
|
{
|
||||||
|
const size_t bitsThisTime = jmin (numBits, 8 - offsetInByte);
|
||||||
|
|
||||||
|
const uint32 tempMask = (mask << offsetInByte) | ~((((uint32) 0xffffffff) >> offsetInByte) << offsetInByte);
|
||||||
|
const uint32 tempBits = (uint32) bitsToSet << offsetInByte;
|
||||||
|
|
||||||
|
data[byte] = (char) (((uint32) data[byte] & tempMask) | tempBits);
|
||||||
|
|
||||||
|
++byte;
|
||||||
|
numBits -= bitsThisTime;
|
||||||
|
bitsToSet >>= bitsThisTime;
|
||||||
|
mask >>= bitsThisTime;
|
||||||
|
offsetInByte = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void MemoryBlock::loadFromHexString (StringRef hex)
|
||||||
|
{
|
||||||
|
ensureSize ((size_t) hex.length() >> 1);
|
||||||
|
char* dest = data;
|
||||||
|
String::CharPointerType t (hex.text);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
int byte = 0;
|
||||||
|
|
||||||
|
for (int loop = 2; --loop >= 0;)
|
||||||
|
{
|
||||||
|
byte <<= 4;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
const juce_wchar c = t.getAndAdvance();
|
||||||
|
|
||||||
|
if (c >= '0' && c <= '9') { byte |= c - '0'; break; }
|
||||||
|
if (c >= 'a' && c <= 'z') { byte |= c - ('a' - 10); break; }
|
||||||
|
if (c >= 'A' && c <= 'Z') { byte |= c - ('A' - 10); break; }
|
||||||
|
|
||||||
|
if (c == 0)
|
||||||
|
{
|
||||||
|
setSize (static_cast<size_t> (dest - data));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*dest++ = (char) byte;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
static const char base64EncodingTable[] = ".ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+";
|
||||||
|
|
||||||
|
String MemoryBlock::toBase64Encoding() const
|
||||||
|
{
|
||||||
|
const size_t numChars = ((size << 3) + 5) / 6;
|
||||||
|
|
||||||
|
String destString ((unsigned int) size); // store the length, followed by a '.', and then the data.
|
||||||
|
const int initialLen = destString.length();
|
||||||
|
destString.preallocateBytes (sizeof (String::CharPointerType::CharType) * (size_t) initialLen + 2 + numChars);
|
||||||
|
|
||||||
|
String::CharPointerType d (destString.getCharPointer());
|
||||||
|
d += initialLen;
|
||||||
|
d.write ('.');
|
||||||
|
|
||||||
|
for (size_t i = 0; i < numChars; ++i)
|
||||||
|
d.write ((juce_wchar) (uint8) base64EncodingTable [getBitRange (i * 6, 6)]);
|
||||||
|
|
||||||
|
d.writeNull();
|
||||||
|
return destString;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char base64DecodingTable[] =
|
||||||
|
{
|
||||||
|
63, 0, 0, 0, 0, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
|
||||||
|
0, 0, 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52
|
||||||
|
};
|
||||||
|
|
||||||
|
bool MemoryBlock::fromBase64Encoding (StringRef s)
|
||||||
|
{
|
||||||
|
String::CharPointerType dot (CharacterFunctions::find (s.text, (juce_wchar) '.'));
|
||||||
|
|
||||||
|
if (dot.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const int numBytesNeeded = String (s.text, dot).getIntValue();
|
||||||
|
|
||||||
|
setSize ((size_t) numBytesNeeded, true);
|
||||||
|
|
||||||
|
String::CharPointerType srcChars (dot + 1);
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
int c = (int) srcChars.getAndAdvance();
|
||||||
|
|
||||||
|
if (c == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
c -= 43;
|
||||||
|
if (isPositiveAndBelow (c, numElementsInArray (base64DecodingTable)))
|
||||||
|
{
|
||||||
|
setBitRange ((size_t) pos, 6, base64DecodingTable [c]);
|
||||||
|
pos += 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,253 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_MEMORYBLOCK_H_INCLUDED
|
||||||
|
#define JUCE_MEMORYBLOCK_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A class to hold a resizable block of raw data.
|
||||||
|
|
||||||
|
*/
|
||||||
|
class JUCE_API MemoryBlock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Create an uninitialised block with 0 size. */
|
||||||
|
MemoryBlock() noexcept;
|
||||||
|
|
||||||
|
/** Creates a memory block with a given initial size.
|
||||||
|
|
||||||
|
@param initialSize the size of block to create
|
||||||
|
@param initialiseToZero whether to clear the memory or just leave it uninitialised
|
||||||
|
*/
|
||||||
|
MemoryBlock (const size_t initialSize,
|
||||||
|
bool initialiseToZero = false);
|
||||||
|
|
||||||
|
/** Creates a copy of another memory block. */
|
||||||
|
MemoryBlock (const MemoryBlock&);
|
||||||
|
|
||||||
|
/** Creates a memory block using a copy of a block of data.
|
||||||
|
|
||||||
|
@param dataToInitialiseFrom some data to copy into this block
|
||||||
|
@param sizeInBytes how much space to use
|
||||||
|
*/
|
||||||
|
MemoryBlock (const void* dataToInitialiseFrom, size_t sizeInBytes);
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~MemoryBlock() noexcept;
|
||||||
|
|
||||||
|
/** Copies another memory block onto this one.
|
||||||
|
This block will be resized and copied to exactly match the other one.
|
||||||
|
*/
|
||||||
|
MemoryBlock& operator= (const MemoryBlock&);
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
MemoryBlock (MemoryBlock&&) noexcept;
|
||||||
|
MemoryBlock& operator= (MemoryBlock&&) noexcept;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Compares two memory blocks.
|
||||||
|
@returns true only if the two blocks are the same size and have identical contents.
|
||||||
|
*/
|
||||||
|
bool operator== (const MemoryBlock& other) const noexcept;
|
||||||
|
|
||||||
|
/** Compares two memory blocks.
|
||||||
|
@returns true if the two blocks are different sizes or have different contents.
|
||||||
|
*/
|
||||||
|
bool operator!= (const MemoryBlock& other) const noexcept;
|
||||||
|
|
||||||
|
/** Returns true if the data in this MemoryBlock matches the raw bytes passed-in. */
|
||||||
|
bool matches (const void* data, size_t dataSize) const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a void pointer to the data.
|
||||||
|
|
||||||
|
Note that the pointer returned will probably become invalid when the
|
||||||
|
block is resized.
|
||||||
|
*/
|
||||||
|
void* getData() const noexcept { return data; }
|
||||||
|
|
||||||
|
/** Returns a byte from the memory block.
|
||||||
|
This returns a reference, so you can also use it to set a byte.
|
||||||
|
*/
|
||||||
|
template <typename Type>
|
||||||
|
char& operator[] (const Type offset) const noexcept { return data [offset]; }
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the block's current allocated size, in bytes. */
|
||||||
|
size_t getSize() const noexcept { return size; }
|
||||||
|
|
||||||
|
/** Resizes the memory block.
|
||||||
|
|
||||||
|
Any data that is present in both the old and new sizes will be retained.
|
||||||
|
When enlarging the block, the new space that is allocated at the end can either be
|
||||||
|
cleared, or left uninitialised.
|
||||||
|
|
||||||
|
@param newSize the new desired size for the block
|
||||||
|
@param initialiseNewSpaceToZero if the block gets enlarged, this determines
|
||||||
|
whether to clear the new section or just leave it
|
||||||
|
uninitialised
|
||||||
|
@see ensureSize
|
||||||
|
*/
|
||||||
|
void setSize (const size_t newSize,
|
||||||
|
bool initialiseNewSpaceToZero = false);
|
||||||
|
|
||||||
|
/** Increases the block's size only if it's smaller than a given size.
|
||||||
|
|
||||||
|
@param minimumSize if the block is already bigger than this size, no action
|
||||||
|
will be taken; otherwise it will be increased to this size
|
||||||
|
@param initialiseNewSpaceToZero if the block gets enlarged, this determines
|
||||||
|
whether to clear the new section or just leave it
|
||||||
|
uninitialised
|
||||||
|
@see setSize
|
||||||
|
*/
|
||||||
|
void ensureSize (const size_t minimumSize,
|
||||||
|
bool initialiseNewSpaceToZero = false);
|
||||||
|
|
||||||
|
/** Frees all the blocks data, setting its size to 0. */
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Fills the entire memory block with a repeated byte value.
|
||||||
|
This is handy for clearing a block of memory to zero.
|
||||||
|
*/
|
||||||
|
void fillWith (uint8 valueToUse) noexcept;
|
||||||
|
|
||||||
|
/** Adds another block of data to the end of this one.
|
||||||
|
The data pointer must not be null. This block's size will be increased accordingly.
|
||||||
|
*/
|
||||||
|
void append (const void* data, size_t numBytes);
|
||||||
|
|
||||||
|
/** Resizes this block to the given size and fills its contents from the supplied buffer.
|
||||||
|
The data pointer must not be null.
|
||||||
|
*/
|
||||||
|
void replaceWith (const void* data, size_t numBytes);
|
||||||
|
|
||||||
|
/** Inserts some data into the block.
|
||||||
|
The dataToInsert pointer must not be null. This block's size will be increased accordingly.
|
||||||
|
If the insert position lies outside the valid range of the block, it will be clipped to
|
||||||
|
within the range before being used.
|
||||||
|
*/
|
||||||
|
void insert (const void* dataToInsert, size_t numBytesToInsert, size_t insertPosition);
|
||||||
|
|
||||||
|
/** Chops out a section of the block.
|
||||||
|
|
||||||
|
This will remove a section of the memory block and close the gap around it,
|
||||||
|
shifting any subsequent data downwards and reducing the size of the block.
|
||||||
|
|
||||||
|
If the range specified goes beyond the size of the block, it will be clipped.
|
||||||
|
*/
|
||||||
|
void removeSection (size_t startByte, size_t numBytesToRemove);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Copies data into this MemoryBlock from a memory address.
|
||||||
|
|
||||||
|
@param srcData the memory location of the data to copy into this block
|
||||||
|
@param destinationOffset the offset in this block at which the data being copied should begin
|
||||||
|
@param numBytes how much to copy in (if this goes beyond the size of the memory block,
|
||||||
|
it will be clipped so not to do anything nasty)
|
||||||
|
*/
|
||||||
|
void copyFrom (const void* srcData,
|
||||||
|
int destinationOffset,
|
||||||
|
size_t numBytes) noexcept;
|
||||||
|
|
||||||
|
/** Copies data from this MemoryBlock to a memory address.
|
||||||
|
|
||||||
|
@param destData the memory location to write to
|
||||||
|
@param sourceOffset the offset within this block from which the copied data will be read
|
||||||
|
@param numBytes how much to copy (if this extends beyond the limits of the memory block,
|
||||||
|
zeros will be used for that portion of the data)
|
||||||
|
*/
|
||||||
|
void copyTo (void* destData,
|
||||||
|
int sourceOffset,
|
||||||
|
size_t numBytes) const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Exchanges the contents of this and another memory block.
|
||||||
|
No actual copying is required for this, so it's very fast.
|
||||||
|
*/
|
||||||
|
void swapWith (MemoryBlock& other) noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Attempts to parse the contents of the block as a zero-terminated UTF8 string. */
|
||||||
|
String toString() const;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Parses a string of hexadecimal numbers and writes this data into the memory block.
|
||||||
|
|
||||||
|
The block will be resized to the number of valid bytes read from the string.
|
||||||
|
Non-hex characters in the string will be ignored.
|
||||||
|
|
||||||
|
@see String::toHexString()
|
||||||
|
*/
|
||||||
|
void loadFromHexString (StringRef sourceHexString);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Sets a number of bits in the memory block, treating it as a long binary sequence. */
|
||||||
|
void setBitRange (size_t bitRangeStart,
|
||||||
|
size_t numBits,
|
||||||
|
int binaryNumberToApply) noexcept;
|
||||||
|
|
||||||
|
/** Reads a number of bits from the memory block, treating it as one long binary sequence */
|
||||||
|
int getBitRange (size_t bitRangeStart,
|
||||||
|
size_t numBitsToRead) const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a string of characters that represent the binary contents of this block.
|
||||||
|
|
||||||
|
Uses a 64-bit encoding system to allow binary data to be turned into a string
|
||||||
|
of simple non-extended characters, e.g. for storage in XML.
|
||||||
|
|
||||||
|
@see fromBase64Encoding
|
||||||
|
*/
|
||||||
|
String toBase64Encoding() const;
|
||||||
|
|
||||||
|
/** Takes a string of encoded characters and turns it into binary data.
|
||||||
|
|
||||||
|
The string passed in must have been created by to64BitEncoding(), and this
|
||||||
|
block will be resized to recreate the original data block.
|
||||||
|
|
||||||
|
@see toBase64Encoding
|
||||||
|
*/
|
||||||
|
bool fromBase64Encoding (StringRef encodedString);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
HeapBlock<char> data;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
JUCE_LEAK_DETECTOR (MemoryBlock)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_MEMORYBLOCK_H_INCLUDED
|
||||||
@@ -0,0 +1,186 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_OPTIONALSCOPEDPOINTER_H_INCLUDED
|
||||||
|
#define JUCE_OPTIONALSCOPEDPOINTER_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Holds a pointer to an object which can optionally be deleted when this pointer
|
||||||
|
goes out of scope.
|
||||||
|
|
||||||
|
This acts in many ways like a ScopedPointer, but allows you to specify whether or
|
||||||
|
not the object is deleted.
|
||||||
|
|
||||||
|
@see ScopedPointer
|
||||||
|
*/
|
||||||
|
template <class ObjectType>
|
||||||
|
class OptionalScopedPointer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates an empty OptionalScopedPointer. */
|
||||||
|
OptionalScopedPointer() : shouldDelete (false) {}
|
||||||
|
|
||||||
|
/** Creates an OptionalScopedPointer to point to a given object, and specifying whether
|
||||||
|
the OptionalScopedPointer will delete it.
|
||||||
|
|
||||||
|
If takeOwnership is true, then the OptionalScopedPointer will act like a ScopedPointer,
|
||||||
|
deleting the object when it is itself deleted. If this parameter is false, then the
|
||||||
|
OptionalScopedPointer just holds a normal pointer to the object, and won't delete it.
|
||||||
|
*/
|
||||||
|
OptionalScopedPointer (ObjectType* objectToHold, bool takeOwnership)
|
||||||
|
: object (objectToHold), shouldDelete (takeOwnership)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Takes ownership of the object that another OptionalScopedPointer holds.
|
||||||
|
|
||||||
|
Like a normal ScopedPointer, the objectToTransferFrom object will become null,
|
||||||
|
as ownership of the managed object is transferred to this object.
|
||||||
|
|
||||||
|
The flag to indicate whether or not to delete the managed object is also
|
||||||
|
copied from the source object.
|
||||||
|
*/
|
||||||
|
OptionalScopedPointer (OptionalScopedPointer& objectToTransferFrom)
|
||||||
|
: object (objectToTransferFrom.release()),
|
||||||
|
shouldDelete (objectToTransferFrom.shouldDelete)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Takes ownership of the object that another OptionalScopedPointer holds.
|
||||||
|
|
||||||
|
Like a normal ScopedPointer, the objectToTransferFrom object will become null,
|
||||||
|
as ownership of the managed object is transferred to this object.
|
||||||
|
|
||||||
|
The ownership flag that says whether or not to delete the managed object is also
|
||||||
|
copied from the source object.
|
||||||
|
*/
|
||||||
|
OptionalScopedPointer& operator= (OptionalScopedPointer& objectToTransferFrom)
|
||||||
|
{
|
||||||
|
if (object != objectToTransferFrom.object)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
object = objectToTransferFrom.object;
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldDelete = objectToTransferFrom.shouldDelete;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The destructor may or may not delete the object that is being held, depending on the
|
||||||
|
takeOwnership flag that was specified when the object was first passed into an
|
||||||
|
OptionalScopedPointer constructor.
|
||||||
|
*/
|
||||||
|
~OptionalScopedPointer()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the object that this pointer is managing. */
|
||||||
|
inline operator ObjectType*() const noexcept { return object; }
|
||||||
|
|
||||||
|
/** Returns the object that this pointer is managing. */
|
||||||
|
inline ObjectType* get() const noexcept { return object; }
|
||||||
|
|
||||||
|
/** Returns the object that this pointer is managing. */
|
||||||
|
inline ObjectType& operator*() const noexcept { return *object; }
|
||||||
|
|
||||||
|
/** Lets you access methods and properties of the object that this pointer is holding. */
|
||||||
|
inline ObjectType* operator->() const noexcept { return object; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Removes the current object from this OptionalScopedPointer without deleting it.
|
||||||
|
This will return the current object, and set this OptionalScopedPointer to a null pointer.
|
||||||
|
*/
|
||||||
|
ObjectType* release() noexcept { return object.release(); }
|
||||||
|
|
||||||
|
/** Resets this pointer to null, possibly deleting the object that it holds, if it has
|
||||||
|
ownership of it.
|
||||||
|
*/
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
if (! shouldDelete)
|
||||||
|
object.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Makes this OptionalScopedPointer point at a new object, specifying whether the
|
||||||
|
OptionalScopedPointer will take ownership of the object.
|
||||||
|
|
||||||
|
If takeOwnership is true, then the OptionalScopedPointer will act like a ScopedPointer,
|
||||||
|
deleting the object when it is itself deleted. If this parameter is false, then the
|
||||||
|
OptionalScopedPointer just holds a normal pointer to the object, and won't delete it.
|
||||||
|
*/
|
||||||
|
void set (ObjectType* newObject, bool takeOwnership)
|
||||||
|
{
|
||||||
|
if (object != newObject)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
object = newObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldDelete = takeOwnership;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Makes this OptionalScopedPointer point at a new object, and take ownership of that object. */
|
||||||
|
void setOwned (ObjectType* newObject)
|
||||||
|
{
|
||||||
|
set (newObject, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Makes this OptionalScopedPointer point at a new object, but will not take ownership of that object. */
|
||||||
|
void setNonOwned (ObjectType* newObject)
|
||||||
|
{
|
||||||
|
set (newObject, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the target object will be deleted when this pointer
|
||||||
|
object is deleted.
|
||||||
|
*/
|
||||||
|
bool willDeleteObject() const noexcept { return shouldDelete; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Swaps this object with another OptionalScopedPointer.
|
||||||
|
The two objects simply exchange their states.
|
||||||
|
*/
|
||||||
|
void swapWith (OptionalScopedPointer<ObjectType>& other) noexcept
|
||||||
|
{
|
||||||
|
object.swapWith (other.object);
|
||||||
|
std::swap (shouldDelete, other.shouldDelete);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
ScopedPointer<ObjectType> object;
|
||||||
|
bool shouldDelete;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_OPTIONALSCOPEDPOINTER_H_INCLUDED
|
||||||
@@ -0,0 +1,415 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_REFERENCECOUNTEDOBJECT_H_INCLUDED
|
||||||
|
#define JUCE_REFERENCECOUNTEDOBJECT_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A base class which provides methods for reference-counting.
|
||||||
|
|
||||||
|
To add reference-counting to a class, derive it from this class, and
|
||||||
|
use the ReferenceCountedObjectPtr class to point to it.
|
||||||
|
|
||||||
|
e.g. @code
|
||||||
|
class MyClass : public ReferenceCountedObject
|
||||||
|
{
|
||||||
|
void foo();
|
||||||
|
|
||||||
|
// This is a neat way of declaring a typedef for a pointer class,
|
||||||
|
// rather than typing out the full templated name each time..
|
||||||
|
typedef ReferenceCountedObjectPtr<MyClass> Ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
MyClass::Ptr p = new MyClass();
|
||||||
|
MyClass::Ptr p2 = p;
|
||||||
|
p = nullptr;
|
||||||
|
p2->foo();
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
Once a new ReferenceCountedObject has been assigned to a pointer, be
|
||||||
|
careful not to delete the object manually.
|
||||||
|
|
||||||
|
This class uses an Atomic<int> value to hold the reference count, so that it
|
||||||
|
the pointers can be passed between threads safely. For a faster but non-thread-safe
|
||||||
|
version, use SingleThreadedReferenceCountedObject instead.
|
||||||
|
|
||||||
|
@see ReferenceCountedObjectPtr, ReferenceCountedArray, SingleThreadedReferenceCountedObject
|
||||||
|
*/
|
||||||
|
class JUCE_API ReferenceCountedObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Increments the object's reference count.
|
||||||
|
|
||||||
|
This is done automatically by the smart pointer, but is public just
|
||||||
|
in case it's needed for nefarious purposes.
|
||||||
|
*/
|
||||||
|
void incReferenceCount() noexcept
|
||||||
|
{
|
||||||
|
++refCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Decreases the object's reference count.
|
||||||
|
If the count gets to zero, the object will be deleted.
|
||||||
|
*/
|
||||||
|
void decReferenceCount() noexcept
|
||||||
|
{
|
||||||
|
jassert (getReferenceCount() > 0);
|
||||||
|
|
||||||
|
if (--refCount == 0)
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Decreases the object's reference count.
|
||||||
|
If the count gets to zero, the object will not be deleted, but this method
|
||||||
|
will return true, allowing the caller to take care of deletion.
|
||||||
|
*/
|
||||||
|
bool decReferenceCountWithoutDeleting() noexcept
|
||||||
|
{
|
||||||
|
jassert (getReferenceCount() > 0);
|
||||||
|
return --refCount == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the object's current reference count. */
|
||||||
|
int getReferenceCount() const noexcept { return refCount.get(); }
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates the reference-counted object (with an initial ref count of zero). */
|
||||||
|
ReferenceCountedObject() {}
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
virtual ~ReferenceCountedObject()
|
||||||
|
{
|
||||||
|
// it's dangerous to delete an object that's still referenced by something else!
|
||||||
|
jassert (getReferenceCount() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Resets the reference count to zero without deleting the object.
|
||||||
|
You should probably never need to use this!
|
||||||
|
*/
|
||||||
|
void resetReferenceCount() noexcept
|
||||||
|
{
|
||||||
|
refCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
Atomic <int> refCount;
|
||||||
|
|
||||||
|
friend struct ContainerDeletePolicy<ReferenceCountedObject>;
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (ReferenceCountedObject)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Adds reference-counting to an object.
|
||||||
|
|
||||||
|
This is effectively a version of the ReferenceCountedObject class, but which
|
||||||
|
uses a non-atomic counter, and so is not thread-safe (but which will be more
|
||||||
|
efficient).
|
||||||
|
For more details on how to use it, see the ReferenceCountedObject class notes.
|
||||||
|
|
||||||
|
@see ReferenceCountedObject, ReferenceCountedObjectPtr, ReferenceCountedArray
|
||||||
|
*/
|
||||||
|
class JUCE_API SingleThreadedReferenceCountedObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Increments the object's reference count.
|
||||||
|
|
||||||
|
This is done automatically by the smart pointer, but is public just
|
||||||
|
in case it's needed for nefarious purposes.
|
||||||
|
*/
|
||||||
|
void incReferenceCount() noexcept
|
||||||
|
{
|
||||||
|
++refCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Decreases the object's reference count.
|
||||||
|
If the count gets to zero, the object will be deleted.
|
||||||
|
*/
|
||||||
|
void decReferenceCount() noexcept
|
||||||
|
{
|
||||||
|
jassert (getReferenceCount() > 0);
|
||||||
|
|
||||||
|
if (--refCount == 0)
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Decreases the object's reference count.
|
||||||
|
If the count gets to zero, the object will not be deleted, but this method
|
||||||
|
will return true, allowing the caller to take care of deletion.
|
||||||
|
*/
|
||||||
|
bool decReferenceCountWithoutDeleting() noexcept
|
||||||
|
{
|
||||||
|
jassert (getReferenceCount() > 0);
|
||||||
|
return --refCount == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the object's current reference count. */
|
||||||
|
int getReferenceCount() const noexcept { return refCount; }
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates the reference-counted object (with an initial ref count of zero). */
|
||||||
|
SingleThreadedReferenceCountedObject() : refCount (0) {}
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
virtual ~SingleThreadedReferenceCountedObject()
|
||||||
|
{
|
||||||
|
// it's dangerous to delete an object that's still referenced by something else!
|
||||||
|
jassert (getReferenceCount() == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
int refCount;
|
||||||
|
|
||||||
|
friend struct ContainerDeletePolicy<ReferenceCountedObject>;
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (SingleThreadedReferenceCountedObject)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A smart-pointer class which points to a reference-counted object.
|
||||||
|
|
||||||
|
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 methods called incReferenceCount(), decReferenceCount(), and
|
||||||
|
decReferenceCountWithoutDeleting(). See ReferenceCountedObject for examples of how these methods
|
||||||
|
should behave.
|
||||||
|
|
||||||
|
When using this class, you'll probably want to create a typedef to abbreviate the full
|
||||||
|
templated name - e.g.
|
||||||
|
@code
|
||||||
|
struct MyClass : public ReferenceCountedObject
|
||||||
|
{
|
||||||
|
typedef ReferenceCountedObjectPtr<MyClass> Ptr;
|
||||||
|
...
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@see ReferenceCountedObject, ReferenceCountedObjectArray
|
||||||
|
*/
|
||||||
|
template <class ReferenceCountedObjectClass>
|
||||||
|
class ReferenceCountedObjectPtr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** The class being referenced by this pointer. */
|
||||||
|
typedef ReferenceCountedObjectClass ReferencedType;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a pointer to a null object. */
|
||||||
|
ReferenceCountedObjectPtr() noexcept
|
||||||
|
: referencedObject (nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a pointer to an object.
|
||||||
|
This will increment the object's reference-count.
|
||||||
|
*/
|
||||||
|
ReferenceCountedObjectPtr (ReferencedType* refCountedObject) noexcept
|
||||||
|
: referencedObject (refCountedObject)
|
||||||
|
{
|
||||||
|
incIfNotNull (refCountedObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copies another pointer.
|
||||||
|
This will increment the object's reference-count.
|
||||||
|
*/
|
||||||
|
ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr& other) noexcept
|
||||||
|
: referencedObject (other.referencedObject)
|
||||||
|
{
|
||||||
|
incIfNotNull (referencedObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copies another pointer.
|
||||||
|
This will increment the object's reference-count (if it is non-null).
|
||||||
|
*/
|
||||||
|
template <class Convertible>
|
||||||
|
ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr<Convertible>& other) noexcept
|
||||||
|
: referencedObject (static_cast <ReferencedType*> (other.get()))
|
||||||
|
{
|
||||||
|
incIfNotNull (referencedObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Changes this pointer to point at a different object.
|
||||||
|
The reference count of the old object is decremented, and it might be
|
||||||
|
deleted if it hits zero. The new object's count is incremented.
|
||||||
|
*/
|
||||||
|
ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr& other)
|
||||||
|
{
|
||||||
|
return operator= (other.referencedObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Changes this pointer to point at a different object.
|
||||||
|
The reference count of the old object is decremented, and it might be
|
||||||
|
deleted if it hits zero. The new object's count is incremented.
|
||||||
|
*/
|
||||||
|
template <class Convertible>
|
||||||
|
ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr<Convertible>& other)
|
||||||
|
{
|
||||||
|
return operator= (static_cast<ReferencedType*> (other.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Changes this pointer to point at a different object.
|
||||||
|
|
||||||
|
The reference count of the old object is decremented, and it might be
|
||||||
|
deleted if it hits zero. The new object's count is incremented.
|
||||||
|
*/
|
||||||
|
ReferenceCountedObjectPtr& operator= (ReferencedType* const newObject)
|
||||||
|
{
|
||||||
|
if (referencedObject != newObject)
|
||||||
|
{
|
||||||
|
incIfNotNull (newObject);
|
||||||
|
ReferencedType* const oldObject = referencedObject;
|
||||||
|
referencedObject = newObject;
|
||||||
|
decIfNotNull (oldObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
/** Takes-over the object from another pointer. */
|
||||||
|
ReferenceCountedObjectPtr (ReferenceCountedObjectPtr&& other) noexcept
|
||||||
|
: referencedObject (other.referencedObject)
|
||||||
|
{
|
||||||
|
other.referencedObject = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Takes-over the object from another pointer. */
|
||||||
|
ReferenceCountedObjectPtr& operator= (ReferenceCountedObjectPtr&& other)
|
||||||
|
{
|
||||||
|
std::swap (referencedObject, other.referencedObject);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Destructor.
|
||||||
|
This will decrement the object's reference-count, which will cause the
|
||||||
|
object to be deleted when the ref-count hits zero.
|
||||||
|
*/
|
||||||
|
~ReferenceCountedObjectPtr()
|
||||||
|
{
|
||||||
|
decIfNotNull (referencedObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the object that this pointer references.
|
||||||
|
The pointer returned may be null, of course.
|
||||||
|
*/
|
||||||
|
operator ReferencedType*() const noexcept { return referencedObject; }
|
||||||
|
|
||||||
|
/** Returns the object that this pointer references.
|
||||||
|
The pointer returned may be null, of course.
|
||||||
|
*/
|
||||||
|
ReferencedType* get() const noexcept { return referencedObject; }
|
||||||
|
|
||||||
|
/** Returns the object that this pointer references.
|
||||||
|
The pointer returned may be null, of course.
|
||||||
|
*/
|
||||||
|
ReferencedType* getObject() const noexcept { return referencedObject; }
|
||||||
|
|
||||||
|
// the -> operator is called on the referenced object
|
||||||
|
ReferencedType* operator->() const noexcept
|
||||||
|
{
|
||||||
|
jassert (referencedObject != nullptr); // null pointer method call!
|
||||||
|
return referencedObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
ReferencedType* referencedObject;
|
||||||
|
|
||||||
|
static void incIfNotNull (ReferencedType* o) noexcept
|
||||||
|
{
|
||||||
|
if (o != nullptr)
|
||||||
|
o->incReferenceCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void decIfNotNull (ReferencedType* o) noexcept
|
||||||
|
{
|
||||||
|
if (o != nullptr && o->decReferenceCountWithoutDeleting())
|
||||||
|
ContainerDeletePolicy<ReferencedType>::destroy (o);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Compares two ReferenceCountedObjectPointers. */
|
||||||
|
template <class ReferenceCountedObjectClass>
|
||||||
|
bool operator== (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, ReferenceCountedObjectClass* const object2) noexcept
|
||||||
|
{
|
||||||
|
return object1.get() == object2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compares two ReferenceCountedObjectPointers. */
|
||||||
|
template <class ReferenceCountedObjectClass>
|
||||||
|
bool operator== (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
|
||||||
|
{
|
||||||
|
return object1.get() == object2.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compares two ReferenceCountedObjectPointers. */
|
||||||
|
template <class ReferenceCountedObjectClass>
|
||||||
|
bool operator== (ReferenceCountedObjectClass* object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
|
||||||
|
{
|
||||||
|
return object1 == object2.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compares two ReferenceCountedObjectPointers. */
|
||||||
|
template <class ReferenceCountedObjectClass>
|
||||||
|
bool operator!= (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectClass* object2) noexcept
|
||||||
|
{
|
||||||
|
return object1.get() != object2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compares two ReferenceCountedObjectPointers. */
|
||||||
|
template <class ReferenceCountedObjectClass>
|
||||||
|
bool operator!= (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
|
||||||
|
{
|
||||||
|
return object1.get() != object2.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compares two ReferenceCountedObjectPointers. */
|
||||||
|
template <class ReferenceCountedObjectClass>
|
||||||
|
bool operator!= (ReferenceCountedObjectClass* object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
|
||||||
|
{
|
||||||
|
return object1 != object2.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_REFERENCECOUNTEDOBJECT_H_INCLUDED
|
||||||
@@ -0,0 +1,253 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_SCOPEDPOINTER_H_INCLUDED
|
||||||
|
#define JUCE_SCOPEDPOINTER_H_INCLUDED
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
This class holds a pointer which is automatically deleted when this object goes
|
||||||
|
out of scope.
|
||||||
|
|
||||||
|
Once a pointer has been passed to a ScopedPointer, it will make sure that the pointer
|
||||||
|
gets deleted when the ScopedPointer is deleted. Using the ScopedPointer on the stack or
|
||||||
|
as member variables is a good way to use RAII to avoid accidentally leaking dynamically
|
||||||
|
created objects.
|
||||||
|
|
||||||
|
A ScopedPointer can be used in pretty much the same way that you'd use a normal pointer
|
||||||
|
to an object. If you use the assignment operator to assign a different object to a
|
||||||
|
ScopedPointer, the old one will be automatically deleted.
|
||||||
|
|
||||||
|
Important note: The class is designed to hold a pointer to an object, NOT to an array!
|
||||||
|
It calls delete on its payload, not delete[], so do not give it an array to hold! For
|
||||||
|
that kind of purpose, you should be using HeapBlock or Array instead.
|
||||||
|
|
||||||
|
A const ScopedPointer is guaranteed not to lose ownership of its object or change the
|
||||||
|
object to which it points during its lifetime. This means that making a copy of a const
|
||||||
|
ScopedPointer is impossible, as that would involve the new copy taking ownership from the
|
||||||
|
old one.
|
||||||
|
|
||||||
|
If you need to get a pointer out of a ScopedPointer without it being deleted, you
|
||||||
|
can use the release() method.
|
||||||
|
|
||||||
|
Something to note is the main difference between this class and the std::auto_ptr class,
|
||||||
|
which is that ScopedPointer provides a cast-to-object operator, wheras std::auto_ptr
|
||||||
|
requires that you always call get() to retrieve the pointer. The advantages of providing
|
||||||
|
the cast is that you don't need to call get(), so can use the ScopedPointer in pretty much
|
||||||
|
exactly the same way as a raw pointer. The disadvantage is that the compiler is free to
|
||||||
|
use the cast in unexpected and sometimes dangerous ways - in particular, it becomes difficult
|
||||||
|
to return a ScopedPointer as the result of a function. To avoid this causing errors,
|
||||||
|
ScopedPointer contains an overloaded constructor that should cause a syntax error in these
|
||||||
|
circumstances, but it does mean that instead of returning a ScopedPointer from a function,
|
||||||
|
you'd need to return a raw pointer (or use a std::auto_ptr instead).
|
||||||
|
*/
|
||||||
|
template <class ObjectType>
|
||||||
|
class ScopedPointer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a ScopedPointer containing a null pointer. */
|
||||||
|
inline ScopedPointer() noexcept : object (nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a ScopedPointer that owns the specified object. */
|
||||||
|
inline ScopedPointer (ObjectType* const objectToTakePossessionOf) noexcept
|
||||||
|
: object (objectToTakePossessionOf)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Creates a ScopedPointer that takes its pointer from another ScopedPointer.
|
||||||
|
|
||||||
|
Because a pointer can only belong to one ScopedPointer, this transfers
|
||||||
|
the pointer from the other object to this one, and the other object is reset to
|
||||||
|
be a null pointer.
|
||||||
|
*/
|
||||||
|
ScopedPointer (ScopedPointer& objectToTransferFrom) noexcept
|
||||||
|
: object (objectToTransferFrom.object)
|
||||||
|
{
|
||||||
|
objectToTransferFrom.object = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Destructor.
|
||||||
|
This will delete the object that this ScopedPointer currently refers to.
|
||||||
|
*/
|
||||||
|
inline ~ScopedPointer() { ContainerDeletePolicy<ObjectType>::destroy (object); }
|
||||||
|
|
||||||
|
/** Changes this ScopedPointer to point to a new object.
|
||||||
|
|
||||||
|
Because a pointer can only belong to one ScopedPointer, this transfers
|
||||||
|
the pointer from the other object to this one, and the other object is reset to
|
||||||
|
be a null pointer.
|
||||||
|
|
||||||
|
If this ScopedPointer already points to an object, that object
|
||||||
|
will first be deleted.
|
||||||
|
*/
|
||||||
|
ScopedPointer& operator= (ScopedPointer& objectToTransferFrom)
|
||||||
|
{
|
||||||
|
if (this != objectToTransferFrom.getAddress())
|
||||||
|
{
|
||||||
|
// Two ScopedPointers should never be able to refer to the same object - if
|
||||||
|
// this happens, you must have done something dodgy!
|
||||||
|
jassert (object == nullptr || object != objectToTransferFrom.object);
|
||||||
|
|
||||||
|
ObjectType* const oldObject = object;
|
||||||
|
object = objectToTransferFrom.object;
|
||||||
|
objectToTransferFrom.object = nullptr;
|
||||||
|
ContainerDeletePolicy<ObjectType>::destroy (oldObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Changes this ScopedPointer to point to a new object.
|
||||||
|
|
||||||
|
If this ScopedPointer already points to an object, that object
|
||||||
|
will first be deleted.
|
||||||
|
|
||||||
|
The pointer that you pass in may be a nullptr.
|
||||||
|
*/
|
||||||
|
ScopedPointer& operator= (ObjectType* const newObjectToTakePossessionOf)
|
||||||
|
{
|
||||||
|
if (object != newObjectToTakePossessionOf)
|
||||||
|
{
|
||||||
|
ObjectType* const oldObject = object;
|
||||||
|
object = newObjectToTakePossessionOf;
|
||||||
|
ContainerDeletePolicy<ObjectType>::destroy (oldObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
ScopedPointer (ScopedPointer&& other) noexcept
|
||||||
|
: object (other.object)
|
||||||
|
{
|
||||||
|
other.object = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedPointer& operator= (ScopedPointer&& other) noexcept
|
||||||
|
{
|
||||||
|
object = other.object;
|
||||||
|
other.object = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns the object that this ScopedPointer refers to. */
|
||||||
|
inline operator ObjectType*() const noexcept { return object; }
|
||||||
|
|
||||||
|
/** Returns the object that this ScopedPointer refers to. */
|
||||||
|
inline ObjectType* get() const noexcept { return object; }
|
||||||
|
|
||||||
|
/** Returns the object that this ScopedPointer refers to. */
|
||||||
|
inline ObjectType& operator*() const noexcept { return *object; }
|
||||||
|
|
||||||
|
/** Lets you access methods and properties of the object that this ScopedPointer refers to. */
|
||||||
|
inline ObjectType* operator->() const noexcept { return object; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Removes the current object from this ScopedPointer without deleting it.
|
||||||
|
This will return the current object, and set the ScopedPointer to a null pointer.
|
||||||
|
*/
|
||||||
|
ObjectType* release() noexcept { ObjectType* const o = object; object = nullptr; return o; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Swaps this object with that of another ScopedPointer.
|
||||||
|
The two objects simply exchange their pointers.
|
||||||
|
*/
|
||||||
|
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() || object == nullptr);
|
||||||
|
|
||||||
|
std::swap (object, other.object);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** If the pointer is non-null, this will attempt to return a new copy of the object that is pointed to.
|
||||||
|
If the pointer is null, this will safely return a nullptr.
|
||||||
|
*/
|
||||||
|
inline ObjectType* createCopy() const { return createCopyIfNotNull (object); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
ObjectType* object;
|
||||||
|
|
||||||
|
// (Required as an alternative to the overloaded & operator).
|
||||||
|
const ScopedPointer* getAddress() const noexcept { return this; }
|
||||||
|
|
||||||
|
#if ! JUCE_MSVC // (MSVC can't deal with multiple copy constructors)
|
||||||
|
/* The copy constructors are private to stop people accidentally copying a const ScopedPointer
|
||||||
|
(the compiler would let you do so by implicitly casting the source to its raw object pointer).
|
||||||
|
|
||||||
|
A side effect of this is that in a compiler that doesn't support C++11, you may hit an
|
||||||
|
error when you write something like this:
|
||||||
|
|
||||||
|
ScopedPointer<MyClass> m = new MyClass(); // Compile error: copy constructor is private.
|
||||||
|
|
||||||
|
Even though the compiler would normally ignore the assignment here, it can't do so when the
|
||||||
|
copy constructor is private. It's very easy to fix though - just write it like this:
|
||||||
|
|
||||||
|
ScopedPointer<MyClass> m (new MyClass()); // Compiles OK
|
||||||
|
|
||||||
|
It's probably best to use the latter form when writing your object declarations anyway, as
|
||||||
|
this is a better representation of the code that you actually want the compiler to produce.
|
||||||
|
*/
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (ScopedPointer)
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Compares a ScopedPointer with another pointer.
|
||||||
|
This can be handy for checking whether this is a null pointer.
|
||||||
|
*/
|
||||||
|
template <class ObjectType>
|
||||||
|
bool operator== (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<ObjectType*> (pointer1) == pointer2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Compares a ScopedPointer with another pointer.
|
||||||
|
This can be handy for checking whether this is a null pointer.
|
||||||
|
*/
|
||||||
|
template <class ObjectType>
|
||||||
|
bool operator!= (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
|
||||||
|
{
|
||||||
|
return static_cast<ObjectType*> (pointer1) != pointer2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#ifndef DOXYGEN
|
||||||
|
// NB: This is just here to prevent any silly attempts to call deleteAndZero() on a ScopedPointer.
|
||||||
|
template <typename Type>
|
||||||
|
void deleteAndZero (ScopedPointer<Type>&) { static_jassert (sizeof (Type) == 12345); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // JUCE_SCOPEDPOINTER_H_INCLUDED
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_SHAREDRESOURCEPOINTER_H_INCLUDED
|
||||||
|
#define JUCE_SHAREDRESOURCEPOINTER_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A smart-pointer that automatically creates and manages the lifetime of a
|
||||||
|
shared static instance of a class.
|
||||||
|
|
||||||
|
The SharedObjectType template type indicates the class to use for the shared
|
||||||
|
object - the only requirements on this class are that it must have a public
|
||||||
|
default constructor and destructor.
|
||||||
|
|
||||||
|
The SharedResourcePointer offers a pattern that differs from using a singleton or
|
||||||
|
static instance of an object, because it uses reference-counting to make sure that
|
||||||
|
the underlying shared object is automatically created/destroyed according to the
|
||||||
|
number of SharedResourcePointer objects that exist. When the last one is deleted,
|
||||||
|
the underlying object is also immediately destroyed. This allows you to use scoping
|
||||||
|
to manage the lifetime of a shared resource.
|
||||||
|
|
||||||
|
Note: the construction/deletion of the shared object must not involve any
|
||||||
|
code that makes recursive calls to a SharedResourcePointer, or you'll cause
|
||||||
|
a deadlock.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
@code
|
||||||
|
// An example of a class that contains the shared data you want to use.
|
||||||
|
struct MySharedData
|
||||||
|
{
|
||||||
|
// There's no need to ever create an instance of this class directly yourself,
|
||||||
|
// but it does need a public constructor that does the initialisation.
|
||||||
|
MySharedData()
|
||||||
|
{
|
||||||
|
sharedStuff = generateHeavyweightStuff();
|
||||||
|
}
|
||||||
|
|
||||||
|
Array<SomeKindOfData> sharedStuff;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DataUserClass
|
||||||
|
{
|
||||||
|
DataUserClass()
|
||||||
|
{
|
||||||
|
// Multiple instances of the DataUserClass will all have the same
|
||||||
|
// shared common instance of MySharedData referenced by their sharedData
|
||||||
|
// member variables.
|
||||||
|
useSharedStuff (sharedData->sharedStuff);
|
||||||
|
}
|
||||||
|
|
||||||
|
// By keeping this pointer as a member variable, the shared resource
|
||||||
|
// is guaranteed to be available for as long as the DataUserClass object.
|
||||||
|
SharedResourcePointer<MySharedData> sharedData;
|
||||||
|
};
|
||||||
|
|
||||||
|
@endcode
|
||||||
|
*/
|
||||||
|
template <typename SharedObjectType>
|
||||||
|
class SharedResourcePointer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Creates an instance of the shared object.
|
||||||
|
If other SharedResourcePointer objects for this type already exist, then
|
||||||
|
this one will simply point to the same shared object that they are already
|
||||||
|
using. Otherwise, if this is the first SharedResourcePointer to be created,
|
||||||
|
then a shared object will be created automatically.
|
||||||
|
*/
|
||||||
|
SharedResourcePointer()
|
||||||
|
{
|
||||||
|
SharedObjectHolder& holder = getSharedObjectHolder();
|
||||||
|
const SpinLock::ScopedLockType sl (holder.lock);
|
||||||
|
|
||||||
|
if (++(holder.refCount) == 1)
|
||||||
|
holder.sharedInstance = new SharedObjectType();
|
||||||
|
|
||||||
|
sharedObject = holder.sharedInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Destructor.
|
||||||
|
If no other SharedResourcePointer objects exist, this will also delete
|
||||||
|
the shared object to which it refers.
|
||||||
|
*/
|
||||||
|
~SharedResourcePointer()
|
||||||
|
{
|
||||||
|
SharedObjectHolder& holder = getSharedObjectHolder();
|
||||||
|
const SpinLock::ScopedLockType sl (holder.lock);
|
||||||
|
|
||||||
|
if (--(holder.refCount) == 0)
|
||||||
|
holder.sharedInstance = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the shared object. */
|
||||||
|
operator SharedObjectType*() const noexcept { return sharedObject; }
|
||||||
|
|
||||||
|
/** Returns the shared object. */
|
||||||
|
SharedObjectType& get() const noexcept { return *sharedObject; }
|
||||||
|
|
||||||
|
/** Returns the object that this pointer references.
|
||||||
|
The pointer returned may be zero, of course.
|
||||||
|
*/
|
||||||
|
SharedObjectType& getObject() const noexcept { return *sharedObject; }
|
||||||
|
|
||||||
|
SharedObjectType* operator->() const noexcept { return sharedObject; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct SharedObjectHolder : public ReferenceCountedObject
|
||||||
|
{
|
||||||
|
SpinLock lock;
|
||||||
|
ScopedPointer<SharedObjectType> sharedInstance;
|
||||||
|
int refCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
static SharedObjectHolder& getSharedObjectHolder() noexcept
|
||||||
|
{
|
||||||
|
static void* holder [(sizeof (SharedObjectHolder) + sizeof(void*) - 1) / sizeof(void*)] = { 0 };
|
||||||
|
return *reinterpret_cast<SharedObjectHolder*> (holder);
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedObjectType* sharedObject;
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedResourcePointer)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_SHAREDRESOURCEPOINTER_H_INCLUDED
|
||||||
@@ -0,0 +1,292 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_SINGLETON_H_INCLUDED
|
||||||
|
#define JUCE_SINGLETON_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Macro to declare member variables and methods for a singleton class.
|
||||||
|
|
||||||
|
To use this, add the line juce_DeclareSingleton (MyClass, doNotRecreateAfterDeletion)
|
||||||
|
to the class's definition.
|
||||||
|
|
||||||
|
Then put a macro juce_ImplementSingleton (MyClass) along with the class's
|
||||||
|
implementation code.
|
||||||
|
|
||||||
|
It's also a very good idea to also add the call clearSingletonInstance() in your class's
|
||||||
|
destructor, in case it is deleted by other means than deleteInstance()
|
||||||
|
|
||||||
|
Clients can then call the static method MyClass::getInstance() to get a pointer
|
||||||
|
to the singleton, or MyClass::getInstanceWithoutCreating() which will return 0 if
|
||||||
|
no instance currently exists.
|
||||||
|
|
||||||
|
e.g. @code
|
||||||
|
|
||||||
|
class MySingleton
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MySingleton()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~MySingleton()
|
||||||
|
{
|
||||||
|
// this ensures that no dangling pointers are left when the
|
||||||
|
// singleton is deleted.
|
||||||
|
clearSingletonInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
juce_DeclareSingleton (MySingleton, false)
|
||||||
|
};
|
||||||
|
|
||||||
|
juce_ImplementSingleton (MySingleton)
|
||||||
|
|
||||||
|
|
||||||
|
// example of usage:
|
||||||
|
MySingleton* m = MySingleton::getInstance(); // creates the singleton if there isn't already one.
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
MySingleton::deleteInstance(); // safely deletes the singleton (if it's been created).
|
||||||
|
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
If doNotRecreateAfterDeletion = true, it won't allow the object to be created more
|
||||||
|
than once during the process's lifetime - i.e. after you've created and deleted the
|
||||||
|
object, getInstance() will refuse to create another one. This can be useful to stop
|
||||||
|
objects being accidentally re-created during your app's shutdown code.
|
||||||
|
|
||||||
|
If you know that your object will only be created and deleted by a single thread, you
|
||||||
|
can use the slightly more efficient juce_DeclareSingleton_SingleThreaded() macro instead
|
||||||
|
of this one.
|
||||||
|
|
||||||
|
@see juce_ImplementSingleton, juce_DeclareSingleton_SingleThreaded
|
||||||
|
*/
|
||||||
|
#define juce_DeclareSingleton(classname, doNotRecreateAfterDeletion) \
|
||||||
|
\
|
||||||
|
static classname* _singletonInstance; \
|
||||||
|
static juce::CriticalSection _singletonLock; \
|
||||||
|
\
|
||||||
|
static classname* JUCE_CALLTYPE getInstance() \
|
||||||
|
{ \
|
||||||
|
if (_singletonInstance == nullptr) \
|
||||||
|
{\
|
||||||
|
const juce::ScopedLock sl (_singletonLock); \
|
||||||
|
\
|
||||||
|
if (_singletonInstance == nullptr) \
|
||||||
|
{ \
|
||||||
|
static bool alreadyInside = false; \
|
||||||
|
static bool createdOnceAlready = false; \
|
||||||
|
\
|
||||||
|
const bool problem = alreadyInside || ((doNotRecreateAfterDeletion) && createdOnceAlready); \
|
||||||
|
jassert (! problem); \
|
||||||
|
if (! problem) \
|
||||||
|
{ \
|
||||||
|
createdOnceAlready = true; \
|
||||||
|
alreadyInside = true; \
|
||||||
|
classname* newObject = new classname(); /* (use a stack variable to avoid setting the newObject value before the class has finished its constructor) */ \
|
||||||
|
alreadyInside = false; \
|
||||||
|
\
|
||||||
|
_singletonInstance = newObject; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
return _singletonInstance; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline classname* JUCE_CALLTYPE getInstanceWithoutCreating() noexcept\
|
||||||
|
{ \
|
||||||
|
return _singletonInstance; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static void JUCE_CALLTYPE deleteInstance() \
|
||||||
|
{ \
|
||||||
|
const juce::ScopedLock sl (_singletonLock); \
|
||||||
|
if (_singletonInstance != nullptr) \
|
||||||
|
{ \
|
||||||
|
classname* const old = _singletonInstance; \
|
||||||
|
_singletonInstance = nullptr; \
|
||||||
|
delete old; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void clearSingletonInstance() noexcept\
|
||||||
|
{ \
|
||||||
|
if (_singletonInstance == this) \
|
||||||
|
_singletonInstance = nullptr; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** This is a counterpart to the juce_DeclareSingleton macro.
|
||||||
|
|
||||||
|
After adding the juce_DeclareSingleton to the class definition, this macro has
|
||||||
|
to be used in the cpp file.
|
||||||
|
*/
|
||||||
|
#define juce_ImplementSingleton(classname) \
|
||||||
|
\
|
||||||
|
classname* classname::_singletonInstance = nullptr; \
|
||||||
|
juce::CriticalSection classname::_singletonLock;
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Macro to declare member variables and methods for a singleton class.
|
||||||
|
|
||||||
|
This is exactly the same as juce_DeclareSingleton, but doesn't use a critical
|
||||||
|
section to make access to it thread-safe. If you know that your object will
|
||||||
|
only ever be created or deleted by a single thread, then this is a
|
||||||
|
more efficient version to use.
|
||||||
|
|
||||||
|
If doNotRecreateAfterDeletion = true, it won't allow the object to be created more
|
||||||
|
than once during the process's lifetime - i.e. after you've created and deleted the
|
||||||
|
object, getInstance() will refuse to create another one. This can be useful to stop
|
||||||
|
objects being accidentally re-created during your app's shutdown code.
|
||||||
|
|
||||||
|
See the documentation for juce_DeclareSingleton for more information about
|
||||||
|
how to use it, the only difference being that you have to use
|
||||||
|
juce_ImplementSingleton_SingleThreaded instead of juce_ImplementSingleton.
|
||||||
|
|
||||||
|
@see juce_ImplementSingleton_SingleThreaded, juce_DeclareSingleton, juce_DeclareSingleton_SingleThreaded_Minimal
|
||||||
|
*/
|
||||||
|
#define juce_DeclareSingleton_SingleThreaded(classname, doNotRecreateAfterDeletion) \
|
||||||
|
\
|
||||||
|
static classname* _singletonInstance; \
|
||||||
|
\
|
||||||
|
static classname* getInstance() \
|
||||||
|
{ \
|
||||||
|
if (_singletonInstance == nullptr) \
|
||||||
|
{ \
|
||||||
|
static bool alreadyInside = false; \
|
||||||
|
static bool createdOnceAlready = false; \
|
||||||
|
\
|
||||||
|
const bool problem = alreadyInside || ((doNotRecreateAfterDeletion) && createdOnceAlready); \
|
||||||
|
jassert (! problem); \
|
||||||
|
if (! problem) \
|
||||||
|
{ \
|
||||||
|
createdOnceAlready = true; \
|
||||||
|
alreadyInside = true; \
|
||||||
|
classname* newObject = new classname(); /* (use a stack variable to avoid setting the newObject value before the class has finished its constructor) */ \
|
||||||
|
alreadyInside = false; \
|
||||||
|
\
|
||||||
|
_singletonInstance = newObject; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
return _singletonInstance; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline classname* getInstanceWithoutCreating() noexcept\
|
||||||
|
{ \
|
||||||
|
return _singletonInstance; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static void deleteInstance() \
|
||||||
|
{ \
|
||||||
|
if (_singletonInstance != nullptr) \
|
||||||
|
{ \
|
||||||
|
classname* const old = _singletonInstance; \
|
||||||
|
_singletonInstance = nullptr; \
|
||||||
|
delete old; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void clearSingletonInstance() noexcept\
|
||||||
|
{ \
|
||||||
|
if (_singletonInstance == this) \
|
||||||
|
_singletonInstance = nullptr; \
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Macro to declare member variables and methods for a singleton class.
|
||||||
|
|
||||||
|
This is like juce_DeclareSingleton_SingleThreaded, but doesn't do any checking
|
||||||
|
for recursion or repeated instantiation. It's intended for use as a lightweight
|
||||||
|
version of a singleton, where you're using it in very straightforward
|
||||||
|
circumstances and don't need the extra checking.
|
||||||
|
|
||||||
|
Juce use the normal juce_ImplementSingleton_SingleThreaded as the counterpart
|
||||||
|
to this declaration, as you would with juce_DeclareSingleton_SingleThreaded.
|
||||||
|
|
||||||
|
See the documentation for juce_DeclareSingleton for more information about
|
||||||
|
how to use it, the only difference being that you have to use
|
||||||
|
juce_ImplementSingleton_SingleThreaded instead of juce_ImplementSingleton.
|
||||||
|
|
||||||
|
@see juce_ImplementSingleton_SingleThreaded, juce_DeclareSingleton
|
||||||
|
*/
|
||||||
|
#define juce_DeclareSingleton_SingleThreaded_Minimal(classname) \
|
||||||
|
\
|
||||||
|
static classname* _singletonInstance; \
|
||||||
|
\
|
||||||
|
static classname* getInstance() \
|
||||||
|
{ \
|
||||||
|
if (_singletonInstance == nullptr) \
|
||||||
|
_singletonInstance = new classname(); \
|
||||||
|
\
|
||||||
|
return _singletonInstance; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static inline classname* getInstanceWithoutCreating() noexcept\
|
||||||
|
{ \
|
||||||
|
return _singletonInstance; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static void deleteInstance() \
|
||||||
|
{ \
|
||||||
|
if (_singletonInstance != nullptr) \
|
||||||
|
{ \
|
||||||
|
classname* const old = _singletonInstance; \
|
||||||
|
_singletonInstance = nullptr; \
|
||||||
|
delete old; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
void clearSingletonInstance() noexcept\
|
||||||
|
{ \
|
||||||
|
if (_singletonInstance == this) \
|
||||||
|
_singletonInstance = nullptr; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** This is a counterpart to the juce_DeclareSingleton_SingleThreaded macro.
|
||||||
|
|
||||||
|
After adding juce_DeclareSingleton_SingleThreaded or juce_DeclareSingleton_SingleThreaded_Minimal
|
||||||
|
to the class definition, this macro has to be used somewhere in the cpp file.
|
||||||
|
*/
|
||||||
|
#define juce_ImplementSingleton_SingleThreaded(classname) \
|
||||||
|
\
|
||||||
|
classname* classname::_singletonInstance = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_SINGLETON_H_INCLUDED
|
||||||
@@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_WEAKREFERENCE_H_INCLUDED
|
||||||
|
#define JUCE_WEAKREFERENCE_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
This class acts as a pointer which will automatically become null if the object
|
||||||
|
to which it points is deleted.
|
||||||
|
|
||||||
|
To accomplish this, the source object needs to cooperate by performing a couple of simple tasks.
|
||||||
|
It must embed a WeakReference::Master object, which stores a shared pointer object, and must clear
|
||||||
|
this master pointer in its destructor.
|
||||||
|
|
||||||
|
E.g.
|
||||||
|
@code
|
||||||
|
class MyObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MyObject()
|
||||||
|
{
|
||||||
|
// If you're planning on using your WeakReferences in a multi-threaded situation, you may choose
|
||||||
|
// to create a WeakReference to the object here in the constructor, which will pre-initialise the
|
||||||
|
// embedded object, avoiding an (extremely unlikely) race condition that could occur if multiple
|
||||||
|
// threads overlap while creating the first WeakReference to it.
|
||||||
|
}
|
||||||
|
|
||||||
|
~MyObject()
|
||||||
|
{
|
||||||
|
// This will zero all the references - you need to call this in your destructor.
|
||||||
|
masterReference.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// You need to embed a variable of this type, with the name "masterReference" inside your object. If the
|
||||||
|
// variable is not public, you should make your class a friend of WeakReference<MyObject> so that the
|
||||||
|
// WeakReference class can access it.
|
||||||
|
WeakReference<MyObject>::Master masterReference;
|
||||||
|
friend class WeakReference<MyObject>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Here's an example of using a pointer..
|
||||||
|
|
||||||
|
MyObject* n = new MyObject();
|
||||||
|
WeakReference<MyObject> myObjectRef = n;
|
||||||
|
|
||||||
|
MyObject* pointer1 = myObjectRef; // returns a valid pointer to 'n'
|
||||||
|
delete n;
|
||||||
|
MyObject* pointer2 = myObjectRef; // returns a null pointer
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@see WeakReference::Master
|
||||||
|
*/
|
||||||
|
template <class ObjectType, class ReferenceCountingType = ReferenceCountedObject>
|
||||||
|
class WeakReference
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Creates a null SafePointer. */
|
||||||
|
inline WeakReference() noexcept {}
|
||||||
|
|
||||||
|
/** Creates a WeakReference that points at the given object. */
|
||||||
|
WeakReference (ObjectType* const object) : holder (getRef (object)) {}
|
||||||
|
|
||||||
|
/** Creates a copy of another WeakReference. */
|
||||||
|
WeakReference (const WeakReference& other) noexcept : holder (other.holder) {}
|
||||||
|
|
||||||
|
/** Copies another pointer to this one. */
|
||||||
|
WeakReference& operator= (const WeakReference& other) { holder = other.holder; return *this; }
|
||||||
|
|
||||||
|
/** Copies another pointer to this one. */
|
||||||
|
WeakReference& operator= (ObjectType* const newObject) { holder = getRef (newObject); return *this; }
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
WeakReference (WeakReference&& other) noexcept : holder (static_cast <SharedRef&&> (other.holder)) {}
|
||||||
|
WeakReference& operator= (WeakReference&& other) noexcept { holder = static_cast <SharedRef&&> (other.holder); return *this; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
|
||||||
|
ObjectType* get() const noexcept { return holder != nullptr ? holder->get() : nullptr; }
|
||||||
|
|
||||||
|
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
|
||||||
|
operator ObjectType*() const noexcept { return get(); }
|
||||||
|
|
||||||
|
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
|
||||||
|
ObjectType* operator->() noexcept { return get(); }
|
||||||
|
|
||||||
|
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
|
||||||
|
const ObjectType* operator->() const noexcept { return get(); }
|
||||||
|
|
||||||
|
/** This returns true if this reference has been pointing at an object, but that object has
|
||||||
|
since been deleted.
|
||||||
|
|
||||||
|
If this reference was only ever pointing at a null pointer, this will return false. Using
|
||||||
|
operator=() to make this refer to a different object will reset this flag to match the status
|
||||||
|
of the reference from which you're copying.
|
||||||
|
*/
|
||||||
|
bool wasObjectDeleted() const noexcept { return holder != nullptr && holder->get() == nullptr; }
|
||||||
|
|
||||||
|
bool operator== (ObjectType* const object) const noexcept { return get() == object; }
|
||||||
|
bool operator!= (ObjectType* const object) const noexcept { return get() != object; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** This class is used internally by the WeakReference class - don't use it directly
|
||||||
|
in your code!
|
||||||
|
@see WeakReference
|
||||||
|
*/
|
||||||
|
class SharedPointer : public ReferenceCountingType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit SharedPointer (ObjectType* const obj) noexcept : owner (obj) {}
|
||||||
|
|
||||||
|
inline ObjectType* get() const noexcept { return owner; }
|
||||||
|
void clearPointer() noexcept { owner = nullptr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ObjectType* volatile owner;
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (SharedPointer)
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef ReferenceCountedObjectPtr<SharedPointer> SharedRef;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
This class is embedded inside an object to which you want to attach WeakReference pointers.
|
||||||
|
See the WeakReference class notes for an example of how to use this class.
|
||||||
|
@see WeakReference
|
||||||
|
*/
|
||||||
|
class Master
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Master() noexcept {}
|
||||||
|
|
||||||
|
~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.
|
||||||
|
jassert (sharedPointer == nullptr || sharedPointer->get() == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The first call to this method will create an internal object that is shared by all weak
|
||||||
|
references to the object.
|
||||||
|
*/
|
||||||
|
SharedPointer* getSharedPointer (ObjectType* const object)
|
||||||
|
{
|
||||||
|
if (sharedPointer == nullptr)
|
||||||
|
{
|
||||||
|
sharedPointer = new SharedPointer (object);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// You're trying to create a weak reference to an object that has already been deleted!!
|
||||||
|
jassert (sharedPointer->get() != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sharedPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The object that owns this master pointer should call this before it gets destroyed,
|
||||||
|
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() noexcept
|
||||||
|
{
|
||||||
|
if (sharedPointer != nullptr)
|
||||||
|
sharedPointer->clearPointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SharedRef sharedPointer;
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (Master)
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
SharedRef holder;
|
||||||
|
|
||||||
|
static inline SharedPointer* getRef (ObjectType* const o)
|
||||||
|
{
|
||||||
|
return (o != nullptr) ? o->masterReference.getSharedPointer (o) : nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_WEAKREFERENCE_H_INCLUDED
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
Result::Result() noexcept {}
|
||||||
|
|
||||||
|
Result::Result (const String& message) noexcept
|
||||||
|
: errorMessage (message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Result::Result (const Result& other)
|
||||||
|
: errorMessage (other.errorMessage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Result& Result::operator= (const Result& other)
|
||||||
|
{
|
||||||
|
errorMessage = other.errorMessage;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
Result::Result (Result&& other) noexcept
|
||||||
|
: errorMessage (static_cast <String&&> (other.errorMessage))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Result& Result::operator= (Result&& other) noexcept
|
||||||
|
{
|
||||||
|
errorMessage = static_cast <String&&> (other.errorMessage);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool Result::operator== (const Result& other) const noexcept
|
||||||
|
{
|
||||||
|
return errorMessage == other.errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Result::operator!= (const Result& other) const noexcept
|
||||||
|
{
|
||||||
|
return errorMessage != other.errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result Result::fail (const String& errorMessage) noexcept
|
||||||
|
{
|
||||||
|
return Result (errorMessage.isEmpty() ? "Unknown Error" : errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
const String& Result::getErrorMessage() const noexcept
|
||||||
|
{
|
||||||
|
return errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Result::wasOk() const noexcept { return errorMessage.isEmpty(); }
|
||||||
|
Result::operator bool() const noexcept { return errorMessage.isEmpty(); }
|
||||||
|
bool Result::failed() const noexcept { return errorMessage.isNotEmpty(); }
|
||||||
|
bool Result::operator!() const noexcept { return errorMessage.isNotEmpty(); }
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_RESULT_H_INCLUDED
|
||||||
|
#define JUCE_RESULT_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
Represents the 'success' or 'failure' of an operation, and holds an associated
|
||||||
|
error message to describe the error when there's a failure.
|
||||||
|
|
||||||
|
E.g.
|
||||||
|
@code
|
||||||
|
Result myOperation()
|
||||||
|
{
|
||||||
|
if (doSomeKindOfFoobar())
|
||||||
|
return Result::ok();
|
||||||
|
else
|
||||||
|
return Result::fail ("foobar didn't work!");
|
||||||
|
}
|
||||||
|
|
||||||
|
const Result result (myOperation());
|
||||||
|
|
||||||
|
if (result.wasOk())
|
||||||
|
{
|
||||||
|
...it's all good...
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
warnUserAboutFailure ("The foobar operation failed! Error message was: "
|
||||||
|
+ result.getErrorMessage());
|
||||||
|
}
|
||||||
|
@endcode
|
||||||
|
*/
|
||||||
|
class JUCE_API Result
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates and returns a 'successful' result. */
|
||||||
|
static Result ok() noexcept { return Result(); }
|
||||||
|
|
||||||
|
/** Creates a 'failure' result.
|
||||||
|
If you pass a blank error message in here, a default "Unknown Error" message
|
||||||
|
will be used instead.
|
||||||
|
*/
|
||||||
|
static Result fail (const String& errorMessage) noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns true if this result indicates a success. */
|
||||||
|
bool wasOk() const noexcept;
|
||||||
|
|
||||||
|
/** Returns true if this result indicates a failure.
|
||||||
|
You can use getErrorMessage() to retrieve the error message associated
|
||||||
|
with the failure.
|
||||||
|
*/
|
||||||
|
bool failed() const noexcept;
|
||||||
|
|
||||||
|
/** Returns true if this result indicates a success.
|
||||||
|
This is equivalent to calling wasOk().
|
||||||
|
*/
|
||||||
|
operator bool() const noexcept;
|
||||||
|
|
||||||
|
/** Returns true if this result indicates a failure.
|
||||||
|
This is equivalent to calling failed().
|
||||||
|
*/
|
||||||
|
bool operator!() const noexcept;
|
||||||
|
|
||||||
|
/** Returns the error message that was set when this result was created.
|
||||||
|
For a successful result, this will be an empty string;
|
||||||
|
*/
|
||||||
|
const String& getErrorMessage() const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
Result (const Result&);
|
||||||
|
Result& operator= (const Result&);
|
||||||
|
|
||||||
|
#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
|
||||||
|
Result (Result&&) noexcept;
|
||||||
|
Result& operator= (Result&&) noexcept;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool operator== (const Result& other) const noexcept;
|
||||||
|
bool operator!= (const Result& other) const noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
String errorMessage;
|
||||||
|
|
||||||
|
// The default constructor is not for public use!
|
||||||
|
// Instead, use Result::ok() or Result::fail()
|
||||||
|
Result() noexcept;
|
||||||
|
explicit Result (const String&) noexcept;
|
||||||
|
|
||||||
|
// These casts are private to prevent people trying to use the Result object in numeric contexts
|
||||||
|
operator int() const;
|
||||||
|
operator void*() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_RESULT_H_INCLUDED
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
Uuid::Uuid()
|
||||||
|
{
|
||||||
|
Random r;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < sizeof (uuid); ++i)
|
||||||
|
uuid[i] = (uint8) (r.nextInt (256));
|
||||||
|
|
||||||
|
// To make it RFC 4122 compliant, need to force a few bits...
|
||||||
|
uuid[6] = (uuid[6] & 0x0f) | 0x40;
|
||||||
|
uuid[8] = (uuid[8] & 0x3f) | 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uuid::~Uuid() noexcept {}
|
||||||
|
|
||||||
|
Uuid::Uuid (const Uuid& other) noexcept
|
||||||
|
{
|
||||||
|
memcpy (uuid, other.uuid, sizeof (uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
Uuid& Uuid::operator= (const Uuid& other) noexcept
|
||||||
|
{
|
||||||
|
memcpy (uuid, other.uuid, sizeof (uuid));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Uuid::operator== (const Uuid& other) const noexcept { return memcmp (uuid, other.uuid, sizeof (uuid)) == 0; }
|
||||||
|
bool Uuid::operator!= (const Uuid& other) const noexcept { return ! operator== (other); }
|
||||||
|
|
||||||
|
Uuid Uuid::null() noexcept
|
||||||
|
{
|
||||||
|
return Uuid ((const uint8*) nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Uuid::isNull() const noexcept
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < sizeof (uuid); ++i)
|
||||||
|
if (uuid[i] != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Uuid::getHexRegion (int start, int length) const
|
||||||
|
{
|
||||||
|
return String::toHexString (uuid + start, length, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
String Uuid::toString() const
|
||||||
|
{
|
||||||
|
return getHexRegion (0, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
String Uuid::toDashedString() const
|
||||||
|
{
|
||||||
|
return getHexRegion (0, 4)
|
||||||
|
+ "-" + getHexRegion (4, 2)
|
||||||
|
+ "-" + getHexRegion (6, 2)
|
||||||
|
+ "-" + getHexRegion (8, 2)
|
||||||
|
+ "-" + getHexRegion (10, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
Uuid::Uuid (const String& uuidString)
|
||||||
|
{
|
||||||
|
operator= (uuidString);
|
||||||
|
}
|
||||||
|
|
||||||
|
Uuid& Uuid::operator= (const String& uuidString)
|
||||||
|
{
|
||||||
|
MemoryBlock mb;
|
||||||
|
mb.loadFromHexString (uuidString);
|
||||||
|
mb.ensureSize (sizeof (uuid), true);
|
||||||
|
mb.copyTo (uuid, 0, sizeof (uuid));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uuid::Uuid (const uint8* const rawData) noexcept
|
||||||
|
{
|
||||||
|
operator= (rawData);
|
||||||
|
}
|
||||||
|
|
||||||
|
Uuid& Uuid::operator= (const uint8* const rawData) noexcept
|
||||||
|
{
|
||||||
|
if (rawData != nullptr)
|
||||||
|
memcpy (uuid, rawData, sizeof (uuid));
|
||||||
|
else
|
||||||
|
zeromem (uuid, sizeof (uuid));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_UUID_H_INCLUDED
|
||||||
|
#define JUCE_UUID_H_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/**
|
||||||
|
A universally unique 128-bit identifier.
|
||||||
|
|
||||||
|
This class generates very random unique numbers. It's vanishingly unlikely
|
||||||
|
that two identical UUIDs would ever be created by chance. The values are
|
||||||
|
formatted to meet the RFC 4122 version 4 standard.
|
||||||
|
|
||||||
|
The class includes methods for saving the ID as a string or as raw binary data.
|
||||||
|
*/
|
||||||
|
class JUCE_API Uuid
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
//==============================================================================
|
||||||
|
/** Creates a new unique ID, compliant with RFC 4122 version 4. */
|
||||||
|
Uuid();
|
||||||
|
|
||||||
|
/** Destructor. */
|
||||||
|
~Uuid() noexcept;
|
||||||
|
|
||||||
|
/** Creates a copy of another UUID. */
|
||||||
|
Uuid (const Uuid&) noexcept;
|
||||||
|
|
||||||
|
/** Copies another UUID. */
|
||||||
|
Uuid& operator= (const Uuid&) noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns true if the ID is zero. */
|
||||||
|
bool isNull() const noexcept;
|
||||||
|
|
||||||
|
/** Returns a null Uuid object. */
|
||||||
|
static Uuid null() noexcept;
|
||||||
|
|
||||||
|
bool operator== (const Uuid&) const noexcept;
|
||||||
|
bool operator!= (const Uuid&) const noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a stringified version of this UUID.
|
||||||
|
|
||||||
|
A Uuid object can later be reconstructed from this string using operator= or
|
||||||
|
the constructor that takes a string parameter.
|
||||||
|
|
||||||
|
@returns a 32 character hex string.
|
||||||
|
*/
|
||||||
|
String toString() const;
|
||||||
|
|
||||||
|
/** Returns a stringified version of this UUID, separating it into sections with dashes.
|
||||||
|
@returns a string in the format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||||
|
*/
|
||||||
|
String toDashedString() const;
|
||||||
|
|
||||||
|
/** Creates an ID from an encoded string version.
|
||||||
|
@see toString
|
||||||
|
*/
|
||||||
|
Uuid (const String& uuidString);
|
||||||
|
|
||||||
|
/** Copies from a stringified UUID.
|
||||||
|
The string passed in should be one that was created with the toString() method.
|
||||||
|
*/
|
||||||
|
Uuid& operator= (const String& uuidString);
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a pointer to the internal binary representation of the ID.
|
||||||
|
|
||||||
|
This is an array of 16 bytes. To reconstruct a Uuid from its data, use
|
||||||
|
the constructor or operator= method that takes an array of uint8s.
|
||||||
|
*/
|
||||||
|
const uint8* getRawData() const noexcept { return uuid; }
|
||||||
|
|
||||||
|
/** Creates a UUID from a 16-byte array.
|
||||||
|
@see getRawData
|
||||||
|
*/
|
||||||
|
Uuid (const uint8* rawData) noexcept;
|
||||||
|
|
||||||
|
/** Sets this UUID from 16-bytes of raw data. */
|
||||||
|
Uuid& operator= (const uint8* rawData) noexcept;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
uint8 uuid[16];
|
||||||
|
String getHexRegion (int, int) const;
|
||||||
|
|
||||||
|
JUCE_LEAK_DETECTOR (Uuid)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // JUCE_UUID_H_INCLUDED
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_WINDOWSREGISTRY_H_INCLUDED
|
||||||
|
#define JUCE_WINDOWSREGISTRY_H_INCLUDED
|
||||||
|
|
||||||
|
#if JUCE_WINDOWS || DOXYGEN
|
||||||
|
|
||||||
|
/**
|
||||||
|
Contains some static helper functions for manipulating the MS Windows registry
|
||||||
|
(Only available on Windows, of course!)
|
||||||
|
*/
|
||||||
|
class JUCE_API WindowsRegistry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** These values can be used to specify whether the 32- or 64-bit registry should be used.
|
||||||
|
When running on a 32-bit OS, there is no 64-bit registry, so the mode will be ignored.
|
||||||
|
*/
|
||||||
|
enum WoW64Mode
|
||||||
|
{
|
||||||
|
/** Default handling: 32-bit apps will use the 32-bit registry, and 64-bit apps
|
||||||
|
will use the 64-bit registry. */
|
||||||
|
WoW64_Default = 0,
|
||||||
|
|
||||||
|
/** Always use the 64-bit registry store. (KEY_WOW64_64KEY). */
|
||||||
|
WoW64_64bit = 0x100,
|
||||||
|
|
||||||
|
/** Always use the 32-bit registry store. (KEY_WOW64_32KEY). */
|
||||||
|
WoW64_32bit = 0x200
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/** Returns a string from the registry.
|
||||||
|
The path is a string for the entire path of a value in the registry,
|
||||||
|
e.g. "HKEY_CURRENT_USER\Software\foo\bar"
|
||||||
|
*/
|
||||||
|
static String JUCE_CALLTYPE getValue (const String& regValuePath,
|
||||||
|
const String& defaultValue = String::empty,
|
||||||
|
WoW64Mode mode = WoW64_Default);
|
||||||
|
|
||||||
|
/** Reads a binary block from the registry.
|
||||||
|
The path is a string for the entire path of a value in the registry,
|
||||||
|
e.g. "HKEY_CURRENT_USER\Software\foo\bar"
|
||||||
|
@returns a DWORD indicating the type of the key.
|
||||||
|
*/
|
||||||
|
static uint32 JUCE_CALLTYPE getBinaryValue (const String& regValuePath, MemoryBlock& resultData, WoW64Mode mode = WoW64_Default);
|
||||||
|
|
||||||
|
/** Sets a registry value as a string.
|
||||||
|
This will take care of creating any groups needed to get to the given registry value.
|
||||||
|
*/
|
||||||
|
static bool JUCE_CALLTYPE setValue (const String& regValuePath, const String& value, WoW64Mode mode = WoW64_Default);
|
||||||
|
|
||||||
|
/** Sets a registry value as a DWORD.
|
||||||
|
This will take care of creating any groups needed to get to the given registry value.
|
||||||
|
*/
|
||||||
|
static bool JUCE_CALLTYPE setValue (const String& regValuePath, uint32 value, WoW64Mode mode = WoW64_Default);
|
||||||
|
|
||||||
|
/** Sets a registry value as a QWORD.
|
||||||
|
This will take care of creating any groups needed to get to the given registry value.
|
||||||
|
*/
|
||||||
|
static bool JUCE_CALLTYPE setValue (const String& regValuePath, uint64 value, WoW64Mode mode = WoW64_Default);
|
||||||
|
|
||||||
|
/** Sets a registry value as a binary block.
|
||||||
|
This will take care of creating any groups needed to get to the given registry value.
|
||||||
|
*/
|
||||||
|
static bool JUCE_CALLTYPE setValue (const String& regValuePath, const MemoryBlock& value, WoW64Mode mode = WoW64_Default);
|
||||||
|
|
||||||
|
/** Returns true if the given value exists in the registry. */
|
||||||
|
static bool JUCE_CALLTYPE valueExists (const String& regValuePath, WoW64Mode mode = WoW64_Default);
|
||||||
|
|
||||||
|
/** Returns true if the given key exists in the registry. */
|
||||||
|
static bool JUCE_CALLTYPE keyExists (const String& regValuePath, WoW64Mode mode = WoW64_Default);
|
||||||
|
|
||||||
|
/** Deletes a registry value. */
|
||||||
|
static void JUCE_CALLTYPE deleteValue (const String& regValuePath, WoW64Mode mode = WoW64_Default);
|
||||||
|
|
||||||
|
/** Deletes a registry key (which is registry-talk for 'folder'). */
|
||||||
|
static void JUCE_CALLTYPE deleteKey (const String& regKeyPath, WoW64Mode mode = WoW64_Default);
|
||||||
|
|
||||||
|
/** Creates a file association in the registry.
|
||||||
|
|
||||||
|
This lets you set the executable that should be launched by a given file extension.
|
||||||
|
@param fileExtension the file extension to associate, including the
|
||||||
|
initial dot, e.g. ".txt"
|
||||||
|
@param symbolicDescription a space-free short token to identify the file type
|
||||||
|
@param fullDescription a human-readable description of the file type
|
||||||
|
@param targetExecutable the executable that should be launched
|
||||||
|
@param iconResourceNumber the icon that gets displayed for the file type will be
|
||||||
|
found by looking up this resource number in the
|
||||||
|
executable. Pass 0 here to not use an icon
|
||||||
|
@param registerForCurrentUserOnly if false, this will try to register the association
|
||||||
|
for all users (you might not have permission to do this
|
||||||
|
unless running in an installer). If true, it will register the
|
||||||
|
association in HKEY_CURRENT_USER.
|
||||||
|
@param mode the WoW64 mode to use for choosing the database
|
||||||
|
*/
|
||||||
|
static bool JUCE_CALLTYPE registerFileAssociation (const String& fileExtension,
|
||||||
|
const String& symbolicDescription,
|
||||||
|
const String& fullDescription,
|
||||||
|
const File& targetExecutable,
|
||||||
|
int iconResourceNumber,
|
||||||
|
bool registerForCurrentUserOnly,
|
||||||
|
WoW64Mode mode = WoW64_Default);
|
||||||
|
|
||||||
|
// DEPRECATED: use the other methods with a WoW64Mode parameter of WoW64_64bit instead.
|
||||||
|
JUCE_DEPRECATED (static String getValueWow64 (const String&, const String& defaultValue = String::empty));
|
||||||
|
JUCE_DEPRECATED (static bool valueExistsWow64 (const String&));
|
||||||
|
JUCE_DEPRECATED (static bool keyExistsWow64 (const String&));
|
||||||
|
|
||||||
|
private:
|
||||||
|
WindowsRegistry() JUCE_DELETED_FUNCTION;
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (WindowsRegistry)
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif // JUCE_WINDOWSREGISTRY_H_INCLUDED
|
||||||
@@ -0,0 +1,746 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission is granted to use this software under the terms of either:
|
||||||
|
a) the GPL v2 (or any later version)
|
||||||
|
b) the Affero GPL v3
|
||||||
|
|
||||||
|
Details of these licenses can be found at: www.gnu.org/licenses
|
||||||
|
|
||||||
|
JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
To release a closed-source product which uses JUCE, commercial licenses are
|
||||||
|
available: visit www.juce.com for more information.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.juce;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.*;
|
||||||
|
import android.view.inputmethod.BaseInputConnection;
|
||||||
|
import android.view.inputmethod.EditorInfo;
|
||||||
|
import android.view.inputmethod.InputConnection;
|
||||||
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
import android.graphics.*;
|
||||||
|
import android.opengl.*;
|
||||||
|
import android.text.ClipboardManager;
|
||||||
|
import android.text.InputType;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import javax.microedition.khronos.egl.EGLConfig;
|
||||||
|
import javax.microedition.khronos.opengles.GL10;
|
||||||
|
import android.media.AudioManager;
|
||||||
|
import android.media.MediaScannerConnection;
|
||||||
|
import android.media.MediaScannerConnection.MediaScannerConnectionClient;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
public final class JuceAppActivity extends Activity
|
||||||
|
{
|
||||||
|
//==============================================================================
|
||||||
|
static
|
||||||
|
{
|
||||||
|
System.loadLibrary ("juce_jni");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void onCreate (Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate (savedInstanceState);
|
||||||
|
|
||||||
|
viewHolder = new ViewHolder (this);
|
||||||
|
setContentView (viewHolder);
|
||||||
|
|
||||||
|
setVolumeControlStream (AudioManager.STREAM_MUSIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final void onDestroy()
|
||||||
|
{
|
||||||
|
quitApp();
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final void onPause()
|
||||||
|
{
|
||||||
|
if (viewHolder != null)
|
||||||
|
viewHolder.onPause();
|
||||||
|
|
||||||
|
suspendApp();
|
||||||
|
super.onPause();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected final void onResume()
|
||||||
|
{
|
||||||
|
super.onResume();
|
||||||
|
|
||||||
|
if (viewHolder != null)
|
||||||
|
viewHolder.onResume();
|
||||||
|
|
||||||
|
resumeApp();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onConfigurationChanged (Configuration cfg)
|
||||||
|
{
|
||||||
|
super.onConfigurationChanged (cfg);
|
||||||
|
setContentView (viewHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void callAppLauncher()
|
||||||
|
{
|
||||||
|
launchApp (getApplicationInfo().publicSourceDir,
|
||||||
|
getApplicationInfo().dataDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
private native void launchApp (String appFile, String appDataDir);
|
||||||
|
private native void quitApp();
|
||||||
|
private native void suspendApp();
|
||||||
|
private native void resumeApp();
|
||||||
|
private native void setScreenSize (int screenWidth, int screenHeight, int dpi);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
public native void deliverMessage (long value);
|
||||||
|
private android.os.Handler messageHandler = new android.os.Handler();
|
||||||
|
|
||||||
|
public final void postMessage (long value)
|
||||||
|
{
|
||||||
|
messageHandler.post (new MessageCallback (value));
|
||||||
|
}
|
||||||
|
|
||||||
|
private final class MessageCallback implements Runnable
|
||||||
|
{
|
||||||
|
public MessageCallback (long value_) { value = value_; }
|
||||||
|
public final void run() { deliverMessage (value); }
|
||||||
|
|
||||||
|
private long value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
private ViewHolder viewHolder;
|
||||||
|
|
||||||
|
public final ComponentPeerView createNewView (boolean opaque, long host)
|
||||||
|
{
|
||||||
|
ComponentPeerView v = new ComponentPeerView (this, opaque, host);
|
||||||
|
viewHolder.addView (v);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void deleteView (ComponentPeerView view)
|
||||||
|
{
|
||||||
|
ViewGroup group = (ViewGroup) (view.getParent());
|
||||||
|
|
||||||
|
if (group != null)
|
||||||
|
group.removeView (view);
|
||||||
|
}
|
||||||
|
|
||||||
|
final class ViewHolder extends ViewGroup
|
||||||
|
{
|
||||||
|
public ViewHolder (Context context)
|
||||||
|
{
|
||||||
|
super (context);
|
||||||
|
setDescendantFocusability (ViewGroup.FOCUS_AFTER_DESCENDANTS);
|
||||||
|
setFocusable (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final void onLayout (boolean changed, int left, int top, int right, int bottom)
|
||||||
|
{
|
||||||
|
setScreenSize (getWidth(), getHeight(), getDPI());
|
||||||
|
|
||||||
|
if (isFirstResize)
|
||||||
|
{
|
||||||
|
isFirstResize = false;
|
||||||
|
callAppLauncher();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void onPause()
|
||||||
|
{
|
||||||
|
for (int i = getChildCount(); --i >= 0;)
|
||||||
|
{
|
||||||
|
View v = getChildAt (i);
|
||||||
|
|
||||||
|
if (v instanceof ComponentPeerView)
|
||||||
|
((ComponentPeerView) v).onPause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void onResume()
|
||||||
|
{
|
||||||
|
for (int i = getChildCount(); --i >= 0;)
|
||||||
|
{
|
||||||
|
View v = getChildAt (i);
|
||||||
|
|
||||||
|
if (v instanceof ComponentPeerView)
|
||||||
|
((ComponentPeerView) v).onResume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final int getDPI()
|
||||||
|
{
|
||||||
|
DisplayMetrics metrics = new DisplayMetrics();
|
||||||
|
getWindowManager().getDefaultDisplay().getMetrics (metrics);
|
||||||
|
return metrics.densityDpi;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isFirstResize = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void excludeClipRegion (android.graphics.Canvas canvas, float left, float top, float right, float bottom)
|
||||||
|
{
|
||||||
|
canvas.clipRect (left, top, right, bottom, android.graphics.Region.Op.DIFFERENCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
public final String getClipboardContent()
|
||||||
|
{
|
||||||
|
ClipboardManager clipboard = (ClipboardManager) getSystemService (CLIPBOARD_SERVICE);
|
||||||
|
return clipboard.getText().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setClipboardContent (String newText)
|
||||||
|
{
|
||||||
|
ClipboardManager clipboard = (ClipboardManager) getSystemService (CLIPBOARD_SERVICE);
|
||||||
|
clipboard.setText (newText);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
public final void showMessageBox (String title, String message, final long callback)
|
||||||
|
{
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder (this);
|
||||||
|
builder.setTitle (title)
|
||||||
|
.setMessage (message)
|
||||||
|
.setCancelable (true)
|
||||||
|
.setPositiveButton ("OK", new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
public void onClick (DialogInterface dialog, int id)
|
||||||
|
{
|
||||||
|
dialog.cancel();
|
||||||
|
JuceAppActivity.this.alertDismissed (callback, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.create().show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void showOkCancelBox (String title, String message, final long callback)
|
||||||
|
{
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder (this);
|
||||||
|
builder.setTitle (title)
|
||||||
|
.setMessage (message)
|
||||||
|
.setCancelable (true)
|
||||||
|
.setPositiveButton ("OK", new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
public void onClick (DialogInterface dialog, int id)
|
||||||
|
{
|
||||||
|
dialog.cancel();
|
||||||
|
JuceAppActivity.this.alertDismissed (callback, 1);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton ("Cancel", new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
public void onClick (DialogInterface dialog, int id)
|
||||||
|
{
|
||||||
|
dialog.cancel();
|
||||||
|
JuceAppActivity.this.alertDismissed (callback, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.create().show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void showYesNoCancelBox (String title, String message, final long callback)
|
||||||
|
{
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder (this);
|
||||||
|
builder.setTitle (title)
|
||||||
|
.setMessage (message)
|
||||||
|
.setCancelable (true)
|
||||||
|
.setPositiveButton ("Yes", new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
public void onClick (DialogInterface dialog, int id)
|
||||||
|
{
|
||||||
|
dialog.cancel();
|
||||||
|
JuceAppActivity.this.alertDismissed (callback, 1);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton ("No", new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
public void onClick (DialogInterface dialog, int id)
|
||||||
|
{
|
||||||
|
dialog.cancel();
|
||||||
|
JuceAppActivity.this.alertDismissed (callback, 2);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.setNeutralButton ("Cancel", new DialogInterface.OnClickListener()
|
||||||
|
{
|
||||||
|
public void onClick (DialogInterface dialog, int id)
|
||||||
|
{
|
||||||
|
dialog.cancel();
|
||||||
|
JuceAppActivity.this.alertDismissed (callback, 0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.create().show();
|
||||||
|
}
|
||||||
|
|
||||||
|
public native void alertDismissed (long callback, int id);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
public final class ComponentPeerView extends ViewGroup
|
||||||
|
implements View.OnFocusChangeListener
|
||||||
|
{
|
||||||
|
public ComponentPeerView (Context context, boolean opaque_, long host)
|
||||||
|
{
|
||||||
|
super (context);
|
||||||
|
this.host = host;
|
||||||
|
setWillNotDraw (false);
|
||||||
|
opaque = opaque_;
|
||||||
|
|
||||||
|
setFocusable (true);
|
||||||
|
setFocusableInTouchMode (true);
|
||||||
|
setOnFocusChangeListener (this);
|
||||||
|
requestFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
private native void handlePaint (long host, Canvas canvas);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDraw (Canvas canvas)
|
||||||
|
{
|
||||||
|
handlePaint (host, canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOpaque()
|
||||||
|
{
|
||||||
|
return opaque;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean opaque;
|
||||||
|
private long host;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
private native void handleMouseDown (long host, int index, float x, float y, long time);
|
||||||
|
private native void handleMouseDrag (long host, int index, float x, float y, long time);
|
||||||
|
private native void handleMouseUp (long host, int index, float x, float y, long time);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onTouchEvent (MotionEvent event)
|
||||||
|
{
|
||||||
|
int action = event.getAction();
|
||||||
|
long time = event.getEventTime();
|
||||||
|
|
||||||
|
switch (action & MotionEvent.ACTION_MASK)
|
||||||
|
{
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
handleMouseDown (host, event.getPointerId(0), event.getX(), event.getY(), time);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MotionEvent.ACTION_CANCEL:
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
|
handleMouseUp (host, event.getPointerId(0), event.getX(), event.getY(), time);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case MotionEvent.ACTION_MOVE:
|
||||||
|
{
|
||||||
|
int n = event.getPointerCount();
|
||||||
|
for (int i = 0; i < n; ++i)
|
||||||
|
handleMouseDrag (host, event.getPointerId(i), event.getX(i), event.getY(i), time);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MotionEvent.ACTION_POINTER_UP:
|
||||||
|
{
|
||||||
|
int i = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
|
||||||
|
handleMouseUp (host, event.getPointerId(i), event.getX(i), event.getY(i), time);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MotionEvent.ACTION_POINTER_DOWN:
|
||||||
|
{
|
||||||
|
int i = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
|
||||||
|
handleMouseDown (host, event.getPointerId(i), event.getX(i), event.getY(i), time);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
private native void handleKeyDown (long host, int keycode, int textchar);
|
||||||
|
private native void handleKeyUp (long host, int keycode, int textchar);
|
||||||
|
|
||||||
|
public void showKeyboard (String type)
|
||||||
|
{
|
||||||
|
InputMethodManager imm = (InputMethodManager) getSystemService (Context.INPUT_METHOD_SERVICE);
|
||||||
|
|
||||||
|
if (imm != null)
|
||||||
|
{
|
||||||
|
if (type.length() > 0)
|
||||||
|
{
|
||||||
|
imm.showSoftInput (this, android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT);
|
||||||
|
imm.setInputMethod (getWindowToken(), type);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
imm.hideSoftInputFromWindow (getWindowToken(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onKeyDown (int keyCode, KeyEvent event)
|
||||||
|
{
|
||||||
|
switch (keyCode)
|
||||||
|
{
|
||||||
|
case KeyEvent.KEYCODE_VOLUME_UP:
|
||||||
|
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
||||||
|
return super.onKeyDown (keyCode, event);
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleKeyDown (host, keyCode, event.getUnicodeChar());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onKeyUp (int keyCode, KeyEvent event)
|
||||||
|
{
|
||||||
|
handleKeyUp (host, keyCode, event.getUnicodeChar());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is here to make keyboard entry work on a Galaxy Tab2 10.1
|
||||||
|
@Override
|
||||||
|
public InputConnection onCreateInputConnection (EditorInfo outAttrs)
|
||||||
|
{
|
||||||
|
outAttrs.actionLabel = "";
|
||||||
|
outAttrs.hintText = "";
|
||||||
|
outAttrs.initialCapsMode = 0;
|
||||||
|
outAttrs.initialSelEnd = outAttrs.initialSelStart = -1;
|
||||||
|
outAttrs.label = "";
|
||||||
|
outAttrs.imeOptions = EditorInfo.IME_ACTION_DONE | EditorInfo.IME_FLAG_NO_EXTRACT_UI;
|
||||||
|
outAttrs.inputType = InputType.TYPE_NULL;
|
||||||
|
|
||||||
|
return new BaseInputConnection (this, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
@Override
|
||||||
|
protected void onSizeChanged (int w, int h, int oldw, int oldh)
|
||||||
|
{
|
||||||
|
super.onSizeChanged (w, h, oldw, oldh);
|
||||||
|
viewSizeChanged (host);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLayout (boolean changed, int left, int top, int right, int bottom)
|
||||||
|
{
|
||||||
|
for (int i = getChildCount(); --i >= 0;)
|
||||||
|
requestTransparentRegion (getChildAt (i));
|
||||||
|
}
|
||||||
|
|
||||||
|
private native void viewSizeChanged (long host);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFocusChange (View v, boolean hasFocus)
|
||||||
|
{
|
||||||
|
if (v == this)
|
||||||
|
focusChanged (host, hasFocus);
|
||||||
|
}
|
||||||
|
|
||||||
|
private native void focusChanged (long host, boolean hasFocus);
|
||||||
|
|
||||||
|
public void setViewName (String newName) {}
|
||||||
|
|
||||||
|
public boolean isVisible() { return getVisibility() == VISIBLE; }
|
||||||
|
public void setVisible (boolean b) { setVisibility (b ? VISIBLE : INVISIBLE); }
|
||||||
|
|
||||||
|
public boolean containsPoint (int x, int y)
|
||||||
|
{
|
||||||
|
return true; //xxx needs to check overlapping views
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void onPause()
|
||||||
|
{
|
||||||
|
for (int i = getChildCount(); --i >= 0;)
|
||||||
|
{
|
||||||
|
View v = getChildAt (i);
|
||||||
|
|
||||||
|
if (v instanceof OpenGLView)
|
||||||
|
((OpenGLView) v).onPause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void onResume()
|
||||||
|
{
|
||||||
|
for (int i = getChildCount(); --i >= 0;)
|
||||||
|
{
|
||||||
|
View v = getChildAt (i);
|
||||||
|
|
||||||
|
if (v instanceof OpenGLView)
|
||||||
|
((OpenGLView) v).onResume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpenGLView createGLView()
|
||||||
|
{
|
||||||
|
OpenGLView glView = new OpenGLView (getContext());
|
||||||
|
addView (glView);
|
||||||
|
return glView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
public final class OpenGLView extends GLSurfaceView
|
||||||
|
implements GLSurfaceView.Renderer
|
||||||
|
{
|
||||||
|
OpenGLView (Context context)
|
||||||
|
{
|
||||||
|
super (context);
|
||||||
|
setEGLContextClientVersion (2);
|
||||||
|
setRenderer (this);
|
||||||
|
setRenderMode (RENDERMODE_WHEN_DIRTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSurfaceCreated (GL10 unused, EGLConfig config)
|
||||||
|
{
|
||||||
|
contextCreated();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSurfaceChanged (GL10 unused, int width, int height)
|
||||||
|
{
|
||||||
|
contextChangedSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDrawFrame (GL10 unused)
|
||||||
|
{
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
|
private native void contextCreated();
|
||||||
|
private native void contextChangedSize();
|
||||||
|
private native void render();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
public final int[] renderGlyph (char glyph, Paint paint, android.graphics.Matrix matrix, Rect bounds)
|
||||||
|
{
|
||||||
|
Path p = new Path();
|
||||||
|
paint.getTextPath (String.valueOf (glyph), 0, 1, 0.0f, 0.0f, p);
|
||||||
|
|
||||||
|
RectF boundsF = new RectF();
|
||||||
|
p.computeBounds (boundsF, true);
|
||||||
|
matrix.mapRect (boundsF);
|
||||||
|
|
||||||
|
boundsF.roundOut (bounds);
|
||||||
|
bounds.left--;
|
||||||
|
bounds.right++;
|
||||||
|
|
||||||
|
final int w = bounds.width();
|
||||||
|
final int h = Math.max (1, bounds.height());
|
||||||
|
|
||||||
|
Bitmap bm = Bitmap.createBitmap (w, h, Bitmap.Config.ARGB_8888);
|
||||||
|
|
||||||
|
Canvas c = new Canvas (bm);
|
||||||
|
matrix.postTranslate (-bounds.left, -bounds.top);
|
||||||
|
c.setMatrix (matrix);
|
||||||
|
c.drawPath (p, paint);
|
||||||
|
|
||||||
|
final int sizeNeeded = w * h;
|
||||||
|
if (cachedRenderArray.length < sizeNeeded)
|
||||||
|
cachedRenderArray = new int [sizeNeeded];
|
||||||
|
|
||||||
|
bm.getPixels (cachedRenderArray, 0, w, 0, 0, w, h);
|
||||||
|
bm.recycle();
|
||||||
|
return cachedRenderArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] cachedRenderArray = new int [256];
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
public static class HTTPStream
|
||||||
|
{
|
||||||
|
public HTTPStream (HttpURLConnection connection_,
|
||||||
|
int[] statusCode, StringBuffer responseHeaders) throws IOException
|
||||||
|
{
|
||||||
|
connection = connection_;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
inputStream = new BufferedInputStream (connection.getInputStream());
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
if (connection.getResponseCode() < org.apache.http.HttpStatus.SC_BAD_REQUEST)
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
statusCode[0] = connection.getResponseCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (statusCode[0] >= org.apache.http.HttpStatus.SC_BAD_REQUEST)
|
||||||
|
inputStream = connection.getErrorStream();
|
||||||
|
else
|
||||||
|
inputStream = connection.getInputStream();
|
||||||
|
|
||||||
|
for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet())
|
||||||
|
if (entry.getKey() != null && entry.getValue() != null)
|
||||||
|
responseHeaders.append (entry.getKey() + ": "
|
||||||
|
+ android.text.TextUtils.join (",", entry.getValue()) + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void release()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
inputStream.close();
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{}
|
||||||
|
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int read (byte[] buffer, int numBytes)
|
||||||
|
{
|
||||||
|
int num = 0;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
num = inputStream.read (buffer, 0, numBytes);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{}
|
||||||
|
|
||||||
|
if (num > 0)
|
||||||
|
position += num;
|
||||||
|
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final long getPosition() { return position; }
|
||||||
|
public final long getTotalLength() { return -1; }
|
||||||
|
public final boolean isExhausted() { return false; }
|
||||||
|
public final boolean setPosition (long newPos) { return false; }
|
||||||
|
|
||||||
|
private HttpURLConnection connection;
|
||||||
|
private InputStream inputStream;
|
||||||
|
private long position;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final HTTPStream createHTTPStream (String address,
|
||||||
|
boolean isPost, byte[] postData, String headers,
|
||||||
|
int timeOutMs, int[] statusCode,
|
||||||
|
StringBuffer responseHeaders)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) (new URL(address)
|
||||||
|
.openConnection());
|
||||||
|
if (connection != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (isPost)
|
||||||
|
{
|
||||||
|
connection.setRequestMethod("POST");
|
||||||
|
connection.setConnectTimeout(timeOutMs);
|
||||||
|
connection.setDoOutput(true);
|
||||||
|
connection.setChunkedStreamingMode(0);
|
||||||
|
OutputStream out = connection.getOutputStream();
|
||||||
|
out.write(postData);
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new HTTPStream (connection, statusCode, responseHeaders);
|
||||||
|
}
|
||||||
|
catch (Throwable e)
|
||||||
|
{
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Throwable e) {}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void launchURL (String url)
|
||||||
|
{
|
||||||
|
startActivity (new Intent (Intent.ACTION_VIEW, Uri.parse (url)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String getLocaleValue (boolean isRegion)
|
||||||
|
{
|
||||||
|
java.util.Locale locale = java.util.Locale.getDefault();
|
||||||
|
|
||||||
|
return isRegion ? locale.getDisplayCountry (java.util.Locale.US)
|
||||||
|
: locale.getDisplayLanguage (java.util.Locale.US);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
private final class SingleMediaScanner implements MediaScannerConnectionClient
|
||||||
|
{
|
||||||
|
public SingleMediaScanner (Context context, String filename)
|
||||||
|
{
|
||||||
|
file = filename;
|
||||||
|
msc = new MediaScannerConnection (context, this);
|
||||||
|
msc.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMediaScannerConnected()
|
||||||
|
{
|
||||||
|
msc.scanFile (file, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onScanCompleted (String path, Uri uri)
|
||||||
|
{
|
||||||
|
msc.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
private MediaScannerConnection msc;
|
||||||
|
private String file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void scanFile (String filename)
|
||||||
|
{
|
||||||
|
new SingleMediaScanner (this, filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,223 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_BASICNATIVEHEADERS_H_INCLUDED
|
||||||
|
#define JUCE_BASICNATIVEHEADERS_H_INCLUDED
|
||||||
|
|
||||||
|
#include "../system/juce_TargetPlatform.h"
|
||||||
|
#undef T
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if JUCE_MAC || JUCE_IOS
|
||||||
|
|
||||||
|
#if JUCE_IOS
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import <CoreData/CoreData.h>
|
||||||
|
#import <MobileCoreServices/MobileCoreServices.h>
|
||||||
|
#include <sys/fcntl.h>
|
||||||
|
#else
|
||||||
|
#define Point CarbonDummyPointName
|
||||||
|
#define Component CarbonDummyCompName
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <CoreAudio/HostTime.h>
|
||||||
|
#undef Point
|
||||||
|
#undef Component
|
||||||
|
#include <sys/dir.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <utime.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#include <net/if_dl.h>
|
||||||
|
#include <mach/mach_time.h>
|
||||||
|
#include <mach-o/dyld.h>
|
||||||
|
#include <objc/runtime.h>
|
||||||
|
#include <objc/objc.h>
|
||||||
|
#include <objc/message.h>
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#elif JUCE_WINDOWS
|
||||||
|
#if JUCE_MSVC
|
||||||
|
#ifndef _CPPRTTI
|
||||||
|
#error "You're compiling without RTTI enabled! This is needed for a lot of JUCE classes, please update your compiler settings!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _CPPUNWIND
|
||||||
|
#error "You're compiling without exceptions enabled! This is needed for a lot of JUCE classes, please update your compiler settings!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma warning (push)
|
||||||
|
#pragma warning (disable : 4100 4201 4514 4312 4995)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define STRICT 1
|
||||||
|
#define WIN32_LEAN_AND_MEAN 1
|
||||||
|
#if JUCE_MINGW
|
||||||
|
#define _WIN32_WINNT 0x0501
|
||||||
|
#else
|
||||||
|
#define _WIN32_WINNT 0x0600
|
||||||
|
#endif
|
||||||
|
#define _UNICODE 1
|
||||||
|
#define UNICODE 1
|
||||||
|
#ifndef _WIN32_IE
|
||||||
|
#define _WIN32_IE 0x0500
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include <shellapi.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <ctime>
|
||||||
|
#include <wininet.h>
|
||||||
|
#include <nb30.h>
|
||||||
|
#include <iphlpapi.h>
|
||||||
|
#include <mapi.h>
|
||||||
|
#include <float.h>
|
||||||
|
#include <process.h>
|
||||||
|
#include <shlobj.h>
|
||||||
|
#include <shlwapi.h>
|
||||||
|
#include <mmsystem.h>
|
||||||
|
|
||||||
|
#if JUCE_MINGW
|
||||||
|
#include <basetyps.h>
|
||||||
|
#else
|
||||||
|
#include <crtdbg.h>
|
||||||
|
#include <comutil.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef PACKED
|
||||||
|
|
||||||
|
#if JUCE_MSVC
|
||||||
|
#pragma warning (pop)
|
||||||
|
#pragma warning (4: 4511 4512 4100 /*4365*/) // (enable some warnings that are turned off in VC8)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JUCE_MSVC && ! JUCE_DONT_AUTOLINK_TO_WIN32_LIBRARIES
|
||||||
|
#pragma comment (lib, "kernel32.lib")
|
||||||
|
#pragma comment (lib, "user32.lib")
|
||||||
|
#pragma comment (lib, "wininet.lib")
|
||||||
|
#pragma comment (lib, "advapi32.lib")
|
||||||
|
#pragma comment (lib, "ws2_32.lib")
|
||||||
|
#pragma comment (lib, "version.lib")
|
||||||
|
#pragma comment (lib, "shlwapi.lib")
|
||||||
|
#pragma comment (lib, "winmm.lib")
|
||||||
|
|
||||||
|
#ifdef _NATIVE_WCHAR_T_DEFINED
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#pragma comment (lib, "comsuppwd.lib")
|
||||||
|
#else
|
||||||
|
#pragma comment (lib, "comsuppw.lib")
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#pragma comment (lib, "comsuppd.lib")
|
||||||
|
#else
|
||||||
|
#pragma comment (lib, "comsupp.lib")
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Used with DynamicLibrary to simplify importing functions from a win32 DLL.
|
||||||
|
|
||||||
|
dll: the DynamicLibrary object
|
||||||
|
functionName: function to import
|
||||||
|
localFunctionName: name you want to use to actually call it (must be different)
|
||||||
|
returnType: the return type
|
||||||
|
params: list of params (bracketed)
|
||||||
|
*/
|
||||||
|
#define JUCE_LOAD_WINAPI_FUNCTION(dll, functionName, localFunctionName, returnType, params) \
|
||||||
|
typedef returnType (WINAPI *type##localFunctionName) params; \
|
||||||
|
type##localFunctionName localFunctionName = (type##localFunctionName) dll.getFunction (#functionName);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#elif JUCE_LINUX
|
||||||
|
#include <sched.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/dir.h>
|
||||||
|
#include <sys/ptrace.h>
|
||||||
|
#include <sys/vfs.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <utime.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <sys/sysinfo.h>
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#elif JUCE_ANDROID
|
||||||
|
#include <jni.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <utime.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/statfs.h>
|
||||||
|
#include <sys/ptrace.h>
|
||||||
|
#include <sys/sysinfo.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <fnmatch.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Need to clear various moronic redefinitions made by system headers..
|
||||||
|
#undef max
|
||||||
|
#undef min
|
||||||
|
#undef direct
|
||||||
|
#undef check
|
||||||
|
|
||||||
|
#endif // JUCE_BASICNATIVEHEADERS_H_INCLUDED
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool File::isOnCDRomDrive() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isOnHardDisk() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isOnRemovableDrive() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String File::getVersion() const
|
||||||
|
{
|
||||||
|
return String::empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
File File::getSpecialLocation (const SpecialLocationType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case userHomeDirectory:
|
||||||
|
case userDocumentsDirectory:
|
||||||
|
case userMusicDirectory:
|
||||||
|
case userMoviesDirectory:
|
||||||
|
case userPicturesDirectory:
|
||||||
|
case userApplicationDataDirectory:
|
||||||
|
case userDesktopDirectory:
|
||||||
|
return File (android.appDataDir);
|
||||||
|
|
||||||
|
case commonApplicationDataDirectory:
|
||||||
|
case commonDocumentsDirectory:
|
||||||
|
return File (android.appDataDir);
|
||||||
|
|
||||||
|
case globalApplicationsDirectory:
|
||||||
|
return File ("/system/app");
|
||||||
|
|
||||||
|
case tempDirectory:
|
||||||
|
return File (android.appDataDir).getChildFile (".temp");
|
||||||
|
|
||||||
|
case invokedExecutableFile:
|
||||||
|
case currentExecutableFile:
|
||||||
|
case currentApplicationFile:
|
||||||
|
case hostApplicationPath:
|
||||||
|
return juce_getExecutableFile();
|
||||||
|
|
||||||
|
default:
|
||||||
|
jassertfalse; // unknown type?
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return File();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::moveToTrash() const
|
||||||
|
{
|
||||||
|
if (! exists())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JUCE_API bool JUCE_CALLTYPE Process::openDocument (const String& fileName, const String& parameters)
|
||||||
|
{
|
||||||
|
const LocalRef<jstring> t (javaString (fileName));
|
||||||
|
android.activity.callVoidMethod (JuceAppActivity.launchURL, t.get());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::revealToUser() const
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,428 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JUCE_ANDROID_JNIHELPERS_H_INCLUDED
|
||||||
|
#define JUCE_ANDROID_JNIHELPERS_H_INCLUDED
|
||||||
|
|
||||||
|
#if ! (defined (JUCE_ANDROID_ACTIVITY_CLASSNAME) && defined (JUCE_ANDROID_ACTIVITY_CLASSPATH))
|
||||||
|
#error "The JUCE_ANDROID_ACTIVITY_CLASSNAME and JUCE_ANDROID_ACTIVITY_CLASSPATH macros must be set!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
extern JNIEnv* getEnv() noexcept;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class GlobalRef
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline GlobalRef() noexcept : obj (0) {}
|
||||||
|
inline explicit GlobalRef (jobject o) : obj (retain (o)) {}
|
||||||
|
inline GlobalRef (const GlobalRef& other) : obj (retain (other.obj)) {}
|
||||||
|
~GlobalRef() { clear(); }
|
||||||
|
|
||||||
|
inline void clear()
|
||||||
|
{
|
||||||
|
if (obj != 0)
|
||||||
|
{
|
||||||
|
getEnv()->DeleteGlobalRef (obj);
|
||||||
|
obj = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline GlobalRef& operator= (const GlobalRef& other)
|
||||||
|
{
|
||||||
|
jobject newObj = retain (other.obj);
|
||||||
|
clear();
|
||||||
|
obj = newObj;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
inline operator jobject() const noexcept { return obj; }
|
||||||
|
inline jobject get() const noexcept { return obj; }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#define DECLARE_CALL_TYPE_METHOD(returnType, typeName) \
|
||||||
|
returnType call##typeName##Method (jmethodID methodID, ... ) const \
|
||||||
|
{ \
|
||||||
|
va_list args; \
|
||||||
|
va_start (args, methodID); \
|
||||||
|
returnType result = getEnv()->Call##typeName##MethodV (obj, methodID, args); \
|
||||||
|
va_end (args); \
|
||||||
|
return result; \
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_CALL_TYPE_METHOD (jobject, Object)
|
||||||
|
DECLARE_CALL_TYPE_METHOD (jboolean, Boolean)
|
||||||
|
DECLARE_CALL_TYPE_METHOD (jbyte, Byte)
|
||||||
|
DECLARE_CALL_TYPE_METHOD (jchar, Char)
|
||||||
|
DECLARE_CALL_TYPE_METHOD (jshort, Short)
|
||||||
|
DECLARE_CALL_TYPE_METHOD (jint, Int)
|
||||||
|
DECLARE_CALL_TYPE_METHOD (jlong, Long)
|
||||||
|
DECLARE_CALL_TYPE_METHOD (jfloat, Float)
|
||||||
|
DECLARE_CALL_TYPE_METHOD (jdouble, Double)
|
||||||
|
#undef DECLARE_CALL_TYPE_METHOD
|
||||||
|
|
||||||
|
void callVoidMethod (jmethodID methodID, ... ) const
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start (args, methodID);
|
||||||
|
getEnv()->CallVoidMethodV (obj, methodID, args);
|
||||||
|
va_end (args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
jobject obj;
|
||||||
|
|
||||||
|
static inline jobject retain (jobject obj)
|
||||||
|
{
|
||||||
|
return obj == 0 ? 0 : getEnv()->NewGlobalRef (obj);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
template <typename JavaType>
|
||||||
|
class LocalRef
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit inline LocalRef (JavaType o) noexcept : obj (o) {}
|
||||||
|
inline LocalRef (const LocalRef& other) noexcept : obj (retain (other.obj)) {}
|
||||||
|
~LocalRef() { clear(); }
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
if (obj != 0)
|
||||||
|
getEnv()->DeleteLocalRef (obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalRef& operator= (const LocalRef& other)
|
||||||
|
{
|
||||||
|
jobject newObj = retain (other.obj);
|
||||||
|
clear();
|
||||||
|
obj = newObj;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline operator JavaType() const noexcept { return obj; }
|
||||||
|
inline JavaType get() const noexcept { return obj; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
JavaType obj;
|
||||||
|
|
||||||
|
static JavaType retain (JavaType obj)
|
||||||
|
{
|
||||||
|
return obj == 0 ? 0 : (JavaType) getEnv()->NewLocalRef (obj);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
String juceString (JNIEnv* env, jstring s)
|
||||||
|
{
|
||||||
|
const char* const utf8 = env->GetStringUTFChars (s, nullptr);
|
||||||
|
CharPointer_UTF8 utf8CP (utf8);
|
||||||
|
const String result (utf8CP);
|
||||||
|
env->ReleaseStringUTFChars (s, utf8);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String juceString (jstring s)
|
||||||
|
{
|
||||||
|
return juceString (getEnv(), s);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalRef<jstring> javaString (const String& s)
|
||||||
|
{
|
||||||
|
return LocalRef<jstring> (getEnv()->NewStringUTF (s.toUTF8()));
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalRef<jstring> javaStringFromChar (const juce_wchar c)
|
||||||
|
{
|
||||||
|
char utf8[8] = { 0 };
|
||||||
|
CharPointer_UTF8 (utf8).write (c);
|
||||||
|
return LocalRef<jstring> (getEnv()->NewStringUTF (utf8));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class JNIClassBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit JNIClassBase (const char* classPath);
|
||||||
|
virtual ~JNIClassBase();
|
||||||
|
|
||||||
|
inline operator jclass() const noexcept { return classRef; }
|
||||||
|
|
||||||
|
static void initialiseAllClasses (JNIEnv*);
|
||||||
|
static void releaseAllClasses (JNIEnv*);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void initialiseFields (JNIEnv*) = 0;
|
||||||
|
|
||||||
|
jmethodID resolveMethod (JNIEnv*, const char* methodName, const char* params);
|
||||||
|
jmethodID resolveStaticMethod (JNIEnv*, const char* methodName, const char* params);
|
||||||
|
jfieldID resolveField (JNIEnv*, const char* fieldName, const char* signature);
|
||||||
|
jfieldID resolveStaticField (JNIEnv*, const char* fieldName, const char* signature);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* const classPath;
|
||||||
|
jclass classRef;
|
||||||
|
|
||||||
|
static Array<JNIClassBase*>& getClasses();
|
||||||
|
void initialise (JNIEnv*);
|
||||||
|
void release (JNIEnv*);
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (JNIClassBase)
|
||||||
|
};
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#define CREATE_JNI_METHOD(methodID, stringName, params) methodID = resolveMethod (env, stringName, params);
|
||||||
|
#define CREATE_JNI_STATICMETHOD(methodID, stringName, params) methodID = resolveStaticMethod (env, stringName, params);
|
||||||
|
#define CREATE_JNI_FIELD(fieldID, stringName, signature) fieldID = resolveField (env, stringName, signature);
|
||||||
|
#define CREATE_JNI_STATICFIELD(fieldID, stringName, signature) fieldID = resolveStaticField (env, stringName, signature);
|
||||||
|
#define DECLARE_JNI_METHOD(methodID, stringName, params) jmethodID methodID;
|
||||||
|
#define DECLARE_JNI_FIELD(fieldID, stringName, signature) jfieldID fieldID;
|
||||||
|
|
||||||
|
#define DECLARE_JNI_CLASS(CppClassName, javaPath) \
|
||||||
|
class CppClassName ## _Class : public JNIClassBase \
|
||||||
|
{ \
|
||||||
|
public: \
|
||||||
|
CppClassName ## _Class() : JNIClassBase (javaPath) {} \
|
||||||
|
\
|
||||||
|
void initialiseFields (JNIEnv* env) \
|
||||||
|
{ \
|
||||||
|
JNI_CLASS_MEMBERS (CREATE_JNI_METHOD, CREATE_JNI_STATICMETHOD, CREATE_JNI_FIELD, CREATE_JNI_STATICFIELD); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
JNI_CLASS_MEMBERS (DECLARE_JNI_METHOD, DECLARE_JNI_METHOD, DECLARE_JNI_FIELD, DECLARE_JNI_FIELD); \
|
||||||
|
}; \
|
||||||
|
static CppClassName ## _Class CppClassName;
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#define JUCE_JNI_CALLBACK(className, methodName, returnType, params) \
|
||||||
|
extern "C" __attribute__ ((visibility("default"))) returnType JUCE_JOIN_MACRO (JUCE_JOIN_MACRO (Java_, className), _ ## methodName) params
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class AndroidSystem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AndroidSystem();
|
||||||
|
|
||||||
|
void initialise (JNIEnv*, jobject activity, jstring appFile, jstring appDataDir);
|
||||||
|
void shutdown (JNIEnv*);
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
GlobalRef activity;
|
||||||
|
String appFile, appDataDir;
|
||||||
|
int screenWidth, screenHeight, dpi;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern AndroidSystem android;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class ThreadLocalJNIEnvHolder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ThreadLocalJNIEnvHolder() noexcept
|
||||||
|
: jvm (nullptr)
|
||||||
|
{
|
||||||
|
zeromem (threads, sizeof (threads));
|
||||||
|
zeromem (envs, sizeof (envs));
|
||||||
|
}
|
||||||
|
|
||||||
|
void initialise (JNIEnv* env)
|
||||||
|
{
|
||||||
|
// NB: the DLL can be left loaded by the JVM, so the same static
|
||||||
|
// objects can end up being reused by subsequent runs of the app
|
||||||
|
zeromem (threads, sizeof (threads));
|
||||||
|
zeromem (envs, sizeof (envs));
|
||||||
|
|
||||||
|
env->GetJavaVM (&jvm);
|
||||||
|
addEnv (env);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEnv* attach() noexcept
|
||||||
|
{
|
||||||
|
if (android.activity != nullptr)
|
||||||
|
{
|
||||||
|
if (JNIEnv* env = attachToCurrentThread())
|
||||||
|
{
|
||||||
|
SpinLock::ScopedLockType sl (addRemoveLock);
|
||||||
|
return addEnv (env);
|
||||||
|
}
|
||||||
|
|
||||||
|
jassertfalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void detach() noexcept
|
||||||
|
{
|
||||||
|
if (android.activity != nullptr)
|
||||||
|
{
|
||||||
|
jvm->DetachCurrentThread();
|
||||||
|
|
||||||
|
const pthread_t thisThread = pthread_self();
|
||||||
|
|
||||||
|
SpinLock::ScopedLockType sl (addRemoveLock);
|
||||||
|
for (int i = 0; i < maxThreads; ++i)
|
||||||
|
if (threads[i] == thisThread)
|
||||||
|
threads[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEnv* getOrAttach() noexcept
|
||||||
|
{
|
||||||
|
if (JNIEnv* env = get())
|
||||||
|
return env;
|
||||||
|
|
||||||
|
SpinLock::ScopedLockType sl (addRemoveLock);
|
||||||
|
|
||||||
|
if (JNIEnv* env = get())
|
||||||
|
return env;
|
||||||
|
|
||||||
|
if (JNIEnv* env = attachToCurrentThread())
|
||||||
|
return addEnv (env);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
JavaVM* jvm;
|
||||||
|
enum { maxThreads = 32 };
|
||||||
|
pthread_t threads [maxThreads];
|
||||||
|
JNIEnv* envs [maxThreads];
|
||||||
|
SpinLock addRemoveLock;
|
||||||
|
|
||||||
|
JNIEnv* addEnv (JNIEnv* env) noexcept
|
||||||
|
{
|
||||||
|
const pthread_t thisThread = pthread_self();
|
||||||
|
|
||||||
|
for (int i = 0; i < maxThreads; ++i)
|
||||||
|
{
|
||||||
|
if (threads[i] == 0)
|
||||||
|
{
|
||||||
|
envs[i] = env;
|
||||||
|
threads[i] = thisThread;
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jassertfalse; // too many threads!
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEnv* get() const noexcept
|
||||||
|
{
|
||||||
|
const pthread_t thisThread = pthread_self();
|
||||||
|
|
||||||
|
for (int i = 0; i < maxThreads; ++i)
|
||||||
|
if (threads[i] == thisThread)
|
||||||
|
return envs[i];
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEnv* attachToCurrentThread()
|
||||||
|
{
|
||||||
|
JNIEnv* env = nullptr;
|
||||||
|
jvm->AttachCurrentThread (&env, nullptr);
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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;") \
|
||||||
|
METHOD (deleteView, "deleteView", "(L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$ComponentPeerView;)V") \
|
||||||
|
METHOD (postMessage, "postMessage", "(J)V") \
|
||||||
|
METHOD (finish, "finish", "()V") \
|
||||||
|
METHOD (getClipboardContent, "getClipboardContent", "()Ljava/lang/String;") \
|
||||||
|
METHOD (setClipboardContent, "setClipboardContent", "(Ljava/lang/String;)V") \
|
||||||
|
METHOD (excludeClipRegion, "excludeClipRegion", "(Landroid/graphics/Canvas;FFFF)V") \
|
||||||
|
METHOD (renderGlyph, "renderGlyph", "(CLandroid/graphics/Paint;Landroid/graphics/Matrix;Landroid/graphics/Rect;)[I") \
|
||||||
|
STATICMETHOD (createHTTPStream, "createHTTPStream", "(Ljava/lang/String;Z[BLjava/lang/String;I[ILjava/lang/StringBuffer;)L" JUCE_ANDROID_ACTIVITY_CLASSPATH "$HTTPStream;") \
|
||||||
|
METHOD (launchURL, "launchURL", "(Ljava/lang/String;)V") \
|
||||||
|
METHOD (showMessageBox, "showMessageBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \
|
||||||
|
METHOD (showOkCancelBox, "showOkCancelBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \
|
||||||
|
METHOD (showYesNoCancelBox, "showYesNoCancelBox", "(Ljava/lang/String;Ljava/lang/String;J)V") \
|
||||||
|
STATICMETHOD (getLocaleValue, "getLocaleValue", "(Z)Ljava/lang/String;") \
|
||||||
|
METHOD (scanFile, "scanFile", "(Ljava/lang/String;)V")
|
||||||
|
|
||||||
|
DECLARE_JNI_CLASS (JuceAppActivity, JUCE_ANDROID_ACTIVITY_CLASSPATH);
|
||||||
|
#undef JNI_CLASS_MEMBERS
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||||
|
METHOD (constructor, "<init>", "(I)V") \
|
||||||
|
METHOD (setColor, "setColor", "(I)V") \
|
||||||
|
METHOD (setAlpha, "setAlpha", "(I)V") \
|
||||||
|
METHOD (setTypeface, "setTypeface", "(Landroid/graphics/Typeface;)Landroid/graphics/Typeface;") \
|
||||||
|
METHOD (ascent, "ascent", "()F") \
|
||||||
|
METHOD (descent, "descent", "()F") \
|
||||||
|
METHOD (setTextSize, "setTextSize", "(F)V") \
|
||||||
|
METHOD (getTextWidths, "getTextWidths", "(Ljava/lang/String;[F)I") \
|
||||||
|
METHOD (setTextScaleX, "setTextScaleX", "(F)V") \
|
||||||
|
METHOD (getTextPath, "getTextPath", "(Ljava/lang/String;IIFFLandroid/graphics/Path;)V") \
|
||||||
|
METHOD (setShader, "setShader", "(Landroid/graphics/Shader;)Landroid/graphics/Shader;") \
|
||||||
|
|
||||||
|
DECLARE_JNI_CLASS (Paint, "android/graphics/Paint");
|
||||||
|
#undef JNI_CLASS_MEMBERS
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||||
|
METHOD (constructor, "<init>", "()V") \
|
||||||
|
METHOD (setValues, "setValues", "([F)V") \
|
||||||
|
|
||||||
|
DECLARE_JNI_CLASS (Matrix, "android/graphics/Matrix");
|
||||||
|
#undef JNI_CLASS_MEMBERS
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||||
|
METHOD (constructor, "<init>", "(IIII)V") \
|
||||||
|
FIELD (left, "left", "I") \
|
||||||
|
FIELD (right, "right", "I") \
|
||||||
|
FIELD (top, "top", "I") \
|
||||||
|
FIELD (bottom, "bottom", "I") \
|
||||||
|
|
||||||
|
DECLARE_JNI_CLASS (RectClass, "android/graphics/Rect");
|
||||||
|
#undef JNI_CLASS_MEMBERS
|
||||||
|
|
||||||
|
#endif // JUCE_ANDROID_JNIHELPERS_H_INCLUDED
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
void Logger::outputDebugString (const String& text)
|
||||||
|
{
|
||||||
|
__android_log_print (ANDROID_LOG_INFO, "JUCE", "%s", text.toUTF8().getAddress());
|
||||||
|
}
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||||
|
METHOD (constructor, "<init>", "()V") \
|
||||||
|
METHOD (toString, "toString", "()Ljava/lang/String;") \
|
||||||
|
|
||||||
|
DECLARE_JNI_CLASS (StringBuffer, "java/lang/StringBuffer");
|
||||||
|
#undef JNI_CLASS_MEMBERS
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||||
|
METHOD (release, "release", "()V") \
|
||||||
|
METHOD (read, "read", "([BI)I") \
|
||||||
|
METHOD (getPosition, "getPosition", "()J") \
|
||||||
|
METHOD (getTotalLength, "getTotalLength", "()J") \
|
||||||
|
METHOD (isExhausted, "isExhausted", "()Z") \
|
||||||
|
METHOD (setPosition, "setPosition", "(J)Z") \
|
||||||
|
|
||||||
|
DECLARE_JNI_CLASS (HTTPStream, JUCE_ANDROID_ACTIVITY_CLASSPATH "$HTTPStream");
|
||||||
|
#undef JNI_CLASS_MEMBERS
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void MACAddress::findAllAddresses (Array<MACAddress>& result)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JUCE_API bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& targetEmailAddress,
|
||||||
|
const String& emailSubject,
|
||||||
|
const String& bodyText,
|
||||||
|
const StringArray& filesToAttach)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class WebInputStream : public InputStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WebInputStream (String address, bool isPost, const MemoryBlock& postData,
|
||||||
|
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||||
|
const String& headers, int timeOutMs, StringPairArray* responseHeaders)
|
||||||
|
: statusCode (0)
|
||||||
|
{
|
||||||
|
if (! address.contains ("://"))
|
||||||
|
address = "http://" + address;
|
||||||
|
|
||||||
|
JNIEnv* env = getEnv();
|
||||||
|
|
||||||
|
jbyteArray postDataArray = 0;
|
||||||
|
|
||||||
|
if (postData.getSize() > 0)
|
||||||
|
{
|
||||||
|
postDataArray = env->NewByteArray (postData.getSize());
|
||||||
|
env->SetByteArrayRegion (postDataArray, 0, postData.getSize(), (const jbyte*) postData.getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalRef<jobject> responseHeaderBuffer (env->NewObject (StringBuffer, StringBuffer.constructor));
|
||||||
|
|
||||||
|
// Annoyingly, the android HTTP functions will choke on this call if you try to do it on the message
|
||||||
|
// thread. You'll need to move your networking code to a background thread to keep it happy..
|
||||||
|
jassert (Thread::getCurrentThread() != nullptr);
|
||||||
|
|
||||||
|
jintArray statusCodeArray = env->NewIntArray (1);
|
||||||
|
jassert (statusCodeArray != 0);
|
||||||
|
|
||||||
|
stream = GlobalRef (env->CallStaticObjectMethod (JuceAppActivity,
|
||||||
|
JuceAppActivity.createHTTPStream,
|
||||||
|
javaString (address).get(),
|
||||||
|
(jboolean) isPost,
|
||||||
|
postDataArray,
|
||||||
|
javaString (headers).get(),
|
||||||
|
(jint) timeOutMs,
|
||||||
|
statusCodeArray,
|
||||||
|
responseHeaderBuffer.get()));
|
||||||
|
|
||||||
|
jint* const statusCodeElements = env->GetIntArrayElements (statusCodeArray, 0);
|
||||||
|
statusCode = statusCodeElements[0];
|
||||||
|
env->ReleaseIntArrayElements (statusCodeArray, statusCodeElements, 0);
|
||||||
|
env->DeleteLocalRef (statusCodeArray);
|
||||||
|
|
||||||
|
if (postDataArray != 0)
|
||||||
|
env->DeleteLocalRef (postDataArray);
|
||||||
|
|
||||||
|
if (stream != 0)
|
||||||
|
{
|
||||||
|
StringArray headerLines;
|
||||||
|
|
||||||
|
{
|
||||||
|
LocalRef<jstring> headersString ((jstring) env->CallObjectMethod (responseHeaderBuffer.get(),
|
||||||
|
StringBuffer.toString));
|
||||||
|
headerLines.addLines (juceString (env, headersString));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (responseHeaders != 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < headerLines.size(); ++i)
|
||||||
|
{
|
||||||
|
const String& header = headerLines[i];
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~WebInputStream()
|
||||||
|
{
|
||||||
|
if (stream != 0)
|
||||||
|
stream.callVoidMethod (HTTPStream.release);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool isError() const { return stream == nullptr; }
|
||||||
|
|
||||||
|
bool isExhausted() override { return stream != nullptr && stream.callBooleanMethod (HTTPStream.isExhausted); }
|
||||||
|
int64 getTotalLength() override { return stream != nullptr ? stream.callLongMethod (HTTPStream.getTotalLength) : 0; }
|
||||||
|
int64 getPosition() override { return stream != nullptr ? stream.callLongMethod (HTTPStream.getPosition) : 0; }
|
||||||
|
bool setPosition (int64 wantedPos) override { return stream != nullptr && stream.callBooleanMethod (HTTPStream.setPosition, (jlong) wantedPos); }
|
||||||
|
|
||||||
|
int read (void* buffer, int bytesToRead) override
|
||||||
|
{
|
||||||
|
jassert (buffer != nullptr && bytesToRead >= 0);
|
||||||
|
|
||||||
|
if (stream == nullptr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
JNIEnv* env = getEnv();
|
||||||
|
|
||||||
|
jbyteArray javaArray = env->NewByteArray (bytesToRead);
|
||||||
|
|
||||||
|
int numBytes = stream.callIntMethod (HTTPStream.read, javaArray, (jint) bytesToRead);
|
||||||
|
|
||||||
|
if (numBytes > 0)
|
||||||
|
env->GetByteArrayRegion (javaArray, 0, numBytes, static_cast<jbyte*> (buffer));
|
||||||
|
|
||||||
|
env->DeleteLocalRef (javaArray);
|
||||||
|
return numBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
GlobalRef stream;
|
||||||
|
int statusCode;
|
||||||
|
|
||||||
|
private:
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
|
||||||
|
};
|
||||||
@@ -0,0 +1,315 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
JNIClassBase::JNIClassBase (const char* cp) : classPath (cp), classRef (0)
|
||||||
|
{
|
||||||
|
getClasses().add (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIClassBase::~JNIClassBase()
|
||||||
|
{
|
||||||
|
getClasses().removeFirstMatchingValue (this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Array<JNIClassBase*>& JNIClassBase::getClasses()
|
||||||
|
{
|
||||||
|
static Array<JNIClassBase*> classes;
|
||||||
|
return classes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNIClassBase::initialise (JNIEnv* env)
|
||||||
|
{
|
||||||
|
classRef = (jclass) env->NewGlobalRef (env->FindClass (classPath));
|
||||||
|
jassert (classRef != 0);
|
||||||
|
|
||||||
|
initialiseFields (env);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNIClassBase::release (JNIEnv* env)
|
||||||
|
{
|
||||||
|
env->DeleteGlobalRef (classRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNIClassBase::initialiseAllClasses (JNIEnv* env)
|
||||||
|
{
|
||||||
|
const Array<JNIClassBase*>& classes = getClasses();
|
||||||
|
for (int i = classes.size(); --i >= 0;)
|
||||||
|
classes.getUnchecked(i)->initialise (env);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JNIClassBase::releaseAllClasses (JNIEnv* env)
|
||||||
|
{
|
||||||
|
const Array<JNIClassBase*>& classes = getClasses();
|
||||||
|
for (int i = classes.size(); --i >= 0;)
|
||||||
|
classes.getUnchecked(i)->release (env);
|
||||||
|
}
|
||||||
|
|
||||||
|
jmethodID JNIClassBase::resolveMethod (JNIEnv* env, const char* methodName, const char* params)
|
||||||
|
{
|
||||||
|
jmethodID m = env->GetMethodID (classRef, methodName, params);
|
||||||
|
jassert (m != 0);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
jmethodID JNIClassBase::resolveStaticMethod (JNIEnv* env, const char* methodName, const char* params)
|
||||||
|
{
|
||||||
|
jmethodID m = env->GetStaticMethodID (classRef, methodName, params);
|
||||||
|
jassert (m != 0);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
jfieldID JNIClassBase::resolveField (JNIEnv* env, const char* fieldName, const char* signature)
|
||||||
|
{
|
||||||
|
jfieldID f = env->GetFieldID (classRef, fieldName, signature);
|
||||||
|
jassert (f != 0);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
jfieldID JNIClassBase::resolveStaticField (JNIEnv* env, const char* fieldName, const char* signature)
|
||||||
|
{
|
||||||
|
jfieldID f = env->GetStaticFieldID (classRef, fieldName, signature);
|
||||||
|
jassert (f != 0);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
ThreadLocalJNIEnvHolder threadLocalJNIEnvHolder;
|
||||||
|
|
||||||
|
#if JUCE_DEBUG
|
||||||
|
static bool systemInitialised = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
JNIEnv* getEnv() noexcept
|
||||||
|
{
|
||||||
|
#if JUCE_DEBUG
|
||||||
|
if (! systemInitialised)
|
||||||
|
{
|
||||||
|
DBG ("*** Call to getEnv() when system not initialised");
|
||||||
|
jassertfalse;
|
||||||
|
std::exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return threadLocalJNIEnvHolder.getOrAttach();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" jint JNI_OnLoad (JavaVM*, void*)
|
||||||
|
{
|
||||||
|
return JNI_VERSION_1_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
AndroidSystem::AndroidSystem() : screenWidth (0), screenHeight (0), dpi (160)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidSystem::initialise (JNIEnv* env, jobject act, jstring file, jstring dataDir)
|
||||||
|
{
|
||||||
|
screenWidth = screenHeight = 0;
|
||||||
|
dpi = 160;
|
||||||
|
JNIClassBase::initialiseAllClasses (env);
|
||||||
|
|
||||||
|
threadLocalJNIEnvHolder.initialise (env);
|
||||||
|
#if JUCE_DEBUG
|
||||||
|
systemInitialised = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
activity = GlobalRef (act);
|
||||||
|
appFile = juceString (env, file);
|
||||||
|
appDataDir = juceString (env, dataDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidSystem::shutdown (JNIEnv* env)
|
||||||
|
{
|
||||||
|
activity.clear();
|
||||||
|
|
||||||
|
#if JUCE_DEBUG
|
||||||
|
systemInitialised = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
JNIClassBase::releaseAllClasses (env);
|
||||||
|
}
|
||||||
|
|
||||||
|
AndroidSystem android;
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
namespace AndroidStatsHelpers
|
||||||
|
{
|
||||||
|
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD) \
|
||||||
|
STATICMETHOD (getProperty, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;")
|
||||||
|
|
||||||
|
DECLARE_JNI_CLASS (SystemClass, "java/lang/System");
|
||||||
|
#undef JNI_CLASS_MEMBERS
|
||||||
|
|
||||||
|
String getSystemProperty (const String& name)
|
||||||
|
{
|
||||||
|
return juceString (LocalRef<jstring> ((jstring) getEnv()->CallStaticObjectMethod (SystemClass,
|
||||||
|
SystemClass.getProperty,
|
||||||
|
javaString (name).get())));
|
||||||
|
}
|
||||||
|
|
||||||
|
String getLocaleValue (bool isRegion)
|
||||||
|
{
|
||||||
|
return juceString (LocalRef<jstring> ((jstring) getEnv()->CallStaticObjectMethod (JuceAppActivity,
|
||||||
|
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;"))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||||
|
{
|
||||||
|
return Android;
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getOperatingSystemName()
|
||||||
|
{
|
||||||
|
return "Android " + AndroidStatsHelpers::getSystemProperty ("os.version");
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getDeviceDescription()
|
||||||
|
{
|
||||||
|
return AndroidStatsHelpers::getAndroidOsBuildValue ("MODEL")
|
||||||
|
+ "-" + AndroidStatsHelpers::getAndroidOsBuildValue ("SERIAL");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SystemStats::isOperatingSystem64Bit()
|
||||||
|
{
|
||||||
|
#if JUCE_64BIT
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getCpuVendor()
|
||||||
|
{
|
||||||
|
return AndroidStatsHelpers::getSystemProperty ("os.arch");
|
||||||
|
}
|
||||||
|
|
||||||
|
int SystemStats::getCpuSpeedInMegaherz()
|
||||||
|
{
|
||||||
|
return 0; // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
int SystemStats::getMemorySizeInMegabytes()
|
||||||
|
{
|
||||||
|
#if __ANDROID_API__ >= 9
|
||||||
|
struct sysinfo sysi;
|
||||||
|
|
||||||
|
if (sysinfo (&sysi) == 0)
|
||||||
|
return (sysi.totalram * sysi.mem_unit / (1024 * 1024));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SystemStats::getPageSize()
|
||||||
|
{
|
||||||
|
return sysconf (_SC_PAGESIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
String SystemStats::getLogonName()
|
||||||
|
{
|
||||||
|
if (const char* user = getenv ("USER"))
|
||||||
|
return CharPointer_UTF8 (user);
|
||||||
|
|
||||||
|
if (struct passwd* const pw = getpwuid (getuid()))
|
||||||
|
return CharPointer_UTF8 (pw->pw_name);
|
||||||
|
|
||||||
|
return String::empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getFullUserName()
|
||||||
|
{
|
||||||
|
return getLogonName();
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getComputerName()
|
||||||
|
{
|
||||||
|
char name [256] = { 0 };
|
||||||
|
if (gethostname (name, sizeof (name) - 1) == 0)
|
||||||
|
return name;
|
||||||
|
|
||||||
|
return String::empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String SystemStats::getUserLanguage() { return AndroidStatsHelpers::getLocaleValue (false); }
|
||||||
|
String SystemStats::getUserRegion() { return AndroidStatsHelpers::getLocaleValue (true); }
|
||||||
|
String SystemStats::getDisplayLanguage() { return getUserLanguage() + "-" + getUserRegion(); }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void CPUInformation::initialise() noexcept
|
||||||
|
{
|
||||||
|
numCpus = jmax (1, (int) sysconf (_SC_NPROCESSORS_ONLN));
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
uint32 juce_millisecondsSinceStartup() noexcept
|
||||||
|
{
|
||||||
|
timespec t;
|
||||||
|
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||||
|
|
||||||
|
return t.tv_sec * 1000 + t.tv_nsec / 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 Time::getHighResolutionTicks() noexcept
|
||||||
|
{
|
||||||
|
timespec t;
|
||||||
|
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||||
|
|
||||||
|
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 Time::getHighResolutionTicksPerSecond() noexcept
|
||||||
|
{
|
||||||
|
return 1000000; // (microseconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
double Time::getMillisecondCounterHiRes() noexcept
|
||||||
|
{
|
||||||
|
return getHighResolutionTicks() * 0.001;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Time::setSystemTimeToThisTime() const
|
||||||
|
{
|
||||||
|
jassertfalse;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Note that a lot of methods that you'd expect to find in this file actually
|
||||||
|
live in juce_posix_SharedCode.h!
|
||||||
|
*/
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// sets the process to 0=low priority, 1=normal, 2=high, 3=realtime
|
||||||
|
JUCE_API void JUCE_CALLTYPE Process::setPriority (ProcessPriority prior)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
struct sched_param param;
|
||||||
|
int policy, maxp, minp;
|
||||||
|
|
||||||
|
const int p = (int) prior;
|
||||||
|
|
||||||
|
if (p <= 1)
|
||||||
|
policy = SCHED_OTHER;
|
||||||
|
else
|
||||||
|
policy = SCHED_RR;
|
||||||
|
|
||||||
|
minp = sched_get_priority_min (policy);
|
||||||
|
maxp = sched_get_priority_max (policy);
|
||||||
|
|
||||||
|
if (p < 2)
|
||||||
|
param.sched_priority = 0;
|
||||||
|
else if (p == 2 )
|
||||||
|
// Set to middle of lower realtime priority range
|
||||||
|
param.sched_priority = minp + (maxp - minp) / 4;
|
||||||
|
else
|
||||||
|
// Set to middle of higher realtime priority range
|
||||||
|
param.sched_priority = minp + (3 * (maxp - minp) / 4);
|
||||||
|
|
||||||
|
pthread_setschedparam (pthread_self(), policy, ¶m);
|
||||||
|
}
|
||||||
|
|
||||||
|
JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JUCE_API bool JUCE_CALLTYPE Process::isRunningUnderDebugger()
|
||||||
|
{
|
||||||
|
return juce_isRunningUnderDebugger();
|
||||||
|
}
|
||||||
|
|
||||||
|
JUCE_API void JUCE_CALLTYPE Process::raisePrivilege() {}
|
||||||
|
JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege() {}
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool File::copyInternal (const File& dest) const
|
||||||
|
{
|
||||||
|
FileInputStream in (*this);
|
||||||
|
|
||||||
|
if (dest.deleteFile())
|
||||||
|
{
|
||||||
|
{
|
||||||
|
FileOutputStream out (dest);
|
||||||
|
|
||||||
|
if (out.failedToOpen())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (out.writeFromInputStream (in, -1) == getSize())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest.deleteFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::findFileSystemRoots (Array<File>& destArray)
|
||||||
|
{
|
||||||
|
destArray.add (File ("/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isHidden() const
|
||||||
|
{
|
||||||
|
return getFileName().startsWithChar ('.');
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getLinkedFile (StringRef file)
|
||||||
|
{
|
||||||
|
HeapBlock<char> buffer (8194);
|
||||||
|
const int numBytes = (int) readlink (file.text, buffer, 8192);
|
||||||
|
return String::fromUTF8 (buffer, jmax (0, numBytes));
|
||||||
|
};
|
||||||
|
|
||||||
|
bool File::isLink() const
|
||||||
|
{
|
||||||
|
return getLinkedFile (getFullPathName()).isNotEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
File File::getLinkedTarget() const
|
||||||
|
{
|
||||||
|
String f (getLinkedFile (getFullPathName()));
|
||||||
|
|
||||||
|
if (f.isNotEmpty())
|
||||||
|
return getSiblingFile (f);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class DirectoryIterator::NativeIterator::Pimpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Pimpl (const File& directory, const String& wc)
|
||||||
|
: parentDir (File::addTrailingSeparator (directory.getFullPathName())),
|
||||||
|
wildCard (wc), dir (opendir (directory.getFullPathName().toUTF8()))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~Pimpl()
|
||||||
|
{
|
||||||
|
if (dir != nullptr)
|
||||||
|
closedir (dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next (String& filenameFound,
|
||||||
|
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||||
|
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||||
|
{
|
||||||
|
if (dir != nullptr)
|
||||||
|
{
|
||||||
|
const char* wildcardUTF8 = nullptr;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
struct dirent* const de = readdir (dir);
|
||||||
|
|
||||||
|
if (de == nullptr)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (wildcardUTF8 == nullptr)
|
||||||
|
wildcardUTF8 = wildCard.toUTF8();
|
||||||
|
|
||||||
|
if (fnmatch (wildcardUTF8, de->d_name, FNM_CASEFOLD) == 0)
|
||||||
|
{
|
||||||
|
filenameFound = CharPointer_UTF8 (de->d_name);
|
||||||
|
|
||||||
|
updateStatInfoForFile (parentDir + filenameFound, isDir, fileSize, modTime, creationTime, isReadOnly);
|
||||||
|
|
||||||
|
if (isHidden != nullptr)
|
||||||
|
*isHidden = filenameFound.startsWithChar ('.');
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
String parentDir, wildCard;
|
||||||
|
DIR* dir;
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (Pimpl)
|
||||||
|
};
|
||||||
|
|
||||||
|
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildCard)
|
||||||
|
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildCard))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectoryIterator::NativeIterator::~NativeIterator() {}
|
||||||
|
|
||||||
|
bool DirectoryIterator::NativeIterator::next (String& filenameFound,
|
||||||
|
bool* isDir, bool* isHidden, int64* fileSize,
|
||||||
|
Time* modTime, Time* creationTime, bool* isReadOnly)
|
||||||
|
{
|
||||||
|
return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
|
||||||
|
}
|
||||||
@@ -0,0 +1,241 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
U_ISOFS_SUPER_MAGIC = 0x9660, // linux/iso_fs.h
|
||||||
|
U_MSDOS_SUPER_MAGIC = 0x4d44, // linux/msdos_fs.h
|
||||||
|
U_NFS_SUPER_MAGIC = 0x6969, // linux/nfs_fs.h
|
||||||
|
U_SMB_SUPER_MAGIC = 0x517B // linux/smb_fs.h
|
||||||
|
};
|
||||||
|
|
||||||
|
bool File::isOnCDRomDrive() const
|
||||||
|
{
|
||||||
|
struct statfs buf;
|
||||||
|
|
||||||
|
return statfs (getFullPathName().toUTF8(), &buf) == 0
|
||||||
|
&& buf.f_type == (short) U_ISOFS_SUPER_MAGIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isOnHardDisk() const
|
||||||
|
{
|
||||||
|
struct statfs buf;
|
||||||
|
|
||||||
|
if (statfs (getFullPathName().toUTF8(), &buf) == 0)
|
||||||
|
{
|
||||||
|
switch (buf.f_type)
|
||||||
|
{
|
||||||
|
case U_ISOFS_SUPER_MAGIC: // CD-ROM
|
||||||
|
case U_MSDOS_SUPER_MAGIC: // Probably floppy (but could be mounted FAT filesystem)
|
||||||
|
case U_NFS_SUPER_MAGIC: // Network NFS
|
||||||
|
case U_SMB_SUPER_MAGIC: // Network Samba
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume so if this fails for some reason
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isOnRemovableDrive() const
|
||||||
|
{
|
||||||
|
jassertfalse; // xxx not implemented for linux!
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String File::getVersion() const
|
||||||
|
{
|
||||||
|
return String(); // xxx not yet implemented
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
static File resolveXDGFolder (const char* const type, const char* const fallbackFolder)
|
||||||
|
{
|
||||||
|
StringArray confLines;
|
||||||
|
File ("~/.config/user-dirs.dirs").readLines (confLines);
|
||||||
|
|
||||||
|
for (int i = 0; i < confLines.size(); ++i)
|
||||||
|
{
|
||||||
|
const String line (confLines[i].trimStart());
|
||||||
|
|
||||||
|
if (line.startsWith (type))
|
||||||
|
{
|
||||||
|
// eg. resolve XDG_MUSIC_DIR="$HOME/Music" to /home/user/Music
|
||||||
|
const File f (line.replace ("$HOME", File ("~").getFullPathName())
|
||||||
|
.fromFirstOccurrenceOf ("=", false, false)
|
||||||
|
.trim().unquoted());
|
||||||
|
|
||||||
|
if (f.isDirectory())
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return File (fallbackFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* const* juce_argv = nullptr;
|
||||||
|
int juce_argc = 0;
|
||||||
|
|
||||||
|
File File::getSpecialLocation (const SpecialLocationType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case userHomeDirectory:
|
||||||
|
{
|
||||||
|
if (const char* homeDir = getenv ("HOME"))
|
||||||
|
return File (CharPointer_UTF8 (homeDir));
|
||||||
|
|
||||||
|
if (struct passwd* const pw = getpwuid (getuid()))
|
||||||
|
return File (CharPointer_UTF8 (pw->pw_dir));
|
||||||
|
|
||||||
|
return File();
|
||||||
|
}
|
||||||
|
|
||||||
|
case userDocumentsDirectory: return resolveXDGFolder ("XDG_DOCUMENTS_DIR", "~");
|
||||||
|
case userMusicDirectory: return resolveXDGFolder ("XDG_MUSIC_DIR", "~");
|
||||||
|
case userMoviesDirectory: return resolveXDGFolder ("XDG_VIDEOS_DIR", "~");
|
||||||
|
case userPicturesDirectory: return resolveXDGFolder ("XDG_PICTURES_DIR", "~");
|
||||||
|
case userDesktopDirectory: return resolveXDGFolder ("XDG_DESKTOP_DIR", "~/Desktop");
|
||||||
|
case userApplicationDataDirectory: return resolveXDGFolder ("XDG_CONFIG_HOME", "~");
|
||||||
|
case commonDocumentsDirectory:
|
||||||
|
case commonApplicationDataDirectory: return File ("/var");
|
||||||
|
case globalApplicationsDirectory: return File ("/usr");
|
||||||
|
|
||||||
|
case tempDirectory:
|
||||||
|
{
|
||||||
|
File tmp ("/var/tmp");
|
||||||
|
|
||||||
|
if (! tmp.isDirectory())
|
||||||
|
{
|
||||||
|
tmp = "/tmp";
|
||||||
|
|
||||||
|
if (! tmp.isDirectory())
|
||||||
|
tmp = File::getCurrentWorkingDirectory();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
case invokedExecutableFile:
|
||||||
|
if (juce_argv != nullptr && juce_argc > 0)
|
||||||
|
return File (CharPointer_UTF8 (juce_argv[0]));
|
||||||
|
// deliberate fall-through...
|
||||||
|
|
||||||
|
case currentExecutableFile:
|
||||||
|
case currentApplicationFile:
|
||||||
|
return juce_getExecutableFile();
|
||||||
|
|
||||||
|
case hostApplicationPath:
|
||||||
|
{
|
||||||
|
const File f ("/proc/self/exe");
|
||||||
|
return f.isLink() ? f.getLinkedTarget() : juce_getExecutableFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
jassertfalse; // unknown type?
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return File();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool File::moveToTrash() const
|
||||||
|
{
|
||||||
|
if (! exists())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
File trashCan ("~/.Trash");
|
||||||
|
|
||||||
|
if (! trashCan.isDirectory())
|
||||||
|
trashCan = "~/.local/share/Trash/files";
|
||||||
|
|
||||||
|
if (! trashCan.isDirectory())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return moveFileTo (trashCan.getNonexistentChildFile (getFileNameWithoutExtension(),
|
||||||
|
getFileExtension()));
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
static bool isFileExecutable (const String& filename)
|
||||||
|
{
|
||||||
|
juce_statStruct info;
|
||||||
|
|
||||||
|
return juce_stat (filename, info)
|
||||||
|
&& S_ISREG (info.st_mode)
|
||||||
|
&& access (filename.toUTF8(), X_OK) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Process::openDocument (const String& fileName, const String& parameters)
|
||||||
|
{
|
||||||
|
String cmdString (fileName.replace (" ", "\\ ",false));
|
||||||
|
cmdString << " " << parameters;
|
||||||
|
|
||||||
|
if (URL::isProbablyAWebsiteURL (fileName)
|
||||||
|
|| cmdString.startsWithIgnoreCase ("file:")
|
||||||
|
|| URL::isProbablyAnEmailAddress (fileName)
|
||||||
|
|| File::createFileWithoutCheckingPath (fileName).isDirectory()
|
||||||
|
|| ! isFileExecutable (fileName))
|
||||||
|
{
|
||||||
|
// create a command that tries to launch a bunch of likely browsers
|
||||||
|
static const char* const browserNames[] = { "xdg-open", "/etc/alternatives/x-www-browser", "firefox", "mozilla",
|
||||||
|
"google-chrome", "chromium-browser", "opera", "konqueror" };
|
||||||
|
StringArray cmdLines;
|
||||||
|
|
||||||
|
for (int i = 0; i < numElementsInArray (browserNames); ++i)
|
||||||
|
cmdLines.add (String (browserNames[i]) + " " + cmdString.trim().quoted());
|
||||||
|
|
||||||
|
cmdString = cmdLines.joinIntoString (" || ");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* const argv[4] = { "/bin/sh", "-c", cmdString.toUTF8(), 0 };
|
||||||
|
|
||||||
|
const int cpid = fork();
|
||||||
|
|
||||||
|
if (cpid == 0)
|
||||||
|
{
|
||||||
|
setsid();
|
||||||
|
|
||||||
|
// Child process
|
||||||
|
execve (argv[0], (char**) argv, environ);
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cpid >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::revealToUser() const
|
||||||
|
{
|
||||||
|
if (isDirectory())
|
||||||
|
startAsProcess();
|
||||||
|
else if (getParentDirectory().exists())
|
||||||
|
getParentDirectory().startAsProcess();
|
||||||
|
}
|
||||||
@@ -0,0 +1,445 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
void MACAddress::findAllAddresses (Array<MACAddress>& result)
|
||||||
|
{
|
||||||
|
const int s = socket (AF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (s != -1)
|
||||||
|
{
|
||||||
|
struct ifaddrs* addrs = nullptr;
|
||||||
|
|
||||||
|
if (getifaddrs (&addrs) != -1)
|
||||||
|
{
|
||||||
|
for (struct ifaddrs* i = addrs; i != nullptr; i = i->ifa_next)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& /* targetEmailAddress */,
|
||||||
|
const String& /* emailSubject */,
|
||||||
|
const String& /* bodyText */,
|
||||||
|
const StringArray& /* filesToAttach */)
|
||||||
|
{
|
||||||
|
jassertfalse; // xxx todo
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class WebInputStream : public InputStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
|
||||||
|
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||||
|
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
|
||||||
|
: statusCode (0), socketHandle (-1), levelsOfRedirection (0),
|
||||||
|
address (address_), headers (headers_), postData (postData_), position (0),
|
||||||
|
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
|
||||||
|
{
|
||||||
|
statusCode = createConnection (progressCallback, progressCallbackContext);
|
||||||
|
|
||||||
|
if (responseHeaders != nullptr && ! isError())
|
||||||
|
{
|
||||||
|
for (int i = 0; i < headerLines.size(); ++i)
|
||||||
|
{
|
||||||
|
const String& headersEntry = headerLines[i];
|
||||||
|
const String key (headersEntry.upToFirstOccurrenceOf (": ", false, false));
|
||||||
|
const String value (headersEntry.fromFirstOccurrenceOf (": ", false, false));
|
||||||
|
const String previousValue ((*responseHeaders) [key]);
|
||||||
|
responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~WebInputStream()
|
||||||
|
{
|
||||||
|
closeSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool isError() const { return socketHandle < 0; }
|
||||||
|
bool isExhausted() override { return finished; }
|
||||||
|
int64 getPosition() override { return position; }
|
||||||
|
|
||||||
|
int64 getTotalLength() override
|
||||||
|
{
|
||||||
|
//xxx to do
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read (void* buffer, int bytesToRead) override
|
||||||
|
{
|
||||||
|
if (finished || isError())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fd_set readbits;
|
||||||
|
FD_ZERO (&readbits);
|
||||||
|
FD_SET (socketHandle, &readbits);
|
||||||
|
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = jmax (1, timeOutMs / 1000);
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
|
||||||
|
return 0; // (timeout)
|
||||||
|
|
||||||
|
const int bytesRead = jmax (0, (int) recv (socketHandle, buffer, bytesToRead, MSG_WAITALL));
|
||||||
|
if (bytesRead == 0)
|
||||||
|
finished = true;
|
||||||
|
|
||||||
|
position += bytesRead;
|
||||||
|
return bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setPosition (int64 wantedPos) override
|
||||||
|
{
|
||||||
|
if (isError())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (wantedPos != position)
|
||||||
|
{
|
||||||
|
finished = false;
|
||||||
|
|
||||||
|
if (wantedPos < position)
|
||||||
|
{
|
||||||
|
closeSocket();
|
||||||
|
position = 0;
|
||||||
|
statusCode = createConnection (0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
skipNextBytes (wantedPos - position);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
int statusCode;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int socketHandle, levelsOfRedirection;
|
||||||
|
StringArray headerLines;
|
||||||
|
String address, headers;
|
||||||
|
MemoryBlock postData;
|
||||||
|
int64 position;
|
||||||
|
bool finished;
|
||||||
|
const bool isPost;
|
||||||
|
const int timeOutMs;
|
||||||
|
|
||||||
|
void closeSocket()
|
||||||
|
{
|
||||||
|
if (socketHandle >= 0)
|
||||||
|
close (socketHandle);
|
||||||
|
|
||||||
|
socketHandle = -1;
|
||||||
|
levelsOfRedirection = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
|
||||||
|
{
|
||||||
|
closeSocket();
|
||||||
|
|
||||||
|
uint32 timeOutTime = Time::getMillisecondCounter();
|
||||||
|
|
||||||
|
if (timeOutMs == 0)
|
||||||
|
timeOutTime += 60000;
|
||||||
|
else if (timeOutMs < 0)
|
||||||
|
timeOutTime = 0xffffffff;
|
||||||
|
else
|
||||||
|
timeOutTime += timeOutMs;
|
||||||
|
|
||||||
|
String hostName, hostPath;
|
||||||
|
int hostPort;
|
||||||
|
if (! decomposeURL (address, hostName, hostPath, hostPort))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
String serverName, proxyName, proxyPath;
|
||||||
|
int proxyPort = 0;
|
||||||
|
int port = 0;
|
||||||
|
|
||||||
|
const String proxyURL (getenv ("http_proxy"));
|
||||||
|
if (proxyURL.startsWithIgnoreCase ("http://"))
|
||||||
|
{
|
||||||
|
if (! decomposeURL (proxyURL, proxyName, proxyPath, proxyPort))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
serverName = proxyName;
|
||||||
|
port = proxyPort;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serverName = hostName;
|
||||||
|
port = hostPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct addrinfo hints;
|
||||||
|
zerostruct (hints);
|
||||||
|
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_flags = AI_NUMERICSERV;
|
||||||
|
|
||||||
|
struct addrinfo* result = nullptr;
|
||||||
|
if (getaddrinfo (serverName.toUTF8(), String (port).toUTF8(), &hints, &result) != 0 || result == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
socketHandle = socket (result->ai_family, result->ai_socktype, 0);
|
||||||
|
|
||||||
|
if (socketHandle == -1)
|
||||||
|
{
|
||||||
|
freeaddrinfo (result);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int receiveBufferSize = 16384;
|
||||||
|
setsockopt (socketHandle, SOL_SOCKET, SO_RCVBUF, (char*) &receiveBufferSize, sizeof (receiveBufferSize));
|
||||||
|
setsockopt (socketHandle, SOL_SOCKET, SO_KEEPALIVE, 0, 0);
|
||||||
|
|
||||||
|
#if JUCE_MAC
|
||||||
|
setsockopt (socketHandle, SOL_SOCKET, SO_NOSIGPIPE, 0, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (connect (socketHandle, result->ai_addr, result->ai_addrlen) == -1)
|
||||||
|
{
|
||||||
|
closeSocket();
|
||||||
|
freeaddrinfo (result);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo (result);
|
||||||
|
|
||||||
|
{
|
||||||
|
const MemoryBlock requestHeader (createRequestHeader (hostName, hostPort, proxyName, proxyPort,
|
||||||
|
hostPath, address, headers, postData, isPost));
|
||||||
|
|
||||||
|
if (! sendHeader (socketHandle, requestHeader, timeOutTime,
|
||||||
|
progressCallback, progressCallbackContext))
|
||||||
|
{
|
||||||
|
closeSocket();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String responseHeader (readResponse (timeOutTime));
|
||||||
|
position = 0;
|
||||||
|
|
||||||
|
if (responseHeader.isNotEmpty())
|
||||||
|
{
|
||||||
|
headerLines = StringArray::fromLines (responseHeader);
|
||||||
|
|
||||||
|
const int status = responseHeader.fromFirstOccurrenceOf (" ", false, false)
|
||||||
|
.substring (0, 3).getIntValue();
|
||||||
|
|
||||||
|
//int contentLength = findHeaderItem (lines, "Content-Length:").getIntValue();
|
||||||
|
//bool isChunked = findHeaderItem (lines, "Transfer-Encoding:").equalsIgnoreCase ("chunked");
|
||||||
|
|
||||||
|
String location (findHeaderItem (headerLines, "Location:"));
|
||||||
|
|
||||||
|
if (status >= 300 && status < 400
|
||||||
|
&& location.isNotEmpty() && location != address)
|
||||||
|
{
|
||||||
|
if (! location.startsWithIgnoreCase ("http://"))
|
||||||
|
location = "http://" + location;
|
||||||
|
|
||||||
|
if (++levelsOfRedirection <= 3)
|
||||||
|
{
|
||||||
|
address = location;
|
||||||
|
return createConnection (progressCallback, progressCallbackContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
levelsOfRedirection = 0;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closeSocket();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
String readResponse (const uint32 timeOutTime)
|
||||||
|
{
|
||||||
|
int numConsecutiveLFs = 0;
|
||||||
|
MemoryOutputStream buffer;
|
||||||
|
|
||||||
|
while (numConsecutiveLFs < 2
|
||||||
|
&& buffer.getDataSize() < 32768
|
||||||
|
&& Time::getMillisecondCounter() <= timeOutTime
|
||||||
|
&& ! (finished || isError()))
|
||||||
|
{
|
||||||
|
char c = 0;
|
||||||
|
if (read (&c, 1) != 1)
|
||||||
|
return String();
|
||||||
|
|
||||||
|
buffer.writeByte (c);
|
||||||
|
|
||||||
|
if (c == '\n')
|
||||||
|
++numConsecutiveLFs;
|
||||||
|
else if (c != '\r')
|
||||||
|
numConsecutiveLFs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const String header (buffer.toString().trimEnd());
|
||||||
|
|
||||||
|
if (header.startsWithIgnoreCase ("HTTP/"))
|
||||||
|
return header;
|
||||||
|
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeValueIfNotPresent (MemoryOutputStream& dest, const String& headers, const String& key, const String& value)
|
||||||
|
{
|
||||||
|
if (! headers.containsIgnoreCase (key))
|
||||||
|
dest << "\r\n" << key << ' ' << value;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MemoryBlock createRequestHeader (const String& hostName, const int hostPort,
|
||||||
|
const String& proxyName, const int proxyPort,
|
||||||
|
const String& hostPath, const String& originalURL,
|
||||||
|
const String& userHeaders, const MemoryBlock& postData,
|
||||||
|
const bool isPost)
|
||||||
|
{
|
||||||
|
MemoryOutputStream header;
|
||||||
|
|
||||||
|
if (proxyName.isEmpty())
|
||||||
|
writeHost (header, isPost, hostPath, hostName, hostPort);
|
||||||
|
else
|
||||||
|
writeHost (header, isPost, originalURL, proxyName, proxyPort);
|
||||||
|
|
||||||
|
writeValueIfNotPresent (header, userHeaders, "User-Agent:", "JUCE/" JUCE_STRINGIFY(JUCE_MAJOR_VERSION)
|
||||||
|
"." JUCE_STRINGIFY(JUCE_MINOR_VERSION)
|
||||||
|
"." JUCE_STRINGIFY(JUCE_BUILDNUMBER));
|
||||||
|
writeValueIfNotPresent (header, userHeaders, "Connection:", "close");
|
||||||
|
|
||||||
|
if (isPost)
|
||||||
|
writeValueIfNotPresent (header, userHeaders, "Content-Length:", String ((int) postData.getSize()));
|
||||||
|
|
||||||
|
header << "\r\n" << userHeaders
|
||||||
|
<< "\r\n" << postData;
|
||||||
|
|
||||||
|
return header.getMemoryBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool sendHeader (int socketHandle, const MemoryBlock& requestHeader, const uint32 timeOutTime,
|
||||||
|
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
|
||||||
|
{
|
||||||
|
size_t totalHeaderSent = 0;
|
||||||
|
|
||||||
|
while (totalHeaderSent < requestHeader.getSize())
|
||||||
|
{
|
||||||
|
if (Time::getMillisecondCounter() > timeOutTime)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const int numToSend = jmin (1024, (int) (requestHeader.getSize() - totalHeaderSent));
|
||||||
|
|
||||||
|
if (send (socketHandle, static_cast <const char*> (requestHeader.getData()) + totalHeaderSent, numToSend, 0) != numToSend)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
totalHeaderSent += numToSend;
|
||||||
|
|
||||||
|
if (progressCallback != nullptr && ! progressCallback (progressCallbackContext, totalHeaderSent, requestHeader.getSize()))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool decomposeURL (const String& url, String& host, String& path, int& port)
|
||||||
|
{
|
||||||
|
if (! url.startsWithIgnoreCase ("http://"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const int nextSlash = url.indexOfChar (7, '/');
|
||||||
|
int nextColon = url.indexOfChar (7, ':');
|
||||||
|
if (nextColon > nextSlash && nextSlash > 0)
|
||||||
|
nextColon = -1;
|
||||||
|
|
||||||
|
if (nextColon >= 0)
|
||||||
|
{
|
||||||
|
host = url.substring (7, nextColon);
|
||||||
|
|
||||||
|
if (nextSlash >= 0)
|
||||||
|
port = url.substring (nextColon + 1, nextSlash).getIntValue();
|
||||||
|
else
|
||||||
|
port = url.substring (nextColon + 1).getIntValue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
port = 80;
|
||||||
|
|
||||||
|
if (nextSlash >= 0)
|
||||||
|
host = url.substring (7, nextSlash);
|
||||||
|
else
|
||||||
|
host = url.substring (7);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextSlash >= 0)
|
||||||
|
path = url.substring (nextSlash);
|
||||||
|
else
|
||||||
|
path = "/";
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String findHeaderItem (const StringArray& lines, const String& itemName)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < lines.size(); ++i)
|
||||||
|
if (lines[i].startsWithIgnoreCase (itemName))
|
||||||
|
return lines[i].substring (itemName.length()).trim();
|
||||||
|
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
|
||||||
|
};
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
void Logger::outputDebugString (const String& text)
|
||||||
|
{
|
||||||
|
std::cerr << text << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||||
|
{
|
||||||
|
return Linux;
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getOperatingSystemName()
|
||||||
|
{
|
||||||
|
return "Linux";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SystemStats::isOperatingSystem64Bit()
|
||||||
|
{
|
||||||
|
#if JUCE_64BIT
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
//xxx not sure how to find this out?..
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
namespace LinuxStatsHelpers
|
||||||
|
{
|
||||||
|
String getCpuInfo (const char* const key)
|
||||||
|
{
|
||||||
|
StringArray lines;
|
||||||
|
File ("/proc/cpuinfo").readLines (lines);
|
||||||
|
|
||||||
|
for (int i = lines.size(); --i >= 0;) // (NB - it's important that this runs in reverse order)
|
||||||
|
if (lines[i].upToFirstOccurrenceOf (":", false, false).trim().equalsIgnoreCase (key))
|
||||||
|
return lines[i].fromFirstOccurrenceOf (":", false, false).trim();
|
||||||
|
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getDeviceDescription()
|
||||||
|
{
|
||||||
|
return LinuxStatsHelpers::getCpuInfo ("Hardware");
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getCpuVendor()
|
||||||
|
{
|
||||||
|
String v (LinuxStatsHelpers::getCpuInfo ("vendor_id"));
|
||||||
|
|
||||||
|
if (v.isEmpty())
|
||||||
|
v = LinuxStatsHelpers::getCpuInfo ("model name");
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SystemStats::getCpuSpeedInMegaherz()
|
||||||
|
{
|
||||||
|
return roundToInt (LinuxStatsHelpers::getCpuInfo ("cpu MHz").getFloatValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
int SystemStats::getMemorySizeInMegabytes()
|
||||||
|
{
|
||||||
|
struct sysinfo sysi;
|
||||||
|
|
||||||
|
if (sysinfo (&sysi) == 0)
|
||||||
|
return sysi.totalram * sysi.mem_unit / (1024 * 1024);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SystemStats::getPageSize()
|
||||||
|
{
|
||||||
|
return sysconf (_SC_PAGESIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
String SystemStats::getLogonName()
|
||||||
|
{
|
||||||
|
if (const char* user = getenv ("USER"))
|
||||||
|
return CharPointer_UTF8 (user);
|
||||||
|
|
||||||
|
if (struct passwd* const pw = getpwuid (getuid()))
|
||||||
|
return CharPointer_UTF8 (pw->pw_name);
|
||||||
|
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getFullUserName()
|
||||||
|
{
|
||||||
|
return getLogonName();
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getComputerName()
|
||||||
|
{
|
||||||
|
char name [256] = { 0 };
|
||||||
|
if (gethostname (name, sizeof (name) - 1) == 0)
|
||||||
|
return name;
|
||||||
|
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getLocaleValue (nl_item key)
|
||||||
|
{
|
||||||
|
const char* oldLocale = ::setlocale (LC_ALL, "");
|
||||||
|
String result (String::fromUTF8 (nl_langinfo (key)));
|
||||||
|
::setlocale (LC_ALL, oldLocale);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getUserLanguage() { return getLocaleValue (_NL_IDENTIFICATION_LANGUAGE); }
|
||||||
|
String SystemStats::getUserRegion() { return getLocaleValue (_NL_IDENTIFICATION_TERRITORY); }
|
||||||
|
String SystemStats::getDisplayLanguage() { return getUserLanguage() + "-" + getUserRegion(); }
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void CPUInformation::initialise() noexcept
|
||||||
|
{
|
||||||
|
const String flags (LinuxStatsHelpers::getCpuInfo ("flags"));
|
||||||
|
hasMMX = flags.contains ("mmx");
|
||||||
|
hasSSE = flags.contains ("sse");
|
||||||
|
hasSSE2 = flags.contains ("sse2");
|
||||||
|
hasSSE3 = flags.contains ("sse3");
|
||||||
|
has3DNow = flags.contains ("3dnow");
|
||||||
|
|
||||||
|
numCpus = LinuxStatsHelpers::getCpuInfo ("processor").getIntValue() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
uint32 juce_millisecondsSinceStartup() noexcept
|
||||||
|
{
|
||||||
|
timespec t;
|
||||||
|
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||||
|
|
||||||
|
return t.tv_sec * 1000 + t.tv_nsec / 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 Time::getHighResolutionTicks() noexcept
|
||||||
|
{
|
||||||
|
timespec t;
|
||||||
|
clock_gettime (CLOCK_MONOTONIC, &t);
|
||||||
|
|
||||||
|
return (t.tv_sec * (int64) 1000000) + (t.tv_nsec / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 Time::getHighResolutionTicksPerSecond() noexcept
|
||||||
|
{
|
||||||
|
return 1000000; // (microseconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
double Time::getMillisecondCounterHiRes() noexcept
|
||||||
|
{
|
||||||
|
return getHighResolutionTicks() * 0.001;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Time::setSystemTimeToThisTime() const
|
||||||
|
{
|
||||||
|
timeval t;
|
||||||
|
t.tv_sec = millisSinceEpoch / 1000;
|
||||||
|
t.tv_usec = (millisSinceEpoch - t.tv_sec * 1000) * 1000;
|
||||||
|
|
||||||
|
return settimeofday (&t, 0) == 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Note that a lot of methods that you'd expect to find in this file actually
|
||||||
|
live in juce_posix_SharedCode.h!
|
||||||
|
*/
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
JUCE_API void JUCE_CALLTYPE Process::setPriority (const ProcessPriority prior)
|
||||||
|
{
|
||||||
|
const int policy = (prior <= NormalPriority) ? SCHED_OTHER : SCHED_RR;
|
||||||
|
const int minp = sched_get_priority_min (policy);
|
||||||
|
const int maxp = sched_get_priority_max (policy);
|
||||||
|
|
||||||
|
struct sched_param param;
|
||||||
|
|
||||||
|
switch (prior)
|
||||||
|
{
|
||||||
|
case LowPriority:
|
||||||
|
case NormalPriority: param.sched_priority = 0; break;
|
||||||
|
case HighPriority: param.sched_priority = minp + (maxp - minp) / 4; break;
|
||||||
|
case RealtimePriority: param.sched_priority = minp + (3 * (maxp - minp) / 4); break;
|
||||||
|
default: jassertfalse; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_setschedparam (pthread_self(), policy, ¶m);
|
||||||
|
}
|
||||||
|
|
||||||
|
JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger()
|
||||||
|
{
|
||||||
|
#if JUCE_BSD
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
static char testResult = 0;
|
||||||
|
|
||||||
|
if (testResult == 0)
|
||||||
|
{
|
||||||
|
testResult = (char) ptrace (PT_TRACE_ME, 0, 0, 0);
|
||||||
|
|
||||||
|
if (testResult >= 0)
|
||||||
|
{
|
||||||
|
ptrace (PT_DETACH, 0, (caddr_t) 1, 0);
|
||||||
|
testResult = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return testResult < 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
JUCE_API bool JUCE_CALLTYPE Process::isRunningUnderDebugger()
|
||||||
|
{
|
||||||
|
return juce_isRunningUnderDebugger();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool swapUserAndEffectiveUser()
|
||||||
|
{
|
||||||
|
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(); }
|
||||||
|
JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege() { if (geteuid() == 0 && getuid() != 0) swapUserAndEffectiveUser(); }
|
||||||
@@ -0,0 +1,498 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Note that a lot of methods that you'd expect to find in this file actually
|
||||||
|
live in juce_posix_SharedCode.h!
|
||||||
|
*/
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool File::copyInternal (const File& dest) const
|
||||||
|
{
|
||||||
|
JUCE_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
NSFileManager* fm = [NSFileManager defaultManager];
|
||||||
|
|
||||||
|
return [fm fileExistsAtPath: juceStringToNS (fullPath)]
|
||||||
|
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
|
||||||
|
&& [fm copyItemAtPath: juceStringToNS (fullPath)
|
||||||
|
toPath: juceStringToNS (dest.getFullPathName())
|
||||||
|
error: nil];
|
||||||
|
#else
|
||||||
|
&& [fm copyPath: juceStringToNS (fullPath)
|
||||||
|
toPath: juceStringToNS (dest.getFullPathName())
|
||||||
|
handler: nil];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::findFileSystemRoots (Array<File>& destArray)
|
||||||
|
{
|
||||||
|
destArray.add (File ("/"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
namespace FileHelpers
|
||||||
|
{
|
||||||
|
static bool isFileOnDriveType (const File& f, const char* const* types)
|
||||||
|
{
|
||||||
|
struct statfs buf;
|
||||||
|
|
||||||
|
if (juce_doStatFS (f, buf))
|
||||||
|
{
|
||||||
|
const String type (buf.f_fstypename);
|
||||||
|
|
||||||
|
while (*types != 0)
|
||||||
|
if (type.equalsIgnoreCase (*types++))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isHiddenFile (const String& path)
|
||||||
|
{
|
||||||
|
#if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
|
||||||
|
JUCE_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
NSNumber* hidden = nil;
|
||||||
|
NSError* err = nil;
|
||||||
|
|
||||||
|
return [[NSURL fileURLWithPath: juceStringToNS (path)]
|
||||||
|
getResourceValue: &hidden forKey: NSURLIsHiddenKey error: &err]
|
||||||
|
&& [hidden boolValue];
|
||||||
|
}
|
||||||
|
#elif JUCE_IOS
|
||||||
|
return File (path).getFileName().startsWithChar ('.');
|
||||||
|
#else
|
||||||
|
FSRef ref;
|
||||||
|
LSItemInfoRecord info;
|
||||||
|
|
||||||
|
return FSPathMakeRefWithOptions ((const UInt8*) path.toRawUTF8(), kFSPathMakeRefDoNotFollowLeafSymlink, &ref, 0) == noErr
|
||||||
|
&& LSCopyItemInfoForRef (&ref, kLSRequestBasicFlagsOnly, &info) == noErr
|
||||||
|
&& (info.flags & kLSItemInfoIsInvisible) != 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JUCE_IOS
|
||||||
|
static String getIOSSystemLocation (NSSearchPathDirectory type)
|
||||||
|
{
|
||||||
|
return nsStringToJuce ([NSSearchPathForDirectoriesInDomains (type, NSUserDomainMask, YES)
|
||||||
|
objectAtIndex: 0]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static bool launchExecutable (const String& pathAndArguments)
|
||||||
|
{
|
||||||
|
const char* const argv[4] = { "/bin/sh", "-c", pathAndArguments.toUTF8(), 0 };
|
||||||
|
|
||||||
|
const int cpid = fork();
|
||||||
|
|
||||||
|
if (cpid == 0)
|
||||||
|
{
|
||||||
|
// Child process
|
||||||
|
if (execve (argv[0], (char**) argv, 0) < 0)
|
||||||
|
exit (0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (cpid < 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isOnCDRomDrive() const
|
||||||
|
{
|
||||||
|
static const char* const cdTypes[] = { "cd9660", "cdfs", "cddafs", "udf", nullptr };
|
||||||
|
|
||||||
|
return FileHelpers::isFileOnDriveType (*this, cdTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isOnHardDisk() const
|
||||||
|
{
|
||||||
|
static const char* const nonHDTypes[] = { "nfs", "smbfs", "ramfs", nullptr };
|
||||||
|
|
||||||
|
return ! (isOnCDRomDrive() || FileHelpers::isFileOnDriveType (*this, nonHDTypes));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isOnRemovableDrive() const
|
||||||
|
{
|
||||||
|
#if JUCE_IOS
|
||||||
|
return false; // xxx is this possible?
|
||||||
|
#else
|
||||||
|
JUCE_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
BOOL removable = false;
|
||||||
|
|
||||||
|
[[NSWorkspace sharedWorkspace]
|
||||||
|
getFileSystemInfoForPath: juceStringToNS (getFullPathName())
|
||||||
|
isRemovable: &removable
|
||||||
|
isWritable: nil
|
||||||
|
isUnmountable: nil
|
||||||
|
description: nil
|
||||||
|
type: nil];
|
||||||
|
|
||||||
|
return removable;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isHidden() const
|
||||||
|
{
|
||||||
|
return FileHelpers::isHiddenFile (getFullPathName());
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
const char* const* juce_argv = nullptr;
|
||||||
|
int juce_argc = 0;
|
||||||
|
|
||||||
|
File File::getSpecialLocation (const SpecialLocationType type)
|
||||||
|
{
|
||||||
|
JUCE_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
String resultPath;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case userHomeDirectory: resultPath = nsStringToJuce (NSHomeDirectory()); break;
|
||||||
|
|
||||||
|
#if JUCE_IOS
|
||||||
|
case userDocumentsDirectory: resultPath = FileHelpers::getIOSSystemLocation (NSDocumentDirectory); break;
|
||||||
|
case userDesktopDirectory: resultPath = FileHelpers::getIOSSystemLocation (NSDesktopDirectory); break;
|
||||||
|
|
||||||
|
case tempDirectory:
|
||||||
|
{
|
||||||
|
File tmp (FileHelpers::getIOSSystemLocation (NSCachesDirectory));
|
||||||
|
tmp = tmp.getChildFile (juce_getExecutableFile().getFileNameWithoutExtension());
|
||||||
|
tmp.createDirectory();
|
||||||
|
return tmp.getFullPathName();
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
case userDocumentsDirectory: resultPath = "~/Documents"; break;
|
||||||
|
case userDesktopDirectory: resultPath = "~/Desktop"; break;
|
||||||
|
|
||||||
|
case tempDirectory:
|
||||||
|
{
|
||||||
|
File tmp ("~/Library/Caches/" + juce_getExecutableFile().getFileNameWithoutExtension());
|
||||||
|
tmp.createDirectory();
|
||||||
|
return File (tmp.getFullPathName());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
case userMusicDirectory: resultPath = "~/Music"; break;
|
||||||
|
case userMoviesDirectory: resultPath = "~/Movies"; break;
|
||||||
|
case userPicturesDirectory: resultPath = "~/Pictures"; break;
|
||||||
|
case userApplicationDataDirectory: resultPath = "~/Library"; break;
|
||||||
|
case commonApplicationDataDirectory: resultPath = "/Library"; break;
|
||||||
|
case commonDocumentsDirectory: resultPath = "/Users/Shared"; break;
|
||||||
|
case globalApplicationsDirectory: resultPath = "/Applications"; break;
|
||||||
|
|
||||||
|
case invokedExecutableFile:
|
||||||
|
if (juce_argv != nullptr && juce_argc > 0)
|
||||||
|
return File (CharPointer_UTF8 (juce_argv[0]));
|
||||||
|
// deliberate fall-through...
|
||||||
|
|
||||||
|
case currentExecutableFile:
|
||||||
|
return juce_getExecutableFile();
|
||||||
|
|
||||||
|
case currentApplicationFile:
|
||||||
|
{
|
||||||
|
const File exe (juce_getExecutableFile());
|
||||||
|
const File parent (exe.getParentDirectory());
|
||||||
|
|
||||||
|
#if JUCE_IOS
|
||||||
|
return parent;
|
||||||
|
#else
|
||||||
|
return parent.getFullPathName().endsWithIgnoreCase ("Contents/MacOS")
|
||||||
|
? parent.getParentDirectory().getParentDirectory()
|
||||||
|
: exe;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
case hostApplicationPath:
|
||||||
|
{
|
||||||
|
unsigned int size = 8192;
|
||||||
|
HeapBlock<char> buffer;
|
||||||
|
buffer.calloc (size + 8);
|
||||||
|
|
||||||
|
_NSGetExecutablePath (buffer.getData(), &size);
|
||||||
|
return File (String::fromUTF8 (buffer, (int) size));
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
jassertfalse; // unknown type?
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resultPath.isNotEmpty())
|
||||||
|
return File (resultPath.convertToPrecomposedUnicode());
|
||||||
|
}
|
||||||
|
|
||||||
|
return File();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
String File::getVersion() const
|
||||||
|
{
|
||||||
|
JUCE_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
if (NSBundle* bundle = [NSBundle bundleWithPath: juceStringToNS (getFullPathName())])
|
||||||
|
if (NSDictionary* info = [bundle infoDictionary])
|
||||||
|
if (NSString* name = [info valueForKey: nsStringLiteral ("CFBundleShortVersionString")])
|
||||||
|
return nsStringToJuce (name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
static NSString* getFileLink (const String& path)
|
||||||
|
{
|
||||||
|
#if JUCE_IOS || (defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
||||||
|
return [[NSFileManager defaultManager] destinationOfSymbolicLinkAtPath: juceStringToNS (path) error: nil];
|
||||||
|
#else
|
||||||
|
// (the cast here avoids a deprecation warning)
|
||||||
|
return [((id) [NSFileManager defaultManager]) pathContentOfSymbolicLinkAtPath: juceStringToNS (path)];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isLink() const
|
||||||
|
{
|
||||||
|
return getFileLink (fullPath) != nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
File File::getLinkedTarget() const
|
||||||
|
{
|
||||||
|
if (NSString* dest = getFileLink (fullPath))
|
||||||
|
return getSiblingFile (nsStringToJuce (dest));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool File::moveToTrash() const
|
||||||
|
{
|
||||||
|
if (! exists())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
#if JUCE_IOS
|
||||||
|
return deleteFile(); //xxx is there a trashcan on the iOS?
|
||||||
|
#else
|
||||||
|
JUCE_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
NSString* p = juceStringToNS (getFullPathName());
|
||||||
|
|
||||||
|
return [[NSWorkspace sharedWorkspace]
|
||||||
|
performFileOperation: NSWorkspaceRecycleOperation
|
||||||
|
source: [p stringByDeletingLastPathComponent]
|
||||||
|
destination: nsEmptyString()
|
||||||
|
files: [NSArray arrayWithObject: [p lastPathComponent]]
|
||||||
|
tag: nil ];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class DirectoryIterator::NativeIterator::Pimpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Pimpl (const File& directory, const String& wildCard_)
|
||||||
|
: parentDir (File::addTrailingSeparator (directory.getFullPathName())),
|
||||||
|
wildCard (wildCard_),
|
||||||
|
enumerator (nil)
|
||||||
|
{
|
||||||
|
JUCE_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
enumerator = [[[NSFileManager defaultManager] enumeratorAtPath: juceStringToNS (directory.getFullPathName())] retain];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~Pimpl()
|
||||||
|
{
|
||||||
|
[enumerator release];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next (String& filenameFound,
|
||||||
|
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||||
|
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||||
|
{
|
||||||
|
JUCE_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
const char* wildcardUTF8 = nullptr;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
NSString* file;
|
||||||
|
if (enumerator == nil || (file = [enumerator nextObject]) == nil)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
[enumerator skipDescendents];
|
||||||
|
filenameFound = nsStringToJuce (file).convertToPrecomposedUnicode();
|
||||||
|
|
||||||
|
if (wildcardUTF8 == nullptr)
|
||||||
|
wildcardUTF8 = wildCard.toUTF8();
|
||||||
|
|
||||||
|
if (fnmatch (wildcardUTF8, filenameFound.toUTF8(), FNM_CASEFOLD) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const String fullPath (parentDir + filenameFound);
|
||||||
|
updateStatInfoForFile (fullPath, isDir, fileSize, modTime, creationTime, isReadOnly);
|
||||||
|
|
||||||
|
if (isHidden != nullptr)
|
||||||
|
*isHidden = FileHelpers::isHiddenFile (fullPath);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
String parentDir, wildCard;
|
||||||
|
NSDirectoryEnumerator* enumerator;
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE (Pimpl)
|
||||||
|
};
|
||||||
|
|
||||||
|
DirectoryIterator::NativeIterator::NativeIterator (const File& directory, const String& wildcard)
|
||||||
|
: pimpl (new DirectoryIterator::NativeIterator::Pimpl (directory, wildcard))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectoryIterator::NativeIterator::~NativeIterator()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DirectoryIterator::NativeIterator::next (String& filenameFound,
|
||||||
|
bool* const isDir, bool* const isHidden, int64* const fileSize,
|
||||||
|
Time* const modTime, Time* const creationTime, bool* const isReadOnly)
|
||||||
|
{
|
||||||
|
return pimpl->next (filenameFound, isDir, isHidden, fileSize, modTime, creationTime, isReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool JUCE_CALLTYPE Process::openDocument (const String& fileName, const String& parameters)
|
||||||
|
{
|
||||||
|
JUCE_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
NSURL* filenameAsURL = [NSURL URLWithString: juceStringToNS (fileName)];
|
||||||
|
|
||||||
|
#if JUCE_IOS
|
||||||
|
(void) parameters;
|
||||||
|
return [[UIApplication sharedApplication] openURL: filenameAsURL];
|
||||||
|
#else
|
||||||
|
NSWorkspace* workspace = [NSWorkspace sharedWorkspace];
|
||||||
|
|
||||||
|
if (parameters.isEmpty())
|
||||||
|
return [workspace openFile: juceStringToNS (fileName)]
|
||||||
|
|| [workspace openURL: filenameAsURL];
|
||||||
|
|
||||||
|
const File file (fileName);
|
||||||
|
|
||||||
|
if (file.isBundle())
|
||||||
|
{
|
||||||
|
StringArray params;
|
||||||
|
params.addTokens (parameters, true);
|
||||||
|
|
||||||
|
NSMutableArray* paramArray = [[[NSMutableArray alloc] init] autorelease];
|
||||||
|
for (int i = 0; i < params.size(); ++i)
|
||||||
|
[paramArray addObject: juceStringToNS (params[i])];
|
||||||
|
|
||||||
|
NSMutableDictionary* dict = [[[NSMutableDictionary alloc] init] autorelease];
|
||||||
|
[dict setObject: paramArray
|
||||||
|
forKey: nsStringLiteral ("NSWorkspaceLaunchConfigurationArguments")];
|
||||||
|
|
||||||
|
return [workspace launchApplicationAtURL: filenameAsURL
|
||||||
|
options: NSWorkspaceLaunchDefault | NSWorkspaceLaunchNewInstance
|
||||||
|
configuration: dict
|
||||||
|
error: nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.exists())
|
||||||
|
return FileHelpers::launchExecutable ("\"" + fileName + "\" " + parameters);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::revealToUser() const
|
||||||
|
{
|
||||||
|
#if ! JUCE_IOS
|
||||||
|
if (exists())
|
||||||
|
[[NSWorkspace sharedWorkspace] selectFile: juceStringToNS (getFullPathName()) inFileViewerRootedAtPath: nsEmptyString()];
|
||||||
|
else if (getParentDirectory().exists())
|
||||||
|
getParentDirectory().revealToUser();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
OSType File::getMacOSType() const
|
||||||
|
{
|
||||||
|
JUCE_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
#if JUCE_IOS || (defined (MAC_OS_X_VERSION_10_5) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
||||||
|
NSDictionary* fileDict = [[NSFileManager defaultManager] attributesOfItemAtPath: juceStringToNS (getFullPathName()) error: nil];
|
||||||
|
#else
|
||||||
|
// (the cast here avoids a deprecation warning)
|
||||||
|
NSDictionary* fileDict = [((id) [NSFileManager defaultManager]) fileAttributesAtPath: juceStringToNS (getFullPathName()) traverseLink: NO];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return [fileDict fileHFSTypeCode];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isBundle() const
|
||||||
|
{
|
||||||
|
#if JUCE_IOS
|
||||||
|
return false; // xxx can't find a sensible way to do this without trying to open the bundle..
|
||||||
|
#else
|
||||||
|
JUCE_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
return [[NSWorkspace sharedWorkspace] isFilePackageAtPath: juceStringToNS (getFullPathName())];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JUCE_MAC
|
||||||
|
void File::addToDock() const
|
||||||
|
{
|
||||||
|
// check that it's not already there...
|
||||||
|
if (! juce_getOutputFromCommand ("defaults read com.apple.dock persistent-apps").containsIgnoreCase (getFullPathName()))
|
||||||
|
{
|
||||||
|
juce_runSystemCommand ("defaults write com.apple.dock persistent-apps -array-add \"<dict><key>tile-data</key><dict><key>file-data</key><dict><key>_CFURLString</key><string>"
|
||||||
|
+ getFullPathName() + "</string><key>_CFURLStringType</key><integer>0</integer></dict></dict></dict>\"");
|
||||||
|
|
||||||
|
juce_runSystemCommand ("osascript -e \"tell application \\\"Dock\\\" to quit\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,445 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
void MACAddress::findAllAddresses (Array<MACAddress>& result)
|
||||||
|
{
|
||||||
|
ifaddrs* addrs = nullptr;
|
||||||
|
|
||||||
|
if (getifaddrs (&addrs) == 0)
|
||||||
|
{
|
||||||
|
for (const ifaddrs* cursor = addrs; cursor != nullptr; cursor = cursor->ifa_next)
|
||||||
|
{
|
||||||
|
sockaddr_storage* sto = (sockaddr_storage*) cursor->ifa_addr;
|
||||||
|
if (sto->ss_family == AF_LINK)
|
||||||
|
{
|
||||||
|
const sockaddr_dl* const sadd = (const sockaddr_dl*) cursor->ifa_addr;
|
||||||
|
|
||||||
|
#ifndef IFT_ETHER
|
||||||
|
enum { IFT_ETHER = 6 };
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (sadd->sdl_type == IFT_ETHER)
|
||||||
|
{
|
||||||
|
MACAddress ma (MACAddress (((const uint8*) sadd->sdl_data) + sadd->sdl_nlen));
|
||||||
|
|
||||||
|
if (! ma.isNull())
|
||||||
|
result.addIfNotAlreadyThere (ma);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
freeifaddrs (addrs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool JUCE_CALLTYPE Process::openEmailWithAttachments (const String& targetEmailAddress,
|
||||||
|
const String& emailSubject,
|
||||||
|
const String& bodyText,
|
||||||
|
const StringArray& filesToAttach)
|
||||||
|
{
|
||||||
|
#if JUCE_IOS
|
||||||
|
(void) targetEmailAddress;
|
||||||
|
(void) emailSubject;
|
||||||
|
(void) bodyText;
|
||||||
|
(void) filesToAttach;
|
||||||
|
|
||||||
|
//xxx probably need to use MFMailComposeViewController
|
||||||
|
jassertfalse;
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
JUCE_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
String script;
|
||||||
|
script << "tell application \"Mail\"\r\n"
|
||||||
|
"set newMessage to make new outgoing message with properties {subject:\""
|
||||||
|
<< emailSubject.replace ("\"", "\\\"")
|
||||||
|
<< "\", content:\""
|
||||||
|
<< bodyText.replace ("\"", "\\\"")
|
||||||
|
<< "\" & return & return}\r\n"
|
||||||
|
"tell newMessage\r\n"
|
||||||
|
"set visible to true\r\n"
|
||||||
|
"set sender to \"sdfsdfsdfewf\"\r\n"
|
||||||
|
"make new to recipient at end of to recipients with properties {address:\""
|
||||||
|
<< targetEmailAddress
|
||||||
|
<< "\"}\r\n";
|
||||||
|
|
||||||
|
for (int i = 0; i < filesToAttach.size(); ++i)
|
||||||
|
{
|
||||||
|
script << "tell content\r\n"
|
||||||
|
"make new attachment with properties {file name:\""
|
||||||
|
<< filesToAttach[i].replace ("\"", "\\\"")
|
||||||
|
<< "\"} at after the last paragraph\r\n"
|
||||||
|
"end tell\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
script << "end tell\r\n"
|
||||||
|
"end tell\r\n";
|
||||||
|
|
||||||
|
NSAppleScript* s = [[NSAppleScript alloc] initWithSource: juceStringToNS (script)];
|
||||||
|
NSDictionary* error = nil;
|
||||||
|
const bool ok = [s executeAndReturnError: &error] != nil;
|
||||||
|
[s release];
|
||||||
|
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class URLConnectionState : public Thread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
URLConnectionState (NSURLRequest* req)
|
||||||
|
: Thread ("http connection"),
|
||||||
|
contentLength (-1),
|
||||||
|
delegate (nil),
|
||||||
|
request ([req retain]),
|
||||||
|
connection (nil),
|
||||||
|
data ([[NSMutableData data] retain]),
|
||||||
|
headers (nil),
|
||||||
|
statusCode (0),
|
||||||
|
initialised (false),
|
||||||
|
hasFailed (false),
|
||||||
|
hasFinished (false)
|
||||||
|
{
|
||||||
|
static DelegateClass cls;
|
||||||
|
delegate = [cls.createInstance() init];
|
||||||
|
DelegateClass::setState (delegate, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
~URLConnectionState()
|
||||||
|
{
|
||||||
|
stop();
|
||||||
|
[connection release];
|
||||||
|
[data release];
|
||||||
|
[request release];
|
||||||
|
[headers release];
|
||||||
|
[delegate release];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool start (URL::OpenStreamProgressCallback* callback, void* context)
|
||||||
|
{
|
||||||
|
startThread();
|
||||||
|
|
||||||
|
while (isThreadRunning() && ! initialised)
|
||||||
|
{
|
||||||
|
if (callback != nullptr)
|
||||||
|
callback (context, -1, (int) [[request HTTPBody] length]);
|
||||||
|
|
||||||
|
Thread::sleep (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return connection != nil && ! hasFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop()
|
||||||
|
{
|
||||||
|
[connection cancel];
|
||||||
|
stopThread (10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int read (char* dest, int numBytes)
|
||||||
|
{
|
||||||
|
int numDone = 0;
|
||||||
|
|
||||||
|
while (numBytes > 0)
|
||||||
|
{
|
||||||
|
const int available = jmin (numBytes, (int) [data length]);
|
||||||
|
|
||||||
|
if (available > 0)
|
||||||
|
{
|
||||||
|
const ScopedLock sl (dataLock);
|
||||||
|
[data getBytes: dest length: (NSUInteger) available];
|
||||||
|
[data replaceBytesInRange: NSMakeRange (0, (NSUInteger) available) withBytes: nil length: 0];
|
||||||
|
|
||||||
|
numDone += available;
|
||||||
|
numBytes -= available;
|
||||||
|
dest += available;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (hasFailed || hasFinished)
|
||||||
|
break;
|
||||||
|
|
||||||
|
Thread::sleep (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return numDone;
|
||||||
|
}
|
||||||
|
|
||||||
|
void didReceiveResponse (NSURLResponse* response)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
const ScopedLock sl (dataLock);
|
||||||
|
[data setLength: 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
initialised = true;
|
||||||
|
contentLength = [response expectedContentLength];
|
||||||
|
|
||||||
|
[headers release];
|
||||||
|
headers = nil;
|
||||||
|
|
||||||
|
if ([response isKindOfClass: [NSHTTPURLResponse class]])
|
||||||
|
{
|
||||||
|
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*) response;
|
||||||
|
headers = [[httpResponse allHeaderFields] retain];
|
||||||
|
statusCode = (int) [httpResponse statusCode];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void didFailWithError (NSError* error)
|
||||||
|
{
|
||||||
|
DBG (nsStringToJuce ([error description])); (void) error;
|
||||||
|
hasFailed = true;
|
||||||
|
initialised = true;
|
||||||
|
signalThreadShouldExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void didReceiveData (NSData* newData)
|
||||||
|
{
|
||||||
|
const ScopedLock sl (dataLock);
|
||||||
|
[data appendData: newData];
|
||||||
|
initialised = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void didSendBodyData (NSInteger /*totalBytesWritten*/, NSInteger /*totalBytesExpected*/)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void finishedLoading()
|
||||||
|
{
|
||||||
|
hasFinished = true;
|
||||||
|
initialised = true;
|
||||||
|
signalThreadShouldExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() override
|
||||||
|
{
|
||||||
|
connection = [[NSURLConnection alloc] initWithRequest: request
|
||||||
|
delegate: delegate];
|
||||||
|
while (! threadShouldExit())
|
||||||
|
{
|
||||||
|
JUCE_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 contentLength;
|
||||||
|
CriticalSection dataLock;
|
||||||
|
NSObject* delegate;
|
||||||
|
NSURLRequest* request;
|
||||||
|
NSURLConnection* connection;
|
||||||
|
NSMutableData* data;
|
||||||
|
NSDictionary* headers;
|
||||||
|
int statusCode;
|
||||||
|
bool initialised, hasFailed, hasFinished;
|
||||||
|
|
||||||
|
private:
|
||||||
|
//==============================================================================
|
||||||
|
struct DelegateClass : public ObjCClass<NSObject>
|
||||||
|
{
|
||||||
|
DelegateClass() : ObjCClass<NSObject> ("JUCEAppDelegate_")
|
||||||
|
{
|
||||||
|
addIvar<URLConnectionState*> ("state");
|
||||||
|
|
||||||
|
addMethod (@selector (connection:didReceiveResponse:), didReceiveResponse, "v@:@@");
|
||||||
|
addMethod (@selector (connection:didFailWithError:), didFailWithError, "v@:@@");
|
||||||
|
addMethod (@selector (connection:didReceiveData:), didReceiveData, "v@:@@");
|
||||||
|
addMethod (@selector (connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:),
|
||||||
|
connectionDidSendBodyData, "v@:@iii");
|
||||||
|
addMethod (@selector (connectionDidFinishLoading:), connectionDidFinishLoading, "v@:@");
|
||||||
|
addMethod (@selector (connection:willSendRequest:redirectResponse:), willSendRequest, "@@:@@");
|
||||||
|
|
||||||
|
registerClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setState (id self, URLConnectionState* state) { object_setInstanceVariable (self, "state", state); }
|
||||||
|
static URLConnectionState* getState (id self) { return getIvar<URLConnectionState*> (self, "state"); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void didReceiveResponse (id self, SEL, NSURLConnection*, NSURLResponse* response)
|
||||||
|
{
|
||||||
|
getState (self)->didReceiveResponse (response);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void didFailWithError (id self, SEL, NSURLConnection*, NSError* error)
|
||||||
|
{
|
||||||
|
getState (self)->didFailWithError (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void didReceiveData (id self, SEL, NSURLConnection*, NSData* newData)
|
||||||
|
{
|
||||||
|
getState (self)->didReceiveData (newData);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NSURLRequest* willSendRequest (id, SEL, NSURLConnection*, NSURLRequest* request, NSURLResponse*)
|
||||||
|
{
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void connectionDidSendBodyData (id self, SEL, NSURLConnection*, NSInteger, NSInteger totalBytesWritten, NSInteger totalBytesExpected)
|
||||||
|
{
|
||||||
|
getState (self)->didSendBodyData (totalBytesWritten, totalBytesExpected);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void connectionDidFinishLoading (id self, SEL, NSURLConnection*)
|
||||||
|
{
|
||||||
|
getState (self)->finishedLoading();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (URLConnectionState)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
class WebInputStream : public InputStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_,
|
||||||
|
URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext,
|
||||||
|
const String& headers_, int timeOutMs_, StringPairArray* responseHeaders)
|
||||||
|
: statusCode (0), address (address_), headers (headers_), postData (postData_), position (0),
|
||||||
|
finished (false), isPost (isPost_), timeOutMs (timeOutMs_)
|
||||||
|
{
|
||||||
|
JUCE_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
createConnection (progressCallback, progressCallbackContext);
|
||||||
|
|
||||||
|
if (responseHeaders != nullptr && connection != nullptr && connection->headers != nil)
|
||||||
|
{
|
||||||
|
statusCode = connection->statusCode;
|
||||||
|
|
||||||
|
NSEnumerator* enumerator = [connection->headers keyEnumerator];
|
||||||
|
|
||||||
|
while (NSString* key = [enumerator nextObject])
|
||||||
|
responseHeaders->set (nsStringToJuce (key),
|
||||||
|
nsStringToJuce ((NSString*) [connection->headers objectForKey: key]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
bool isError() const { return connection == nullptr; }
|
||||||
|
int64 getTotalLength() override { return connection == nullptr ? -1 : connection->contentLength; }
|
||||||
|
bool isExhausted() override { return finished; }
|
||||||
|
int64 getPosition() override { return position; }
|
||||||
|
|
||||||
|
int read (void* buffer, int bytesToRead) override
|
||||||
|
{
|
||||||
|
jassert (buffer != nullptr && bytesToRead >= 0);
|
||||||
|
|
||||||
|
if (finished || isError())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
JUCE_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
const int bytesRead = connection->read (static_cast<char*> (buffer), bytesToRead);
|
||||||
|
position += bytesRead;
|
||||||
|
|
||||||
|
if (bytesRead == 0)
|
||||||
|
finished = true;
|
||||||
|
|
||||||
|
return bytesRead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setPosition (int64 wantedPos) override
|
||||||
|
{
|
||||||
|
if (wantedPos != position)
|
||||||
|
{
|
||||||
|
finished = false;
|
||||||
|
|
||||||
|
if (wantedPos < position)
|
||||||
|
{
|
||||||
|
connection = nullptr;
|
||||||
|
position = 0;
|
||||||
|
createConnection (0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
skipNextBytes (wantedPos - position);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int statusCode;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ScopedPointer<URLConnectionState> connection;
|
||||||
|
String address, headers;
|
||||||
|
MemoryBlock postData;
|
||||||
|
int64 position;
|
||||||
|
bool finished;
|
||||||
|
const bool isPost;
|
||||||
|
const int timeOutMs;
|
||||||
|
|
||||||
|
void createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext)
|
||||||
|
{
|
||||||
|
jassert (connection == nullptr);
|
||||||
|
|
||||||
|
NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: juceStringToNS (address)]
|
||||||
|
cachePolicy: NSURLRequestReloadIgnoringLocalCacheData
|
||||||
|
timeoutInterval: timeOutMs <= 0 ? 60.0 : (timeOutMs / 1000.0)];
|
||||||
|
|
||||||
|
if (req != nil)
|
||||||
|
{
|
||||||
|
[req setHTTPMethod: nsStringLiteral (isPost ? "POST" : "GET")];
|
||||||
|
//[req setCachePolicy: NSURLRequestReloadIgnoringLocalAndRemoteCacheData];
|
||||||
|
|
||||||
|
StringArray headerLines;
|
||||||
|
headerLines.addLines (headers);
|
||||||
|
headerLines.removeEmptyStrings (true);
|
||||||
|
|
||||||
|
for (int i = 0; i < headerLines.size(); ++i)
|
||||||
|
{
|
||||||
|
const String key (headerLines[i].upToFirstOccurrenceOf (":", false, false).trim());
|
||||||
|
const String value (headerLines[i].fromFirstOccurrenceOf (":", false, false).trim());
|
||||||
|
|
||||||
|
if (key.isNotEmpty() && value.isNotEmpty())
|
||||||
|
[req addValue: juceStringToNS (value) forHTTPHeaderField: juceStringToNS (key)];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPost && postData.getSize() > 0)
|
||||||
|
[req setHTTPBody: [NSData dataWithBytes: postData.getData()
|
||||||
|
length: postData.getSize()]];
|
||||||
|
|
||||||
|
connection = new URLConnectionState (req);
|
||||||
|
|
||||||
|
if (! connection->start (progressCallback, progressCallbackContext))
|
||||||
|
connection = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebInputStream)
|
||||||
|
};
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
String String::fromCFString (CFStringRef cfString)
|
||||||
|
{
|
||||||
|
if (cfString == 0)
|
||||||
|
return String();
|
||||||
|
|
||||||
|
CFRange range = { 0, CFStringGetLength (cfString) };
|
||||||
|
CFIndex bytesNeeded = 0;
|
||||||
|
CFStringGetBytes (cfString, range, kCFStringEncodingUTF8, 0, false, nullptr, 0, &bytesNeeded);
|
||||||
|
|
||||||
|
HeapBlock<UInt8> utf8 ((size_t) bytesNeeded + 1);
|
||||||
|
CFStringGetBytes (cfString, range, kCFStringEncodingUTF8, 0, false, utf8, bytesNeeded + 1, nullptr);
|
||||||
|
|
||||||
|
return String (CharPointer_UTF8 ((const CharPointer_UTF8::CharType*) utf8.getData()),
|
||||||
|
CharPointer_UTF8 ((const CharPointer_UTF8::CharType*) utf8.getData() + bytesNeeded));
|
||||||
|
}
|
||||||
|
|
||||||
|
CFStringRef String::toCFString() const
|
||||||
|
{
|
||||||
|
const char* const utf8 = toRawUTF8();
|
||||||
|
return CFStringCreateWithBytes (kCFAllocatorDefault, (const UInt8*) utf8,
|
||||||
|
(CFIndex) strlen (utf8), kCFStringEncodingUTF8, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
String String::convertToPrecomposedUnicode() const
|
||||||
|
{
|
||||||
|
#if JUCE_IOS
|
||||||
|
JUCE_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
return nsStringToJuce ([juceStringToNS (*this) precomposedStringWithCanonicalMapping]);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
UnicodeMapping map;
|
||||||
|
|
||||||
|
map.unicodeEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
|
||||||
|
kUnicodeNoSubset,
|
||||||
|
kTextEncodingDefaultFormat);
|
||||||
|
|
||||||
|
map.otherEncoding = CreateTextEncoding (kTextEncodingUnicodeDefault,
|
||||||
|
kUnicodeCanonicalCompVariant,
|
||||||
|
kTextEncodingDefaultFormat);
|
||||||
|
|
||||||
|
map.mappingVersion = kUnicodeUseLatestMapping;
|
||||||
|
|
||||||
|
UnicodeToTextInfo conversionInfo = 0;
|
||||||
|
String result;
|
||||||
|
|
||||||
|
if (CreateUnicodeToTextInfo (&map, &conversionInfo) == noErr)
|
||||||
|
{
|
||||||
|
const size_t bytesNeeded = CharPointer_UTF16::getBytesRequiredFor (getCharPointer());
|
||||||
|
|
||||||
|
HeapBlock<char> tempOut;
|
||||||
|
tempOut.calloc (bytesNeeded + 4);
|
||||||
|
|
||||||
|
ByteCount bytesRead = 0;
|
||||||
|
ByteCount outputBufferSize = 0;
|
||||||
|
|
||||||
|
if (ConvertFromUnicodeToText (conversionInfo,
|
||||||
|
bytesNeeded, (ConstUniCharArrayPtr) toUTF16().getAddress(),
|
||||||
|
kUnicodeDefaultDirectionMask,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
bytesNeeded, &bytesRead,
|
||||||
|
&outputBufferSize, tempOut) == noErr)
|
||||||
|
{
|
||||||
|
result = String (CharPointer_UTF16 ((CharPointer_UTF16::CharType*) tempOut.getData()));
|
||||||
|
}
|
||||||
|
|
||||||
|
DisposeUnicodeToTextInfo (&conversionInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -0,0 +1,306 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
ScopedAutoReleasePool::ScopedAutoReleasePool()
|
||||||
|
{
|
||||||
|
pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedAutoReleasePool::~ScopedAutoReleasePool()
|
||||||
|
{
|
||||||
|
[((NSAutoreleasePool*) pool) release];
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void Logger::outputDebugString (const String& text)
|
||||||
|
{
|
||||||
|
// Would prefer to use std::cerr here, but avoiding it for
|
||||||
|
// the moment, due to clang JIT linkage problems.
|
||||||
|
fputs (text.toRawUTF8(), stderr);
|
||||||
|
fputs ("\n", stderr);
|
||||||
|
fflush (stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
namespace SystemStatsHelpers
|
||||||
|
{
|
||||||
|
#if JUCE_INTEL && ! JUCE_NO_INLINE_ASM
|
||||||
|
static void doCPUID (uint32& a, uint32& b, uint32& c, uint32& d, uint32 type)
|
||||||
|
{
|
||||||
|
uint32 la = a, lb = b, lc = c, ld = d;
|
||||||
|
|
||||||
|
asm ("mov %%ebx, %%esi \n\t"
|
||||||
|
"cpuid \n\t"
|
||||||
|
"xchg %%esi, %%ebx"
|
||||||
|
: "=a" (la), "=S" (lb), "=c" (lc), "=d" (ld) : "a" (type)
|
||||||
|
#if JUCE_64BIT
|
||||||
|
, "b" (lb), "c" (lc), "d" (ld)
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
|
a = la; b = lb; c = lc; d = ld;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
void CPUInformation::initialise() noexcept
|
||||||
|
{
|
||||||
|
#if JUCE_INTEL && ! JUCE_NO_INLINE_ASM
|
||||||
|
uint32 a = 0, b = 0, d = 0, c = 0;
|
||||||
|
SystemStatsHelpers::doCPUID (a, b, c, d, 1);
|
||||||
|
|
||||||
|
hasMMX = (d & (1u << 23)) != 0;
|
||||||
|
hasSSE = (d & (1u << 25)) != 0;
|
||||||
|
hasSSE2 = (d & (1u << 26)) != 0;
|
||||||
|
has3DNow = (b & (1u << 31)) != 0;
|
||||||
|
hasSSE3 = (c & (1u << 0)) != 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if JUCE_IOS || (MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5)
|
||||||
|
numCpus = (int) [[NSProcessInfo processInfo] activeProcessorCount];
|
||||||
|
#else
|
||||||
|
numCpus = (int) MPProcessors();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if JUCE_MAC
|
||||||
|
struct RLimitInitialiser
|
||||||
|
{
|
||||||
|
RLimitInitialiser()
|
||||||
|
{
|
||||||
|
rlimit lim;
|
||||||
|
getrlimit (RLIMIT_NOFILE, &lim);
|
||||||
|
lim.rlim_cur = lim.rlim_max = RLIM_INFINITY;
|
||||||
|
setrlimit (RLIMIT_NOFILE, &lim);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static RLimitInitialiser rLimitInitialiser;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
#if ! JUCE_IOS
|
||||||
|
static String getOSXVersion()
|
||||||
|
{
|
||||||
|
JUCE_AUTORELEASEPOOL
|
||||||
|
{
|
||||||
|
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfFile:
|
||||||
|
nsStringLiteral ("/System/Library/CoreServices/SystemVersion.plist")];
|
||||||
|
|
||||||
|
return nsStringToJuce ([dict objectForKey: nsStringLiteral ("ProductVersion")]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SystemStats::OperatingSystemType SystemStats::getOperatingSystemType()
|
||||||
|
{
|
||||||
|
#if JUCE_IOS
|
||||||
|
return iOS;
|
||||||
|
#else
|
||||||
|
StringArray parts;
|
||||||
|
parts.addTokens (getOSXVersion(), ".", StringRef());
|
||||||
|
|
||||||
|
jassert (parts[0].getIntValue() == 10);
|
||||||
|
const int major = parts[1].getIntValue();
|
||||||
|
jassert (major > 2);
|
||||||
|
|
||||||
|
return (OperatingSystemType) (major + MacOSX_10_4 - 4);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getOperatingSystemName()
|
||||||
|
{
|
||||||
|
#if JUCE_IOS
|
||||||
|
return "iOS " + nsStringToJuce ([[UIDevice currentDevice] systemVersion]);
|
||||||
|
#else
|
||||||
|
return "Mac OSX " + getOSXVersion();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getDeviceDescription()
|
||||||
|
{
|
||||||
|
#if JUCE_IOS
|
||||||
|
return nsStringToJuce ([[UIDevice currentDevice] model]);
|
||||||
|
#else
|
||||||
|
return String();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SystemStats::isOperatingSystem64Bit()
|
||||||
|
{
|
||||||
|
#if JUCE_IOS
|
||||||
|
return false;
|
||||||
|
#elif JUCE_64BIT
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return getOperatingSystemType() >= MacOSX_10_6;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int SystemStats::getMemorySizeInMegabytes()
|
||||||
|
{
|
||||||
|
uint64 mem = 0;
|
||||||
|
size_t memSize = sizeof (mem);
|
||||||
|
int mib[] = { CTL_HW, HW_MEMSIZE };
|
||||||
|
sysctl (mib, 2, &mem, &memSize, 0, 0);
|
||||||
|
return (int) (mem / (1024 * 1024));
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getCpuVendor()
|
||||||
|
{
|
||||||
|
#if JUCE_INTEL && ! JUCE_NO_INLINE_ASM
|
||||||
|
uint32 dummy = 0;
|
||||||
|
uint32 vendor[4] = { 0 };
|
||||||
|
|
||||||
|
SystemStatsHelpers::doCPUID (dummy, vendor[0], vendor[2], vendor[1], 0);
|
||||||
|
|
||||||
|
return String (reinterpret_cast <const char*> (vendor), 12);
|
||||||
|
#else
|
||||||
|
return String();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int SystemStats::getCpuSpeedInMegaherz()
|
||||||
|
{
|
||||||
|
uint64 speedHz = 0;
|
||||||
|
size_t speedSize = sizeof (speedHz);
|
||||||
|
int mib[] = { CTL_HW, HW_CPU_FREQ };
|
||||||
|
sysctl (mib, 2, &speedHz, &speedSize, 0, 0);
|
||||||
|
|
||||||
|
#if JUCE_BIG_ENDIAN
|
||||||
|
if (speedSize == 4)
|
||||||
|
speedHz >>= 32;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return (int) (speedHz / 1000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
String SystemStats::getLogonName()
|
||||||
|
{
|
||||||
|
return nsStringToJuce (NSUserName());
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getFullUserName()
|
||||||
|
{
|
||||||
|
return nsStringToJuce (NSFullUserName());
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getComputerName()
|
||||||
|
{
|
||||||
|
char name [256] = { 0 };
|
||||||
|
if (gethostname (name, sizeof (name) - 1) == 0)
|
||||||
|
return String (name).upToLastOccurrenceOf (".local", false, true);
|
||||||
|
|
||||||
|
return String();
|
||||||
|
}
|
||||||
|
|
||||||
|
static String getLocaleValue (CFStringRef key)
|
||||||
|
{
|
||||||
|
CFLocaleRef cfLocale = CFLocaleCopyCurrent();
|
||||||
|
const String result (String::fromCFString ((CFStringRef) CFLocaleGetValue (cfLocale, key)));
|
||||||
|
CFRelease (cfLocale);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
String SystemStats::getUserLanguage() { return getLocaleValue (kCFLocaleLanguageCode); }
|
||||||
|
String SystemStats::getUserRegion() { return getLocaleValue (kCFLocaleCountryCode); }
|
||||||
|
|
||||||
|
String SystemStats::getDisplayLanguage()
|
||||||
|
{
|
||||||
|
CFArrayRef cfPrefLangs = CFLocaleCopyPreferredLanguages();
|
||||||
|
const String result (String::fromCFString ((CFStringRef) CFArrayGetValueAtIndex (cfPrefLangs, 0)));
|
||||||
|
CFRelease (cfPrefLangs);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
/* 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:
|
||||||
|
HiResCounterInfo()
|
||||||
|
{
|
||||||
|
mach_timebase_info_data_t timebase;
|
||||||
|
(void) mach_timebase_info (&timebase);
|
||||||
|
|
||||||
|
if (timebase.numer % 1000000 == 0)
|
||||||
|
{
|
||||||
|
hiResCounterNumerator = timebase.numer / 1000000;
|
||||||
|
hiResCounterDenominator = timebase.denom;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hiResCounterNumerator = timebase.numer;
|
||||||
|
hiResCounterDenominator = timebase.denom * (uint64) 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
highResTimerFrequency = (timebase.denom * (uint64) 1000000000) / timebase.numer;
|
||||||
|
highResTimerToMillisecRatio = hiResCounterNumerator / (double) hiResCounterDenominator;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 millisecondsSinceStartup() const noexcept
|
||||||
|
{
|
||||||
|
return (uint32) ((mach_absolute_time() * hiResCounterNumerator) / hiResCounterDenominator);
|
||||||
|
}
|
||||||
|
|
||||||
|
double getMillisecondCounterHiRes() const noexcept
|
||||||
|
{
|
||||||
|
return mach_absolute_time() * highResTimerToMillisecRatio;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 highResTimerFrequency;
|
||||||
|
|
||||||
|
private:
|
||||||
|
double highResTimerToMillisecRatio;
|
||||||
|
};
|
||||||
|
|
||||||
|
static HiResCounterInfo hiResCounterInfo;
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
jassertfalse;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
int SystemStats::getPageSize()
|
||||||
|
{
|
||||||
|
return (int) NSPageSize();
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
==============================================================================
|
||||||
|
|
||||||
|
This file is part of the juce_core module of the JUCE library.
|
||||||
|
Copyright (c) 2013 - Raw Material Software Ltd.
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any purpose with
|
||||||
|
or without fee is hereby granted, provided that the above copyright notice and this
|
||||||
|
permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
|
||||||
|
TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
|
||||||
|
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
||||||
|
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
NOTE! This permissive ISC license applies ONLY to files within the juce_core module!
|
||||||
|
All other JUCE modules are covered by a dual GPL/commercial license, so if you are
|
||||||
|
using any other modules, be sure to check that you also comply with their license.
|
||||||
|
|
||||||
|
For more details, visit www.juce.com
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Note that a lot of methods that you'd expect to find in this file actually
|
||||||
|
live in juce_posix_SharedCode.h!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if JUCE_IOS
|
||||||
|
bool isIOSAppActive = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
JUCE_API bool JUCE_CALLTYPE Process::isForegroundProcess()
|
||||||
|
{
|
||||||
|
#if JUCE_MAC
|
||||||
|
return [NSApp isActive];
|
||||||
|
#else
|
||||||
|
return isIOSAppActive;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
JUCE_API void JUCE_CALLTYPE Process::makeForegroundProcess()
|
||||||
|
{
|
||||||
|
#if JUCE_MAC
|
||||||
|
[NSApp activateIgnoringOtherApps: YES];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
JUCE_API void JUCE_CALLTYPE Process::hide()
|
||||||
|
{
|
||||||
|
#if JUCE_MAC
|
||||||
|
[NSApp hide: nil];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
JUCE_API void JUCE_CALLTYPE Process::raisePrivilege()
|
||||||
|
{
|
||||||
|
jassertfalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
JUCE_API void JUCE_CALLTYPE Process::lowerPrivilege()
|
||||||
|
{
|
||||||
|
jassertfalse;
|
||||||
|
}
|
||||||
|
|
||||||
|
JUCE_API void JUCE_CALLTYPE Process::setPriority (ProcessPriority)
|
||||||
|
{
|
||||||
|
// xxx
|
||||||
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger()
|
||||||
|
{
|
||||||
|
static char testResult = 0;
|
||||||
|
|
||||||
|
if (testResult == 0)
|
||||||
|
{
|
||||||
|
struct kinfo_proc info;
|
||||||
|
int m[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
|
||||||
|
size_t sz = sizeof (info);
|
||||||
|
sysctl (m, 4, &info, &sz, 0, 0);
|
||||||
|
testResult = ((info.kp_proc.p_flag & P_TRACED) != 0) ? 1 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return testResult > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
JUCE_API bool JUCE_CALLTYPE Process::isRunningUnderDebugger()
|
||||||
|
{
|
||||||
|
return juce_isRunningUnderDebugger();
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user