Huge refactor: use util::exception everywhere instead of std exceptions

This commit is contained in:
Nikita Lisitsa 2023-08-06 18:33:07 +03:00
parent 2bff6d6cf3
commit 85d7a0ca33
59 changed files with 357 additions and 326 deletions

View file

@ -1,6 +1,7 @@
#pragma once
#include <psemek/util/function.hpp>
#include <psemek/util/exception.hpp>
#include <atomic>
#include <mutex>
@ -60,15 +61,19 @@ namespace psemek::async
}
struct empty_future_error
: std::exception
: util::exception
{
char const * what() const noexcept { return "future is empty"; }
empty_future_error(boost::stacktrace::stacktrace stacktrace = {})
: util::exception("Future is empty", std::move(stacktrace))
{}
};
struct canceled_task_error
: std::exception
: util::exception
{
char const * what() const noexcept { return "task canceled"; }
canceled_task_error(boost::stacktrace::stacktrace stacktrace = {})
: util::exception("Task canceled", std::move(stacktrace))
{}
};
struct auto_cancel_tag{};
@ -177,15 +182,19 @@ namespace psemek::async
};
struct empty_promise_error
: std::exception
: util::exception
{
char const * what() const noexcept { return "promise is empty"; }
empty_promise_error(boost::stacktrace::stacktrace stacktrace = {})
: util::exception("Promise is empty", std::move(stacktrace))
{}
};
struct satisfied_promise_error
: std::exception
: util::exception
{
char const * what() const noexcept { return "promise already contains a value or exception"; }
satisfied_promise_error(boost::stacktrace::stacktrace stacktrace = {})
: util::exception("Promise already contains a value or exception", std::move(stacktrace))
{}
};
template <typename T>

View file

@ -1,4 +1,5 @@
#include <psemek/async/synchronous_executor.hpp>
#include <psemek/util/exception.hpp>
#include <stdexcept>
@ -12,7 +13,7 @@ namespace psemek::async
void synchronous_executor::post_at(clock::time_point, task)
{
throw std::runtime_error("synchronous_executor doesn't support executor::post_at");
throw util::exception("Synchronous_executor doesn't support executor::post_at");
}
void synchronous_executor::stop()

View file

@ -1,4 +1,5 @@
#include <psemek/audio/recorder.hpp>
#include <psemek/util/exception.hpp>
#include <vector>
@ -78,7 +79,7 @@ namespace psemek::audio
std::shared_ptr<track> record(stream_ptr stream)
{
if (!stream->length())
throw std::runtime_error("cannot record an infinite stream");
throw util::exception("Cannot record an infinite stream");
return record(stream, *stream->length());
}

View file

@ -1,4 +1,5 @@
#include <psemek/audio/track.hpp>
#include <psemek/util/exception.hpp>
#include <atomic>
@ -82,14 +83,14 @@ namespace psemek::audio
track_ptr load_raw(util::span<float const> samples)
{
if ((samples.size() % 2) != 0)
throw std::runtime_error("bad sample count");
throw util::exception("Sample count must be even");
return std::make_shared<raw_track_impl>(std::make_shared<data_holder>(samples));
}
track_ptr load_raw(std::vector<float> samples)
{
if ((samples.size() % 2) != 0)
throw std::runtime_error("bad sample count");
throw util::exception("Sample count must be even");
return std::make_shared<raw_track_impl>(std::make_shared<data_holder>(std::move(samples)));
}

View file

@ -3,6 +3,7 @@
#include <psemek/audio/detail/resampler.hpp>
#include <psemek/util/to_string.hpp>
#include <psemek/util/at_scope_exit.hpp>
#include <psemek/util/exception.hpp>
#ifdef __GNUC__
#pragma GCC diagnostic push
@ -24,7 +25,7 @@ namespace psemek::audio
std::vector<float> convert_audio(std::vector<std::vector<float>> const & channels, int frequency)
{
if (channels.empty() || channels.size() > 2)
throw std::runtime_error(util::to_string("Can't convert audio with ", static_cast<int>(channels.size()), " channels"));
throw util::exception(util::to_string("Can't convert audio with ", static_cast<int>(channels.size()), " channels"));
std::vector<float> result(channels[0].size() * 2);
auto out = result.begin();
@ -66,7 +67,7 @@ namespace psemek::audio
AudioFile<float> audio_file;
audio_file.shouldLogErrorsToConsole(false);
audio_file.onError = [](std::string const & error) {
throw std::runtime_error("failed to load WAV file: " + error);
throw util::exception("Failed to load WAV file: " + error);
};
audio_file.loadFromMemory(data_u8);

View file

@ -1,9 +1,10 @@
#include <psemek/fonts/bmfont.hpp>
#include <psemek/util/to_string.hpp>
#include <psemek/util/exception.hpp>
#include <boost/preprocessor/stringize.hpp>
#define RAPIDJSON_ASSERT(x) if (!(x)) throw ::std::runtime_error("Error parsing font description: " BOOST_PP_STRINGIZE(x));
#define RAPIDJSON_ASSERT(x) if (!(x)) throw ::psemek::util::exception("Error parsing font description: " BOOST_PP_STRINGIZE(x));
#define RAPIDJSON_NOEXCEPT_ASSERT(x)
#include <rapidjson/document.h>
@ -53,7 +54,7 @@ namespace psemek::fonts
document.ParseInsitu(description_str.data());
if (document.HasParseError())
throw std::runtime_error(util::to_string("Error msdf font description: ", to_string(document.GetParseError()), " at ", document.GetErrorOffset()));
throw util::exception(util::to_string("Error msdf font description: ", to_string(document.GetParseError()), " at ", document.GetErrorOffset()));
bmfont_data result;

View file

@ -1,6 +1,7 @@
#include <psemek/fonts/kerned_font.hpp>
#include <psemek/util/unicode.hpp>
#include <psemek/util/exception.hpp>
namespace psemek::fonts
{
@ -10,9 +11,9 @@ namespace psemek::fonts
, atlas_{std::move(atlas)}
{
if (!supports_character('?'))
throw std::runtime_error("Kerned font must support '?' character");
throw util::exception("Kerned font must support '?' character");
if (!supports_character(' '))
throw std::runtime_error("Kerned font must support ' ' character");
throw util::exception("Kerned font must support ' ' character");
std::vector<char32_t> chars;
for (auto const & g : data_.glyphs)

View file

@ -1,6 +1,7 @@
#include <psemek/fonts/monospace_font.hpp>
#include <psemek/util/unicode.hpp>
#include <psemek/util/exception.hpp>
namespace psemek::fonts
{
@ -13,10 +14,10 @@ namespace psemek::fonts
, texcoords_{std::move(texcoords)}
{
if (range_.end - range_.begin != texcoords_.size())
throw std::runtime_error("Wrong number of texture coordinates");
throw util::exception("Wrong number of texture coordinates");
if (!supports_character('?'))
throw std::runtime_error("Monospace font must support '?' character");
throw util::exception("Monospace font must support '?' character");
}
static geom::vector<float, 2> advance_dir(shape_options::direction_t direction)

View file

@ -1,6 +1,7 @@
#pragma once
#include <psemek/geom/point.hpp>
#include <psemek/util/exception.hpp>
#include <vector>
#include <stdexcept>
@ -30,7 +31,7 @@ namespace psemek::geom
: points_(std::move(points))
{
if (points_.empty())
throw std::runtime_error("Points array should be non-empty");
throw util::exception("Points array should be non-empty");
temp_.resize(points_.size());
}

View file

@ -1,17 +1,16 @@
#pragma once
#include <exception>
#include <psemek/util/exception.hpp>
namespace psemek::geom::detail
{
struct empty_array_exception
: std::exception
: util::exception
{
char const * what() const noexcept
{
return "Attempt to index a zero vector";
}
empty_array_exception(boost::stacktrace::stacktrace stacktrace = {})
: util::exception("Indexing an empty array", std::move(stacktrace))
{}
};
template <typename T, std::size_t N>

View file

@ -4,6 +4,7 @@
#include <psemek/geom/scale.hpp>
#include <psemek/geom/rotation.hpp>
#include <psemek/geom/translation.hpp>
#include <psemek/util/exception.hpp>
#include <algorithm>
@ -149,7 +150,7 @@ namespace psemek::gfx
);
}
default:
throw std::runtime_error("unsupported glTF animation interpolation type");
throw util::exception("Unknown glTF animation interpolation type");
}
}

View file

@ -1,4 +1,5 @@
#include <psemek/gfx/dither.hpp>
#include <psemek/util/exception.hpp>
namespace psemek::gfx
{
@ -25,7 +26,7 @@ namespace psemek::gfx
basic_pixmap<std::uint8_t> ordered_dither(std::size_t size)
{
if (size > 16)
throw std::runtime_error("8-bit dither map cannot be larger than 16x16");
throw util::exception("8-bit dither map cannot be larger than 16x16");
basic_pixmap<std::uint8_t> result({size, size});

View file

@ -1,6 +1,7 @@
#include <psemek/gfx/error.hpp>
#include <psemek/gfx/gl.hpp>
#include <psemek/util/to_string.hpp>
#include <psemek/util/exception.hpp>
#include <stdexcept>
@ -31,8 +32,8 @@ namespace psemek::gfx
auto e = gl::GetError();
if (e != gl::GetError())
throw std::runtime_error(util::to_string(context, gl_error_str(e)));
if (e != gl::NO_ERROR)
throw util::exception(util::to_string(context, gl_error_str(e)));
}
}

View file

@ -1,6 +1,7 @@
#include <psemek/gfx/framebuffer.hpp>
#include <psemek/util/to_string.hpp>
#include <psemek/util/exception.hpp>
namespace psemek::gfx
{
@ -209,7 +210,7 @@ namespace psemek::gfx
void framebuffer::assert_complete(std::string_view name) const
{
if (auto s = status(); s != gl::FRAMEBUFFER_COMPLETE)
throw std::runtime_error(util::to_string("Framebuffer ", name, name.empty() ? "" : " ", "incomplete: ", framebuffer_status_string(s)));
throw util::exception(util::to_string("Framebuffer ", name, name.empty() ? "" : " ", "incomplete: ", framebuffer_status_string(s)));
}
framebuffer::framebuffer(std::nullptr_t)

View file

@ -3,11 +3,12 @@
#include <psemek/geom/rotation.hpp>
#include <psemek/geom/translation.hpp>
#include <psemek/util/to_string.hpp>
#include <psemek/util/exception.hpp>
#include <psemek/log/log.hpp>
#include <boost/preprocessor/stringize.hpp>
#define RAPIDJSON_ASSERT(x) if (!(x)) throw ::std::runtime_error("Error parsing glTF: " BOOST_PP_STRINGIZE(x));
#define RAPIDJSON_ASSERT(x) if (!(x)) throw ::psemek::util::exception("Error parsing glTF: " BOOST_PP_STRINGIZE(x));
#define RAPIDJSON_NOEXCEPT_ASSERT(x)
#include <rapidjson/document.h>
@ -65,7 +66,7 @@ namespace psemek::gfx
return gltf_asset::accessor::mat3;
if (type == "MAT4")
return gltf_asset::accessor::mat4;
throw std::runtime_error(util::to_string("Unknown accessor component type: ", type));
throw util::exception(util::to_string("Unknown accessor component type: ", type));
}
static std::unordered_set<std::string> supported_extensions =
@ -126,14 +127,14 @@ namespace psemek::gfx
document.ParseInsitu(description_str.data());
if (document.HasParseError())
throw std::runtime_error(util::to_string("Error parsing glTF: ", to_string(document.GetParseError()), " at ", document.GetErrorOffset()));
throw util::exception(util::to_string("Error parsing glTF: ", to_string(document.GetParseError()), " at ", document.GetErrorOffset()));
gltf_asset result;
if (document.HasMember("extensionsRequired"))
for (auto const & extension : document["extensionsRequired"].GetArray())
if (!supported_extensions.contains(extension.GetString()))
throw std::runtime_error("glTF extension " + std::string(extension.GetString()) + " is not supported");
throw util::exception("glTF extension " + std::string(extension.GetString()) + " is not supported");
if (document.HasMember("nodes")) for (auto const & node : document["nodes"].GetArray())
{
@ -323,7 +324,7 @@ namespace psemek::gfx
else if (path == "translation")
channel_target.path = gltf_asset::animation::channel::translation;
else
throw std::runtime_error("Unknown glTF animation target path: " + path);
throw util::exception("Unknown glTF animation target path: " + path);
}
for (auto const & sampler : animation["samplers"].GetArray())
@ -341,7 +342,7 @@ namespace psemek::gfx
else if (interpolation == "CUBICSPLINE")
sampler_target.interpolation = geom::easing_type::cubic;
else
throw std::runtime_error("Unknown glTF animation interpolation type: " + interpolation);
throw util::exception("Unknown glTF animation interpolation type: " + interpolation);
}
}
@ -401,7 +402,7 @@ namespace psemek::gfx
else if (type == "spot")
target.type = gltf_asset::light::spot;
else
throw std::runtime_error("unknown light type: " + type);
throw util::exception("Unknown light type: " + type);
if (light.HasMember("color"))
{
@ -459,7 +460,7 @@ namespace psemek::gfx
case type_t::vec2: return 2;
case type_t::vec3: return 3;
case type_t::vec4: return 4;
default: throw std::runtime_error("unsupported attribute type");
default: throw util::exception("Unsupported attribute type");
}
}

View file

@ -1,6 +1,7 @@
#include <psemek/gfx/init.hpp>
#include <psemek/gfx/gl.hpp>
#include <psemek/log/log.hpp>
#include <psemek/util/exception.hpp>
namespace psemek::gfx
{
@ -8,7 +9,7 @@ namespace psemek::gfx
void init()
{
if (!gl::sys::initialize())
throw std::runtime_error("Failed to load OpenGL functions");
throw util::exception("Failed to load OpenGL functions");
auto vendor = gl::GetString(gl::VENDOR);
auto renderer = gl::GetString(gl::RENDERER);

View file

@ -2,6 +2,7 @@
#include <psemek/util/to_string.hpp>
#include <psemek/util/binary_stream.hpp>
#include <psemek/util/exception.hpp>
namespace psemek::gfx
{
@ -127,7 +128,7 @@ namespace psemek::gfx
case gl::UNSIGNED_BYTE: return 1;
case gl::UNSIGNED_SHORT: return 2;
case gl::UNSIGNED_INT: return 4;
default: throw std::runtime_error("Unknown undex type");
default: throw util::exception("Unknown undex type");
}
}
@ -291,7 +292,7 @@ namespace psemek::gfx
auto pose_count = s.read<std::uint32_t>();
if (pose_count != result.bones.size())
throw std::runtime_error("Number of transforms in a pose must be equal to the number of bones");
throw util::exception("Number of transforms in a pose must be equal to the number of bones");
auto pose_ptr = s.read_ptr<bone_transform<float>>(pose_count);
std::string_view name(name_ptr, name_length);
@ -310,32 +311,32 @@ namespace psemek::gfx
{
case SECTION_MESH:
if (had_section_mesh)
throw std::runtime_error("Section 'mesh' must not repeat");
throw util::exception("Section 'mesh' must not repeat");
parse_section_mesh();
had_section_mesh = true;
break;
case SECTION_BONES:
if (had_section_bones)
throw std::runtime_error("Section 'bones' must not repeat");
throw util::exception("Section 'bones' must not repeat");
if (!had_section_mesh)
throw std::runtime_error("Section 'bones' must come after section 'mesh'");
throw util::exception("Section 'bones' must come after section 'mesh'");
if ((vertex_format & WEIGHTS_MASK) == 0)
throw std::runtime_error("Section 'bones' requires weights in vertex format");
throw util::exception("Section 'bones' requires weights in vertex format");
parse_section_bones();
had_section_bones = true;
break;
case SECTION_POSE:
if (!had_section_bones)
throw std::runtime_error("Section 'pose' must come after section 'bones'");
throw util::exception("Section 'pose' must come after section 'bones'");
parse_section_pose();
break;
default:
throw std::runtime_error("Unknown section code " + util::to_string(section_type));
throw util::exception("Unknown section code " + util::to_string(section_type));
}
}
if (!had_section_mesh)
throw std::runtime_error("Section 'mesh' must be present");
throw util::exception("Section 'mesh' must be present");
return result;
}

View file

@ -1,4 +1,5 @@
#include <psemek/gfx/pixmap.hpp>
#include <psemek/util/exception.hpp>
#include <iostream>
#include <sstream>
@ -11,7 +12,7 @@ namespace psemek::gfx
{
auto fail = [](std::string str)
{
throw std::runtime_error("Error loading PBM image: " + str);
throw util::exception("Error loading PBM image: " + str);
};
std::string line;
@ -73,7 +74,7 @@ namespace psemek::gfx
{
auto fail = [](std::string str)
{
throw std::runtime_error("Error loading PGM image: " + str);
throw util::exception("Error loading PGM image: " + str);
};
std::string line;
@ -134,7 +135,7 @@ namespace psemek::gfx
{
auto fail = [](std::string str)
{
throw std::runtime_error("Error loading PPM image: " + str);
throw util::exception("Error loading PPM image: " + str);
};
std::string line;

View file

@ -1,5 +1,6 @@
#include <psemek/gfx/obj_parser.hpp>
#include <psemek/util/to_string.hpp>
#include <psemek/util/exception.hpp>
#include <string>
#include <sstream>
@ -20,7 +21,7 @@ namespace psemek::gfx
std::size_t line_count = 0;
auto fail = [&](auto const & ... args){
throw std::runtime_error(util::to_string("Error parsing OBJ data, line ", line_count, ": ", args...));
throw util::exception(util::to_string("Error parsing OBJ data, line ", line_count, ": ", args...));
};
while (std::getline(is >> std::ws, line))

View file

@ -5,6 +5,7 @@
#include <psemek/gfx/resource/font_9x12_png.hpp>
#include <psemek/geom/constants.hpp>
#include <psemek/io/memory_stream.hpp>
#include <psemek/util/enum.hpp>
static const char vertex_source[] =
R"(
@ -290,7 +291,7 @@ namespace psemek::gfx
s = {9.f, 12.f};
break;
default:
throw std::runtime_error("Unknown font");
throw util::unknown_enum_value_exception(f);
}
s[0] *= str.size() * scale;
@ -485,7 +486,7 @@ namespace psemek::gfx
pen[0] -= size[0];
break;
default:
throw std::runtime_error("Unknown x alignment");
throw util::unknown_enum_value_exception(opts.x);
}
switch (opts.y)
@ -499,7 +500,7 @@ namespace psemek::gfx
pen[1] -= size[1];
break;
default:
throw std::runtime_error("Unknown y alignment");
throw util::unknown_enum_value_exception(opts.y);
}
geom::vector<float, 3> const sx = {9.f * opts.scale, 0.f, 0.f};

View file

@ -2,6 +2,7 @@
#include <psemek/log/log.hpp>
#include <psemek/util/at_scope_exit.hpp>
#include <psemek/util/exception.hpp>
#include <png.h>
@ -16,7 +17,7 @@ namespace psemek::gfx
{
png_error_ptr error = [](png_structp, png_const_charp str)
{
throw std::runtime_error(str);
throw util::exception(str);
};
png_error_ptr warn = [](png_structp, png_const_charp str)
@ -25,7 +26,7 @@ namespace psemek::gfx
};
auto png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, error, warn);
if (!png) throw std::runtime_error("png_create_read_struct returned null");
if (!png) throw util::exception("png_create_read_struct returned null");
png_set_error_fn(png, nullptr, error, warn);
@ -37,10 +38,10 @@ namespace psemek::gfx
});
info = png_create_info_struct(png);
if (!info) throw std::runtime_error("png_create_info_struct returned null");
if (!info) throw util::exception("png_create_info_struct returned null");
end_info = png_create_info_struct(png);
if (!end_info) throw std::runtime_error("png_create_info_struct returned null");
if (!end_info) throw util::exception("png_create_info_struct returned null");
png_rw_ptr read = [](png_structp png, png_bytep ptr, size_t count){
reinterpret_cast<io::istream *>(png_get_io_ptr(png))->read(reinterpret_cast<char *>(ptr), count);
@ -58,7 +59,7 @@ namespace psemek::gfx
png_set_strip_16(png);
if (monochrome && color_type != PNG_COLOR_TYPE_GRAY)
throw std::runtime_error("invalid color type for monochrome PNG");
throw util::exception("Invalid color type for monochrome PNG");
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png);
@ -75,7 +76,7 @@ namespace psemek::gfx
auto const row_bytes = png_get_rowbytes(png, info);
if (row_bytes != width * sizeof(Pixel))
throw std::runtime_error("PNG row bytes mismatch");
throw util::exception("PNG row bytes mismatch");
for (std::uint32_t i = 0; i < height; ++i)
png_read_row(png, reinterpret_cast<png_bytep>(result.data() + i * width), nullptr);
@ -87,7 +88,7 @@ namespace psemek::gfx
{
png_error_ptr error = [](png_structp, png_const_charp str)
{
throw std::runtime_error(str);
throw util::exception(str);
};
png_error_ptr warn = [](png_structp, png_const_charp str)
@ -96,7 +97,7 @@ namespace psemek::gfx
};
auto png = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, error, warn);
if (!png) throw std::runtime_error("png_create_write_struct returned null");
if (!png) throw util::exception("png_create_write_struct returned null");
png_set_error_fn(png, nullptr, error, warn);
@ -107,7 +108,7 @@ namespace psemek::gfx
});
info = png_create_info_struct(png);
if (!info) throw std::runtime_error("png_create_info_struct returned null");
if (!info) throw util::exception("png_create_info_struct returned null");
png_rw_ptr write = [](png_structp png, png_bytep ptr, size_t count){
reinterpret_cast<io::ostream *>(png_get_io_ptr(png))->write(reinterpret_cast<char const *>(ptr), count);

View file

@ -2,6 +2,7 @@
#include <psemek/util/to_string.hpp>
#include <psemek/util/at_scope_exit.hpp>
#include <psemek/util/exception.hpp>
#include <memory>
#include <vector>
@ -256,7 +257,7 @@ namespace psemek::gfx
gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &log_len);
std::unique_ptr<char[]> log(new char [log_len]);
gl::GetShaderInfoLog(shader, log_len, nullptr, log.get());
throw std::runtime_error(util::to_string("Shader compilation failed: ", log.get(), "\nShader source: \n", annotated_source(source)));
throw util::exception(util::to_string("Shader compilation failed: ", log.get(), "\nShader source: \n", annotated_source(source)));
}
}
@ -274,7 +275,7 @@ namespace psemek::gfx
gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &log_len);
std::unique_ptr<char[]> log(new char [log_len]);
gl::GetProgramInfoLog(program, log_len, nullptr, log.get());
throw std::runtime_error(util::to_string("Program link failed: ", log.get()));
throw util::exception(util::to_string("Program link failed: ", log.get()));
}
for (auto s : shaders)

View file

@ -27,6 +27,7 @@
#include <psemek/util/to_string.hpp>
#include <psemek/util/hash.hpp>
#include <psemek/util/exception.hpp>
#include <map>
#include <unordered_map>
@ -1079,13 +1080,13 @@ void main(){}
assert(o.mesh);
if (o.mat->lit && o.mat->transparent)
throw std::runtime_error("Materials that are both lit & transparent are not supported");
throw util::exception("Materials that are both lit & transparent are not supported");
if (o.mat->lit && o.mat->blooming)
throw std::runtime_error("Materials that are both lit & blooming are not supported");
throw util::exception("Materials that are both lit & blooming are not supported");
if (o.mat->casts_shadow && o.mat->transparent)
throw std::runtime_error("Transparent objects cannot cast shadow");
throw util::exception("Transparent objects cannot cast shadow");
auto c = o.bbox.center() - all_bbox.corner(0, 0, 0);
@ -1567,9 +1568,9 @@ void main(){}
if (l.shadowed)
{
if (l.cascades == 0)
throw std::runtime_error("The number of shadow map cascades should be positive");
throw util::exception("The number of shadow map cascades should be positive");
if (l.cascades > 8)
throw std::runtime_error("More than 8 shadow map cascades are not supported");
throw util::exception("More than 8 shadow map cascades are not supported");
light_transform.resize(l.cascades);

View file

@ -1,36 +1,44 @@
#pragma once
#include <exception>
#include <psemek/util/exception.hpp>
namespace psemek::io
{
struct null_stream
: std::exception
{};
: util::exception
{
using util::exception::exception;
};
struct null_istream
: null_stream
{
char const * what() const noexcept override;
null_istream(boost::stacktrace::stacktrace stacktrace = {});
};
struct null_ostream
: null_stream
{
char const * what() const noexcept override;
null_ostream(boost::stacktrace::stacktrace stacktrace = {});
};
struct stream_end
: util::exception
{
using util::exception::exception;
};
struct istream_end
: std::exception
: stream_end
{
char const * what() const noexcept override;
istream_end(boost::stacktrace::stacktrace stacktrace = {});
};
struct ostream_end
: std::exception
: stream_end
{
char const * what() const noexcept override;
ostream_end(boost::stacktrace::stacktrace stacktrace = {});
};
}

View file

@ -3,24 +3,20 @@
namespace psemek::io
{
char const * null_istream::what() const noexcept
{
return "Attempt to read from null input stream";
}
null_istream::null_istream(boost::stacktrace::stacktrace stacktrace)
: null_stream("Attempt to read from null input stream", std::move(stacktrace))
{}
char const * null_ostream::what() const noexcept
{
return "Attempt to write to null output stream";
}
null_ostream::null_ostream(boost::stacktrace::stacktrace stacktrace)
: null_stream("Attempt to write to null output stream", std::move(stacktrace))
{}
char const * istream_end::what() const noexcept
{
return "Unexpected input stream end";
}
istream_end::istream_end(boost::stacktrace::stacktrace stacktrace)
: stream_end("Unexpected input stream end", std::move(stacktrace))
{}
char const * ostream_end::what() const noexcept
{
return "Unexpected output stream end";
}
ostream_end::ostream_end(boost::stacktrace::stacktrace stacktrace)
: stream_end("Unexpected output stream end", std::move(stacktrace))
{}
}

View file

@ -1,4 +1,5 @@
#include <psemek/io/file_stream.hpp>
#include <psemek/util/system_error.hpp>
#include <cstring>
#include <codecvt>
@ -8,7 +9,7 @@ namespace psemek::io
static void throw_fopen [[noreturn]] (std::filesystem::path const & path)
{
throw std::system_error(std::error_code{errno, std::system_category()}, "Failed to open " + path.string());
throw util::system_error(std::error_code{errno, std::system_category()}, "Failed to open " + path.string());
}
static FILE * safe_fopen(std::filesystem::path const & path, const char * mode)
@ -42,7 +43,7 @@ namespace psemek::io
{
case 0: return "wb";
case file_ostream::append: return "ab";
default: throw std::runtime_error("Unknown file_ostream open flags");
default: throw util::exception("Unknown file_ostream open flags");
}
}

View file

@ -1,5 +1,6 @@
#include <psemek/log/log.hpp>
#include <psemek/util/to_string.hpp>
#include <psemek/util/exception.hpp>
#include <chrono>
#include <ctime>
@ -153,7 +154,7 @@ namespace psemek::log
auto it = thread_names.find(id);
if (it != thread_names.end())
throw std::runtime_error("Thread \"" + name + "\" already registered!");
throw util::exception("Thread \"" + name + "\" already registered!");
thread_names[id] = name;
}
@ -174,7 +175,7 @@ namespace psemek::log
{
std::ostringstream os;
os << "Thread " << id << " not found!";
throw std::runtime_error(os.str());
throw util::exception(os.str());
}
name = std::move(it->second);

View file

@ -1,5 +1,7 @@
#pragma once
#include <psemek/util/enum.hpp>
#include <cmath>
#include <algorithm>
#include <exception>
@ -10,21 +12,12 @@ namespace psemek::ml
// All activation functions are chosen in a way so that the derivative
// can be expressed as a function of the activation function's value, i.e.
// f'(x) = G(f(x)) for some G: R -> R
enum class activation_type
{
id,
sigmoid,
tanh,
relu,
count,
};
struct unknown_activation_type
: std::exception
{
char const * what() const noexcept override;
};
psemek_declare_enum(activation_type, std::uint8_t,
(id)
(sigmoid)
(tanh)
(relu)
)
template <typename T>
T activation(T x, activation_type type)
@ -39,7 +32,7 @@ namespace psemek::ml
case activation_type::relu:
return std::max(T{0}, x);
default:
throw unknown_activation_type{};
throw util::unknown_enum_value_exception{type};
}
}
@ -56,7 +49,7 @@ namespace psemek::ml
case activation_type::relu:
return value == T{0} ? T{0} : T{1};
default:
throw unknown_activation_type{};
throw util::unknown_enum_value_exception{type};
}
}

View file

@ -1,39 +1,38 @@
#pragma once
#include <stdexcept>
#include <cstddef>
#include <psemek/util/exception.hpp>
namespace psemek::ml
{
struct neural_net_error
: std::runtime_error
: util::exception
{
using runtime_error::runtime_error;
using util::exception::exception;
};
struct empty_neural_net_error
: neural_net_error
{
empty_neural_net_error();
empty_neural_net_error(boost::stacktrace::stacktrace stacktrace = {});
};
struct wrong_activation_types_count_error
: neural_net_error
{
wrong_activation_types_count_error(std::size_t expected, std::size_t actual);
wrong_activation_types_count_error(std::size_t expected, std::size_t actual, boost::stacktrace::stacktrace stacktrace = {});
};
struct wrong_neural_net_input_size
: neural_net_error
{
wrong_neural_net_input_size(std::size_t expected, std::size_t actual);
wrong_neural_net_input_size(std::size_t expected, std::size_t actual, boost::stacktrace::stacktrace stacktrace = {});
};
struct wrong_neural_net_output_size
: neural_net_error
{
wrong_neural_net_output_size(std::size_t expected, std::size_t actual);
wrong_neural_net_output_size(std::size_t expected, std::size_t actual, boost::stacktrace::stacktrace stacktrace = {});
};
}

View file

@ -1,11 +0,0 @@
#include <psemek/ml/neural_net/activation.hpp>
namespace psemek::ml
{
char const * unknown_activation_type::what() const noexcept
{
return "unknown activation type";
}
}

View file

@ -5,20 +5,20 @@
namespace psemek::ml
{
empty_neural_net_error::empty_neural_net_error()
: neural_net_error("neural net must have at least a single layer")
empty_neural_net_error::empty_neural_net_error(boost::stacktrace::stacktrace stacktrace)
: neural_net_error("Neural net must have at least a single layer", std::move(stacktrace))
{}
wrong_activation_types_count_error::wrong_activation_types_count_error(std::size_t expected, std::size_t actual)
: neural_net_error(util::to_string("wrong number of activation types: expected ", expected, ", got ", actual))
wrong_activation_types_count_error::wrong_activation_types_count_error(std::size_t expected, std::size_t actual, boost::stacktrace::stacktrace stacktrace)
: neural_net_error(util::to_string("Wrong number of activation types: expected ", expected, ", got ", actual), std::move(stacktrace))
{}
wrong_neural_net_input_size::wrong_neural_net_input_size(std::size_t expected, std::size_t actual)
: neural_net_error(util::to_string("wrong neural net input size: expected ", expected, ", got ", actual))
wrong_neural_net_input_size::wrong_neural_net_input_size(std::size_t expected, std::size_t actual, boost::stacktrace::stacktrace stacktrace)
: neural_net_error(util::to_string("Wrong neural net input size: expected ", expected, ", got ", actual), std::move(stacktrace))
{}
wrong_neural_net_output_size::wrong_neural_net_output_size(std::size_t expected, std::size_t actual)
: neural_net_error(util::to_string("wrong neural net output size: expected ", expected, ", got ", actual))
wrong_neural_net_output_size::wrong_neural_net_output_size(std::size_t expected, std::size_t actual, boost::stacktrace::stacktrace stacktrace)
: neural_net_error(util::to_string("Wrong neural net output size: expected ", expected, ", got ", actual), std::move(stacktrace))
{}
}

View file

@ -24,7 +24,7 @@ test_case(ml_neural__net_gradient)
std::vector<activation_type> activations(sizes.size() - 1);
for (auto & a : activations)
a = static_cast<activation_type>(uniform<std::size_t>(rng, 0, static_cast<std::size_t>(activation_type::count) - 1));
a = static_cast<activation_type>(uniform<std::size_t>(rng, 0, static_cast<std::size_t>(activation_type_values().size()) - 1));
neural_net<double> nn(std::move(sizes), std::move(activations));
randomize_normal(nn, rng);
@ -71,7 +71,7 @@ test_case(ml_neural__net_arg__gradient)
std::vector<activation_type> activations(sizes.size() - 1);
for (auto & a : activations)
a = static_cast<activation_type>(uniform<std::size_t>(rng, 0, static_cast<std::size_t>(activation_type::count) - 1));
a = static_cast<activation_type>(uniform<std::size_t>(rng, 0, static_cast<std::size_t>(activation_type_values().size()) - 1));
neural_net<double> nn(std::move(sizes), std::move(activations));
randomize_normal(nn, rng);

View file

@ -199,7 +199,7 @@ namespace psemek::parser
auto r = p.apply(buffer);
if (r.index() == 1) break;
if (buffer.it == pos)
throw grammar_error("infinite loop");
throw grammar_error("Infinite loop");
res.push_back(std::move(std::get<0>(r)));
}
@ -265,7 +265,7 @@ namespace psemek::parser
if (res.index() == 1)
return accum;
if (pos == buffer.it)
throw grammar_error("infinite loop");
throw grammar_error("Infinite loop");
accum = f(accum, std::get<0>(res));
}
@ -289,7 +289,7 @@ namespace psemek::parser
if (res.index() == 1)
return accum;
if (pos == buffer.it)
throw grammar_error("infinite loop");
throw grammar_error("Infinite loop");
accum = f(std::move(accum), std::move(std::get<0>(res)));
}

View file

@ -8,37 +8,35 @@
#include <memory>
#include <psemek/util/to_string.hpp>
#include <psemek/util/exception.hpp>
namespace psemek::parser
{
struct parse_error
: std::runtime_error
: util::exception
{
parse_error(std::string message, std::size_t line, std::size_t character)
: std::runtime_error(std::move(message))
parse_error(std::string message, std::size_t line, std::size_t character, boost::stacktrace::stacktrace stacktrace = {})
: util::exception(util::to_string(message, " at ", line, "#", character), std::move(stacktrace))
, message_{std::move(message)}
, line_{line}
, character_{character}
, what_{util::to_string(message, " at ", line, "#", character)}
{}
std::string const & message() const { return message_; }
std::size_t line() const { return line_; }
std::size_t character() const { return character_; }
const char * what() const noexcept { return what_.data(); }
private:
std::string message_;
std::size_t line_;
std::size_t character_;
std::string what_;
};
struct grammar_error
: std::runtime_error
: util::exception
{
grammar_error(std::string message)
: std::runtime_error(std::move(message))
{}
using util::exception::exception;
};
namespace detail

View file

@ -6,6 +6,8 @@
#include <psemek/geom/constants.hpp>
#include <psemek/geom/box.hpp>
#include <psemek/util/exception.hpp>
#include <type_traits>
#include <stdexcept>
@ -65,7 +67,7 @@ namespace psemek::random
using std::size;
using std::begin;
if (size(container) == 0)
throw std::runtime_error("cannot sample from empty container");
throw util::exception("Cannot sample from empty container");
return *std::next(begin(container), uniform<std::size_t>(rng, 0, size(container) - 1));
}

View file

@ -1,6 +1,7 @@
#pragma once
#include <psemek/rs/resource.hpp>
#include <psemek/util/exception.hpp>
#include <stdexcept>
@ -8,9 +9,9 @@ namespace psemek::rs
{
struct unknown_id_error
: std::runtime_error
: util::exception
{
unknown_id_error(rs::id id);
unknown_id_error(rs::id id, boost::stacktrace::stacktrace stacktrace = {});
rs::id id() const { return id_; }
@ -19,9 +20,9 @@ namespace psemek::rs
};
struct unknown_name_error
: std::runtime_error
: util::exception
{
unknown_name_error(std::string_view name);
unknown_name_error(std::string_view name, boost::stacktrace::stacktrace stacktrace = {});
std::string_view name() const { return name_; }

View file

@ -42,13 +42,13 @@ namespace psemek::rs
}
unknown_id_error::unknown_id_error(rs::id id)
: std::runtime_error(util::to_string("unknown resource id: ", id))
unknown_id_error::unknown_id_error(rs::id id, boost::stacktrace::stacktrace stacktrace)
: util::exception(util::to_string("unknown resource id: ", id), std::move(stacktrace))
, id_(id)
{}
unknown_name_error::unknown_name_error(std::string_view name)
: std::runtime_error(util::to_string("unknown resource name: ", name))
unknown_name_error::unknown_name_error(std::string_view name, boost::stacktrace::stacktrace stacktrace)
: util::exception(util::to_string("unknown resource name: ", name), std::move(stacktrace))
{}
resource const * find(id id)

View file

@ -1,5 +1,6 @@
#include <psemek/sdl2/init.hpp>
#include <psemek/log/log.hpp>
#include <psemek/util/exception.hpp>
#include <SDL2/SDL.h>
@ -62,7 +63,7 @@ namespace psemek::sdl2
[[noreturn]] void fail(std::string const & message)
{
throw std::runtime_error(message + SDL_GetError());
throw util::exception(message + SDL_GetError());
}
std::shared_ptr<void> init(std::uint32_t subsystems)

View file

@ -4,6 +4,7 @@
#include <psemek/sir/trivial.hpp>
#include <psemek/sir/container.hpp>
#include <psemek/io/memory_stream.hpp>
#include <psemek/util/at.hpp>
namespace psemek::sir
{
@ -27,7 +28,6 @@ namespace psemek::sir
private:
std::string_view data_;
std::size_t offset_;
};
static_assert(is_istream_v<memory_istream>);
@ -93,7 +93,7 @@ namespace psemek::sir
T const & at(std::size_t i) const
{
if (i >= size())
throw std::out_of_range("psemek::sir::vector::at");
throw util::key_error(i);
return begin_[i];
}
@ -263,7 +263,7 @@ namespace psemek::sir
{
auto p = find(key);
if (p == end_)
throw std::out_of_range("psemek::sir::map::at");
throw util::key_error(key);
return p->second;
}

View file

@ -7,6 +7,7 @@
#include <psemek/util/to_string.hpp>
#include <psemek/util/type_name.hpp>
#include <psemek/util/function.hpp>
#include <psemek/util/exception.hpp>
#include <exception>
#include <typeindex>
@ -16,21 +17,20 @@ namespace psemek::ui::impl
{
struct component_not_supported_exception
: std::exception
: util::exception
{
component_not_supported_exception(std::type_index type)
: type_(type)
, message_(util::to_string("UI component ", util::type_name(type_), " is not supported"))
component_not_supported_exception(std::type_index type, boost::stacktrace::stacktrace stacktrace = {})
: util::exception(util::to_string("UI component ", util::type_name(type_), " is not supported"), std::move(stacktrace))
, type_(type)
{}
const char * what() const noexcept override
std::type_index type() const
{
return message_.data();
return type_;
}
private:
std::type_index type_;
std::string message_;
};
struct component_factory_base

View file

@ -1,9 +1,10 @@
#pragma once
#include <psemek/util/exception.hpp>
#undef assert
#ifdef PSEMEK_DEBUG
#define assert(x) ((void)(!(x) && ::psemek::util::assert_handler(#x, __FILE__, __LINE__)))
#define assert(x) ((void)(!(x) && ::psemek::util::assertion_handler("Assertion failed: " #x)))
#else
#define assert(x) ((void)(x))
#endif
@ -11,6 +12,9 @@
namespace psemek::util
{
[[noreturn]] bool assert_handler(char const * expression, char const * file, int line);
[[noreturn]] inline bool assertion_handler(char const * assertion, boost::stacktrace::stacktrace stacktrace = {})
{
throw ::psemek::util::exception(assertion, std::move(stacktrace));
}
}

View file

@ -1,8 +1,8 @@
#pragma once
#include <string_view>
#include <stdexcept>
#include <psemek/util/exception.hpp>
#include <string_view>
#include <vector>
namespace psemek::util
@ -13,7 +13,7 @@ namespace psemek::util
inline void unexpected_end()
{
throw std::runtime_error("Unexpected binary stream end");
throw exception("Unexpected binary stream end");
}
template <typename T>

View file

@ -6,6 +6,7 @@
#include <psemek/util/range.hpp>
#include <psemek/util/hash.hpp>
#include <psemek/util/hstring.hpp>
#include <psemek/util/exception.hpp>
#include <cstdint>
#include <typeindex>
@ -779,7 +780,7 @@ namespace psemek::util
{
auto p = species_[species.value]->get_species_component<Component>();
if (!p)
throw std::runtime_error(util::to_string("Component ", type_name<Component>(), " is not present in species ", species_[species.value]->name()));
throw util::exception(util::to_string("Component ", type_name<Component>(), " is not present in species ", species_[species.value]->name()));
return *p;
}
@ -795,7 +796,7 @@ namespace psemek::util
auto u = ecs_detail::unpack(entity.value);
auto p = species_[u.species]->get_entity_component<Component>();
if (!p)
throw std::runtime_error(util::to_string("Component ", type_name<Component>(), " is not present in species ", species_[u.species]->name()));
throw util::exception(util::to_string("Component ", type_name<Component>(), " is not present in species ", species_[u.species]->name()));
return p[u.entity];
}

View file

@ -5,6 +5,7 @@
#include <psemek/util/to_string.hpp>
#include <psemek/util/type_name.hpp>
#include <psemek/util/exception.hpp>
#include <string_view>
#include <stdexcept>
@ -16,17 +17,17 @@ namespace psemek::util
{
struct unknown_enum_value_exception_base
: std::runtime_error
: exception
{
using std::runtime_error::runtime_error;
using exception::exception;
};
template <typename Enum>
struct unknown_enum_value_exception
: unknown_enum_value_exception_base
{
unknown_enum_value_exception(Enum value)
: unknown_enum_value_exception_base(to_string("unknown ", type_name<Enum>(), " value: ", static_cast<std::underlying_type_t<Enum>>(value)))
unknown_enum_value_exception(Enum value, boost::stacktrace::stacktrace stacktrace = {})
: unknown_enum_value_exception_base(to_string("unknown ", type_name<Enum>(), " value: ", static_cast<std::underlying_type_t<Enum>>(value)), std::move(stacktrace))
, value_(value)
{}

View file

@ -1,5 +1,7 @@
#pragma once
#include <psemek/util/exception.hpp>
#include <type_traits>
#include <memory>
#include <functional>
@ -7,6 +9,14 @@
namespace psemek::util
{
struct empty_function_error
: exception
{
empty_function_error(boost::stacktrace::stacktrace stacktrace = {})
: exception("Trying to call an empty function", std::move(stacktrace))
{}
};
template <typename Signature>
struct function;
@ -149,7 +159,7 @@ namespace psemek::util
R function<R(Args...)>::operator()(Args1 && ... args) const
{
if (!vtable_)
throw std::bad_function_call();
throw empty_function_error{};
return vtable_->call(const_cast<void *>(static_cast<void const *>(&storage_)), std::forward<Args1>(args)...);
}

View file

@ -1,6 +1,7 @@
#pragma once
#include <psemek/util/flat_list.hpp>
#include <psemek/util/at.hpp>
#include <tuple>
#include <variant>
@ -80,9 +81,10 @@ namespace psemek::util
template <typename F, typename T>
struct tuple_apply_at_impl<F, T, std::index_sequence<>>
{
static decltype(auto) apply(F && f, T & t, std::size_t)
static decltype(auto) apply(F && f, T & t, std::size_t i)
{
throw std::out_of_range("Bad tuple index");
throw key_error(i);
// For proper type deduction
return std::forward<F>(f)(std::get<0>(t));
}
};
@ -105,21 +107,13 @@ namespace psemek::util
decltype(auto) tuple_apply_at(F && f, T & t, std::size_t i)
{
if (i >= std::tuple_size_v<T>)
throw std::out_of_range("Bad tuple index");
throw key_error(i);
return tuple_apply_at_impl<F, T, std::make_index_sequence<std::tuple_size_v<T>>>::apply(std::forward<F>(f), t, i);
}
}
struct bad_handle
: std::out_of_range
{
bad_handle()
: std::out_of_range("Bad handle")
{}
};
template <typename Handle, typename ... Types>
struct heterogeneous_container
{
@ -230,7 +224,7 @@ namespace psemek::util
{
auto u = unpack_handle(h);
if (u.first >= types_count)
throw bad_handle{};
throw exception("Broken handle");
detail::tuple_apply_at([&u](auto & t) -> void {
t.erase(u.second);
}, storage_, u.first);
@ -275,12 +269,12 @@ namespace psemek::util
if constexpr (std::is_same_v<std::decay_t<decltype(t[hh])>, T>)
{
if (i != j)
throw std::bad_any_cast{};
throw exception("Error in heterogeneous_container");
res = &t[hh];
}
}, storage_);
if (!res)
throw std::bad_any_cast{};
throw exception("Error in heterogeneous_container");
return *res;
}
@ -298,12 +292,12 @@ namespace psemek::util
if constexpr (std::is_same_v<std::decay_t<decltype(t[hh])>, T>)
{
if (i != j)
throw std::bad_any_cast{};
throw exception("Error in heterogeneous_container");
res = &t[hh];
}
}, storage_);
if (!res)
throw std::bad_any_cast{};
throw exception("Error in heterogeneous_container");
return *res;
}

View file

@ -1,14 +1,14 @@
#pragma once
#include <exception>
#include <psemek/util/exception.hpp>
namespace psemek::util
{
struct not_implemented_error
: std::exception
: exception
{
char const * what() const noexcept override;
not_implemented_error(boost::stacktrace::stacktrace stacktrace = {});
};
[[noreturn]] void not_implemented();

View file

@ -1,6 +1,8 @@
#pragma once
#include <psemek/util/array.hpp>
#include <psemek/util/exception.hpp>
#include <psemek/util/to_string.hpp>
#include <stdexcept>
@ -112,7 +114,7 @@ namespace psemek::util
for (std::size_t i = 0; i < N; ++i)
{
if (ix[i] < origin_[i] || ix[i] >= origin_[i] + static_cast<Index>(size[i]))
throw std::runtime_error("element out of range");
throw exception(to_string("Spatial array index ", ix[i], "(#", i, ") is out of bounds [", origin_[i], origin_[i] + static_cast<Index>(size[i]), ")"));
ix[i] -= origin_[i];
}
return array_(ix);

View file

@ -0,0 +1,25 @@
#pragma once
#include <psemek/util/exception.hpp>
namespace psemek::util
{
struct system_error
: exception
{
system_error(std::error_code error_code, std::string message, boost::stacktrace::stacktrace stacktrace = {})
: exception(message + ": " + error_code.message(), std::move(stacktrace))
, error_code_(error_code)
{}
std::error_code error_code() const
{
return error_code_;
}
private:
std::error_code error_code_;
};
}

View file

@ -1,5 +1,7 @@
#pragma once
#include <psemek/util/exception.hpp>
#include <sstream>
#include <stdexcept>
@ -42,7 +44,7 @@ namespace psemek::util
T x;
iss >> x;
if (!iss)
throw std::invalid_argument("failed to parse from string");
throw exception("Failed to parse from string");
return x;
}

View file

@ -1,8 +1,9 @@
#pragma once
#include <psemek/util/exception.hpp>
#include <string>
#include <iterator>
#include <exception>
namespace psemek::util
{
@ -70,14 +71,13 @@ namespace psemek::util
};
struct invalid_utf8
: std::exception
: exception
{
invalid_utf8(char const * data)
: data_{data}
invalid_utf8(char const * data, boost::stacktrace::stacktrace stacktrace = {})
: exception("Invalid UTF-8 string", std::move(stacktrace))
, data_{data}
{}
char const * what() const noexcept override;
char const * data() const { return data_; }
private:

View file

@ -1,14 +0,0 @@
#include <psemek/util/assert.hpp>
#include <psemek/util/to_string.hpp>
#include <stdexcept>
namespace psemek::util
{
[[noreturn]] bool assert_handler(char const * expression, char const * file, int line)
{
throw std::runtime_error(to_string(file, ":", line, " Assertion failed: ", expression));
}
}

View file

@ -1,5 +1,6 @@
#include <psemek/util/executable_path.hpp>
#include <psemek/util/to_string.hpp>
#include <psemek/util/exception.hpp>
#ifdef WIN32
#include <libloaderapi.h>
@ -23,13 +24,13 @@ namespace psemek::util
else if (error == ERROR_INSUFFICIENT_BUFFER)
result.resize(result.size() * 2);
else
throw std::runtime_error(util::to_string("failed to retrieve executable path: ", std::hex, error));
throw exception(util::to_string("failed to retrieve executable path: ", std::hex, error));
}
return std::filesystem::path(result);
#elif defined __linux__
return std::filesystem::canonical("/proc/self/exe");
#else
throw std::runtime_error("executable_path() is not implemented for this platform");
throw exception("executable_path() is not implemented for this platform");
#endif
}

View file

@ -1,18 +0,0 @@
#include <psemek/util/function.hpp>
#include <functional>
namespace psemek::util
{
namespace detail
{
void bad_function_call()
{
throw std::bad_function_call{};
}
}
}

View file

@ -5,10 +5,9 @@
namespace psemek::util
{
char const * not_implemented_error::what() const noexcept
{
return "not implemented";
}
not_implemented_error::not_implemented_error(boost::stacktrace::stacktrace stacktrace)
: exception("Not implemented", std::move(stacktrace))
{}
void not_implemented()
{

View file

@ -110,9 +110,4 @@ namespace psemek::util
throw invalid_utf8(ptr);
}
char const * invalid_utf8::what() const noexcept
{
return "Invalid UTF-8 string";
}
}

View file

@ -11,7 +11,7 @@ using namespace psemek::util;
test_case(util_function_empty_call)
{
function<void()> f;
expect_throw(f(), std::bad_function_call);
expect_throw(f(), empty_function_error);
}
using heavy = std::array<int, 256>;

View file

@ -96,9 +96,9 @@ test_case(util_heterogeneous__container_get)
expect_equal_deref(std::get<2>(c.get(f0)), 3.14f);
expect_equal_deref(std::get<float *>(c.get(f0)), 3.14f);
expect_throw(c.get<float>(c0), std::bad_any_cast);
expect_throw(c.get<float>(c1), std::bad_any_cast);
expect_throw(c.get<char>(f0), std::bad_any_cast);
expect_throw(c.get<float>(c0), std::exception);
expect_throw(c.get<float>(c1), std::exception);
expect_throw(c.get<char>(f0), std::exception);
}
test_case(util_heterogeneous__container_visit)

View file

@ -13,37 +13,41 @@
// Have to put it before including to_string.hpp due to how unqualified lookup works,
// see e.g. https://alexanderlobov.net/posts/2019-07-08-function-lookup-in-templates
template <typename T>
std::ostream & operator << (std::ostream & s, std::optional<T> const & o)
namespace std
{
template <typename T>
ostream & operator << (ostream & s, optional<T> const & o)
{
if (o)
s << *o;
else
s << "(empty)";
return s;
}
}
template <typename T1, typename T2>
std::ostream & operator << (std::ostream & s, std::pair<T1, T2> const & p)
{
template <typename T1, typename T2>
ostream & operator << (ostream & s, pair<T1, T2> const & p)
{
s << '(' << p.first << ", " << p.second << ')';
return s;
}
}
template <typename ... Ts>
std::ostream & operator << (std::ostream & s, std::tuple<Ts...> const & t)
{
template <typename ... Ts>
ostream & operator << (ostream & s, tuple<Ts...> const & t)
{
s << '(';
[&]<std::size_t ... Is>(std::index_sequence<Is...>){
((s << (Is == 0 ? "" : ", ") << std::get<Is>(t)), ...);
}(std::make_index_sequence<sizeof...(Ts)>{});
[&]<size_t ... Is>(index_sequence<Is...>){
((s << (Is == 0 ? "" : ", ") << get<Is>(t)), ...);
}(make_index_sequence<sizeof...(Ts)>{});
s << ')';
return s;
}
}
template <typename T>
std::ostream & operator << (std::ostream & s, std::vector<T> const & v)
{
template <typename T>
ostream & operator << (ostream & s, vector<T> const & v)
{
s << "[";
bool first = true;
for (auto const & x : v)
@ -55,11 +59,11 @@ std::ostream & operator << (std::ostream & s, std::vector<T> const & v)
}
s << "]";
return s;
}
}
template <typename T>
std::ostream & operator << (std::ostream & s, std::set<T> const & v)
{
template <typename T>
ostream & operator << (ostream & s, set<T> const & v)
{
s << "{";
bool first = true;
for (auto const & x : v)
@ -71,6 +75,8 @@ std::ostream & operator << (std::ostream & s, std::set<T> const & v)
}
s << "}";
return s;
}
}
namespace psemek::util
@ -81,16 +87,21 @@ namespace psemek::util
}
inline std::ostream & operator << (std::ostream & s, std::type_info const & type)
namespace std
{
s << psemek::util::type_name(type);
return s;
}
inline std::ostream & operator << (std::ostream & s, std::type_index const & type)
{
inline ostream & operator << (ostream & s, type_info const & type)
{
s << psemek::util::type_name(type);
return s;
}
inline ostream & operator << (ostream & s, type_index const & type)
{
s << psemek::util::type_name(type);
return s;
}
}
#include <psemek/util/to_string.hpp>