DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

commit 855eb9f77a2112f8aac4ff9fbb15b8c8b2889673
parent 1f2b3045d080401a56df7ecd3f01da26cde381ea
Author: falkTX <falktx@gmail.com>
Date:   Fri, 25 Apr 2014 19:10:57 +0100

More d_string into its own file; Rework base headers

Diffstat:
Mdistrho/DistrhoPlugin.hpp | 6++++++
Mdistrho/DistrhoUtils.hpp | 638+++++++------------------------------------------------------------------------
Adistrho/extra/d_string.hpp | 746+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdistrho/src/DistrhoDefines.h | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 867 insertions(+), 582 deletions(-)

diff --git a/distrho/DistrhoPlugin.hpp b/distrho/DistrhoPlugin.hpp @@ -21,6 +21,12 @@ #include <cmath> +#ifdef PROPER_CPP11_SUPPORT +# include <cstdint> +#else +# include <stdint.h> +#endif + #ifndef M_PI # define M_PI 3.14159265358979323846 #endif diff --git a/distrho/DistrhoUtils.hpp b/distrho/DistrhoUtils.hpp @@ -19,7 +19,6 @@ #include "src/DistrhoDefines.h" -#include <cassert> #include <cstdarg> #include <cstdio> #include <cstdlib> @@ -59,7 +58,7 @@ inline float // misc functions static inline -long d_cconst(int a, int b, int c, int d) noexcept +long d_cconst(const int a, const int b, const int c, const int d) noexcept { return (a << 24) | (b << 16) | (c << 8) | (d << 0); } @@ -71,622 +70,97 @@ long d_cconst(int a, int b, int c, int d) noexcept # define d_debug(...) #else static inline -void d_debug(const char* const fmt, ...) +void d_debug(const char* const fmt, ...) noexcept { - ::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); + try { + ::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); + } catch (...) {} } #endif static inline -void d_stdout(const char* const fmt, ...) +void d_stdout(const char* const fmt, ...) noexcept { - ::va_list args; - ::va_start(args, fmt); - std::vfprintf(stdout, fmt, args); - std::fprintf(stdout, "\n"); - ::va_end(args); + try { + ::va_list args; + ::va_start(args, fmt); + std::vfprintf(stdout, fmt, args); + std::fprintf(stdout, "\n"); + ::va_end(args); + } catch (...) {} } static inline -void d_stderr(const char* const fmt, ...) +void d_stderr(const char* const fmt, ...) noexcept { - ::va_list args; - ::va_start(args, fmt); - std::vfprintf(stderr, fmt, args); - std::fprintf(stderr, "\n"); - ::va_end(args); + try { + ::va_list args; + ::va_start(args, fmt); + std::vfprintf(stderr, fmt, args); + std::fprintf(stderr, "\n"); + ::va_end(args); + } catch (...) {} } static inline -void d_stderr2(const char* const fmt, ...) +void d_stderr2(const char* const fmt, ...) noexcept { - ::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); + try { + ::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); + } catch (...) {} } static inline -void d_safe_assert(const char* const assertion, const char* const file, const int line) +void d_safe_assert(const char* const assertion, const char* const file, const int line) noexcept { d_stderr2("assertion failure: \"%s\" in file %s, line %i", assertion, file, line); } -// ----------------------------------------------------------------------- -// d_*sleep - -static inline -void d_sleep(unsigned int secs) -{ -#ifdef DISTRHO_OS_WINDOWS - ::Sleep(secs * 1000); -#else - ::sleep(secs); -#endif -} - static inline -void d_msleep(unsigned int msecs) +void d_safe_exception(const char* const exception, const char* const file, const int line) noexcept { -#ifdef DISTRHO_OS_WINDOWS - ::Sleep(msecs); -#else - ::usleep(msecs * 1000); -#endif + d_stderr2("exception caught: \"%s\" in file %s, line %i", exception, file, line); } // ----------------------------------------------------------------------- -// d_string class +// d_*sleep -class d_string +static inline +void d_sleep(const uint secs) { -public: - // ------------------------------------------------------------------- - // constructors (no explicit conversions allowed) - - /* - * Empty string. - */ - explicit d_string() - { - _init(); - _dup(nullptr); - } - - /* - * Simple character. - */ - explicit d_string(const char c) - { - char ch[2]; - ch[0] = c; - ch[1] = '\0'; - - _init(); - _dup(ch); - } - - /* - * Simple char string. - */ - explicit d_string(char* const strBuf) - { - _init(); - _dup(strBuf); - } - - /* - * Simple const char string. - */ - explicit d_string(const char* const strBuf) - { - _init(); - _dup(strBuf); - } - - /* - * Integer. - */ - explicit d_string(const int value) - { - char strBuf[0xff+1]; - std::memset(strBuf, 0, (0xff+1)*sizeof(char)); - std::snprintf(strBuf, 0xff, "%d", value); - - _init(); - _dup(strBuf); - } - - /* - * Unsigned integer, possibly in hexadecimal. - */ - explicit d_string(const unsigned int value, const bool hexadecimal = false) - { - char strBuf[0xff+1]; - std::memset(strBuf, 0, (0xff+1)*sizeof(char)); - std::snprintf(strBuf, 0xff, hexadecimal ? "0x%x" : "%u", value); - - _init(); - _dup(strBuf); - } - - /* - * Long integer. - */ - explicit d_string(const long int value) - { - char strBuf[0xff+1]; - std::memset(strBuf, 0, (0xff+1)*sizeof(char)); - std::snprintf(strBuf, 0xff, "%ld", value); - - _init(); - _dup(strBuf); - } - - /* - * Long unsigned integer, possibly hexadecimal. - */ - explicit d_string(const unsigned long int value, const bool hexadecimal = false) - { - char strBuf[0xff+1]; - std::memset(strBuf, 0, (0xff+1)*sizeof(char)); - std::snprintf(strBuf, 0xff, hexadecimal ? "0x%lx" : "%lu", value); - - _init(); - _dup(strBuf); - } + DISTRHO_SAFE_ASSERT_RETURN(secs > 0,); - /* - * Single-precision floating point number. - */ - explicit d_string(const float value) - { - char strBuf[0xff+1]; - std::memset(strBuf, 0, (0xff+1)*sizeof(char)); - std::snprintf(strBuf, 0xff, "%f", value); - - _init(); - _dup(strBuf); - } - - /* - * Double-precision floating point number. - */ - explicit d_string(const double value) - { - char strBuf[0xff+1]; - std::memset(strBuf, 0, (0xff+1)*sizeof(char)); - std::snprintf(strBuf, 0xff, "%g", value); - - _init(); - _dup(strBuf); - } - - // ------------------------------------------------------------------- - // non-explicit constructor - - /* - * Create string from another string. - */ - d_string(const d_string& str) - { - _init(); - _dup(str.fBuffer); - } - - // ------------------------------------------------------------------- - // destructor - - /* - * Destructor. - */ - ~d_string() - { - assert(fBuffer != nullptr); - - delete[] fBuffer; - fBuffer = nullptr; - } - - // ------------------------------------------------------------------- - // 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 - { - if (strBuf == nullptr) - return false; - - if (ignoreCase) - { -#ifdef __USE_GNU - return (strcasestr(fBuffer, strBuf) != nullptr); + try { +#ifdef DISTRHO_OS_WIN + ::Sleep(secs * 1000); #else - d_string tmp1(fBuffer), tmp2(strBuf); - tmp1.toLower(); - tmp2.toLower(); - return (std::strstr((const char*)tmp1, (const char*)tmp2) != nullptr); + ::sleep(secs); #endif - } - - return (std::strstr(fBuffer, strBuf) != nullptr); - } - - /* - * Overloaded function. - */ - bool contains(const d_string& str, const bool ignoreCase = false) const - { - return contains(str.fBuffer, ignoreCase); - } - - /* - * Check if character at 'pos' is a digit. - */ - bool isDigit(const size_t pos) const noexcept - { - if (pos >= fBufferLen) - return false; - - return (fBuffer[pos] >= '0' && fBuffer[pos] <= '9'); - } - - /* - * Check if the string starts with the character 'c'. - */ - bool startsWith(const char c) const - { - if (c == '\0') - return false; - - return (fBufferLen > 0 && fBuffer[0] == c); - } - - /* - * Check if the string starts with the string 'prefix'. - */ - bool startsWith(const char* const prefix) const - { - if (prefix == nullptr) - return false; - - const size_t prefixLen(std::strlen(prefix)); - - if (fBufferLen < prefixLen) - return false; - - return (std::strncmp(fBuffer + (fBufferLen-prefixLen), prefix, prefixLen) == 0); - } - - /* - * Check if the string ends with the character 'c'. - */ - bool endsWith(const char c) const - { - if (c == '\0') - return false; - - return (fBufferLen > 0 && fBuffer[fBufferLen] == c); - } - - /* - * Check if the string ends with the string 'suffix'. - */ - bool endsWith(const char* const suffix) const - { - if (suffix == nullptr) - return false; - - const size_t suffixLen(std::strlen(suffix)); - - if (fBufferLen < suffixLen) - return false; - - return (std::strncmp(fBuffer + (fBufferLen-suffixLen), suffix, suffixLen) == 0); - } - - /* - * 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 - { - if (before == '\0' || after == '\0') - return; - - for (size_t i=0; i < fBufferLen; ++i) - { - if (fBuffer[i] == before) - fBuffer[i] = after; - else if (fBuffer[i] == '\0') - break; - } - } - - /* - * 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] += 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] -= kCharDiff; - } - } - - // ------------------------------------------------------------------- - // public operators - - operator const char*() const noexcept - { - return fBuffer; - } - - char& operator[](const size_t pos) const noexcept - { - return fBuffer[pos]; - } - - bool operator==(const char* const strBuf) const - { - return (strBuf != nullptr && std::strcmp(fBuffer, strBuf) == 0); - } - - bool operator==(const d_string& str) const - { - return operator==(str.fBuffer); - } - - bool operator!=(const char* const strBuf) const - { - return !operator==(strBuf); - } - - bool operator!=(const d_string& str) const - { - return !operator==(str.fBuffer); - } - - d_string& operator=(const char* const strBuf) - { - _dup(strBuf); - - return *this; - } - - d_string& operator=(const d_string& str) - { - return operator=(str.fBuffer); - } - - d_string& operator+=(const char* const strBuf) - { - 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) - { - return operator+=(str.fBuffer); - } - - d_string operator+(const char* const strBuf) - { - 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) - { - return operator+(str.fBuffer); - } - - // ------------------------------------------------------------------- - -private: - char* fBuffer; // the actual string buffer - size_t fBufferLen; // string length - bool fFirstInit; // true when first initiated - - /* - * Shared init function. - * Called on all constructors. - */ - void _init() noexcept - { - fBuffer = nullptr; - fBufferLen = 0; - fFirstInit = true; - } - - /* - * Helper function. - * Called whenever the string needs to be allocated. - * - * Notes: - * - Allocates string only if first initiated, or 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) - { - if (strBuf != nullptr) - { - // don't recreate string if contents match - if (fFirstInit || std::strcmp(fBuffer, strBuf) != 0) - { - if (! fFirstInit) - { - assert(fBuffer != nullptr); - delete[] fBuffer; - } - - fBufferLen = (size > 0) ? size : std::strlen(strBuf); - fBuffer = new char[fBufferLen+1]; - - std::strcpy(fBuffer, strBuf); - - fBuffer[fBufferLen] = '\0'; - - fFirstInit = false; - } - } - else - { - assert(size == 0); - - // don't recreate null string - if (fFirstInit || fBufferLen != 0) - { - if (! fFirstInit) - { - assert(fBuffer != nullptr); - delete[] fBuffer; - } - - fBufferLen = 0; - fBuffer = new char[1]; - fBuffer[0] = '\0'; - - fFirstInit = false; - } - } - } -}; - -// ----------------------------------------------------------------------- - -static inline -d_string operator+(const d_string& strBefore, const char* const strBufAfter) -{ - const char* const strBufBefore = (const char*)strBefore; - 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); + } DISTRHO_SAFE_EXCEPTION("carla_sleep"); } static inline -d_string operator+(const char* const strBufBefore, const d_string& strAfter) +void d_msleep(const uint msecs) { - const char* const strBufAfter = (const char*)strAfter; - const size_t newBufSize = ((strBufBefore != nullptr) ? std::strlen(strBufBefore) : 0) + strAfter.length() + 1; - char newBuf[newBufSize]; + DISTRHO_SAFE_ASSERT_RETURN(msecs > 0,); - std::strcpy(newBuf, strBufBefore); - std::strcat(newBuf, strBufAfter); - - return d_string(newBuf); + try { +#ifdef DISTRHO_OS_WIN + ::Sleep(msecs); +#else + ::usleep(msecs * 1000); +#endif + } DISTRHO_SAFE_EXCEPTION("carla_msleep"); } // ----------------------------------------------------------------------- diff --git a/distrho/extra/d_string.hpp b/distrho/extra/d_string.hpp @@ -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 "../DistrhoUtils.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 diff --git a/distrho/src/DistrhoDefines.h b/distrho/src/DistrhoDefines.h @@ -108,6 +108,59 @@ # define nullptr (0) #endif +/* Define DISTRHO_SAFE_ASSERT* */ +#define DISTRHO_SAFE_ASSERT(cond) if (cond) pass(); else d_safe_assert(#cond, __FILE__, __LINE__); +#define DISTRHO_SAFE_ASSERT_BREAK(cond) if (cond) pass(); else { d_safe_assert(#cond, __FILE__, __LINE__); break; } +#define DISTRHO_SAFE_ASSERT_CONTINUE(cond) if (cond) pass(); else { d_safe_assert(#cond, __FILE__, __LINE__); continue; } +#define DISTRHO_SAFE_ASSERT_RETURN(cond, ret) if (cond) pass(); else { d_safe_assert(#cond, __FILE__, __LINE__); return ret; } + +/* Define DISTRHO_SAFE_EXCEPTION */ +#define DISTRHO_SAFE_EXCEPTION(msg) catch(...) { d_safe_exception(msg, __FILE__, __LINE__); } +#define DISTRHO_SAFE_EXCEPTION_BREAK(msg) catch(...) { d_safe_exception(msg, __FILE__, __LINE__); break; } +#define DISTRHO_SAFE_EXCEPTION_CONTINUE(msg) catch(...) { d_safe_exception(msg, __FILE__, __LINE__); continue; } +#define DISTRHO_SAFE_EXCEPTION_RETURN(msg, ret) catch(...) { d_safe_exception(msg, __FILE__, __LINE__); return ret; } + +/* Define DISTRHO_DECLARE_NON_COPY_CLASS */ +#ifdef DISTRHO_PROPER_CPP11_SUPPORT +# define DISTRHO_DECLARE_NON_COPY_CLASS(ClassName) \ +private: \ + ClassName(ClassName&) = delete; \ + ClassName(const ClassName&) = delete; \ + ClassName& operator=(ClassName&) = delete; \ + ClassName& operator=(const ClassName&) = delete; +#else +# define DISTRHO_DECLARE_NON_COPY_CLASS(ClassName) \ +private: \ + ClassName(ClassName&); \ + ClassName(const ClassName&); \ + ClassName& operator=(ClassName&); \ + ClassName& operator=(const ClassName&); +#endif + +/* Define DISTRHO_DECLARE_NON_COPY_STRUCT */ +#ifdef DISTRHO_PROPER_CPP11_SUPPORT +# define DISTRHO_DECLARE_NON_COPY_STRUCT(StructName) \ + StructName(StructName&) = delete; \ + StructName(const StructName&) = delete; \ + StructName& operator=(StructName&) = delete; \ + StructName& operator=(const StructName&) = delete; +#else +# define DISTRHO_DECLARE_NON_COPY_STRUCT(StructName) +#endif + +/* Define DISTRHO_PREVENT_HEAP_ALLOCATION */ +#ifdef DISTRHO_PROPER_CPP11_SUPPORT +# define DISTRHO_PREVENT_HEAP_ALLOCATION \ +private: \ + static void* operator new(size_t) = delete; \ + static void operator delete(void*) = delete; +#else +# define DISTRHO_PREVENT_HEAP_ALLOCATION \ +private: \ + static void* operator new(size_t); \ + static void operator delete(void*); +#endif + /* Define namespace */ #ifndef DISTRHO_NO_NAMESPACE # ifndef DISTRHO_NAMESPACE @@ -124,4 +177,10 @@ #define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#UI" +/* Useful typedefs */ +typedef unsigned char uchar; +typedef unsigned long int ulong; +typedef unsigned short int ushort; +typedef unsigned int uint; + #endif // DISTRHO_DEFINES_H_INCLUDED