@@ -24,8 +24,8 @@ | |||
#endif | |||
// Set Version | |||
#define CARLA_VERSION_HEX 0x01090 | |||
#define CARLA_VERSION_STRING "1.9.0" | |||
#define CARLA_VERSION_HEX 0x01091 | |||
#define CARLA_VERSION_STRING "1.9.1" | |||
// Check OS | |||
#if defined(WIN64) || defined(_WIN64) || defined(__WIN64__) | |||
@@ -68,6 +68,17 @@ | |||
# define nullptr (0) | |||
#endif | |||
// Common includes | |||
#ifdef CARLA_OS_WIN | |||
# include <winsock2.h> | |||
# include <windows.h> | |||
#else | |||
# include <unistd.h> | |||
# ifndef __cdecl | |||
# define __cdecl | |||
# endif | |||
#endif | |||
// Define various string format types | |||
#if defined(CARLA_OS_WIN64) | |||
# define P_INT64 "%I64i" | |||
@@ -20,7 +20,7 @@ | |||
#include "CarlaLibUtils.hpp" | |||
#include "CarlaMutex.hpp" | |||
#include "RtList.hpp" | |||
#include "List.hpp" | |||
// ----------------------------------------------------------------------- | |||
@@ -33,9 +33,9 @@ public: | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(filename != nullptr, nullptr); | |||
const CarlaMutex::ScopedLocker sl(mutex); | |||
const CarlaMutex::ScopedLocker sl(fMutex); | |||
for (NonRtList<Lib>::Itenerator it = libs.begin(); it.valid(); it.next()) | |||
for (List<Lib>::Itenerator it = fLibs.begin(); it.valid(); it.next()) | |||
{ | |||
Lib& lib(*it); | |||
CARLA_ASSERT(lib.count > 0); | |||
@@ -58,7 +58,7 @@ public: | |||
lib.filename = carla_strdup(filename); | |||
lib.count = 1; | |||
libs.append(lib); | |||
fLibs.append(lib); | |||
return libPtr; | |||
} | |||
@@ -67,9 +67,9 @@ public: | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(libPtr != nullptr, false); | |||
const CarlaMutex::ScopedLocker sl(mutex); | |||
const CarlaMutex::ScopedLocker sl(fMutex); | |||
for (NonRtList<Lib>::Itenerator it = libs.begin(); it.valid(); it.next()) | |||
for (List<Lib>::Itenerator it = fLibs.begin(); it.valid(); it.next()) | |||
{ | |||
Lib& lib(*it); | |||
CARLA_ASSERT(lib.count > 0); | |||
@@ -89,7 +89,7 @@ public: | |||
lib_close(lib.lib); | |||
lib.lib = nullptr; | |||
libs.remove(it); | |||
fLibs.remove(it); | |||
} | |||
return true; | |||
@@ -106,8 +106,8 @@ private: | |||
int count; | |||
}; | |||
CarlaMutex mutex; | |||
NonRtList<Lib> libs; | |||
List<Lib> fLibs; | |||
CarlaMutex fMutex; | |||
}; | |||
// ----------------------------------------------------------------------- | |||
@@ -20,6 +20,10 @@ | |||
#include "CarlaUtils.hpp" | |||
#ifndef CARLA_OS_WIN | |||
# include <dlfcn.h> | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
// library related calls | |||
@@ -27,24 +31,75 @@ | |||
* Open 'filename' library (must not be null). | |||
* May return null, in which case "lib_error" has the error. | |||
*/ | |||
void* lib_open(const char* const filename); | |||
static inline | |||
void* lib_open(const char* const filename) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(filename != nullptr, nullptr); | |||
#ifdef CARLA_OS_WIN | |||
return (void*)LoadLibraryA(filename); | |||
#else | |||
return dlopen(filename, RTLD_NOW|RTLD_LOCAL); | |||
#endif | |||
} | |||
/* | |||
* Close a previously opened library (must not be null). | |||
* If false is returned,"lib_error" has the error. | |||
*/ | |||
bool lib_close(void* const lib); | |||
static inline | |||
bool lib_close(void* const lib) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(lib != nullptr, false); | |||
#ifdef CARLA_OS_WIN | |||
return FreeLibrary((HMODULE)lib); | |||
#else | |||
return (dlclose(lib) == 0); | |||
#endif | |||
} | |||
/* | |||
* Get a library symbol (must not be null). | |||
* May return null if the symbol is not found. | |||
*/ | |||
void* lib_symbol(void* const lib, const char* const symbol); | |||
static inline | |||
void* lib_symbol(void* const lib, const char* const symbol) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(lib != nullptr, nullptr); | |||
CARLA_SAFE_ASSERT_RETURN(symbol != nullptr, nullptr); | |||
#ifdef CARLA_OS_WIN | |||
return (void*)GetProcAddress((HMODULE)lib, symbol); | |||
#else | |||
return dlsym(lib, symbol); | |||
#endif | |||
} | |||
/* | |||
* Return the last operation error ('filename' must not be null). | |||
*/ | |||
const char* lib_error(const char* const filename); | |||
static inline | |||
const char* lib_error(const char* const filename) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(filename != nullptr, nullptr); | |||
#ifdef CARLA_OS_WIN | |||
static char libError[2048+1]; | |||
carla_zeroChar(libError, 2048+1); | |||
LPVOID winErrorString; | |||
DWORD winErrorCode = GetLastError(); | |||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, winErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&winErrorString, 0, nullptr); | |||
std::snprintf(libError, 2048, "%s: error code %li: %s", filename, winErrorCode, (const char*)winErrorString); | |||
LocalFree(winErrorString); | |||
return libError; | |||
#else | |||
return dlerror(); | |||
#endif | |||
} | |||
// ----------------------------------------------------------------------- | |||
@@ -20,8 +20,7 @@ | |||
#include "CarlaBackend.hpp" | |||
#include "CarlaString.hpp" | |||
#include "juce_core.h" | |||
#include "CarlaThread.hpp" | |||
#include <fcntl.h> | |||
@@ -30,11 +29,11 @@ using CarlaBackend::CallbackFunc; | |||
// ----------------------------------------------------------------------- | |||
// Log thread | |||
class CarlaLogThread : public juce::Thread | |||
class CarlaLogThread : public CarlaThread | |||
{ | |||
public: | |||
CarlaLogThread() | |||
: Thread("CarlaLogThread"), | |||
: CarlaThread("CarlaLogThread"), | |||
fCallback(nullptr), | |||
fCallbackPtr(nullptr) | |||
{ | |||
@@ -50,7 +49,7 @@ public: | |||
fcntl(fPipe[0], F_SETFL, O_NONBLOCK); | |||
startThread(2); | |||
start(2); | |||
} | |||
~CarlaLogThread() | |||
@@ -58,7 +57,7 @@ public: | |||
fCallback = nullptr; | |||
fCallbackPtr = nullptr; | |||
stopThread(5000); | |||
stop(5000); | |||
fflush(stdout); | |||
fflush(stderr); | |||
@@ -78,7 +77,7 @@ public: | |||
protected: | |||
void run() | |||
{ | |||
while (! threadShouldExit()) | |||
while (! shouldExit()) | |||
{ | |||
size_t r, lastRead; | |||
ssize_t r2; // to avoid sign/unsign conversions | |||
@@ -142,7 +141,8 @@ private: | |||
void* fCallbackPtr; | |||
CarlaString fOldBuffer; | |||
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaLogThread) | |||
CARLA_PREVENT_HEAP_ALLOCATION | |||
CARLA_DECLARE_NON_COPY_CLASS(CarlaLogThread) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
@@ -406,7 +406,6 @@ private: | |||
bool fNeedsInit; | |||
CARLA_PREVENT_HEAP_ALLOCATION | |||
CARLA_DECLARE_NON_COPY_CLASS(Lv2WorldClass) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
@@ -18,7 +18,7 @@ | |||
#ifndef CARLA_MUTEX_HPP_INCLUDED | |||
#define CARLA_MUTEX_HPP_INCLUDED | |||
#include "CarlaJuceUtils.hpp" | |||
#include "CarlaUtils.hpp" | |||
#include <pthread.h> | |||
@@ -39,7 +39,7 @@ public: | |||
pthread_mutexattr_settype(&atts, PTHREAD_MUTEX_RECURSIVE); | |||
pthread_mutex_init(&fMutex, &atts); | |||
pthread_mutexattr_destroy (&atts); | |||
pthread_mutexattr_destroy(&atts); | |||
} | |||
/* | |||
@@ -18,7 +18,7 @@ | |||
#ifndef CARLA_OSC_UTILS_HPP_INCLUDED | |||
#define CARLA_OSC_UTILS_HPP_INCLUDED | |||
#include "CarlaJuceUtils.hpp" | |||
#include "CarlaUtils.hpp" | |||
#include <lo/lo.h> | |||
@@ -19,7 +19,7 @@ | |||
#ifndef CARLA_RING_BUFFER_HPP_INCLUDED | |||
#define CARLA_RING_BUFFER_HPP_INCLUDED | |||
#include "CarlaJuceUtils.hpp" | |||
#include "CarlaUtils.hpp" | |||
#ifndef RING_BUFFER_SIZE | |||
# define RING_BUFFER_SIZE 2048 | |||
@@ -42,10 +42,10 @@ class RingBufferControl | |||
{ | |||
public: | |||
RingBufferControl(RingBuffer* const ringBuf) | |||
: fRingBuf(nullptr) | |||
: fRingBuf(ringBuf) | |||
{ | |||
if (ringBuf != nullptr) | |||
setRingBuffer(ringBuf, true); | |||
clear(); | |||
} | |||
void clear() | |||
@@ -89,7 +89,7 @@ public: | |||
} | |||
} | |||
bool dataAvailable() const | |||
bool isDataAvailable() const | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(fRingBuf != nullptr, false); | |||
@@ -20,7 +20,7 @@ | |||
#include "CarlaBackendUtils.hpp" | |||
#include "CarlaMIDI.h" | |||
#include "RtList.hpp" | |||
#include "List.hpp" | |||
#include "juce_core.h" | |||
@@ -93,11 +93,11 @@ struct StateCustomData { | |||
CARLA_DECLARE_NON_COPY_STRUCT(StateCustomData) | |||
}; | |||
typedef NonRtList<StateParameter*> StateParameterList; | |||
typedef NonRtList<StateCustomData*> StateCustomDataList; | |||
typedef List<StateParameter*> StateParameterList; | |||
typedef List<StateCustomData*> StateCustomDataList; | |||
typedef NonRtList<StateParameter*>::Itenerator StateParameterItenerator; | |||
typedef NonRtList<StateCustomData*>::Itenerator StateCustomDataItenerator; | |||
typedef List<StateParameter*>::Itenerator StateParameterItenerator; | |||
typedef List<StateCustomData*>::Itenerator StateCustomDataItenerator; | |||
struct SaveState { | |||
const char* type; | |||
@@ -18,9 +18,7 @@ | |||
#ifndef CARLA_STRING_HPP_INCLUDED | |||
#define CARLA_STRING_HPP_INCLUDED | |||
#include "CarlaJuceUtils.hpp" | |||
#include <cstdio> // for *printf | |||
#include "CarlaUtils.hpp" | |||
// ----------------------------------------------------------------------- | |||
// CarlaString class | |||
@@ -680,7 +678,6 @@ private: | |||
} | |||
CARLA_PREVENT_HEAP_ALLOCATION | |||
CARLA_LEAK_DETECTOR(CarlaString) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
@@ -84,7 +84,7 @@ public: | |||
fShouldExit = false; | |||
if (pthread_create(const_cast<pthread_t*>(&fHandle), nullptr, _threadEntryPoint, this) == 0) | |||
if (pthread_create(const_cast<pthread_t*>(&fHandle), nullptr, _entryPoint, this) == 0) | |||
{ | |||
#if (__GLIBC__ * 1000 + __GLIBC_MINOR__) >= 2012 | |||
if (fName.isNotEmpty()) | |||
@@ -154,10 +154,10 @@ public: | |||
} | |||
private: | |||
CarlaMutex fLock; // Thread lock | |||
const CarlaString fName; // Thread name | |||
volatile pthread_t fHandle; // Handle for this thread | |||
volatile bool fShouldExit; // ... | |||
const CarlaString fName; // Thread name | |||
volatile CarlaMutex fLock; // Thread lock | |||
volatile pthread_t fHandle; // Handle for this thread | |||
volatile bool fShouldExit; // true if thread should exit | |||
void _init() noexcept | |||
{ | |||
@@ -169,17 +169,8 @@ private: | |||
#endif | |||
} | |||
static void* _threadEntryPoint(void* userData) | |||
void _runEntryPoint() | |||
{ | |||
static_cast<CarlaThread*>(userData)->threadEntryPoint(); | |||
return nullptr; | |||
} | |||
void threadEntryPoint() | |||
{ | |||
//if (fName.isNotEmpty()) | |||
// setCurrentThreadName(threadName); | |||
// tell dad we're ready | |||
fLock.unlock(); | |||
@@ -189,6 +180,12 @@ private: | |||
_init(); | |||
} | |||
static void* _entryPoint(void* userData) | |||
{ | |||
static_cast<CarlaThread*>(userData)->_runEntryPoint(); | |||
return nullptr; | |||
} | |||
CARLA_PREVENT_HEAP_ALLOCATION | |||
CARLA_DECLARE_NON_COPY_CLASS(CarlaThread) | |||
}; | |||
@@ -20,7 +20,17 @@ | |||
#include "CarlaDefines.hpp" | |||
#include <cstring> // for memcpy and memset | |||
#include <cassert> | |||
#include <cstdarg> | |||
#include <cstdio> | |||
#include <cstdlib> | |||
#include <cstring> | |||
#ifdef CARLA_PROPER_CPP11_SUPPORT | |||
# include <cstdint> | |||
#else | |||
# include <stdint.h> | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
// misc functions | |||
@@ -28,7 +38,7 @@ | |||
/* | |||
* Return "true" or "false" according to yesNo. | |||
*/ | |||
inline | |||
static inline | |||
const char* bool2str(const bool yesNo) noexcept | |||
{ | |||
return yesNo ? "true" : "false"; | |||
@@ -37,7 +47,7 @@ const char* bool2str(const bool yesNo) noexcept | |||
/* | |||
* Dummy function. | |||
*/ | |||
inline | |||
static inline | |||
void pass() noexcept {} | |||
// ----------------------------------------------------------------------- | |||
@@ -50,23 +60,57 @@ void pass() noexcept {} | |||
#ifndef DEBUG | |||
# define carla_debug(...) | |||
#else | |||
void carla_debug(const char* const fmt, ...); | |||
static inline | |||
void carla_debug(const char* const fmt, ...) | |||
{ | |||
va_list args; | |||
va_start(args, fmt); | |||
std::fprintf(stdout, "\x1b[30;1m"); | |||
std::vfprintf(stdout, fmt, args); | |||
std::fprintf(stdout, "\x1b[0m\n"); | |||
va_end(args); | |||
} | |||
#endif | |||
/* | |||
* Print a string to stdout with newline. | |||
*/ | |||
void carla_stdout(const char* const fmt, ...); | |||
static inline | |||
void carla_stdout(const char* const fmt, ...) | |||
{ | |||
va_list args; | |||
va_start(args, fmt); | |||
std::vfprintf(stdout, fmt, args); | |||
std::fprintf(stdout, "\n"); | |||
va_end(args); | |||
} | |||
/* | |||
* Print a string to stderr with newline. | |||
*/ | |||
void carla_stderr(const char* const fmt, ...); | |||
static inline | |||
void carla_stderr(const char* const fmt, ...) | |||
{ | |||
va_list args; | |||
va_start(args, fmt); | |||
std::vfprintf(stderr, fmt, args); | |||
std::fprintf(stderr, "\n"); | |||
va_end(args); | |||
} | |||
/* | |||
* Print a string to stderr with newline (red color). | |||
*/ | |||
void carla_stderr2(const char* const fmt, ...); | |||
static inline | |||
void carla_stderr2(const char* const fmt, ...) | |||
{ | |||
va_list args; | |||
va_start(args, fmt); | |||
std::fprintf(stderr, "\x1b[31m"); | |||
std::vfprintf(stderr, fmt, args); | |||
std::fprintf(stderr, "\x1b[0m\n"); | |||
va_end(args); | |||
} | |||
// ----------------------------------------------------------------------- | |||
// carla_safe_assert* | |||
@@ -74,7 +118,7 @@ void carla_stderr2(const char* const fmt, ...); | |||
/* | |||
* Print a safe assertion error message. | |||
*/ | |||
inline | |||
static inline | |||
void carla_safe_assert(const char* const assertion, const char* const file, const int line) | |||
{ | |||
carla_stderr2("Carla assertion failure: \"%s\" in file %s, line %i", assertion, file, line); | |||
@@ -83,7 +127,7 @@ void carla_safe_assert(const char* const assertion, const char* const file, cons | |||
/* | |||
* Print a safe assertion error message, with 1 extra integer value. | |||
*/ | |||
inline | |||
static inline | |||
void carla_safe_assert_int(const char* const assertion, const char* const file, const int line, const int value) | |||
{ | |||
carla_stderr2("Carla assertion failure: \"%s\" in file %s, line %i, value %i", assertion, file, line, value); | |||
@@ -92,7 +136,7 @@ void carla_safe_assert_int(const char* const assertion, const char* const file, | |||
/* | |||
* Print a safe assertion error message, with 2 extra integer values. | |||
*/ | |||
inline | |||
static inline | |||
void carla_safe_assert_int2(const char* const assertion, const char* const file, const int line, const int v1, const int v2) | |||
{ | |||
carla_stderr2("Carla assertion failure: \"%s\" in file %s, line %i, v1 %i, v2 %i", assertion, file, line, v1, v2); | |||
@@ -104,12 +148,32 @@ void carla_safe_assert_int2(const char* const assertion, const char* const file, | |||
/* | |||
* Sleep for 'secs' seconds. | |||
*/ | |||
void carla_sleep(const unsigned int secs); | |||
static inline | |||
void carla_sleep(const unsigned int secs) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(secs > 0,); | |||
#ifdef CARLA_OS_WIN | |||
Sleep(secs * 1000); | |||
#else | |||
sleep(secs); | |||
#endif | |||
} | |||
/* | |||
* Sleep for 'msecs' milliseconds. | |||
*/ | |||
void carla_msleep(const unsigned int msecs); | |||
static inline | |||
void carla_msleep(const unsigned int msecs) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(msecs > 0,); | |||
#ifdef CARLA_OS_WIN | |||
Sleep(msecs); | |||
#else | |||
usleep(msecs * 1000); | |||
#endif | |||
} | |||
// ----------------------------------------------------------------------- | |||
// carla_setenv | |||
@@ -117,7 +181,18 @@ void carla_msleep(const unsigned int msecs); | |||
/* | |||
* Set environment variable 'key' to 'value'. | |||
*/ | |||
void carla_setenv(const char* const key, const char* const value); | |||
static inline | |||
void carla_setenv(const char* const key, const char* const value) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(key != nullptr,); | |||
CARLA_SAFE_ASSERT_RETURN(value != nullptr,); | |||
#ifdef CARLA_OS_WIN | |||
SetEnvironmentVariableA(key, value); | |||
#else | |||
setenv(key, value, 1); | |||
#endif | |||
} | |||
// ----------------------------------------------------------------------- | |||
// carla_strdup | |||
@@ -126,14 +201,34 @@ void carla_setenv(const char* const key, const char* const value); | |||
* Custom 'strdup' function. | |||
* Return value is always valid, and must be freed with "delete[] var". | |||
*/ | |||
const char* carla_strdup(const char* const strBuf); | |||
static inline | |||
const char* carla_strdup(const char* const strBuf) | |||
{ | |||
CARLA_SAFE_ASSERT(strBuf != nullptr); | |||
const size_t bufferLen = (strBuf != nullptr) ? std::strlen(strBuf) : 0; | |||
char* const buffer = new char[bufferLen+1]; | |||
if (strBuf != nullptr && bufferLen > 0) | |||
std::strncpy(buffer, strBuf, bufferLen); | |||
buffer[bufferLen] = '\0'; | |||
return buffer; | |||
} | |||
/* | |||
* Custom 'strdup' function. | |||
* Calls "std::free(strBuf)". | |||
* Return value is always valid, and must be freed with "delete[] var". | |||
*/ | |||
const char* carla_strdup_free(char* const strBuf); | |||
static inline | |||
const char* carla_strdup_free(char* const strBuf) | |||
{ | |||
const char* const buffer(carla_strdup(strBuf)); | |||
std::free(strBuf); | |||
return buffer; | |||
} | |||
// ----------------------------------------------------------------------- | |||
// math functions | |||
@@ -141,7 +236,8 @@ const char* carla_strdup_free(char* const strBuf); | |||
/* | |||
* Return the lower of 2 values, with 'min' as the minimum possible value. | |||
*/ | |||
template<typename T> inline | |||
template<typename T> | |||
static inline | |||
const T& carla_min(const T& v1, const T& v2, const T& min) noexcept | |||
{ | |||
return ((v1 <= min || v2 <= min) ? min : (v1 < v2 ? v1 : v2)); | |||
@@ -150,7 +246,8 @@ const T& carla_min(const T& v1, const T& v2, const T& min) noexcept | |||
/* | |||
* Return the higher of 2 values, with 'max' as the maximum possible value. | |||
*/ | |||
template<typename T> inline | |||
template<typename T> | |||
static inline | |||
const T& carla_max(const T& v1, const T& v2, const T& max) noexcept | |||
{ | |||
return ((v1 >= max || v2 >= max) ? max : (v1 > v2 ? v1 : v2)); | |||
@@ -159,7 +256,8 @@ const T& carla_max(const T& v1, const T& v2, const T& max) noexcept | |||
/* | |||
* Fix bounds of 'value', between 'min' and 'max'. | |||
*/ | |||
template<typename T> inline | |||
template<typename T> | |||
static inline | |||
const T& carla_fixValue(const T& min, const T& max, const T& value) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(max > min, max); | |||
@@ -174,7 +272,8 @@ const T& carla_fixValue(const T& min, const T& max, const T& value) | |||
/* | |||
* Add array values to another array. | |||
*/ | |||
template<typename T> inline | |||
template<typename T> | |||
static inline | |||
void carla_add(T* dataDst, T* dataSrc, const size_t size) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(dataDst != nullptr,); | |||
@@ -188,7 +287,8 @@ void carla_add(T* dataDst, T* dataSrc, const size_t size) | |||
/* | |||
* Add array values to another array. | |||
*/ | |||
template<typename T> inline | |||
template<typename T> | |||
static inline | |||
void carla_add(T* dataDst, const T* dataSrc, const size_t size) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(dataDst != nullptr,); | |||
@@ -202,7 +302,8 @@ void carla_add(T* dataDst, const T* dataSrc, const size_t size) | |||
/* | |||
* Fill an array with a fixed value. | |||
*/ | |||
template<typename T> inline | |||
template<typename T> | |||
static inline | |||
void carla_fill(T* data, const size_t size, const T v) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(data != nullptr,); | |||
@@ -235,7 +336,8 @@ inline float | |||
/* | |||
* Clear a char array. | |||
*/ | |||
template<typename C = char> inline | |||
template<typename C = char> | |||
static inline | |||
void carla_zeroChar(C* const data, const size_t numChars) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(data != nullptr,); | |||
@@ -247,7 +349,7 @@ void carla_zeroChar(C* const data, const size_t numChars) | |||
/* | |||
* Clear a memory location. | |||
*/ | |||
inline | |||
static inline | |||
void carla_zeroMem(void* const memory, const size_t numBytes) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(memory != nullptr,); | |||
@@ -259,7 +361,8 @@ void carla_zeroMem(void* const memory, const size_t numBytes) | |||
/* | |||
* Clear a single struct/class. | |||
*/ | |||
template <typename T> inline | |||
template <typename T> | |||
static inline | |||
void carla_zeroStruct(T& structure) | |||
{ | |||
std::memset(&structure, 0, sizeof(T)); | |||
@@ -268,7 +371,8 @@ void carla_zeroStruct(T& structure) | |||
/* | |||
* Clear an array of struct/class. | |||
*/ | |||
template <typename T> inline | |||
template <typename T> | |||
static inline | |||
void carla_zeroStruct(T* const structure, const size_t count) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(structure != nullptr,); | |||
@@ -277,12 +381,11 @@ void carla_zeroStruct(T* const structure, const size_t count) | |||
std::memset(structure, 0, count*sizeof(T)); | |||
} | |||
// ----------------------------------------------------------------------- | |||
/* | |||
* Copy a single struct/class. | |||
*/ | |||
template <typename T> inline | |||
template <typename T> | |||
static inline | |||
void carla_copyStruct(T& struct1, T& struct2) | |||
{ | |||
std::memcpy(&struct1, &struct2, sizeof(T)); | |||
@@ -291,7 +394,8 @@ void carla_copyStruct(T& struct1, T& struct2) | |||
/* | |||
* Copy an array of struct/class. | |||
*/ | |||
template <typename T> inline | |||
template <typename T> | |||
static inline | |||
void carla_copyStruct(T* const struct1, T* const struct2, const size_t count) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(struct1 != nullptr,); | |||
@@ -20,8 +20,6 @@ | |||
#include "CarlaUtils.hpp" | |||
#include <cstring> | |||
// ----------------------------------------------------------------------- | |||
// Include fixes | |||
@@ -24,10 +24,10 @@ | |||
namespace juce { | |||
class JucePluginWindow : public DocumentWindow | |||
class PluginWindow : public DocumentWindow | |||
{ | |||
public: | |||
JucePluginWindow() | |||
PluginWindow() | |||
: DocumentWindow("PluginWindow", Colour(50, 50, 200), DocumentWindow::closeButton, false), | |||
fClosed(false) | |||
{ | |||
@@ -75,12 +75,12 @@ protected: | |||
private: | |||
volatile bool fClosed; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(JucePluginWindow) | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow) | |||
}; | |||
} // namespace juce | |||
using juce::JucePluginWindow; | |||
typedef juce::PluginWindow JucePluginWindow; | |||
// ----------------------------------------------------------------------- | |||
@@ -0,0 +1,420 @@ | |||
/* | |||
* High-level, templated, C++ doubly-linked list | |||
* Copyright (C) 2013 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU General Public License as | |||
* published by the Free Software Foundation; either version 2 of | |||
* the License, or any later version. | |||
* | |||
* This program 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. | |||
* | |||
* For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
*/ | |||
#ifndef LIST_HPP_INCLUDED | |||
#define LIST_HPP_INCLUDED | |||
#include "CarlaUtils.hpp" | |||
#include <new> | |||
extern "C" { | |||
#include "rtmempool/list.h" | |||
} | |||
// Declare non copyable and prevent heap allocation | |||
#ifdef CARLA_PROPER_CPP11_SUPPORT | |||
# define LIST_DECLARATIONS(ClassName) \ | |||
ClassName(ClassName&) = delete; \ | |||
ClassName(const ClassName&) = delete; \ | |||
ClassName& operator=(const ClassName&) = delete; \ | |||
static void* operator new(size_t) = delete; | |||
#else | |||
# define LIST_DECLARATIONS(ClassName) \ | |||
ClassName(ClassName&); \ | |||
ClassName(const ClassName&); \ | |||
ClassName& operator=(const ClassName&); | |||
#endif | |||
typedef struct list_head k_list_head; | |||
// ----------------------------------------------------------------------- | |||
// Abstract List class | |||
// _allocate() and _deallocate are virtual calls provided by subclasses | |||
template<typename T> | |||
class AbstractList | |||
{ | |||
protected: | |||
struct Data { | |||
T value; | |||
k_list_head siblings; | |||
}; | |||
AbstractList() | |||
: fDataSize(sizeof(Data)), | |||
fCount(0) | |||
{ | |||
_init(); | |||
} | |||
virtual ~AbstractList() | |||
{ | |||
CARLA_ASSERT(fCount == 0); | |||
} | |||
public: | |||
class Itenerator { | |||
public: | |||
Itenerator(const k_list_head* queue) | |||
: fData(nullptr), | |||
fEntry(queue->next), | |||
fEntry2(fEntry->next), | |||
fQueue(queue) | |||
{ | |||
CARLA_ASSERT(fEntry != nullptr); | |||
CARLA_ASSERT(fEntry2 != nullptr); | |||
CARLA_ASSERT(fQueue != nullptr); | |||
} | |||
bool valid() const noexcept | |||
{ | |||
return (fEntry != fQueue); | |||
} | |||
void next() noexcept | |||
{ | |||
fEntry = fEntry2; | |||
fEntry2 = fEntry->next; | |||
} | |||
T& operator*() | |||
{ | |||
fData = list_entry(fEntry, Data, siblings); | |||
CARLA_ASSERT(fData != nullptr); | |||
return fData->value; | |||
} | |||
private: | |||
Data* fData; | |||
k_list_head* fEntry; | |||
k_list_head* fEntry2; | |||
const k_list_head* const fQueue; | |||
friend class AbstractList; | |||
}; | |||
Itenerator begin() const | |||
{ | |||
return Itenerator(&fQueue); | |||
} | |||
void clear() | |||
{ | |||
if (fCount != 0) | |||
{ | |||
k_list_head* entry; | |||
k_list_head* entry2; | |||
list_for_each_safe(entry, entry2, &fQueue) | |||
{ | |||
if (Data* data = list_entry(entry, Data, siblings)) | |||
{ | |||
data->~Data(); | |||
_deallocate(data); | |||
} | |||
} | |||
} | |||
_init(); | |||
} | |||
size_t count() const noexcept | |||
{ | |||
return fCount; | |||
} | |||
bool isEmpty() const noexcept | |||
{ | |||
return (fCount == 0); | |||
} | |||
bool append(const T& value) | |||
{ | |||
if (Data* const data = _allocate()) | |||
{ | |||
new(data)Data(); | |||
data->value = value; | |||
list_add_tail(&data->siblings, &fQueue); | |||
++fCount; | |||
return true; | |||
} | |||
return false; | |||
} | |||
bool appendAt(const T& value, const Itenerator& it) | |||
{ | |||
if (Data* const data = _allocate()) | |||
{ | |||
new(data)Data(); | |||
data->value = value; | |||
list_add_tail(&data->siblings, it.fEntry->next); | |||
++fCount; | |||
return true; | |||
} | |||
return false; | |||
} | |||
bool insert(const T& value) | |||
{ | |||
if (Data* const data = _allocate()) | |||
{ | |||
new(data)Data(); | |||
data->value = value; | |||
list_add(&data->siblings, &fQueue); | |||
++fCount; | |||
return true; | |||
} | |||
return false; | |||
} | |||
bool insertAt(const T& value, const Itenerator& it) | |||
{ | |||
if (Data* const data = _allocate()) | |||
{ | |||
new(data)Data(); | |||
data->value = value; | |||
list_add(&data->siblings, it.fEntry->prev); | |||
++fCount; | |||
return true; | |||
} | |||
return false; | |||
} | |||
T& getAt(const size_t index, const bool remove = false) | |||
{ | |||
if (fCount == 0 || index >= fCount) | |||
return fRetValue; | |||
size_t i = 0; | |||
Data* data = nullptr; | |||
k_list_head* entry; | |||
k_list_head* entry2; | |||
list_for_each_safe(entry, entry2, &fQueue) | |||
{ | |||
if (index != i++) | |||
continue; | |||
data = list_entry(entry, Data, siblings); | |||
if (data != nullptr) | |||
fRetValue = data->value; | |||
if (remove) | |||
{ | |||
--fCount; | |||
list_del(entry); | |||
if (data != nullptr) | |||
{ | |||
data->~Data(); | |||
_deallocate(data); | |||
} | |||
} | |||
break; | |||
} | |||
return fRetValue; | |||
} | |||
T& getFirst(const bool remove = false) | |||
{ | |||
return _getFirstOrLast(true, remove); | |||
} | |||
T& getLast(const bool remove = false) | |||
{ | |||
return _getFirstOrLast(false, remove); | |||
} | |||
void remove(Itenerator& it) | |||
{ | |||
CARLA_ASSERT(it.fEntry != nullptr); | |||
CARLA_ASSERT(it.fData != nullptr); | |||
if (it.fEntry != nullptr && it.fData != nullptr) | |||
{ | |||
--fCount; | |||
list_del(it.fEntry); | |||
it.fData->~Data(); | |||
_deallocate(it.fData); | |||
} | |||
} | |||
bool removeOne(const T& value) | |||
{ | |||
Data* data = nullptr; | |||
k_list_head* entry; | |||
k_list_head* entry2; | |||
list_for_each_safe(entry, entry2, &fQueue) | |||
{ | |||
data = list_entry(entry, Data, siblings); | |||
CARLA_SAFE_ASSERT_CONTINUE(data != nullptr); | |||
if (data->value == value) | |||
{ | |||
--fCount; | |||
list_del(entry); | |||
data->~Data(); | |||
_deallocate(data); | |||
break; | |||
} | |||
} | |||
return (data != nullptr); | |||
} | |||
void removeAll(const T& value) | |||
{ | |||
Data* data; | |||
k_list_head* entry; | |||
k_list_head* entry2; | |||
list_for_each_safe(entry, entry2, &fQueue) | |||
{ | |||
data = list_entry(entry, Data, siblings); | |||
CARLA_SAFE_ASSERT_CONTINUE(data != nullptr); | |||
if (data->value == value) | |||
{ | |||
--fCount; | |||
list_del(entry); | |||
data->~Data(); | |||
_deallocate(data); | |||
} | |||
} | |||
} | |||
void spliceAppend(AbstractList& list, const bool init = true) | |||
{ | |||
if (init) | |||
{ | |||
list_splice_tail_init(&fQueue, &list.fQueue); | |||
list.fCount += fCount; | |||
fCount = 0; | |||
} | |||
else | |||
{ | |||
list_splice_tail(&fQueue, &list.fQueue); | |||
list.fCount += fCount; | |||
} | |||
} | |||
void spliceInsert(AbstractList& list, const bool init = true) | |||
{ | |||
if (init) | |||
{ | |||
list_splice_init(&fQueue, &list.fQueue); | |||
list.fCount += fCount; | |||
fCount = 0; | |||
} | |||
else | |||
{ | |||
list_splice(&fQueue, &list.fQueue); | |||
list.fCount += fCount; | |||
} | |||
} | |||
protected: | |||
const size_t fDataSize; | |||
size_t fCount; | |||
k_list_head fQueue; | |||
virtual Data* _allocate() = 0; | |||
virtual void _deallocate(Data*& dataPtr) = 0; | |||
private: | |||
T fRetValue; | |||
void _init() noexcept | |||
{ | |||
fCount = 0; | |||
INIT_LIST_HEAD(&fQueue); | |||
} | |||
T& _getFirstOrLast(const bool first, const bool remove) | |||
{ | |||
if (fCount == 0) | |||
return fRetValue; | |||
k_list_head* const entry = first ? fQueue.next : fQueue.prev; | |||
Data* data = list_entry(entry, Data, siblings); | |||
if (data != nullptr) | |||
fRetValue = data->value; | |||
if (remove) | |||
{ | |||
--fCount; | |||
list_del(entry); | |||
if (data != nullptr) | |||
{ | |||
data->~Data(); | |||
_deallocate(data); | |||
} | |||
} | |||
return fRetValue; | |||
} | |||
LIST_DECLARATIONS(AbstractList) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
// List | |||
template<typename T> | |||
class List : public AbstractList<T> | |||
{ | |||
public: | |||
List() | |||
{ | |||
} | |||
private: | |||
typename AbstractList<T>::Data* _allocate() override | |||
{ | |||
return (typename AbstractList<T>::Data*)std::malloc(this->fDataSize); | |||
} | |||
void _deallocate(typename AbstractList<T>::Data*& dataPtr) override | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr,); | |||
std::free(dataPtr); | |||
dataPtr = nullptr; | |||
} | |||
LIST_DECLARATIONS(List) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
#endif // LIST_HPP_INCLUDED |
@@ -82,6 +82,9 @@ private: | |||
} fRetAtom; | |||
friend class Lv2AtomQueue; | |||
CARLA_PREVENT_HEAP_ALLOCATION | |||
CARLA_DECLARE_NON_COPY_CLASS(Lv2AtomRingBufferControl) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
@@ -93,7 +96,7 @@ public: | |||
{ | |||
} | |||
void copyDataFrom(Lv2AtomQueue& queue) | |||
void copyDataFromQueue(Lv2AtomQueue& queue) | |||
{ | |||
// lock queue | |||
const CarlaMutex::ScopedLocker qsl(queue.fMutex); | |||
@@ -104,21 +107,21 @@ public: | |||
carla_copyStruct<RingBuffer>(fRingBufferCtrl.fBuffer, queue.fRingBufferCtrl.fBuffer); | |||
} | |||
// reset queque | |||
fRingBufferCtrl.clear(); | |||
// reset queque - FIXME? no queue.? | |||
queue.fRingBufferCtrl.clear(); | |||
} | |||
void lock() | |||
void lock() const noexcept | |||
{ | |||
fMutex.lock(); | |||
} | |||
bool tryLock() | |||
bool tryLock() const noexcept | |||
{ | |||
return fMutex.tryLock(); | |||
} | |||
void unlock() | |||
void unlock() const noexcept | |||
{ | |||
fMutex.unlock(); | |||
} | |||
@@ -127,6 +130,8 @@ public: | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(atom != nullptr && atom->size > 0, false); | |||
const CarlaMutex::ScopedLocker sl(fMutex); | |||
return fRingBufferCtrl.writeAtom(atom, static_cast<int32_t>(portIndex)); | |||
} | |||
@@ -134,7 +139,9 @@ public: | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(atom != nullptr && portIndex != nullptr, false); | |||
if (! fRingBufferCtrl.dataAvailable()) | |||
const CarlaMutex::ScopedLocker sl(fMutex); | |||
if (! fRingBufferCtrl.isDataAvailable()) | |||
return false; | |||
if (const LV2_Atom* retAtom = fRingBufferCtrl.readAtom(portIndex)) | |||
@@ -18,381 +18,17 @@ | |||
#ifndef RT_LIST_HPP_INCLUDED | |||
#define RT_LIST_HPP_INCLUDED | |||
#include "CarlaUtils.hpp" | |||
#include <new> | |||
#include "List.hpp" | |||
extern "C" { | |||
#include "rtmempool/list.h" | |||
#include "rtmempool/rtmempool.h" | |||
} | |||
// Declare non copyable and prevent heap allocation | |||
#ifdef CARLA_PROPER_CPP11_SUPPORT | |||
# define LIST_DECLARATIONS(ClassName) \ | |||
ClassName(ClassName&) = delete; \ | |||
ClassName(const ClassName&) = delete; \ | |||
ClassName& operator=(const ClassName&) = delete; \ | |||
static void* operator new(size_t) = delete; | |||
#else | |||
# define LIST_DECLARATIONS(ClassName) \ | |||
ClassName(ClassName&); \ | |||
ClassName(const ClassName&); \ | |||
ClassName& operator=(const ClassName&); | |||
#endif | |||
typedef struct list_head k_list_head; | |||
// ----------------------------------------------------------------------- | |||
// Abstract List class | |||
// _allocate() and _deallocate are virtual calls provided by subclasses | |||
template<typename T> | |||
class List | |||
{ | |||
protected: | |||
struct Data { | |||
T value; | |||
k_list_head siblings; | |||
}; | |||
List() | |||
: fDataSize(sizeof(Data)), | |||
fCount(0) | |||
{ | |||
_init(); | |||
} | |||
virtual ~List() | |||
{ | |||
CARLA_ASSERT(fCount == 0); | |||
} | |||
public: | |||
class Itenerator { | |||
public: | |||
Itenerator(const k_list_head* queue) | |||
: fData(nullptr), | |||
fEntry(queue->next), | |||
fEntry2(fEntry->next), | |||
fQueue(queue) | |||
{ | |||
CARLA_ASSERT(fEntry != nullptr); | |||
CARLA_ASSERT(fEntry2 != nullptr); | |||
CARLA_ASSERT(fQueue != nullptr); | |||
} | |||
bool valid() const noexcept | |||
{ | |||
return (fEntry != fQueue); | |||
} | |||
void next() noexcept | |||
{ | |||
fEntry = fEntry2; | |||
fEntry2 = fEntry->next; | |||
} | |||
T& operator*() | |||
{ | |||
fData = list_entry(fEntry, Data, siblings); | |||
CARLA_ASSERT(fData != nullptr); | |||
return fData->value; | |||
} | |||
private: | |||
Data* fData; | |||
k_list_head* fEntry; | |||
k_list_head* fEntry2; | |||
const k_list_head* const fQueue; | |||
friend class List; | |||
}; | |||
Itenerator begin() const | |||
{ | |||
return Itenerator(&fQueue); | |||
} | |||
void clear() | |||
{ | |||
if (fCount != 0) | |||
{ | |||
k_list_head* entry; | |||
k_list_head* entry2; | |||
list_for_each_safe(entry, entry2, &fQueue) | |||
{ | |||
if (Data* data = list_entry(entry, Data, siblings)) | |||
{ | |||
data->~Data(); | |||
_deallocate(data); | |||
} | |||
} | |||
} | |||
_init(); | |||
} | |||
size_t count() const noexcept | |||
{ | |||
return fCount; | |||
} | |||
bool isEmpty() const noexcept | |||
{ | |||
return (fCount == 0); | |||
} | |||
bool append(const T& value) | |||
{ | |||
if (Data* const data = _allocate()) | |||
{ | |||
new(data)Data(); | |||
data->value = value; | |||
list_add_tail(&data->siblings, &fQueue); | |||
++fCount; | |||
return true; | |||
} | |||
return false; | |||
} | |||
bool appendAt(const T& value, const Itenerator& it) | |||
{ | |||
if (Data* const data = _allocate()) | |||
{ | |||
new(data)Data(); | |||
data->value = value; | |||
list_add_tail(&data->siblings, it.fEntry->next); | |||
++fCount; | |||
return true; | |||
} | |||
return false; | |||
} | |||
bool insert(const T& value) | |||
{ | |||
if (Data* const data = _allocate()) | |||
{ | |||
new(data)Data(); | |||
data->value = value; | |||
list_add(&data->siblings, &fQueue); | |||
++fCount; | |||
return true; | |||
} | |||
return false; | |||
} | |||
bool insertAt(const T& value, const Itenerator& it) | |||
{ | |||
if (Data* const data = _allocate()) | |||
{ | |||
new(data)Data(); | |||
data->value = value; | |||
list_add(&data->siblings, it.fEntry->prev); | |||
++fCount; | |||
return true; | |||
} | |||
return false; | |||
} | |||
T& getAt(const size_t index, const bool remove = false) | |||
{ | |||
if (fCount == 0 || index >= fCount) | |||
return fRetValue; | |||
size_t i = 0; | |||
Data* data = nullptr; | |||
k_list_head* entry; | |||
k_list_head* entry2; | |||
list_for_each_safe(entry, entry2, &fQueue) | |||
{ | |||
if (index != i++) | |||
continue; | |||
data = list_entry(entry, Data, siblings); | |||
if (data != nullptr) | |||
fRetValue = data->value; | |||
if (remove) | |||
{ | |||
--fCount; | |||
list_del(entry); | |||
if (data != nullptr) | |||
{ | |||
data->~Data(); | |||
_deallocate(data); | |||
} | |||
} | |||
break; | |||
} | |||
return fRetValue; | |||
} | |||
T& getFirst(const bool remove = false) | |||
{ | |||
return _getFirstOrLast(true, remove); | |||
} | |||
T& getLast(const bool remove = false) | |||
{ | |||
return _getFirstOrLast(false, remove); | |||
} | |||
void remove(Itenerator& it) | |||
{ | |||
CARLA_ASSERT(it.fEntry != nullptr); | |||
CARLA_ASSERT(it.fData != nullptr); | |||
if (it.fEntry != nullptr && it.fData != nullptr) | |||
{ | |||
--fCount; | |||
list_del(it.fEntry); | |||
it.fData->~Data(); | |||
_deallocate(it.fData); | |||
} | |||
} | |||
bool removeOne(const T& value) | |||
{ | |||
Data* data = nullptr; | |||
k_list_head* entry; | |||
k_list_head* entry2; | |||
list_for_each_safe(entry, entry2, &fQueue) | |||
{ | |||
data = list_entry(entry, Data, siblings); | |||
CARLA_SAFE_ASSERT_CONTINUE(data != nullptr); | |||
if (data->value == value) | |||
{ | |||
--fCount; | |||
list_del(entry); | |||
data->~Data(); | |||
_deallocate(data); | |||
break; | |||
} | |||
} | |||
return (data != nullptr); | |||
} | |||
void removeAll(const T& value) | |||
{ | |||
Data* data; | |||
k_list_head* entry; | |||
k_list_head* entry2; | |||
list_for_each_safe(entry, entry2, &fQueue) | |||
{ | |||
data = list_entry(entry, Data, siblings); | |||
CARLA_SAFE_ASSERT_CONTINUE(data != nullptr); | |||
if (data->value == value) | |||
{ | |||
--fCount; | |||
list_del(entry); | |||
data->~Data(); | |||
_deallocate(data); | |||
} | |||
} | |||
} | |||
void spliceAppend(List& list, const bool init = true) | |||
{ | |||
if (init) | |||
{ | |||
list_splice_tail_init(&fQueue, &list.fQueue); | |||
list.fCount += fCount; | |||
fCount = 0; | |||
} | |||
else | |||
{ | |||
list_splice_tail(&fQueue, &list.fQueue); | |||
list.fCount += fCount; | |||
} | |||
} | |||
void spliceInsert(List& list, const bool init = true) | |||
{ | |||
if (init) | |||
{ | |||
list_splice_init(&fQueue, &list.fQueue); | |||
list.fCount += fCount; | |||
fCount = 0; | |||
} | |||
else | |||
{ | |||
list_splice(&fQueue, &list.fQueue); | |||
list.fCount += fCount; | |||
} | |||
} | |||
protected: | |||
const size_t fDataSize; | |||
size_t fCount; | |||
k_list_head fQueue; | |||
virtual Data* _allocate() = 0; | |||
virtual void _deallocate(Data*& dataPtr) = 0; | |||
private: | |||
T fRetValue; | |||
void _init() noexcept | |||
{ | |||
fCount = 0; | |||
INIT_LIST_HEAD(&fQueue); | |||
} | |||
T& _getFirstOrLast(const bool first, const bool remove) | |||
{ | |||
if (fCount == 0) | |||
return fRetValue; | |||
k_list_head* const entry = first ? fQueue.next : fQueue.prev; | |||
Data* data = list_entry(entry, Data, siblings); | |||
if (data != nullptr) | |||
fRetValue = data->value; | |||
if (remove) | |||
{ | |||
--fCount; | |||
list_del(entry); | |||
if (data != nullptr) | |||
{ | |||
data->~Data(); | |||
_deallocate(data); | |||
} | |||
} | |||
return fRetValue; | |||
} | |||
LIST_DECLARATIONS(List) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
// Realtime safe list | |||
template<typename T> | |||
class RtList : public List<T> | |||
class RtList : public AbstractList<T> | |||
{ | |||
public: | |||
// ------------------------------------------------------------------- | |||
@@ -403,7 +39,7 @@ public: | |||
public: | |||
Pool(const size_t minPreallocated, const size_t maxPreallocated) | |||
: fHandle(nullptr), | |||
fDataSize(sizeof(typename List<T>::Data)) | |||
fDataSize(sizeof(typename AbstractList<T>::Data)) | |||
{ | |||
resize(minPreallocated, maxPreallocated); | |||
} | |||
@@ -455,8 +91,8 @@ public: | |||
} | |||
private: | |||
RtMemPool_Handle fHandle; | |||
const size_t fDataSize; | |||
mutable RtMemPool_Handle fHandle; | |||
const size_t fDataSize; | |||
}; | |||
// ------------------------------------------------------------------- | |||
@@ -469,23 +105,23 @@ public: | |||
void append_sleepy(const T& value) | |||
{ | |||
if (typename List<T>::Data* const data = _allocate_sleepy()) | |||
if (typename AbstractList<T>::Data* const data = _allocate_sleepy()) | |||
{ | |||
new(data)typename List<T>::Data(); | |||
new(data)typename AbstractList<T>::Data(); | |||
data->value = value; | |||
list_add_tail(&data->siblings, &this->fQueue); | |||
++this->fCount; | |||
++(this->fCount); | |||
} | |||
} | |||
void insert_sleepy(const T& value) | |||
{ | |||
if (typename List<T>::Data* const data = _allocate_sleepy()) | |||
if (typename AbstractList<T>::Data* const data = _allocate_sleepy()) | |||
{ | |||
new(data)typename List<T>::Data(); | |||
new(data)typename AbstractList<T>::Data(); | |||
data->value = value; | |||
list_add(&data->siblings, &this->fQueue); | |||
++this->fCount; | |||
++(this->fCount); | |||
} | |||
} | |||
@@ -500,37 +136,33 @@ public: | |||
{ | |||
CARLA_ASSERT(fMemPool == list.fMemPool); | |||
List<T>::spliceAppend(list, init); | |||
AbstractList<T>::spliceAppend(list, init); | |||
} | |||
void spliceInsert(RtList& list, const bool init = true) | |||
{ | |||
CARLA_ASSERT(fMemPool == list.fMemPool); | |||
List<T>::spliceInsert(list, init); | |||
AbstractList<T>::spliceInsert(list, init); | |||
} | |||
private: | |||
Pool& fMemPool; | |||
typename List<T>::Data* _allocate() override | |||
typename AbstractList<T>::Data* _allocate() override | |||
{ | |||
return _allocate_atomic(); | |||
return (typename AbstractList<T>::Data*)fMemPool.allocate_atomic(); | |||
} | |||
typename List<T>::Data* _allocate_atomic() | |||
typename AbstractList<T>::Data* _allocate_sleepy() | |||
{ | |||
return (typename List<T>::Data*)fMemPool.allocate_atomic(); | |||
return (typename AbstractList<T>::Data*)fMemPool.allocate_sleepy(); | |||
} | |||
typename List<T>::Data* _allocate_sleepy() | |||
void _deallocate(typename AbstractList<T>::Data*& dataPtr) override | |||
{ | |||
return (typename List<T>::Data*)fMemPool.allocate_sleepy(); | |||
} | |||
CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr,); | |||
void _deallocate(typename List<T>::Data*& dataPtr) override | |||
{ | |||
CARLA_ASSERT(dataPtr != nullptr); | |||
fMemPool.deallocate(dataPtr); | |||
dataPtr = nullptr; | |||
} | |||
@@ -538,33 +170,6 @@ private: | |||
LIST_DECLARATIONS(RtList) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
// Non-Realtime list | |||
template<typename T> | |||
class NonRtList : public List<T> | |||
{ | |||
public: | |||
NonRtList() | |||
{ | |||
} | |||
private: | |||
typename List<T>::Data* _allocate() override | |||
{ | |||
return (typename List<T>::Data*)std::malloc(this->fDataSize); | |||
} | |||
void _deallocate(typename List<T>::Data*& dataPtr) override | |||
{ | |||
CARLA_ASSERT(dataPtr != nullptr); | |||
std::free(dataPtr); | |||
dataPtr = nullptr; | |||
} | |||
LIST_DECLARATIONS(NonRtList) | |||
}; | |||
// ----------------------------------------------------------------------- | |||
#endif // RT_LIST_HPP_INCLUDED |
@@ -1,213 +0,0 @@ | |||
/* | |||
* Carla utils | |||
* Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU General Public License as | |||
* published by the Free Software Foundation; either version 2 of | |||
* the License, or any later version. | |||
* | |||
* This program 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. | |||
* | |||
* For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
*/ | |||
#include "CarlaDefines.hpp" | |||
// IDE Helper | |||
#ifndef REAL_BUILD | |||
# include "CarlaUtils.hpp" | |||
# include "CarlaLibUtils.hpp" | |||
#endif | |||
#include <cstdarg> // needed for va_* | |||
#include <cstdio> // needed for *printf | |||
#include <cstdlib> // needed for free | |||
#include <cstring> // needed for str* | |||
#ifdef CARLA_OS_WIN | |||
# include <winsock2.h> // should be included before "windows.h" | |||
# include <windows.h> | |||
#else | |||
# include <dlfcn.h> | |||
# include <unistd.h> | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
#ifdef CARLA_UTILS_HPP_INCLUDED | |||
// ----------------------------------------------------------------------- | |||
// string print functions | |||
#ifdef DEBUG | |||
void carla_debug(const char* const fmt, ...) | |||
{ | |||
va_list args; | |||
va_start(args, fmt); | |||
std::fprintf(stdout, "\x1b[30;1m"); | |||
std::vfprintf(stdout, fmt, args); | |||
std::fprintf(stdout, "\x1b[0m\n"); | |||
va_end(args); | |||
} | |||
#endif | |||
void carla_stdout(const char* const fmt, ...) | |||
{ | |||
va_list args; | |||
va_start(args, fmt); | |||
std::vfprintf(stdout, fmt, args); | |||
std::fprintf(stdout, "\n"); | |||
va_end(args); | |||
} | |||
void carla_stderr(const char* const fmt, ...) | |||
{ | |||
va_list args; | |||
va_start(args, fmt); | |||
std::vfprintf(stderr, fmt, args); | |||
std::fprintf(stderr, "\n"); | |||
va_end(args); | |||
} | |||
void carla_stderr2(const char* const fmt, ...) | |||
{ | |||
va_list args; | |||
va_start(args, fmt); | |||
std::fprintf(stderr, "\x1b[31m"); | |||
std::vfprintf(stderr, fmt, args); | |||
std::fprintf(stderr, "\x1b[0m\n"); | |||
va_end(args); | |||
} | |||
// ----------------------------------------------------------------------- | |||
// carla_*sleep | |||
void carla_sleep(const unsigned int secs) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(secs > 0,); | |||
#ifdef CARLA_OS_WIN | |||
Sleep(secs * 1000); | |||
#else | |||
sleep(secs); | |||
#endif | |||
} | |||
void carla_msleep(const unsigned int msecs) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(msecs > 0,); | |||
#ifdef CARLA_OS_WIN | |||
Sleep(msecs); | |||
#else | |||
usleep(msecs * 1000); | |||
#endif | |||
} | |||
// ----------------------------------------------------------------------- | |||
// carla_setenv | |||
void carla_setenv(const char* const key, const char* const value) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(key != nullptr,); | |||
CARLA_SAFE_ASSERT_RETURN(value != nullptr,); | |||
#ifdef CARLA_OS_WIN | |||
SetEnvironmentVariableA(key, value); | |||
#else | |||
setenv(key, value, 1); | |||
#endif | |||
} | |||
// ----------------------------------------------------------------------- | |||
// carla_strdup | |||
const char* carla_strdup(const char* const strBuf) | |||
{ | |||
CARLA_SAFE_ASSERT(strBuf != nullptr); | |||
const size_t bufferLen = (strBuf != nullptr) ? std::strlen(strBuf) : 0; | |||
char* const buffer = new char[bufferLen+1]; | |||
if (strBuf != nullptr && bufferLen > 0) | |||
std::strncpy(buffer, strBuf, bufferLen); | |||
buffer[bufferLen] = '\0'; | |||
return buffer; | |||
} | |||
const char* carla_strdup_free(char* const strBuf) | |||
{ | |||
const char* const buffer(carla_strdup(strBuf)); | |||
std::free(strBuf); | |||
return buffer; | |||
} | |||
#endif // CARLA_UTILS_HPP_INCLUDED | |||
// ----------------------------------------------------------------------- | |||
#ifdef CARLA_LIB_UTILS_HPP_INCLUDED | |||
// ----------------------------------------------------------------------- | |||
// library related calls | |||
void* lib_open(const char* const filename) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(filename != nullptr, nullptr); | |||
#ifdef CARLA_OS_WIN | |||
return (void*)LoadLibraryA(filename); | |||
#else | |||
return dlopen(filename, RTLD_NOW|RTLD_LOCAL); | |||
#endif | |||
} | |||
bool lib_close(void* const lib) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(lib != nullptr, false); | |||
#ifdef CARLA_OS_WIN | |||
return FreeLibrary((HMODULE)lib); | |||
#else | |||
return (dlclose(lib) == 0); | |||
#endif | |||
} | |||
void* lib_symbol(void* const lib, const char* const symbol) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(lib != nullptr, nullptr); | |||
CARLA_SAFE_ASSERT_RETURN(symbol != nullptr, nullptr); | |||
#ifdef CARLA_OS_WIN | |||
return (void*)GetProcAddress((HMODULE)lib, symbol); | |||
#else | |||
return dlsym(lib, symbol); | |||
#endif | |||
} | |||
const char* lib_error(const char* const filename) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(filename != nullptr, nullptr); | |||
#ifdef CARLA_OS_WIN | |||
static char libError[2048+1]; | |||
carla_zeroChar(libError, 2048+1); | |||
LPVOID winErrorString; | |||
DWORD winErrorCode = GetLastError(); | |||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, winErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&winErrorString, 0, nullptr); | |||
std::snprintf(libError, 2048, "%s: error code %li: %s", filename, winErrorCode, (const char*)winErrorString); | |||
LocalFree(winErrorString); | |||
return libError; | |||
#else | |||
return dlerror(); | |||
#endif | |||
} | |||
#endif // CARLA_LIB_UTILS_HPP_INCLUDED | |||
// ----------------------------------------------------------------------- |