Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:01:18

0001 #ifndef CommonTools_Utils_LazyResult_h
0002 #define CommonTools_Utils_LazyResult_h
0003 // -*- C++ -*-
0004 //
0005 // Package:     CommonTools/Utils
0006 // Class  :     LazyResult
0007 //
0008 /**\class LazyResult LazyResult.h "CommonTools/Utils/interface/LazyResult.h"
0009  Description: Wrapper around a function call for lazy execution.
0010 
0011  Usage:
0012     // example: lazy addition
0013     auto result = LazyResult(std::plus<int>, x, x);
0014     std::cout << result.value() << std::endl;
0015 
0016 Notes:
0017   * The arguments for the delayed call are stored by reference (watch their
0018     lifetime).
0019   * The overhead in memory compared to just storing the result is small: one
0020     reference per argument, one bool flag and a function pointer (on my system:
0021     1 byte for lambda function, 8 bytes for global function and 16 bytes for
0022     member function due to possible index to virtual table).
0023 
0024 Implementation:
0025 
0026   * For the Args... we explicitly add const& (also in the the args_ tuple).
0027     Otherwise, the arguments will be stored by value which comes with too much
0028     overhead. This implies that the lifetime of the arguments passed to
0029     LazyResult neet to live longer than the LazyResult instance. Function pointers
0030     are small, so no need for const& to the Func.
0031   * An alternative to using a ::value() member function to get the result could
0032     be a cast operator: operator Result const &(). This might be pretty because
0033     the result is automatically evaluated the first time you try to bind it to
0034     a Result const &. I think this would however be too implicit and dangerous.
0035 
0036 */
0037 //
0038 // Original Author:  Jonas Rembser
0039 //         Created:  Mon, 14 Jun 2020 00:00:00 GMT
0040 //
0041 
0042 #include <tuple>
0043 #include <type_traits>
0044 
0045 template <class Func, class... Args>
0046 class LazyResult {
0047 public:
0048   using Result = typename std::invoke_result<Func, Args...>::type;
0049 
0050   LazyResult(Func func, Args const&... args) : func_(func), args_(args...) {}
0051 
0052   Result const& value() {
0053     if (!evaluated_) {
0054       evaluate();
0055     }
0056     return result_;
0057   }
0058 
0059 private:
0060   void evaluate() { evaluateImpl(std::make_index_sequence<sizeof...(Args)>{}); }
0061 
0062   template <std::size_t... ArgIndices>
0063   void evaluateImpl(std::index_sequence<ArgIndices...>) {
0064     result_ = func_(std::get<ArgIndices>(args_)...);
0065     evaluated_ = true;
0066   }
0067 
0068   // having evaluated_ and the potentially small func_ together might
0069   // save alignemnt bits (e.g. a lambda function is just 1 byte)
0070   bool evaluated_ = false;
0071   Func func_;
0072   std::tuple<Args const&...> args_;
0073   Result result_;
0074 };
0075 
0076 #endif