[debt] fix a leak in lnav_view_filters

pull/824/head
Timothy Stack 3 years ago
parent 2de57d242d
commit 1cefe583fa

@ -53,9 +53,7 @@ public:
: am_ptr(ptr), am_free_func(default_free) { : am_ptr(ptr), am_free_func(default_free) {
}; };
auto_mem(auto_mem &am) auto_mem(const auto_mem &am) = delete;
: am_ptr(am.release()), am_free_func(am.am_free_func)
{};
template<typename F> template<typename F>
explicit auto_mem(F free_func) explicit auto_mem(F free_func)

@ -33,6 +33,8 @@
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
#include <memory>
#include "base/string_util.hh" #include "base/string_util.hh"
#include "fmt/format.h" #include "fmt/format.h"
#include "yajlpp/yajlpp.hh" #include "yajlpp/yajlpp.hh"
@ -626,7 +628,7 @@ log_format::scan_result_t external_log_format::scan(logfile &lf,
if (this->elf_type == ELF_TYPE_JSON) { if (this->elf_type == ELF_TYPE_JSON) {
yajlpp_parse_context &ypc = *(this->jlf_parse_context); yajlpp_parse_context &ypc = *(this->jlf_parse_context);
logline ll(li.li_file_range.fr_offset, 0, 0, LEVEL_INFO); logline ll(li.li_file_range.fr_offset, 0, 0, LEVEL_INFO);
yajl_handle handle = this->jlf_yajl_handle.in(); yajl_handle handle = this->jlf_yajl_handle.get();
json_log_userdata jlu(sbr); json_log_userdata jlu(sbr);
if (!this->lf_specialized && dst.size() >= 3) { if (!this->lf_specialized && dst.size() >= 3) {
@ -1198,7 +1200,7 @@ void external_log_format::get_subline(const logline &ll, shared_buffer_ref &sbr,
if (this->jlf_cached_offset != ll.get_offset() || if (this->jlf_cached_offset != ll.get_offset() ||
this->jlf_cached_full != full_message) { this->jlf_cached_full != full_message) {
yajlpp_parse_context &ypc = *(this->jlf_parse_context); yajlpp_parse_context &ypc = *(this->jlf_parse_context);
yajl_handle handle = this->jlf_yajl_handle.in(); yajl_handle handle = this->jlf_yajl_handle.get();
json_log_userdata jlu(sbr); json_log_userdata jlu(sbr);
this->jlf_share_manager.invalidate_refs(); this->jlf_share_manager.invalidate_refs();
@ -1651,13 +1653,14 @@ void external_log_format::build(std::vector<std::string> &errors) {
": structured logs cannot have regexes"); ": structured logs cannot have regexes");
} }
if (this->elf_type == ELF_TYPE_JSON) { if (this->elf_type == ELF_TYPE_JSON) {
this->jlf_parse_context.reset( this->jlf_parse_context = std::make_shared<yajlpp_parse_context>(
new yajlpp_parse_context(this->elf_name.to_string())); this->elf_name.to_string());
this->jlf_yajl_handle.reset(yajl_alloc( this->jlf_yajl_handle.reset(
&this->jlf_parse_context->ypc_callbacks, yajl_alloc(&this->jlf_parse_context->ypc_callbacks,
NULL, nullptr,
this->jlf_parse_context.get())); this->jlf_parse_context.get()),
yajl_config(this->jlf_yajl_handle.in(), yajl_dont_validate_strings, yajl_handle_deleter());
yajl_config(this->jlf_yajl_handle.get(), yajl_dont_validate_strings,
1); 1);
} }
@ -2198,11 +2201,12 @@ std::shared_ptr<log_format> external_log_format::specialized(int fmt_lock)
if (this->elf_type == ELF_TYPE_JSON) { if (this->elf_type == ELF_TYPE_JSON) {
this->jlf_parse_context = std::make_shared<yajlpp_parse_context>(this->elf_name.to_string()); this->jlf_parse_context = std::make_shared<yajlpp_parse_context>(this->elf_name.to_string());
this->jlf_yajl_handle.reset(yajl_alloc( this->jlf_yajl_handle.reset(
&this->jlf_parse_context->ypc_callbacks, yajl_alloc(&this->jlf_parse_context->ypc_callbacks,
nullptr, nullptr,
this->jlf_parse_context.get())); this->jlf_parse_context.get()),
yajl_config(this->jlf_yajl_handle.in(), yajl_dont_validate_strings, 1); yajl_handle_deleter());
yajl_config(this->jlf_yajl_handle.get(), yajl_dont_validate_strings, 1);
this->jlf_cached_line.reserve(16 * 1024); this->jlf_cached_line.reserve(16 * 1024);
} }

@ -103,6 +103,14 @@ public:
std::shared_ptr<pcrepp> lp_pcre; std::shared_ptr<pcrepp> lp_pcre;
}; };
struct yajl_handle_deleter {
void operator()(yajl_handle handle) const {
if (handle != nullptr) {
yajl_free(handle);
}
}
};
external_log_format(const intern_string_t name) external_log_format(const intern_string_t name)
: elf_file_pattern(".*"), : elf_file_pattern(".*"),
elf_column_count(0), elf_column_count(0),
@ -116,7 +124,7 @@ public:
elf_type(ELF_TYPE_TEXT), elf_type(ELF_TYPE_TEXT),
jlf_hide_extra(false), jlf_hide_extra(false),
jlf_cached_offset(-1), jlf_cached_offset(-1),
jlf_yajl_handle(yajl_free), jlf_yajl_handle(nullptr, yajl_handle_deleter()),
elf_name(name) { elf_name(name) {
this->jlf_line_offsets.reserve(128); this->jlf_line_offsets.reserve(128);
}; };
@ -439,7 +447,7 @@ public:
std::vector<char> jlf_cached_line; std::vector<char> jlf_cached_line;
string_attrs_t jlf_line_attrs; string_attrs_t jlf_line_attrs;
std::shared_ptr<yajlpp_parse_context> jlf_parse_context; std::shared_ptr<yajlpp_parse_context> jlf_parse_context;
auto_mem<yajl_handle_t> jlf_yajl_handle; std::shared_ptr<yajl_handle_t> jlf_yajl_handle;
private: private:
const intern_string_t elf_name; const intern_string_t elf_name;

@ -75,16 +75,6 @@ public:
}; // class bad_variant_access }; // class bad_variant_access
template <typename R = void>
struct MAPBOX_VARIANT_DEPRECATED static_visitor
{
using result_type = R;
protected:
static_visitor() {}
~static_visitor() {}
};
#if !defined(MAPBOX_VARIANT_MINIMIZE_SIZE) #if !defined(MAPBOX_VARIANT_MINIMIZE_SIZE)
using type_index_t = unsigned int; using type_index_t = unsigned int;
#else #else
@ -170,44 +160,68 @@ template <typename T, typename... Types>
struct value_traits struct value_traits
{ {
using value_type = typename std::remove_const<typename std::remove_reference<T>::type>::type; using value_type = typename std::remove_const<typename std::remove_reference<T>::type>::type;
using value_type_wrapper = recursive_wrapper<value_type>;
static constexpr type_index_t direct_index = direct_type<value_type, Types...>::index; static constexpr type_index_t direct_index = direct_type<value_type, Types...>::index;
static constexpr bool is_direct = direct_index != invalid_value; static constexpr bool is_direct = direct_index != invalid_value;
static constexpr type_index_t index = is_direct ? direct_index : convertible_type<value_type, Types...>::index; static constexpr type_index_t index_direct_or_wrapper = is_direct ? direct_index : direct_type<value_type_wrapper, Types...>::index;
static constexpr bool is_direct_or_wrapper = index_direct_or_wrapper != invalid_value;
static constexpr type_index_t index = is_direct_or_wrapper ? index_direct_or_wrapper : convertible_type<value_type, Types...>::index;
static constexpr bool is_valid = index != invalid_value; static constexpr bool is_valid = index != invalid_value;
static constexpr type_index_t tindex = is_valid ? sizeof...(Types)-index : 0; static constexpr type_index_t tindex = is_valid ? sizeof...(Types)-index : 0;
using target_type = typename std::tuple_element<tindex, std::tuple<void, Types...>>::type; using target_type = typename std::tuple_element<tindex, std::tuple<void, Types...>>::type;
}; };
template <typename T, typename R = void> template <typename Src, typename Dest>
struct enable_if_type struct copy_cvref
{ {
using type = R; using type = Dest;
}; };
template <typename F, typename V, typename Enable = void> template <typename Src, typename Dest>
struct result_of_unary_visit struct copy_cvref<Src const&, Dest>
{ {
using type = typename std::result_of<F(V&)>::type; using type = Dest const&;
}; };
template <typename F, typename V> template <typename Src, typename Dest>
struct result_of_unary_visit<F, V, typename enable_if_type<typename F::result_type>::type> struct copy_cvref<Src&, Dest>
{ {
using type = typename F::result_type; using type = Dest&;
}; };
template <typename F, typename V, typename Enable = void> template <typename Src, typename Dest>
struct result_of_binary_visit struct copy_cvref<Src&&, Dest>
{ {
using type = typename std::result_of<F(V&, V&)>::type; using type = Dest&&;
}; };
template <typename F, typename V> template <typename F, typename = void>
struct result_of_binary_visit<F, V, typename enable_if_type<typename F::result_type>::type> struct deduced_result_type
{};
template <typename F, typename... Args>
struct deduced_result_type<F(Args...), decltype((void)std::declval<F>()(std::declval<Args>()...))>
{ {
using type = typename F::result_type; using type = decltype(std::declval<F>()(std::declval<Args>()...));
}; };
template <typename F, typename = void>
struct visitor_result_type : deduced_result_type<F>
{};
// specialization for explicit result_type member in visitor class
template <typename F, typename... Args>
struct visitor_result_type<F(Args...), decltype((void)std::declval<typename std::decay<F>::type::result_type>())>
{
using type = typename std::decay<F>::type::result_type;
};
template <typename F, typename T>
using result_of_unary_visit = typename visitor_result_type<F&&(T&&)>::type;
template <typename F, typename T>
using result_of_binary_visit = typename visitor_result_type<F&&(T&&, T&&)>::type;
template <type_index_t arg1, type_index_t... others> template <type_index_t arg1, type_index_t... others>
struct static_max; struct static_max;
@ -277,245 +291,174 @@ struct variant_helper<>
template <typename T> template <typename T>
struct unwrapper struct unwrapper
{ {
static T const& apply_const(T const& obj) { return obj; } using value_type = T;
static T& apply(T& obj) { return obj; }
};
template <typename T> template <typename V>
struct unwrapper<recursive_wrapper<T>> static auto apply(typename std::remove_reference<V>::type& var)
{ -> typename std::enable_if<std::is_lvalue_reference<V>::value,
static auto apply_const(recursive_wrapper<T> const& obj) decltype(var.template get_unchecked<T>())>::type
-> typename recursive_wrapper<T>::type const&
{ {
return obj.get(); return var.template get_unchecked<T>();
} }
static auto apply(recursive_wrapper<T>& obj)
-> typename recursive_wrapper<T>::type& template <typename V>
static auto apply(typename std::remove_reference<V>::type& var)
-> typename std::enable_if<!std::is_lvalue_reference<V>::value,
decltype(std::move(var.template get_unchecked<T>()))>::type
{ {
return obj.get(); return std::move(var.template get_unchecked<T>());
} }
}; };
template <typename T> template <typename T>
struct unwrapper<std::reference_wrapper<T>> struct unwrapper<recursive_wrapper<T>> : unwrapper<T>
{ {};
static auto apply_const(std::reference_wrapper<T> const& obj)
-> typename std::reference_wrapper<T>::type const& template <typename T>
{ struct unwrapper<std::reference_wrapper<T>> : unwrapper<T>
return obj.get(); {};
}
static auto apply(std::reference_wrapper<T>& obj)
-> typename std::reference_wrapper<T>::type&
{
return obj.get();
}
};
template <typename F, typename V, typename R, typename... Types> template <typename R, typename... Types>
struct dispatcher; struct dispatcher;
template <typename F, typename V, typename R, typename T, typename... Types> template <typename R, typename T, typename... Types>
struct dispatcher<F, V, R, T, Types...> struct dispatcher<R, T, Types...>
{ {
VARIANT_INLINE static R apply_const(V const& v, F&& f) template <typename V, typename F>
{ VARIANT_INLINE static R apply(V&& v, F&& f)
if (v.template is<T>())
{
return f(unwrapper<T>::apply_const(v.template get_unchecked<T>()));
}
else
{
return dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
}
}
VARIANT_INLINE static R apply(V& v, F&& f)
{ {
if (v.template is<T>()) if (v.template is<T>())
{ {
return f(unwrapper<T>::apply(v.template get_unchecked<T>())); return std::forward<F>(f)(unwrapper<T>::template apply<V>(v));
} }
else else
{ {
return dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f)); return dispatcher<R, Types...>::apply(std::forward<V>(v), std::forward<F>(f));
} }
} }
}; };
template <typename F, typename V, typename R, typename T> template <typename R, typename T>
struct dispatcher<F, V, R, T> struct dispatcher<R, T>
{ {
VARIANT_INLINE static R apply_const(V const& v, F&& f) template <typename V, typename F>
VARIANT_INLINE static R apply(V&& v, F&& f)
{ {
return f(unwrapper<T>::apply_const(v.template get_unchecked<T>())); return std::forward<F>(f)(unwrapper<T>::template apply<V>(v));
}
VARIANT_INLINE static R apply(V& v, F&& f)
{
return f(unwrapper<T>::apply(v.template get_unchecked<T>()));
} }
}; };
template <typename F, typename V, typename R, typename T, typename... Types> template <typename R, typename T, typename... Types>
struct binary_dispatcher_rhs; struct binary_dispatcher_rhs;
template <typename F, typename V, typename R, typename T0, typename T1, typename... Types> template <typename R, typename T0, typename T1, typename... Types>
struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...> struct binary_dispatcher_rhs<R, T0, T1, Types...>
{ {
VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) template <typename V, typename F>
VARIANT_INLINE static R apply(V&& lhs, V&& rhs, F&& f)
{ {
if (rhs.template is<T1>()) // call binary functor if (rhs.template is<T1>()) // call binary functor
{ {
return f(unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()), return std::forward<F>(f)(unwrapper<T0>::template apply<V>(lhs),
unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>())); unwrapper<T1>::template apply<V>(rhs));
} }
else else
{ {
return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f)); return binary_dispatcher_rhs<R, T0, Types...>::apply(std::forward<V>(lhs),
} std::forward<V>(rhs),
} std::forward<F>(f));
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
{
if (rhs.template is<T1>()) // call binary functor
{
return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()),
unwrapper<T1>::apply(rhs.template get_unchecked<T1>()));
}
else
{
return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
} }
} }
}; };
template <typename F, typename V, typename R, typename T0, typename T1> template <typename R, typename T0, typename T1>
struct binary_dispatcher_rhs<F, V, R, T0, T1> struct binary_dispatcher_rhs<R, T0, T1>
{ {
VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) template <typename V, typename F>
{ VARIANT_INLINE static R apply(V&& lhs, V&& rhs, F&& f)
return f(unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()),
unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>()));
}
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
{ {
return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()), return std::forward<F>(f)(unwrapper<T0>::template apply<V>(lhs),
unwrapper<T1>::apply(rhs.template get_unchecked<T1>())); unwrapper<T1>::template apply<V>(rhs));
} }
}; };
template <typename F, typename V, typename R, typename T, typename... Types> template <typename R, typename T, typename... Types>
struct binary_dispatcher_lhs; struct binary_dispatcher_lhs;
template <typename F, typename V, typename R, typename T0, typename T1, typename... Types> template <typename R, typename T0, typename T1, typename... Types>
struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...> struct binary_dispatcher_lhs<R, T0, T1, Types...>
{ {
VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) template <typename V, typename F>
{ VARIANT_INLINE static R apply(V&& lhs, V&& rhs, F&& f)
if (lhs.template is<T1>()) // call binary functor
{
return f(unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()),
unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>()));
}
else
{
return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
}
}
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
{ {
if (lhs.template is<T1>()) // call binary functor if (lhs.template is<T1>()) // call binary functor
{ {
return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()), return std::forward<F>(f)(unwrapper<T1>::template apply<V>(lhs),
unwrapper<T0>::apply(rhs.template get_unchecked<T0>())); unwrapper<T0>::template apply<V>(rhs));
} }
else else
{ {
return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f)); return binary_dispatcher_lhs<R, T0, Types...>::apply(std::forward<V>(lhs),
std::forward<V>(rhs),
std::forward<F>(f));
} }
} }
}; };
template <typename F, typename V, typename R, typename T0, typename T1> template <typename R, typename T0, typename T1>
struct binary_dispatcher_lhs<F, V, R, T0, T1> struct binary_dispatcher_lhs<R, T0, T1>
{ {
VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f) template <typename V, typename F>
VARIANT_INLINE static R apply(V&& lhs, V&& rhs, F&& f)
{ {
return f(unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()), return std::forward<F>(f)(unwrapper<T1>::template apply<V>(lhs),
unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>())); unwrapper<T0>::template apply<V>(rhs));
}
VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
{
return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()),
unwrapper<T0>::apply(rhs.template get_unchecked<T0>()));
} }
}; };
template <typename F, typename V, typename R, typename... Types> template <typename R, typename... Types>
struct binary_dispatcher; struct binary_dispatcher;
template <typename F, typename V, typename R, typename T, typename... Types> template <typename R, typename T, typename... Types>
struct binary_dispatcher<F, V, R, T, Types...> struct binary_dispatcher<R, T, Types...>
{ {
VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f) template <typename V, typename F>
VARIANT_INLINE static R apply(V&& v0, V&& v1, F&& f)
{ {
if (v0.template is<T>()) if (v0.template is<T>())
{ {
if (v1.template is<T>()) if (v1.template is<T>())
{ {
return f(unwrapper<T>::apply_const(v0.template get_unchecked<T>()), return std::forward<F>(f)(unwrapper<T>::template apply<V>(v0),
unwrapper<T>::apply_const(v1.template get_unchecked<T>())); // call binary functor unwrapper<T>::template apply<V>(v1)); // call binary functor
} }
else else
{ {
return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f)); return binary_dispatcher_rhs<R, T, Types...>::apply(std::forward<V>(v0),
std::forward<V>(v1),
std::forward<F>(f));
} }
} }
else if (v1.template is<T>()) else if (v1.template is<T>())
{ {
return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f)); return binary_dispatcher_lhs<R, T, Types...>::apply(std::forward<V>(v0),
std::forward<V>(v1),
std::forward<F>(f));
} }
return binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f)); return binary_dispatcher<R, Types...>::apply(std::forward<V>(v0),
} std::forward<V>(v1),
std::forward<F>(f));
VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
{
if (v0.template is<T>())
{
if (v1.template is<T>())
{
return f(unwrapper<T>::apply(v0.template get_unchecked<T>()),
unwrapper<T>::apply(v1.template get_unchecked<T>())); // call binary functor
}
else
{
return binary_dispatcher_rhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
}
}
else if (v1.template is<T>())
{
return binary_dispatcher_lhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
}
return binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
} }
}; };
template <typename F, typename V, typename R, typename T> template <typename R, typename T>
struct binary_dispatcher<F, V, R, T> struct binary_dispatcher<R, T>
{ {
VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f) template <typename V, typename F>
VARIANT_INLINE static R apply(V&& v0, V&& v1, F&& f)
{ {
return f(unwrapper<T>::apply_const(v0.template get_unchecked<T>()), return std::forward<F>(f)(unwrapper<T>::template apply<V>(v0),
unwrapper<T>::apply_const(v1.template get_unchecked<T>())); // call binary functor unwrapper<T>::template apply<V>(v1)); // call binary functor
}
VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
{
return f(unwrapper<T>::apply(v0.template get_unchecked<T>()),
unwrapper<T>::apply(v1.template get_unchecked<T>())); // call binary functor
} }
}; };
@ -586,11 +529,19 @@ public:
using types = std::tuple<Types...>; using types = std::tuple<Types...>;
private: private:
using first_type = typename std::tuple_element<0, types>::type; using first_type = typename std::tuple_element<0, types>::type;
using unwrap_first_type = typename detail::unwrapper<first_type>::value_type;
using data_type = typename std::aligned_storage<data_size, data_align>::type; using data_type = typename std::aligned_storage<data_size, data_align>::type;
using helper_type = detail::variant_helper<Types...>; using helper_type = detail::variant_helper<Types...>;
template <typename V, typename T = unwrap_first_type>
using alternative_ref = typename detail::copy_cvref<V, T>::type;
type_index_t type_index; type_index_t type_index;
#ifdef __clang_analyzer__
data_type data {};
#else
data_type data; data_type data;
#endif
public: public:
VARIANT_INLINE variant() noexcept(std::is_nothrow_default_constructible<first_type>::value) VARIANT_INLINE variant() noexcept(std::is_nothrow_default_constructible<first_type>::value)
@ -644,21 +595,34 @@ private:
public: public:
VARIANT_INLINE variant<Types...>& operator=(variant<Types...>&& other) VARIANT_INLINE variant<Types...>& operator=(variant<Types...>&& other)
// note we check for nothrow-constructible, not nothrow-assignable, since
// move_assign uses move-construction via placement new.
noexcept(detail::conjunction<std::is_nothrow_move_constructible<Types>...>::value)
{ {
if (this == &other) { // playing safe in release mode, hit assertion in debug.
assert(false);
return *this;
}
move_assign(std::move(other)); move_assign(std::move(other));
return *this; return *this;
} }
VARIANT_INLINE variant<Types...>& operator=(variant<Types...> const& other) VARIANT_INLINE variant<Types...>& operator=(variant<Types...> const& other)
{ {
copy_assign(other); if (this != &other)
copy_assign(other);
return *this; return *this;
} }
// conversions // conversions
// move-assign // move-assign
template <typename T> template <typename T, typename Traits = detail::value_traits<T, Types...>,
VARIANT_INLINE variant<Types...>& operator=(T&& rhs) noexcept typename Enable = typename std::enable_if<Traits::is_valid && !std::is_same<variant<Types...>, typename Traits::value_type>::value>::type >
VARIANT_INLINE variant<Types...>& operator=(T&& rhs)
// not that we check is_nothrow_constructible<T>, not is_nothrow_move_assignable<T>,
// since we construct a temporary
noexcept(std::is_nothrow_constructible<typename Traits::target_type, T&&>::value
&& std::is_nothrow_move_assignable<variant<Types...>>::value)
{ {
variant<Types...> temp(std::forward<T>(rhs)); variant<Types...> temp(std::forward<T>(rhs));
move_assign(std::move(temp)); move_assign(std::move(temp));
@ -855,7 +819,7 @@ public:
VARIANT_INLINE int which() const noexcept VARIANT_INLINE int which() const noexcept
{ {
return static_cast<int>(sizeof...(Types)-type_index - 1); return static_cast<int>(sizeof...(Types) - type_index - 1);
} }
template <typename T, typename std::enable_if< template <typename T, typename std::enable_if<
@ -867,51 +831,44 @@ public:
// visitor // visitor
// unary // unary
template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type> template <typename F, typename V, typename T0 = alternative_ref<V>,
auto VARIANT_INLINE static visit(V const& v, F&& f) typename R = detail::result_of_unary_visit<F, T0>>
-> decltype(detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f))) VARIANT_INLINE static R visit(V&& v, F&& f)
{
return detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
}
// non-const
template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
auto VARIANT_INLINE static visit(V& v, F&& f)
-> decltype(detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f)))
{ {
return detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f)); return detail::dispatcher<R, Types...>::apply(std::forward<V>(v), std::forward<F>(f));
} }
// binary // binary
// const template <typename F, typename V, typename T0 = alternative_ref<V>,
template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type> typename R = detail::result_of_binary_visit<F, T0>>
auto VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F&& f) VARIANT_INLINE static R binary_visit(V&& v0, V&& v1, F&& f)
-> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f)))
{ {
return detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f)); return detail::binary_dispatcher<R, Types...>::apply(std::forward<V>(v0),
} std::forward<V>(v1),
// non-const std::forward<F>(f));
template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
auto VARIANT_INLINE static binary_visit(V& v0, V& v1, F&& f)
-> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f)))
{
return detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
} }
// match // match
// unary // unary
template <typename... Fs> template <typename... Fs>
auto VARIANT_INLINE match(Fs&&... fs) const auto VARIANT_INLINE match(Fs&&... fs) const&
-> decltype(variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...))) -> decltype(variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)))
{ {
return variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)); return variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...));
} }
// non-const // non-const
template <typename... Fs> template <typename... Fs>
auto VARIANT_INLINE match(Fs&&... fs) auto VARIANT_INLINE match(Fs&&... fs) &
-> decltype(variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...))) -> decltype(variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)))
{ {
return variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)); return variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...));
} }
template <typename... Fs>
auto VARIANT_INLINE match(Fs&&... fs) &&
-> decltype(variant::visit(std::move(*this), ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)))
{
return variant::visit(std::move(*this), ::mapbox::util::make_visitor(std::forward<Fs>(fs)...));
}
~variant() noexcept // no-throw destructor ~variant() noexcept // no-throw destructor
{ {
@ -962,33 +919,19 @@ public:
}; };
// unary visitor interface // unary visitor interface
// const
template <typename F, typename V>
auto VARIANT_INLINE apply_visitor(F&& f, V const& v) -> decltype(V::visit(v, std::forward<F>(f)))
{
return V::visit(v, std::forward<F>(f));
}
// non-const
template <typename F, typename V> template <typename F, typename V>
auto VARIANT_INLINE apply_visitor(F&& f, V& v) -> decltype(V::visit(v, std::forward<F>(f))) auto VARIANT_INLINE apply_visitor(F&& f, V&& v)
-> decltype(v.visit(std::forward<V>(v), std::forward<F>(f)))
{ {
return V::visit(v, std::forward<F>(f)); return v.visit(std::forward<V>(v), std::forward<F>(f));
} }
// binary visitor interface // binary visitor interface
// const
template <typename F, typename V> template <typename F, typename V>
auto VARIANT_INLINE apply_visitor(F&& f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f))) auto VARIANT_INLINE apply_visitor(F&& f, V&& v0, V&& v1)
-> decltype(v0.binary_visit(std::forward<V>(v0), std::forward<V>(v1), std::forward<F>(f)))
{ {
return V::binary_visit(v0, v1, std::forward<F>(f)); return v0.binary_visit(std::forward<V>(v0), std::forward<V>(v1), std::forward<F>(f));
}
// non-const
template <typename F, typename V>
auto VARIANT_INLINE apply_visitor(F&& f, V& v0, V& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
{
return V::binary_visit(v0, v1, std::forward<F>(f));
} }
// getter interface // getter interface
@ -1020,6 +963,78 @@ ResultType const& get_unchecked(T const& var)
{ {
return var.template get_unchecked<ResultType>(); return var.template get_unchecked<ResultType>();
} }
// variant_size
template <typename T>
struct variant_size;
//variable templates is c++14
//template <typename T>
//constexpr std::size_t variant_size_v = variant_size<T>::value;
template <typename T>
struct variant_size<const T>
: variant_size<T> {};
template <typename T>
struct variant_size<volatile T>
: variant_size<T> {};
template <typename T>
struct variant_size<const volatile T>
: variant_size<T> {};
template <typename... Types>
struct variant_size<variant<Types...>>
: std::integral_constant<std::size_t, sizeof...(Types)> {};
// variant_alternative
template <std::size_t Index, typename T>
struct variant_alternative;
#if defined(__clang__)
#if __has_builtin(__type_pack_element)
#define has_type_pack_element
#endif
#endif
#if defined(has_type_pack_element)
template <std::size_t Index, typename ...Types>
struct variant_alternative<Index, variant<Types...>>
{
static_assert(sizeof...(Types) > Index , "Index out of range");
using type = __type_pack_element<Index, Types...>;
};
#else
template <std::size_t Index, typename First, typename...Types>
struct variant_alternative<Index, variant<First, Types...>>
: variant_alternative<Index - 1, variant<Types...>>
{
static_assert(sizeof...(Types) > Index -1 , "Index out of range");
};
template <typename First, typename...Types>
struct variant_alternative<0, variant<First, Types...>>
{
using type = First;
};
#endif
template <size_t Index, typename T>
using variant_alternative_t = typename variant_alternative<Index, T>::type;
template <size_t Index, typename T>
struct variant_alternative<Index, const T>
: std::add_const<variant_alternative<Index, T>> {};
template <size_t Index, typename T>
struct variant_alternative<Index, volatile T>
: std::add_volatile<variant_alternative<Index, T>> {};
template <size_t Index, typename T>
struct variant_alternative<Index, const volatile T>
: std::add_cv<variant_alternative<Index, T>> {};
} // namespace util } // namespace util
} // namespace mapbox } // namespace mapbox
@ -1032,6 +1047,7 @@ struct hash< ::mapbox::util::variant<Types...>> {
return ::mapbox::util::apply_visitor(::mapbox::util::detail::hasher{}, v); return ::mapbox::util::apply_visitor(::mapbox::util::detail::hasher{}, v);
} }
}; };
} }
#endif // MAPBOX_UTIL_VARIANT_HPP #endif // MAPBOX_UTIL_VARIANT_HPP

@ -0,0 +1,85 @@
#ifndef VARIANT_CAST_HPP
#define VARIANT_CAST_HPP
#include <type_traits>
namespace mapbox {
namespace util {
namespace detail {
template <class T>
class static_caster
{
public:
template <class V>
T& operator()(V& v) const
{
return static_cast<T&>(v);
}
};
template <class T>
class dynamic_caster
{
public:
using result_type = T&;
template <class V>
T& operator()(V& v, typename std::enable_if<!std::is_polymorphic<V>::value>::type* = nullptr) const
{
throw std::bad_cast();
}
template <class V>
T& operator()(V& v, typename std::enable_if<std::is_polymorphic<V>::value>::type* = nullptr) const
{
return dynamic_cast<T&>(v);
}
};
template <class T>
class dynamic_caster<T*>
{
public:
using result_type = T*;
template <class V>
T* operator()(V& v, typename std::enable_if<!std::is_polymorphic<V>::value>::type* = nullptr) const
{
return nullptr;
}
template <class V>
T* operator()(V& v, typename std::enable_if<std::is_polymorphic<V>::value>::type* = nullptr) const
{
return dynamic_cast<T*>(&v);
}
};
}
template <class T, class V>
typename detail::dynamic_caster<T>::result_type
dynamic_variant_cast(V& v)
{
return mapbox::util::apply_visitor(detail::dynamic_caster<T>(), v);
}
template <class T, class V>
typename detail::dynamic_caster<const T>::result_type
dynamic_variant_cast(const V& v)
{
return mapbox::util::apply_visitor(detail::dynamic_caster<const T>(), v);
}
template <class T, class V>
T& static_variant_cast(V& v)
{
return mapbox::util::apply_visitor(detail::static_caster<T>(), v);
}
template <class T, class V>
const T& static_variant_cast(const V& v)
{
return mapbox::util::apply_visitor(detail::static_caster<const T>(), v);
}
}
}
#endif // VARIANT_CAST_HPP

@ -1,6 +1,8 @@
#ifndef MAPBOX_UTIL_VARIANT_VISITOR_HPP #ifndef MAPBOX_UTIL_VARIANT_VISITOR_HPP
#define MAPBOX_UTIL_VARIANT_VISITOR_HPP #define MAPBOX_UTIL_VARIANT_VISITOR_HPP
#include <utility>
namespace mapbox { namespace mapbox {
namespace util { namespace util {
@ -10,28 +12,31 @@ struct visitor;
template <typename Fn> template <typename Fn>
struct visitor<Fn> : Fn struct visitor<Fn> : Fn
{ {
using type = Fn;
using Fn::operator(); using Fn::operator();
visitor(Fn fn) : Fn(fn) {} template<typename T>
visitor(T&& fn) : Fn(std::forward<T>(fn)) {}
}; };
template <typename Fn, typename... Fns> template <typename Fn, typename... Fns>
struct visitor<Fn, Fns...> : Fn, visitor<Fns...> struct visitor<Fn, Fns...> : Fn, visitor<Fns...>
{ {
using type = visitor;
using Fn::operator(); using Fn::operator();
using visitor<Fns...>::operator(); using visitor<Fns...>::operator();
visitor(Fn fn, Fns... fns) : Fn(fn), visitor<Fns...>(fns...) {} template<typename T, typename... Ts>
visitor(T&& fn, Ts&&... fns)
: Fn(std::forward<T>(fn))
, visitor<Fns...>(std::forward<Ts>(fns)...) {}
}; };
template <typename... Fns> template <typename... Fns>
visitor<Fns...> make_visitor(Fns... fns) visitor<typename std::decay<Fns>::type...> make_visitor(Fns&&... fns)
{ {
return visitor<Fns...>(fns...); return visitor<typename std::decay<Fns>::type...>
(std::forward<Fns>(fns)...);
} }
} // namespace util } // namespace util
} // namespace mapbox } // namespace mapbox

@ -80,11 +80,11 @@ struct from_sqlite<text_filter::type_t> {
}; };
template<> template<>
struct from_sqlite<pair<string, pcre *>> { struct from_sqlite<pair<string, auto_mem<pcre>>> {
inline pair<string, pcre *>operator()(int argc, sqlite3_value **val, int argi) { inline pair<string, auto_mem<pcre>> operator()(int argc, sqlite3_value **val, int argi) {
const char *pattern = (const char *) sqlite3_value_text(val[argi]); const char *pattern = (const char *) sqlite3_value_text(val[argi]);
const char *errptr; const char *errptr;
pcre *code; auto_mem<pcre> code;
int eoff; int eoff;
if (pattern == nullptr || pattern[0] == '\0') { if (pattern == nullptr || pattern[0] == '\0') {
@ -101,7 +101,7 @@ struct from_sqlite<pair<string, pcre *>> {
throw from_sqlite_conversion_error(errptr, argi); throw from_sqlite_conversion_error(errptr, argi);
} }
return make_pair(string(pattern), code); return make_pair(string(pattern), std::move(code));
} }
}; };
@ -458,7 +458,7 @@ CREATE TABLE lnav_view_filters (
nonstd::optional<int64_t> _filter_id, nonstd::optional<int64_t> _filter_id,
nonstd::optional<bool> enabled, nonstd::optional<bool> enabled,
nonstd::optional<text_filter::type_t> type, nonstd::optional<text_filter::type_t> type,
pair<string, pcre *> pattern) { pair<string, auto_mem<pcre>> pattern) {
textview_curses &tc = lnav_data.ld_views[view_index]; textview_curses &tc = lnav_data.ld_views[view_index];
text_sub_source *tss = tc.get_sub_source(); text_sub_source *tss = tc.get_sub_source();
filter_stack &fs = tss->get_filters(); filter_stack &fs = tss->get_filters();
@ -470,7 +470,7 @@ CREATE TABLE lnav_view_filters (
type.value_or(text_filter::type_t::EXCLUDE), type.value_or(text_filter::type_t::EXCLUDE),
pattern.first, pattern.first,
*filter_index, *filter_index,
pattern.second); pattern.second.release());
fs.add_filter(pf); fs.add_filter(pf);
if (!enabled.value_or(true)) { if (!enabled.value_or(true)) {
pf->disable(); pf->disable();
@ -506,7 +506,7 @@ CREATE TABLE lnav_view_filters (
int64_t new_filter_id, int64_t new_filter_id,
bool enabled, bool enabled,
text_filter::type_t type, text_filter::type_t type,
pair<string, pcre *> pattern) { pair<string, auto_mem<pcre>> pattern) {
auto view_index = lnav_view_t(rowid >> 32); auto view_index = lnav_view_t(rowid >> 32);
int filter_index = rowid & 0xffffffffLL; int filter_index = rowid & 0xffffffffLL;
textview_curses &tc = lnav_data.ld_views[view_index]; textview_curses &tc = lnav_data.ld_views[view_index];
@ -533,7 +533,7 @@ CREATE TABLE lnav_view_filters (
auto pf = make_shared<pcre_filter>(type, auto pf = make_shared<pcre_filter>(type,
pattern.first, pattern.first,
tf->get_index(), tf->get_index(),
pattern.second); pattern.second.release());
if (!enabled) { if (!enabled) {
pf->disable(); pf->disable();

@ -222,7 +222,7 @@ struct ToSqliteVisitor {
}; };
template<typename T> template<typename T>
void operator()(T t) const { void operator()(T&& t) const {
to_sqlite(this->tsv_context, t); to_sqlite(this->tsv_context, t);
} }

@ -30,6 +30,10 @@ add_executable(test_reltime test_reltime.cc)
target_link_libraries(test_reltime diag PkgConfig::libpcre) target_link_libraries(test_reltime diag PkgConfig::libpcre)
add_test(NAME test_reltime COMMAND test_reltime) add_test(NAME test_reltime COMMAND test_reltime)
add_executable(test_auto_mem test_auto_mem.cc)
target_link_libraries(test_auto_mem diag PkgConfig::libpcre)
add_test(NAME test_auto_mem COMMAND test_auto_mem)
add_executable(test_date_time_scanner test_date_time_scanner.cc) add_executable(test_date_time_scanner test_date_time_scanner.cc)
target_link_libraries(test_date_time_scanner diag PkgConfig::libpcre) target_link_libraries(test_date_time_scanner diag PkgConfig::libpcre)
add_test(NAME test_date_time_scanner COMMAND test_date_time_scanner) add_test(NAME test_date_time_scanner COMMAND test_date_time_scanner)

@ -73,7 +73,7 @@ int main(int argc, char *argv[])
assert(md1.in() == &md1_val); assert(md1.in() == &md1_val);
{ {
auto_mem<struct my_data, my_free> md_cp(md1); auto_mem<struct my_data, my_free> md_cp(std::move(md1));
assert(md1 == NULL); assert(md1 == NULL);
assert(free_count == 2); assert(free_count == 2);

Loading…
Cancel
Save