Browse Source

Add new files

tags/1.9.4
falkTX 11 years ago
parent
commit
7224c92058
4 changed files with 1170 additions and 0 deletions
  1. +139
    -0
      source/modules/distrho/extra/d_leakdetector.hpp
  2. +221
    -0
      source/modules/distrho/extra/d_mutex.hpp
  3. +746
    -0
      source/modules/distrho/extra/d_string.hpp
  4. +64
    -0
      source/modules/distrho/src/DistrhoPluginChecks.h

+ 139
- 0
source/modules/distrho/extra/d_leakdetector.hpp View File

@@ -0,0 +1,139 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com>
*
* Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef DISTRHO_LEAK_DETECTOR_HPP_INCLUDED
#define DISTRHO_LEAK_DETECTOR_HPP_INCLUDED

#include "../DistrhoUtils.hpp"

// -----------------------------------------------------------------------
// The following code was based from juce-core LeakDetector class
// Copyright (C) 2013 Raw Material Software Ltd.

/** A good old-fashioned C macro concatenation helper.
This combines two items (which may themselves be macros) into a single string,
avoiding the pitfalls of the ## macro operator.
*/
#define DISTRHO_JOIN_MACRO_HELPER(a, b) a ## b
#define DISTRHO_JOIN_MACRO(item1, item2) DISTRHO_JOIN_MACRO_HELPER(item1, item2)

/** This macro lets you embed a leak-detecting object inside a class.\n
To use it, simply declare a DISTRHO_LEAK_DETECTOR(YourClassName) inside a private section
of the class declaration. E.g.
\code
class MyClass
{
public:
MyClass();
void blahBlah();

private:
DISTRHO_LEAK_DETECTOR(MyClass)
};
\endcode
*/
#define DISTRHO_LEAK_DETECTOR(ClassName) \
friend class ::DistrhoLeakedObjectDetector<ClassName>; \
static const char* getLeakedObjectClassName() noexcept { return #ClassName; } \
::DistrhoLeakedObjectDetector<ClassName> DISTRHO_JOIN_MACRO(leakDetector, __LINE__);

#define DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ClassName) \
DISTRHO_DECLARE_NON_COPY_CLASS(ClassName) \
DISTRHO_LEAK_DETECTOR(ClassName)

//==============================================================================
/**
Embedding an instance of this class inside another class can be used as a low-overhead
way of detecting leaked instances.

This class keeps an internal static count of the number of instances that are
active, so that when the app is shutdown and the static destructors are called,
it can check whether there are any left-over instances that may have been leaked.

To use it, use the DISTRHO_LEAK_DETECTOR macro as a simple way to put one in your
class declaration.
*/
template <class OwnerClass>
class DistrhoLeakedObjectDetector
{
public:
//==============================================================================
DistrhoLeakedObjectDetector() noexcept { ++(getCounter().numObjects); }
DistrhoLeakedObjectDetector(const DistrhoLeakedObjectDetector&) noexcept { ++(getCounter().numObjects); }

~DistrhoLeakedObjectDetector() noexcept
{
if (--(getCounter().numObjects) < 0)
{
/** If you hit this, then you've managed to delete more instances of this class than you've
created.. That indicates that you're deleting some dangling pointers.

Note that although this assertion will have been triggered during a destructor, it might
not be this particular deletion that's at fault - the incorrect one may have happened
at an earlier point in the program, and simply not been detected until now.

Most errors like this are caused by using old-fashioned, non-RAII techniques for
your object management. Tut, tut. Always, always use ScopedPointers, OwnedArrays,
ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs!
*/
d_stderr2("*** Dangling pointer deletion! Class: '%s', Count: %i", getLeakedObjectClassName(), getCounter().numObjects);
}
}

private:
//==============================================================================
class LeakCounter
{
public:
LeakCounter() noexcept
{
numObjects = 0;
}

~LeakCounter() noexcept
{
if (numObjects > 0)
{
/** If you hit this, then you've leaked one or more objects of the type specified by
the 'OwnerClass' template parameter - the name should have been printed by the line above.

If you're leaking, it's probably because you're using old-fashioned, non-RAII techniques for
your object management. Tut, tut. Always, always use ScopedPointers, OwnedArrays,
ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs!
*/
d_stderr2("*** Leaked objects detected: %i instance(s) of class '%s'", numObjects, getLeakedObjectClassName());
}
}

// this should be an atomic...
volatile int numObjects;
};

static const char* getLeakedObjectClassName() noexcept
{
return OwnerClass::getLeakedObjectClassName();
}

static LeakCounter& getCounter() noexcept
{
static LeakCounter counter;
return counter;
}
};

// -----------------------------------------------------------------------

#endif // DISTRHO_LEAK_DETECTOR_HPP_INCLUDED

+ 221
- 0
source/modules/distrho/extra/d_mutex.hpp View File

@@ -0,0 +1,221 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com>
*
* Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef DISTRHO_MUTEX_HPP_INCLUDED
#define DISTRHO_MUTEX_HPP_INCLUDED

#include "../DistrhoUtils.hpp"

#include <pthread.h>

// -----------------------------------------------------------------------
// d_mutex class

class d_mutex
{
public:
/*
* Constructor.
*/
d_mutex() noexcept
{
pthread_mutex_init(&fMutex, nullptr);
}

/*
* Destructor.
*/
~d_mutex() noexcept
{
pthread_mutex_destroy(&fMutex);
}

/*
* Lock the mutex.
*/
void lock() const noexcept
{
pthread_mutex_lock(&fMutex);
}

/*
* Try to lock the mutex.
* Returns true if successful.
*/
bool tryLock() const noexcept
{
return (pthread_mutex_trylock(&fMutex) == 0);
}

/*
* Unlock the mutex, optionally resetting the tryLock check.
*/
void unlock() const noexcept
{
pthread_mutex_unlock(&fMutex);
}

private:
mutable pthread_mutex_t fMutex;

DISTRHO_PREVENT_HEAP_ALLOCATION
DISTRHO_DECLARE_NON_COPY_CLASS(d_mutex)
};

// -----------------------------------------------------------------------
// d_rmutex class

class d_rmutex
{
public:
/*
* Constructor.
*/
d_rmutex() noexcept
{
#ifdef DISTRHO_OS_WIN
InitializeCriticalSection(&fSection);
#else
pthread_mutexattr_t atts;
pthread_mutexattr_init(&atts);
pthread_mutexattr_settype(&atts, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&fMutex, &atts);
pthread_mutexattr_destroy(&atts);
#endif
}

/*
* Destructor.
*/
~d_rmutex() noexcept
{
#ifdef DISTRHO_OS_WIN
DeleteCriticalSection(&fSection);
#else
pthread_mutex_destroy(&fMutex);
#endif
}

/*
* Lock the mutex.
*/
void lock() const noexcept
{
#ifdef DISTRHO_OS_WIN
EnterCriticalSection(&fSection);
#else
pthread_mutex_lock(&fMutex);
#endif
}

/*
* Try to lock the mutex.
* Returns true if successful.
*/
bool tryLock() const noexcept
{
#ifdef DISTRHO_OS_WIN
return (TryEnterCriticalSection(&fSection) != FALSE);
#else
return (pthread_mutex_trylock(&fMutex) == 0);
#endif
}

/*
* Unlock the mutex.
*/
void unlock() const noexcept
{
#ifdef DISTRHO_OS_WIN
LeaveCriticalSection(&fSection);
#else
pthread_mutex_unlock(&fMutex);
#endif
}

private:
#ifdef DISTRHO_OS_WIN
mutable CRITICAL_SECTION fSection;
#else
mutable pthread_mutex_t fMutex;
#endif

DISTRHO_PREVENT_HEAP_ALLOCATION
DISTRHO_DECLARE_NON_COPY_CLASS(d_rmutex)
};

// -----------------------------------------------------------------------
// Helper class to lock&unlock a mutex during a function scope.

template <class Mutex>
class d_scopeLocker
{
public:
d_scopeLocker(const Mutex& mutex) noexcept
: fMutex(mutex)
{
fMutex.lock();
}

~d_scopeLocker() noexcept
{
fMutex.unlock();
}

private:
const Mutex& fMutex;

DISTRHO_PREVENT_HEAP_ALLOCATION
DISTRHO_DECLARE_NON_COPY_CLASS(d_scopeLocker)
};

// -----------------------------------------------------------------------
// Helper class to unlock&lock a mutex during a function scope.

template <class Mutex>
class d_scopeUnlocker
{
public:
d_scopeUnlocker(const Mutex& mutex) noexcept
: fMutex(mutex)
{
fMutex.unlock();
}

~d_scopeUnlocker() noexcept
{
fMutex.lock();
}

private:
const Mutex& fMutex;

DISTRHO_PREVENT_HEAP_ALLOCATION
DISTRHO_DECLARE_NON_COPY_CLASS(d_scopeUnlocker)
};

// -----------------------------------------------------------------------
// Define types

typedef d_scopeLocker<d_mutex> d_mutexLocker;
typedef d_scopeLocker<d_rmutex> d_rmutexLocker;

typedef d_scopeUnlocker<d_mutex> d_mutexUnlocker;
typedef d_scopeUnlocker<d_rmutex> d_rmutexUnlocker;

// -----------------------------------------------------------------------

#endif // DISTRHO_MUTEX_HPP_INCLUDED

+ 746
- 0
source/modules/distrho/extra/d_string.hpp View File

@@ -0,0 +1,746 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com>
*
* Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef DISTRHO_STRING_HPP_INCLUDED
#define DISTRHO_STRING_HPP_INCLUDED

#include "d_leakdetector.hpp"

// -----------------------------------------------------------------------
// d_string class

class d_string
{
public:
// -------------------------------------------------------------------
// constructors (no explicit conversions allowed)

/*
* Empty string.
*/
explicit d_string() noexcept
{
_init();
}

/*
* Simple character.
*/
explicit d_string(const char c) noexcept
{
char ch[2];
ch[0] = c;
ch[1] = '\0';

_init();
_dup(ch);
}

/*
* Simple char string.
*/
explicit d_string(char* const strBuf) noexcept
{
_init();
_dup(strBuf);
}

/*
* Simple const char string.
*/
explicit d_string(const char* const strBuf) noexcept
{
_init();
_dup(strBuf);
}

/*
* Integer.
*/
explicit d_string(const int value) noexcept
{
char strBuf[0xff+1];
std::snprintf(strBuf, 0xff, "%d", value);
strBuf[0xff] = '\0';

_init();
_dup(strBuf);
}

/*
* Unsigned integer, possibly in hexadecimal.
*/
explicit d_string(const unsigned int value, const bool hexadecimal = false) noexcept
{
char strBuf[0xff+1];
std::snprintf(strBuf, 0xff, hexadecimal ? "0x%x" : "%u", value);
strBuf[0xff] = '\0';

_init();
_dup(strBuf);
}

/*
* Long integer.
*/
explicit d_string(const long value) noexcept
{
char strBuf[0xff+1];
std::snprintf(strBuf, 0xff, "%ld", value);
strBuf[0xff] = '\0';

_init();
_dup(strBuf);
}

/*
* Long unsigned integer, possibly hexadecimal.
*/
explicit d_string(const unsigned long value, const bool hexadecimal = false) noexcept
{
char strBuf[0xff+1];
std::snprintf(strBuf, 0xff, hexadecimal ? "0x%lx" : "%lu", value);
strBuf[0xff] = '\0';

_init();
_dup(strBuf);
}

/*
* Long long integer.
*/
explicit d_string(const long long value) noexcept
{
char strBuf[0xff+1];
std::snprintf(strBuf, 0xff, "%lld", value);
strBuf[0xff] = '\0';

_init();
_dup(strBuf);
}

/*
* Long long unsigned integer, possibly hexadecimal.
*/
explicit d_string(const unsigned long long value, const bool hexadecimal = false) noexcept
{
char strBuf[0xff+1];
std::snprintf(strBuf, 0xff, hexadecimal ? "0x%llx" : "%llu", value);
strBuf[0xff] = '\0';

_init();
_dup(strBuf);
}

/*
* Single-precision floating point number.
*/
explicit d_string(const float value) noexcept
{
char strBuf[0xff+1];
std::snprintf(strBuf, 0xff, "%f", value);
strBuf[0xff] = '\0';

_init();
_dup(strBuf);
}

/*
* Double-precision floating point number.
*/
explicit d_string(const double value) noexcept
{
char strBuf[0xff+1];
std::snprintf(strBuf, 0xff, "%g", value);
strBuf[0xff] = '\0';

_init();
_dup(strBuf);
}

// -------------------------------------------------------------------
// non-explicit constructor

/*
* Create string from another string.
*/
d_string(const d_string& str) noexcept
{
_init();
_dup(str.fBuffer);
}

// -------------------------------------------------------------------
// destructor

/*
* Destructor.
*/
~d_string() noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(fBuffer != nullptr,);

if (fBuffer == _null())
return;

std::free(fBuffer);

fBuffer = nullptr;
fBufferLen = 0;
}

// -------------------------------------------------------------------
// public methods

/*
* Get length of the string.
*/
size_t length() const noexcept
{
return fBufferLen;
}

/*
* Check if the string is empty.
*/
bool isEmpty() const noexcept
{
return (fBufferLen == 0);
}

/*
* Check if the string is not empty.
*/
bool isNotEmpty() const noexcept
{
return (fBufferLen != 0);
}

/*
* Check if the string contains another string, optionally ignoring case.
*/
bool contains(const char* const strBuf, const bool ignoreCase = false) const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(strBuf != nullptr, false);

if (ignoreCase)
{
#ifdef __USE_GNU
return (strcasestr(fBuffer, strBuf) != nullptr);
#else
d_string tmp1(fBuffer), tmp2(strBuf);

// memory allocation failed or empty string(s)
if (tmp1.fBuffer == _null() || tmp2.fBuffer == _null())
return false;

tmp1.toLower();
tmp2.toLower();
return (std::strstr(tmp1, tmp2) != nullptr);
#endif
}

return (std::strstr(fBuffer, strBuf) != nullptr);
}

/*
* Check if character at 'pos' is a digit.
*/
bool isDigit(const size_t pos) const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(pos < fBufferLen, false);

return (fBuffer[pos] >= '0' && fBuffer[pos] <= '9');
}

/*
* Check if the string starts with the character 'c'.
*/
bool startsWith(const char c) const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(c != '\0', false);

return (fBufferLen > 0 && fBuffer[0] == c);
}

/*
* Check if the string starts with the string 'prefix'.
*/
bool startsWith(const char* const prefix) const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(prefix != nullptr, false);

const size_t prefixLen(std::strlen(prefix));

if (fBufferLen < prefixLen)
return false;

return (std::strncmp(fBuffer, prefix, prefixLen) == 0);
}

/*
* Check if the string ends with the character 'c'.
*/
bool endsWith(const char c) const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(c != '\0', false);

return (fBufferLen > 0 && fBuffer[fBufferLen-1] == c);
}

/*
* Check if the string ends with the string 'suffix'.
*/
bool endsWith(const char* const suffix) const noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(suffix != nullptr, false);

const size_t suffixLen(std::strlen(suffix));

if (fBufferLen < suffixLen)
return false;

return (std::strncmp(fBuffer + (fBufferLen-suffixLen), suffix, suffixLen) == 0);
}

/*
* Find the first occurrence of character 'c' in the string.
* Returns "length()" if the character is not found.
*/
size_t find(const char c, bool* const found = nullptr) const noexcept
{
if (fBufferLen == 0 || c == '\0')
{
if (found != nullptr)
*found = false;
return fBufferLen;
}

for (size_t i=0; i < fBufferLen; ++i)
{
if (fBuffer[i] == c)
{
if (found != nullptr)
*found = true;
return i;
}
}

if (found != nullptr)
*found = false;
return fBufferLen;
}

/*
* Find the first occurrence of string 'strBuf' in the string.
* Returns "length()" if the string is not found.
*/
size_t find(const char* const strBuf, bool* const found = nullptr) const noexcept
{
if (fBufferLen == 0 || strBuf == nullptr || strBuf[0] == '\0')
{
if (found != nullptr)
*found = false;
return fBufferLen;
}

if (char* const subStrBuf = std::strstr(fBuffer, strBuf))
{
const ssize_t ret(subStrBuf - fBuffer);

if (ret < 0)
{
// should never happen!
d_safe_assert("ret >= 0", __FILE__, __LINE__);

if (found != nullptr)
*found = false;
return fBufferLen;
}

if (found != nullptr)
*found = true;
return static_cast<size_t>(ret);
}

if (found != nullptr)
*found = false;
return fBufferLen;
}

/*
* Find the last occurrence of character 'c' in the string.
* Returns "length()" if the character is not found.
*/
size_t rfind(const char c, bool* const found = nullptr) const noexcept
{
if (fBufferLen == 0 || c == '\0')
{
if (found != nullptr)
*found = false;
return fBufferLen;
}

for (size_t i=fBufferLen; i > 0; --i)
{
if (fBuffer[i-1] == c)
{
if (found != nullptr)
*found = true;
return i-1;
}
}

if (found != nullptr)
*found = false;
return fBufferLen;
}

/*
* Find the last occurrence of string 'strBuf' in the string.
* Returns "length()" if the string is not found.
*/
size_t rfind(const char* const strBuf, bool* const found = nullptr) const noexcept
{
if (found != nullptr)
*found = false;

if (fBufferLen == 0 || strBuf == nullptr || strBuf[0] == '\0')
return fBufferLen;

const size_t strBufLen(std::strlen(strBuf));

size_t ret = fBufferLen;
const char* tmpBuf = fBuffer;

for (size_t i=0; i < fBufferLen; ++i)
{
if (std::strstr(tmpBuf+1, strBuf) == nullptr && std::strncmp(tmpBuf, strBuf, strBufLen) == 0)
{
if (found != nullptr)
*found = true;
break;
}

--ret;
++tmpBuf;
}

return fBufferLen-ret;
}

/*
* Clear the string.
*/
void clear() noexcept
{
truncate(0);
}

/*
* Replace all occurrences of character 'before' with character 'after'.
*/
void replace(const char before, const char after) noexcept
{
DISTRHO_SAFE_ASSERT_RETURN(before != '\0' && after != '\0',);

for (size_t i=0; i < fBufferLen; ++i)
{
if (fBuffer[i] == before)
fBuffer[i] = after;
}
}

/*
* Truncate the string to size 'n'.
*/
void truncate(const size_t n) noexcept
{
if (n >= fBufferLen)
return;

for (size_t i=n; i < fBufferLen; ++i)
fBuffer[i] = '\0';

fBufferLen = n;
}

/*
* Convert all non-basic characters to '_'.
*/
void toBasic() noexcept
{
for (size_t i=0; i < fBufferLen; ++i)
{
if (fBuffer[i] >= '0' && fBuffer[i] <= '9')
continue;
if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
continue;
if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
continue;
if (fBuffer[i] == '_')
continue;

fBuffer[i] = '_';
}
}

/*
* Convert to all ascii characters to lowercase.
*/
void toLower() noexcept
{
static const char kCharDiff('a' - 'A');

for (size_t i=0; i < fBufferLen; ++i)
{
if (fBuffer[i] >= 'A' && fBuffer[i] <= 'Z')
fBuffer[i] = static_cast<char>(fBuffer[i] + kCharDiff);
}
}

/*
* Convert to all ascii characters to uppercase.
*/
void toUpper() noexcept
{
static const char kCharDiff('a' - 'A');

for (size_t i=0; i < fBufferLen; ++i)
{
if (fBuffer[i] >= 'a' && fBuffer[i] <= 'z')
fBuffer[i] = static_cast<char>(fBuffer[i] - kCharDiff);
}
}

/*
* Direct access to the string buffer (read-only).
*/
const char* buffer() const noexcept
{
return fBuffer;
}

// -------------------------------------------------------------------
// public operators

operator const char*() const noexcept
{
return fBuffer;
}

char operator[](const size_t pos) const noexcept
{
if (pos < fBufferLen)
return fBuffer[pos];

d_safe_assert("pos < fBufferLen", __FILE__, __LINE__);

static char fallback;
fallback = '\0';
return fallback;
}

char& operator[](const size_t pos) noexcept
{
if (pos < fBufferLen)
return fBuffer[pos];

d_safe_assert("pos < fBufferLen", __FILE__, __LINE__);

static char fallback;
fallback = '\0';
return fallback;
}

bool operator==(const char* const strBuf) const noexcept
{
return (strBuf != nullptr && std::strcmp(fBuffer, strBuf) == 0);
}

bool operator==(const d_string& str) const noexcept
{
return operator==(str.fBuffer);
}

bool operator!=(const char* const strBuf) const noexcept
{
return !operator==(strBuf);
}

bool operator!=(const d_string& str) const noexcept
{
return !operator==(str.fBuffer);
}

d_string& operator=(const char* const strBuf) noexcept
{
_dup(strBuf);

return *this;
}

d_string& operator=(const d_string& str) noexcept
{
_dup(str.fBuffer);

return *this;
}

d_string& operator+=(const char* const strBuf) noexcept
{
if (strBuf == nullptr)
return *this;

const size_t newBufSize = fBufferLen + std::strlen(strBuf) + 1;
char newBuf[newBufSize];

std::strcpy(newBuf, fBuffer);
std::strcat(newBuf, strBuf);

_dup(newBuf, newBufSize-1);

return *this;
}

d_string& operator+=(const d_string& str) noexcept
{
return operator+=(str.fBuffer);
}

d_string operator+(const char* const strBuf) noexcept
{
const size_t newBufSize = fBufferLen + ((strBuf != nullptr) ? std::strlen(strBuf) : 0) + 1;
char newBuf[newBufSize];

std::strcpy(newBuf, fBuffer);

if (strBuf != nullptr)
std::strcat(newBuf, strBuf);

return d_string(newBuf);
}

d_string operator+(const d_string& str) noexcept
{
return operator+(str.fBuffer);
}

// -------------------------------------------------------------------

private:
char* fBuffer; // the actual string buffer
size_t fBufferLen; // string length

/*
* Static null string.
* Prevents allocation for new and/or empty strings.
*/
static char* _null() noexcept
{
static char sNull = '\0';
return &sNull;
}

/*
* Shared init function.
* Called on all constructors.
*/
void _init() noexcept
{
fBuffer = _null();
fBufferLen = 0;
}

/*
* Helper function.
* Called whenever the string needs to be allocated.
*
* Notes:
* - Allocates string only if 'strBuf' is not null and new string contents are different
* - If 'strBuf' is null, 'size' must be 0
*/
void _dup(const char* const strBuf, const size_t size = 0) noexcept
{
if (strBuf != nullptr)
{
// don't recreate string if contents match
if (std::strcmp(fBuffer, strBuf) == 0)
return;

if (fBuffer != _null())
std::free(fBuffer);

fBufferLen = (size > 0) ? size : std::strlen(strBuf);
fBuffer = (char*)std::malloc(fBufferLen+1);

if (fBuffer == nullptr)
return _init();

std::strcpy(fBuffer, strBuf);

fBuffer[fBufferLen] = '\0';
}
else
{
DISTRHO_SAFE_ASSERT(size == 0);

// don't recreate null string
if (fBuffer == _null())
return;

DISTRHO_SAFE_ASSERT(fBuffer != nullptr);
std::free(fBuffer);

_init();
}
}

DISTRHO_LEAK_DETECTOR(d_string)
DISTRHO_PREVENT_HEAP_ALLOCATION
};

// -----------------------------------------------------------------------

static inline
d_string operator+(const d_string& strBefore, const char* const strBufAfter) noexcept
{
const char* const strBufBefore = strBefore.buffer();
const size_t newBufSize = strBefore.length() + ((strBufAfter != nullptr) ? std::strlen(strBufAfter) : 0) + 1;
char newBuf[newBufSize];

std::strcpy(newBuf, strBufBefore);
std::strcat(newBuf, strBufAfter);

return d_string(newBuf);
}

static inline
d_string operator+(const char* const strBufBefore, const d_string& strAfter) noexcept
{
const char* const strBufAfter = strAfter.buffer();
const size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1;
char newBuf[newBufSize];

std::strcpy(newBuf, strBufBefore);
std::strcat(newBuf, strBufAfter);

return d_string(newBuf);
}

// -----------------------------------------------------------------------

#endif // DISTRHO_STRING_HPP_INCLUDED

+ 64
- 0
source/modules/distrho/src/DistrhoPluginChecks.h View File

@@ -0,0 +1,64 @@
/*
* DISTRHO Plugin Framework (DPF)
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com>
*
* Permission to use, copy, modify, and/or distribute this software for any purpose with
* or without fee is hereby granted, provided that the above copyright notice and this
* permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#ifndef DISTRHO_PLUGIN_CHECKS_H_INCLUDED
#define DISTRHO_PLUGIN_CHECKS_H_INCLUDED

#include "DistrhoPluginInfo.h"

#ifndef DISTRHO_PLUGIN_NAME
# error DISTRHO_PLUGIN_NAME undefined!
#endif

#ifndef DISTRHO_PLUGIN_HAS_UI
# error DISTRHO_PLUGIN_HAS_UI undefined!
#endif

#ifndef DISTRHO_PLUGIN_IS_SYNTH
# error DISTRHO_PLUGIN_IS_SYNTH undefined!
#endif

#ifndef DISTRHO_PLUGIN_NUM_INPUTS
# error DISTRHO_PLUGIN_NUM_INPUTS undefined!
#endif

#ifndef DISTRHO_PLUGIN_NUM_OUTPUTS
# error DISTRHO_PLUGIN_NUM_OUTPUTS undefined!
#endif

#ifndef DISTRHO_PLUGIN_WANT_LATENCY
# error DISTRHO_PLUGIN_WANT_LATENCY undefined!
#endif

#ifndef DISTRHO_PLUGIN_WANT_PROGRAMS
# error DISTRHO_PLUGIN_WANT_PROGRAMS undefined!
#endif

#ifndef DISTRHO_PLUGIN_WANT_STATE
# error DISTRHO_PLUGIN_WANT_STATE undefined!
#endif

#ifndef DISTRHO_PLUGIN_WANT_TIMEPOS
# error DISTRHO_PLUGIN_WANT_TIMEPOS undefined!
#endif

#ifndef DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
# define DISTRHO_PLUGIN_WANT_DIRECT_ACCESS 0
#endif

#define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#UI"

#endif // DISTRHO_PLUGIN_CHECKS_H_INCLUDED

Loading…
Cancel
Save