#define __ardour_variant_h__
#include <stdint.h>
+#include <limits.h>
+#include <algorithm>
#include <stdexcept>
#include "ardour/libardour_visibility.h"
+#include "evoral/Beats.hpp"
#include "pbd/compose.h"
namespace ARDOUR {
{
public:
enum Type {
+ NOTHING, ///< Nothing (void)
+ BEATS, ///< Beats+ticks
BOOL, ///< Boolean
DOUBLE, ///< C double (64-bit IEEE-754)
FLOAT, ///< C float (32-bit IEEE-754)
URI ///< URI string
};
- explicit Variant(bool value) : _type(BOOL) { _bool = value; }
- explicit Variant(double value) : _type(DOUBLE) { _double = value; }
- explicit Variant(float value) : _type(FLOAT) { _float = value; }
- explicit Variant(int value) : _type(INT) { _int = value; }
- explicit Variant(long value) : _type(LONG) { _long = value; }
+ Variant() : _type(NOTHING) { _long = 0; }
+ explicit Variant(bool value) : _type(BOOL) { _bool = value; }
+ explicit Variant(double value) : _type(DOUBLE) { _double = value; }
+ explicit Variant(float value) : _type(FLOAT) { _float = value; }
+ explicit Variant(int32_t value) : _type(INT) { _int = value; }
+ explicit Variant(int64_t value) : _type(LONG) { _long = value; }
+
+ explicit Variant(const Evoral::Beats& beats)
+ : _type(BEATS)
+ , _beats(beats)
+ {}
+
+ /** Make a variant of a specific string type (string types only) */
Variant(Type type, const std::string& value)
: _type(type)
, _string(value)
{}
+ /** Make a numeric variant from a double (numeric types only).
+ *
+ * If conversion is impossible, the variant will have type NOTHING.
+ */
+ Variant(Type type, double value)
+ : _type(type)
+ {
+ switch (type) {
+ case BOOL:
+ _bool = value != 0.0;
+ break;
+ case DOUBLE:
+ _double = (double)value;
+ break;
+ case FLOAT:
+ _float = (float)value;
+ break;
+ case INT:
+ _int = (int32_t)lrint(std::max((double)INT32_MIN,
+ std::min(value, (double)INT32_MAX)));
+ break;
+ case LONG:
+ _long = (int64_t)lrint(std::max((double)INT64_MIN,
+ std::min(value, (double)INT64_MAX)));
+ break;
+ case BEATS:
+ _beats = Evoral::Beats(value);
+ break;
+ default:
+ _type = NOTHING;
+ _long = 0;
+ }
+ }
+
+ /** Convert a numeric variant to a double. */
+ double to_double() const {
+ switch (_type) {
+ case BOOL: return _bool;
+ case DOUBLE: return _double;
+ case FLOAT: return _float;
+ case INT: return _int;
+ case LONG: return _long;
+ case BEATS: return _beats.to_double();
+ default: return 0.0;
+ }
+ }
+
bool get_bool() const { ensure_type(BOOL); return _bool; }
double get_double() const { ensure_type(DOUBLE); return _double; }
float get_float() const { ensure_type(FLOAT); return _float; }
int get_int() const { ensure_type(INT); return _int; }
long get_long() const { ensure_type(LONG); return _long; }
+ bool operator==(bool v) const { return _type == BOOL && _bool == v; }
+ double operator==(double v) const { return _type == DOUBLE && _double == v; }
+ float operator==(float v) const { return _type == FLOAT && _float == v; }
+ int operator==(int v) const { return _type == INT && _int == v; }
+ long operator==(long v) const { return _type == LONG && _long == v; }
+
+ Variant& operator=(bool v) { _type = BOOL; _bool = v; return *this; }
+ Variant& operator=(double v) { _type = DOUBLE; _double = v; return *this; }
+ Variant& operator=(float v) { _type = FLOAT; _float = v; return *this; }
+ Variant& operator=(int v) { _type = INT; _int = v; return *this; }
+ Variant& operator=(long v) { _type = LONG; _long = v; return *this; }
+
const std::string& get_path() const { ensure_type(PATH); return _string; }
const std::string& get_string() const { ensure_type(STRING); return _string; }
const std::string& get_uri() const { ensure_type(URI); return _string; }
+ bool operator==(const Variant& v) const {
+ if (_type != v._type) {
+ return false;
+ }
+
+ switch (_type) {
+ case NOTHING: return true;
+ case BEATS: return _beats == v._beats;
+ case BOOL: return _bool == v._bool;
+ case DOUBLE: return _double == v._double;
+ case FLOAT: return _float == v._float;
+ case INT: return _int == v._int;
+ case LONG: return _long == v._long;
+ case PATH:
+ case STRING:
+ case URI: return _string == v._string;
+ }
+
+ return false;
+ }
+
+ bool operator==(const Evoral::Beats& v) const {
+ return _type == BEATS && _beats == v;
+ }
+
+ bool operator!() const { return _type == NOTHING; }
+
+ Variant& operator=(Evoral::Beats v) {
+ _type = BEATS;
+ _beats = v;
+ return *this;
+ }
+
+ const Evoral::Beats& get_beats() const {
+ ensure_type(BEATS); return _beats;
+ }
+
Type type() const { return _type; }
+ static bool type_is_numeric(Type type) {
+ switch (type) {
+ case BOOL: case DOUBLE: case FLOAT: case INT: case LONG: case BEATS:
+ return true;
+ default:
+ return false;
+ }
+ }
+
private:
static const char* type_name(const Type type) {
static const char* names[] = {
}
}
- Type _type; ///< Type tag
- std::string _string; ///< For all string types (PATH, STRING, URI)
+ Type _type; ///< Type tag
+ std::string _string; ///< PATH, STRING, URI
+ Evoral::Beats _beats; ///< BEATS
// Union of all primitive numeric types
union {