#include "enum_runtime.h" #include #include #include #include namespace NEnumSerializationRuntime { template [[noreturn]] static void ThrowUndefinedValueException(const TEnumRepresentationType key, const TStringBuf className) { throw yexception() << "Undefined value " << key << " in " << className << ". "; } template const TString& TEnumDescriptionBase::ToString(TRepresentationType key) const { const auto it = Names.find(key); if (Y_LIKELY(it != Names.end())) { return it->second; } ThrowUndefinedValueException(key, ClassName); } template std::pair TEnumDescriptionBase::TryFromString(const TStringBuf name) const { const auto it = Values.find(name); if (it != Values.end()) { return {true, it->second}; } return {false, TRepresentationType()}; } template static typename TContainer::value_type const* FindPtrInSortedContainer(const TContainer& vec, const TNeedle& needle, TGetKey&& getKey) { const auto it = LowerBoundBy(vec.begin(), vec.end(), needle, getKey); if (it == vec.end()) { return nullptr; } if (getKey(*it) != needle) { return nullptr; } return std::addressof(*it); } template std::pair TEnumDescriptionBase::TryFromStringSorted(const TStringBuf name, const TInitializationData& enumInitData) { const auto& vec = enumInitData.ValuesInitializer; const auto* ptr = FindPtrInSortedContainer(vec, name, std::mem_fn(&TEnumStringPair::Name)); if (ptr) { return {true, ptr->Key}; } return {false, TRepresentationType()}; } template std::pair TEnumDescriptionBase::TryFromStringFullScan(const TStringBuf name, const TInitializationData& enumInitData) { const auto& vec = enumInitData.ValuesInitializer; const auto* ptr = FindIfPtr(vec, [&](const auto& item) { return item.Name == name; }); if (ptr) { return {true, ptr->Key}; } return {false, TRepresentationType()}; } [[noreturn]] static void ThrowUndefinedNameException(const TStringBuf name, const TStringBuf className, const TStringBuf allEnumNames) { ythrow yexception() << "Key '" << name << "' not found in enum " << className << ". Valid options are: " << allEnumNames << ". "; } template [[noreturn]] static void ThrowUndefinedNameException(const TStringBuf name, const typename TEnumDescriptionBase::TInitializationData& enumInitData) { auto exc = __LOCATION__ + yexception() << "Key '" << name << "' not found in enum " << enumInitData.ClassName << ". Valid options are: "; const auto& vec = enumInitData.NamesInitializer; for (size_t i = 0; i < vec.size(); ++i) { if (i != 0) { exc << ", "; } exc << '\'' << vec[i].Name << '\''; } exc << ". "; throw exc; } template auto TEnumDescriptionBase::FromString(const TStringBuf name) const -> TRepresentationType { const auto findResult = TryFromString(name); if (Y_LIKELY(findResult.first)) { return findResult.second; } ThrowUndefinedNameException(name, ClassName, AllEnumNames()); } template TEnumRepresentationType TEnumDescriptionBase::FromStringFullScan(const TStringBuf name, const TInitializationData& enumInitData) { const auto findResult = TryFromStringFullScan(name, enumInitData); if (Y_LIKELY(findResult.first)) { return findResult.second; } ThrowUndefinedNameException(name, enumInitData); } template TEnumRepresentationType TEnumDescriptionBase::FromStringSorted(const TStringBuf name, const TInitializationData& enumInitData) { const auto findResult = TryFromStringSorted(name, enumInitData); if (Y_LIKELY(findResult.first)) { return findResult.second; } ThrowUndefinedNameException(name, enumInitData); } template TStringBuf TEnumDescriptionBase::ToStringBuf(TRepresentationType key) const { return this->ToString(key); } template TStringBuf TEnumDescriptionBase::ToStringBufFullScan(const TRepresentationType key, const TInitializationData& enumInitData) { const auto& vec = enumInitData.NamesInitializer; const auto* ptr = FindIfPtr(vec, [&](const auto& item) { return item.Key == key; }); if (Y_UNLIKELY(!ptr)) { ThrowUndefinedValueException(key, enumInitData.ClassName); } return ptr->Name; } template TStringBuf TEnumDescriptionBase::ToStringBufSorted(const TRepresentationType key, const TInitializationData& enumInitData) { const auto& vec = enumInitData.NamesInitializer; const auto* ptr = FindPtrInSortedContainer(vec, key, std::mem_fn(&TEnumStringPair::Key)); if (Y_UNLIKELY(!ptr)) { ThrowUndefinedValueException(key, enumInitData.ClassName); } return ptr->Name; } template TStringBuf TEnumDescriptionBase::ToStringBufDirect(const TRepresentationType key, const TInitializationData& enumInitData) { const auto& vec = enumInitData.NamesInitializer; if (Y_UNLIKELY(vec.empty() || key < vec.front().Key)) { ThrowUndefinedValueException(key, enumInitData.ClassName); } const size_t index = static_cast(key - vec.front().Key); if (Y_UNLIKELY(index >= vec.size())) { ThrowUndefinedValueException(key, enumInitData.ClassName); } return vec[index].Name; } template void TEnumDescriptionBase::Out(IOutputStream* os, const TRepresentationType key) const { (*os) << this->ToStringBuf(key); } template void TEnumDescriptionBase::OutFullScan(IOutputStream* os, const TRepresentationType key, const TInitializationData& enumInitData) { (*os) << ToStringBufFullScan(key, enumInitData); } template void TEnumDescriptionBase::OutSorted(IOutputStream* os, const TRepresentationType key, const TInitializationData& enumInitData) { (*os) << ToStringBufSorted(key, enumInitData); } template void TEnumDescriptionBase::OutDirect(IOutputStream* os, const TRepresentationType key, const TInitializationData& enumInitData) { (*os) << ToStringBufDirect(key, enumInitData); } template TEnumDescriptionBase::TEnumDescriptionBase(const TInitializationData& enumInitData) : ClassName(enumInitData.ClassName) { const TArrayRef& namesInitializer = enumInitData.NamesInitializer; const TArrayRef& valuesInitializer = enumInitData.ValuesInitializer; const TArrayRef& cppNamesInitializer = enumInitData.CppNamesInitializer; TMap mapValueToName; TMap mapNameToValue; for (const TEnumStringPair& it : namesInitializer) { mapValueToName.emplace(it.Key, TString(it.Name)); } for (const TEnumStringPair& it : valuesInitializer) { mapNameToValue.emplace(it.Name, it.Key); } Names = std::move(mapValueToName); Values = std::move(mapNameToValue); AllValues.reserve(Names.size()); for (const auto& it : Names) { if (!AllNames.empty()) { AllNames += ", "; } AllNames += TString::Join('\'', it.second, '\''); AllValues.push_back(it.first); } AllCppNames.reserve(cppNamesInitializer.size()); for (const auto& cn : cppNamesInitializer) { AllCppNames.push_back(TString::Join(enumInitData.CppNamesPrefix, cn)); } } template TEnumDescriptionBase::~TEnumDescriptionBase() = default; // explicit instantiation template class TEnumDescriptionBase; template class TEnumDescriptionBase; template class TEnumDescriptionBase; template class TEnumDescriptionBase; }