0,0 → 1,161 |
// |
// Copyright 2013 Francisco Jerez |
// |
// Permission is hereby granted, free of charge, to any person obtaining a |
// copy of this software and associated documentation files (the "Software"), |
// to deal in the Software without restriction, including without limitation |
// the rights to use, copy, modify, merge, publish, distribute, sublicense, |
// and/or sell copies of the Software, and to permit persons to whom the |
// Software is furnished to do so, subject to the following conditions: |
// |
// The above copyright notice and this permission notice shall be included in |
// all copies or substantial portions of the Software. |
// |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
// OTHER DEALINGS IN THE SOFTWARE. |
// |
|
#ifndef CLOVER_UTIL_LAZY_HPP |
#define CLOVER_UTIL_LAZY_HPP |
|
#include <type_traits> |
#include <stdexcept> |
#include <memory> |
|
namespace clover { |
namespace detail { |
template<typename T> |
class basic_lazy { |
public: |
virtual |
~basic_lazy() { |
} |
|
virtual basic_lazy * |
clone() const = 0; |
|
virtual |
operator T() const = 0; |
}; |
|
template<typename T, typename F> |
class deferred_lazy : public basic_lazy<T> { |
public: |
template<typename G> |
deferred_lazy(G &&f) : f(new F(std::forward<G>(f))) { |
} |
|
virtual basic_lazy<T> * |
clone() const { |
return new deferred_lazy(*this); |
} |
|
operator T() const { |
if (f) { |
x = (*f)(); |
f = {}; |
} |
|
return x; |
} |
|
private: |
mutable std::shared_ptr<F> f; |
mutable T x; |
}; |
|
template<typename T> |
class strict_lazy : public basic_lazy<T> { |
public: |
template<typename S> |
strict_lazy(S &&x) : x(std::forward<S>(x)) { |
} |
|
virtual basic_lazy<T> * |
clone() const { |
return new strict_lazy(*this); |
} |
|
operator T() const { |
return x; |
} |
|
private: |
T x; |
}; |
} |
|
/// |
/// Object that represents a value of type \a T that is calculated |
/// lazily as soon as it is required. |
/// |
template<typename T> |
class lazy { |
public: |
class undefined_error : std::logic_error { |
public: |
undefined_error() : std::logic_error("") { |
} |
}; |
|
/// |
/// Initialize to some fixed value \a x which isn't calculated |
/// lazily. |
/// |
lazy(T x) : obj(new detail::strict_lazy<T>(x)) { |
} |
|
/// |
/// Initialize by providing a functor \a f that will calculate |
/// the value on-demand. |
/// |
template<typename F> |
lazy(F &&f) : obj(new detail::deferred_lazy< |
T, typename std::remove_reference<F>::type |
>(std::forward<F>(f))) { |
} |
|
/// |
/// Initialize to undefined. |
/// |
lazy() : lazy([]() { |
throw undefined_error(); |
return T(); |
}) { |
} |
|
lazy(const lazy &other) : obj(obj->clone()) { |
} |
|
lazy(lazy &&other) : obj(NULL) { |
std::swap(obj, other.obj); |
} |
|
~lazy() { |
delete obj; |
} |
|
lazy & |
operator=(lazy other) { |
std::swap(obj, other.obj); |
return *this; |
} |
|
/// |
/// Evaluate the value. |
/// |
operator T() const { |
return *obj; |
} |
|
private: |
detail::basic_lazy<T> *obj; |
}; |
} |
|
#endif |