17ec681f3Smrg// 27ec681f3Smrg// Copyright 2013 Francisco Jerez 37ec681f3Smrg// 47ec681f3Smrg// Permission is hereby granted, free of charge, to any person obtaining a 57ec681f3Smrg// copy of this software and associated documentation files (the "Software"), 67ec681f3Smrg// to deal in the Software without restriction, including without limitation 77ec681f3Smrg// the rights to use, copy, modify, merge, publish, distribute, sublicense, 87ec681f3Smrg// and/or sell copies of the Software, and to permit persons to whom the 97ec681f3Smrg// Software is furnished to do so, subject to the following conditions: 107ec681f3Smrg// 117ec681f3Smrg// The above copyright notice and this permission notice shall be included in 127ec681f3Smrg// all copies or substantial portions of the Software. 137ec681f3Smrg// 147ec681f3Smrg// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 157ec681f3Smrg// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 167ec681f3Smrg// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 177ec681f3Smrg// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 187ec681f3Smrg// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 197ec681f3Smrg// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 207ec681f3Smrg// OTHER DEALINGS IN THE SOFTWARE. 217ec681f3Smrg// 227ec681f3Smrg 237ec681f3Smrg#ifndef CLOVER_UTIL_LAZY_HPP 247ec681f3Smrg#define CLOVER_UTIL_LAZY_HPP 257ec681f3Smrg 267ec681f3Smrg#include <type_traits> 277ec681f3Smrg#include <stdexcept> 287ec681f3Smrg#include <memory> 297ec681f3Smrg 307ec681f3Smrgnamespace clover { 317ec681f3Smrg namespace detail { 327ec681f3Smrg template<typename T> 337ec681f3Smrg class basic_lazy { 347ec681f3Smrg public: 357ec681f3Smrg virtual 367ec681f3Smrg ~basic_lazy() { 377ec681f3Smrg } 387ec681f3Smrg 397ec681f3Smrg virtual basic_lazy * 407ec681f3Smrg clone() const = 0; 417ec681f3Smrg 427ec681f3Smrg virtual 437ec681f3Smrg operator T() const = 0; 447ec681f3Smrg }; 457ec681f3Smrg 467ec681f3Smrg template<typename T, typename F> 477ec681f3Smrg class deferred_lazy : public basic_lazy<T> { 487ec681f3Smrg public: 497ec681f3Smrg template<typename G> 507ec681f3Smrg deferred_lazy(G &&f) : f(new F(std::forward<G>(f))) { 517ec681f3Smrg } 527ec681f3Smrg 537ec681f3Smrg virtual basic_lazy<T> * 547ec681f3Smrg clone() const { 557ec681f3Smrg return new deferred_lazy(*this); 567ec681f3Smrg } 577ec681f3Smrg 587ec681f3Smrg operator T() const { 597ec681f3Smrg if (f) { 607ec681f3Smrg x = (*f)(); 617ec681f3Smrg f = {}; 627ec681f3Smrg } 637ec681f3Smrg 647ec681f3Smrg return x; 657ec681f3Smrg } 667ec681f3Smrg 677ec681f3Smrg private: 687ec681f3Smrg mutable std::shared_ptr<F> f; 697ec681f3Smrg mutable T x; 707ec681f3Smrg }; 717ec681f3Smrg 727ec681f3Smrg template<typename T> 737ec681f3Smrg class strict_lazy : public basic_lazy<T> { 747ec681f3Smrg public: 757ec681f3Smrg template<typename S> 767ec681f3Smrg strict_lazy(S &&x) : x(std::forward<S>(x)) { 777ec681f3Smrg } 787ec681f3Smrg 797ec681f3Smrg virtual basic_lazy<T> * 807ec681f3Smrg clone() const { 817ec681f3Smrg return new strict_lazy(*this); 827ec681f3Smrg } 837ec681f3Smrg 847ec681f3Smrg operator T() const { 857ec681f3Smrg return x; 867ec681f3Smrg } 877ec681f3Smrg 887ec681f3Smrg private: 897ec681f3Smrg T x; 907ec681f3Smrg }; 917ec681f3Smrg } 927ec681f3Smrg 937ec681f3Smrg /// 947ec681f3Smrg /// Object that represents a value of type \a T that is calculated 957ec681f3Smrg /// lazily as soon as it is required. 967ec681f3Smrg /// 977ec681f3Smrg template<typename T> 987ec681f3Smrg class lazy { 997ec681f3Smrg public: 1007ec681f3Smrg class undefined_error : std::logic_error { 1017ec681f3Smrg public: 1027ec681f3Smrg undefined_error() : std::logic_error("") { 1037ec681f3Smrg } 1047ec681f3Smrg }; 1057ec681f3Smrg 1067ec681f3Smrg /// 1077ec681f3Smrg /// Initialize to some fixed value \a x which isn't calculated 1087ec681f3Smrg /// lazily. 1097ec681f3Smrg /// 1107ec681f3Smrg lazy(T x) : obj(new detail::strict_lazy<T>(x)) { 1117ec681f3Smrg } 1127ec681f3Smrg 1137ec681f3Smrg /// 1147ec681f3Smrg /// Initialize by providing a functor \a f that will calculate 1157ec681f3Smrg /// the value on-demand. 1167ec681f3Smrg /// 1177ec681f3Smrg template<typename F> 1187ec681f3Smrg lazy(F &&f) : obj(new detail::deferred_lazy< 1197ec681f3Smrg T, typename std::remove_reference<F>::type 1207ec681f3Smrg >(std::forward<F>(f))) { 1217ec681f3Smrg } 1227ec681f3Smrg 1237ec681f3Smrg /// 1247ec681f3Smrg /// Initialize to undefined. 1257ec681f3Smrg /// 1267ec681f3Smrg lazy() : lazy([]() { 1277ec681f3Smrg throw undefined_error(); 1287ec681f3Smrg return T(); 1297ec681f3Smrg }) { 1307ec681f3Smrg } 1317ec681f3Smrg 1327ec681f3Smrg lazy(const lazy &other) : obj(obj->clone()) { 1337ec681f3Smrg } 1347ec681f3Smrg 1357ec681f3Smrg lazy(lazy &&other) : obj(NULL) { 1367ec681f3Smrg std::swap(obj, other.obj); 1377ec681f3Smrg } 1387ec681f3Smrg 1397ec681f3Smrg ~lazy() { 1407ec681f3Smrg delete obj; 1417ec681f3Smrg } 1427ec681f3Smrg 1437ec681f3Smrg lazy & 1447ec681f3Smrg operator=(lazy other) { 1457ec681f3Smrg std::swap(obj, other.obj); 1467ec681f3Smrg return *this; 1477ec681f3Smrg } 1487ec681f3Smrg 1497ec681f3Smrg /// 1507ec681f3Smrg /// Evaluate the value. 1517ec681f3Smrg /// 1527ec681f3Smrg operator T() const { 1537ec681f3Smrg return *obj; 1547ec681f3Smrg } 1557ec681f3Smrg 1567ec681f3Smrg private: 1577ec681f3Smrg detail::basic_lazy<T> *obj; 1587ec681f3Smrg }; 1597ec681f3Smrg} 1607ec681f3Smrg 1617ec681f3Smrg#endif 162