Browse Source

Split carla classes from utils; add print test

tags/1.9.4
falkTX 12 years ago
parent
commit
2aef20ecf4
14 changed files with 951 additions and 770 deletions
  1. +0
    -4
      source/Makefile.mk
  2. +3
    -0
      source/backend/engine/carla_engine.pro
  3. +41
    -18
      source/includes/carla_defines.hpp
  4. +1
    -3
      source/tests/CarlaString.cpp
  5. +6
    -4
      source/tests/Makefile
  6. +27
    -0
      source/tests/Print.cpp
  7. +2
    -2
      source/tests/RtList.cpp
  8. +1
    -3
      source/tests/Thread.cpp
  9. +12
    -11
      source/utils/carla_backend_utils.hpp
  10. +5
    -5
      source/utils/carla_juce_utils.hpp
  11. +112
    -0
      source/utils/carla_mutex.hpp
  12. +412
    -0
      source/utils/carla_string.hpp
  13. +253
    -0
      source/utils/carla_thread.hpp
  14. +76
    -720
      source/utils/carla_utils.hpp

+ 0
- 4
source/Makefile.mk View File

@@ -35,10 +35,6 @@ BUILD_C_FLAGS = $(BASE_FLAGS) -std=c99 $(CFLAGS)
BUILD_CXX_FLAGS = $(BASE_FLAGS) -std=c++0x $(CXXFLAGS) BUILD_CXX_FLAGS = $(BASE_FLAGS) -std=c++0x $(CXXFLAGS)
LINK_FLAGS = $(LDFLAGS) 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 # Modify to enable/disable specific features




+ 3
- 0
source/backend/engine/carla_engine.pro View File

@@ -51,6 +51,9 @@ HEADERS += \
HEADERS += \ HEADERS += \
../../includes/carla_defines.hpp \ ../../includes/carla_defines.hpp \
../../includes/carla_midi.h \ ../../includes/carla_midi.h \
../../utils/carla_mutex.hpp \
../../utils/carla_string.hpp \
../../utils/carla_thread.hpp \
../../utils/carla_utils.hpp \ ../../utils/carla_utils.hpp \
../../utils/carla_backend_utils.hpp \ ../../utils/carla_backend_utils.hpp \
../../utils/carla_juce_utils.hpp \ ../../utils/carla_juce_utils.hpp \


+ 41
- 18
source/includes/carla_defines.hpp View File

@@ -18,15 +18,38 @@
#ifndef __CARLA_DEFINES_HPP__ #ifndef __CARLA_DEFINES_HPP__
#define __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 #endif


// Common includes // Common includes
#ifdef Q_OS_WIN
#ifdef CARLA_OS_WIN
# include <winsock2.h> # include <winsock2.h>
# include <windows.h> # include <windows.h>
#else #else
@@ -36,13 +59,13 @@
# endif # endif
#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_INT64 "%I64i"
# define P_INTPTR "%I64i" # define P_INTPTR "%I64i"
# define P_UINTPTR "%I64x" # define P_UINTPTR "%I64x"
# define P_SIZE "%I64u" # define P_SIZE "%I64u"
#elif defined(Q_OS_WIN32)
#elif defined(CARLA_OS_WIN32)
# define P_INT64 "%I64i" # define P_INT64 "%I64i"
# define P_INTPTR "%i" # define P_INTPTR "%i"
# define P_UINTPTR "%x" # define P_UINTPTR "%x"
@@ -60,14 +83,14 @@
#endif #endif


// Define BINARY_NATIVE // Define BINARY_NATIVE
#if defined(Q_OS_HAIKU) || defined(Q_OS_UNIX)
#if defined(CARLA_OS_HAIKU) || defined(CARLA_OS_UNIX)
# ifdef __LP64__ # ifdef __LP64__
# define BINARY_NATIVE BINARY_POSIX64 # define BINARY_NATIVE BINARY_POSIX64
# else # else
# define BINARY_NATIVE BINARY_POSIX32 # define BINARY_NATIVE BINARY_POSIX32
# endif # endif
#elif defined(Q_OS_WIN)
# ifdef Q_OS_WIN64
#elif defined(CARLA_OS_WIN)
# ifdef CARLA_OS_WIN64
# define BINARY_NATIVE BINARY_WIN64 # define BINARY_NATIVE BINARY_WIN64
# else # else
# define BINARY_NATIVE BINARY_WIN32 # define BINARY_NATIVE BINARY_WIN32
@@ -79,20 +102,20 @@


// Define CARLA_ASSERT* // Define CARLA_ASSERT*
#ifdef NDEBUG #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 #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 #endif


// Define CARLA_EXPORT // Define CARLA_EXPORT
#ifdef BUILD_BRIDGE #ifdef BUILD_BRIDGE
# define CARLA_EXPORT extern "C" # define CARLA_EXPORT extern "C"
#else #else
# if defined(Q_OS_WIN) && ! defined(__WINE__)
# if defined(CARLA_OS_WIN) && ! defined(__WINE__)
# define CARLA_EXPORT extern "C" __declspec (dllexport) # define CARLA_EXPORT extern "C" __declspec (dllexport)
# else # else
# define CARLA_EXPORT extern "C" __attribute__ ((visibility("default"))) # define CARLA_EXPORT extern "C" __attribute__ ((visibility("default")))


+ 1
- 3
source/tests/CarlaString.cpp View File

@@ -15,9 +15,7 @@
* For a full copy of the GNU General Public License see the GPL.txt file * 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() int main()
{ {


+ 6
- 4
source/tests/Makefile View File

@@ -10,10 +10,8 @@ include ../Makefile.mk


BUILD_CXX_FLAGS += -I../backend -I../includes -I../utils BUILD_CXX_FLAGS += -I../backend -I../includes -I../utils
# BUILD_CXX_FLAGS += -I/opt/mingw32/include # 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 all: $(TARGETS) RUN


@@ -23,17 +21,21 @@ CarlaString: CarlaString.cpp
$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) -o $@ $(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) -o $@


RtList: RtList.cpp ../libs/rtmempool.a 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 Thread: Thread.cpp
$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) -pthread -lpthread -o $@ $(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) -pthread -lpthread -o $@


Print_: Print.cpp
$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) -o Print # $@

GL_: GL.cpp 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) -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 # $@ $(CXX) $^ $(BUILD_CXX_FLAGS) -I../backend/engine/plugin -I../libs/distrho-plugin-toolkit $(LINK_FLAGS) -lGL -lGLU -o GL # $@


RUN: $(TARGETS) RUN: $(TARGETS)
# ./CarlaString && ./RtList && ./Thread # ./CarlaString && ./RtList && ./Thread
./Print
# ./GL # ./GL


# -------------------------------------------------------------- # --------------------------------------------------------------


+ 27
- 0
source/tests/Print.cpp View File

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

+ 2
- 2
source/tests/RtList.cpp View File

@@ -15,10 +15,10 @@
* For a full copy of the GNU General Public License see the GPL.txt file * For a full copy of the GNU General Public License see the GPL.txt file
*/ */


#include "carla_utils.hpp"
#include "rt_list.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 MIN_RT_EVENTS = 152;
const unsigned short MAX_RT_EVENTS = 512; const unsigned short MAX_RT_EVENTS = 512;


+ 1
- 3
source/tests/Thread.cpp View File

@@ -15,9 +15,7 @@
* For a full copy of the GNU General Public License see the GPL.txt file * 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 class MyThread : public CarlaThread
{ {


+ 12
- 11
source/utils/carla_backend_utils.hpp View File

@@ -44,7 +44,7 @@ const char* BinaryType2Str(const BinaryType& type)
return "BINARY_OTHER"; return "BINARY_OTHER";
} }


qWarning("CarlaBackend::BinaryType2Str(%i) - invalid type", type);
carla_stderr("CarlaBackend::BinaryType2Str(%i) - invalid type", type);
return nullptr; return nullptr;
} }


@@ -73,7 +73,7 @@ const char* PluginType2Str(const PluginType& type)
return "PLUGIN_SFZ"; return "PLUGIN_SFZ";
} }


qWarning("CarlaBackend::PluginType2Str(%i) - invalid type", type);
carla_stderr("CarlaBackend::PluginType2Str(%i) - invalid type", type);
return nullptr; return nullptr;
} }


@@ -102,7 +102,7 @@ const char* PluginCategory2Str(const PluginCategory& category)
return "PLUGIN_CATEGORY_OTHER"; return "PLUGIN_CATEGORY_OTHER";
} }


qWarning("CarlaBackend::PluginCategory2Str(%i) - invalid category", category);
carla_stderr("CarlaBackend::PluginCategory2Str(%i) - invalid category", category);
return nullptr; return nullptr;
} }


@@ -129,7 +129,7 @@ const char* ParameterType2Str(const ParameterType& type)
#endif #endif
} }


qWarning("CarlaBackend::ParameterType2Str(%i) - invalid type", type);
carla_stderr("CarlaBackend::ParameterType2Str(%i) - invalid type", type);
return nullptr; return nullptr;
} }


@@ -156,7 +156,7 @@ const char* InternalParametersIndex2Str(const InternalParametersIndex& index)
return "PARAMETER_MAX"; return "PARAMETER_MAX";
} }


qWarning("CarlaBackend::InternalParametersIndex2Str(%i) - invalid index", index);
carla_stderr("CarlaBackend::InternalParametersIndex2Str(%i) - invalid index", index);
return nullptr; return nullptr;
} }


@@ -225,7 +225,7 @@ const char* OptionsType2Str(const OptionsType& type)
#endif #endif
} }


qWarning("CarlaBackend::OptionsType2Str(%i) - invalid type", type);
carla_stderr("CarlaBackend::OptionsType2Str(%i) - invalid type", type);
return nullptr; return nullptr;
} }


@@ -282,7 +282,7 @@ const char* CallbackType2Str(const CallbackType& type)
return "CALLBACK_QUIT"; return "CALLBACK_QUIT";
} }


qWarning("CarlaBackend::CallbackType2Str(%i) - invalid type", type);
carla_stderr("CarlaBackend::CallbackType2Str(%i) - invalid type", type);
return nullptr; return nullptr;
} }


@@ -303,7 +303,7 @@ const char* ProcessMode2Str(const ProcessMode& mode)
return "PROCESS_MODE_BRIDGE"; return "PROCESS_MODE_BRIDGE";
} }


qWarning("CarlaBackend::ProcessModeType2Str(%i) - invalid type", mode);
carla_stderr("CarlaBackend::ProcessModeType2Str(%i) - invalid type", mode);
return nullptr; return nullptr;
} }


@@ -312,7 +312,7 @@ const char* ProcessMode2Str(const ProcessMode& mode)
static inline static inline
uintptr_t getAddressFromPointer(void* ptr) uintptr_t getAddressFromPointer(void* ptr)
{ {
qDebug("CarlaBackend::getAddressFromPointer(%p)", ptr);
carla_debug("CarlaBackend::getAddressFromPointer(%p)", ptr);
CARLA_ASSERT(ptr != nullptr); CARLA_ASSERT(ptr != nullptr);


uintptr_t* addr = (uintptr_t*)&ptr; uintptr_t* addr = (uintptr_t*)&ptr;
@@ -333,7 +333,7 @@ void* getPointerFromAddress(uintptr_t& addr)
static inline static inline
const char* getPluginTypeString(const PluginType& type) const char* getPluginTypeString(const PluginType& type)
{ {
qDebug("CarlaBackend::getPluginTypeString(%s)", PluginType2Str(type));
carla_debug("CarlaBackend::getPluginTypeString(%s)", PluginType2Str(type));


switch (type) switch (type)
{ {
@@ -357,6 +357,7 @@ const char* getPluginTypeString(const PluginType& type)
return "SFZ"; return "SFZ";
} }


carla_stderr("CarlaBackend::getPluginTypeString(%i) - invalid type", type);
return "NONE"; return "NONE";
} }


@@ -365,7 +366,7 @@ const char* getPluginTypeString(const PluginType& type)
static inline static inline
PluginCategory getPluginCategoryFromName(const char* const name) PluginCategory getPluginCategoryFromName(const char* const name)
{ {
qDebug("CarlaBackend::getPluginCategoryFromName(\"%s\")", name);
carla_debug("CarlaBackend::getPluginCategoryFromName(\"%s\")", name);
CARLA_ASSERT(name); CARLA_ASSERT(name);


if (! name) if (! name)


+ 5
- 5
source/utils/carla_juce_utils.hpp View File

@@ -19,9 +19,9 @@
#ifndef __CARLA_JUCE_UTILS_HPP__ #ifndef __CARLA_JUCE_UTILS_HPP__
#define __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) \ #define CARLA_DECLARE_NON_COPYABLE(className) \
className (const className&);\ className (const className&);\
@@ -82,7 +82,7 @@ public:
{ {
if (--(getCounter().numObjects) < 0) 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 /** 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. created.. That indicates that you're deleting some dangling pointers.
@@ -113,7 +113,7 @@ private:
{ {
if (numObjects > 0) 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 /** 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. the 'OwnerClass' template parameter - the name should have been printed by the line above.
@@ -313,7 +313,7 @@ private:
return this; 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 /* 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). would let you do so by implicitly casting the source to its raw object pointer).




+ 112
- 0
source/utils/carla_mutex.hpp View File

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

+ 412
- 0
source/utils/carla_string.hpp View File

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

+ 253
- 0
source/utils/carla_thread.hpp View File

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

+ 76
- 720
source/utils/carla_utils.hpp View File

@@ -18,47 +18,101 @@
#ifndef __CARLA_UTILS_HPP__ #ifndef __CARLA_UTILS_HPP__
#define __CARLA_UTILS_HPP__ #define __CARLA_UTILS_HPP__


#include "carla_juce_utils.hpp"
#include "carla_defines.hpp"


#include <cassert>
#include <cstdarg>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring> #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> # include <kernel/OS.h>
#elif defined(Q_OS_LINUX)
#elif defined(CARLA_OS_LINUX)
# include <sys/prctl.h> # include <sys/prctl.h>
# include <linux/prctl.h> # include <linux/prctl.h>
#endif #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* // carla_assert*


static inline static inline
void carla_assert(const char* const assertion, const char* const file, const int line) 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 static inline
void carla_assert_int(const char* const assertion, const char* const file, const int line, const int value) 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 static inline
void carla_assert_int2(const char* const assertion, const char* const file, const int line, const int v1, const int v2) 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); CARLA_ASSERT(secs > 0);


#ifdef Q_OS_WIN
#ifdef CARLA_OS_WIN
Sleep(secs * 1000); Sleep(secs * 1000);
#else #else
sleep(secs); sleep(secs);
@@ -81,7 +135,7 @@ void carla_msleep(const unsigned int msecs)
{ {
CARLA_ASSERT(msecs > 0); CARLA_ASSERT(msecs > 0);


#ifdef Q_OS_WIN
#ifdef CARLA_OS_WIN
Sleep(msecs); Sleep(msecs);
#else #else
usleep(msecs * 1000); usleep(msecs * 1000);
@@ -93,7 +147,7 @@ void carla_usleep(const unsigned int usecs)
{ {
CARLA_ASSERT(usecs > 0); CARLA_ASSERT(usecs > 0);


#ifdef Q_OS_WIN
#ifdef CARLA_OS_WIN
Sleep(usecs / 1000); Sleep(usecs / 1000);
#else #else
usleep(usecs); usleep(usecs);
@@ -109,7 +163,7 @@ void carla_setenv(const char* const key, const char* const value)
CARLA_ASSERT(key != nullptr); CARLA_ASSERT(key != nullptr);
CARLA_ASSERT(value != nullptr); CARLA_ASSERT(value != nullptr);


#ifdef Q_OS_WIN
#ifdef CARLA_OS_WIN
SetEnvironmentVariableA(key, value); SetEnvironmentVariableA(key, value);
#else #else
setenv(key, value, 1); setenv(key, value, 1);
@@ -124,13 +178,13 @@ void carla_setprocname(const char* const name)
{ {
CARLA_ASSERT(name != nullptr); 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) if ((thread_id this_thread = find_thread(nullptr)) != B_NAME_NOT_FOUND)
rename_thread(this_thread, name); rename_thread(this_thread, name);
#elif defined(Q_OS_LINUX)
#elif defined(CARLA_OS_LINUX)
prctl(PR_SET_NAME, name); prctl(PR_SET_NAME, name);
#else #else
qWarning("carla_setprocname(\"%s\") - unsupported on this platform", name);
carla_stderr("carla_setprocname(\"%s\") - unsupported on this platform", name);
#endif #endif
} }


@@ -226,704 +280,6 @@ void carla_zeroStruct(T& structure)
std::memset(&structure, 0, sizeof(T)); 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__ #endif // __CARLA_UTILS_HPP__

Loading…
Cancel
Save