Skip to content

Commit d8846ba

Browse files
author
atksh
committed
less memory usage
1 parent a22dfb3 commit d8846ba

8 files changed

Lines changed: 255 additions & 246 deletions

File tree

cpp/function_ref.h

Lines changed: 166 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,19 @@
2424
#define TL_FUNCTION_REF_MSVC2015
2525
#endif
2626

27-
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
27+
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
2828
!defined(__clang__))
2929
/// \exclude
3030
#define TL_FUNCTION_REF_GCC49
3131
#endif
3232

33-
#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \
33+
#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \
3434
!defined(__clang__))
3535
/// \exclude
3636
#define TL_FUNCTION_REF_GCC54
3737
#endif
3838

39-
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
39+
#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \
4040
!defined(__clang__))
4141
// GCC < 5 doesn't support overloading on const&& for member functions
4242
/// \exclude
@@ -49,8 +49,8 @@
4949
#endif
5050

5151
// constexpr implies const in C++11, not C++14
52-
#if (__cplusplus == 201103L || defined(TL_FUNCTION_REF_MSVC2015) || \
53-
defined(TL_FUNCTION_REF_GCC49)) && \
52+
#if (__cplusplus == 201103L || defined(TL_FUNCTION_REF_MSVC2015) || \
53+
defined(TL_FUNCTION_REF_GCC49)) && \
5454
!defined(TL_FUNCTION_REF_GCC54)
5555
/// \exclude
5656
#define TL_FUNCTION_REF_11_CONSTEXPR
@@ -62,151 +62,173 @@
6262
#include <functional>
6363
#include <utility>
6464

65-
namespace tl {
66-
namespace detail {
67-
namespace fnref {
68-
// C++14-style aliases for brevity
69-
template <class T> using remove_const_t = typename std::remove_const<T>::type;
70-
template <class T>
71-
using remove_reference_t = typename std::remove_reference<T>::type;
72-
template <class T> using decay_t = typename std::decay<T>::type;
73-
template <bool E, class T = void>
74-
using enable_if_t = typename std::enable_if<E, T>::type;
75-
template <bool B, class T, class F>
76-
using conditional_t = typename std::conditional<B, T, F>::type;
77-
78-
// std::invoke from C++17
79-
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
80-
template <typename Fn, typename... Args,
81-
typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>,
82-
int = 0>
83-
constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
84-
noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
85-
-> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) {
86-
return std::mem_fn(f)(std::forward<Args>(args)...);
87-
}
88-
89-
template <typename Fn, typename... Args,
90-
typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>{}>>
91-
constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
92-
noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
93-
-> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) {
94-
return std::forward<Fn>(f)(std::forward<Args>(args)...);
95-
}
96-
97-
// std::invoke_result from C++17
98-
template <class F, class, class... Us> struct invoke_result_impl;
99-
100-
template <class F, class... Us>
101-
struct invoke_result_impl<
102-
F, decltype(tl::detail::fnref::invoke(std::declval<F>(), std::declval<Us>()...), void()),
103-
Us...> {
104-
using type = decltype(tl::detail::fnref::invoke(std::declval<F>(), std::declval<Us>()...));
105-
};
106-
107-
template <class F, class... Us>
108-
using invoke_result = invoke_result_impl<F, void, Us...>;
109-
110-
template <class F, class... Us>
111-
using invoke_result_t = typename invoke_result<F, Us...>::type;
112-
113-
template <class, class R, class F, class... Args>
114-
struct is_invocable_r_impl : std::false_type {};
115-
116-
template <class R, class F, class... Args>
117-
struct is_invocable_r_impl<
118-
typename std::is_convertible<invoke_result_t<F, Args...>, R>::type, R, F, Args...>
119-
: std::true_type {};
120-
121-
template <class R, class F, class... Args>
122-
using is_invocable_r = is_invocable_r_impl<std::true_type, R, F, Args...>;
123-
124-
} // namespace detail
125-
} // namespace fnref
126-
127-
/// A lightweight non-owning reference to a callable.
128-
///
129-
/// Example usage:
130-
///
131-
/// ```cpp
132-
/// void foo (function_ref<int(int)> func) {
133-
/// std::cout << "Result is " << func(21); //42
134-
/// }
135-
///
136-
/// foo([](int i) { return i*2; });
137-
template <class F> class function_ref;
138-
139-
/// Specialization for function types.
140-
template <class R, class... Args> class function_ref<R(Args...)> {
141-
public:
142-
constexpr function_ref() noexcept = delete;
143-
144-
/// Creates a `function_ref` which refers to the same callable as `rhs`.
145-
constexpr function_ref(const function_ref<R(Args...)> &rhs) noexcept = default;
146-
147-
/// Constructs a `function_ref` referring to `f`.
65+
namespace tl
66+
{
67+
namespace detail
68+
{
69+
namespace fnref
70+
{
71+
// C++14-style aliases for brevity
72+
template <class T>
73+
using remove_const_t = typename std::remove_const<T>::type;
74+
template <class T>
75+
using remove_reference_t = typename std::remove_reference<T>::type;
76+
template <class T>
77+
using decay_t = typename std::decay<T>::type;
78+
template <bool E, class T = void>
79+
using enable_if_t = typename std::enable_if<E, T>::type;
80+
template <bool B, class T, class F>
81+
using conditional_t = typename std::conditional<B, T, F>::type;
82+
83+
// std::invoke from C++17
84+
// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround
85+
template <typename Fn, typename... Args,
86+
typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>::value>,
87+
int = 0>
88+
constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
89+
noexcept(std::mem_fn(f)(std::forward<Args>(args)...)))
90+
-> decltype(std::mem_fn(f)(std::forward<Args>(args)...))
91+
{
92+
return std::mem_fn(f)(std::forward<Args>(args)...);
93+
}
94+
95+
template <typename Fn, typename... Args,
96+
typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>{}>>
97+
constexpr auto invoke(Fn &&f, Args &&... args) noexcept(
98+
noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...)))
99+
-> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...))
100+
{
101+
return std::forward<Fn>(f)(std::forward<Args>(args)...);
102+
}
103+
104+
// std::invoke_result from C++17
105+
template <class F, class, class... Us>
106+
struct invoke_result_impl;
107+
108+
template <class F, class... Us>
109+
struct invoke_result_impl<
110+
F, decltype(tl::detail::fnref::invoke(std::declval<F>(), std::declval<Us>()...), void()),
111+
Us...>
112+
{
113+
using type = decltype(tl::detail::fnref::invoke(std::declval<F>(), std::declval<Us>()...));
114+
};
115+
116+
template <class F, class... Us>
117+
using invoke_result = invoke_result_impl<F, void, Us...>;
118+
119+
template <class F, class... Us>
120+
using invoke_result_t = typename invoke_result<F, Us...>::type;
121+
122+
template <class, class R, class F, class... Args>
123+
struct is_invocable_r_impl : std::false_type
124+
{
125+
};
126+
127+
template <class R, class F, class... Args>
128+
struct is_invocable_r_impl<
129+
typename std::is_convertible<invoke_result_t<F, Args...>, R>::type, R, F, Args...>
130+
: std::true_type
131+
{
132+
};
133+
134+
template <class R, class F, class... Args>
135+
using is_invocable_r = is_invocable_r_impl<std::true_type, R, F, Args...>;
136+
137+
} // namespace fnref
138+
} // namespace detail
139+
140+
/// A lightweight non-owning reference to a callable.
148141
///
149-
/// \synopsis template <typename F> constexpr function_ref(F &&f) noexcept
150-
template <typename F,
151-
detail::fnref::enable_if_t<
152-
!std::is_same<detail::fnref::decay_t<F>, function_ref>::value &&
153-
detail::fnref::is_invocable_r<R, F &&, Args...>::value> * = nullptr>
154-
TL_FUNCTION_REF_11_CONSTEXPR function_ref(F &&f) noexcept
155-
: obj_(const_cast<void*>(reinterpret_cast<const void *>(std::addressof(f)))) {
156-
callback_ = [](void *obj, Args... args) -> R {
157-
return detail::fnref::invoke(
158-
*reinterpret_cast<typename std::add_pointer<F>::type>(obj),
159-
std::forward<Args>(args)...);
160-
};
161-
}
162-
163-
/// Makes `*this` refer to the same callable as `rhs`.
164-
TL_FUNCTION_REF_11_CONSTEXPR function_ref<R(Args...)> &
165-
operator=(const function_ref<R(Args...)> &rhs) noexcept = default;
166-
167-
/// Makes `*this` refer to `f`.
142+
/// Example usage:
168143
///
169-
/// \synopsis template <typename F> constexpr function_ref &operator=(F &&f) noexcept;
170-
template <typename F,
171-
detail::fnref::enable_if_t<detail::fnref::is_invocable_r<R, F &&, Args...>::value>
172-
* = nullptr>
173-
TL_FUNCTION_REF_11_CONSTEXPR function_ref<R(Args...)> &operator=(F &&f) noexcept {
174-
obj_ = reinterpret_cast<void *>(std::addressof(f));
175-
callback_ = [](void *obj, Args... args) {
176-
return detail::fnref::invoke(
177-
*reinterpret_cast<typename std::add_pointer<F>::type>(obj),
178-
std::forward<Args>(args)...);
179-
};
180-
181-
return *this;
182-
}
183-
184-
/// Swaps the referred callables of `*this` and `rhs`.
185-
constexpr void swap(function_ref<R(Args...)> &rhs) noexcept {
186-
std::swap(obj_, rhs.obj_);
187-
std::swap(callback_, rhs.callback_);
188-
}
144+
/// ```cpp
145+
/// void foo (function_ref<int(int)> func) {
146+
/// std::cout << "Result is " << func(21); //42
147+
/// }
148+
///
149+
/// foo([](int i) { return i*2; });
150+
template <class F>
151+
class function_ref;
152+
153+
/// Specialization for function types.
154+
template <class R, class... Args>
155+
class function_ref<R(Args...)>
156+
{
157+
public:
158+
constexpr function_ref() noexcept = delete;
159+
160+
/// Creates a `function_ref` which refers to the same callable as `rhs`.
161+
constexpr function_ref(const function_ref<R(Args...)> &rhs) noexcept = default;
189162

190-
/// Call the stored callable with the given arguments.
191-
R operator()(Args... args) const {
192-
return callback_(obj_, std::forward<Args>(args)...);
163+
/// Constructs a `function_ref` referring to `f`.
164+
///
165+
/// \synopsis template <typename F> constexpr function_ref(F &&f) noexcept
166+
template <typename F,
167+
detail::fnref::enable_if_t<
168+
!std::is_same<detail::fnref::decay_t<F>, function_ref>::value &&
169+
detail::fnref::is_invocable_r<R, F &&, Args...>::value> * = nullptr>
170+
TL_FUNCTION_REF_11_CONSTEXPR function_ref(F &&f) noexcept
171+
: obj_(const_cast<void *>(reinterpret_cast<const void *>(std::addressof(f))))
172+
{
173+
callback_ = [](void *obj, Args... args) -> R {
174+
return detail::fnref::invoke(
175+
*reinterpret_cast<typename std::add_pointer<F>::type>(obj),
176+
std::forward<Args>(args)...);
177+
};
178+
}
179+
180+
/// Makes `*this` refer to the same callable as `rhs`.
181+
TL_FUNCTION_REF_11_CONSTEXPR function_ref<R(Args...)> &
182+
operator=(const function_ref<R(Args...)> &rhs) noexcept = default;
183+
184+
/// Makes `*this` refer to `f`.
185+
///
186+
/// \synopsis template <typename F> constexpr function_ref &operator=(F &&f) noexcept;
187+
template <typename F,
188+
detail::fnref::enable_if_t<detail::fnref::is_invocable_r<R, F &&, Args...>::value>
189+
* = nullptr>
190+
TL_FUNCTION_REF_11_CONSTEXPR function_ref<R(Args...)> &operator=(F &&f) noexcept
191+
{
192+
obj_ = reinterpret_cast<void *>(std::addressof(f));
193+
callback_ = [](void *obj, Args... args) {
194+
return detail::fnref::invoke(
195+
*reinterpret_cast<typename std::add_pointer<F>::type>(obj),
196+
std::forward<Args>(args)...);
197+
};
198+
199+
return *this;
200+
}
201+
202+
/// Swaps the referred callables of `*this` and `rhs`.
203+
constexpr void swap(function_ref<R(Args...)> &rhs) noexcept
204+
{
205+
std::swap(obj_, rhs.obj_);
206+
std::swap(callback_, rhs.callback_);
207+
}
208+
209+
/// Call the stored callable with the given arguments.
210+
R operator()(Args... args) const
211+
{
212+
return callback_(obj_, std::forward<Args>(args)...);
213+
}
214+
215+
private:
216+
void *obj_ = nullptr;
217+
R (*callback_)
218+
(void *, Args...) = nullptr;
219+
};
220+
221+
/// Swaps the referred callables of `lhs` and `rhs`.
222+
template <typename R, typename... Args>
223+
constexpr void swap(function_ref<R(Args...)> &lhs,
224+
function_ref<R(Args...)> &rhs) noexcept
225+
{
226+
lhs.swap(rhs);
193227
}
194228

195-
private:
196-
void *obj_ = nullptr;
197-
R (*callback_)(void *, Args...) = nullptr;
198-
};
199-
200-
/// Swaps the referred callables of `lhs` and `rhs`.
201-
template <typename R, typename... Args>
202-
constexpr void swap(function_ref<R(Args...)> &lhs,
203-
function_ref<R(Args...)> &rhs) noexcept {
204-
lhs.swap(rhs);
205-
}
206-
207229
#if __cplusplus >= 201703L
208-
template <typename R, typename... Args>
209-
function_ref(R (*)(Args...))->function_ref<R(Args...)>;
230+
template <typename R, typename... Args>
231+
function_ref(R (*)(Args...))->function_ref<R(Args...)>;
210232

211233
// TODO, will require some kind of callable traits
212234
// template <typename F>

cpp/parallel.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,20 @@ void parallel_for_each(const Iter first, const Iter last, T &result, const F &fu
3434
threads.emplace_back(std::thread([&, t] { std::for_each(iters[t], iters[t + 1], [&](auto &x) { f(x, rr[t]); }); }));
3535
}
3636
std::for_each(threads.begin(), threads.end(), [&](std::thread &x) { x.join(); });
37+
threads.clear();
38+
std::vector<std::thread>().swap(threads);
39+
iters.clear();
40+
std::vector<Iter>().swap(iters);
3741
}
3842
for (int t = 0; t < nthreads; t++)
3943
{
4044
result.insert(result.end(),
4145
std::make_move_iterator(rr[t].begin()),
4246
std::make_move_iterator(rr[t].end()));
47+
rr[t].clear();
48+
T().swap(rr[t]);
4349
}
50+
std::vector<T>().swap(rr);
4451
}
4552

4653
template <typename F, typename Iter>
@@ -67,5 +74,9 @@ void parallel_for_each(const Iter first, const Iter last, const F &func)
6774
threads.emplace_back(std::thread([&, t] { std::for_each(iters[t], iters[t + 1], [&](auto &x) { f(x); }); }));
6875
}
6976
std::for_each(threads.begin(), threads.end(), [&](std::thread &x) { x.join(); });
77+
threads.clear();
78+
std::vector<std::thread>().swap(threads);
79+
iters.clear();
80+
std::vector<Iter>().swap(iters);
7081
}
7182
}

0 commit comments

Comments
 (0)