1 /* 2 * Copyright (C) 2014-2015 David Robillard <d@drobilla.net> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License along 15 * with this program; if not, write to the Free Software Foundation, Inc., 16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 */ 18 19 #ifndef __ardour_variant_h__ 20 #define __ardour_variant_h__ 21 22 #include <stdint.h> 23 #include <limits.h> 24 25 #include <algorithm> 26 #include <stdexcept> 27 28 #include "ardour/libardour_visibility.h" 29 #include "temporal/beats.h" 30 #include "pbd/compose.h" 31 32 namespace ARDOUR { 33 34 /** A value with dynamic type (tagged union). */ 35 class LIBARDOUR_API Variant 36 { 37 public: 38 enum Type { 39 NOTHING, ///< Nothing (void) 40 BEATS, ///< Beats+ticks 41 BOOL, ///< Boolean 42 DOUBLE, ///< C double (64-bit IEEE-754) 43 FLOAT, ///< C float (32-bit IEEE-754) 44 INT, ///< Signed 32-bit int 45 LONG, ///< Signed 64-bit int 46 PATH, ///< File path string 47 STRING, ///< Raw string (no semantics) 48 URI ///< URI string 49 }; 50 Variant()51 Variant() : _type(NOTHING) { _long = 0; } 52 Variant(bool value)53 explicit Variant(bool value) : _type(BOOL) { _bool = value; } Variant(double value)54 explicit Variant(double value) : _type(DOUBLE) { _double = value; } Variant(float value)55 explicit Variant(float value) : _type(FLOAT) { _float = value; } Variant(int32_t value)56 explicit Variant(int32_t value) : _type(INT) { _int = value; } Variant(int64_t value)57 explicit Variant(int64_t value) : _type(LONG) { _long = value; } 58 Variant(const Temporal::Beats & beats)59 explicit Variant(const Temporal::Beats& beats) 60 : _type(BEATS) 61 , _beats(beats) 62 {} 63 64 /** Make a variant of a specific string type (string types only) */ Variant(Type type,const std::string & value)65 Variant(Type type, const std::string& value) 66 : _type(type) 67 , _string(value) 68 {} 69 70 /** Make a numeric variant from a double (numeric types only). 71 * 72 * If conversion is impossible, the variant will have type NOTHING. 73 */ Variant(Type type,double value)74 Variant(Type type, double value) 75 : _type(type) 76 { 77 switch (type) { 78 case BOOL: 79 _bool = value != 0.0; 80 break; 81 case DOUBLE: 82 _double = (double)value; 83 break; 84 case FLOAT: 85 _float = (float)value; 86 break; 87 case INT: 88 _int = (int32_t)lrint(std::max((double)INT32_MIN, 89 std::min(value, (double)INT32_MAX))); 90 break; 91 case LONG: 92 _long = (int64_t)lrint(std::max((double)INT64_MIN, 93 std::min(value, (double)INT64_MAX))); 94 break; 95 case BEATS: 96 _beats = Temporal::Beats(value); 97 break; 98 default: 99 _type = NOTHING; 100 _long = 0; 101 } 102 } 103 104 /** Convert a numeric variant to a double. */ to_double()105 double to_double() const { 106 switch (_type) { 107 case BOOL: return _bool; 108 case DOUBLE: return _double; 109 case FLOAT: return _float; 110 case INT: return _int; 111 case LONG: return _long; 112 case BEATS: return _beats.to_double(); 113 default: return 0.0; 114 } 115 } 116 get_bool()117 bool get_bool() const { ensure_type(BOOL); return _bool; } get_double()118 double get_double() const { ensure_type(DOUBLE); return _double; } get_float()119 float get_float() const { ensure_type(FLOAT); return _float; } get_int()120 int get_int() const { ensure_type(INT); return _int; } get_long()121 long get_long() const { ensure_type(LONG); return _long; } 122 123 bool operator==(bool v) const { return _type == BOOL && _bool == v; } 124 double operator==(double v) const { return _type == DOUBLE && _double == v; } 125 float operator==(float v) const { return _type == FLOAT && _float == v; } 126 int operator==(int v) const { return _type == INT && _int == v; } 127 long operator==(long v) const { return _type == LONG && _long == v; } 128 129 Variant& operator=(bool v) { _type = BOOL; _bool = v; return *this; } 130 Variant& operator=(double v) { _type = DOUBLE; _double = v; return *this; } 131 Variant& operator=(float v) { _type = FLOAT; _float = v; return *this; } 132 Variant& operator=(int v) { _type = INT; _int = v; return *this; } 133 Variant& operator=(long v) { _type = LONG; _long = v; return *this; } 134 get_path()135 const std::string& get_path() const { ensure_type(PATH); return _string; } get_string()136 const std::string& get_string() const { ensure_type(STRING); return _string; } get_uri()137 const std::string& get_uri() const { ensure_type(URI); return _string; } 138 139 bool operator==(const Variant& v) const { 140 if (_type != v._type) { 141 return false; 142 } 143 144 switch (_type) { 145 case NOTHING: return true; 146 case BEATS: return _beats == v._beats; 147 case BOOL: return _bool == v._bool; 148 case DOUBLE: return _double == v._double; 149 case FLOAT: return _float == v._float; 150 case INT: return _int == v._int; 151 case LONG: return _long == v._long; 152 case PATH: 153 case STRING: 154 case URI: return _string == v._string; 155 } 156 157 return false; 158 } 159 160 bool operator==(const Temporal::Beats& v) const { 161 return _type == BEATS && _beats == v; 162 } 163 164 bool operator!() const { return _type == NOTHING; } 165 166 Variant& operator=(Temporal::Beats v) { 167 _type = BEATS; 168 _beats = v; 169 return *this; 170 } 171 get_beats()172 const Temporal::Beats& get_beats() const { 173 ensure_type(BEATS); return _beats; 174 } 175 type()176 Type type() const { return _type; } 177 type_is_numeric(Type type)178 static bool type_is_numeric(Type type) { 179 switch (type) { 180 case BOOL: case DOUBLE: case FLOAT: case INT: case LONG: case BEATS: 181 return true; 182 default: 183 return false; 184 } 185 } 186 187 private: type_name(const Type type)188 static const char* type_name(const Type type) { 189 static const char* names[] = { 190 "bool", "double", "float", "int", "long", "path", "string", "uri" 191 }; 192 193 return names[type]; 194 } 195 ensure_type(const Type type)196 void ensure_type(const Type type) const { 197 if (_type != type) { 198 throw std::domain_error( 199 string_compose("get_%1 called on %2 variant", 200 type_name(type), type_name(_type))); 201 } 202 } 203 204 Type _type; ///< Type tag 205 std::string _string; ///< PATH, STRING, URI 206 Temporal::Beats _beats; ///< BEATS 207 208 // Union of all primitive numeric types 209 union { 210 bool _bool; 211 double _double; 212 float _float; 213 int32_t _int; 214 int64_t _long; 215 }; 216 }; 217 218 } // namespace ARDOUR 219 220 #endif // __ardour_variant_h__ 221