Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions error/v1/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
cmake_minimum_required(VERSION 3.18)

project(error LANGUAGES CXX)

# Import third-party dependencies.
find_package(Boost REQUIRED CONFIG COMPONENTS headers)
find_package(fmt REQUIRED CONFIG)
find_package(GTest REQUIRED CONFIG)

# Enable some compiler warnings (supported by gcc & clang).
set(warnings
-Wall
-Wconversion
-Wextra
-Wformat=2
-Wold-style-cast
-Woverloaded-virtual
-Wshadow
-Wsign-conversion
-Wuninitialized
-Wunused
)
string(REPLACE ";" " " warnings "${warnings}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${warnings}")

add_library(error SHARED)
add_library(caesar::error ALIAS error)

# Require C++17.
target_compile_features(error PUBLIC cxx_std_17)

# Add sources.
set(sources
caesar/error/detail/no_value_policy.cpp
caesar/error/domain_error.cpp
caesar/error/error_category.cpp
caesar/error/error_code.cpp
caesar/error/error.cpp
caesar/error/expected.cpp
caesar/error/out_of_range.cpp
caesar/error/runtime_error.cpp
)
target_sources(error PRIVATE ${sources})

# Add include dirs.
target_include_directories(
error
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>
)

# Link to imported targets.
target_link_libraries(
error
PUBLIC
Boost::headers
PRIVATE
fmt::fmt
)

# Add test sources.
set(tests
test/error_code_test.cpp
test/error_test.cpp
test/expected_test.cpp
)

add_executable(error-test ${tests})

target_link_libraries(
error-test
PRIVATE
caesar::error
GTest::gmock_main
)

# Register tests with CTest.
enable_testing()
include(GoogleTest)
gtest_discover_tests(error-test)
9 changes: 9 additions & 0 deletions error/v1/caesar/error.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once

#include "error/domain_error.hpp"
#include "error/error_category.hpp"
#include "error/error_code.hpp"
#include "error/error.hpp"
#include "error/expected.hpp"
#include "error/out_of_range.hpp"
#include "error/runtime_error.hpp"
1 change: 1 addition & 0 deletions error/v1/caesar/error/detail/no_value_policy.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include "no_value_policy.hpp"
39 changes: 39 additions & 0 deletions error/v1/caesar/error/detail/no_value_policy.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#pragma once

#include "../error.hpp"
#include "../runtime_error.hpp"

#include <boost/outcome/outcome.hpp>

namespace caesar::detail {

namespace outcome = BOOST_OUTCOME_V2_NAMESPACE;

/**
* \private
* A mixin type that defines how invalid access to Expected object members is
* handled
*/
struct NoValuePolicy : public outcome::policy::base {
/** \private Called on each access to Expected::value */
template<class Expected>
static constexpr void
wide_value_check(Expected&& self)
{
if (not base::_has_value(self)) {
base::_error(std::forward<Expected>(self)).throw_exception();
}
}

/** \private Called on each access to Expected::error */
template<class Expected>
static constexpr void
wide_error_check(Expected&& self)
{
if (not base::_has_error(std::forward<Expected>(self))) {
Error(RuntimeError::BadExpectedAccess).throw_exception();
}
}
};

} // namespace caesar::detail
27 changes: 27 additions & 0 deletions error/v1/caesar/error/domain_error.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "domain_error.hpp"

#include "error.hpp"

#include <stdexcept>

namespace caesar {

const char*
DomainErrorCategory::description(int value) const noexcept
{
const auto e = static_cast<ErrorCodeEnum>(value);

switch (e) {
case DomainError::DivisionByZero: return "Division by zero";
}

return "<unknown>";
}

void
DomainErrorCategory::throw_exception(const Error& error) const
{
throw std::domain_error(error.message());
}

} // namespace caesar
62 changes: 62 additions & 0 deletions error/v1/caesar/error/domain_error.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#pragma once

#include "error_category.hpp"
#include "error_code.hpp"

namespace caesar {

/**
* Error code used to indicate domain errors, i.e. situations where the inputs
* are outside of the domain on which an operation is defined.
*
* \see DomainErrorCategory
* \see ErrorCode
*/
enum class DomainError {
DivisionByZero = 1,
};

/**
* Error category associated with domain errors
*
* \see DomainError
* \see ErrorCategory
*/
class DomainErrorCategory : public ErrorCategory {
using Base = ErrorCategory;

public:
/** The associated error code enumeration type */
using ErrorCodeEnum = DomainError;

/** \copydoc ErrorCategory::name() */
const char*
name() const noexcept override
{
return "DomainError";
}

/** \copydoc ErrorCategory::description(int) */
const char*
description(int value) const noexcept override;

/** \copydoc ErrorCategory::throw_exception(const Error&) */
[[noreturn]] void
throw_exception(const Error& error) const override;
};

/** Singleton instance of the class */
static constexpr DomainErrorCategory domain_error_category;

/** \private Enables implicit construction of ErrorCode from DomainError */
template<>
struct IsErrorCodeEnum<DomainError> : public std::true_type {};

/** \private Enables implicit construction of ErrorCode from DomainError */
constexpr ErrorCode
make_error_code(DomainError e) noexcept
{
return {static_cast<int>(e), &domain_error_category};
}

} // namespace caesar
21 changes: 21 additions & 0 deletions error/v1/caesar/error/error.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include "error.hpp"

#include <fmt/core.h>

namespace caesar {

std::string
Error::message() const
{
return fmt::format("{}:{}: {}: {}", file(), line(),
error_code().category()->name(),
error_code().description());
}

void
Error::throw_exception() const
{
error_code().category()->throw_exception(*this);
}

} // namespace caesar
85 changes: 85 additions & 0 deletions error/v1/caesar/error/error.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#pragma once

#include "error_code.hpp"

#include <experimental/source_location>
#include <string>

namespace caesar {

/**
* Encapsulates an error code as well as contextual information about its point
* of origin
*
* \see ErrorCategory
* \see ErrorCode
*/
class Error {
using source_location = std::experimental::source_location;

public:
/**
* Construct a new Error object.
*
* \param[in] error_code error code
* \param[in] file source file where the error originated
* \param[in] line source line where the error originated
*/
constexpr Error(const ErrorCode& error_code,
const char* file,
int line) noexcept
: error_code_(error_code), file_(file), line_(line)
{}

/**
* Construct a new Error object.
*
* \param[in] error_code error code
* \param[in] origin source location where the error originated
*/
explicit constexpr Error(
const ErrorCode& error_code,
const source_location& origin = source_location::current()) noexcept
: Error(error_code, origin.file_name(), static_cast<int>(origin.line()))
{}

/** Return the error code. */
constexpr const ErrorCode&
error_code() const noexcept
{
return error_code_;
}

/** Return the source file where the error originated. */
constexpr const char*
file() const noexcept
{
return file_;
}

/** Return the source line where the error originated. */
constexpr int
line() const noexcept
{
return line_;
}

/** Return an explanatory message. */
std::string
message() const;

/** Throw an exception object corresponding to the error. */
void
throw_exception() const;

// XXX boost/outcome requires error types to be default-constructible :(
// this constraint is removed in boost v1.76
Error() = default;

private:
ErrorCode error_code_;
const char* file_;
int line_;
};

} // namespace caesar
1 change: 1 addition & 0 deletions error/v1/caesar/error/error_category.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#include "error_category.hpp"
Loading