/
Ant010ff
/
ffpp
Обзор
Документация
Войти
/
Ant010ff
/
ffpp
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
include/exceptionsupport.hpp
237 строк
7 KB
Ant010ff
Version 2.11.3.
08 авг 2026, 16:44
08 авг 2026, 16:44
fd187d3
Код
Авторство
О чём код?
/* This header is part of a Functional Flow Processing Primitives (FFPP) library, version 2.11.3. Official repository: https://gitlab.com/ant010ff/ffpp Licensed under the MIT License <http://opensource.org/licenses/MIT>. SPDX-License-Identifier: MIT Copyright (c) 2021 - 2026 Anton Nasonov <ant010fff @ gmail . com>. */ #ifndef FFPP_EXCEPTION_SUPPORT_HPP #define FFPP_EXCEPTION_SUPPORT_HPP namespace FFPP::dtl { struct SourceLocation { std::source_location sl; }; template<size_t t_nArguments> consteval auto MakeExceptionFormat() { if constexpr(t_nArguments == 0) { return std::array<CharT, 1> { '\0' }; } else { constexpr size_t c_cchTotal = t_nArguments * 3; std::array<CharT, c_cchTotal> arFormat { }; size_t index = 0; bool bFirst = true; for(size_t i = 0; i < t_nArguments; ++i) { if(bFirst) bFirst = false; else arFormat[index++] = ' '; arFormat[index++] = '{'; arFormat[index++] = '}'; } arFormat[index] = '\0'; return arFormat; } } template<typename TChar, typename TTrait> FFPP_ATTR_INLINE inline auto& operator << (std::basic_ostream<TChar, TTrait>& os, std::source_location const& sl) { os << '[' << sl.file_name() << ':' << sl.line() << ']'; return os; }//operator << (std::basic_ostream<TChar, TTrait>& os, std::source_location const& sl) template<typename... TArguments> inline StringT FormatExceptionMessage(TArguments const&... args) { using namespace dtl; constexpr StringViewT c_svDelimiter { " " }, c_svEmpty { }; bool bFirst = true; std::stringstream ss; ((ss << (bFirst ? (bFirst = false, c_svEmpty) : c_svDelimiter) << args), ...); return ss.str(); } }//FFPP::dtl #if FFPP_ENABLE_FORMAT template <> struct std::formatter<FFPP::dtl::SourceLocation> { constexpr auto parse(std::format_parse_context& ctx) noexcept { auto it = ctx.begin(); while(it != ctx.end() && *it != '}') ++it; return it; } auto format(FFPP::dtl::SourceLocation const& sl, std::format_context& ctx) const { return std::format_to( ctx.out(), "[{}:{}]", sl.sl.file_name(), sl.sl.line() ); } }; #endif namespace FFPP { template<std::derived_from<std::exception> TBase = std::runtime_error, size_t t_cchBuffer = FFPP_DEFAULT_EXCEPTION_BUFFER> class Exception : public Base::ExceptionAdaptor<TBase> { public: static constexpr size_t c_cchBuffer = t_cchBuffer; static_assert(c_cchBuffer >= 32, "Exception buffer too small"); static constexpr bool #if FFPP_ENABLE_FORMAT c_bInplaceFormat = true #else c_bInplaceFormat = false #endif ; virtual ~Exception() = default; Exception() noexcept { arBuffer_[0] = '\0'; }; Exception(StringViewT svMessage) { //assert(svMessage.size() < c_cchBuffer); nSize_ = std::min(svMessage.size(), c_cchBuffer - 1); std::copy_n(svMessage.begin(), nSize_, arBuffer_.begin()); arBuffer_[nSize_++] = '\0'; //needs trailing zero in buffer for what() } Exception(Base::Exception const& that) : Exception(that.View()) { } #if FFPP_ENABLE_FORMAT template<typename... TArguments> Exception(StringViewT svFormat, TArguments const&... args) { BufferOutputIterator itBuffer { arBuffer_.data(), arBuffer_.data() + c_cchBuffer - 1 }; auto itEnd = std::vformat_to(itBuffer, svFormat, std::make_format_args(args...)); if(itEnd.nOutput > c_cchBuffer - 1) [[unlikely]] { arBuffer_[c_cchBuffer - 4] = '.'; arBuffer_[c_cchBuffer - 3] = '.'; arBuffer_[c_cchBuffer - 2] = '.'; arBuffer_[c_cchBuffer - 1] = '\0'; //needs trailing zero in buffer for what() } else { *itEnd.pPosition = '\0'; //needs trailing zero in buffer for what() } nSize_ = std::min(itEnd.nOutput, c_cchBuffer); } #endif Exception(Exception const&) = default; Exception(Exception&&) = default; Exception& operator = (Exception const&) = default; Exception& operator = (Exception&&) = default; virtual StringViewT View() const noexcept override { if(nSize_ == 0) return { }; return { arBuffer_.data(), nSize_ - 1 }; //excluding trailing zero } const char* what() const noexcept override { return arBuffer_.data(); } private: using BufferT = std::array<CharT, c_cchBuffer>; struct BufferOutputIterator { using iterator_category = std::output_iterator_tag; using value_type = void; using difference_type = std::ptrdiff_t; using pointer = void; using reference = void; CharT* pPosition = nullptr; CharT* pEnd = nullptr; size_t nOutput = 0; BufferOutputIterator& operator * () noexcept { return *this; } BufferOutputIterator& operator ++ () noexcept { return *this; } BufferOutputIterator& operator ++ (int) noexcept { return *this; } BufferOutputIterator& operator = (CharT c) noexcept { if(pPosition < pEnd) { *pPosition = c; ++pPosition; } ++nOutput; return *this; } }; BufferT arBuffer_ { }; size_t nSize_ = 0; };//Exception template<typename Tag = void> struct ExceptPolicy { template<typename TValue> static TValue const& Convert(TValue const& v) { return v; } template<typename TValue> requires std::same_as<std::decay_t<TValue>, std::source_location> static auto Convert(TValue const& v) { return dtl::SourceLocation { v }; } template<typename TException, bool t_bSourceLocation> [[noreturn]] static void OnExcept(std::source_location const& sl, auto const&... args) { #if !FFPP_NO_EXCEPTIONS using ExceptionT = Exception<TException>; if constexpr(requires { ExceptionT::c_bInplaceFormat; }) { if constexpr(ExceptionT::c_bInplaceFormat) { auto constexpr arFormat = dtl::MakeExceptionFormat<sizeof...(args) + (t_bSourceLocation ? 1 : 0)>(); //static_assert(arFormat.size() <= ExceptionT::c_cchBuffer, "Exception message buffer too small"); if constexpr(t_bSourceLocation) { throw ExceptionT( StringViewT { arFormat.data(), arFormat.size() - 1 } , Convert(args)... , Convert(sl) ); } else { throw ExceptionT( StringViewT { arFormat.data(), arFormat.size() - 1 } , Convert(args)... ); } } } if constexpr(t_bSourceLocation) { throw ExceptionT(dtl::FormatExceptionMessage(args..., sl)); } throw ExceptionT(dtl::FormatExceptionMessage(args...)); #else std::terminate(); #endif } };//ExceptPolicy template<std::derived_from<std::exception> TException = std::runtime_error, bool t_bSourceLocation = true> struct Except { using ExceptPolicyT = FFPP_EXCEPT_POLICY_CLASS; template<typename... TArguments> struct Throw { Throw(TArguments const&... args, std::source_location const& sl = std::source_location::current()) { ExceptPolicyT::OnExcept<TException, t_bSourceLocation>(sl, args...); assert(!"Unreachable point in exception code path!"); std::terminate(); } };//Throw template<typename... TArguments> Throw(TArguments const&...) -> Throw<TArguments...>; };//Except }//FFPP #endif//FFPP_EXCEPTION_SUPPORT_HPP