Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. //
  2. // Copyright 2013 Francisco Jerez
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a
  5. // copy of this software and associated documentation files (the "Software"),
  6. // to deal in the Software without restriction, including without limitation
  7. // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. // and/or sell copies of the Software, and to permit persons to whom the
  9. // Software is furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17. // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18. // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19. // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. // OTHER DEALINGS IN THE SOFTWARE.
  21. //
  22.  
  23. #ifndef CLOVER_UTIL_LAZY_HPP
  24. #define CLOVER_UTIL_LAZY_HPP
  25.  
  26. #include <type_traits>
  27. #include <stdexcept>
  28. #include <memory>
  29.  
  30. namespace clover {
  31.    namespace detail {
  32.       template<typename T>
  33.       class basic_lazy {
  34.       public:
  35.          virtual
  36.          ~basic_lazy() {
  37.          }
  38.  
  39.          virtual basic_lazy *
  40.          clone() const = 0;
  41.  
  42.          virtual
  43.          operator T() const = 0;
  44.       };
  45.  
  46.       template<typename T, typename F>
  47.       class deferred_lazy : public basic_lazy<T> {
  48.       public:
  49.          template<typename G>
  50.          deferred_lazy(G &&f) : f(new F(std::forward<G>(f))) {
  51.          }
  52.  
  53.          virtual basic_lazy<T> *
  54.          clone() const {
  55.             return new deferred_lazy(*this);
  56.          }
  57.  
  58.          operator T() const {
  59.             if (f) {
  60.                x = (*f)();
  61.                f = {};
  62.             }
  63.  
  64.             return x;
  65.          }
  66.  
  67.       private:
  68.          mutable std::shared_ptr<F> f;
  69.          mutable T x;
  70.       };
  71.  
  72.       template<typename T>
  73.       class strict_lazy : public basic_lazy<T> {
  74.       public:
  75.          template<typename S>
  76.          strict_lazy(S &&x) : x(std::forward<S>(x)) {
  77.          }
  78.  
  79.          virtual basic_lazy<T> *
  80.          clone() const {
  81.             return new strict_lazy(*this);
  82.          }
  83.  
  84.          operator T() const {
  85.             return x;
  86.          }
  87.  
  88.       private:
  89.          T x;
  90.       };
  91.    }
  92.  
  93.    ///
  94.    /// Object that represents a value of type \a T that is calculated
  95.    /// lazily as soon as it is required.
  96.    ///
  97.    template<typename T>
  98.    class lazy {
  99.    public:
  100.       class undefined_error : std::logic_error {
  101.       public:
  102.          undefined_error() : std::logic_error("") {
  103.          }
  104.       };
  105.  
  106.       ///
  107.       /// Initialize to some fixed value \a x which isn't calculated
  108.       /// lazily.
  109.       ///
  110.       lazy(T x) : obj(new detail::strict_lazy<T>(x)) {
  111.       }
  112.  
  113.       ///
  114.       /// Initialize by providing a functor \a f that will calculate
  115.       /// the value on-demand.
  116.       ///
  117.       template<typename F>
  118.       lazy(F &&f) : obj(new detail::deferred_lazy<
  119.                            T, typename std::remove_reference<F>::type
  120.                         >(std::forward<F>(f))) {
  121.       }
  122.  
  123.       ///
  124.       /// Initialize to undefined.
  125.       ///
  126.       lazy() : lazy([]() {
  127.                throw undefined_error();
  128.                return T();
  129.             }) {
  130.       }
  131.  
  132.       lazy(const lazy &other) : obj(obj->clone()) {
  133.       }
  134.  
  135.       lazy(lazy &&other) : obj(NULL) {
  136.          std::swap(obj, other.obj);
  137.       }
  138.  
  139.       ~lazy() {
  140.          delete obj;
  141.       }
  142.  
  143.       lazy &
  144.       operator=(lazy other) {
  145.          std::swap(obj, other.obj);
  146.          return *this;
  147.       }
  148.  
  149.       ///
  150.       /// Evaluate the value.
  151.       ///
  152.       operator T() const {
  153.          return *obj;
  154.       }
  155.  
  156.    private:
  157.       detail::basic_lazy<T> *obj;
  158.    };
  159. }
  160.  
  161. #endif
  162.