8fd9c829f7d024230ff9ec59b6e019d247410643
[ardour.git] / libs / ardour / ardour / variant.h
1 /*
2     Copyright (C) 2014 Paul Davis
3     Author: David Robillard
4
5     This program is free software; you can redistribute it and/or modify it
6     under the terms of the GNU General Public License as published by the Free
7     Software Foundation; either version 2 of the License, or (at your option)
8     any later version.
9
10     This program is distributed in the hope that it will be useful, but WITHOUT
11     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13     for more details.
14
15     You should have received a copy of the GNU General Public License along
16     with this program; if not, write to the Free Software Foundation, Inc.,
17     675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #ifndef __ardour_variant_h__
21 #define __ardour_variant_h__
22
23 #include <stdint.h>
24 #include <limits.h>
25
26 #include <algorithm>
27 #include <stdexcept>
28
29 #include "ardour/libardour_visibility.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                 BOOL,    ///< Boolean
41                 DOUBLE,  ///< C double (64-bit IEEE-754)
42                 FLOAT,   ///< C float (32-bit IEEE-754)
43                 INT,     ///< Signed 32-bit int
44                 LONG,    ///< Signed 64-bit int
45                 PATH,    ///< File path string
46                 STRING,  ///< Raw string (no semantics)
47                 URI      ///< URI string
48         };
49
50         explicit Variant()              : _type(NOTHING) { _long   = 0;     }
51         explicit Variant(bool    value) : _type(BOOL)    { _bool   = value; }
52         explicit Variant(double  value) : _type(DOUBLE)  { _double = value; }
53         explicit Variant(float   value) : _type(FLOAT)   { _float  = value; }
54         explicit Variant(int32_t value) : _type(INT)     { _int    = value; }
55         explicit Variant(int64_t value) : _type(LONG)    { _long   = value; }
56
57         /** Make a variant of a specific string type (string types only) */
58         Variant(Type type, const std::string& value)
59                 : _type(type)
60                 , _string(value)
61         {}
62
63         /** Make a numeric variant from a double (numeric types only).
64          *
65          * If conversion is impossible, the variant will have type NOTHING.
66          */
67         Variant(Type type, double value)
68                 : _type(type)
69         {
70                 switch (type) {
71                 case BOOL:
72                         _bool = value != 0.0;
73                         break;
74                 case DOUBLE:
75                         _double = (double)value;
76                         break;
77                 case FLOAT:
78                         _float = (float)value;
79                         break;
80                 case INT:
81                         _int = (int32_t)lrint(std::max((double)INT32_MIN,
82                                                        std::min(value, (double)INT32_MAX)));
83                         break;
84                 case LONG:
85                         _long = (int64_t)lrint(std::max((double)INT64_MIN,
86                                                         std::min(value, (double)INT64_MAX)));
87                         break;
88                 default:
89                         _type = NOTHING;
90                         _long = 0;
91                 }
92         }
93
94         /** Convert a numeric variant to a double. */
95         double to_double() const {
96                 switch (_type) {
97                 case BOOL:   return _bool;
98                 case DOUBLE: return _double;
99                 case FLOAT:  return _float;
100                 case INT:    return _int;
101                 case LONG:   return _long;
102                 default:     return 0.0;
103                 }
104         }
105
106         bool   get_bool()   const { ensure_type(BOOL);   return _bool;   }
107         double get_double() const { ensure_type(DOUBLE); return _double; }
108         float  get_float()  const { ensure_type(FLOAT);  return _float;  }
109         int    get_int()    const { ensure_type(INT);    return _int;    }
110         long   get_long()   const { ensure_type(LONG);   return _long;   }
111
112         const std::string& get_path()   const { ensure_type(PATH);   return _string; }
113         const std::string& get_string() const { ensure_type(STRING); return _string; }
114         const std::string& get_uri()    const { ensure_type(URI);    return _string; }
115
116         Type type() const { return _type; }
117
118         static bool type_is_numeric(Type type) {
119                 switch (type) {
120                 case BOOL: case DOUBLE: case FLOAT: case INT: case LONG:
121                         return true;
122                 default:
123                         return false;
124                 }
125         }
126
127 private:
128         static const char* type_name(const Type type) {
129                 static const char* names[] = {
130                         "bool", "double", "float", "int", "long", "path", "string", "uri"
131                 };
132
133                 return names[type];
134         }
135
136         void ensure_type(const Type type) const {
137                 if (_type != type) {
138                         throw std::domain_error(
139                                 string_compose("get_%1 called on %2 variant",
140                                                type_name(type), type_name(_type)));
141                 }
142         }
143
144         Type        _type;    ///< Type tag
145         std::string _string;  ///< For all string types (PATH, STRING, URI)
146
147         // Union of all primitive numeric types
148         union {
149                 bool    _bool;
150                 double  _double;
151                 float   _float;
152                 int32_t _int;
153                 int64_t _long;
154         };
155 };
156
157 } // namespace ARDOUR
158
159 #endif // __ardour_variant_h__