168 lines
6.3 KiB
C++
168 lines
6.3 KiB
C++
#pragma once
|
|
|
|
#include <string.h>
|
|
#include "assert.h"
|
|
#include "platform.h"
|
|
|
|
// This file is the runtime representation of a config data structure. A config data structure
|
|
// is a JSON-like object for representing generic data. This format is suitable when the
|
|
// development cost of creating a custom binary format is big and the benefits are small.
|
|
// (I.e. for any data that is not massive bulk data -- such as small configuration files.)
|
|
//
|
|
// The runtime format is essential (type, data) where type is a four-byte type identifier
|
|
// and data is four bytes of data. We use four bytes for the type identifier for alignment
|
|
// purposes. Note that the runtime format represent an entire config object as a single
|
|
// memory block. Local pointers inside the memory block are used to build structure.
|
|
//
|
|
// Note that it is possible to optimize this format further to squeeze out a few more bytes.
|
|
|
|
namespace stingray_plugin_foundation {
|
|
|
|
struct ConstConfigArray;
|
|
struct ConstConfigObject;
|
|
|
|
namespace const_config
|
|
{
|
|
// Type used for offset parameters
|
|
typedef unsigned offset_t;
|
|
|
|
// The supported value types
|
|
enum ValueType {NIL, BOOL, INTEGER, FLOAT, STRING, ARRAY, OBJECT};
|
|
|
|
// Generic representation of a value of one of the types.
|
|
union Value {
|
|
int b;
|
|
int i;
|
|
float f;
|
|
offset_t s; // Offset to char *
|
|
offset_t a; // Offset to ConstConfigArray *
|
|
offset_t o; // Offset toConstConfigObject *
|
|
};
|
|
}
|
|
|
|
// Represents the root object (the first item in the memory block).
|
|
struct ConstConfigRoot
|
|
{
|
|
int type; // ValueType
|
|
const_config::Value value;
|
|
};
|
|
|
|
// Represents an array. Note that the type is only stored once, all objects in an array
|
|
// must have the same type. In the memory layout, the ConstConfigArray block is followed
|
|
// by *size* data items (which are bool, int, float, etc) depending on type.
|
|
struct ConstConfigArray
|
|
{
|
|
int type; // ValueType
|
|
int size;
|
|
const_config::Value first_item; // size data items follows in memory
|
|
};
|
|
|
|
// Represents an entry in a ConstConfigObject. Stores the key (always a string), the
|
|
// type of the entry and the value.
|
|
struct ConstConfigObjectEntry
|
|
{
|
|
const_config::offset_t name; // Offset to name
|
|
int type; // ValueType
|
|
const_config::Value value;
|
|
};
|
|
|
|
// Represents an object. In the memory layout, ConstConfigObject is followed by
|
|
// *size* ConstConfigObjectEntry structures that contain the actual objects.
|
|
struct ConstConfigObject
|
|
{
|
|
int size;
|
|
ConstConfigObjectEntry first_entry;
|
|
};
|
|
|
|
// Convenience class used to access config data.
|
|
class ConstConfigItem
|
|
{
|
|
public:
|
|
// Creates a nil config item.
|
|
ConstConfigItem() : _base(nullptr), _type(const_config::NIL) {}
|
|
|
|
// Creates a config item from the specified root.
|
|
ConstConfigItem(const ConstConfigRoot &root) : _base((const char *)&root), _type(root.type), _value(root.value) {}
|
|
|
|
// Creates a config item with the specified base, type and data.
|
|
ConstConfigItem(const char *base, const_config::ValueType t, const_config::Value v) : _base(base), _type(t), _value(v) {}
|
|
|
|
bool is_nil() const {return _type == const_config::NIL;}
|
|
bool is_bool() const {return _type == const_config::BOOL;}
|
|
bool is_false() const {return _type == const_config::BOOL && !_value.b;}
|
|
bool is_true() const {return _type == const_config::BOOL && _value.b;}
|
|
bool is_integer() const {return _type == const_config::INTEGER;}
|
|
bool is_float() const {return _type == const_config::FLOAT;}
|
|
bool is_number() const {return is_integer() || is_float();}
|
|
bool is_string() const {return _type == const_config::STRING;}
|
|
bool is_resource() const { return is_string() || is_object() && (*this)["$resource_name"].is_string(); }
|
|
bool is_resource(const char *type) const { return is_resource() && (is_string() || (*this)["$resource_type"].is_string() && strcmp((*this)["$resource_type"].to_string(),type)==0); }
|
|
bool is_array() const { return _type == const_config::ARRAY; }
|
|
bool is_object() const {return _type == const_config::OBJECT;}
|
|
|
|
bool to_bool() const {XENSURE(is_bool()); return _value.b != 0;}
|
|
int to_integer() const {XENSURE(is_integer()); return _value.i;}
|
|
float to_float() const {return is_float() ? _value.f : float(to_integer());}
|
|
const char *to_string() const {XENSURE(is_string()); return raw_s();}
|
|
const char *to_resource(const char *type) const {
|
|
XENSURE(is_resource(type));
|
|
if (is_string()) {
|
|
return to_string();
|
|
}
|
|
return (*this)["$resource_name"].to_string();
|
|
}
|
|
|
|
bool operator||(bool b) const {return is_bool() ? to_bool() : b;}
|
|
int operator||(int i) const {return is_integer() ? _value.i : i;}
|
|
unsigned operator||(unsigned i) const {return is_integer() ? unsigned(_value.i) : i;}
|
|
float operator||(float f) const {return is_float() ? _value.f : (is_integer() ? _value.i : f);}
|
|
const char *operator||(const char *s) const {return is_string() ? raw_s() : s;}
|
|
ConstConfigItem operator||(ConstConfigItem o) {return is_nil() ? o : *this;}
|
|
|
|
int size() const {return is_array() ? raw_a()->size : 0;}
|
|
int n_items() const {return is_object() ? raw_o()->size : 0;}
|
|
|
|
ConstConfigItem operator[](int i) const {
|
|
if (!is_array())
|
|
return ConstConfigItem();
|
|
if (i<0 || i>=raw_a()->size)
|
|
return ConstConfigItem();
|
|
const ConstConfigArray &arr = *raw_a();
|
|
return ConstConfigItem(_base, (const_config::ValueType)arr.type, *(&arr.first_item + i));
|
|
}
|
|
|
|
ConstConfigItem operator[](const char *s) const {
|
|
if (!is_object())
|
|
return ConstConfigItem();
|
|
const ConstConfigObject &obj = *raw_o();
|
|
for (int i=0; i<obj.size; ++i) {
|
|
const ConstConfigObjectEntry &e = *(&obj.first_entry + i);
|
|
if (strcmp(_base + e.name, s) == 0)
|
|
return ConstConfigItem(_base, (const_config::ValueType)e.type, e.value);
|
|
}
|
|
return ConstConfigItem();
|
|
}
|
|
|
|
ConstConfigItem item(int i, const char **s = 0) const {
|
|
if (!is_object())
|
|
return ConstConfigItem();
|
|
const ConstConfigObject &obj = *raw_o();
|
|
if (i<0 || i>=obj.size)
|
|
return ConstConfigItem();
|
|
|
|
const ConstConfigObjectEntry &e = *(&obj.first_entry + i);
|
|
if(s) *s = _base + e.name;
|
|
return ConstConfigItem(_base, (const_config::ValueType)e.type, e.value);
|
|
}
|
|
|
|
private:
|
|
const char *raw_s() const {return _base + _value.s;}
|
|
const ConstConfigArray *raw_a() const {return (ConstConfigArray *)(_base + _value.a);}
|
|
const ConstConfigObject *raw_o() const {return (ConstConfigObject *)(_base + _value.o);}
|
|
|
|
const char *_base; // Base for offsets
|
|
int _type; // ValueType
|
|
const_config::Value _value;
|
|
};
|
|
|
|
} // namespace stingray_plugin_foundation
|