Google OR-Tools v9.14
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
element_storage.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 OR_TOOLS_MATH_OPT_ELEMENTAL_ELEMENT_STORAGE_H_
15#define OR_TOOLS_MATH_OPT_ELEMENTAL_ELEMENT_STORAGE_H_
16
17#include <algorithm>
18#include <cstdint>
19#include <string>
20#include <utility>
21#include <variant>
22#include <vector>
23
24#include "absl/container/flat_hash_map.h"
25#include "absl/status/statusor.h"
26#include "absl/strings/string_view.h"
28
30
31namespace detail {
32
33// A dense element storage, for use when no elements have been erased.
34// Same API as `ElementStorage`, but no deletion.
35// TODO(b/369972336): We should stay in dense mode if we have a small percentage
36// of deletions.
38 public:
39 int64_t Add(const absl::string_view name) {
40 const int64_t id = elements_.size();
41 elements_.emplace_back(name);
42 return id;
43 }
44
45 bool exists(const int64_t id) const {
46 return 0 <= id && id < elements_.size();
47 }
48
49 absl::StatusOr<absl::string_view> GetName(const int64_t id) const {
50 if (exists(id)) {
51 return elements_[id];
52 }
53 return util::InvalidArgumentErrorBuilder() << "no element with id " << id;
54 }
55
56 int64_t next_id() const { return size(); }
57
58 std::vector<int64_t> AllIds() const;
59
60 int64_t size() const { return elements_.size(); }
61
62 private:
64 std::vector<std::string> elements_;
65};
66
67// A sparse element storage, which supports deletion.
69 public:
71
72 int64_t Add(const absl::string_view name) {
73 const int64_t id = next_id_;
74 elements_.try_emplace(id, name);
75 ++next_id_;
76 return id;
77 }
78
79 bool Erase(int64_t id) { return elements_.erase(id) > 0; }
80
81 bool exists(int64_t id) const { return elements_.contains(id); }
82
83 absl::StatusOr<absl::string_view> GetName(int64_t id) const {
84 if (const auto it = elements_.find(id); it != elements_.end()) {
85 return it->second;
86 }
87 return util::InvalidArgumentErrorBuilder() << "no element with id " << id;
88 }
89
90 int64_t next_id() const { return next_id_; }
91
92 std::vector<int64_t> AllIds() const;
93
94 int64_t size() const { return elements_.size(); }
95
96 void ensure_next_id_at_least(int64_t id) {
97 next_id_ = std::max(next_id_, id);
98 }
99
100 private:
101 absl::flat_hash_map<int64_t, std::string> elements_;
102 int64_t next_id_ = 0;
103};
104
105} // namespace detail
106
108 // Functions with deduced return must be defined before they are used.
109 private:
110 // std::visit is very slow, see
111 // 5253596299885805568
112 //
113 // This function is static, taking Self as template argument, to avoid
114 // having const and non-const versions. Post C++ 23, prefer:
115 // https://en.cppreference.com/w/cpp/language/member_functions#Explicit_object_member_functions
116 template <typename Self, typename Fn>
117 static auto Visit(Self& self, Fn fn) {
118 if (std::holds_alternative<detail::DenseElementStorage>(self.impl_)) {
119 return fn(std::get<detail::DenseElementStorage>(self.impl_));
120 } else {
121 return fn(std::get<detail::SparseElementStorage>(self.impl_));
122 }
123 }
124
125 public:
126 // We start with a dense storage, which is more efficient, and switch to a
127 // sparse storage when an element is erased.
128 ElementStorage() : impl_(detail::DenseElementStorage()) {}
129
130 // Creates a new element and returns its id.
131 int64_t Add(const absl::string_view name) {
132 return Visit(*this, [name](auto& impl) { return impl.Add(name); });
133 }
134
135 // Deletes an element by id, returning true on success and false if no element
136 // was deleted (it was already deleted or the id was not from any existing
137 // element).
138 bool Erase(const int64_t id) { return AsSparse().Erase(id); }
139
140 // Returns true an element with this id was created and not yet erased.
141 bool Exists(const int64_t id) const {
142 return Visit(*this, [id](auto& impl) { return impl.exists(id); });
143 }
144
145 // Returns the name of this element, or CHECK fails if no element with this id
146 // exists.
147 absl::StatusOr<absl::string_view> GetName(const int64_t id) const {
148 return Visit(*this, [id](auto& impl) { return impl.GetName(id); });
149 }
150
151 // Returns the id that will be used for the next element added.
152 //
153 // NOTE: when no elements have been erased, this equals size().
154 int64_t next_id() const {
155 return Visit(*this, [](auto& impl) { return impl.next_id(); });
156 }
157
158 // Returns all ids of all elements in the model in an unsorted,
159 // non-deterministic order.
160 std::vector<int64_t> AllIds() const;
161
162 // Returns the number of elements added and not erased.
163 int64_t size() const {
164 return Visit(*this, [](auto& impl) { return impl.size(); });
165 }
166
167 // Increases next_id() to `id` if it is currently less than `id`.
168 //
169 // Useful for reading a model back from proto, most users should not need to
170 // call this directly.
171 void EnsureNextIdAtLeast(const int64_t id) {
172 if (id > next_id()) {
173 AsSparse().ensure_next_id_at_least(id);
174 }
175 }
176
177 private:
178 detail::SparseElementStorage& AsSparse() {
179 if (auto* sparse = std::get_if<detail::SparseElementStorage>(&impl_)) {
180 return *sparse;
181 }
182 impl_ = detail::SparseElementStorage(
183 std::move(std::get<detail::DenseElementStorage>(impl_)));
184 return std::get<detail::SparseElementStorage>(impl_);
185 }
186
187 std::variant<detail::DenseElementStorage, detail::SparseElementStorage> impl_;
188};
189
190} // namespace operations_research::math_opt
191
192#endif // OR_TOOLS_MATH_OPT_ELEMENTAL_ELEMENT_STORAGE_H_
int64_t size() const
Returns the number of elements added and not erased.
absl::StatusOr< absl::string_view > GetName(const int64_t id) const
int64_t Add(const absl::string_view name)
Creates a new element and returns its id.
bool Exists(const int64_t id) const
Returns true an element with this id was created and not yet erased.
absl::StatusOr< absl::string_view > GetName(const int64_t id) const
A sparse element storage, which supports deletion.
absl::StatusOr< absl::string_view > GetName(int64_t id) const
An object oriented wrapper for quadratic constraints in ModelStorage.
Definition gurobi_isv.cc:28
StatusBuilder InvalidArgumentErrorBuilder()