[C++-sig] problem with Boost.Python enum with duplicate values

scott snyder snyder at d0mino.fnal.gov
Thu Oct 2 18:40:23 CEST 2003


hi -

I've found that the enum support in Boost.Python does not fully
handle the case of duplicate enum values.  For example, i was
processing (with pyste) this enum:

  enum { X=0, Y=1, NUM_COORDINATES=2, SIZE=NUM_COORDINATES };

Pyste generated code to set all four enum symbols like this:

    enum_< UniqueInt<4> >("unnamed")
        .value("Y", Hep2Vector::Y)
        .value("X", Hep2Vector::X)
        .value("SIZE", Hep2Vector::SIZE)
        .value("NUM_COORDINATES", Hep2Vector::NUM_COORDINATES)
        .export_values()
    ;

However, from python, the `SIZE' symbol was not present.

Looking at the code in enum.cpp, is see that it keeps the enum items
in a map indexed by the value --- so values added later overwrite
any added earlier.

It's common to use C++ enums to define small integral constants,
in addition to using them for things which are actual enumerations.
So the case of multiple enum symbols with the same value really should
be supported.

The following patch attempts to do this.
When value() is called, if the value is already in the map,
then we add the symbol to a (new) list instead.
export_values() then visits the list as well as the map when
exporting symbols.
The map is still used for the value->symbol mapping (so the first
one listed is the one you'll get).

thanks,
sss


Index: src/object/enum.cpp
===================================================================
RCS file: /cvsroot/boost/boost/libs/python/src/object/enum.cpp,v
retrieving revision 1.5
diff -u -p -r1.5 enum.cpp
--- src/object/enum.cpp	20 Feb 2003 20:27:44 -0000	1.5
+++ src/object/enum.cpp	2 Oct 2003 16:23:30 -0000
@@ -148,6 +148,7 @@ namespace
       dict d;
       d["__slots__"] = tuple();
       d["values"] = dict();
+      d["othervalues"] = list();
 
       object module_name = module_prefix();
       if (module_name)
@@ -192,7 +193,12 @@ void enum_base::add_value(char const* na
     (*this).attr(name_) = x;
 
     dict d = extract<dict>(this->attr("values"))();
-    d[value] = x;
+    if (d.has_key (value)) {
+      list l = extract<list>(this->attr("othervalues"))();
+      l.append (x);
+    }
+    else
+      d[value] = x;
     
     // Set the name field in the new enum instanec
     enum_object* p = downcast<enum_object>(x.ptr());
@@ -204,11 +210,16 @@ void enum_base::export_values()
 {
     dict d = extract<dict>(this->attr("values"))();
     list values = d.values();
+    list othervalues = extract<list>(this->attr("othervalues"))();
     scope current;
     
     for (unsigned i = 0, max = len(values); i < max; ++i)
     {
         api::setattr(current, object(values[i].attr("name")), values[i]);
+    }
+    for (unsigned i = 0, max = len(othervalues); i < max; ++i)
+    {
+        api::setattr(current, object(othervalues[i].attr("name")), othervalues[i]);
     }
  }
 
Index: test/enum.cpp
===================================================================
RCS file: /cvsroot/boost/boost/libs/python/test/enum.cpp,v
retrieving revision 1.6
diff -u -p -r1.6 enum.cpp
--- test/enum.cpp	21 May 2003 22:17:22 -0000	1.6
+++ test/enum.cpp	2 Oct 2003 16:23:30 -0000
@@ -13,7 +13,7 @@
 #endif 
 using namespace boost::python;
 
-enum color { red = 1, green = 2, blue = 4 };
+enum color { red = 1, green = 2, blue = 4, blue2 = 4 };
 
 #if BOOST_WORKAROUND(__MWERKS__, <= 0x2407)
 namespace boost  // Pro7 has a hard time detecting enums
@@ -35,6 +35,7 @@ BOOST_PYTHON_MODULE(enum_ext)
         .value("red", red)
         .value("green", green)
         .value("blue", blue)
+        .value("blue2", blue2)
         .export_values()
         ;
     
Index: test/enum.py
===================================================================
RCS file: /cvsroot/boost/boost/libs/python/test/enum.py,v
retrieving revision 1.4
diff -u -p -r1.4 enum.py
--- test/enum.py	26 Aug 2003 13:11:51 -0000	1.4
+++ test/enum.py	2 Oct 2003 16:23:30 -0000
@@ -10,6 +10,15 @@ enum_ext.color.green
 >>> identity(color.blue)
 enum_ext.color.blue
 
+>>> identity(color.blue2)
+enum_ext.color.blue
+
+>>> int(color.blue)
+4
+
+>>> int(color.blue2)
+4
+
 >>> identity(color(1))
 enum_ext.color.red
 




More information about the Cplusplus-sig mailing list