Line data Source code
1 : /**
2 : * Copyright Soramitsu Co., Ltd. 2017 All Rights Reserved.
3 : * http://soramitsu.co.jp
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #ifndef IROHA_LAZY_INITIALIZER_HPP
19 : #define IROHA_LAZY_INITIALIZER_HPP
20 :
21 : #include <boost/optional.hpp>
22 : #include <functional>
23 :
24 : namespace shared_model {
25 : namespace detail {
26 :
27 : /**
28 : * Lazy class for lazy converting one type to another
29 : * @tparam Target - output type
30 : */
31 : template <typename Target>
32 : class LazyInitializer {
33 : private:
34 : /// Type of generator function
35 : using GeneratorType = std::function<Target()>;
36 :
37 : public:
38 : /**
39 : * Default constructor prevents compilation error in pre 7.2 gcc.
40 : *
41 : * Short explanation: gcc needs default constructor
42 : * when the constructor is inherited (via using Base::Base)
43 : * if the inherited class has default initalizers for any of its members.
44 : * This can be found in shared_model/backend/protobuf/protobuf/block.hpp
45 : * where Lazy fields are initialized via default initializers.
46 : *
47 : * Note that this does not result in default constructor being called, so
48 : * the resulting code is still correct. This is an issue of gcc compiler
49 : * which is resolved in 7.2
50 : *
51 : * For more details: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67054
52 : */
53 : LazyInitializer();
54 :
55 : template <typename T>
56 : explicit LazyInitializer(T &&generator)
57 83646 : : generator_(std::forward<T>(generator)) {}
58 :
59 : using PointerType = typename std::add_pointer_t<Target>;
60 :
61 : const Target &operator*() const {
62 60423 : return *ptr();
63 : }
64 :
65 : const PointerType ptr() const {
66 60431 : if (target_value_ == boost::none) {
67 : // Use type move constructor with emplace
68 : // since Target copy assignment operator could be deleted
69 :
70 46544 : target_value_.emplace(generator_());
71 46544 : }
72 60432 : return target_value_.get_ptr();
73 0 : }
74 :
75 : const PointerType operator->() const {
76 3 : return ptr();
77 : }
78 :
79 : /**
80 : * Remove generated value. Next ptr() call will generate new value
81 : */
82 : void invalidate() const {
83 : target_value_ = boost::none;
84 : }
85 :
86 : private:
87 : GeneratorType generator_;
88 : mutable boost::optional<Target> target_value_;
89 : };
90 :
91 : /**
92 : * Function for creating lazy object
93 : * @tparam Generator - type of generator
94 : * @param generator - instance of Generator
95 : * @return initialized lazy value
96 : */
97 : template <typename Generator>
98 : auto makeLazyInitializer(Generator &&generator) {
99 : using targetType = decltype(generator());
100 865 : return LazyInitializer<targetType>(std::forward<Generator>(generator));
101 : }
102 : } // namespace detail
103 : } // namespace shared_model
104 : #endif // IROHA_LAZY_INITIALIZER_HPP
|