text: /*
   * The MIT License (MIT)
   *
   * Copyright (c) 2015 Microsoft Corporation
   * 
   * -=- Robust Distributed System Nucleus (rDSN) -=- 
   *
   * Permission is hereby granted, free of charge, to any person obtaining a copy
   * of this software and associated documentation files (the "Software"), to deal
   * in the Software without restriction, including without limitation the rights
   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   * copies of the Software, and to permit persons to whom the Software is
   * furnished to do so, subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included in
   * all copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   * THE SOFTWARE.
   */
  
  /*
   * Description:
   *     What is this file about?
   *
   * Revision history:
   *     xxxx-xx-xx, author, first version
   *     xxxx-xx-xx, author, fix bug about xxx
   */
  
  # pragma once
  
  # include <map>
  # include <string>
  # include <mutex>
  
  
  // an invalid enum value must be provided so as to be the default value when parsing failed
  #define ENUM_BEGIN2(type, name, invalid_value)    \
      static inline ::dsn::enum_helper_xxx<type>* RegisterEnu_##name() {\
          ::dsn::enum_helper_xxx<type>* helper = new ::dsn::enum_helper_xxx<type>(invalid_value);
  
  #define ENUM_BEGIN(type, invalid_value) ENUM_BEGIN2(type, type, invalid_value)
  
  #define ENUM_REG(e) helper->register_enum(#e, e);
  
  #define ENUM_END2(type, name) return helper; \
          } \
      inline type enum_from_string(const char* s, type invalid_value) {\
          return ::dsn::enum_helper_xxx<type>::instance(RegisterEnu_##name).parse(s); \
          }\
      inline const char* enum_to_string(type val)  {\
          return ::dsn::enum_helper_xxx<type>::instance(RegisterEnu_##name).to_string(val); \
          }
  
  #define ENUM_END(type) ENUM_END2(type, type)
  
  
  namespace dsn {
  
  template<typename TEnum>
  class enum_helper_xxx
  {
  private:
      struct EnumContext
      {
          std::string name;
      };
  
  public:
      enum_helper_xxx(TEnum invalid) : _invalid(invalid) {}
  
      void register_enum(const char* name, TEnum v)
      {
          _nameToValue[std::string(name)] = v;
  
          EnumContext ctx;
          ctx.name.assign(name);
          _valueToContext[v] = ctx;
      }
  
      TEnum parse(const std::string& name)
      {
          auto it = _nameToValue.find(name);
          return it != _nameToValue.end() ? it->second : _invalid;
      }
  
      const char* to_string(TEnum v)
      {
          auto it = _valueToContext.find(v);
          if (it != _valueToContext.end())
          {
              return it->second.name.c_str();
          }
          else
          {
              return "Unknown";
          }
      }
      
      static enum_helper_xxx& instance(enum_helper_xxx<TEnum>* (*registor)())
      {
          if (_instance == nullptr)
          {
              static std::once_flag flag;
              std::call_once(flag, [&]() {
                  _instance = registor();
              });
          }
          return *_instance;
      }
  
  private:
      static enum_helper_xxx *_instance;
  
  private:
      TEnum                        _invalid;
      std::map<TEnum, EnumContext> _valueToContext;
      std::map<std::string, TEnum> _nameToValue;
  };
  
  template<typename TEnum> enum_helper_xxx<TEnum>* enum_helper_xxx<TEnum>::_instance = 0;
  
  } // end namespace
  
  