EnumValues.h 1.7 KB
Newer Older
A
Anton Popov 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
#pragma once

#include <Common/HashTable/HashMap.h>
#include <unordered_map>

namespace DB
{

namespace ErrorCodes
{
    extern const int BAD_ARGUMENTS;
}

template <typename T>
class EnumValues
{
public:
    using Value = std::pair<std::string, T>;
    using Values = std::vector<Value>;
    using NameToValueMap = HashMap<StringRef, T, StringRefHash>;
    using ValueToNameMap = std::unordered_map<T, StringRef>;

private:
    Values values;
    NameToValueMap name_to_value_map;
    ValueToNameMap value_to_name_map;

    void fillMaps();

public:
    EnumValues(const Values & values_);

    const Values & getValues() const { return values; }

    auto findByValue(const T & value) const
    {
        const auto it = value_to_name_map.find(value);
        if (it == std::end(value_to_name_map))
            throw Exception{"Unexpected value " + toString(value) + " in enum", ErrorCodes::BAD_ARGUMENTS};

        return it;
    }

    const StringRef & getNameForValue(const T & value) const
    {
        return findByValue(value)->second;
    }

    T getValue(StringRef field_name, bool try_treat_as_id = false) const;

    template <typename TValues>
    bool containsAll(const TValues & rhs_values) const
    {
        auto check = [&](const auto & value)
        {
            auto it = name_to_value_map.find(value.first);
            /// If we don't have this name, than we have to be sure,
            /// that this value exists in enum
            if (it == name_to_value_map.end())
                return value_to_name_map.count(value.second) > 0;

            /// If we have this name, than it should have the same value
            return it->value.second == value.second;
        };

        return std::all_of(rhs_values.begin(), rhs_values.end(), check);
    }
};

}