p2p/stingray_sdk/plugin_foundation/const_config.h
Lucas Schwiderski 2c9ce46dd2
chore: Rework project structure
There likely won't be much need for multiple separate crates.
2023-05-26 23:42:01 +02:00

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