FYI: find ortools \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i 's/\(Copyright 2010\)-2018/\1-2021/g'
992 lines
38 KiB
C++
992 lines
38 KiB
C++
// Copyright 2010-2021 Google LLC
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#ifndef OR_TOOLS_BASE_STL_UTIL_H_
|
|
#define OR_TOOLS_BASE_STL_UTIL_H_
|
|
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <deque>
|
|
#include <forward_list>
|
|
#include <functional>
|
|
#include <iterator>
|
|
#include <list>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <type_traits>
|
|
#include <vector>
|
|
|
|
#include "absl/meta/type_traits.h"
|
|
#include "absl/strings/internal/resize_uninitialized.h"
|
|
#include "ortools/base/integral_types.h"
|
|
#include "ortools/base/macros.h"
|
|
|
|
namespace gtl {
|
|
namespace internal {
|
|
template <typename LessFunc>
|
|
class Equiv {
|
|
public:
|
|
explicit Equiv(const LessFunc& f) : f_(f) {}
|
|
template <typename T>
|
|
bool operator()(const T& a, const T& b) const {
|
|
return !f_(b, a) && !f_(a, b);
|
|
}
|
|
|
|
private:
|
|
LessFunc f_;
|
|
};
|
|
} // namespace internal
|
|
|
|
// Sorts and removes duplicates from a sequence container.
|
|
// If specified, the 'less_func' is used to compose an
|
|
// equivalence comparator for the sorting and uniqueness tests.
|
|
template <typename T, typename LessFunc>
|
|
inline void STLSortAndRemoveDuplicates(T* v, const LessFunc& less_func) {
|
|
std::sort(v->begin(), v->end(), less_func);
|
|
v->erase(std::unique(v->begin(), v->end(),
|
|
gtl::internal::Equiv<LessFunc>(less_func)),
|
|
v->end());
|
|
}
|
|
template <typename T>
|
|
inline void STLSortAndRemoveDuplicates(T* v) {
|
|
std::sort(v->begin(), v->end());
|
|
v->erase(std::unique(v->begin(), v->end()), v->end());
|
|
}
|
|
|
|
// Stable sorts and removes duplicates from a sequence container, retaining
|
|
// the first equivalent element for each equivalence set.
|
|
// The 'less_func' is used to compose an equivalence comparator for the sorting
|
|
// and uniqueness tests.
|
|
template <typename T, typename LessFunc>
|
|
inline void STLStableSortAndRemoveDuplicates(T* v, const LessFunc& less_func) {
|
|
std::stable_sort(v->begin(), v->end(), less_func);
|
|
v->erase(std::unique(v->begin(), v->end(),
|
|
gtl::internal::Equiv<LessFunc>(less_func)),
|
|
v->end());
|
|
}
|
|
// Stable sorts and removes duplicates from a sequence container, retaining
|
|
// the first equivalent element for each equivalence set, using < comparison and
|
|
// == equivalence testing.
|
|
template <typename T>
|
|
inline void STLStableSortAndRemoveDuplicates(T* v) {
|
|
std::stable_sort(v->begin(), v->end());
|
|
v->erase(std::unique(v->begin(), v->end()), v->end());
|
|
}
|
|
|
|
// Remove every occurrence of element e in v. See
|
|
// http://en.wikipedia.org/wiki/Erase-remove_idiom.
|
|
template <typename T, typename E>
|
|
void STLEraseAllFromSequence(T* v, const E& e) {
|
|
v->erase(std::remove(v->begin(), v->end(), e), v->end());
|
|
}
|
|
template <typename T, typename A, typename E>
|
|
void STLEraseAllFromSequence(std::list<T, A>* c, const E& e) {
|
|
c->remove(e);
|
|
}
|
|
template <typename T, typename A, typename E>
|
|
void STLEraseAllFromSequence(std::forward_list<T, A>* c, const E& e) {
|
|
c->remove(e);
|
|
}
|
|
|
|
// Remove each element e in v satisfying pred(e).
|
|
template <typename T, typename P>
|
|
void STLEraseAllFromSequenceIf(T* v, P pred) {
|
|
v->erase(std::remove_if(v->begin(), v->end(), pred), v->end());
|
|
}
|
|
template <typename T, typename A, typename P>
|
|
void STLEraseAllFromSequenceIf(std::list<T, A>* c, P pred) {
|
|
c->remove_if(pred);
|
|
}
|
|
template <typename T, typename A, typename P>
|
|
void STLEraseAllFromSequenceIf(std::forward_list<T, A>* c, P pred) {
|
|
c->remove_if(pred);
|
|
}
|
|
|
|
// Clears internal memory of an STL object by swapping the argument with a new,
|
|
// empty object. STL clear()/reserve(0) does not always free internal memory
|
|
// allocated.
|
|
template <typename T>
|
|
void STLClearObject(T* obj) {
|
|
T tmp;
|
|
tmp.swap(*obj);
|
|
// This reserve(0) is needed because "T tmp" sometimes allocates memory (arena
|
|
// implementation?), even though this may not always work.
|
|
obj->reserve(0);
|
|
}
|
|
// STLClearObject overload for deque, which is missing reserve().
|
|
template <typename T, typename A>
|
|
void STLClearObject(std::deque<T, A>* obj) {
|
|
std::deque<T, A> tmp;
|
|
tmp.swap(*obj);
|
|
}
|
|
|
|
// Calls STLClearObject() if the object is bigger than the specified limit,
|
|
// otherwise calls the object's clear() member. This can be useful if you want
|
|
// to allow the object to hold on to its allocated memory as long as it's not
|
|
// too much.
|
|
//
|
|
// Note: The name is misleading since the object is always cleared, regardless
|
|
// of its size.
|
|
template <typename T>
|
|
inline void STLClearIfBig(T* obj, size_t limit = 1 << 20) {
|
|
if (obj->capacity() >= limit) {
|
|
STLClearObject(obj);
|
|
} else {
|
|
obj->clear();
|
|
}
|
|
}
|
|
// STLClearIfBig overload for deque, which is missing capacity().
|
|
template <typename T, typename A>
|
|
inline void STLClearIfBig(std::deque<T, A>* obj, size_t limit = 1 << 20) {
|
|
if (obj->size() >= limit) {
|
|
STLClearObject(obj);
|
|
} else {
|
|
obj->clear();
|
|
}
|
|
}
|
|
|
|
// Removes all elements and reduces the number of buckets in a hash_set or
|
|
// hash_map back to the default if the current number of buckets is "limit" or
|
|
// more.
|
|
//
|
|
// Adding items to a hash container may add buckets, but removing items or
|
|
// calling clear() does not necessarily reduce the number of buckets. Having
|
|
// lots of buckets is good if you insert comparably many items in every
|
|
// iteration because you'll reduce collisions and table resizes. But having lots
|
|
// of buckets is bad if you insert few items in most subsequent iterations,
|
|
// because repeatedly clearing out all those buckets can get expensive.
|
|
//
|
|
// One solution is to call STLClearHashIfBig() with a "limit" value that is a
|
|
// small multiple of the typical number of items in your table. In the common
|
|
// case, this is equivalent to an ordinary clear. In the rare case where you
|
|
// insert a lot of items, the number of buckets is reset to the default to keep
|
|
// subsequent clear operations cheap. Note that the default number of buckets is
|
|
// 193 in the Gnu library implementation as of Jan '08.
|
|
template <typename T>
|
|
inline void STLClearHashIfBig(T* obj, size_t limit) {
|
|
if (obj->bucket_count() >= limit) {
|
|
T tmp;
|
|
tmp.swap(*obj);
|
|
} else {
|
|
obj->clear();
|
|
}
|
|
}
|
|
|
|
// Reserves space in the given string only if the existing capacity is not
|
|
// already enough. This is useful for strings because string::reserve() may
|
|
// *shrink* the capacity in some cases, which is usually not what users want.
|
|
// The behavior of this function is similar to that of vector::reserve() but for
|
|
// string.
|
|
inline void STLStringReserveIfNeeded(std::string* s, size_t min_capacity) {
|
|
if (min_capacity > s->capacity()) s->reserve(min_capacity);
|
|
}
|
|
|
|
// Like str->resize(new_size), except any new characters added to "*str" as a
|
|
// result of resizing may be left uninitialized, rather than being filled with
|
|
// '0' bytes. Typically used when code is then going to overwrite the backing
|
|
// store of the string with known data.
|
|
template <typename T, typename Traits, typename Alloc>
|
|
inline void STLStringResizeUninitialized(std::basic_string<T, Traits, Alloc>* s,
|
|
size_t new_size) {
|
|
absl::strings_internal::STLStringResizeUninitialized(s, new_size);
|
|
}
|
|
|
|
// Returns true if the string implementation supports a resize where
|
|
// the new characters added to the string are left untouched.
|
|
//
|
|
// (A better name might be "STLStringSupportsUninitializedResize", alluding to
|
|
// the previous function.)
|
|
template <typename T, typename Traits, typename Alloc>
|
|
inline bool STLStringSupportsNontrashingResize(
|
|
const std::basic_string<T, Traits, Alloc>& s) {
|
|
return absl::strings_internal::STLStringSupportsNontrashingResize(&s);
|
|
}
|
|
|
|
// Assigns the n bytes starting at ptr to the given string. This is intended to
|
|
// be faster than string::assign() in SOME cases, however, it's actually slower
|
|
// in some cases as well.
|
|
//
|
|
// Just use string::assign directly unless you have benchmarks showing that this
|
|
// function makes your code faster. (Even then, a future version of
|
|
// string::assign() may be faster than this.)
|
|
inline void STLAssignToString(std::string* str, const char* ptr, size_t n) {
|
|
STLStringResizeUninitialized(str, n);
|
|
if (n == 0) return;
|
|
memcpy(&*str->begin(), ptr, n);
|
|
}
|
|
|
|
// Appends the n bytes starting at ptr to the given string. This is intended to
|
|
// be faster than string::append() in SOME cases, however, it's actually slower
|
|
// in some cases as well.
|
|
//
|
|
// Just use string::append directly unless you have benchmarks showing that this
|
|
// function makes your code faster. (Even then, a future version of
|
|
// string::append() may be faster than this.)
|
|
inline void STLAppendToString(std::string* str, const char* ptr, size_t n) {
|
|
if (n == 0) return;
|
|
size_t old_size = str->size();
|
|
STLStringResizeUninitialized(str, old_size + n);
|
|
memcpy(&*str->begin() + old_size, ptr, n);
|
|
}
|
|
|
|
// Returns a mutable char* pointing to a string's internal buffer, which may not
|
|
// be null-terminated. Returns nullptr for an empty string. If not non-null,
|
|
// writing through this pointer will modify the string.
|
|
//
|
|
// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
|
|
// next call to a string method that invalidates iterators.
|
|
//
|
|
// In C++11 you may simply use &str[0] to get a mutable char*.
|
|
//
|
|
// Prior to C++11, there was no standard-blessed way of getting a mutable
|
|
// reference to a string's internal buffer. The requirement that string be
|
|
// contiguous is officially part of the C++11 standard [string.require]/5.
|
|
// According to Matt Austern, this should already work on all current C++98
|
|
// implementations.
|
|
inline char* string_as_array(std::string* str) {
|
|
// DO NOT USE const_cast<char*>(str->data())! See the unittest for why.
|
|
return str->empty() ? nullptr : &*str->begin();
|
|
}
|
|
|
|
// Tests two hash maps/sets for equality. This exists because operator== in the
|
|
// STL can return false when the maps/sets contain identical elements. This is
|
|
// because it compares the internal hash tables which may be different if the
|
|
// order of insertions and deletions differed.
|
|
template <typename HashSet>
|
|
inline bool HashSetEquality(const HashSet& set_a, const HashSet& set_b) {
|
|
if (set_a.size() != set_b.size()) return false;
|
|
for (typename HashSet::const_iterator i = set_a.begin(); i != set_a.end();
|
|
++i)
|
|
if (set_b.find(*i) == set_b.end()) return false;
|
|
return true;
|
|
}
|
|
|
|
// WARNING: Using HashMapEquality for multiple-associative containers like
|
|
// multimap and hash_multimap will result in wrong behavior.
|
|
|
|
template <typename HashMap, typename BinaryPredicate>
|
|
inline bool HashMapEquality(const HashMap& map_a, const HashMap& map_b,
|
|
BinaryPredicate mapped_type_equal) {
|
|
if (map_a.size() != map_b.size()) return false;
|
|
for (typename HashMap::const_iterator i = map_a.begin(); i != map_a.end();
|
|
++i) {
|
|
typename HashMap::const_iterator j = map_b.find(i->first);
|
|
if (j == map_b.end()) return false;
|
|
if (!mapped_type_equal(i->second, j->second)) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// We overload for 'map' without a specialized functor and simply use its
|
|
// operator== function.
|
|
template <typename K, typename V, typename C, typename A>
|
|
inline bool HashMapEquality(const std::map<K, V, C, A>& map_a,
|
|
const std::map<K, V, C, A>& map_b) {
|
|
return map_a == map_b;
|
|
}
|
|
|
|
template <typename HashMap>
|
|
inline bool HashMapEquality(const HashMap& a, const HashMap& b) {
|
|
using Mapped = typename HashMap::mapped_type;
|
|
return HashMapEquality(a, b, std::equal_to<Mapped>());
|
|
}
|
|
|
|
// Calls delete (non-array version) on pointers in the range [begin, end).
|
|
//
|
|
// Note: If you're calling this on an entire container, you probably want to
|
|
// call STLDeleteElements(&container) instead (which also clears the container),
|
|
// or use an ElementDeleter.
|
|
template <typename ForwardIterator>
|
|
void STLDeleteContainerPointers(ForwardIterator begin, ForwardIterator end) {
|
|
while (begin != end) {
|
|
auto temp = begin;
|
|
++begin;
|
|
delete *temp;
|
|
}
|
|
}
|
|
|
|
// Calls delete (non-array version) on BOTH items (pointers) in each pair in the
|
|
// range [begin, end).
|
|
template <typename ForwardIterator>
|
|
void STLDeleteContainerPairPointers(ForwardIterator begin,
|
|
ForwardIterator end) {
|
|
while (begin != end) {
|
|
auto temp = begin;
|
|
++begin;
|
|
delete temp->first;
|
|
delete temp->second;
|
|
}
|
|
}
|
|
|
|
// Calls delete (non-array version) on the FIRST item (pointer) in each pair in
|
|
// the range [begin, end).
|
|
template <typename ForwardIterator>
|
|
void STLDeleteContainerPairFirstPointers(ForwardIterator begin,
|
|
ForwardIterator end) {
|
|
while (begin != end) {
|
|
auto temp = begin;
|
|
++begin;
|
|
delete temp->first;
|
|
}
|
|
}
|
|
|
|
// Calls delete (non-array version) on the SECOND item (pointer) in each pair in
|
|
// the range [begin, end).
|
|
//
|
|
// Note: If you're calling this on an entire container, you probably want to
|
|
// call STLDeleteValues(&container) instead, or use ValueDeleter.
|
|
template <typename ForwardIterator>
|
|
void STLDeleteContainerPairSecondPointers(ForwardIterator begin,
|
|
ForwardIterator end) {
|
|
while (begin != end) {
|
|
auto temp = begin;
|
|
++begin;
|
|
delete temp->second;
|
|
}
|
|
}
|
|
|
|
// Deletes all the elements in an STL container and clears the container. This
|
|
// function is suitable for use with a vector, set, hash_set, or any other STL
|
|
// container which defines sensible begin(), end(), and clear() methods.
|
|
//
|
|
// If container is nullptr, this function is a no-op.
|
|
//
|
|
// As an alternative to calling STLDeleteElements() directly, consider
|
|
// ElementDeleter (defined below), which ensures that your container's elements
|
|
// are deleted when the ElementDeleter goes out of scope.
|
|
template <typename T>
|
|
void STLDeleteElements(T* container) {
|
|
if (!container) return;
|
|
STLDeleteContainerPointers(container->begin(), container->end());
|
|
container->clear();
|
|
}
|
|
|
|
// Given an STL container consisting of (key, value) pairs, STLDeleteValues
|
|
// deletes all the "value" components and clears the container. Does nothing in
|
|
// the case it's given a nullptr.
|
|
template <typename T>
|
|
void STLDeleteValues(T* v) {
|
|
if (!v) return;
|
|
(STLDeleteContainerPairSecondPointers)(v->begin(), v->end());
|
|
v->clear();
|
|
}
|
|
|
|
// A very simple interface that simply provides a virtual destructor. It is used
|
|
// as a non-templated base class for the TemplatedElementDeleter and
|
|
// TemplatedValueDeleter classes.
|
|
//
|
|
// Clients should NOT use this class directly.
|
|
class BaseDeleter {
|
|
public:
|
|
virtual ~BaseDeleter() {}
|
|
BaseDeleter(const BaseDeleter&) = delete;
|
|
void operator=(const BaseDeleter&) = delete;
|
|
|
|
protected:
|
|
BaseDeleter() {}
|
|
};
|
|
|
|
// Given a pointer to an STL container, this class will delete all the element
|
|
// pointers when it goes out of scope.
|
|
//
|
|
// Clients should NOT use this class directly. Use ElementDeleter instead.
|
|
template <typename STLContainer>
|
|
class TemplatedElementDeleter : public BaseDeleter {
|
|
public:
|
|
explicit TemplatedElementDeleter(STLContainer* ptr) : container_ptr_(ptr) {}
|
|
|
|
virtual ~TemplatedElementDeleter() { STLDeleteElements(container_ptr_); }
|
|
|
|
TemplatedElementDeleter(const TemplatedElementDeleter&) = delete;
|
|
void operator=(const TemplatedElementDeleter&) = delete;
|
|
|
|
private:
|
|
STLContainer* container_ptr_;
|
|
};
|
|
|
|
// ElementDeleter is an RAII (go/raii) object that deletes the elements in the
|
|
// given container when it goes out of scope. This is similar to
|
|
// std::unique_ptr<> except that a container's elements will be deleted rather
|
|
// than the container itself.
|
|
//
|
|
// Example:
|
|
// std::vector<MyProto*> tmp_proto;
|
|
// ElementDeleter d(&tmp_proto);
|
|
// if (...) return false;
|
|
// ...
|
|
// return success;
|
|
//
|
|
// Since C++11, consider using containers of std::unique_ptr instead.
|
|
class ElementDeleter {
|
|
public:
|
|
template <typename STLContainer>
|
|
explicit ElementDeleter(STLContainer* ptr)
|
|
: deleter_(new TemplatedElementDeleter<STLContainer>(ptr)) {}
|
|
|
|
~ElementDeleter() { delete deleter_; }
|
|
|
|
ElementDeleter(const ElementDeleter&) = delete;
|
|
void operator=(const ElementDeleter&) = delete;
|
|
|
|
private:
|
|
BaseDeleter* deleter_;
|
|
};
|
|
|
|
// Given a pointer to an STL container this class will delete all the value
|
|
// pointers when it goes out of scope.
|
|
//
|
|
// Clients should NOT use this class directly. Use ValueDeleter instead.
|
|
template <typename STLContainer>
|
|
class TemplatedValueDeleter : public BaseDeleter {
|
|
public:
|
|
explicit TemplatedValueDeleter(STLContainer* ptr) : container_ptr_(ptr) {}
|
|
|
|
virtual ~TemplatedValueDeleter() { STLDeleteValues(container_ptr_); }
|
|
|
|
TemplatedValueDeleter(const TemplatedValueDeleter&) = delete;
|
|
void operator=(const TemplatedValueDeleter&) = delete;
|
|
|
|
private:
|
|
STLContainer* container_ptr_;
|
|
};
|
|
|
|
// ValueDeleter is an RAII (go/raii) object that deletes the 'second' member in
|
|
// the given container of std::pair<>s when it goes out of scope.
|
|
//
|
|
// Example:
|
|
// std::map<std::string, Foo*> foo_map;
|
|
// ValueDeleter d(&foo_map);
|
|
// if (...) return false;
|
|
// ...
|
|
// return success;
|
|
class ValueDeleter {
|
|
public:
|
|
template <typename STLContainer>
|
|
explicit ValueDeleter(STLContainer* ptr)
|
|
: deleter_(new TemplatedValueDeleter<STLContainer>(ptr)) {}
|
|
|
|
~ValueDeleter() { delete deleter_; }
|
|
|
|
ValueDeleter(const ValueDeleter&) = delete;
|
|
void operator=(const ValueDeleter&) = delete;
|
|
|
|
private:
|
|
BaseDeleter* deleter_;
|
|
};
|
|
|
|
// RAII (go/raii) object that deletes elements in the given container when it
|
|
// goes out of scope. Like ElementDeleter (above) except that this class is
|
|
// templated and doesn't have a virtual destructor.
|
|
//
|
|
// New code should prefer ElementDeleter.
|
|
template <typename STLContainer>
|
|
class STLElementDeleter {
|
|
public:
|
|
STLElementDeleter(STLContainer* ptr) : container_ptr_(ptr) {}
|
|
~STLElementDeleter() { STLDeleteElements(container_ptr_); }
|
|
|
|
private:
|
|
STLContainer* container_ptr_;
|
|
};
|
|
|
|
// RAII (go/raii) object that deletes the values in the given container of
|
|
// std::pair<>s when it goes out of scope. Like ValueDeleter (above) except that
|
|
// this class is templated and doesn't have a virtual destructor.
|
|
//
|
|
// New code should prefer ValueDeleter.
|
|
template <typename STLContainer>
|
|
class STLValueDeleter {
|
|
public:
|
|
STLValueDeleter(STLContainer* ptr) : container_ptr_(ptr) {}
|
|
~STLValueDeleter() { STLDeleteValues(container_ptr_); }
|
|
|
|
private:
|
|
STLContainer* container_ptr_;
|
|
};
|
|
|
|
// Sets the referenced pointer to nullptr and returns its original value. This
|
|
// can be a convenient way to remove a pointer from a container to avoid the
|
|
// eventual deletion by an ElementDeleter.
|
|
//
|
|
// Example:
|
|
//
|
|
// std::vector<Foo*> v{new Foo, new Foo, new Foo};
|
|
// ElementDeleter d(&v);
|
|
// Foo* safe = release_ptr(&v[1]);
|
|
// // v[1] is now nullptr and the Foo it previously pointed to is now
|
|
// // stored in "safe"
|
|
template <typename T>
|
|
ABSL_MUST_USE_RESULT T* release_ptr(T** ptr) {
|
|
assert(ptr);
|
|
T* tmp = *ptr;
|
|
*ptr = nullptr;
|
|
return tmp;
|
|
}
|
|
|
|
namespace stl_util_internal {
|
|
|
|
// Like std::less, but allows heterogeneous arguments.
|
|
struct TransparentLess {
|
|
template <typename T>
|
|
bool operator()(const T& a, const T& b) const {
|
|
// std::less is better than '<' here, because it can order pointers.
|
|
return std::less<T>()(a, b);
|
|
}
|
|
template <typename T1, typename T2>
|
|
bool operator()(const T1& a, const T2& b) const {
|
|
return a < b;
|
|
}
|
|
};
|
|
|
|
// Trait to detect whether a type T is an hash table.
|
|
// The heuristic used is that the type contains an inner type `hasher` and does
|
|
// not contain an inner type `reverse_iterator`.
|
|
// If the container is iterable in reverse, then order might actually matter.
|
|
template <typename, typename = void, typename = void>
|
|
struct Unordered : std::false_type {};
|
|
|
|
template <typename T>
|
|
struct Unordered<T, absl::void_t<typename T::hasher>> : std::true_type {};
|
|
|
|
template <typename T>
|
|
struct Unordered<T, absl::void_t<typename T::hasher>,
|
|
absl::void_t<typename T::reverse_iterator>> : std::false_type {
|
|
};
|
|
|
|
} // namespace stl_util_internal
|
|
|
|
// STLSetDifference:
|
|
//
|
|
// In1 STLSetDifference(a, b);
|
|
// In1 STLSetDifference(a, b, compare);
|
|
// void STLSetDifference(a, b, &out);
|
|
// void STLSetDifference(a, b, &out, compare);
|
|
// Out STLSetDifferenceAs<Out>(a, b);
|
|
// Out STLSetDifferenceAs<Out>(a, b, compare);
|
|
//
|
|
// Appends the elements in "a" that are not in "b" to an output container.
|
|
// Optionally specify a comparator, or '<' is used by default. Both input
|
|
// containers must be sorted with respect to the comparator. If specified,
|
|
// the output container must be distinct from both "a" and "b".
|
|
//
|
|
// If an output container pointer is not given, a container will be returned
|
|
// by value. The return type can be explicitly specified by calling
|
|
// STLSetDifferenceAs, but it defaults to the type of argument "a".
|
|
//
|
|
// See std::set_difference() for details on how set difference is computed.
|
|
//
|
|
// The form taking 4 arguments. All other forms call into this one.
|
|
// Explicit comparator, append to output container.
|
|
template <typename In1, typename In2, typename Out, typename Compare>
|
|
void STLSetDifference(const In1& a, const In2& b, Out* out, Compare compare) {
|
|
static_assert(!gtl::stl_util_internal::Unordered<In1>::value,
|
|
"In1 must be an ordered set");
|
|
static_assert(!gtl::stl_util_internal::Unordered<In2>::value,
|
|
"In2 must be an ordered set");
|
|
assert(std::is_sorted(a.begin(), a.end(), compare));
|
|
assert(std::is_sorted(b.begin(), b.end(), compare));
|
|
assert(static_cast<const void*>(&a) != static_cast<const void*>(out));
|
|
assert(static_cast<const void*>(&b) != static_cast<const void*>(out));
|
|
std::set_difference(a.begin(), a.end(), b.begin(), b.end(),
|
|
std::inserter(*out, out->end()), compare);
|
|
}
|
|
// Append to output container, Implicit comparator.
|
|
// Note: The 'enable_if' keeps this overload from participating in
|
|
// overload resolution if 'out' is a function pointer, gracefully forcing
|
|
// the 3-argument overload that treats the third argument as a comparator.
|
|
template <typename In1, typename In2, typename Out>
|
|
typename std::enable_if<!std::is_function<Out>::value, void>::type
|
|
STLSetDifference(const In1& a, const In2& b, Out* out) {
|
|
STLSetDifference(a, b, out, gtl::stl_util_internal::TransparentLess());
|
|
}
|
|
// Explicit comparator, explicit return type.
|
|
template <typename Out, typename In1, typename In2, typename Compare>
|
|
Out STLSetDifferenceAs(const In1& a, const In2& b, Compare compare) {
|
|
Out out;
|
|
STLSetDifference(a, b, &out, compare);
|
|
return out;
|
|
}
|
|
// Implicit comparator, explicit return type.
|
|
template <typename Out, typename In1, typename In2>
|
|
Out STLSetDifferenceAs(const In1& a, const In2& b) {
|
|
return STLSetDifferenceAs<Out>(a, b,
|
|
gtl::stl_util_internal::TransparentLess());
|
|
}
|
|
// Explicit comparator, implicit return type.
|
|
template <typename In1, typename In2, typename Compare>
|
|
In1 STLSetDifference(const In1& a, const In2& b, Compare compare) {
|
|
return STLSetDifferenceAs<In1>(a, b, compare);
|
|
}
|
|
// Implicit comparator, implicit return type.
|
|
template <typename In1, typename In2>
|
|
In1 STLSetDifference(const In1& a, const In2& b) {
|
|
return STLSetDifference(a, b, gtl::stl_util_internal::TransparentLess());
|
|
}
|
|
template <typename In1>
|
|
In1 STLSetDifference(const In1& a, const In1& b) {
|
|
return STLSetDifference(a, b, gtl::stl_util_internal::TransparentLess());
|
|
}
|
|
|
|
// STLSetUnion:
|
|
//
|
|
// In1 STLSetUnion(a, b);
|
|
// In1 STLSetUnion(a, b, compare);
|
|
// void STLSetUnion(a, b, &out);
|
|
// void STLSetUnion(a, b, &out, compare);
|
|
// Out STLSetUnionAs<Out>(a, b);
|
|
// Out STLSetUnionAs<Out>(a, b, compare);
|
|
// Appends the elements in one or both of the input containers to output
|
|
// container "out". Both input containers must be sorted with operator '<',
|
|
// or with the comparator if specified. "out" must be distinct from both "a"
|
|
// and "b".
|
|
//
|
|
// See std::set_union() for how set union is computed.
|
|
template <typename In1, typename In2, typename Out, typename Compare>
|
|
void STLSetUnion(const In1& a, const In2& b, Out* out, Compare compare) {
|
|
static_assert(!gtl::stl_util_internal::Unordered<In1>::value,
|
|
"In1 must be an ordered set");
|
|
static_assert(!gtl::stl_util_internal::Unordered<In2>::value,
|
|
"In2 must be an ordered set");
|
|
assert(std::is_sorted(a.begin(), a.end(), compare));
|
|
assert(std::is_sorted(b.begin(), b.end(), compare));
|
|
assert(static_cast<const void*>(&a) != static_cast<const void*>(out));
|
|
assert(static_cast<const void*>(&b) != static_cast<const void*>(out));
|
|
std::set_union(a.begin(), a.end(), b.begin(), b.end(),
|
|
std::inserter(*out, out->end()), compare);
|
|
}
|
|
// Note: The 'enable_if' keeps this overload from participating in
|
|
// overload resolution if 'out' is a function pointer, gracefully forcing
|
|
// the 3-argument overload that treats the third argument as a comparator.
|
|
template <typename In1, typename In2, typename Out>
|
|
typename std::enable_if<!std::is_function<Out>::value, void>::type STLSetUnion(
|
|
const In1& a, const In2& b, Out* out) {
|
|
return STLSetUnion(a, b, out, gtl::stl_util_internal::TransparentLess());
|
|
}
|
|
template <typename Out, typename In1, typename In2, typename Compare>
|
|
Out STLSetUnionAs(const In1& a, const In2& b, Compare compare) {
|
|
Out out;
|
|
STLSetUnion(a, b, &out, compare);
|
|
return out;
|
|
}
|
|
template <typename Out, typename In1, typename In2>
|
|
Out STLSetUnionAs(const In1& a, const In2& b) {
|
|
return STLSetUnionAs<Out>(a, b, gtl::stl_util_internal::TransparentLess());
|
|
}
|
|
template <typename In1, typename In2, typename Compare>
|
|
In1 STLSetUnion(const In1& a, const In2& b, Compare compare) {
|
|
return STLSetUnionAs<In1>(a, b, compare);
|
|
}
|
|
template <typename In1, typename In2>
|
|
In1 STLSetUnion(const In1& a, const In2& b) {
|
|
return STLSetUnion(a, b, gtl::stl_util_internal::TransparentLess());
|
|
}
|
|
template <typename In1>
|
|
In1 STLSetUnion(const In1& a, const In1& b) {
|
|
return STLSetUnion(a, b, gtl::stl_util_internal::TransparentLess());
|
|
}
|
|
|
|
// STLSetSymmetricDifference:
|
|
//
|
|
// In1 STLSetSymmetricDifference(a, b);
|
|
// In1 STLSetSymmetricDifference(a, b, compare);
|
|
// void STLSetSymmetricDifference(a, b, &out);
|
|
// void STLSetSymmetricDifference(a, b, &out, compare);
|
|
// Out STLSetSymmetricDifferenceAs<Out>(a, b);
|
|
// Out STLSetSymmetricDifferenceAs<Out>(a, b, compare);
|
|
//
|
|
// Appends the elements in "a" that are not in "b", and the elements in "b"
|
|
// that are not in "a", to output container "out". Both input containers
|
|
// must be sorted with operator '<', or with the comparator if specified.
|
|
// "out" must be distinct from both "a" and "b".
|
|
//
|
|
// See std::set_symmetric_difference() for how these elements are selected.
|
|
template <typename In1, typename In2, typename Out, typename Compare>
|
|
void STLSetSymmetricDifference(const In1& a, const In2& b, Out* out,
|
|
Compare compare) {
|
|
static_assert(!gtl::stl_util_internal::Unordered<In1>::value,
|
|
"In1 must be an ordered set");
|
|
static_assert(!gtl::stl_util_internal::Unordered<In2>::value,
|
|
"In2 must be an ordered set");
|
|
assert(std::is_sorted(a.begin(), a.end(), compare));
|
|
assert(std::is_sorted(b.begin(), b.end(), compare));
|
|
assert(static_cast<const void*>(&a) != static_cast<const void*>(out));
|
|
assert(static_cast<const void*>(&b) != static_cast<const void*>(out));
|
|
std::set_symmetric_difference(a.begin(), a.end(), b.begin(), b.end(),
|
|
std::inserter(*out, out->end()), compare);
|
|
}
|
|
// Note: The 'enable_if' keeps this overload from participating in
|
|
// overload resolution if 'out' is a function pointer, gracefully forcing
|
|
// the 3-argument overload that treats the third argument as a comparator.
|
|
template <typename In1, typename In2, typename Out>
|
|
typename std::enable_if<!std::is_function<Out>::value, void>::type
|
|
STLSetSymmetricDifference(const In1& a, const In2& b, Out* out) {
|
|
return STLSetSymmetricDifference(a, b, out,
|
|
gtl::stl_util_internal::TransparentLess());
|
|
}
|
|
template <typename Out, typename In1, typename In2, typename Compare>
|
|
Out STLSetSymmetricDifferenceAs(const In1& a, const In2& b, Compare comp) {
|
|
Out out;
|
|
STLSetSymmetricDifference(a, b, &out, comp);
|
|
return out;
|
|
}
|
|
template <typename Out, typename In1, typename In2>
|
|
Out STLSetSymmetricDifferenceAs(const In1& a, const In2& b) {
|
|
return STLSetSymmetricDifferenceAs<Out>(
|
|
a, b, gtl::stl_util_internal::TransparentLess());
|
|
}
|
|
template <typename In1, typename In2, typename Compare>
|
|
In1 STLSetSymmetricDifference(const In1& a, const In2& b, Compare comp) {
|
|
return STLSetSymmetricDifferenceAs<In1>(a, b, comp);
|
|
}
|
|
template <typename In1, typename In2>
|
|
In1 STLSetSymmetricDifference(const In1& a, const In2& b) {
|
|
return STLSetSymmetricDifference(a, b,
|
|
gtl::stl_util_internal::TransparentLess());
|
|
}
|
|
template <typename In1>
|
|
In1 STLSetSymmetricDifference(const In1& a, const In1& b) {
|
|
return STLSetSymmetricDifference(a, b,
|
|
gtl::stl_util_internal::TransparentLess());
|
|
}
|
|
|
|
// STLSetIntersection:
|
|
//
|
|
// In1 STLSetIntersection(a, b);
|
|
// In1 STLSetIntersection(a, b, compare);
|
|
// void STLSetIntersection(a, b, &out);
|
|
// void STLSetIntersection(a, b, &out, compare);
|
|
// Out STLSetIntersectionAs<Out>(a, b);
|
|
// Out STLSetIntersectionAs<Out>(a, b, compare);
|
|
//
|
|
// Appends the elements that are in both "a" and "b" to output container
|
|
// "out". Both input containers must be sorted with operator '<' or with
|
|
// "compare" if specified. "out" must be distinct from both "a" and "b".
|
|
//
|
|
// See std::set_intersection() for how set intersection is computed.
|
|
template <typename In1, typename In2, typename Out, typename Compare>
|
|
void STLSetIntersection(const In1& a, const In2& b, Out* out, Compare compare) {
|
|
static_assert(!gtl::stl_util_internal::Unordered<In1>::value,
|
|
"In1 must be an ordered set");
|
|
static_assert(!gtl::stl_util_internal::Unordered<In2>::value,
|
|
"In2 must be an ordered set");
|
|
assert(std::is_sorted(a.begin(), a.end(), compare));
|
|
assert(std::is_sorted(b.begin(), b.end(), compare));
|
|
assert(static_cast<const void*>(&a) != static_cast<const void*>(out));
|
|
assert(static_cast<const void*>(&b) != static_cast<const void*>(out));
|
|
std::set_intersection(a.begin(), a.end(), b.begin(), b.end(),
|
|
std::inserter(*out, out->end()), compare);
|
|
}
|
|
// Note: The 'enable_if' keeps this overload from participating in
|
|
// overload resolution if 'out' is a function pointer, gracefully forcing
|
|
// the 3-argument overload that treats the third argument as a comparator.
|
|
template <typename In1, typename In2, typename Out>
|
|
typename std::enable_if<!std::is_function<Out>::value, void>::type
|
|
STLSetIntersection(const In1& a, const In2& b, Out* out) {
|
|
return STLSetIntersection(a, b, out,
|
|
gtl::stl_util_internal::TransparentLess());
|
|
}
|
|
template <typename Out, typename In1, typename In2, typename Compare>
|
|
Out STLSetIntersectionAs(const In1& a, const In2& b, Compare compare) {
|
|
Out out;
|
|
STLSetIntersection(a, b, &out, compare);
|
|
return out;
|
|
}
|
|
template <typename Out, typename In1, typename In2>
|
|
Out STLSetIntersectionAs(const In1& a, const In2& b) {
|
|
return STLSetIntersectionAs<Out>(a, b,
|
|
gtl::stl_util_internal::TransparentLess());
|
|
}
|
|
template <typename In1, typename In2, typename Compare>
|
|
In1 STLSetIntersection(const In1& a, const In2& b, Compare compare) {
|
|
return STLSetIntersectionAs<In1>(a, b, compare);
|
|
}
|
|
template <typename In1, typename In2>
|
|
In1 STLSetIntersection(const In1& a, const In2& b) {
|
|
return STLSetIntersection(a, b, gtl::stl_util_internal::TransparentLess());
|
|
}
|
|
template <typename In1>
|
|
In1 STLSetIntersection(const In1& a, const In1& b) {
|
|
return STLSetIntersection(a, b, gtl::stl_util_internal::TransparentLess());
|
|
}
|
|
|
|
// Returns true iff every element in "b" is also in "a". Both containers
|
|
// must be sorted by the specified comparator, or by '<' if none is given.
|
|
template <typename In1, typename In2, typename Compare>
|
|
bool STLIncludes(const In1& a, const In2& b, Compare compare) {
|
|
static_assert(!gtl::stl_util_internal::Unordered<In1>::value,
|
|
"In1 must be an ordered set");
|
|
static_assert(!gtl::stl_util_internal::Unordered<In2>::value,
|
|
"In2 must be an ordered set");
|
|
assert(std::is_sorted(a.begin(), a.end(), compare));
|
|
assert(std::is_sorted(b.begin(), b.end(), compare));
|
|
return std::includes(a.begin(), a.end(), b.begin(), b.end(), compare);
|
|
}
|
|
template <typename In1, typename In2>
|
|
bool STLIncludes(const In1& a, const In2& b) {
|
|
return STLIncludes(a, b, gtl::stl_util_internal::TransparentLess());
|
|
}
|
|
|
|
// SortedRangesHaveIntersection:
|
|
//
|
|
// bool SortedRangesHaveIntersection(begin1, end1, begin2, end2);
|
|
// bool SortedRangesHaveIntersection(begin1, end1, begin2, end2,
|
|
// comparator);
|
|
//
|
|
// Returns true iff any element in the sorted range [begin1, end1) is
|
|
// equivalent to any element in the sorted range [begin2, end2). The iterators
|
|
// themselves do not have to be the same type, but the value types must be
|
|
// sorted either by the specified comparator, or by '<' if no comparator is
|
|
// given.
|
|
// [Two elements a,b are considered equivalent if !(a < b) && !(b < a) ].
|
|
template <typename InputIterator1, typename InputIterator2, typename Comp>
|
|
bool SortedRangesHaveIntersection(InputIterator1 begin1, InputIterator1 end1,
|
|
InputIterator2 begin2, InputIterator2 end2,
|
|
Comp comparator) {
|
|
assert(std::is_sorted(begin1, end1, comparator));
|
|
assert(std::is_sorted(begin2, end2, comparator));
|
|
while (begin1 != end1 && begin2 != end2) {
|
|
if (comparator(*begin1, *begin2)) {
|
|
++begin1;
|
|
continue;
|
|
}
|
|
if (comparator(*begin2, *begin1)) {
|
|
++begin2;
|
|
continue;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
template <typename InputIterator1, typename InputIterator2>
|
|
bool SortedRangesHaveIntersection(InputIterator1 begin1, InputIterator1 end1,
|
|
InputIterator2 begin2, InputIterator2 end2) {
|
|
return SortedRangesHaveIntersection(
|
|
begin1, end1, begin2, end2, gtl::stl_util_internal::TransparentLess());
|
|
}
|
|
|
|
// Returns true iff the ordered containers 'in1' and 'in2' have a non-empty
|
|
// intersection. The container elements do not have to be the same type, but the
|
|
// elements must be sorted either by the specified comparator, or by '<' if no
|
|
// comparator is given.
|
|
template <typename In1, typename In2, typename Comp>
|
|
bool SortedContainersHaveIntersection(const In1& in1, const In2& in2,
|
|
Comp comparator) {
|
|
return SortedRangesHaveIntersection(in1.begin(), in1.end(), in2.begin(),
|
|
in2.end(), comparator);
|
|
}
|
|
template <typename In1, typename In2>
|
|
bool SortedContainersHaveIntersection(const In1& in1, const In2& in2) {
|
|
return SortedContainersHaveIntersection(
|
|
in1, in2, gtl::stl_util_internal::TransparentLess());
|
|
}
|
|
|
|
// An std::allocator<T> subclass that keeps count of the active bytes allocated
|
|
// by this class of allocators. This allocator is thread compatible
|
|
// (go/thread-compatible). This should only be used in situations where you can
|
|
// ensure that only a single thread performs allocation and deallocation.
|
|
//
|
|
// Example:
|
|
// using MyAlloc = STLCountingAllocator<std::string>;
|
|
// int64_t bytes = 0;
|
|
// std::vector<std::string, MyAlloc> v(MyAlloc(&bytes));
|
|
// v.push_back("hi");
|
|
// LOG(INFO) << "Bytes allocated " << bytes;
|
|
//
|
|
template <typename T, typename Alloc = std::allocator<T>>
|
|
class STLCountingAllocator : public Alloc {
|
|
public:
|
|
using Base = Alloc;
|
|
using pointer = typename Alloc::pointer;
|
|
using size_type = typename Alloc::size_type;
|
|
|
|
STLCountingAllocator() : bytes_used_(nullptr) {}
|
|
explicit STLCountingAllocator(int64_t* b) : bytes_used_(b) {}
|
|
|
|
// Constructor used for rebinding
|
|
template <typename U, typename B>
|
|
STLCountingAllocator(const STLCountingAllocator<U, B>& x)
|
|
: Alloc(x), bytes_used_(x.bytes_used()) {}
|
|
|
|
pointer allocate(size_type n,
|
|
std::allocator<void>::const_pointer hint = nullptr) {
|
|
assert(bytes_used_ != nullptr);
|
|
*bytes_used_ += n * sizeof(T);
|
|
return Alloc::allocate(n, hint);
|
|
}
|
|
|
|
void deallocate(pointer p, size_type n) {
|
|
Alloc::deallocate(p, n);
|
|
assert(bytes_used_ != nullptr);
|
|
*bytes_used_ -= n * sizeof(T);
|
|
}
|
|
|
|
// Rebind allows an std::allocator<T> to be used for a different type
|
|
template <typename U>
|
|
class rebind {
|
|
using OtherA = typename Alloc::template rebind<U>::other;
|
|
|
|
public:
|
|
using other = STLCountingAllocator<U, OtherA>;
|
|
};
|
|
|
|
int64_t* bytes_used() const { return bytes_used_; }
|
|
|
|
private:
|
|
int64_t* bytes_used_;
|
|
};
|
|
|
|
template <typename A>
|
|
class STLCountingAllocator<void, A> : public A {
|
|
public:
|
|
STLCountingAllocator() : bytes_used_(nullptr) {}
|
|
explicit STLCountingAllocator(int64_t* b) : bytes_used_(b) {}
|
|
|
|
// Constructor used for rebinding
|
|
template <typename U, typename B>
|
|
STLCountingAllocator(const STLCountingAllocator<U, B>& x)
|
|
: A(x), bytes_used_(x.bytes_used()) {}
|
|
|
|
template <typename U>
|
|
class rebind {
|
|
using OtherA = typename A::template rebind<U>::other;
|
|
|
|
public:
|
|
using other = STLCountingAllocator<U, OtherA>;
|
|
};
|
|
int64_t* bytes_used() const { return bytes_used_; }
|
|
|
|
private:
|
|
int64_t* bytes_used_;
|
|
};
|
|
|
|
template <typename T, typename A>
|
|
bool operator==(const STLCountingAllocator<T, A>& a,
|
|
const STLCountingAllocator<T, A>& b) {
|
|
using Base = typename STLCountingAllocator<T, A>::Base;
|
|
return static_cast<const Base&>(a) == static_cast<const Base&>(b) &&
|
|
a.bytes_used() == b.bytes_used();
|
|
}
|
|
|
|
template <typename T, typename A>
|
|
bool operator!=(const STLCountingAllocator<T, A>& a,
|
|
const STLCountingAllocator<T, A>& b) {
|
|
return !(a == b);
|
|
}
|
|
|
|
} // namespace gtl
|
|
#endif // OR_TOOLS_BASE_STL_UTIL_H_
|