Files
ortools-clone/ortools/base/stl_util.h
Mizux Seiha 8bb54b04ef Bump Copyright to 2021
FYI:
find ortools \( -type d -name .git -prune \) -o -type f -print0 | xargs -0 sed -i 's/\(Copyright 2010\)-2018/\1-2021/g'
2021-04-01 21:00:53 +02:00

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_