/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: AuroraEnum.hpp Date: 2021-10-28 Author: Reece ***/ #pragma once /////////////////////////////////////////////////////////////////////////////////////////// /// Configuration /////////////////////////////////////////////////////////////////////////////////////////// #if defined(AUE_OUT_OF_ECOSYSTEM) && defined(__cplusplus) #if !defined(AU_LANG_CPP) #define AU_LANG_CPP #endif #if !defined(AUE_NOCPPSTL) #include #include #if !defined(AU_AuHashMap) #define AU_AuHashMap template using AuHashMap = std::unordered_map; #endif #if !defined(AU_AuString) #define AU_AuString using AuString = std::string; #endif #if !defined(AU_AuROString) #define AU_AuROString using AuROString = std::string_view; #endif #endif #if !defined(AU_AuUInt) #define AU_AuUInt using AuUInt = size_t; #endif #endif /////////////////////////////////////////////////////////////////////////////////////////// /// Utilities /////////////////////////////////////////////////////////////////////////////////////////// /// @hideinitializer #define _AUE_BRACKET_SCOPE(...) __VA_ARGS__ /// @hideinitializer #define __AUE_STRIP_BRACKETS(X) X /// @hideinitializer #define _AUE_STRIP_BRACKETS(X) __AUE_STRIP_BRACKETS(_AUE_BRACKET_SCOPE X) /// @hideinitializer #define _AUE_EMIT_ARRAY(val) val, /// @hideinitializer #define _AUE_EMIT_A(val) #val, /// @hideinitializer #define _AUE_EMIT_D(name, val) name::val, /// @hideinitializer #define _AUE_EMIT_E(name, val) val, /// @hideinitializer #define _AUE_EMIT_PAIRNAME(name, val) {#val, name::val}, /// @hideinitializer #define _AUE_EMIT_CALL(name, val) consumer(name::val); /// @hideinitializer #define _AUE_EMIT_CHECK(name, val) if (codename == #val) {return name::val;} #if defined(__cplusplus) #define _AUE_EMIT_CCHECK(name, val) if (strcmp(#val, codename) == 0) { return name::val; } #else #define _AUE_EMIT_CCHECK(name, val) if (strcmp(#val, codename) == 0) { return k ## name ## val; } #endif #if !defined(_AUE_DISABLE_STRING_VIEWS) && !defined(AU_LANG_CPP_14) && !defined(AU_LANG_CPP_17) #define _AUE_STRING_VIEW AuROString #else #define _AUE_STRING_VIEW AuString #endif /////////////////////////////////////////////////////////////////////////////////////////// // API /////////////////////////////////////////////////////////////////////////////////////////// #define AUE_DEFINE_VA(name, ...) AUE_DEFINE(name, (__VA_ARGS__)) #if defined(AU_LANG_CPP) #define AUE_DEFINE_DECL_LANG(name, vals) enum class name : AuUInt32 { AU_FOR_EACH(_AUE_EMIT_ARRAY, _AUE_STRIP_BRACKETS(vals)) kEnumCount, kEnumInvalid = (AuUInt32) -1, eEnumInvalid = (AuUInt32)-1, eEnumCount = kEnumCount }; #define AUE_DEFINE_DECL_EXT(name, vals, ext) enum class name : ext { AU_FOR_EACH(_AUE_EMIT_ARRAY, _AUE_STRIP_BRACKETS(vals)) kEnumCount, kEnumInvalid = (ext) -1, eEnumInvalid = (ext)-1, eEnumCount = kEnumCount }; #else #define AUE_DEFINE_DECL_LANG(name, vals) enum name : uint32_ct { AU_FOR_EACH(_AUE_EMIT_ARRAY, _AUE_STRIP_BRACKETS(vals)) k ## name ## EnumCount, k ## name ## EnumInvalid = (uint32_ct) -1, e ## name ## EnumInvalid = (uint32_ct)-1, e ## name ## EnumCount = k ## name ## EnumCount }; #define AUE_DEFINE_DECL_EXT(name, vals, ext) enum name : ext { AU_FOR_EACH(_AUE_EMIT_ARRAY, _AUE_STRIP_BRACKETS(vals)) k ## name ## EnumCount, k ## name ## EnumInvalid = (ext) -1, e ## name ## EnumInvalid = (ext)-1, e ## name ## EnumCount = k ## name ## EnumCount }; #endif #if defined(AUE_NOCPPSTL) #define AUE_DEFINE_BODY(name, vals) \ inline const char * k ## name ## ToString[static_cast(name::kEnumCount)] = { AU_FOR_EACH(_AUE_EMIT_A, _AUE_STRIP_BRACKETS(vals)) }; \ inline const name k ## name ## Values[static_cast(name::kEnumCount)] = { AU_FOR_EACH_THAT(_AUE_EMIT_D, name, _AUE_STRIP_BRACKETS(vals)) }; \ inline const char * name ## ToString(name val) { static const char * invalid = "kEnumInvalid"; if (static_cast(val) >= static_cast(name::kEnumCount)) return invalid; return k ## name ## ToString[static_cast(val)]; } \ inline name name ## FromString(const char *codename) { AU_FOR_EACH_THAT(_AUE_EMIT_CCHECK, name, _AUE_STRIP_BRACKETS(vals)) return name::kEnumInvalid; } \ inline bool name ## IsValid(name val) { return static_cast(val) < static_cast(name::kEnumCount); } \ template \ inline void name ## ForEach(const T &consumer) { AU_FOR_EACH_THAT(_AUE_EMIT_CALL, name, _AUE_STRIP_BRACKETS(vals)) } \ static const AuUInt k ## name ## Count = static_cast(name::kEnumCount); \ static const name k ## name ## Invalid = name::kEnumInvalid; \ static const name k ## name ## MaxLegal = static_cast(k ## name ## Count - 1); \ static const name k ## name ## MinLegal = static_cast(0); #elif defined(AU_LANG_CPP) #define AUE_DEFINE_BODY(name, vals) \ inline const AuString k ## name ## ToString[static_cast(name::kEnumCount)] = {AU_FOR_EACH(_AUE_EMIT_A, _AUE_STRIP_BRACKETS(vals))}; \ inline const name k ## name ## Values[static_cast(name::kEnumCount)] = {AU_FOR_EACH_THAT(_AUE_EMIT_D, name, _AUE_STRIP_BRACKETS(vals))}; \ inline const AuHashMap k ## name ## FromString = {AU_FOR_EACH_THAT(_AUE_EMIT_PAIRNAME, name, _AUE_STRIP_BRACKETS(vals)) { "kEnumInvalid", name::kEnumCount }}; \ inline name name ## FromString(const _AUE_STRING_VIEW & codename) { AU_FOR_EACH_THAT(_AUE_EMIT_CHECK, name, _AUE_STRIP_BRACKETS(vals)) return name::kEnumInvalid; } \ inline name name ## FromHashString(const _AUE_STRING_VIEW & codename) { auto itr = k ## name ## FromString.find(codename); if (itr == k ## name ## FromString.end()) return name::kEnumInvalid; return itr->second; } \ inline const AuString &name ## ToString(name val) { static const AuString invalid = "kEnumInvalid"; if (static_cast(val) >= static_cast(name::kEnumCount)) return invalid; return k ## name ## ToString[static_cast(val)]; } \ inline bool name ## IsValid(name val) { return static_cast(val) < static_cast(name::kEnumCount); } \ template \ inline void name ## ForEach(const T &consumer) { AU_FOR_EACH_THAT(_AUE_EMIT_CALL, name, _AUE_STRIP_BRACKETS(vals)) } \ static const AuUInt k ## name ## Count = static_cast(name::kEnumCount); \ static const name k ## name ## Invalid = name::kEnumInvalid; \ static const name k ## name ## MaxLegal = static_cast(k ## name ## Count - 1); \ static const name k ## name ## MinLegal = static_cast(0); #elif defined(AU_LANG_C) #define AUE_DEFINE_BODY(name, vals) \ static const char * k ## name ## ToString[(size_ct)(k ## name ## EnumCount)] = { AU_FOR_EACH(_AUE_EMIT_A, _AUE_STRIP_BRACKETS(vals)) }; \ static const name k ## name ## Values[(size_ct)(k ## name ## EnumCount)] = { AU_FOR_EACH_THAT(_AUE_EMIT_E, name, _AUE_STRIP_BRACKETS(vals)) }; \ static name name ## FromString(const char *codename) { AU_FOR_EACH_THAT(_AUE_EMIT_CCHECK, name, _AUE_STRIP_BRACKETS(vals)) return k ## name ## EnumInvalid; } \ static const char * name ## ToString(name val) { static const char * invalid = "kEnumInvalid"; if ((size_ct)(val) >= (size_ct)(k ## name ## EnumCount)) return invalid; return k ## name ## ToString[(size_ct)(val)]; } \ static bool name ## IsValid(name val) { return (size_ct)(val) < (size_ct)(k ## name ## EnumCount); } \ static const size_ct k ## name ## Count = (size_ct)(k ## name ## EnumCount); \ static const name k ## name ## Invalid = k ## name ## EnumInvalid; \ static const name k ## name ## MaxLegal = (name)(k ## name ## Count - 1); \ static const name k ## name ## MinLegal = (name)(0); #endif #define AUE_DEFINE(name, vals) AUE_DEFINE_DECL_LANG(name, vals) AUE_DEFINE_BODY(name, vals) #define AUE_DEFINE_EXT(name, ext, vals) AUE_DEFINE_DECL_EXT(name, vals, ext) AUE_DEFINE_BODY(name, vals) #define AUE_ITERATE(name, index) name index = static_cast(0); static_cast(index) < static_cast(name::kEnumCount); index = static_cast(static_cast(index) + 1)