Skip to content
Snippets Groups Projects
Commit e5010408 authored by Daniel Hornung's avatar Daniel Hornung
Browse files

ENH: New functions getEnumNameFromValue() and getEnumValueFromName()

parent a34f7beb
No related branches found
No related tags found
2 merge requests!14ENH: New functions getEnumNameFromValue() and getEnumValueFromName(),!12F consolidation
Pipeline #12221 failed
......@@ -46,9 +46,9 @@ class Entity;
class Property;
// Atomic data types.
enum AtomicDataType {
enum class AtomicDataType {
// The data type is unset/unknown.
UNSPECIFIED_DATA_TYPE = ProtoAtomicDataType::ATOMIC_DATA_TYPE_UNSPECIFIED,
UNSPECIFIED = ProtoAtomicDataType::ATOMIC_DATA_TYPE_UNSPECIFIED,
// TEXT data type.
TEXT = ProtoAtomicDataType::ATOMIC_DATA_TYPE_TEXT,
// DOUBLE data type.
......@@ -61,6 +61,17 @@ enum AtomicDataType {
BOOLEAN = ProtoAtomicDataType::ATOMIC_DATA_TYPE_BOOLEAN,
};
const std::map<AtomicDataType, std::string> atomicdatatype_names =
{
{AtomicDataType::UNSPECIFIED, "UNSPECIFIED"},
{AtomicDataType::TEXT, "TEXT"},
{AtomicDataType::DOUBLE, "DOUBLE"},
{AtomicDataType::DATETIME, "DATETIME"},
{AtomicDataType::INTEGER, "INTEGER"},
{AtomicDataType::BOOLEAN, "BOOLEAN"}
};
class DataType;
class ListDataType;
......
......@@ -73,27 +73,43 @@ static const std::string logger_name = "caosdb::entity";
/**
* The property importance.
*/
enum Importance {
IMPORTANCE_UNSPECIFIED =
ProtoImportance::IMPORTANCE_UNSPECIFIED, ///< Unset/None
enum class Importance {
UNSPECIFIED =
ProtoImportance::IMPORTANCE_UNSPECIFIED, ///< Unset/None
OBLIGATORY =
ProtoImportance::IMPORTANCE_OBLIGATORY, ///< Obligatory importance.
ProtoImportance::IMPORTANCE_OBLIGATORY, ///< Obligatory importance.
RECOMMENDED =
ProtoImportance::IMPORTANCE_RECOMMENDED, ///< Recommended importance.
ProtoImportance::IMPORTANCE_RECOMMENDED, ///< Recommended importance.
SUGGESTED = ProtoImportance::IMPORTANCE_SUGGESTED, ///< Suggested importance.
FIX = ProtoImportance::IMPORTANCE_FIX, ///< Fix importance.
};
const std::map<Importance, std::string> importance_names =
{
{Importance::UNSPECIFIED, "UNSPECIFIED"},
{Importance::OBLIGATORY, "OBLIGATORY"},
{Importance::RECOMMENDED, "RECOMMENDED"},
{Importance::SUGGESTED, "SUGGESTED"},
{Importance::FIX, "FIX"}
};
/**
* The entity role.
*/
enum Role {
ROLE_UNSPECIFIED = EntityRole::ENTITY_ROLE_UNSPECIFIED, ///< Unset/None
enum class Role {
UNSPECIFIED = EntityRole::ENTITY_ROLE_UNSPECIFIED, ///< Unset/None
RECORD_TYPE = EntityRole::ENTITY_ROLE_RECORD_TYPE, ///< RecordType
RECORD = EntityRole::ENTITY_ROLE_RECORD, ///< Record
PROPERTY = EntityRole::ENTITY_ROLE_PROPERTY, ///< Property
FILE = EntityRole::ENTITY_ROLE_FILE, ///< File
};
const std::map<Role, std::string> role_names =
{
{Role::UNSPECIFIED, "UNSPECIFIED"},
{Role::RECORD_TYPE, "RECORD_TYPE"},
{Role::RECORD, "RECORD"},
{Role::PROPERTY, "PROPERTY"},
{Role::FILE, "FILE"}
};
struct FileDescriptor {
FileTransmissionId *file_transmission_id;
......
......@@ -21,20 +21,25 @@
#ifndef CAOSDB_UTILS_H
#define CAOSDB_UTILS_H
#include "caosdb/entity.h"
#include "caosdb/data_type.h"
#include <boost/beast/core/detail/base64.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/filesystem/string_file.hpp>
#include <boost/lexical_cast.hpp> // for lexical_cast
#include <boost/json.hpp>
#include <cassert>
#include <cstdlib>
#include <exception> // for logic_error
#include <fstream>
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <string_view>
#include <mutex>
#include <shared_mutex>
#include <string>
#include <string_view>
namespace caosdb::utility {
using boost::filesystem::exists;
......@@ -43,6 +48,49 @@ using boost::filesystem::path;
using boost::json::stream_parser;
using boost::json::value;
/**
* @brief Get the name of the enum value. May be useful for higher-order CaosDB clients.
*/
template <typename Enum>
auto getEnumNameFromValue(Enum v) -> std::string {
if (std::is_same_v<std::underlying_type_t<Enum>, int >) {
return boost::lexical_cast<std::string>(static_cast<int>(v));
}
throw std::logic_error(std::string("Enum type ") + typeid(v).name() + " not implemented.");
}
// Forward declaration of specializations
template <>
auto getEnumNameFromValue<caosdb::entity::AtomicDataType>(caosdb::entity::AtomicDataType v)
-> std::string;
template <>
auto getEnumNameFromValue<caosdb::entity::Importance>(caosdb::entity::Importance v)
-> std::string;
template <>
auto getEnumNameFromValue<caosdb::entity::Role>(caosdb::entity::Role v)
-> std::string;
/**
* @brief Get the enum value from a string.
*
* @detail May be useful for higher-order CaosDB clients and only makes sense if specialized.
*/
template <typename Enum>
auto getEnumValueFromName(const std::string &name) -> Enum {
throw std::logic_error(std::string("Enum type ") + typeid(Enum).name() + " not implemented.");
}
// Forward declaration of specializations
template <>
auto getEnumValueFromName<caosdb::entity::AtomicDataType>(const std::string &name)
-> caosdb::entity::AtomicDataType;
template <>
auto getEnumValueFromName<caosdb::entity::Importance>(const std::string &name)
-> caosdb::entity::Importance;
template <>
auto getEnumValueFromName<caosdb::entity::Role>(const std::string &name)
-> caosdb::entity::Role;
/**
* @brief Read a text file into a string and return the file's content.
*/
......
......@@ -29,6 +29,7 @@ set(libcaosdb_SRC
${CMAKE_CURRENT_SOURCE_DIR}/caosdb/protobuf_helper.cpp
${CMAKE_CURRENT_SOURCE_DIR}/caosdb/transaction.cpp
${CMAKE_CURRENT_SOURCE_DIR}/caosdb/transaction_handler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/caosdb/utility.cpp
${CMAKE_CURRENT_SOURCE_DIR}/caosdb/unary_rpc_handler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/caosdb/file_transmission/register_file_upload_handler.cpp
${CMAKE_CURRENT_SOURCE_DIR}/caosdb/file_transmission/upload_request_handler.cpp
......
/*
* This file is a part of the CaosDB Project.
*
* Copyright (C) 2021 Daniel Hornung <d.hornung@indiscale.com>
* Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "caosdb/data_type.h"
#include "caosdb/entity.h"
#include "caosdb/utility.h"
#include <algorithm>
namespace caosdb::utility {
using caosdb::entity::AtomicDataType;
using caosdb::entity::Importance;
using caosdb::entity::Role;
// using emap = std::map<int, std::string>; // enum mapping
// Enum helper template specializations //////////////////////////////////////
template <>
auto getEnumNameFromValue<Importance>(Importance v) -> std::string {
auto result = caosdb::entity::importance_names.at(v);
return result;
}
template <>
auto getEnumNameFromValue<Role>(Role v) -> std::string {
auto result = caosdb::entity::role_names.at(v);
return result;
}
template <>
auto getEnumNameFromValue<AtomicDataType>(AtomicDataType v) -> std::string {
auto result = caosdb::entity::atomicdatatype_names.at(v);
return result;
}
template <>
auto getEnumValueFromName<Importance>(const std::string &name) -> Importance {
// TODO (dh): Why does this compile?
// if (caosdb::entity::importance_names.begin()->second == name) {}
// std::for_each(caosdb::entity::importance_names.begin(),
// caosdb::entity::importance_names.end(),
// [](const auto &entry){});
// TODO (dh): Whereas this does not?
// auto result = std::find(caosdb::entity::importance_names.cbegin(),
// caosdb::entity::importance_names.cend(),
// [name](const auto& entry){ return entry.second == name; });
// Workaround: plaint old iteration:
for (auto entry: caosdb::entity::importance_names) {
if (entry.second == name) {
return entry.first;
}
}
throw std::out_of_range(std::string("Could not find enum value for string '") + name + "'.");
}
template <>
auto getEnumValueFromName<AtomicDataType>(const std::string &name) -> AtomicDataType {
for (auto entry: caosdb::entity::atomicdatatype_names) {
if (entry.second == name) {
return entry.first;
}
}
throw std::out_of_range(std::string("Could not find enum value for string '") + name + "'.");
}
template <>
auto getEnumValueFromName<Role>(const std::string &name) -> Role {
for (auto entry: caosdb::entity::role_names) {
if (entry.second == name) {
return entry.first;
}
}
throw std::out_of_range(std::string("Could not find enum value for string '") + name + "'.");
}
// End of template specialization /////////////////////////////////////////////
} // namespace caosdb::utility
......@@ -24,6 +24,8 @@
#include "boost/beast/core/detail/base64.hpp" // for encoded_size
#include "boost/json/object.hpp" // for object
#include "boost/json/value.hpp" // for value
#include "caosdb/entity.h" // for importance_names, role...
#include "caosdb/data_type.h" // for atomicdatatype_names
#include "caosdb/utility.h" // for base64_encode, load_js...
#include "caosdb_test_utility.h" // for TEST_DATA_DIR
#include <gtest/gtest-message.h> // for Message
......@@ -53,4 +55,29 @@ TEST(test_utility, test_load_json_file) {
EXPECT_THAT(sub["see?"].as_array(), ElementsAre(true, false));
}
TEST(test_utility, enum_names) {
// All working enums
for (auto entry : caosdb::entity::importance_names) {
EXPECT_EQ(getEnumNameFromValue<caosdb::entity::Importance>(entry.first), entry.second);
EXPECT_EQ(getEnumValueFromName<caosdb::entity::Importance>(entry.second), entry.first);
}
for (auto entry : caosdb::entity::role_names) {
EXPECT_EQ(getEnumNameFromValue<caosdb::entity::Role>(entry.first), entry.second);
EXPECT_EQ(getEnumValueFromName<caosdb::entity::Role>(entry.second), entry.first);
}
for (auto entry : caosdb::entity::atomicdatatype_names) {
EXPECT_EQ(getEnumNameFromValue<caosdb::entity::AtomicDataType>(entry.first), entry.second);
EXPECT_EQ(getEnumValueFromName<caosdb::entity::AtomicDataType>(entry.second), entry.first);
}
// Some non-working examples
EXPECT_THROW_MESSAGE(getEnumValueFromName<caosdb::entity::Importance>("Invalid name"),
std::out_of_range,
"Could not find enum value for string 'Invalid name'.");
enum e1 {a};
EXPECT_THROW_STARTS_WITH(getEnumNameFromValue<e1>(a), std::logic_error, "Enum type ");
EXPECT_THROW_STARTS_WITH(getEnumValueFromName<e1>("Hello!"), std::logic_error, "Enum type ");
}
} // namespace caosdb::utility
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment