VOID is a windows define (not MSVC specific)
[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 #ifdef PLATFORM_WINDOWS
33 #undef VOID
34 #endif
35
36 namespace ARDOUR {
37
38 /** A value with dynamic type (tagged union). */
39 class LIBARDOUR_API Variant
40 {
41 public:
42         enum Type {
43                 VOID,    ///< Nothing
44                 BOOL,    ///< Boolean
45                 DOUBLE,  ///< C double (64-bit IEEE-754)
46                 FLOAT,   ///< C float (32-bit IEEE-754)
47                 INT,     ///< Signed 32-bit int
48                 LONG,    ///< Signed 64-bit int
49                 PATH,    ///< File path string
50                 STRING,  ///< Raw string (no semantics)
51                 URI      ///< URI string
52         };
53
54         explicit Variant()              : _type(VOID)   { _long   = 0;     }
55         explicit Variant(bool    value) : _type(BOOL)   { _bool   = value; }
56         explicit Variant(double  value) : _type(DOUBLE) { _double = value; }
57         explicit Variant(float   value) : _type(FLOAT)  { _float  = value; }
58         explicit Variant(int32_t value) : _type(INT)    { _int    = value; }
59         explicit Variant(int64_t value) : _type(LONG)   { _long   = value; }
60
61         /** Make a variant of a specific string type (string types only) */
62         Variant(Type type, const std::string& value)
63                 : _type(type)
64                 , _string(value)
65         {}
66
67         /** Make a numeric variant from a double (numeric types only).
68          *
69          * If conversion is impossible, the variant will have type VOID.
70          */
71         Variant(Type type, double value)
72                 : _type(type)
73         {
74                 switch (type) {
75                 case BOOL:
76                         _bool = value != 0.0;
77                         break;
78                 case DOUBLE:
79                         _double = (double)value;
80                         break;
81                 case FLOAT:
82                         _float = (float)value;
83                         break;
84                 case INT:
85                         _int = (int32_t)lrint(std::max((double)INT32_MIN,
86                                                        std::min(value, (double)INT32_MAX)));
87                         break;
88                 case LONG:
89                         _long = (int64_t)lrint(std::max((double)INT64_MIN,
90                                                         std::min(value, (double)INT64_MAX)));
91                         break;
92                 default:
93                         _type = VOID;
94                         _long = 0;
95                 }
96         }
97
98         /** Convert a numeric variant to a double. */
99         double to_double() const {
100                 switch (_type) {
101                 case BOOL:   return _bool;
102                 case DOUBLE: return _double;
103                 case FLOAT:  return _float;
104                 case INT:    return _int;
105                 case LONG:   return _long;
106                 default:     return 0.0;
107                 }
108         }
109
110         bool   get_bool()   const { ensure_type(BOOL);   return _bool;   }
111         double get_double() const { ensure_type(DOUBLE); return _double; }
112         float  get_float()  const { ensure_type(FLOAT);  return _float;  }
113         int    get_int()    const { ensure_type(INT);    return _int;    }
114         long   get_long()   const { ensure_type(LONG);   return _long;   }
115
116         const std::string& get_path()   const { ensure_type(PATH);   return _string; }
117         const std::string& get_string() const { ensure_type(STRING); return _string; }
118         const std::string& get_uri()    const { ensure_type(URI);    return _string; }
119
120         Type type() const { return _type; }
121
122         static bool type_is_numeric(Type type) {
123                 switch (type) {
124                 case BOOL: case DOUBLE: case FLOAT: case INT: case LONG:
125                         return true;
126                 default:
127                         return false;
128                 }
129         }
130
131 private:
132         static const char* type_name(const Type type) {
133                 static const char* names[] = {
134                         "bool", "double", "float", "int", "long", "path", "string", "uri"
135                 };
136
137                 return names[type];
138         }
139
140         void ensure_type(const Type type) const {
141                 if (_type != type) {
142                         throw std::domain_error(
143                                 string_compose("get_%1 called on %2 variant",
144                                                type_name(type), type_name(_type)));
145                 }
146         }
147
148         Type        _type;    ///< Type tag
149         std::string _string;  ///< For all string types (PATH, STRING, URI)
150
151         // Union of all primitive numeric types
152         union {
153                 bool    _bool;
154                 double  _double;
155                 float   _float;
156                 int32_t _int;
157                 int64_t _long;
158         };
159 };
160
161 } // namespace ARDOUR
162
163 #endif // __ardour_variant_h__