77#ifndef __FLYWEIGHT_HPP__
78#define __FLYWEIGHT_HPP__
83#include <unordered_map>
91 constexpr static size_t hash_combine(
size_t a,
size_t b) {
92 return a ^ b + 0x9e3779b9 + (a << 6) + (a >> 2);
96 template<
typename... Args>
98 constexpr size_t operator()(
const std::tuple<Args...>& value)
const {
99 return hash_tuple<std::tuple<Args...>, 0, Args...>(value);
102 template<
typename TTuple,
size_t I,
typename T>
103 constexpr static size_t hash_tuple(
const TTuple& v) {
104 return std::hash<T>{}(std::get<I>(v));
107 template<
typename TTuple,
size_t I,
typename T1,
typename T2,
typename... Rest>
108 constexpr static size_t hash_tuple(
const TTuple& v) {
110 hash_tuple<TTuple, I, T1>(v),
111 hash_tuple<TTuple, I+1, T2, Rest...>(v)
118 struct refcounted_value {
124 refcounted_value(T&& value) : value(value), refcount(0) {}
131 refcounted_value& reference() {
140 return refcount <= 0;
145 template<
typename Fn,
typename... Args>
146 auto apply(Fn&& f, std::tuple<Args...>&& t) {
147 return std::apply(std::move(f), std::move(t));
155 template<
int N,
int... S>
156 struct gens : gens<N-1, N-1, S...> {};
159 struct gens<0, S...> {
160 using type = seq<S...>;
163 template<
typename... Args>
165 template<
typename Fn,
int... S>
166 static auto invoke(Fn&& f, std::tuple<Args...>&& t, seq<S...>) {
167 return f(std::forward<Args>(std::get<S>(t))...);
171 template<
typename Fn,
typename... Args>
172 auto apply(Fn&& f, std::tuple<Args...>&& t) {
173 return apply_impl<Args...>::invoke(std::move(f), std::move(t),
typename gens<
sizeof...(Args)>::type{});
183template<
typename T,
typename... Args>
187 return T { std::forward<Args>(args)... };
203template<
typename T,
typename Flyweight,
typename ArgTuple>
211 , arg_tuple(arg_tuple)
218 : value(other.
flyweight.get(other.arg_tuple))
220 , arg_tuple(other.arg_tuple)
230 value = other.flyweight.get(other.arg_tuple);
232 arg_tuple = other.arg_tuple;
271template<
typename T,
typename... Args>
275 using autorelease_value = autorelease_value<T,
flyweight, std::tuple<Args...>>;
284 template<
typename Creator>
286 : creator([creator](Args&&... args) {
return creator(std::forward<Args>(args)...); })
296 template<
typename Creator,
typename Deleter>
298 : creator([creator](Args&&... args) {
return creator(std::forward<Args>(args)...); })
299 , deleter([deleter](T& value) { deleter(value); })
309 T&
get(
const std::tuple<Args...>& arg_tuple) {
310 auto it = map.find(arg_tuple);
311 if (it == map.end()) {
312 it = map.emplace(arg_tuple, detail::apply(creator, (std::tuple<Args...>) arg_tuple)).first;
317 template<
bool uses_multiple_args = (
sizeof...(Args) > 1)>
318 auto get(Args&&... args) ->
typename std::enable_if<uses_multiple_args, T&>::type {
319 return get(std::tuple<Args...> { std::forward<Args>(args)... });
333 template<
bool uses_multiple_args = (
sizeof...(Args) > 1)>
334 auto get_autorelease(Args&&... args) ->
typename std::enable_if<uses_multiple_args, autorelease_value>::type {
335 return get_autorelease(std::tuple<Args...> { std::forward<Args>(args)... });
339 bool is_loaded(
const std::tuple<Args...>& arg_tuple)
const {
340 return map.find(arg_tuple) != map.end();
343 template<
bool uses_multiple_args = (
sizeof...(Args) > 1)>
344 auto is_loaded(Args&&... args)
const ->
typename std::enable_if<uses_multiple_args, bool>::type {
345 return is_loaded(std::tuple<Args...> { std::forward<Args>(args)... });
351 bool release(
const std::tuple<Args...>& arg_tuple) {
352 auto it = map.find(arg_tuple);
353 if (it != map.end()) {
363 template<
bool uses_multiple_args = (
sizeof...(Args) > 1)>
364 auto release(Args&&... args) ->
typename std::enable_if<uses_multiple_args, bool>::type {
365 return release(std::tuple<Args...> { std::forward<Args>(args)... });
371 std::unordered_map<std::tuple<Args...>, T, detail::tuple_hasher<Args...>>
map;
391template<
typename T,
typename... Args>
401 template<
typename Creator>
405 template<
typename Creator,
typename Deleter>
410 T&
get(
const std::tuple<Args...>& arg_tuple) {
412 return value.reference();
415 template<
bool uses_multiple_args = (
sizeof...(Args) > 1)>
416 auto get(Args&&... args) ->
typename std::enable_if<uses_multiple_args, T&>::type {
417 return get(std::tuple<Args...> { std::forward<Args>(args)... });
430 template<
bool uses_multiple_args = (
sizeof...(Args) > 1)>
431 auto get_autorelease(Args&&... args) ->
typename std::enable_if<uses_multiple_args, autorelease_value>::type {
432 return get_autorelease(std::tuple<Args...> { std::forward<Args>(args)... });
440 return it->second.refcount;
447 template<
bool uses_multiple_args = (
sizeof...(Args) > 1)>
448 auto reference_count(Args&&... args)
const ->
typename std::enable_if<uses_multiple_args, size_t>::type {
449 return reference_count(std::tuple<Args...> { std::forward<Args>(args)... });
454 bool release(
const std::tuple<Args...>& arg_tuple) {
456 if (it !=
base::map.end() && it->second.dereference()) {
466 template<
bool uses_multiple_args = (
sizeof...(Args) > 1)>
467 auto release(Args&&... args) ->
typename std::enable_if<uses_multiple_args, bool>::type {
468 return release(std::tuple<Args...> { std::forward<Args>(args)... });
Definition: flyweight.hpp:392
flyweight_refcounted(Creator &&creator)
Definition: flyweight.hpp:402
auto release(Args &&... args) -> typename std::enable_if< uses_multiple_args, bool >::type
Alternative to flyweight_refcounted::release with the arguments unpacked.
Definition: flyweight.hpp:467
auto get_autorelease(Args &&... args) -> typename std::enable_if< uses_multiple_args, autorelease_value >::type
Alternative to flyweight_refcounted::get_autorelease with the arguments unpacked.
Definition: flyweight.hpp:431
auto reference_count(Args &&... args) const -> typename std::enable_if< uses_multiple_args, size_t >::type
Alternative to flyweight_refcounted::reference_count with the arguments unpacked.
Definition: flyweight.hpp:448
auto get(Args &&... args) -> typename std::enable_if< uses_multiple_args, T & >::type
Alternative to flyweight_refcounted::get with the arguments unpacked.
Definition: flyweight.hpp:416
flyweight_refcounted(Creator &&creator, Deleter &&deleter)
Definition: flyweight.hpp:406
autorelease_value get_autorelease(const std::tuple< Args... > &arg_tuple)
Definition: flyweight.hpp:422
T & get(const std::tuple< Args... > &arg_tuple)
Definition: flyweight.hpp:410
size_t reference_count(const std::tuple< Args... > &arg_tuple) const
Definition: flyweight.hpp:437
flyweight_refcounted()
Definition: flyweight.hpp:398
bool release(const std::tuple< Args... > &arg_tuple)
Definition: flyweight.hpp:454
Definition: flyweight.hpp:272
flyweight(Creator &&creator)
Definition: flyweight.hpp:285
flyweight(Creator &&creator, Deleter &&deleter)
Definition: flyweight.hpp:297
std::unordered_map< std::tuple< Args... >, T, detail::tuple_hasher< Args... > > map
Definition: flyweight.hpp:371
flyweight()
Definition: flyweight.hpp:279
std::function< void(T &)> deleter
Definition: flyweight.hpp:377
auto is_loaded(Args &&... args) const -> typename std::enable_if< uses_multiple_args, bool >::type
Alternative to flyweight::is_loaded with the arguments unpacked.
Definition: flyweight.hpp:344
auto get_autorelease(Args &&... args) -> typename std::enable_if< uses_multiple_args, autorelease_value >::type
Alternative to flyweight::get_autorelease with the arguments unpacked.
Definition: flyweight.hpp:334
auto release(Args &&... args) -> typename std::enable_if< uses_multiple_args, bool >::type
Alternative to flyweight::release with the arguments unpacked.
Definition: flyweight.hpp:364
bool is_loaded(const std::tuple< Args... > &arg_tuple) const
Check whether the value mapped to the passed arguments is loaded.
Definition: flyweight.hpp:339
T & get(const std::tuple< Args... > &arg_tuple)
Definition: flyweight.hpp:309
auto get(Args &&... args) -> typename std::enable_if< uses_multiple_args, T & >::type
Alternative to flyweight::get with the arguments unpacked.
Definition: flyweight.hpp:318
bool release(const std::tuple< Args... > &arg_tuple)
Definition: flyweight.hpp:351
autorelease_value get_autorelease(const std::tuple< Args... > &arg_tuple)
Definition: flyweight.hpp:325
std::function< T(Args &&...)> creator
Definition: flyweight.hpp:374
Value wrapper that releases it back to the owning flyweight upon destruction.
Definition: flyweight.hpp:204
autorelease_value(const autorelease_value &other)
Definition: flyweight.hpp:217
T & operator*()
Returns the wrapped value.
Definition: flyweight.hpp:236
~autorelease_value()
Release the value back to the owning flyweight.
Definition: flyweight.hpp:249
T & operator->()
Returns the wrapped value.
Definition: flyweight.hpp:240
autorelease_value(T &value, Flyweight &flyweight, const ArgTuple &arg_tuple)
Constructor.
Definition: flyweight.hpp:208
autorelease_value & operator=(const autorelease_value &other)
Definition: flyweight.hpp:225
Definition: flyweight.hpp:184
T operator()(Args &&... args)
Default creator implementation, just call the value constructor forwarding the passed arguments.
Definition: flyweight.hpp:186
Definition: flyweight.hpp:195
void operator()(T &)
Default deleter implementation, a no-op.
Definition: flyweight.hpp:197