Unverified Commit d6ebaac3 authored by Dominik Charousset's avatar Dominik Charousset Committed by GitHub

Merge pull request #927

Auto-generate to_string implementations for enums
parents 2ee64506 539ed0bc
...@@ -97,6 +97,16 @@ function(pretty_yes var) ...@@ -97,6 +97,16 @@ function(pretty_yes var)
endif() endif()
endfunction(pretty_yes) endfunction(pretty_yes)
add_executable(caf-generate-enum-strings cmake/caf-generate-enum-strings.cpp)
function(enum_to_string relative_input_file relative_output_file)
set(input "${CMAKE_CURRENT_SOURCE_DIR}/${relative_input_file}")
set(output "${CMAKE_CURRENT_BINARY_DIR}/${relative_output_file}")
add_custom_command(OUTPUT "${output}"
COMMAND caf-generate-enum-strings "${input}" "${output}"
DEPENDS caf-generate-enum-strings "${input}")
endfunction()
################################################################################ ################################################################################
# set prefix paths if available # # set prefix paths if available #
################################################################################ ################################################################################
......
#include <algorithm>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
using std::cerr;
using std::find;
using std::find_if;
using std::string;
using std::vector;
void trim(string& str) {
auto not_space = [](char c) { return isspace(c) == 0; };
str.erase(str.begin(), find_if(str.begin(), str.end(), not_space));
str.erase(find_if(str.rbegin(), str.rend(), not_space).base(), str.end());
}
template <size_t N>
bool starts_with(const string& str, const char (&prefix)[N]) {
return str.compare(0, N - 1, prefix) == 0;
}
template <size_t N>
void drop_prefix(string& str, const char (&prefix)[N]) {
if (str.compare(0, N - 1, prefix) == 0)
str.erase(str.begin(), str.begin() + (N - 1));
}
void keep_alnum(string& str) {
auto not_alnum = [](char c) { return isalnum(c) == 0 && c != '_'; };
str.erase(find_if(str.begin(), str.end(), not_alnum), str.end());
}
int main(int argc, char** argv) {
if (argc != 3) {
cerr << "wrong number of arguments.\n"
<< "usage: " << argv[0] << "input-file output-file\n";
return EXIT_FAILURE;
}
std::ifstream in{argv[1]};
if (!in) {
cerr << "unable to open input file: " << argv[1] << '\n';
return EXIT_FAILURE;
}
vector<string> namespaces;
string enum_name;
string line;
bool is_enum_class = false;
// Locate the beginning of the enum.
for (;;) {
if (!getline(in, line)) {
cerr << "unable to locate enum in file: " << argv[1] << '\n';
return EXIT_FAILURE;
}
trim(line);
if (starts_with(line, "enum ")) {
drop_prefix(line, "enum ");
if (starts_with(line, "class ")) {
is_enum_class = true;
drop_prefix(line, "class ");
}
trim(line);
keep_alnum(line);
enum_name = line;
break;
}
if (starts_with(line, "namespace ")) {
if (line.back() == '{')
line.pop_back();
line.erase(line.begin(), find(line.begin(), line.end(), ' '));
trim(line);
namespaces.emplace_back(line);
}
}
// Sanity checking.
if (namespaces.empty()) {
cerr << "enum found outside of a namespace\n";
return EXIT_FAILURE;
}
if (enum_name.empty()) {
cerr << "empty enum name found\n";
return EXIT_FAILURE;
}
std::ofstream out{argv[2]};
if (!out) {
cerr << "unable to open output file: " << argv[1] << '\n';
return EXIT_FAILURE;
}
// Print file header.
out << "#include \"" << namespaces[0];
for (size_t i = 1; i < namespaces.size(); ++i)
out << '/' << namespaces[i];
out << '/' << enum_name << ".hpp\"\n\n"
<< "#include <string>\n\n"
<< "namespace " << namespaces[0] << " {\n";
for (size_t i = 1; i < namespaces.size(); ++i)
out << "namespace " << namespaces[i] << " {\n";
out << "\nstd::string to_string(" << enum_name << " x) {\n"
<< " switch(x) {\n"
<< " default:\n"
<< " return \"???\";\n";
// Read until hitting the closing '}'.
std::string case_label_prefix;
if (is_enum_class)
case_label_prefix = enum_name + "::";
for (;;) {
if (!getline(in, line)) {
cerr << "unable to read enum values\n";
return EXIT_FAILURE;
}
trim(line);
if (line.empty())
continue;
if (line[0] == '}')
break;
if (line[0] != '/') {
keep_alnum(line);
out << " case " << case_label_prefix << line << ":\n"
<< " return \"" << line << "\";\n";
}
}
// Done. Print file footer and exit.
out << " };\n"
<< "}\n\n";
for (auto i = namespaces.rbegin(); i != namespaces.rend(); ++i)
out << "} // namespace " << *i << '\n';
}
...@@ -4,8 +4,23 @@ project(caf_core C CXX) ...@@ -4,8 +4,23 @@ project(caf_core C CXX)
# e.g., for creating proper Xcode projects # e.g., for creating proper Xcode projects
file(GLOB_RECURSE LIBCAF_CORE_HDRS "caf/*.hpp") file(GLOB_RECURSE LIBCAF_CORE_HDRS "caf/*.hpp")
enum_to_string("caf/exit_reason.hpp" "exit_reason_strings.cpp")
enum_to_string("caf/intrusive/inbox_result.hpp" "inbox_result_strings.cpp")
enum_to_string("caf/intrusive/task_result.hpp" "task_result_strings.cpp")
enum_to_string("caf/message_priority.hpp" "message_priority_strings.cpp")
enum_to_string("caf/pec.hpp" "pec_strings.cpp")
enum_to_string("caf/sec.hpp" "sec_strings.cpp")
enum_to_string("caf/stream_priority.hpp" "stream_priority_strings.cpp")
# list cpp files excluding platform-dependent files # list cpp files excluding platform-dependent files
set(LIBCAF_CORE_SRCS set(LIBCAF_CORE_SRCS
"${CMAKE_CURRENT_BINARY_DIR}/exit_reason_strings.cpp"
"${CMAKE_CURRENT_BINARY_DIR}/inbox_result_strings.cpp"
"${CMAKE_CURRENT_BINARY_DIR}/message_priority_strings.cpp"
"${CMAKE_CURRENT_BINARY_DIR}/pec_strings.cpp"
"${CMAKE_CURRENT_BINARY_DIR}/sec_strings.cpp"
"${CMAKE_CURRENT_BINARY_DIR}/stream_priority_strings.cpp"
"${CMAKE_CURRENT_BINARY_DIR}/task_result_strings.cpp"
src/abstract_actor.cpp src/abstract_actor.cpp
src/abstract_channel.cpp src/abstract_channel.cpp
src/abstract_composable_behavior.cpp src/abstract_composable_behavior.cpp
...@@ -126,7 +141,6 @@ set(LIBCAF_CORE_SRCS ...@@ -126,7 +141,6 @@ set(LIBCAF_CORE_SRCS
src/skip.cpp src/skip.cpp
src/stream_aborter.cpp src/stream_aborter.cpp
src/stream_manager.cpp src/stream_manager.cpp
src/stream_priority.cpp
src/string_algorithms.cpp src/string_algorithms.cpp
src/string_view.cpp src/string_view.cpp
src/term.cpp src/term.cpp
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <type_traits>
namespace caf {
namespace detail {
/// Converts x to its underlying type and fetches the name from the
/// lookup table. Assumes consecutive enum values.
template <class E, size_t N>
const char* enum_to_string(E x, const char* (&lookup_table)[N]) {
auto index = static_cast<typename std::underlying_type<E>::type>(x);
return index < N ? lookup_table[index] : "<unknown>";
}
} // namespace detail
} // namespace caf
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#pragma once #pragma once
#include <string>
#include "caf/error.hpp" #include "caf/error.hpp"
namespace caf { namespace caf {
...@@ -49,10 +51,9 @@ enum class exit_reason : uint8_t { ...@@ -49,10 +51,9 @@ enum class exit_reason : uint8_t {
}; };
/// Returns a string representation of given exit reason. /// Returns a string representation of given exit reason.
std::string to_string(exit_reason x); std::string to_string(exit_reason);
/// @relates exit_reason /// @relates exit_reason
error make_error(exit_reason); error make_error(exit_reason);
} // namespace caf } // namespace caf
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#pragma once #pragma once
#include <string>
namespace caf { namespace caf {
namespace intrusive { namespace intrusive {
...@@ -34,9 +36,11 @@ enum class inbox_result { ...@@ -34,9 +36,11 @@ enum class inbox_result {
/// Indicates that the enqueue operation failed because the /// Indicates that the enqueue operation failed because the
/// queue has been closed by the reader. /// queue has been closed by the reader.
queue_closed queue_closed,
}; };
/// @relates inbox_result
std::string to_string(inbox_result);
} // namespace intrusive } // namespace intrusive
} // namespace caf } // namespace caf
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#pragma once #pragma once
#include <string>
#include <type_traits> #include <type_traits>
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
...@@ -41,6 +42,9 @@ enum class task_result { ...@@ -41,6 +42,9 @@ enum class task_result {
stop_all, stop_all,
}; };
/// @relates task_result
std::string to_string(task_result);
} // namespace intrusive } // namespace intrusive
} // namespace caf } // namespace caf
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#pragma once #pragma once
#include <cstdint> #include <cstdint>
#include <string>
#include <type_traits> #include <type_traits>
namespace caf { namespace caf {
...@@ -37,5 +38,7 @@ using high_message_priority_constant = std::integral_constant< ...@@ -37,5 +38,7 @@ using high_message_priority_constant = std::integral_constant<
using normal_message_priority_constant = std::integral_constant< using normal_message_priority_constant = std::integral_constant<
message_priority, message_priority::normal>; message_priority, message_priority::normal>;
} // namespace caf /// @relates message_priority
std::string to_string(message_priority);
} // namespace caf
...@@ -78,7 +78,4 @@ error make_error(pec code, size_t line, size_t column); ...@@ -78,7 +78,4 @@ error make_error(pec code, size_t line, size_t column);
/// information for where the parser stopped in the argument. /// information for where the parser stopped in the argument.
error make_error(pec code, string_view argument); error make_error(pec code, string_view argument);
/// @relates pec
const char* to_string(pec x);
} // namespace caf } // namespace caf
...@@ -39,7 +39,6 @@ ...@@ -39,7 +39,6 @@
#include "caf/actor_control_block.hpp" #include "caf/actor_control_block.hpp"
#include "caf/detail/disposer.hpp" #include "caf/detail/disposer.hpp"
#include "caf/detail/enum_to_string.hpp"
#include "caf/detail/shared_spinlock.hpp" #include "caf/detail/shared_spinlock.hpp"
namespace caf { namespace caf {
......
...@@ -20,8 +20,6 @@ ...@@ -20,8 +20,6 @@
#include "caf/duration.hpp" #include "caf/duration.hpp"
#include "caf/detail/enum_to_string.hpp"
namespace caf { namespace caf {
namespace { namespace {
...@@ -47,14 +45,14 @@ const char* time_unit_short_strings[] = { ...@@ -47,14 +45,14 @@ const char* time_unit_short_strings[] = {
} // namespace } // namespace
std::string to_string(time_unit x) { std::string to_string(time_unit x) {
return detail::enum_to_string(x, time_unit_strings); return time_unit_strings[static_cast<uint32_t>(x)];
} }
std::string to_string(const duration& x) { std::string to_string(const duration& x) {
if (x.unit == time_unit::invalid) if (x.unit == time_unit::invalid)
return "infinite"; return "infinite";
auto result = std::to_string(x.count); auto result = std::to_string(x.count);
result += detail::enum_to_string(x.unit, time_unit_short_strings); result += time_unit_short_strings[static_cast<uint32_t>(x.unit)];
return result; return result;
} }
......
...@@ -20,29 +20,8 @@ ...@@ -20,29 +20,8 @@
#include "caf/message.hpp" #include "caf/message.hpp"
#include "caf/detail/enum_to_string.hpp"
namespace caf { namespace caf {
namespace {
const char* exit_reason_strings[] = {
"normal",
"unhandled_exception",
"unknown",
"out_of_workers",
"user_shutdown",
"kill",
"remote_link_unreachable",
"unreachable"
};
} // namespace
std::string to_string(exit_reason x) {
return detail::enum_to_string(x, exit_reason_strings);
}
error make_error(exit_reason x) { error make_error(exit_reason x) {
return {static_cast<uint8_t>(x), atom("exit")}; return {static_cast<uint8_t>(x), atom("exit")};
} }
......
...@@ -23,31 +23,6 @@ ...@@ -23,31 +23,6 @@
#include "caf/make_message.hpp" #include "caf/make_message.hpp"
#include "caf/string_view.hpp" #include "caf/string_view.hpp"
namespace {
constexpr const char* tbl[] = {
"success",
"trailing_character",
"unexpected_eof",
"unexpected_character",
"negative_duration",
"duration_overflow",
"too_many_characters",
"illegal_escape_sequence",
"unexpected_newline",
"integer_overflow",
"integer_underflow",
"exponent_underflow",
"exponent_overflow",
"type_mismatch",
"not_an_option",
"illegal_argument",
"missing_argument",
"illegal_category",
};
} // namespace
namespace caf { namespace caf {
error make_error(pec code) { error make_error(pec code) {
...@@ -69,8 +44,4 @@ error make_error(pec code, string_view argument) { ...@@ -69,8 +44,4 @@ error make_error(pec code, string_view argument) {
make_message(std::move(context))}; make_message(std::move(context))};
} }
const char* to_string(pec x) {
return tbl[static_cast<uint8_t>(x)];
}
} // namespace caf } // namespace caf
...@@ -18,69 +18,8 @@ ...@@ -18,69 +18,8 @@
#include "caf/sec.hpp" #include "caf/sec.hpp"
#include "caf/detail/enum_to_string.hpp"
namespace caf { namespace caf {
namespace {
const char* sec_strings[] = {
"none",
"unexpected_message",
"unexpected_response",
"request_receiver_down",
"request_timeout",
"no_such_group_module",
"no_actor_published_at_port",
"unexpected_actor_messaging_interface",
"state_not_serializable",
"unsupported_sys_key",
"unsupported_sys_message",
"disconnect_during_handshake",
"cannot_forward_to_invalid_actor",
"no_route_to_receiving_node",
"failed_to_assign_scribe_from_handle",
"failed_to_assign_doorman_from_handle",
"cannot_close_invalid_port",
"cannot_connect_to_node",
"cannot_open_port",
"network_syscall_failed",
"invalid_argument",
"invalid_protocol_family",
"cannot_publish_invalid_actor",
"cannot_spawn_actor_from_arguments",
"end_of_stream",
"no_context",
"unknown_type",
"no_proxy_registry",
"runtime_error",
"remote_linking_failed",
"cannot_add_upstream",
"upstream_already_exists",
"invalid_upstream",
"cannot_add_downstream",
"downstream_already_exists",
"invalid_downstream",
"no_downstream_stages_defined",
"stream_init_failed",
"invalid_stream_state",
"unhandled_stream_error",
"bad_function_call",
"feature_disabled",
"cannot_open_file",
"socket_invalid",
"socket_disconnected",
"socket_operation_failed",
"unavailable_or_would_block",
"remote_lookup_failed",
};
} // namespace
std::string to_string(sec x) {
return detail::enum_to_string(x, sec_strings);
}
error make_error(sec x) { error make_error(sec x) {
return {static_cast<uint8_t>(x), atom("system")}; return {static_cast<uint8_t>(x), atom("system")};
} }
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/stream_priority.hpp"
namespace caf {
std::string to_string(stream_priority x) {
switch (x) {
default:
return "invalid";
case stream_priority::very_high:
return "very_high";
case stream_priority::high:
return "high";
case stream_priority::normal:
return "normal";
case stream_priority::low:
return "low";
case stream_priority::very_low:
return "very_low";
}
}
} // namespace caf
...@@ -62,7 +62,6 @@ ...@@ -62,7 +62,6 @@
#include "caf/streambuf.hpp" #include "caf/streambuf.hpp"
#include "caf/variant.hpp" #include "caf/variant.hpp"
#include "caf/detail/enum_to_string.hpp"
#include "caf/detail/get_mac_addresses.hpp" #include "caf/detail/get_mac_addresses.hpp"
#include "caf/detail/ieee_754.hpp" #include "caf/detail/ieee_754.hpp"
#include "caf/detail/int_list.hpp" #include "caf/detail/int_list.hpp"
...@@ -93,13 +92,17 @@ bool operator==(const raw_struct& lhs, const raw_struct& rhs) { ...@@ -93,13 +92,17 @@ bool operator==(const raw_struct& lhs, const raw_struct& rhs) {
enum class test_enum : uint32_t { enum class test_enum : uint32_t {
a, a,
b, b,
c c,
}; };
const char* test_enum_strings[] = { "a", "b", "c" }; const char* test_enum_strings[] = {
"a",
"b",
"c",
};
std::string to_string(test_enum x) { std::string to_string(test_enum x) {
return detail::enum_to_string(x, test_enum_strings); return test_enum_strings[static_cast<uint32_t>(x)];
} }
struct test_array { struct test_array {
......
...@@ -4,14 +4,18 @@ project(caf_io C CXX) ...@@ -4,14 +4,18 @@ project(caf_io C CXX)
# e.g., for creating proper Xcode projects # e.g., for creating proper Xcode projects
file(GLOB_RECURSE LIBCAF_IO_HDRS "caf/*.hpp") file(GLOB_RECURSE LIBCAF_IO_HDRS "caf/*.hpp")
enum_to_string("caf/io/basp/message_type.hpp" "message_type_to_string.cpp")
enum_to_string("caf/io/network/operation.hpp" "operation_to_string.cpp")
# list cpp files excluding platform-dependent files # list cpp files excluding platform-dependent files
set(LIBCAF_IO_SRCS set(LIBCAF_IO_SRCS
"${CMAKE_CURRENT_BINARY_DIR}/message_type_to_string.cpp"
"${CMAKE_CURRENT_BINARY_DIR}/operation_to_string.cpp"
src/detail/socket_guard.cpp src/detail/socket_guard.cpp
src/io/abstract_broker.cpp src/io/abstract_broker.cpp
src/io/basp/header.cpp src/io/basp/header.cpp
src/io/basp/instance.cpp src/io/basp/instance.cpp
src/io/basp/message_queue.cpp src/io/basp/message_queue.cpp
src/io/basp/message_type.cpp
src/io/basp/routing_table.cpp src/io/basp/routing_table.cpp
src/io/basp/worker.cpp src/io/basp/worker.cpp
src/io/basp_broker.cpp src/io/basp_broker.cpp
......
...@@ -28,15 +28,9 @@ namespace network { ...@@ -28,15 +28,9 @@ namespace network {
enum class operation { enum class operation {
read, read,
write, write,
propagate_error propagate_error,
}; };
inline std::string to_string(operation op) {
return op == operation::read ? "read"
: (op == operation::write ? "write"
: "propagate_error");
}
} // namespace network } // namespace network
} // namespace io } // namespace io
} // namespace caf } // namespace caf
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/io/basp/message_type.hpp"
#include "caf/detail/enum_to_string.hpp"
namespace caf {
namespace io {
namespace basp {
namespace {
const char* message_type_strings[] = {
"server_handshake", "client_handshake", "direct_message", "routed_message",
"proxy_creation", "proxy_destruction", "heartbeat",
};
} // namespace
std::string to_string(message_type x) {
return detail::enum_to_string(x, message_type_strings);
}
} // namespace basp
} // namespace io
} // namespace caf
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment