Skip to content

Commit 62076bd

Browse files
committed
util: update sorted_interval_list
1 parent 4b02b4e commit 62076bd

5 files changed

Lines changed: 55 additions & 12 deletions

File tree

ortools/util/python/proto.i

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,9 @@ namespace operations_research {
5757
%typemap(argout) CppType* const, CppType* {
5858
std::string encoded_protobuf;
5959
$1->SerializeToString(&encoded_protobuf);
60-
#if defined(PY3)
6160
PyObject* const python_encoded_protobuf =
6261
PyBytes_FromStringAndSize(encoded_protobuf.c_str(),
6362
encoded_protobuf.size());
64-
#else // PY3
65-
PyObject* const python_encoded_protobuf =
66-
PyString_FromStringAndSize(encoded_protobuf.c_str(),
67-
encoded_protobuf.size());
68-
#endif // PY3
6963
if (python_encoded_protobuf != nullptr) {
7064
PyObject* const result = PyObject_CallMethod(
7165
$input, const_cast<char*>("ParseFromString"),
@@ -84,13 +78,8 @@ namespace operations_research {
8478
if (clss != nullptr) {
8579
std::string encoded_protobuf;
8680
$1.SerializeToString(&encoded_protobuf);
87-
#if defined(PY3)
8881
PyObject* const python_encoded_protobuf = PyBytes_FromStringAndSize(
8982
encoded_protobuf.c_str(), encoded_protobuf.size());
90-
#else // PY3
91-
PyObject* const python_encoded_protobuf = PyString_FromStringAndSize(
92-
encoded_protobuf.c_str(), encoded_protobuf.size());
93-
#endif // PY3
9483
PyObject* const result = PyObject_CallMethod(
9584
clss, const_cast<char*>("FromString"),
9685
const_cast<char*>("(O)"),

ortools/util/python/sorted_interval_list_doc.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,14 @@ R"doc(Returns a compact string of a vector of intervals like
336336

337337
static const char *mkd_doc_operations_research_Domain_UnionWith = R"doc(Returns the union of D and domain.)doc";
338338

339+
static const char *mkd_doc_operations_research_Domain_UniqueValueNotIn =
340+
R"doc(If this \minus other is a singleton, returns it. Returns nullopt
341+
otherwise.
342+
343+
This is similar to checking if
344+
this.IntersectionWith(other.Complement()) is non-empty and fixed, but
345+
avoid allocating memory.)doc";
346+
339347
static const char *mkd_doc_operations_research_Domain_ValueAtOrAfter = R"doc()doc";
340348

341349
static const char *mkd_doc_operations_research_Domain_ValueAtOrBefore =

ortools/util/sorted_interval_list.cc

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <cstdint>
1919
#include <cstdlib>
2020
#include <limits>
21+
#include <optional>
2122
#include <ostream>
2223
#include <string>
2324
#include <utility>
@@ -454,6 +455,42 @@ Domain Domain::IntersectionWith(const Domain& domain) const {
454455
return result;
455456
}
456457

458+
std::optional<int64_t> Domain::UniqueValueNotIn(const Domain& other) const {
459+
std::optional<int64_t> result;
460+
int i = 0;
461+
const auto& to_exclude = other.intervals_;
462+
for (auto [start, end] : intervals_) {
463+
while (start <= end) {
464+
// find the first interval with to_exclude[i].end >= start.
465+
while (i < to_exclude.size() && to_exclude[i].end < start) ++i;
466+
if (i < to_exclude.size()) {
467+
DCHECK_GE(to_exclude[i].end, start);
468+
if (to_exclude[i].start <= start) {
469+
if (to_exclude[i].end == kint64max) return result;
470+
start = to_exclude[i].end + 1;
471+
continue;
472+
}
473+
// Notice that if end > start, there will be no overflow here.
474+
if (end == start || to_exclude[i].start == start + 1) {
475+
if (result != std::nullopt) return std::nullopt;
476+
result = start;
477+
if (to_exclude[i].end == kint64max) return result;
478+
start = to_exclude[i].end + 1;
479+
continue;
480+
}
481+
return std::nullopt;
482+
} else if (end == start) {
483+
if (result != std::nullopt) return std::nullopt;
484+
result = start;
485+
break; // Next interval.
486+
} else {
487+
return std::nullopt;
488+
}
489+
}
490+
}
491+
return result;
492+
}
493+
457494
Domain Domain::UnionWith(const Domain& domain) const {
458495
Domain result;
459496
const auto& a = intervals_;

ortools/util/sorted_interval_list.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,14 @@ class Domain {
506506
ABSL_MUST_USE_RESULT Domain
507507
SimplifyUsingImpliedDomain(const Domain& implied_domain) const;
508508

509+
/**
510+
* If this \minus other is a singleton, returns it. Returns nullopt otherwise.
511+
*
512+
* This is similar to checking if this.IntersectionWith(other.Complement()) is
513+
* non-empty and fixed, but avoid allocating memory.
514+
*/
515+
std::optional<int64_t> UniqueValueNotIn(const Domain& other) const;
516+
509517
/**
510518
* Returns a compact string of a vector of intervals like "[1,4][6][10,20]".
511519
*/

ortools/util/testing_utils.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@
1717
namespace operations_research {
1818

1919
inline constexpr bool kAsanEnabled = false;
20+
inline constexpr bool kHwAsanEnabled = false;
2021
inline constexpr bool kMsanEnabled = false;
2122
inline constexpr bool kTsanEnabled = false;
2223
inline bool ProbablyRunningInsideUnitTest() { return false; }
2324

2425
inline constexpr bool kAnyXsanEnabled =
25-
kAsanEnabled || kMsanEnabled || kTsanEnabled;
26+
kAsanEnabled || kMsanEnabled || kTsanEnabled || kHwAsanEnabled;
2627

2728
} // namespace operations_research
2829

0 commit comments

Comments
 (0)