Fixed three minor issues
[libdai.git] / include / dai / enum.h
index f2618f7..02dfb3f 100644 (file)
@@ -1,22 +1,16 @@
-/*  Copyright (C) 2006-2008  Joris Mooij  [j dot mooij at science dot ru dot nl]
-    Radboud University Nijmegen, The Netherlands
-    
-    This file is part of libDAI.
+/*  This file is part of libDAI - http://www.libdai.org/
+ *
+ *  libDAI is licensed under the terms of the GNU General Public License version
+ *  2, or (at your option) any later version. libDAI is distributed without any
+ *  warranty. See the file COPYING for more details.
+ *
+ *  Copyright (C) 2006-2009  Joris Mooij  [joris dot mooij at libdai dot org]
+ *  Copyright (C) 2006-2007  Radboud University Nijmegen, The Netherlands
+ */
 
-    libDAI is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
 
-    libDAI is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with libDAI; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-*/
+/// \file
+/// \brief Defines the DAI_ENUM macro, which can be used to define an \c enum with additional functionality.
 
 
 #ifndef __defined_libdai_enum_h
 
 #include <cstring>
 #include <iostream>
-
-
-namespace dai {
-
-
-// C++ enums are too limited for my purposes. This defines wrapper classes
-// that provide much more functionality than a simple enum. The only
-// disadvantage is that one wrapper class needs to be written for each
-// number of values an enum can take... a better solution is needed.
-
-
-#define ENUM2(x,a,b) class x {\
+#include <dai/exceptions.h>
+
+
+/// Extends the C++ \c enum type by supporting input/output streaming and conversion to and from <tt>const char*</tt> and \c size_t
+/** For more details see the source code.
+ *
+ *  \par Example:
+ *  \code
+ *  DAI_ENUM(colors,RED,GREEN,BLUE)
+ *  \endcode
+ *  defines a class \a colors encapsulating an
+ *  \code
+ *  enum {RED, GREEN, BLUE};
+ *  \endcode
+ *  which offers additional functionality over the plain \c enum keyword.
+ */
+#define DAI_ENUM(x,val0,...) class x {\
     public:\
-        enum value {a, b};\
+        enum value {val0,__VA_ARGS__};\
 \
-        x() : v(a) {}\
+        x() : v(val0) {}\
 \
         x(value w) : v(w) {}\
 \
         x(char const *w) {\
-           static char const* labels[] = {#a, #b};\
-           size_t i = 0;\
-           for( ; i < sizeof(labels) / sizeof(char const *); i++ )\
-               if( strcmp( w, labels[i] ) == 0 ) {\
-                   v = (value)i;\
-                   break;\
-               }\
-           if( i == sizeof(labels) / sizeof(char const *) )\
-               throw "Unknown " #x " value";\
-        }\
-\
-        operator value () const { return v; }\
-\
-        operator size_t () const { return (size_t)v; }\
-\
-        operator char const* () const {\
-           static char const* labels[] = {#a, #b};\
-           return labels[v];\
+            static char const* labelstring = #val0 "," #__VA_ARGS__;\
+            size_t pos_begin = 0;\
+            size_t i = 0;\
+            for( size_t pos_end = 0; ; pos_end++ ) {\
+                if( (labelstring[pos_end] == ',') || (labelstring[pos_end] == '\0') ) {\
+                    if( (strlen( w ) == pos_end - pos_begin) && (strncmp( labelstring + pos_begin, w, pos_end - pos_begin ) == 0) ) {\
+                        v = (value)i;\
+                        return;\
+                    } else {\
+                        i++;\
+                        pos_begin = pos_end + 1;\
+                    }\
+                }\
+                if( labelstring[pos_end] == '\0' )\
+                    break;\
+            }\
+            DAI_THROWE(UNKNOWN_ENUM_VALUE,"'" + std::string(w) + "' is not in [" + std::string(labelstring) + "]");\
+        }\
+\
+        operator value() const { return v; }\
+\
+        operator size_t() const { return (size_t)v; }\
+\
+        operator char const*() const {\
+            static char labelstring[] = #val0 "," #__VA_ARGS__;\
+            size_t pos_begin = 0;\
+            size_t i = 0;\
+            for( size_t pos_end = 0; ; pos_end++ )\
+                if( (labelstring[pos_end] == ',') || (labelstring[pos_end] == '\0') ) {\
+                    if( (size_t)v == i ) {\
+                        labelstring[pos_end] = '\0';\
+                        return labelstring + pos_begin;\
+                    } else {\
+                        i++;\
+                        pos_begin = pos_end + 1;\
+                    }\
+                }\
         }\
 \
         friend std::istream& operator >> (std::istream& is, x& y) {\
@@ -77,196 +95,9 @@ namespace dai {
             return os;\
         }\
 \
-    private:\
+    protected:\
         value v;\
 };
 
 
-#define ENUM3(x,a,b,c) class x {\
-    public:\
-        enum value {a, b, c};\
-\
-        x() : v(a) {}\
-\
-        x(value w) : v(w) {}\
-\
-        x(char const *w) {\
-           static char const* labels[] = {#a, #b, #c};\
-           size_t i = 0;\
-           for( ; i < sizeof(labels) / sizeof(char const *); i++ )\
-               if( strcmp( w, labels[i] ) == 0 ) {\
-                   v = (value)i;\
-                   break;\
-               }\
-           if( i == sizeof(labels) / sizeof(char const *) )\
-               throw "Unknown " #x " value";\
-        }\
-\
-        operator value () const { return v; }\
-\
-        operator size_t () const { return (size_t)v; }\
-\
-        operator char const* () const {\
-           static char const* labels[] = {#a, #b, #c};\
-           return labels[v];\
-        }\
-\
-        friend std::istream& operator >> (std::istream& is, x& y) {\
-            std::string s;\
-            is >> s;\
-            y = x(s.c_str());\
-            return is;\
-        }\
-\
-        friend std::ostream& operator << (std::ostream& os, const x& y) {\
-            os << (const char *)y;\
-            return os;\
-        }\
-\
-    private:\
-        value v;\
-};
-
-
-#define ENUM4(x,a,b,c,d) class x {\
-    public:\
-        enum value {a, b, c, d};\
-\
-        x() : v(a) {}\
-\
-        x(value w) : v(w) {}\
-\
-        x(char const *w) {\
-           static char const* labels[] = {#a, #b, #c, #d};\
-           size_t i = 0;\
-           for( ; i < sizeof(labels) / sizeof(char const *); i++ )\
-               if( strcmp( w, labels[i] ) == 0 ) {\
-                   v = (value)i;\
-                   break;\
-               }\
-           if( i == sizeof(labels) / sizeof(char const *) )\
-               throw "Unknown " #x " value";\
-        }\
-\
-        operator value () const { return v; }\
-\
-        operator size_t () const { return (size_t)v; }\
-\
-        operator char const* () const {\
-           static char const* labels[] = {#a, #b, #c, #d};\
-           return labels[v];\
-        }\
-\
-        friend std::istream& operator >> (std::istream& is, x& y) {\
-            std::string s;\
-            is >> s;\
-            y = x(s.c_str());\
-            return is;\
-        }\
-\
-        friend std::ostream& operator << (std::ostream& os, const x& y) {\
-            os << (const char *)y;\
-            return os;\
-        }\
-\
-    private:\
-        value v;\
-};
-
-
-#define ENUM5(x,a,b,c,d,e) class x {\
-    public:\
-        enum value {a, b, c, d, e};\
-\
-        x() : v(a) {}\
-\
-        x(value w) : v(w) {}\
-\
-        x(char const *w) {\
-           static char const* labels[] = {#a, #b, #c, #d, #e};\
-           size_t i = 0;\
-           for( ; i < sizeof(labels) / sizeof(char const *); i++ )\
-               if( strcmp( w, labels[i] ) == 0 ) {\
-                   v = (value)i;\
-                   break;\
-               }\
-           if( i == sizeof(labels) / sizeof(char const *) )\
-               throw "Unknown " #x " value";\
-        }\
-\
-        operator value () const { return v; }\
-\
-        operator size_t () const { return (size_t)v; }\
-\
-        operator char const* () const {\
-           static char const* labels[] = {#a, #b, #c, #d, #e};\
-           return labels[v];\
-        }\
-\
-        friend std::istream& operator >> (std::istream& is, x& y) {\
-            std::string s;\
-            is >> s;\
-            y = x(s.c_str());\
-            return is;\
-        }\
-\
-        friend std::ostream& operator << (std::ostream& os, const x& y) {\
-            os << (const char *)y;\
-            return os;\
-        }\
-\
-    private:\
-        value v;\
-};
-
-
-#define ENUM6(x,a,b,c,d,e,f) class x {\
-    public:\
-        enum value {a, b, c, d, e, f};\
-\
-        x() : v(a) {}\
-\
-        x(value w) : v(w) {}\
-\
-        x(char const *w) {\
-           static char const* labels[] = {#a, #b, #c, #d, #e, #f};\
-           size_t i = 0;\
-           for( ; i < sizeof(labels) / sizeof(char const *); i++ )\
-               if( strcmp( w, labels[i] ) == 0 ) {\
-                   v = (value)i;\
-                   break;\
-               }\
-           if( i == sizeof(labels) / sizeof(char const *) )\
-               throw "Unknown " #x " value";\
-        }\
-\
-        operator value () const { return v; }\
-\
-        operator size_t () const { return (size_t)v; }\
-\
-        operator char const* () const {\
-           static char const* labels[] = {#a, #b, #c, #d, #e, #f};\
-           return labels[v];\
-        }\
-\
-        friend std::istream& operator >> (std::istream& is, x& y) {\
-            std::string s;\
-            is >> s;\
-            y = x(s.c_str());\
-            return is;\
-        }\
-\
-        friend std::ostream& operator << (std::ostream& os, const x& y) {\
-            os << (const char *)y;\
-            return os;\
-        }\
-\
-    private:\
-        value v;\
-};
-
-
-} // end of namespace dai
-
-
 #endif