Google OR-Tools v9.15
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
model.h
Go to the documentation of this file.
1// Copyright 2010-2025 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 ORTOOLS_SAT_MODEL_H_
15#define ORTOOLS_SAT_MODEL_H_
16
17#include <cstddef>
18#include <cstdio>
19#include <ctime>
20#include <functional>
21#include <memory>
22#include <string>
23#include <vector>
24
25#include "absl/container/flat_hash_map.h"
26#include "absl/log/check.h"
28
29namespace operations_research {
30namespace sat {
31
38class Model {
39 // FastTypeId<Type>() evaluates at compile/link-time to a unique integer for
40 // the passed in type. Their values are neither contiguous nor small, making
41 // them unfit for using as an index into a vector, but a good match for keys
42 // into maps or straight up comparisons. Note that on 64-bit (unix) systems
43 // size_t is 64-bit while int is 32-bit and the compiler will happily and
44 // quietly assign such a 64-bit value to a 32-bit integer. While a client
45 // should never do that it SHOULD still be safe, assuming the BSS segment
46 // doesn't span more than 4GiB.
47 template <typename Type>
48 static inline size_t FastTypeId() {
49 static_assert(sizeof(char*) <= sizeof(size_t),
50 "ptr size too large for size_t");
51
52 // This static variable isn't actually used, only its address, so there are
53 // no concurrency issues.
54 static char dummy_var;
55 return reinterpret_cast<size_t>(&dummy_var);
56 }
57
58 public:
59 Model() = default;
60
62 // The order of deletion seems to be platform dependent.
63 // We force a reverse order on the cleanup vector.
64 for (int i = cleanup_list_.size() - 1; i >= 0; --i) {
65 cleanup_list_[i].reset();
66 }
67 }
68
73 explicit Model(std::string name) : name_(name) {}
74
75 // This type is neither copyable nor movable.
76 Model(const Model&) = delete;
77 Model& operator=(const Model&) = delete;
78
103 template <typename T>
104 T Add(std::function<T(Model*)> f) {
105 return f(this);
106 }
107
109 template <typename T>
110 T Get(std::function<T(const Model&)> f) const {
111 return f(*this);
112 }
113
128 template <typename T>
130 const size_t type_id = FastTypeId<T>();
131 auto find = singletons_.find(type_id);
132 if (find != singletons_.end()) {
133 return static_cast<T*>(find->second);
134 }
135
136 // New element.
137 // TODO(user): directly store std::unique_ptr<> in singletons_?
138 T* new_t = MyNew<T>(0);
139 singletons_[type_id] = new_t;
140 TakeOwnership(new_t);
141 return new_t;
142 }
143
149 template <typename T>
150 const T* Get() const {
151 const auto& it = singletons_.find(FastTypeId<T>());
152 return it != singletons_.end() ? static_cast<const T*>(it->second)
153 : nullptr;
154 }
155
159 template <typename T>
160 T* Mutable() const {
161 const auto& it = singletons_.find(FastTypeId<T>());
162 return it != singletons_.end() ? static_cast<T*>(it->second) : nullptr;
163 }
164
170 template <typename T>
171 T* TakeOwnership(T* t) {
172 cleanup_list_.emplace_back(new Delete<T>(t));
173 return t;
174 }
175
181 template <typename T>
182 T* Create() {
183 T* new_t = MyNew<T>(0);
184 TakeOwnership(new_t);
185 return new_t;
186 }
187
193 template <typename T>
194 void Register(T* non_owned_class) {
195 const size_t type_id = FastTypeId<T>();
196 CHECK(!singletons_.contains(type_id));
197 singletons_[type_id] = non_owned_class;
198 }
199
200 const std::string& Name() const { return name_; }
201
202 private:
203 // We want to call the constructor T(model*) if it exists or just T() if
204 // it doesn't. For this we use some template "magic":
205 // - The first MyNew() will only be defined if the type in decltype() exist.
206 // - The second MyNew() will always be defined, but because of the ellipsis
207 // it has lower priority that the first one.
208 template <typename T>
209 decltype(T(static_cast<Model*>(nullptr)))* MyNew(int) {
210 return new T(this);
211 }
212 template <typename T>
213 T* MyNew(...) {
214 return new T();
215 }
216
217 const std::string name_;
218
219 // Map of FastTypeId<T> to a "singleton" of type T.
220 absl::flat_hash_map</*typeid*/ size_t, void*> singletons_;
221
222 struct DeleteInterface {
223 virtual ~DeleteInterface() = default;
224 };
225 template <typename T>
226 class Delete : public DeleteInterface {
227 public:
228 explicit Delete(T* t) : to_delete_(t) {}
229 ~Delete() override = default;
230
231 private:
232 std::unique_ptr<T> to_delete_;
233 };
234
235 // The list of items to delete.
236 //
237 // TODO(user): I don't think we need the two layers of unique_ptr, but we
238 // don't care too much about efficiency here and this was easier to get
239 // working.
240 std::vector<std::unique_ptr<DeleteInterface>> cleanup_list_;
241};
242
243} // namespace sat
244} // namespace operations_research
245
246#endif // ORTOOLS_SAT_MODEL_H_
T Add(std::function< T(Model *)> f)
Definition model.h:104
T Get(std::function< T(const Model &)> f) const
Similar to Add() but this is const.
Definition model.h:110
Model(std::string name)
Definition model.h:73
const std::string & Name() const
Definition model.h:200
Model(const Model &)=delete
void Register(T *non_owned_class)
Definition model.h:194
Model & operator=(const Model &)=delete
const T * Get() const
Definition model.h:150
OR-Tools root namespace.