24#include "absl/container/flat_hash_set.h"
25#include "absl/status/status.h"
26#include "absl/strings/str_cat.h"
27#include "absl/strings/string_view.h"
28#include "absl/types/span.h"
36constexpr double kInf = std::numeric_limits<double>::infinity();
39absl::Status CheckSortedIdsSubsetWithIndexOffset(
40 const absl::Span<const int64_t> ids,
41 const absl::Span<const int64_t> universe,
const int64_t offset) {
43 int universe_index = 0;
46 while (id_index < ids.size() && universe_index < universe.size()) {
47 if (universe[universe_index] < ids[id_index]) {
49 }
else if (universe[universe_index] == ids[id_index]) {
55 if (id_index < ids.size()) {
57 <<
"Bad id: " << ids[id_index] <<
" (at index: " << id_index + offset
60 return absl::OkStatus();
71 explicit FastIdCheck(
const absl::Span<const int64_t> ids) {
73 interval_mode_ =
true;
74 }
else if (ids.size() == ids.back() + 1 - ids.front()) {
75 interval_mode_ =
true;
76 interval_lb_ = ids.front();
77 interval_ub_ = ids.back() + 1;
79 ids_ = absl::flat_hash_set<int64_t>(ids.begin(), ids.end());
82 bool contains(int64_t
id)
const {
84 return id >= interval_lb_ &&
id < interval_ub_;
86 return ids_.contains(
id);
91 bool interval_mode_ =
false;
92 int64_t interval_lb_ = 0;
93 int64_t interval_ub_ = 0;
94 absl::flat_hash_set<int64_t> ids_;
100absl::Status CheckSortedIdsNotBad(
const absl::Span<const int64_t> ids,
101 const absl::Span<const int64_t> bad_list) {
104 while (id_index < ids.size() && bad_index < bad_list.size()) {
105 if (bad_list[bad_index] < ids[id_index]) {
107 }
else if (bad_list[bad_index] > ids[id_index]) {
111 <<
"Bad id: " << ids[id_index] <<
" (at index: " << id_index
115 return absl::OkStatus();
120 int64_t previous{-1};
121 for (
int i = 0; i < ids.size(); previous = ids[i], ++i) {
124 <<
"Expected ids to be nonnegative and not max(int64_t) but at "
126 << i <<
" found id: " << ids[i];
128 if (ids[i] <= previous) {
130 <<
"Expected ids to be strictly increasing, but at index " << i
131 <<
" found id: " << ids[i] <<
" and at index " << i - 1
132 <<
" found id: " << ids[i - 1];
135 return absl::OkStatus();
139 const absl::Span<const int64_t> universe) {
140 RETURN_IF_ERROR(CheckSortedIdsSubsetWithIndexOffset(ids, universe, 0));
141 return absl::OkStatus();
145 const absl::Span<const int64_t> universe) {
147 return absl::OkStatus();
149 const FastIdCheck id_check(universe);
150 for (
int i = 0; i < ids.size(); ++i) {
151 if (!id_check.contains(ids[i])) {
153 <<
"Bad id: " << ids[i] <<
" (at index: " << i <<
") not found";
156 return absl::OkStatus();
160 for (
int i = 0; i < deleted_ids_.size(); ++i) {
161 const int64_t deleted_id = deleted_ids_[i];
162 if (!old_ids_.
HasId(deleted_id)) {
164 <<
"Tried to delete id: " << deleted_id <<
" (at index: " << i
165 <<
") but it was not present";
168 if (!new_ids_.empty() && new_ids_.front() < old_ids_.
next_free_id()) {
170 <<
"All new ids should be greater or equal to the first unused id: "
172 <<
" but the first new id was: " << new_ids_.front();
174 return absl::OkStatus();
178 const absl::Span<const int64_t> ids)
const {
179 RETURN_IF_ERROR(CheckSortedIdsNotBad(ids, deleted_ids_)) <<
" was deleted";
180 for (
int i = 0; i < ids.size(); ++i) {
181 if (!old_ids_.
HasId(ids[i])) {
183 <<
"Bad id: " << ids[i] <<
" (at index: " << i <<
") not found";
186 return absl::OkStatus();
190 const absl::Span<const int64_t> ids)
const {
195 size_t split_point = ids.size();
196 if (!new_ids_.empty()) {
202 RETURN_IF_ERROR(CheckSortedIdsSubsetWithIndexOffset(ids.subspan(split_point),
203 new_ids_, split_point));
204 return absl::OkStatus();
208 const absl::Span<const int64_t> ids)
const {
210 return absl::OkStatus();
212 const FastIdCheck deleted_fast(deleted_ids_);
213 const FastIdCheck new_fast(new_ids_);
214 for (
int i = 0; i < ids.size(); ++i) {
215 const int64_t
id = ids[i];
216 if (!new_ids_.empty() &&
id >= new_ids_[0]) {
217 if (!new_fast.contains(
id)) {
219 <<
"Bad id: " <<
id <<
" (at index: " << i <<
") not found";
221 }
else if (!old_ids_.
HasId(
id)) {
223 <<
"Bad id: " <<
id <<
" (at index: " << i <<
") not found";
224 }
else if (deleted_fast.contains(
id)) {
226 <<
"Bad id: " <<
id <<
" (at index: " << i <<
") was deleted";
229 return absl::OkStatus();
234 absl::string_view ids_description,
235 absl::string_view universe_description) {
236 for (
int i = 0; i < ids.size(); ++i) {
237 const int64_t
id = ids[i];
238 if (!universe.
HasId(
id)) {
240 <<
"Id: " <<
id <<
" (at index: " << i <<
") in "
241 << ids_description <<
" is missing from " << universe_description;
244 return absl::OkStatus();
249 absl::string_view first_description,
250 absl::string_view second_description) {
251 if (first_ids.size() != second_ids.
Size()) {
253 << first_description <<
" has size " << first_ids.size() <<
", but "
254 << second_description <<
" has size " << second_ids.
Size();
257 second_description));
258 return absl::OkStatus();
int64_t next_free_id() const
bool HasId(int64_t id) const
absl::Status CheckSortedIdsSubsetOfFinal(const absl::Span< const int64_t > ids) const
absl::Status CheckIdsSubsetOfFinal(const absl::Span< const int64_t > ids) const
absl::Status CheckSortedIdsSubsetOfNotDeleted(const absl::Span< const int64_t > ids) const
absl::Status IsValid() const
absl::Status CheckUnsortedIdsSubset(const absl::Span< const int64_t > ids, const absl::Span< const int64_t > universe)
absl::Status CheckIdsRangeAndStrictlyIncreasing(absl::Span< const int64_t > ids)
absl::Status CheckSortedIdsSubset(const absl::Span< const int64_t > ids, const absl::Span< const int64_t > universe)
absl::Status CheckIdsSubset(absl::Span< const int64_t > ids, const IdNameBiMap &universe, absl::string_view ids_description, absl::string_view universe_description)
absl::Status CheckIdsIdentical(absl::Span< const int64_t > first_ids, const IdNameBiMap &second_ids, absl::string_view first_description, absl::string_view second_description)
Collection of objects used to extend the Constraint Solver library.
StatusBuilder InvalidArgumentErrorBuilder()
#define RETURN_IF_ERROR(expr)