diff --git a/include/fmt/core.h b/include/fmt/core.h index dad05be9..11d65d9b 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -204,42 +204,6 @@ FMT_INLINE_NAMESPACE v6 { #endif -#ifndef FMT_THROW -# if FMT_EXCEPTIONS -# if FMT_MSC_VER || FMT_NVCC -FMT_BEGIN_NAMESPACE -namespace internal { -template inline void do_throw(const Exception& x) { - // Silence unreachable code warnings in MSVC and NVCC because these - // are nearly impossible to fix in a generic code. - volatile bool b = true; - if (b) throw x; -} -} // namespace internal -FMT_END_NAMESPACE -# define FMT_THROW(x) internal::do_throw(x) -# else -# define FMT_THROW(x) throw x -# endif -# define FMT_RETHROW() throw -# else -# define FMT_THROW(x) \ - do { \ - static_cast(sizeof(x)); \ - FMT_ASSERT(false, ""); \ - } while (false) -# define FMT_RETHROW() FMT_ASSERT(false, "") -# endif -#endif - -#if FMT_EXCEPTIONS -# define FMT_TRY try -# define FMT_CATCH(x) catch (x) -#else -# define FMT_TRY if (true) -# define FMT_CATCH(x) if (false) -#endif - #if !defined(FMT_HEADER_ONLY) && defined(_WIN32) # define FMT_CLASS_API FMT_SUPPRESS_MSC_WARNING(4275) # ifdef FMT_EXPORT @@ -1490,6 +1454,33 @@ struct named_arg : view, named_arg_base { : named_arg_base(name), value(val) {} }; +// scope_exit is proposed in TS v3. This implementation is slightly different +// because without deduction guide there's no easy way to construct from lambda. +// Factory template function is needed (see make_scope_exit). +// Move assignment is disabled because of unclear semantic: whether to call +// currently assigned functor or not... +template class scope_exit { + bool passive_{false}; + F func_; + + public: + explicit scope_exit(F&& f) noexcept : func_(std::forward(f)) {} + ~scope_exit() { + if (!passive_) func_(); + } + scope_exit(const F&) = delete; + scope_exit(scope_exit&& rhs) noexcept : func_{std::move(rhs.func_)} { + rhs.release(); + } + const scope_exit& operator=(const scope_exit&) = delete; + const scope_exit& operator=(scope_exit&&) = delete; + void release() noexcept { passive_ = true; } +}; + +template scope_exit make_scope_exit(F&& f) { + return scope_exit{std::forward(f)}; +} + } // namespace internal /** @@ -1581,14 +1572,11 @@ class dynamic_format_arg_store } data_.emplace_back(internal::make_arg( static_cast&>(arg.value))); - FMT_TRY { - named_info_.push_back({arg.name, static_cast(data_.size() - 2u)}); - data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; - } - FMT_CATCH(...) { - data_.pop_back(); - FMT_RETHROW(); - } + + auto guard{internal::make_scope_exit([this]() { this->data_.pop_back(); })}; + named_info_.push_back({arg.name, static_cast(data_.size() - 2u)}); + data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; + guard.release(); } public: @@ -1622,7 +1610,8 @@ class dynamic_format_arg_store /** \rst Adds a reference to the argument into the dynamic store for later passing to - a formating function. Supports wrapped named arguments. + a formating function. Supports named arguments wrapped in + std::reference_wrapper (via std::ref()/std::cref()). **Example**:: fmt::dynamic_format_arg_store store; diff --git a/include/fmt/format.h b/include/fmt/format.h index fd891ca8..a087ca31 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -88,6 +88,40 @@ # define FMT_FALLTHROUGH #endif +#ifndef FMT_THROW +# if FMT_EXCEPTIONS +# if FMT_MSC_VER || FMT_NVCC +FMT_BEGIN_NAMESPACE +namespace internal { +template inline void do_throw(const Exception& x) { + // Silence unreachable code warnings in MSVC and NVCC because these + // are nearly impossible to fix in a generic code. + volatile bool b = true; + if (b) throw x; +} +} // namespace internal +FMT_END_NAMESPACE +# define FMT_THROW(x) internal::do_throw(x) +# else +# define FMT_THROW(x) throw x +# endif +# else +# define FMT_THROW(x) \ + do { \ + static_cast(sizeof(x)); \ + FMT_ASSERT(false, ""); \ + } while (false) +# endif +#endif + +#if FMT_EXCEPTIONS +# define FMT_TRY try +# define FMT_CATCH(x) catch (x) +#else +# define FMT_TRY if (true) +# define FMT_CATCH(x) if (false) +#endif + #ifndef FMT_USE_USER_DEFINED_LITERALS // For Intel and NVIDIA compilers both they and the system gcc/msc support UDLs. # if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || \ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 23ea9fcf..89176633 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -95,7 +95,6 @@ add_fmt_test(grisu-test) target_compile_definitions(grisu-test PRIVATE FMT_USE_GRISU=1) add_fmt_test(gtest-extra-test) add_fmt_test(format-test mock-allocator.h) -add_fmt_test(format-dyn-args-test) if (MSVC) target_compile_options(format-test PRIVATE /bigobj) endif ()