Google OR-Tools v9.11
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
lazy_mutable_copy.h
Go to the documentation of this file.
1// Copyright 2010-2024 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14#ifndef OR_TOOLS_UTIL_LAZY_MUTABLE_COPY_H_
15#define OR_TOOLS_UTIL_LAZY_MUTABLE_COPY_H_
16
17#include <memory>
18
19namespace operations_research {
20
21// LazyMutableCopy<T> is a helper class for making an on-demand copy of an
22// object of arbitrary type T. Type T must have a copy constructor.
23//
24// Sample usage:
25// const Proto& original_input = ...;
26// LazyMutableCopy<Proto> input(original_input);
27// if (input.get().foo() == BAD_VALUE) {
28// input.get_mutable()->set_foo(GOOD_VALUE); // Copies the object.
29// }
30// // Process "input" here without worrying about BAD_VALUE.
31// A good pattern is to have function taking LazyMutableCopy<> as argument:
32// void ProcessProto(LazyMutableCopy<Proto> input) { // pass by copy
33// ...
34// }
35// At the call site: ProcessProto(const_ref_to_my_proto);
36//
37// In basic usage, a LazyMutableCopy is in one of two states:
38// - original: points to the const original. No memory allocated.
39// - copy: points to a mutable copy of the original and owns it. Owning the
40// copy means that the destructor will delete it, like std::unique_ptr<>.
41// This is what you get by calling get_mutable() or constructing it with
42// a move.
43template <class T>
45 public:
46 // You can construct a LazyMutableCopy with a const reference to an object,
47 // which must outlive this class (unless get_mutable() was called).
48 LazyMutableCopy(const T& obj) // NOLINT(google-explicit-constructor)
49 : ptr_(&obj) {}
50
51 // The other option is to construct a LazyMutableCopy with a std::move(T).
52 // In this case you transfer ownership and you can mutate it for free.
53 LazyMutableCopy(T&& obj) // NOLINT(google-explicit-constructor)
54 : copy_(std::make_unique<T>(std::move(obj))), ptr_(copy_.get()) {}
55
56 // You can move a LazyMutableCopy but not copy it, much like a
57 // std::unique_ptr<>.
61 class LazyMutableCopy<T>& operator=(const LazyMutableCopy<T>&) = delete;
62
63 // This will copy the object if we don't already have ownership.
65 if (copy_ == nullptr && ptr_ != nullptr) {
66 copy_ = std::make_unique<T>(*ptr_);
67 ptr_ = copy_.get();
68 }
69 return copy_.get();
70 }
71
72 // Lazily make a copy if not already done and transfer ownership from this
73 // class to the returned std::unique_ptr<T>. Calling this function leaves the
74 // class in a state where the only valid operations is to assign it a new
75 // value.
76 //
77 // We force a call via
78 // std::move(lazy_mutable_copy).copy_or_move_as_unique_ptr() to make it
79 // clearer that lazy_mutable_copy shouldn't really be used after this.
80 std::unique_ptr<T> copy_or_move_as_unique_ptr() && {
81 if (copy_ == nullptr && ptr_ != nullptr) {
82 std::unique_ptr<T> result = std::make_unique<T>(*ptr_);
83 ptr_ = nullptr;
84 return result;
85 }
86 ptr_ = nullptr;
87 return std::move(copy_);
88 }
89
90 // True iff get_mutable() was called at least once (in which case the object
91 // was copied) or if we constructed this via std::move().
92 bool has_ownership() const { return copy_ != nullptr; }
93
94 // Standard smart pointer accessor, but only for const purpose.
95 // Undefined if the class contains no object.
96 const T* get() const { return ptr_; }
97 const T& operator*() const { return *ptr_; }
98 const T* operator->() const { return ptr_; }
99
100 // Destroys any owned value. Calling this function leaves the class in a state
101 // where the only valid operations is to assign it a new value.
102 //
103 // We force a call via std::move(lazy_mutable_copy).dispose() to make it
104 // clearer that lazy_mutable_copy shouldn't really be used after this.
105 void dispose() && {
106 ptr_ = nullptr;
107 copy_ = nullptr;
108 }
109
110 private:
111 std::unique_ptr<T> copy_;
112 const T* ptr_ = nullptr;
113};
114
115} // namespace operations_research
116
117#endif // OR_TOOLS_UTIL_LAZY_MUTABLE_COPY_H_
LazyMutableCopy(const LazyMutableCopy &)=delete
class LazyMutableCopy< T > & operator=(const LazyMutableCopy< T > &)=delete
T * get_mutable()
This will copy the object if we don't already have ownership.
LazyMutableCopy(LazyMutableCopy &&)=default
class LazyMutableCopy< T > & operator=(LazyMutableCopy< T > &&)=default
std::unique_ptr< T > copy_or_move_as_unique_ptr() &&
In SWIG mode, we don't want anything besides these top-level includes.
STL namespace.