Browse Source

More d_string into its own file; Rework base headers

gh-pages
falkTX 9 years ago
parent
commit
855eb9f77a
4 changed files with 867 additions and 582 deletions
  1. +6
    -0
      distrho/DistrhoPlugin.hpp
  2. +56
    -582
      distrho/DistrhoUtils.hpp
  3. +746
    -0
      distrho/extra/d_string.hpp
  4. +59
    -0
      distrho/src/DistrhoDefines.h

+ 6
- 0
distrho/DistrhoPlugin.hpp View File

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


+ 56
- 582
distrho/DistrhoUtils.hpp View File

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

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


+ 746
- 0
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 "../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

+ 59
- 0
distrho/src/DistrhoDefines.h View File

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

Loading…
Cancel
Save