Interest in a small Enum IO utility?

Hi, I have some code that helps with defining iostream-operators for enums. We use this in our C++<->xml bindings. Basically, it's just two maps (string->enum & enum<-string) and some syntactic sugar. However, I happen to think it is quite neat and so figured it might be useful to other people too. (And it's always nice to give something back :) So, is this something that would fit in boost? Advantages: * Enables lexical_cast on enums. * Pure implementation detail from user-of-enum's perspective. * Very little syntax overhead, inspired by boost::assign. * Works across namespaces & DLLS. * Allows user to define io-ops for "external" enums too. (But the IO-op-macro hs to go into the external namespace.) * Uses pimpl-idiom for faster compilation. * Suitable for header-only version. Issues to work out: * Uses the Loki-singleton to store implementation details. * Initialization is a bit rough. (We get away with it because we have a static "initClass" method for every class. It is a natural place for enumio-setup in our app, but this does not translate to general code well.) * Stores std::strings, although it's almost always constructed from string literals. Wastes a bit of memory for simpler implementation. * EnumIO<E>::The() is globally accessible, so there could be conflicts. (Very low probability though) See below for example & implementation. Comments? Cheers, /Marcus --- user .h ------------------------------------------------ enum Foo { Bar, Baz; } // to export from a win32 dll, add dllimport/export here std::istream& operator>>(std::istream&, Foo& foo); std::ostream& operator<<(std::ostream&, Foo foo); --- user.cpp ------------------------------------------------ #include "user.h" #include <enumio.h> ENUMIO_IMPLEMENT_IOSTREAM_OPS(Foo) // just one way to do it bool init = (::EnumIO<Foo>::the() (Bar, "bar") (Baz, "baz")), true; --- enumio.h ------------------------------------------------ class EnumUtilBase { public: ~ EnumIOBase(); protected: explicit EnumIOBase(const std::type_info& enumType); std::istream & in(std::istream & os, int &value) const; std::ostream & out(std::ostream & os, int value) const; protected: void add(int value, const char* data); private: class Impl; boost::scoped_ptr<Impl> m_i; }; // Helps with serialization (iostream) of enums template<class E> class EnumIO : public EnumIOBase { public: typedef E Enum; EnumIO<E> the() { return ::Loki::SingletonHolder<::EnumIO<E> >::the(); } EnumIO(); EnumIO<E>& operator()(E value, const char* data); std::istream & in(std::istream & is, E & value) const; std::ostream & out(std::ostream & os, E value) const; }; #define ENUMIO_IMPLEMENT_IOSTREAM_OPS(E) \ std::istream& operator>>(std::istream& is, E& value) { \ return ::EnumIO<E>::the().in(is, value); } \ std::ostream& operator>>(std::ostream& os, E value) { \ return ::EnumIO<E>::the().out(os, value); } template<class E> inline EnumIO<E>::EnumIO() : EnumIOBase(typeid(E)) { BOOST_STATIC_ASSERT(sizeof(E) == sizeof(int)); } template<class E> inline EnumIO<E> &EnumIO<E>::operator()(E value, const char* data) { EnumIOBase::add(value, data); return *this; } template<class E> inline std::istream & EnumIO<E>::in(std::istream & is, E & value) const { return EnumIOBase::in(is, (int&) value); } template<class E> inline std::ostream & EnumIO<E>::out(std::ostream& os, E value) const { return EnumIOBase::out(os, value); } --- enumio.cpp ------------------------------------------------ typedef std::map<int, std::string> MapOut; typedef std::map<std::string, int> MapIn; class EnumIOBase::Impl { public: const char* m_typename; ///< is retrieved from typeid(X).name() MapIn m_mapIn; MapOut m_mapOut; }; EnumIOBase::EnumIOBase(const std::type_info& enumType) : m_i(new Impl) { m_i->m_typename = enumType.name(); } EnumIOBase::~EnumIOBase() { } std::istream & EnumIOBase::in(std::istream & is, int &value) const { std::string str; is >> str; if (m_i->m_mapIn.empty()) { MapIn& m = const_cast<MapIn&>(m_i->m_mapIn); for(MapOut::const_iterator i = m_i->m_mapOut.begin(); i != m_i->m_mapOut.end(); ++i) { m.insert(std::make_pair(i->second, i->first)); } } MapIn::const_iterator i = m_i->m_mapIn.find(str); if (i != m_i->m_mapIn.end()) { value = i->second; } else { is.setstate(std::ios::failbit); } return is; } std::ostream & EnumIOBase::out(std::ostream & os, int value) const { const std::string& str = toStr(value); if (!str.empty()) { os << str; } else { os.setstate(std::ios::failbit); } return os; } void EnumIOBase::add(int value, const char* data) { m_i->m_mapOut.insert(std::make_pair(value, data)); }

Marcus Lindblom wrote:
std::ostream & EnumIOBase::out(std::ostream & os, int value) const
Sorry, the body for this function should of course be as follows. (I edited some of the code to remove some cruft from our current version) std::ostream & EnumIOBase::out(std::ostream & os, int value) const { MapOut::const_iterator i = m_i->m_mapOut.find(value); if (i != m_i->m_mapOut.end()) { os << i->second; } else { os.setstate(std::ios::failbit); } return os; } Cheers, /Marcus

Marcus Lindblom wrote:
Hi,
I have some code that helps with defining iostream-operators for enums. We use this in our C++<->xml bindings.
Basically, it's just two maps (string->enum & enum<-string) and some syntactic sugar. However, I happen to think it is quite neat and so figured it might be useful to other people too. (And it's always nice to give something back :)
So, is this something that would fit in boost?
Ping? Am I way off here? Cheers, /Marcus

Marcus Lindblom wrote:
Marcus Lindblom wrote:
Hi,
I have some code that helps with defining iostream-operators for enums. We use this in our C++<->xml bindings.
Basically, it's just two maps (string->enum & enum<-string) and some syntactic sugar. However, I happen to think it is quite neat and so figured it might be useful to other people too. (And it's always nice to give something back :)
So, is this something that would fit in boost?
Ping? Am I way off here?
I think there'd be some interest. Basically enums without a string mapping aren't much use -- and there was interest in boost_enum and other enum related helpers. BTW, in case you aren't aware you can use boost.bimap so you should only need one map. Jeff

Jeff Garland wrote:
Marcus Lindblom wrote:
Marcus Lindblom wrote:
Hi,
I have some code that helps with defining iostream-operators for enums. We use this in our C++<->xml bindings.
Basically, it's just two maps (string->enum & enum<-string) and some syntactic sugar. However, I happen to think it is quite neat and so figured it might be useful to other people too. (And it's always nice to give something back :)
So, is this something that would fit in boost? Ping? Am I way off here?
I think there'd be some interest. Basically enums without a string mapping aren't much use -- and there was interest in boost_enum and other enum related helpers.
I didn't know about the previous Boost.Enum proposal. It seems to be abandoned. I'll have to dig through the archives to see what happened with it. However, my "lib" is much smaller in scope, intentionally.
BTW, in case you aren't aware you can use boost.bimap so you should only need one map.
Yes. It's not there because we haven't switched to boost 1.34 yet (will do soon) so I haven't had access to it. Cheers, /Marcus

Marcus Lindblom wrote:
Jeff Garland wrote:
I think there'd be some interest. Basically enums without a string mapping aren't much use -- and there was interest in boost_enum and other enum related helpers.
I didn't know about the previous Boost.Enum proposal. It seems to be abandoned. I'll have to dig through the archives to see what happened with it.
Seems likely at this point.
However, my "lib" is much smaller in scope, intentionally.
Yep -- that's likely a good thing. Anyway, I'd be interested in seeing a full proposal. Jeff

Quoting Jeff Garland <jeff@crystalclearsoftware.com>:
Marcus Lindblom wrote:
I didn't know about the previous Boost.Enum proposal. It seems to be abandoned. I'll have to dig through the archives to see what happened with it.
Seems likely at this point.
Yup. I'll try to make some comments about that proposal when I put mine up, some differences and similarities, etc.
However, my "lib" is much smaller in scope, intentionally.
Yep -- that's likely a good thing. Anyway, I'd be interested in seeing a full proposal.
Thanks! I'll see what I can put together. I still need to to solve the singleton issue though. Perhaps I could borrow a singleton from somwhere else (like pool?). Cheers, /Marcus
participants (2)
-
Jeff Garland
-
Marcus Lindblom