// Copyright 2010-2018 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #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 class Equiv { public: explicit Equiv(const LessFunc& f) : f_(f) {} template 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 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(less_func)), v->end()); } template 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 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(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 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 void STLEraseAllFromSequence(T* v, const E& e) { v->erase(std::remove(v->begin(), v->end(), e), v->end()); } template void STLEraseAllFromSequence(std::list* c, const E& e) { c->remove(e); } template void STLEraseAllFromSequence(std::forward_list* c, const E& e) { c->remove(e); } // Remove each element e in v satisfying pred(e). template void STLEraseAllFromSequenceIf(T* v, P pred) { v->erase(std::remove_if(v->begin(), v->end(), pred), v->end()); } template void STLEraseAllFromSequenceIf(std::list* c, P pred) { c->remove_if(pred); } template void STLEraseAllFromSequenceIf(std::forward_list* 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 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 void STLClearObject(std::deque* obj) { std::deque 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 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 inline void STLClearIfBig(std::deque* 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 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 inline void STLStringResizeUninitialized(std::basic_string* 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 inline bool STLStringSupportsNontrashingResize( const std::basic_string& 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(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 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 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 inline bool HashMapEquality(const std::map& map_a, const std::map& map_b) { return map_a == map_b; } template inline bool HashMapEquality(const HashMap& a, const HashMap& b) { using Mapped = typename HashMap::mapped_type; return HashMapEquality(a, b, std::equal_to()); } // 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 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 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 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 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 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 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 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 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 explicit ElementDeleter(STLContainer* ptr) : deleter_(new TemplatedElementDeleter(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 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 foo_map; // ValueDeleter d(&foo_map); // if (...) return false; // ... // return success; class ValueDeleter { public: template explicit ValueDeleter(STLContainer* ptr) : deleter_(new TemplatedValueDeleter(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 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 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 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 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 bool operator()(const T& a, const T& b) const { // std::less is better than '<' here, because it can order pointers. return std::less()(a, b); } template 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 struct Unordered : std::false_type {}; template struct Unordered> : std::true_type {}; template struct Unordered, absl::void_t> : 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(a, b); // Out STLSetDifferenceAs(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 void STLSetDifference(const In1& a, const In2& b, Out* out, Compare compare) { static_assert(!gtl::stl_util_internal::Unordered::value, "In1 must be an ordered set"); static_assert(!gtl::stl_util_internal::Unordered::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(&a) != static_cast(out)); assert(static_cast(&b) != static_cast(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 std::enable_if::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 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 Out STLSetDifferenceAs(const In1& a, const In2& b) { return STLSetDifferenceAs(a, b, gtl::stl_util_internal::TransparentLess()); } // Explicit comparator, implicit return type. template In1 STLSetDifference(const In1& a, const In2& b, Compare compare) { return STLSetDifferenceAs(a, b, compare); } // Implicit comparator, implicit return type. template In1 STLSetDifference(const In1& a, const In2& b) { return STLSetDifference(a, b, gtl::stl_util_internal::TransparentLess()); } template 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(a, b); // Out STLSetUnionAs(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 void STLSetUnion(const In1& a, const In2& b, Out* out, Compare compare) { static_assert(!gtl::stl_util_internal::Unordered::value, "In1 must be an ordered set"); static_assert(!gtl::stl_util_internal::Unordered::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(&a) != static_cast(out)); assert(static_cast(&b) != static_cast(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 std::enable_if::value, void>::type STLSetUnion( const In1& a, const In2& b, Out* out) { return STLSetUnion(a, b, out, gtl::stl_util_internal::TransparentLess()); } template Out STLSetUnionAs(const In1& a, const In2& b, Compare compare) { Out out; STLSetUnion(a, b, &out, compare); return out; } template Out STLSetUnionAs(const In1& a, const In2& b) { return STLSetUnionAs(a, b, gtl::stl_util_internal::TransparentLess()); } template In1 STLSetUnion(const In1& a, const In2& b, Compare compare) { return STLSetUnionAs(a, b, compare); } template In1 STLSetUnion(const In1& a, const In2& b) { return STLSetUnion(a, b, gtl::stl_util_internal::TransparentLess()); } template 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(a, b); // Out STLSetSymmetricDifferenceAs(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 void STLSetSymmetricDifference(const In1& a, const In2& b, Out* out, Compare compare) { static_assert(!gtl::stl_util_internal::Unordered::value, "In1 must be an ordered set"); static_assert(!gtl::stl_util_internal::Unordered::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(&a) != static_cast(out)); assert(static_cast(&b) != static_cast(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 std::enable_if::value, void>::type STLSetSymmetricDifference(const In1& a, const In2& b, Out* out) { return STLSetSymmetricDifference(a, b, out, gtl::stl_util_internal::TransparentLess()); } template Out STLSetSymmetricDifferenceAs(const In1& a, const In2& b, Compare comp) { Out out; STLSetSymmetricDifference(a, b, &out, comp); return out; } template Out STLSetSymmetricDifferenceAs(const In1& a, const In2& b) { return STLSetSymmetricDifferenceAs( a, b, gtl::stl_util_internal::TransparentLess()); } template In1 STLSetSymmetricDifference(const In1& a, const In2& b, Compare comp) { return STLSetSymmetricDifferenceAs(a, b, comp); } template In1 STLSetSymmetricDifference(const In1& a, const In2& b) { return STLSetSymmetricDifference(a, b, gtl::stl_util_internal::TransparentLess()); } template 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(a, b); // Out STLSetIntersectionAs(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 void STLSetIntersection(const In1& a, const In2& b, Out* out, Compare compare) { static_assert(!gtl::stl_util_internal::Unordered::value, "In1 must be an ordered set"); static_assert(!gtl::stl_util_internal::Unordered::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(&a) != static_cast(out)); assert(static_cast(&b) != static_cast(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 std::enable_if::value, void>::type STLSetIntersection(const In1& a, const In2& b, Out* out) { return STLSetIntersection(a, b, out, gtl::stl_util_internal::TransparentLess()); } template Out STLSetIntersectionAs(const In1& a, const In2& b, Compare compare) { Out out; STLSetIntersection(a, b, &out, compare); return out; } template Out STLSetIntersectionAs(const In1& a, const In2& b) { return STLSetIntersectionAs(a, b, gtl::stl_util_internal::TransparentLess()); } template In1 STLSetIntersection(const In1& a, const In2& b, Compare compare) { return STLSetIntersectionAs(a, b, compare); } template In1 STLSetIntersection(const In1& a, const In2& b) { return STLSetIntersection(a, b, gtl::stl_util_internal::TransparentLess()); } template 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 bool STLIncludes(const In1& a, const In2& b, Compare compare) { static_assert(!gtl::stl_util_internal::Unordered::value, "In1 must be an ordered set"); static_assert(!gtl::stl_util_internal::Unordered::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 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 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 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 bool SortedContainersHaveIntersection(const In1& in1, const In2& in2, Comp comparator) { return SortedRangesHaveIntersection(in1.begin(), in1.end(), in2.begin(), in2.end(), comparator); } template bool SortedContainersHaveIntersection(const In1& in1, const In2& in2) { return SortedContainersHaveIntersection( in1, in2, gtl::stl_util_internal::TransparentLess()); } // An std::allocator 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; // int64 bytes = 0; // std::vector v(MyAlloc(&bytes)); // v.push_back("hi"); // LOG(INFO) << "Bytes allocated " << bytes; // template > 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* b) : bytes_used_(b) {} // Constructor used for rebinding template STLCountingAllocator(const STLCountingAllocator& x) : Alloc(x), bytes_used_(x.bytes_used()) {} pointer allocate(size_type n, std::allocator::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 to be used for a different type template class rebind { using OtherA = typename Alloc::template rebind::other; public: using other = STLCountingAllocator; }; int64* bytes_used() const { return bytes_used_; } private: int64* bytes_used_; }; template class STLCountingAllocator : public A { public: STLCountingAllocator() : bytes_used_(nullptr) {} explicit STLCountingAllocator(int64* b) : bytes_used_(b) {} // Constructor used for rebinding template STLCountingAllocator(const STLCountingAllocator& x) : A(x), bytes_used_(x.bytes_used()) {} template class rebind { using OtherA = typename A::template rebind::other; public: using other = STLCountingAllocator; }; int64* bytes_used() const { return bytes_used_; } private: int64* bytes_used_; }; template bool operator==(const STLCountingAllocator& a, const STLCountingAllocator& b) { using Base = typename STLCountingAllocator::Base; return static_cast(a) == static_cast(b) && a.bytes_used() == b.bytes_used(); } template bool operator!=(const STLCountingAllocator& a, const STLCountingAllocator& b) { return !(a == b); } } // namespace gtl #endif // OR_TOOLS_BASE_STL_UTIL_H_