Skip to content

Instantly share code, notes, and snippets.

@shawnfeng0
Last active November 15, 2021 09:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shawnfeng0/722d5307341d4b669f02cf08a4bf51c0 to your computer and use it in GitHub Desktop.
Save shawnfeng0/722d5307341d4b669f02cf08a4bf51c0 to your computer and use it in GitHub Desktop.
Define an enum that can be converted to a string
//
// Created by shawnfeng(shawnfeng0@gmail.com) on 2021/11/1.
//
#pragma once
#include <map>
#include <string>
#include <vector>
// reference:
// https://stackoverflow.com/questions/207976/how-to-easily-map-c-enums-to-strings
// https://stackoverflow.com/questions/201593/is-there-a-simple-way-to-convert-c-enum-to-string#201792
namespace enum_string {
template <typename T>
static inline void split_string_for_each(const std::string &str,
const std::string &delimiter,
const T &foreach_function,
ssize_t max_number = -1) {
ssize_t num = 0;
std::string::size_type start;
std::string::size_type end = -1;
while (true) {
start = str.find_first_not_of(delimiter, end + 1);
if (start == std::string::npos) break; // over
end = str.find_first_of(delimiter, start + 1);
if (end == std::string::npos) {
foreach_function(num, str.substr(start));
break;
}
foreach_function(num, str.substr(start, end - start));
++num;
if (max_number > 0 && num == max_number) break;
}
}
/**
* Strip function, delete the specified characters on both sides of the string.
*/
inline std::string &strip(std::string &s,
const std::string &characters = " \t\r\n") {
s.erase(0, s.find_first_not_of(characters));
return s.erase(s.find_last_not_of(characters) + 1);
}
template <typename UnderlyingType>
static inline std::map<UnderlyingType, std::string> ParserEnumDefine(
const std::string &name, const std::string &define_str) {
UnderlyingType cur_num = 0;
std::string cur_item_str;
std::map<UnderlyingType, std::string> result_map;
split_string_for_each(define_str, ",", [&](int num, const std::string &str) {
split_string_for_each(
str, "=",
[&](int num, const std::string &str) {
if (num == 0) cur_item_str = str;
if (num == 1) cur_num = std::stoi(str);
},
2);
result_map.emplace(cur_num, name + "::" + strip(cur_item_str));
cur_num++;
});
return result_map;
}
} // namespace enum_string
/**
* Example:
* @code
#include <iostream>
#include "enum_with_string.h"
ENUM_WITH_STRING(Animal, dog, cat, monkey = 50, fish, human = 100, duck)
int main() {
std::cout << to_string(Animal::dog) << std::endl;
std::cout << to_string(Animal::cat) << std::endl;
std::cout << to_string(Animal::monkey) << std::endl;
std::cout << to_string(Animal::fish) << std::endl;
std::cout << to_string(Animal::human) << std::endl;
std::cout << to_string(Animal::duck) << std::endl;
}
* @endcode
*/
#define ENUM_WITH_STRING(Name, ...) \
enum class Name { __VA_ARGS__, __COUNT }; \
static inline const std::string &to_string(Name value) { \
using underlying_type = std::underlying_type<Name>::type; \
static const auto map = \
enum_string::ParserEnumDefine<underlying_type>(#Name, #__VA_ARGS__); \
static const std::string cannot_converted = \
"Cannot be converted to string"; \
underlying_type under_value = static_cast<underlying_type>(value); \
if (map.count(under_value)) \
return map.at(under_value); \
else \
return cannot_converted; \
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment