| @@ -35,10 +35,6 @@ BUILD_C_FLAGS = $(BASE_FLAGS) -std=c99 $(CFLAGS) | |||
| BUILD_CXX_FLAGS = $(BASE_FLAGS) -std=c++0x $(CXXFLAGS) | |||
| LINK_FLAGS = $(LDFLAGS) | |||
| ifneq ($(DEBUG),true) | |||
| BUILD_CXX_FLAGS += -DQT_NO_DEBUG -DQT_NO_DEBUG_STREAM -DQT_NO_DEBUG_OUTPUT | |||
| endif | |||
| # -------------------------------------------------------------- | |||
| # Modify to enable/disable specific features | |||
| @@ -51,6 +51,9 @@ HEADERS += \ | |||
| HEADERS += \ | |||
| ../../includes/carla_defines.hpp \ | |||
| ../../includes/carla_midi.h \ | |||
| ../../utils/carla_mutex.hpp \ | |||
| ../../utils/carla_string.hpp \ | |||
| ../../utils/carla_thread.hpp \ | |||
| ../../utils/carla_utils.hpp \ | |||
| ../../utils/carla_backend_utils.hpp \ | |||
| ../../utils/carla_juce_utils.hpp \ | |||
| @@ -18,15 +18,38 @@ | |||
| #ifndef __CARLA_DEFINES_HPP__ | |||
| #define __CARLA_DEFINES_HPP__ | |||
| #include <QtCore/Qt> | |||
| // Check OS | |||
| #if defined(__APPLE__) | |||
| # define CARLA_OS_MAC | |||
| #elif defined(__HAIKU__) | |||
| # define CARLA_OS_HAIKU | |||
| #elif defined(__linux__) || defined(__linux) || defined(QTCREATOR_TEST) | |||
| # define CARLA_OS_LINUX | |||
| #elif defined(WIN64) || defined(_WIN64) || defined(__WIN64__) | |||
| # define CARLA_OS_WIN64 | |||
| #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) | |||
| # define CARLA_OS_WIN32 | |||
| #else | |||
| # warning Unsupported platform! | |||
| #endif | |||
| // If the compiler can't do C++11 lambdas, it most likely doesn't know about nullptr either | |||
| #ifndef Q_COMPILER_LAMBDA | |||
| # define nullptr (0) | |||
| #if defined(CARLA_OS_WIN32) || defined(CARLA_OS_WIN64) | |||
| # define CARLA_OS_WIN | |||
| #elif ! defined(CARLA_OS_HAIKU) | |||
| # define CARLA_OS_UNIX | |||
| #endif | |||
| // Check for C++11 support | |||
| #if defined(HAVE_CPP11_SUPPORT) || defined(QTCREATOR_TEST) | |||
| # define CARLA_CPP11_SUPPORT | |||
| #elif defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__) | |||
| # if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405 | |||
| # define CARLA_CPP11_SUPPORT | |||
| # endif | |||
| #endif | |||
| // Common includes | |||
| #ifdef Q_OS_WIN | |||
| #ifdef CARLA_OS_WIN | |||
| # include <winsock2.h> | |||
| # include <windows.h> | |||
| #else | |||
| @@ -36,13 +59,13 @@ | |||
| # endif | |||
| #endif | |||
| // Define various string format types, needed for qDebug/Warning/Critical sections | |||
| #if defined(Q_OS_WIN64) | |||
| // Define various string format types | |||
| #if defined(CARLA_OS_WIN64) | |||
| # define P_INT64 "%I64i" | |||
| # define P_INTPTR "%I64i" | |||
| # define P_UINTPTR "%I64x" | |||
| # define P_SIZE "%I64u" | |||
| #elif defined(Q_OS_WIN32) | |||
| #elif defined(CARLA_OS_WIN32) | |||
| # define P_INT64 "%I64i" | |||
| # define P_INTPTR "%i" | |||
| # define P_UINTPTR "%x" | |||
| @@ -60,14 +83,14 @@ | |||
| #endif | |||
| // Define BINARY_NATIVE | |||
| #if defined(Q_OS_HAIKU) || defined(Q_OS_UNIX) | |||
| #if defined(CARLA_OS_HAIKU) || defined(CARLA_OS_UNIX) | |||
| # ifdef __LP64__ | |||
| # define BINARY_NATIVE BINARY_POSIX64 | |||
| # else | |||
| # define BINARY_NATIVE BINARY_POSIX32 | |||
| # endif | |||
| #elif defined(Q_OS_WIN) | |||
| # ifdef Q_OS_WIN64 | |||
| #elif defined(CARLA_OS_WIN) | |||
| # ifdef CARLA_OS_WIN64 | |||
| # define BINARY_NATIVE BINARY_WIN64 | |||
| # else | |||
| # define BINARY_NATIVE BINARY_WIN32 | |||
| @@ -79,20 +102,20 @@ | |||
| // Define CARLA_ASSERT* | |||
| #ifdef NDEBUG | |||
| # define CARLA_ASSERT(cond) ((!(cond)) ? carla_assert(#cond, __FILE__, __LINE__) : qt_noop()) | |||
| # define CARLA_ASSERT_INT(cond, value) ((!(cond)) ? carla_assert_int(#cond, __FILE__, __LINE__, value) : qt_noop()) | |||
| # define CARLA_ASSERT_INT2(cond, v1, v2) ((!(cond)) ? carla_assert_int2(#cond, __FILE__, __LINE__, v1, v2) : qt_noop()) | |||
| # define CARLA_ASSERT(cond) ((!(cond)) ? carla_assert(#cond, __FILE__, __LINE__) : pass()) | |||
| # define CARLA_ASSERT_INT(cond, value) ((!(cond)) ? carla_assert_int(#cond, __FILE__, __LINE__, value) : pass()) | |||
| # define CARLA_ASSERT_INT2(cond, v1, v2) ((!(cond)) ? carla_assert_int2(#cond, __FILE__, __LINE__, v1, v2) : pass()) | |||
| #else | |||
| # define CARLA_ASSERT(cond) Q_ASSERT(cond) | |||
| # define CARLA_ASSERT_INT(cond, value) Q_ASSERT(cond) | |||
| # define CARLA_ASSERT_INT2(cond, v1, v2) Q_ASSERT(cond) | |||
| # define CARLA_ASSERT(cond) assert(cond) | |||
| # define CARLA_ASSERT_INT(cond, value) assert(cond) | |||
| # define CARLA_ASSERT_INT2(cond, v1, v2) assert(cond) | |||
| #endif | |||
| // Define CARLA_EXPORT | |||
| #ifdef BUILD_BRIDGE | |||
| # define CARLA_EXPORT extern "C" | |||
| #else | |||
| # if defined(Q_OS_WIN) && ! defined(__WINE__) | |||
| # if defined(CARLA_OS_WIN) && ! defined(__WINE__) | |||
| # define CARLA_EXPORT extern "C" __declspec (dllexport) | |||
| # else | |||
| # define CARLA_EXPORT extern "C" __attribute__ ((visibility("default"))) | |||
| @@ -15,9 +15,7 @@ | |||
| * For a full copy of the GNU General Public License see the GPL.txt file | |||
| */ | |||
| #include "carla_utils.hpp" | |||
| #include <cassert> | |||
| #include "carla_string.hpp" | |||
| int main() | |||
| { | |||
| @@ -10,10 +10,8 @@ include ../Makefile.mk | |||
| BUILD_CXX_FLAGS += -I../backend -I../includes -I../utils | |||
| # BUILD_CXX_FLAGS += -I/opt/mingw32/include | |||
| BUILD_CXX_FLAGS += $(shell pkg-config --cflags QtCore) | |||
| LINK_FLAGS += $(shell pkg-config --libs QtCore) | |||
| TARGETS = CarlaString RtList Thread GL_ | |||
| TARGETS = CarlaString RtList Thread Print_ | |||
| all: $(TARGETS) RUN | |||
| @@ -23,17 +21,21 @@ CarlaString: CarlaString.cpp | |||
| $(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) -o $@ | |||
| RtList: RtList.cpp ../libs/rtmempool.a | |||
| $(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) -o $@ | |||
| $(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) -pthread -lpthread -o $@ | |||
| Thread: Thread.cpp | |||
| $(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) -pthread -lpthread -o $@ | |||
| Print_: Print.cpp | |||
| $(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) -o Print # $@ | |||
| GL_: GL.cpp | |||
| # $(CXX) $^ $(BUILD_CXX_FLAGS) -I../backend/engine/plugin -I../libs/distrho-plugin-toolkit $(LINK_FLAGS) -lgdi32 -lopengl32 -lole32 -luuid -lws2_32 -o GL # $@ | |||
| $(CXX) $^ $(BUILD_CXX_FLAGS) -I../backend/engine/plugin -I../libs/distrho-plugin-toolkit $(LINK_FLAGS) -lGL -lGLU -o GL # $@ | |||
| RUN: $(TARGETS) | |||
| # ./CarlaString && ./RtList && ./Thread | |||
| # ./GL | |||
| # -------------------------------------------------------------- | |||
| @@ -0,0 +1,27 @@ | |||
| /* | |||
| * Carla Tests | |||
| * 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 GPL.txt file | |||
| */ | |||
| #include "carla_utils.hpp" | |||
| int main() | |||
| { | |||
| carla_debug("DEBUG"); | |||
| carla_stdout("STDOUT"); | |||
| carla_stderr("STDERR"); | |||
| carla_stderr2("STDERR2"); | |||
| return 0; | |||
| } | |||
| @@ -15,10 +15,10 @@ | |||
| * For a full copy of the GNU General Public License see the GPL.txt file | |||
| */ | |||
| #include "carla_utils.hpp" | |||
| #include "rt_list.hpp" | |||
| #include <cassert> | |||
| #include "carla_string.hpp" | |||
| #include "carla_mutex.hpp" | |||
| const unsigned short MIN_RT_EVENTS = 152; | |||
| const unsigned short MAX_RT_EVENTS = 512; | |||
| @@ -15,9 +15,7 @@ | |||
| * For a full copy of the GNU General Public License see the GPL.txt file | |||
| */ | |||
| #include "carla_utils.hpp" | |||
| #include <cassert> | |||
| #include "carla_thread.hpp" | |||
| class MyThread : public CarlaThread | |||
| { | |||
| @@ -44,7 +44,7 @@ const char* BinaryType2Str(const BinaryType& type) | |||
| return "BINARY_OTHER"; | |||
| } | |||
| qWarning("CarlaBackend::BinaryType2Str(%i) - invalid type", type); | |||
| carla_stderr("CarlaBackend::BinaryType2Str(%i) - invalid type", type); | |||
| return nullptr; | |||
| } | |||
| @@ -73,7 +73,7 @@ const char* PluginType2Str(const PluginType& type) | |||
| return "PLUGIN_SFZ"; | |||
| } | |||
| qWarning("CarlaBackend::PluginType2Str(%i) - invalid type", type); | |||
| carla_stderr("CarlaBackend::PluginType2Str(%i) - invalid type", type); | |||
| return nullptr; | |||
| } | |||
| @@ -102,7 +102,7 @@ const char* PluginCategory2Str(const PluginCategory& category) | |||
| return "PLUGIN_CATEGORY_OTHER"; | |||
| } | |||
| qWarning("CarlaBackend::PluginCategory2Str(%i) - invalid category", category); | |||
| carla_stderr("CarlaBackend::PluginCategory2Str(%i) - invalid category", category); | |||
| return nullptr; | |||
| } | |||
| @@ -129,7 +129,7 @@ const char* ParameterType2Str(const ParameterType& type) | |||
| #endif | |||
| } | |||
| qWarning("CarlaBackend::ParameterType2Str(%i) - invalid type", type); | |||
| carla_stderr("CarlaBackend::ParameterType2Str(%i) - invalid type", type); | |||
| return nullptr; | |||
| } | |||
| @@ -156,7 +156,7 @@ const char* InternalParametersIndex2Str(const InternalParametersIndex& index) | |||
| return "PARAMETER_MAX"; | |||
| } | |||
| qWarning("CarlaBackend::InternalParametersIndex2Str(%i) - invalid index", index); | |||
| carla_stderr("CarlaBackend::InternalParametersIndex2Str(%i) - invalid index", index); | |||
| return nullptr; | |||
| } | |||
| @@ -225,7 +225,7 @@ const char* OptionsType2Str(const OptionsType& type) | |||
| #endif | |||
| } | |||
| qWarning("CarlaBackend::OptionsType2Str(%i) - invalid type", type); | |||
| carla_stderr("CarlaBackend::OptionsType2Str(%i) - invalid type", type); | |||
| return nullptr; | |||
| } | |||
| @@ -282,7 +282,7 @@ const char* CallbackType2Str(const CallbackType& type) | |||
| return "CALLBACK_QUIT"; | |||
| } | |||
| qWarning("CarlaBackend::CallbackType2Str(%i) - invalid type", type); | |||
| carla_stderr("CarlaBackend::CallbackType2Str(%i) - invalid type", type); | |||
| return nullptr; | |||
| } | |||
| @@ -303,7 +303,7 @@ const char* ProcessMode2Str(const ProcessMode& mode) | |||
| return "PROCESS_MODE_BRIDGE"; | |||
| } | |||
| qWarning("CarlaBackend::ProcessModeType2Str(%i) - invalid type", mode); | |||
| carla_stderr("CarlaBackend::ProcessModeType2Str(%i) - invalid type", mode); | |||
| return nullptr; | |||
| } | |||
| @@ -312,7 +312,7 @@ const char* ProcessMode2Str(const ProcessMode& mode) | |||
| static inline | |||
| uintptr_t getAddressFromPointer(void* ptr) | |||
| { | |||
| qDebug("CarlaBackend::getAddressFromPointer(%p)", ptr); | |||
| carla_debug("CarlaBackend::getAddressFromPointer(%p)", ptr); | |||
| CARLA_ASSERT(ptr != nullptr); | |||
| uintptr_t* addr = (uintptr_t*)&ptr; | |||
| @@ -333,7 +333,7 @@ void* getPointerFromAddress(uintptr_t& addr) | |||
| static inline | |||
| const char* getPluginTypeString(const PluginType& type) | |||
| { | |||
| qDebug("CarlaBackend::getPluginTypeString(%s)", PluginType2Str(type)); | |||
| carla_debug("CarlaBackend::getPluginTypeString(%s)", PluginType2Str(type)); | |||
| switch (type) | |||
| { | |||
| @@ -357,6 +357,7 @@ const char* getPluginTypeString(const PluginType& type) | |||
| return "SFZ"; | |||
| } | |||
| carla_stderr("CarlaBackend::getPluginTypeString(%i) - invalid type", type); | |||
| return "NONE"; | |||
| } | |||
| @@ -365,7 +366,7 @@ const char* getPluginTypeString(const PluginType& type) | |||
| static inline | |||
| PluginCategory getPluginCategoryFromName(const char* const name) | |||
| { | |||
| qDebug("CarlaBackend::getPluginCategoryFromName(\"%s\")", name); | |||
| carla_debug("CarlaBackend::getPluginCategoryFromName(\"%s\")", name); | |||
| CARLA_ASSERT(name); | |||
| if (! name) | |||
| @@ -19,9 +19,9 @@ | |||
| #ifndef __CARLA_JUCE_UTILS_HPP__ | |||
| #define __CARLA_JUCE_UTILS_HPP__ | |||
| #include "carla_defines.hpp" | |||
| #include "carla_utils.hpp" | |||
| #include <cassert> | |||
| #include <algorithm> | |||
| #define CARLA_DECLARE_NON_COPYABLE(className) \ | |||
| className (const className&);\ | |||
| @@ -82,7 +82,7 @@ public: | |||
| { | |||
| if (--(getCounter().numObjects) < 0) | |||
| { | |||
| qWarning("*** Dangling pointer deletion! Class: '%s'", getLeakedObjectClassName()); | |||
| carla_stderr("*** Dangling pointer deletion! Class: '%s'", 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. | |||
| @@ -113,7 +113,7 @@ private: | |||
| { | |||
| if (numObjects > 0) | |||
| { | |||
| qWarning("*** Leaked objects detected: %i instance(s) of class '%s'", numObjects, getLeakedObjectClassName()); | |||
| carla_stderr("*** Leaked objects detected: %i instance(s) of class '%s'", numObjects, 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. | |||
| @@ -313,7 +313,7 @@ private: | |||
| return this; | |||
| } | |||
| #if ! defined(Q_CC_MSVC) // (MSVC can't deal with multiple copy constructors) | |||
| #if ! defined(CARLA_CC_MSVC) // (MSVC can't deal with multiple copy constructors) | |||
| /* These 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). | |||
| @@ -0,0 +1,112 @@ | |||
| /* | |||
| * Carla common 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 GPL.txt file | |||
| */ | |||
| #ifndef __CARLA_MUTEX_HPP__ | |||
| #define __CARLA_MUTEX_HPP__ | |||
| #include "carla_juce_utils.hpp" | |||
| // #define CPP11_MUTEX | |||
| #ifdef CPP11_MUTEX | |||
| # include <mutex> | |||
| #else | |||
| # include <pthread.h> | |||
| #endif | |||
| // ------------------------------------------------- | |||
| // CarlaMutex class | |||
| class CarlaMutex | |||
| { | |||
| public: | |||
| CarlaMutex() | |||
| { | |||
| #ifndef CPP11_MUTEX | |||
| pthread_mutex_init(&pmutex, nullptr); | |||
| #endif | |||
| } | |||
| ~CarlaMutex() | |||
| { | |||
| #ifndef CPP11_MUTEX | |||
| pthread_mutex_destroy(&pmutex); | |||
| #endif | |||
| } | |||
| void lock() | |||
| { | |||
| #ifdef CPP11_MUTEX | |||
| cmutex.lock(); | |||
| #else | |||
| pthread_mutex_lock(&pmutex); | |||
| #endif | |||
| } | |||
| bool tryLock() | |||
| { | |||
| #ifdef CPP11_MUTEX | |||
| return cmutex.try_lock(); | |||
| #else | |||
| return (pthread_mutex_trylock(&pmutex) == 0); | |||
| #endif | |||
| } | |||
| void unlock() | |||
| { | |||
| #ifdef CPP11_MUTEX | |||
| cmutex.unlock(); | |||
| #else | |||
| pthread_mutex_unlock(&pmutex); | |||
| #endif | |||
| } | |||
| class ScopedLocker | |||
| { | |||
| public: | |||
| ScopedLocker(CarlaMutex* const mutex) | |||
| : fMutex(mutex) | |||
| { | |||
| fMutex->lock(); | |||
| } | |||
| ~ScopedLocker() | |||
| { | |||
| fMutex->unlock(); | |||
| } | |||
| private: | |||
| CarlaMutex* const fMutex; | |||
| CARLA_PREVENT_HEAP_ALLOCATION | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ScopedLocker) | |||
| }; | |||
| private: | |||
| #ifdef CPP11_MUTEX | |||
| std::mutex cmutex; | |||
| #else | |||
| pthread_mutex_t pmutex; | |||
| #endif | |||
| CARLA_PREVENT_HEAP_ALLOCATION | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaMutex) | |||
| }; | |||
| // ------------------------------------------------- | |||
| #endif // __CARLA_MUTEX_HPP__ | |||
| @@ -0,0 +1,412 @@ | |||
| /* | |||
| * Carla common 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 GPL.txt file | |||
| */ | |||
| #ifndef __CARLA_STRING_HPP__ | |||
| #define __CARLA_STRING_HPP__ | |||
| #include "carla_juce_utils.hpp" | |||
| // ------------------------------------------------- | |||
| // CarlaString class | |||
| class CarlaString | |||
| { | |||
| public: | |||
| // --------------------------------------------- | |||
| // constructors (no explicit conversions allowed) | |||
| explicit CarlaString() | |||
| { | |||
| _init(); | |||
| _dup(nullptr); | |||
| } | |||
| explicit CarlaString(char* const strBuf) | |||
| { | |||
| _init(); | |||
| _dup(strBuf); | |||
| } | |||
| explicit CarlaString(const char* const strBuf) | |||
| { | |||
| _init(); | |||
| _dup(strBuf); | |||
| } | |||
| explicit CarlaString(const int value) | |||
| { | |||
| const size_t strBufSize = std::abs(value/10) + 3; | |||
| char strBuf[strBufSize]; | |||
| std::snprintf(strBuf, strBufSize, "%d", value); | |||
| _init(); | |||
| _dup(strBuf, strBufSize); | |||
| } | |||
| explicit CarlaString(const unsigned int value, const bool hexadecimal = false) | |||
| { | |||
| const size_t strBufSize = value/10 + 2 + (hexadecimal ? 2 : 0); | |||
| char strBuf[strBufSize]; | |||
| std::snprintf(strBuf, strBufSize, hexadecimal ? "0x%x" : "%u", value); | |||
| _init(); | |||
| _dup(strBuf, strBufSize); | |||
| } | |||
| explicit CarlaString(const long int value) | |||
| { | |||
| const size_t strBufSize = std::abs(value/10) + 3; | |||
| char strBuf[strBufSize]; | |||
| std::snprintf(strBuf, strBufSize, "%ld", value); | |||
| _init(); | |||
| _dup(strBuf, strBufSize); | |||
| } | |||
| explicit CarlaString(const unsigned long int value, const bool hexadecimal = false) | |||
| { | |||
| const size_t strBufSize = value/10 + 2 + (hexadecimal ? 2 : 0); | |||
| char strBuf[strBufSize]; | |||
| std::snprintf(strBuf, strBufSize, hexadecimal ? "0x%lx" : "%lu", value); | |||
| _init(); | |||
| _dup(strBuf, strBufSize); | |||
| } | |||
| explicit CarlaString(const float value) | |||
| { | |||
| char strBuf[0xff]; | |||
| std::snprintf(strBuf, 0xff, "%f", value); | |||
| _init(); | |||
| _dup(strBuf); | |||
| } | |||
| explicit CarlaString(const double value) | |||
| { | |||
| char strBuf[0xff]; | |||
| std::snprintf(strBuf, 0xff, "%g", value); | |||
| _init(); | |||
| _dup(strBuf); | |||
| } | |||
| // --------------------------------------------- | |||
| // non-explicit constructor | |||
| CarlaString(const CarlaString& str) | |||
| { | |||
| _init(); | |||
| _dup(str.buffer); | |||
| } | |||
| // --------------------------------------------- | |||
| // deconstructor | |||
| ~CarlaString() | |||
| { | |||
| CARLA_ASSERT(buffer); | |||
| delete[] buffer; | |||
| } | |||
| // --------------------------------------------- | |||
| // public methods | |||
| size_t length() const | |||
| { | |||
| return bufferLen; | |||
| } | |||
| bool isEmpty() const | |||
| { | |||
| return (bufferLen == 0); | |||
| } | |||
| bool isNotEmpty() const | |||
| { | |||
| return (bufferLen != 0); | |||
| } | |||
| #if __USE_GNU | |||
| bool contains(const char* const strBuf, const bool ignoreCase = false) const | |||
| { | |||
| if (strBuf == nullptr) | |||
| return false; | |||
| if (ignoreCase) | |||
| return (strcasestr(buffer, strBuf) != nullptr); | |||
| else | |||
| return (std::strstr(buffer, strBuf) != nullptr); | |||
| } | |||
| bool contains(const CarlaString& str, const bool ignoreCase = false) const | |||
| { | |||
| return contains(str.buffer, ignoreCase); | |||
| } | |||
| #else | |||
| bool contains(const char* const strBuf) const | |||
| { | |||
| if (strBuf == nullptr) | |||
| return false; | |||
| return (std::strstr(buffer, strBuf) != nullptr); | |||
| } | |||
| bool contains(const CarlaString& str) const | |||
| { | |||
| return contains(str.buffer); | |||
| } | |||
| #endif | |||
| bool isDigit(const size_t pos) const | |||
| { | |||
| if (pos >= bufferLen) | |||
| return false; | |||
| return (buffer[pos] >= '0' && buffer[pos] <= '9'); | |||
| } | |||
| void clear() | |||
| { | |||
| truncate(0); | |||
| } | |||
| void replace(const char before, const char after) | |||
| { | |||
| if (after == '\0') | |||
| return; | |||
| for (size_t i=0; i < bufferLen; i++) | |||
| { | |||
| if (buffer[i] == before) | |||
| buffer[i] = after; | |||
| else if (buffer[i] == '\0') | |||
| break; | |||
| } | |||
| } | |||
| void truncate(const size_t n) | |||
| { | |||
| if (n >= bufferLen) | |||
| return; | |||
| for (size_t i=n; i < bufferLen; i++) | |||
| buffer[i] = '\0'; | |||
| bufferLen = n; | |||
| } | |||
| void toBasic() | |||
| { | |||
| for (size_t i=0; i < bufferLen; i++) | |||
| { | |||
| if (buffer[i] >= '0' && buffer[i] <= '9') | |||
| continue; | |||
| if (buffer[i] >= 'A' && buffer[i] <= 'Z') | |||
| continue; | |||
| if (buffer[i] >= 'a' && buffer[i] <= 'z') | |||
| continue; | |||
| if (buffer[i] == '_') | |||
| continue; | |||
| buffer[i] = '_'; | |||
| } | |||
| } | |||
| void toLower() | |||
| { | |||
| static const char charDiff = 'a' - 'A'; | |||
| for (size_t i=0; i < bufferLen; i++) | |||
| { | |||
| if (buffer[i] >= 'A' && buffer[i] <= 'Z') | |||
| buffer[i] += charDiff; | |||
| } | |||
| } | |||
| void toUpper() | |||
| { | |||
| static const char charDiff = 'a' - 'A'; | |||
| for (size_t i=0; i < bufferLen; i++) | |||
| { | |||
| if (buffer[i] >= 'a' && buffer[i] <= 'z') | |||
| buffer[i] -= charDiff; | |||
| } | |||
| } | |||
| // --------------------------------------------- | |||
| // public operators | |||
| operator const char*() const | |||
| { | |||
| return buffer; | |||
| } | |||
| char& operator[](const size_t pos) | |||
| { | |||
| return buffer[pos]; | |||
| } | |||
| bool operator==(const char* const strBuf) const | |||
| { | |||
| return (strBuf != nullptr && std::strcmp(buffer, strBuf) == 0); | |||
| } | |||
| bool operator==(const CarlaString& str) const | |||
| { | |||
| return operator==(str.buffer); | |||
| } | |||
| bool operator!=(const char* const strBuf) const | |||
| { | |||
| return !operator==(strBuf); | |||
| } | |||
| bool operator!=(const CarlaString& str) const | |||
| { | |||
| return !operator==(str.buffer); | |||
| } | |||
| CarlaString& operator=(const char* const strBuf) | |||
| { | |||
| _dup(strBuf); | |||
| return *this; | |||
| } | |||
| CarlaString& operator=(const CarlaString& str) | |||
| { | |||
| return operator=(str.buffer); | |||
| } | |||
| CarlaString& operator+=(const char* const strBuf) | |||
| { | |||
| const size_t newBufSize = bufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1; | |||
| char newBuf[newBufSize]; | |||
| std::strcpy(newBuf, buffer); | |||
| std::strcat(newBuf, strBuf); | |||
| _dup(newBuf, newBufSize-1); | |||
| return *this; | |||
| } | |||
| CarlaString& operator+=(const CarlaString& str) | |||
| { | |||
| return operator+=(str.buffer); | |||
| } | |||
| CarlaString operator+(const char* const strBuf) | |||
| { | |||
| const size_t newBufSize = bufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1; | |||
| char newBuf[newBufSize]; | |||
| std::strcpy(newBuf, buffer); | |||
| std::strcat(newBuf, strBuf); | |||
| return CarlaString(newBuf); | |||
| } | |||
| CarlaString operator+(const CarlaString& str) | |||
| { | |||
| return operator+(str.buffer); | |||
| } | |||
| // --------------------------------------------- | |||
| private: | |||
| char* buffer; | |||
| size_t bufferLen; | |||
| bool firstInit; | |||
| void _init() | |||
| { | |||
| buffer = nullptr; | |||
| bufferLen = 0; | |||
| firstInit = true; | |||
| } | |||
| // allocate string strBuf if not null | |||
| // size > 0 only if strBuf is valid | |||
| void _dup(const char* const strBuf, const size_t size = 0) | |||
| { | |||
| if (strBuf != nullptr) | |||
| { | |||
| // don't recreate string if contents match | |||
| if (firstInit || std::strcmp(buffer, strBuf) != 0) | |||
| { | |||
| if (! firstInit) | |||
| { | |||
| CARLA_ASSERT(buffer); | |||
| delete[] buffer; | |||
| } | |||
| bufferLen = (size > 0) ? size : std::strlen(strBuf); | |||
| buffer = new char[bufferLen+1]; | |||
| std::strcpy(buffer, strBuf); | |||
| buffer[bufferLen] = '\0'; | |||
| firstInit = false; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| CARLA_ASSERT(size == 0); | |||
| // don't recreate null string | |||
| if (firstInit || bufferLen != 0) | |||
| { | |||
| if (! firstInit) | |||
| { | |||
| CARLA_ASSERT(buffer); | |||
| delete[] buffer; | |||
| } | |||
| bufferLen = 0; | |||
| buffer = new char[1]; | |||
| buffer[0] = '\0'; | |||
| firstInit = false; | |||
| } | |||
| } | |||
| } | |||
| CARLA_LEAK_DETECTOR(CarlaString) | |||
| CARLA_PREVENT_HEAP_ALLOCATION | |||
| }; | |||
| static inline | |||
| CarlaString operator+(const char* const strBufBefore, const CarlaString& strAfter) | |||
| { | |||
| const char* const strBufAfter = (const char*)strAfter; | |||
| const size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + std::strlen(strBufAfter) + 1; | |||
| char newBuf[newBufSize]; | |||
| std::strcpy(newBuf, strBufBefore); | |||
| std::strcat(newBuf, strBufAfter); | |||
| return CarlaString(newBuf); | |||
| } | |||
| // ------------------------------------------------- | |||
| #endif // __CARLA_UTILS_HPP__ | |||
| @@ -0,0 +1,253 @@ | |||
| /* | |||
| * Carla common 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 GPL.txt file | |||
| */ | |||
| #ifndef __CARLA_THREAD_HPP__ | |||
| #define __CARLA_THREAD_HPP__ | |||
| #include "carla_juce_utils.hpp" | |||
| // #define CPP11_MUTEX | |||
| #ifdef CPP11_THREAD | |||
| # include <thread> | |||
| #else | |||
| # include <pthread.h> | |||
| #endif | |||
| // ------------------------------------------------- | |||
| // CarlaThread class | |||
| class CarlaThread | |||
| { | |||
| public: | |||
| CarlaThread() | |||
| : fStarted(false), | |||
| fFinished(false) | |||
| { | |||
| #ifdef CPP11_MUTEX | |||
| cthread = nullptr; | |||
| #else | |||
| _zero(); | |||
| pthread_attr_init(&pthreadAttr); | |||
| pthread_attr_setdetachstate(&pthreadAttr, PTHREAD_CREATE_JOINABLE); | |||
| #endif | |||
| } | |||
| ~CarlaThread() | |||
| { | |||
| CARLA_ASSERT(! isRunning()); | |||
| if (isRunning()) | |||
| terminate(); | |||
| #ifdef CPP11_MUTEX | |||
| if (cthread != nullptr) | |||
| { | |||
| cthread->join(); | |||
| delete cthread; | |||
| } | |||
| #else | |||
| if (! _isNull()) | |||
| pthread_join(pthreadId, nullptr); | |||
| pthread_attr_destroy(&pthreadAttr); | |||
| #endif | |||
| } | |||
| bool start() | |||
| { | |||
| CARLA_ASSERT(! isRunning()); | |||
| if (isRunning()) | |||
| return false; | |||
| fStarted = false; | |||
| fFinished = false; | |||
| #ifdef CPP11_MUTEX | |||
| CARLA_ASSERT(cthread == nullptr); | |||
| if (cthread != nullptr) | |||
| return false; | |||
| cthread = new std::thread(_cthreadRoutine, this); | |||
| CARLA_ASSERT(cthread->joinable()); | |||
| return true; | |||
| #else | |||
| CARLA_ASSERT(_isNull()); | |||
| if (! _isNull()) | |||
| return false; | |||
| return (pthread_create(&pthreadId, &pthreadAttr, _pthreadRoutine, this) == 0); | |||
| #endif | |||
| } | |||
| bool stop(const unsigned int timeout = 0) | |||
| { | |||
| CARLA_ASSERT(isRunning()); | |||
| if (! isRunning()) | |||
| return true; | |||
| #ifdef CPP11_MUTEX | |||
| if (cthread == nullptr) | |||
| return true; | |||
| #else | |||
| if (_isNull()) | |||
| return true; | |||
| #endif | |||
| if (timeout == 0) | |||
| { | |||
| #ifdef CPP11_MUTEX | |||
| cthread->join(); | |||
| #else | |||
| pthread_join(pthreadId, nullptr); | |||
| #endif | |||
| } | |||
| else | |||
| { | |||
| for (unsigned int i=0; i < timeout && ! fFinished; i++) | |||
| carla_msleep(1); | |||
| } | |||
| if (! fFinished) | |||
| return false; | |||
| #ifdef CPP11_MUTEX | |||
| delete cthread; | |||
| cthread = nullptr; | |||
| #else | |||
| _zero(); | |||
| #endif | |||
| return true; | |||
| } | |||
| void terminate() | |||
| { | |||
| CARLA_ASSERT(isRunning()); | |||
| if (fFinished) | |||
| return; | |||
| #ifdef CPP11_MUTEX | |||
| if (cthread == nullptr) | |||
| return; | |||
| #else | |||
| if (_isNull()) | |||
| return; | |||
| #endif | |||
| #ifdef CPP11_MUTEX | |||
| cthread->detach(); | |||
| //cthread->join(); | |||
| delete cthread; | |||
| cthread = nullptr; | |||
| #else | |||
| pthread_detach(pthreadId); | |||
| //pthread_join(pthreadId, nullptr); | |||
| pthread_cancel(pthreadId); | |||
| _zero(); | |||
| #endif | |||
| fFinished = true; | |||
| } | |||
| bool isRunning() | |||
| { | |||
| return (fStarted && ! fFinished); | |||
| } | |||
| void waitForStarted(const unsigned int timeout = 0) // ms | |||
| { | |||
| if (fStarted) | |||
| return; | |||
| if (timeout == 0) | |||
| { | |||
| while (! fStarted) {} | |||
| } | |||
| else | |||
| { | |||
| for (unsigned int i=0; i < timeout && ! fStarted; i++) | |||
| carla_msleep(1); | |||
| } | |||
| } | |||
| void waitForFinished() | |||
| { | |||
| waitForStarted(); | |||
| stop(0); | |||
| } | |||
| protected: | |||
| virtual void run() = 0; | |||
| private: | |||
| bool fStarted; | |||
| bool fFinished; | |||
| void handleRoutine() | |||
| { | |||
| fStarted = true; | |||
| run(); | |||
| fFinished = true; | |||
| } | |||
| #ifdef CPP11_MUTEX | |||
| std::thread* cthread; | |||
| static void _cthreadRoutine(CarlaThread* const _this_) | |||
| { | |||
| _this_->handleRoutine(); | |||
| } | |||
| #else | |||
| pthread_t pthreadId; | |||
| pthread_attr_t pthreadAttr; | |||
| static void* _pthreadRoutine(void* const _this_) | |||
| { | |||
| ((CarlaThread*)_this_)->handleRoutine(); | |||
| pthread_exit(nullptr); | |||
| return nullptr; | |||
| } | |||
| bool _isNull() | |||
| { | |||
| #ifdef CARLA_OS_WIN | |||
| return (pthreadId.p == nullptr); | |||
| #else | |||
| return (pthreadId == 0); | |||
| #endif | |||
| } | |||
| void _zero() | |||
| { | |||
| carla_zeroStruct<pthread_t>(pthreadId); | |||
| } | |||
| #endif | |||
| CARLA_PREVENT_HEAP_ALLOCATION | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaThread) | |||
| }; | |||
| // ------------------------------------------------- | |||
| #endif // __CARLA_THREAD_HPP__ | |||
| @@ -18,47 +18,101 @@ | |||
| #ifndef __CARLA_UTILS_HPP__ | |||
| #define __CARLA_UTILS_HPP__ | |||
| #include "carla_juce_utils.hpp" | |||
| #include "carla_defines.hpp" | |||
| #include <cassert> | |||
| #include <cstdarg> | |||
| #include <cstdio> | |||
| #include <cstdlib> | |||
| #include <cstring> | |||
| // #define CPP11_MUTEX | |||
| #ifdef CPP11_MUTEX | |||
| # include <mutex> | |||
| # include <thread> | |||
| #else | |||
| # include <pthread.h> | |||
| #endif | |||
| #if defined(Q_OS_HAIKU) | |||
| #if defined(CARLA_OS_HAIKU) | |||
| # include <kernel/OS.h> | |||
| #elif defined(Q_OS_LINUX) | |||
| #elif defined(CARLA_OS_LINUX) | |||
| # include <sys/prctl.h> | |||
| # include <linux/prctl.h> | |||
| #endif | |||
| // ------------------------------------------------- | |||
| // misc functions | |||
| static inline | |||
| const char* bool2str(const bool yesNo) | |||
| { | |||
| return yesNo ? "true" : "false"; | |||
| } | |||
| static inline | |||
| void pass() {} | |||
| // ------------------------------------------------- | |||
| // string print functions | |||
| #ifndef DEBUG | |||
| # define carla_debug(...) | |||
| #else | |||
| static inline | |||
| void carla_debug(const char* const fmt, ...) | |||
| { | |||
| std::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 | |||
| static inline | |||
| void carla_stdout(const char* const fmt, ...) | |||
| { | |||
| std::va_list args; | |||
| va_start(args, fmt); | |||
| std::vfprintf(stdout, fmt, args); | |||
| std::fprintf(stdout, "\n"); | |||
| va_end(args); | |||
| } | |||
| static inline | |||
| void carla_stderr(const char* const fmt, ...) | |||
| { | |||
| std::va_list args; | |||
| va_start(args, fmt); | |||
| std::vfprintf(stderr, fmt, args); | |||
| std::fprintf(stderr, "\n"); | |||
| va_end(args); | |||
| } | |||
| static inline | |||
| void carla_stderr2(const char* const fmt, ...) | |||
| { | |||
| std::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_assert* | |||
| static inline | |||
| void carla_assert(const char* const assertion, const char* const file, const int line) | |||
| { | |||
| qCritical("Carla assertion failure: \"%s\" in file %s, line %i", assertion, file, line); | |||
| carla_stderr2("Carla assertion failure: \"%s\" in file %s, line %i", assertion, file, line); | |||
| } | |||
| static inline | |||
| void carla_assert_int(const char* const assertion, const char* const file, const int line, const int value) | |||
| { | |||
| qCritical("Carla assertion failure: \"%s\" in file %s, line %i, value %i", assertion, file, line, value); | |||
| carla_stderr2("Carla assertion failure: \"%s\" in file %s, line %i, value %i", assertion, file, line, value); | |||
| } | |||
| static inline | |||
| void carla_assert_int2(const char* const assertion, const char* const file, const int line, const int v1, const int v2) | |||
| { | |||
| qCritical("Carla assertion failure: \"%s\" in file %s, line %i, v1 %i, v2 %i", assertion, file, line, v1, v2); | |||
| carla_stderr2("Carla assertion failure: \"%s\" in file %s, line %i, v1 %i, v2 %i", assertion, file, line, v1, v2); | |||
| } | |||
| // ------------------------------------------------- | |||
| @@ -69,7 +123,7 @@ void carla_sleep(const unsigned int secs) | |||
| { | |||
| CARLA_ASSERT(secs > 0); | |||
| #ifdef Q_OS_WIN | |||
| #ifdef CARLA_OS_WIN | |||
| Sleep(secs * 1000); | |||
| #else | |||
| sleep(secs); | |||
| @@ -81,7 +135,7 @@ void carla_msleep(const unsigned int msecs) | |||
| { | |||
| CARLA_ASSERT(msecs > 0); | |||
| #ifdef Q_OS_WIN | |||
| #ifdef CARLA_OS_WIN | |||
| Sleep(msecs); | |||
| #else | |||
| usleep(msecs * 1000); | |||
| @@ -93,7 +147,7 @@ void carla_usleep(const unsigned int usecs) | |||
| { | |||
| CARLA_ASSERT(usecs > 0); | |||
| #ifdef Q_OS_WIN | |||
| #ifdef CARLA_OS_WIN | |||
| Sleep(usecs / 1000); | |||
| #else | |||
| usleep(usecs); | |||
| @@ -109,7 +163,7 @@ void carla_setenv(const char* const key, const char* const value) | |||
| CARLA_ASSERT(key != nullptr); | |||
| CARLA_ASSERT(value != nullptr); | |||
| #ifdef Q_OS_WIN | |||
| #ifdef CARLA_OS_WIN | |||
| SetEnvironmentVariableA(key, value); | |||
| #else | |||
| setenv(key, value, 1); | |||
| @@ -124,13 +178,13 @@ void carla_setprocname(const char* const name) | |||
| { | |||
| CARLA_ASSERT(name != nullptr); | |||
| #if defined(Q_OS_HAIKU) | |||
| #if defined(CARLA_OS_HAIKU) | |||
| if ((thread_id this_thread = find_thread(nullptr)) != B_NAME_NOT_FOUND) | |||
| rename_thread(this_thread, name); | |||
| #elif defined(Q_OS_LINUX) | |||
| #elif defined(CARLA_OS_LINUX) | |||
| prctl(PR_SET_NAME, name); | |||
| #else | |||
| qWarning("carla_setprocname(\"%s\") - unsupported on this platform", name); | |||
| carla_stderr("carla_setprocname(\"%s\") - unsupported on this platform", name); | |||
| #endif | |||
| } | |||
| @@ -226,704 +280,6 @@ void carla_zeroStruct(T& structure) | |||
| std::memset(&structure, 0, sizeof(T)); | |||
| } | |||
| // ------------------------------------------------- | |||
| // other misc functions | |||
| static inline | |||
| const char* bool2str(const bool yesNo) | |||
| { | |||
| return yesNo ? "true" : "false"; | |||
| } | |||
| static inline | |||
| void pass() {} | |||
| // ------------------------------------------------- | |||
| // CarlaMutex class | |||
| class CarlaMutex | |||
| { | |||
| public: | |||
| CarlaMutex() | |||
| { | |||
| #ifndef CPP11_MUTEX | |||
| pthread_mutex_init(&pmutex, nullptr); | |||
| #endif | |||
| } | |||
| ~CarlaMutex() | |||
| { | |||
| #ifndef CPP11_MUTEX | |||
| pthread_mutex_destroy(&pmutex); | |||
| #endif | |||
| } | |||
| void lock() | |||
| { | |||
| #ifdef CPP11_MUTEX | |||
| cmutex.lock(); | |||
| #else | |||
| pthread_mutex_lock(&pmutex); | |||
| #endif | |||
| } | |||
| bool tryLock() | |||
| { | |||
| #ifdef CPP11_MUTEX | |||
| return cmutex.try_lock(); | |||
| #else | |||
| return (pthread_mutex_trylock(&pmutex) == 0); | |||
| #endif | |||
| } | |||
| void unlock() | |||
| { | |||
| #ifdef CPP11_MUTEX | |||
| cmutex.unlock(); | |||
| #else | |||
| pthread_mutex_unlock(&pmutex); | |||
| #endif | |||
| } | |||
| class ScopedLocker | |||
| { | |||
| public: | |||
| ScopedLocker(CarlaMutex* const mutex) | |||
| : fMutex(mutex) | |||
| { | |||
| fMutex->lock(); | |||
| } | |||
| ~ScopedLocker() | |||
| { | |||
| fMutex->unlock(); | |||
| } | |||
| private: | |||
| CarlaMutex* const fMutex; | |||
| CARLA_PREVENT_HEAP_ALLOCATION | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ScopedLocker) | |||
| }; | |||
| private: | |||
| #ifdef CPP11_MUTEX | |||
| std::mutex cmutex; | |||
| #else | |||
| pthread_mutex_t pmutex; | |||
| #endif | |||
| CARLA_PREVENT_HEAP_ALLOCATION | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaMutex) | |||
| }; | |||
| // ------------------------------------------------- | |||
| // CarlaThread class | |||
| class CarlaThread | |||
| { | |||
| public: | |||
| CarlaThread() | |||
| : fStarted(false), | |||
| fFinished(false) | |||
| { | |||
| #ifdef CPP11_MUTEX | |||
| cthread = nullptr; | |||
| #else | |||
| _zero(); | |||
| pthread_attr_init(&pthreadAttr); | |||
| pthread_attr_setdetachstate(&pthreadAttr, PTHREAD_CREATE_JOINABLE); | |||
| #endif | |||
| } | |||
| ~CarlaThread() | |||
| { | |||
| CARLA_ASSERT(! isRunning()); | |||
| if (isRunning()) | |||
| terminate(); | |||
| #ifdef CPP11_MUTEX | |||
| if (cthread != nullptr) | |||
| { | |||
| cthread->join(); | |||
| delete cthread; | |||
| } | |||
| #else | |||
| if (! _isNull()) | |||
| pthread_join(pthreadId, nullptr); | |||
| pthread_attr_destroy(&pthreadAttr); | |||
| #endif | |||
| } | |||
| bool start() | |||
| { | |||
| CARLA_ASSERT(! isRunning()); | |||
| if (isRunning()) | |||
| return false; | |||
| fStarted = false; | |||
| fFinished = false; | |||
| #ifdef CPP11_MUTEX | |||
| CARLA_ASSERT(cthread == nullptr); | |||
| if (cthread != nullptr) | |||
| return false; | |||
| cthread = new std::thread(_cthreadRoutine, this); | |||
| CARLA_ASSERT(cthread->joinable()); | |||
| return true; | |||
| #else | |||
| CARLA_ASSERT(_isNull()); | |||
| if (! _isNull()) | |||
| return false; | |||
| return (pthread_create(&pthreadId, &pthreadAttr, _pthreadRoutine, this) == 0); | |||
| #endif | |||
| } | |||
| bool stop(const unsigned int timeout = 0) | |||
| { | |||
| CARLA_ASSERT(isRunning()); | |||
| if (! isRunning()) | |||
| return true; | |||
| #ifdef CPP11_MUTEX | |||
| if (cthread == nullptr) | |||
| return true; | |||
| #else | |||
| if (_isNull()) | |||
| return true; | |||
| #endif | |||
| if (timeout == 0) | |||
| { | |||
| #ifdef CPP11_MUTEX | |||
| cthread->join(); | |||
| #else | |||
| pthread_join(pthreadId, nullptr); | |||
| #endif | |||
| } | |||
| else | |||
| { | |||
| for (unsigned int i=0; i < timeout && ! fFinished; i++) | |||
| carla_msleep(1); | |||
| } | |||
| if (! fFinished) | |||
| return false; | |||
| #ifdef CPP11_MUTEX | |||
| delete cthread; | |||
| cthread = nullptr; | |||
| #else | |||
| _zero(); | |||
| #endif | |||
| return true; | |||
| } | |||
| void terminate() | |||
| { | |||
| CARLA_ASSERT(isRunning()); | |||
| if (fFinished) | |||
| return; | |||
| #ifdef CPP11_MUTEX | |||
| if (cthread == nullptr) | |||
| return; | |||
| #else | |||
| if (_isNull()) | |||
| return; | |||
| #endif | |||
| #ifdef CPP11_MUTEX | |||
| cthread->detach(); | |||
| //cthread->join(); | |||
| delete cthread; | |||
| cthread = nullptr; | |||
| #else | |||
| pthread_detach(pthreadId); | |||
| //pthread_join(pthreadId, nullptr); | |||
| pthread_cancel(pthreadId); | |||
| _zero(); | |||
| #endif | |||
| fFinished = true; | |||
| } | |||
| bool isRunning() | |||
| { | |||
| return (fStarted && ! fFinished); | |||
| } | |||
| void waitForStarted(const unsigned int timeout = 0) // ms | |||
| { | |||
| if (fStarted) | |||
| return; | |||
| if (timeout == 0) | |||
| { | |||
| while (! fStarted) {} | |||
| } | |||
| else | |||
| { | |||
| for (unsigned int i=0; i < timeout && ! fStarted; i++) | |||
| carla_msleep(1); | |||
| } | |||
| } | |||
| void waitForFinished() | |||
| { | |||
| waitForStarted(); | |||
| stop(0); | |||
| } | |||
| protected: | |||
| virtual void run() = 0; | |||
| private: | |||
| bool fStarted; | |||
| bool fFinished; | |||
| void handleRoutine() | |||
| { | |||
| fStarted = true; | |||
| run(); | |||
| fFinished = true; | |||
| } | |||
| #ifdef CPP11_MUTEX | |||
| std::thread* cthread; | |||
| static void _cthreadRoutine(CarlaThread* const _this_) | |||
| { | |||
| _this_->handleRoutine(); | |||
| } | |||
| #else | |||
| pthread_t pthreadId; | |||
| pthread_attr_t pthreadAttr; | |||
| static void* _pthreadRoutine(void* const _this_) | |||
| { | |||
| ((CarlaThread*)_this_)->handleRoutine(); | |||
| pthread_exit(nullptr); | |||
| return nullptr; | |||
| } | |||
| bool _isNull() | |||
| { | |||
| #ifdef Q_OS_WIN | |||
| return pthreadId.p == nullptr; | |||
| #else | |||
| return pthreadId == 0; | |||
| #endif | |||
| } | |||
| void _zero() | |||
| { | |||
| carla_zeroStruct<pthread_t>(pthreadId); | |||
| } | |||
| #endif | |||
| CARLA_PREVENT_HEAP_ALLOCATION | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaThread) | |||
| }; | |||
| // ------------------------------------------------- | |||
| // CarlaString class | |||
| class CarlaString | |||
| { | |||
| public: | |||
| // --------------------------------------------- | |||
| // constructors (no explicit conversions allowed) | |||
| explicit CarlaString() | |||
| { | |||
| _init(); | |||
| _dup(nullptr); | |||
| } | |||
| explicit CarlaString(char* const strBuf) | |||
| { | |||
| _init(); | |||
| _dup(strBuf); | |||
| } | |||
| explicit CarlaString(const char* const strBuf) | |||
| { | |||
| _init(); | |||
| _dup(strBuf); | |||
| } | |||
| explicit CarlaString(const int value) | |||
| { | |||
| const size_t strBufSize = std::abs(value/10) + 3; | |||
| char strBuf[strBufSize]; | |||
| std::snprintf(strBuf, strBufSize, "%d", value); | |||
| _init(); | |||
| _dup(strBuf, strBufSize); | |||
| } | |||
| explicit CarlaString(const unsigned int value, const bool hexadecimal = false) | |||
| { | |||
| const size_t strBufSize = value/10 + 2 + (hexadecimal ? 2 : 0); | |||
| char strBuf[strBufSize]; | |||
| std::snprintf(strBuf, strBufSize, hexadecimal ? "0x%x" : "%u", value); | |||
| _init(); | |||
| _dup(strBuf, strBufSize); | |||
| } | |||
| explicit CarlaString(const long int value) | |||
| { | |||
| const size_t strBufSize = std::abs(value/10) + 3; | |||
| char strBuf[strBufSize]; | |||
| std::snprintf(strBuf, strBufSize, "%ld", value); | |||
| _init(); | |||
| _dup(strBuf, strBufSize); | |||
| } | |||
| explicit CarlaString(const unsigned long int value, const bool hexadecimal = false) | |||
| { | |||
| const size_t strBufSize = value/10 + 2 + (hexadecimal ? 2 : 0); | |||
| char strBuf[strBufSize]; | |||
| std::snprintf(strBuf, strBufSize, hexadecimal ? "0x%lx" : "%lu", value); | |||
| _init(); | |||
| _dup(strBuf, strBufSize); | |||
| } | |||
| explicit CarlaString(const float value) | |||
| { | |||
| char strBuf[0xff]; | |||
| std::snprintf(strBuf, 0xff, "%f", value); | |||
| _init(); | |||
| _dup(strBuf); | |||
| } | |||
| explicit CarlaString(const double value) | |||
| { | |||
| char strBuf[0xff]; | |||
| std::snprintf(strBuf, 0xff, "%g", value); | |||
| _init(); | |||
| _dup(strBuf); | |||
| } | |||
| // --------------------------------------------- | |||
| // non-explicit constructor | |||
| CarlaString(const CarlaString& str) | |||
| { | |||
| _init(); | |||
| _dup(str.buffer); | |||
| } | |||
| // --------------------------------------------- | |||
| // deconstructor | |||
| ~CarlaString() | |||
| { | |||
| CARLA_ASSERT(buffer); | |||
| delete[] buffer; | |||
| } | |||
| // --------------------------------------------- | |||
| // public methods | |||
| size_t length() const | |||
| { | |||
| return bufferLen; | |||
| } | |||
| bool isEmpty() const | |||
| { | |||
| return (bufferLen == 0); | |||
| } | |||
| bool isNotEmpty() const | |||
| { | |||
| return (bufferLen != 0); | |||
| } | |||
| #if __USE_GNU | |||
| bool contains(const char* const strBuf, const bool ignoreCase = false) const | |||
| { | |||
| if (strBuf == nullptr) | |||
| return false; | |||
| if (ignoreCase) | |||
| return (strcasestr(buffer, strBuf) != nullptr); | |||
| else | |||
| return (std::strstr(buffer, strBuf) != nullptr); | |||
| } | |||
| bool contains(const CarlaString& str, const bool ignoreCase = false) const | |||
| { | |||
| return contains(str.buffer, ignoreCase); | |||
| } | |||
| #else | |||
| bool contains(const char* const strBuf) const | |||
| { | |||
| if (strBuf == nullptr) | |||
| return false; | |||
| return (std::strstr(buffer, strBuf) != nullptr); | |||
| } | |||
| bool contains(const CarlaString& str) const | |||
| { | |||
| return contains(str.buffer); | |||
| } | |||
| #endif | |||
| bool isDigit(const size_t pos) const | |||
| { | |||
| if (pos >= bufferLen) | |||
| return false; | |||
| return (buffer[pos] >= '0' && buffer[pos] <= '9'); | |||
| } | |||
| void clear() | |||
| { | |||
| truncate(0); | |||
| } | |||
| void replace(const char before, const char after) | |||
| { | |||
| if (after == '\0') | |||
| return; | |||
| for (size_t i=0; i < bufferLen; i++) | |||
| { | |||
| if (buffer[i] == before) | |||
| buffer[i] = after; | |||
| else if (buffer[i] == '\0') | |||
| break; | |||
| } | |||
| } | |||
| void truncate(const size_t n) | |||
| { | |||
| if (n >= bufferLen) | |||
| return; | |||
| for (size_t i=n; i < bufferLen; i++) | |||
| buffer[i] = '\0'; | |||
| bufferLen = n; | |||
| } | |||
| void toBasic() | |||
| { | |||
| for (size_t i=0; i < bufferLen; i++) | |||
| { | |||
| if (buffer[i] >= '0' && buffer[i] <= '9') | |||
| continue; | |||
| if (buffer[i] >= 'A' && buffer[i] <= 'Z') | |||
| continue; | |||
| if (buffer[i] >= 'a' && buffer[i] <= 'z') | |||
| continue; | |||
| if (buffer[i] == '_') | |||
| continue; | |||
| buffer[i] = '_'; | |||
| } | |||
| } | |||
| void toLower() | |||
| { | |||
| static const char charDiff = 'a' - 'A'; | |||
| for (size_t i=0; i < bufferLen; i++) | |||
| { | |||
| if (buffer[i] >= 'A' && buffer[i] <= 'Z') | |||
| buffer[i] += charDiff; | |||
| } | |||
| } | |||
| void toUpper() | |||
| { | |||
| static const char charDiff = 'a' - 'A'; | |||
| for (size_t i=0; i < bufferLen; i++) | |||
| { | |||
| if (buffer[i] >= 'a' && buffer[i] <= 'z') | |||
| buffer[i] -= charDiff; | |||
| } | |||
| } | |||
| // --------------------------------------------- | |||
| // public operators | |||
| operator const char*() const | |||
| { | |||
| return buffer; | |||
| } | |||
| char& operator[](const size_t pos) | |||
| { | |||
| return buffer[pos]; | |||
| } | |||
| bool operator==(const char* const strBuf) const | |||
| { | |||
| return (strBuf != nullptr && std::strcmp(buffer, strBuf) == 0); | |||
| } | |||
| bool operator==(const CarlaString& str) const | |||
| { | |||
| return operator==(str.buffer); | |||
| } | |||
| bool operator!=(const char* const strBuf) const | |||
| { | |||
| return !operator==(strBuf); | |||
| } | |||
| bool operator!=(const CarlaString& str) const | |||
| { | |||
| return !operator==(str.buffer); | |||
| } | |||
| CarlaString& operator=(const char* const strBuf) | |||
| { | |||
| _dup(strBuf); | |||
| return *this; | |||
| } | |||
| CarlaString& operator=(const CarlaString& str) | |||
| { | |||
| return operator=(str.buffer); | |||
| } | |||
| CarlaString& operator+=(const char* const strBuf) | |||
| { | |||
| const size_t newBufSize = bufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1; | |||
| char newBuf[newBufSize]; | |||
| std::strcpy(newBuf, buffer); | |||
| std::strcat(newBuf, strBuf); | |||
| _dup(newBuf, newBufSize-1); | |||
| return *this; | |||
| } | |||
| CarlaString& operator+=(const CarlaString& str) | |||
| { | |||
| return operator+=(str.buffer); | |||
| } | |||
| CarlaString operator+(const char* const strBuf) | |||
| { | |||
| const size_t newBufSize = bufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1; | |||
| char newBuf[newBufSize]; | |||
| std::strcpy(newBuf, buffer); | |||
| std::strcat(newBuf, strBuf); | |||
| return CarlaString(newBuf); | |||
| } | |||
| CarlaString operator+(const CarlaString& str) | |||
| { | |||
| return operator+(str.buffer); | |||
| } | |||
| // --------------------------------------------- | |||
| private: | |||
| char* buffer; | |||
| size_t bufferLen; | |||
| bool firstInit; | |||
| void _init() | |||
| { | |||
| buffer = nullptr; | |||
| bufferLen = 0; | |||
| firstInit = true; | |||
| } | |||
| // allocate string strBuf if not null | |||
| // size > 0 only if strBuf is valid | |||
| void _dup(const char* const strBuf, const size_t size = 0) | |||
| { | |||
| if (strBuf != nullptr) | |||
| { | |||
| // don't recreate string if contents match | |||
| if (firstInit || std::strcmp(buffer, strBuf) != 0) | |||
| { | |||
| if (! firstInit) | |||
| { | |||
| CARLA_ASSERT(buffer); | |||
| delete[] buffer; | |||
| } | |||
| bufferLen = (size > 0) ? size : std::strlen(strBuf); | |||
| buffer = new char[bufferLen+1]; | |||
| std::strcpy(buffer, strBuf); | |||
| buffer[bufferLen] = '\0'; | |||
| firstInit = false; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| CARLA_ASSERT(size == 0); | |||
| // don't recreate null string | |||
| if (firstInit || bufferLen != 0) | |||
| { | |||
| if (! firstInit) | |||
| { | |||
| CARLA_ASSERT(buffer); | |||
| delete[] buffer; | |||
| } | |||
| bufferLen = 0; | |||
| buffer = new char[1]; | |||
| buffer[0] = '\0'; | |||
| firstInit = false; | |||
| } | |||
| } | |||
| } | |||
| CARLA_LEAK_DETECTOR(CarlaString) | |||
| CARLA_PREVENT_HEAP_ALLOCATION | |||
| }; | |||
| static inline | |||
| CarlaString operator+(const char* const strBufBefore, const CarlaString& strAfter) | |||
| { | |||
| const char* const strBufAfter = (const char*)strAfter; | |||
| const size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + std::strlen(strBufAfter) + 1; | |||
| char newBuf[newBufSize]; | |||
| std::strcpy(newBuf, strBufBefore); | |||
| std::strcat(newBuf, strBufAfter); | |||
| return CarlaString(newBuf); | |||
| } | |||
| // ------------------------------------------------- | |||
| #endif // __CARLA_UTILS_HPP__ | |||