296 lines
7.5 KiB
Objective-C
296 lines
7.5 KiB
Objective-C
|
|
#ifndef FRAMELIB_ERRORS_H
|
|
#define FRAMELIB_ERRORS_H
|
|
|
|
#include "FrameLib_Threading.h"
|
|
#include "FrameLib_Types.h"
|
|
|
|
#include <algorithm>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
|
|
/**
|
|
|
|
@defgroup Hosting
|
|
|
|
*/
|
|
|
|
|
|
// Possible sources of error
|
|
|
|
enum ErrorSource { kErrorObject, kErrorParameter, kErrorMemory, kErrorDSP };
|
|
|
|
/**
|
|
|
|
@class FrameLib_ErrorReporter
|
|
|
|
@ingroup Hosting
|
|
|
|
@brief a class used to report errors to the host environment.
|
|
|
|
*/
|
|
|
|
class FrameLib_ErrorReporter
|
|
{
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
@class ErrorReport
|
|
|
|
@brief a report for a single error.
|
|
|
|
*/
|
|
|
|
class ErrorReport
|
|
{
|
|
friend FrameLib_ErrorReporter;
|
|
|
|
ErrorReport(ErrorSource source, FrameLib_Proxy *reporter, const char *error, const char *items, size_t numChars, unsigned long numItems)
|
|
: mSource(source), mReporter(reporter), mError(error), mItems(items), mItemSize(numChars), mNumItems(numItems) {}
|
|
|
|
public:
|
|
|
|
ErrorReport() : mSource(kErrorObject), mReporter(nullptr), mError(nullptr), mItems(nullptr), mItemSize(0), mNumItems(0) {}
|
|
|
|
void getErrorText(std::string& text) const;
|
|
void getErrorText(char *text, size_t N) const;
|
|
ErrorSource getSource() const { return mSource; }
|
|
FrameLib_Proxy* getReporter() const { return mReporter; }
|
|
|
|
private:
|
|
|
|
void copy(char*& dest, const char *str, size_t length, size_t& left) const;
|
|
|
|
// Data
|
|
|
|
ErrorSource mSource;
|
|
FrameLib_Proxy* mReporter;
|
|
const char* mError;
|
|
const char* mItems;
|
|
size_t mItemSize;
|
|
unsigned long mNumItems;
|
|
};
|
|
|
|
/**
|
|
|
|
@class ErrorList
|
|
|
|
@brief a list of ErrorReport objects.
|
|
|
|
*/
|
|
|
|
class ErrorList
|
|
{
|
|
friend FrameLib_ErrorReporter;
|
|
|
|
const static int sCharArraySize = 8192;
|
|
const static int sReportArraySize = 1024;
|
|
|
|
public:
|
|
|
|
/**
|
|
|
|
@class ConstIterator
|
|
|
|
@brief an iterator for reports in the list (with an underlying const ErrorReport type).
|
|
|
|
*/
|
|
|
|
class ConstIterator
|
|
{
|
|
friend ErrorList;
|
|
|
|
ConstIterator(const ErrorReport *ptr) : mPtr(ptr) {};
|
|
|
|
public:
|
|
|
|
const ErrorReport operator *() { return *mPtr; }
|
|
const ErrorReport *operator ->() { return mPtr; }
|
|
|
|
friend bool operator == (const ConstIterator &a, const ConstIterator &b) { return a.mPtr == b.mPtr; }
|
|
friend bool operator != (const ConstIterator &a, const ConstIterator &b) { return a.mPtr != b.mPtr; }
|
|
|
|
ConstIterator& operator ++()
|
|
{
|
|
mPtr++;
|
|
return *this;
|
|
}
|
|
|
|
ConstIterator operator ++(int)
|
|
{
|
|
ConstIterator result = *this;
|
|
operator++();
|
|
return result;
|
|
}
|
|
|
|
private:
|
|
|
|
// Pointer
|
|
|
|
const ErrorReport *mPtr;
|
|
};
|
|
|
|
ErrorList() : mReportsSize(0), mItemsSize(0), mFull(false) {}
|
|
|
|
// Non-copyable
|
|
|
|
ErrorList(const ErrorList&) = delete;
|
|
ErrorList& operator=(const ErrorList&) = delete;
|
|
|
|
const ErrorReport operator[](size_t idx) const { return mReports[idx]; }
|
|
size_t size() const { return mReportsSize; }
|
|
|
|
ConstIterator begin() const { return mReports; }
|
|
ConstIterator last() const { return mReports + mReportsSize - 1; }
|
|
ConstIterator end() const { return mReports + mReportsSize; }
|
|
|
|
bool isFull() const { return mFull; }
|
|
|
|
private:
|
|
|
|
char *getItemsPointer() { return mItems + mItemsSize; }
|
|
|
|
bool addItem(const char *str)
|
|
{
|
|
char *ptr = mItems + mItemsSize;
|
|
size_t size = strlen(str) + 1;
|
|
|
|
if (mItemsSize + size < sCharArraySize)
|
|
{
|
|
std::copy(str, str + size, ptr);
|
|
mItemsSize += size;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool addItem(size_t number)
|
|
{
|
|
const int strBufSize = 32;
|
|
char charArray[strBufSize];
|
|
snprintf(charArray, strBufSize, "%zu", number);
|
|
return addItem(charArray);
|
|
}
|
|
|
|
bool addItem(long number)
|
|
{
|
|
const int strBufSize = 32;
|
|
char charArray[strBufSize];
|
|
snprintf(charArray, strBufSize, "%ld", number);
|
|
return addItem(charArray);
|
|
}
|
|
|
|
bool addItem(double number)
|
|
{
|
|
const int strBufSize = 32;
|
|
char charArray[strBufSize];
|
|
snprintf(charArray, strBufSize, "%lf", number);
|
|
return addItem(charArray);
|
|
}
|
|
|
|
bool addItems()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
template<typename T>
|
|
bool addItems(T first)
|
|
{
|
|
return addItem(first);
|
|
}
|
|
|
|
template<typename T, typename... Args>
|
|
bool addItems(T first, Args... args)
|
|
{
|
|
if (addItem(first))
|
|
return addItems(args...);
|
|
return false;
|
|
}
|
|
|
|
template<typename... Args>
|
|
void add(ErrorSource source, FrameLib_Proxy *reporter, const char *error, Args... args)
|
|
{
|
|
char *ptr = getItemsPointer();
|
|
|
|
if (!mFull && (mReportsSize < sReportArraySize) && addItems(args...))
|
|
{
|
|
size_t itemSize = getItemsPointer() - ptr;
|
|
mReports[mReportsSize] = ErrorReport(source, reporter, error, ptr, itemSize, sizeof...(args));
|
|
mReportsSize++;
|
|
}
|
|
else
|
|
mFull = true;
|
|
}
|
|
|
|
void remove()
|
|
{
|
|
if (mReportsSize)
|
|
{
|
|
mFull = false;
|
|
mReportsSize--;
|
|
mItemsSize -= mReports[mReportsSize].mItemSize;
|
|
mReports[mReportsSize] = ErrorReport();
|
|
}
|
|
}
|
|
|
|
// Data
|
|
|
|
ErrorReport mReports[sReportArraySize];
|
|
char mItems[sCharArraySize];
|
|
size_t mReportsSize;
|
|
size_t mItemsSize;
|
|
bool mFull;
|
|
};
|
|
|
|
/**
|
|
|
|
@class HostNotifier
|
|
|
|
@brief a virtual struct used to supply a method for notifying the host of errors.
|
|
|
|
*/
|
|
|
|
struct HostNotifier : public FrameLib_Proxy
|
|
{
|
|
virtual bool notify(const ErrorReport& report) = 0;
|
|
};
|
|
|
|
// Constructor
|
|
|
|
FrameLib_ErrorReporter(HostNotifier *notifier) : mNotifier(notifier), mNotified (false), mReports(new ErrorList()) {}
|
|
|
|
// Add and Retrieve Errors (list ownership is passed on retrieval)
|
|
|
|
template<typename... Args>
|
|
void reportError(ErrorSource source, FrameLib_Proxy *reporter, const char *error, Args... args)
|
|
{
|
|
mReports->add(source, reporter, error, args...);
|
|
|
|
if (mNotifier && !mNotified)
|
|
{
|
|
if (mNotifier->notify(*(mReports->last())))
|
|
mReports->remove();
|
|
else
|
|
mNotified = true;
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<ErrorList> getErrors();
|
|
|
|
private:
|
|
|
|
// Data
|
|
|
|
HostNotifier *mNotifier;
|
|
bool mNotified;
|
|
std::unique_ptr<ErrorList> mReports;
|
|
FrameLib_SpinLock mLock;
|
|
};
|
|
|
|
#endif
|