STL algorithm之count、find、binary_search、lower_bound、upper_bound和equal_range的区别

本文介绍了如何根据需求选择合适的搜索算法,包括线性搜索算法如find和count,以及对数时间的binary_search、lower_bound和equal_range等。文章还探讨了在不同容器中使用这些算法的最佳实践。

你要寻找什么,而且你有一个容器或者你有一个由迭代器划分出来的区间——你要找的东西就在里面。你要怎么完成搜索呢?你箭袋中的箭有这些:count、count_if、find、find_if、binary_search、lower_bound、upper_bound和equal_range。面对着它们,你要怎么做出选择?

简单。你寻找的是能又快又简单的东西。越快越简单的越好。

暂时,我假设你有一对指定了搜索区间的迭代器。然后,我会考虑到你有的是一个容器而不是一个区间的情况。

要选择搜索策略,必须依赖于你的迭代器是否定义了一个有序区间。如果是,你就可以通过binary_search、lower_bound、upper_bound和equal_range来加速(通常是对数时间——参见条款34)搜索。如果迭代器并没有划分一个有序区间,你就只能用线性时间的算法count、count_if、find和find_if。在下文中,我会忽略掉count和find是否有_if的不同,就像我会忽略掉binary_search、lower_bound、upper_bound和equal_range是否带有判断式的不同。你是依赖默认的搜索谓词还是指定一个自己的,对选择搜索算法的考虑是一样的。

如果你有一个无序区间,你的选择是count或着find。它们分别可以回答略微不同的问题,所以值得仔细去区分它们。count回答的问题是:“是否存在这个值,如果有,那么存在几份拷贝?”而find回答的问题是:“是否存在,如果有,那么它在哪儿?”

假设你想知道的东西是,是否有一个特定的Widget值w在list中。如果用count,代码看起来像这样:

list<Widget> lw;			// Widget的listWidget w;				// 特定的Widget值...if (count(lw.begin(), lw.end(), w)) {	...			// w在lw中} else {	...			// 不在}

这里示范了一种惯用法:把count用来作为是否存在的检查。count返回零或者一个正数,所以我们把非零转化为true而把零转化为false。如果这样能使我们要做的更加显而易见:

if (count(lw.begin(), lw.end(), w) != 0) ...

而且有些程序员这样写,但是使用隐式转换则更常见,就像最初的例子。

和最初的代码比较,使用find略微更难懂些,因为你必须检查find的返回值和list的end迭代器是否相等:

if (find(lw.begin(), lw.end(), w) != lw.end()) {	...				// 找到了} else {	...				// 没找到}

如果是为了检查是否存在,count这个惯用法编码起来比较简单。但是,当搜索成功时,它的效率比较低,因为当找到匹配的值后find就停止了,而count必须继续搜索,直到区间的结尾以寻找其他匹配的值。对大多数程序员来说,find在效率上的优势足以证明略微增加复杂度是合适的。

通常,只知道区间内是否有某个值是不够的。取而代之的是,你想获得区间中的第一个等于该值的对象。比如,你可能想打印出这个对象,你可能想在它前面插入什么,或者你可能想要删除它(但当迭代时删除的引导参见条款9)。当你需要知道的不止是某个值是否存在,而且要知道哪个对象(或哪些对象)拥有该值,你就得用find:

list<Widget>::iterator i = find(lw.begin(), lw.end(), w);if (i != lw.end()) {	...				// 找到了,i指向第一个} else {	...				// 没有找到}

对于有序区间,你有其他的选择,而且你应该明确的使用它们。count和find是线性时间的,但有序区间的搜索算法(binary_search、lower_bound、upper_bound和equal_range)是对数时间的。

从无序区间迁移到有序区间导致了另一个迁移:从使用相等来判断两个值是否相同到使用等价来判断。条款19由一个详细地讲述了相等和等价的区别,所以我在这里不会重复。取而代之的是,我会简单地说明count和find算法都用相等来搜索,而binary_search、lower_bound、upper_bound和equal_range则用等价。

要测试在有序区间中是否存在一个值,使用binary_search。不像标准C库中的(因此也是标准C++库中的)bsearch,binary_search只返回一个bool:这个值是否找到了。binary_search回答这个问题:“它在吗?”它的回答只能是是或者否。如果你需要比这样更多的信息,你需要一个不同的算法。

这里有一个binary_search应用于有序vector的例子(你可以从条款23中知道有序vector的优点):

vector<Widget> vw;			// 建立vector,放入...				// 数据,sort(vw.begin(), vw.end());		// 把数据排序Widget w;				// 要找的值...if (binary_search(vw.begin(), vw.end(), w)) {	...			// w在vw中} else {	...			// 不在}

如果你有一个有序区间而且你的问题是:“它在吗,如果是,那么在哪儿?”你就需要equal_range,但你可能想要用lower_bound。我会很快讨论equal_range,但首先,让我们看看怎么用lower_bound来在区间中定位某个值。

当你用lower_bound来寻找一个值的时候,它返回一个迭代器,这个迭代器指向这个值的第一个拷贝(如果找到的话)或者到可以插入这个值的位置(如果没找到)。因此lower_bound回答这个问题:“它在吗?如果是,第一个拷贝在哪里?如果不是,它将在哪里?”和find一样,你必须测试lower_bound的结果,来看看它是否指向你要寻找的值。但又不像find,你不能只是检测lower_bound的返回值是否等于end迭代器。取而代之的是,你必须检测lower_bound所标示出的对象是不是你需要的值。

很多程序员这么用lower_bound:

vector<Widget>::iterator i = lower_bound(vw.begin(), vw.end(), w);if (i != vw.end() && *i == w) {	// 保证i指向一个对象;				// 也就保证了这个对象有正确的值。				// 这是个bug! 	...			// 找到这个值,i指向				// 第一个等于该值的对象} else {	...			// 没找到}

大部分情况下这是行得通的,但不是真的完全正确。再看一遍检测需要的值是否找到的代码:

if (i != vw.end() && *i == w) ...

这是一个相等的测试,但lower_bound搜索用的是等价。大部分情况下,等价测试和相等测试产生的结果相同,但就像条款19论证的,相等和等价的结果不同的情况并不难见到。在这种情况下,上面的代码就是错的。

要完全完成,你就必须检测lower_bound返回的迭代器指向的对象的值是否和你要寻找的值等价。你可以手动完成(条款19演示了你该怎么做,当它值得一做时条款24提供了一个例子),但可以更狡猾地完成,因为你必须确认使用了和lower_bound使用的相同的比较函数。一般而言,那可以是一个任意的函数(或函数对象)。如果你传递一个比较函数给lower_bound,你必须确认和你的手写的等价检测代码使用了相同的比较函数。这意味着如果你改变了你传递给lower_bound的比较函数,你也得对你的等价检测部分作出修改。保持比较函数同步不是火箭发射,但却是另一个要记住的东西,而且我想你已经有很多需要你记的东西了。

这儿有一个简单的方法:使用equal_range。equal_range返回一对迭代器,第一个等于lower_bound返回的迭代器,第二个等于upper_bound返回的(也就是,等价于要搜索值区间的末迭代器的下一个)。因此,equal_range,返回了一对划分出了和你要搜索的值等价的区间的迭代器。一个名字很好的算法,不是吗?(当然,也许叫equivalent_range会更好,但叫equal_range也非常好。)

对于equal_range的返回值,有两个重要的地方。第一,如果这两个迭代器相同,就意味着对象的区间是空的;这个只没有找到。这个结果是用equal_range来回答“它在吗?”这个问题的答案。你可以这么用:

vector<Widget> vw;...sort(vw.begin(), vw.end());typedef vector<Widget>::iterator VWIter;	// 方便的typedeftypedef pair<VWIter, VWIter> VWIterPair;VWIterPair p = equal_range(vw.begin(), vw.end(), w);if (p.first != p.second) {			// 如果equal_range不返回					// 空的区间...	...				// 说明找到了,p.first指向					// 第一个而p.second					// 指向最后一个的下一个} else {	...				// 没找到,p.first和					// p.second都指向搜索值}					// 的插入位置

这段代码只用等价,所以总是正确的。

第二个要注意的是equal_range返回的东西是两个迭代器,对它们作distance就等于区间中对象的数目,也就是,等价于要寻找的值的对象。结果,equal_range不光完成了搜索有序区间的任务,而且完成了计数。比如说,要在vw中找到等价于w的Widget,然后打印出来有多少这样的Widget存在,你可以这么做:

VWIterPair p = equal_range(vw.begin(), vw.end(), w);cout << "There are " << distance(p.first, p.second)		<< " elements in vw equivalent to w.";

到目前为止,我们所讨论的都是假设我们要在一个区间内搜索一个值,但是有时候我们更感兴趣于在区间中寻找一个位置。比如,假设我们有一个Timestamp类和一个Timestamp的vector,它按照老的timestamp放在前面的方法排序:

class Timestamp { ... };bool operator<(const Timestamp& lhs,		// 返回在时间上lhs	const Timestamp& rhs);		// 是否在rhs前面vector<Timestamp> vt;			// 建立vector,填充数据,...					// 排序,使老的时间sort(vt.begin(), vt.end());			// 在新的前面

现在假设我们有一个特殊的timestamp——ageLimit,而且我们从vt中删除所有比ageLimit老的timestamp。在这种情况下,我们不需要在vt中搜索和ageLimit等价的Timestamp,因为可能不存在任何等价于这个精确值的元素。 取而代之的是,我们需要在vt中找到一个位置:第一个不比ageLimit更老的元素。这是再简单不过的了,因为lower_bound会给我们答案的:

Timestamp ageLimit;...vt.erase(vt.begin(), lower_bound(vt.begin(),	// 从vt中排除所有	vt.end(),				// 排在ageLimit的值	ageLimit));			// 前面的对象

如果我们的需求稍微改变了一点,我们要排除所有至少和ageLimit一样老的timestamp,也就是我们需要找到第一个比ageLimit年轻的timestamp的位置。这是一个为upper_bound特制的任务:

vt.erase(vt.begin(), upper_bound(vt.begin(),	// 从vt中除去所有	vt.end(),				// 排在ageLimit的值前面	ageLimit));			// 或者等价的对象

如果你要把东西插入一个有序区间,而且对象的插入位置是在有序的等价关系下它应该在的地方时,upper_bound也很有用。比如,你可能有一个有序的Person对象的list,对象按照name排序:

class Person {public:	...	const string& name() const;	...};struct PersonNameLess:public binary_function<Person, Person, bool> {	// 参见条款40	bool operator()(const Person& lhs, const Person& rhs) const	{		return lhs.name() < rhs.name();	}};list<Person> lp;...lp.sort(PersonNameLess());			// 使用PersonNameLess排序lp

要保持list仍然是我们希望的顺序(按照name,插入后等价的名字仍然按顺序排列),我们可以用upper_bound来指定插入位置:

Person newPerson;...lp.insert(upper_bound(lp.begin(),		// 在lp中排在newPerson	lp.end(),				// 之前或者等价	newPerson,			// 的最后一个	PersonNameLess()),			// 对象后面	newPerson);			// 插入newPerson

这工作的很好而且很方便,但很重要的是不要被误导——错误地认为upper_bound的这种用法让我们魔术般地在一个list里在对数时间内找到了插入位置。我们并没有——条款34解释了因为我们用了list,查找花费线性时间,但是它只用了对数次的比较。

一直到这里,我都只考虑我们有一对定义了搜索区间的迭代器的情况。通常我们有一个容器,而不是一个区间。在这种情况下,我们必须区别序列和关联容器。对于标准的序列容器(vector、string、deque和list),你应该遵循我在本条款提出的建议,使用容器的begin和end迭代器来划分出区间。

这种情况对标准关联容器(set、multiset、map和multimap)来说是不同的,因为它们提供了搜索的成员函数,它们往往是比用STL算法更好的选择。条款44详细说明了为什么它们是更好的选择,简要地说,是因为它们更快行为更自然。幸运的是,成员函数通常和相应的算法有同样的名字,所以前面的讨论推荐你使用的算法count、find、equal_range、lower_bound或upper_bound,在搜索关联容器时你都可以简单的用同名的成员函数来代替。

调用binary_search的策略不同,因为这个算法没有提供对应的成员函数。要测试在set或map中是否存在某个值,使用count的惯用方法来对成员进行检测:

set<Widget> s;		// 建立set,放入数据 ...Widget w;			// w仍然是保存要搜索的值...if (s.count(w)) {	...		// 存在和w等价的值} else {	...		// 不存在这样的值}

要测试某个值在multiset或multimap中是否存在,find往往比count好,因为一旦找到等于期望值的单个对象,find就可以停下了,而count,在最遭的情况下,必须检测容器里的每一个对象。(对于set和map,这不是问题,因为set不允许重复的值,而map不允许重复的键。)

但是,count给关联容器计数是可靠的。特别,它比调用equal_range然后应用distance到结果迭代器更好。首先,它更清晰:count 意味着“计数”。第二,它更简单;不用建立一对迭代器然后把它的组成(译注:就是first和second)传给distance。第三,它可能更快一点。

要给出所有我们在本条款中所考虑到的,我们的从哪儿着手?下面的表格道出了一切。

你想知道的使用的算法使用的成员函数
在无序区间在有序区间在set或map上在multiset或multimap上
期望值是否存在?findbinary_searchcountfind
期望值是否存在?如果有,第一个等于这个值的对象在哪里?findequal_rangefindfind或lower_bound(参见下面)
第一个不在期望值之前的对象在哪里?find_iflower_boundlower_boundlower_bound
第一个在期望值之后的对象在哪里?find_ifupper_boundupper_boundupper_bound
有多少对象等于期望值?countequal_range,然后distancecountcount
等于期望值的所有对象在哪里?find(迭代)equal_rangeequal_rangeequal_range

上表总结了要怎么操作有序区间,equal_range的出现频率可能令人吃惊。当搜索时,这个频率因为等价检测的重要性而上升了。对于lower_bound和upper_bound,它很容易在相等检测中退却,但对于equal_range,只检测等价是很自然的。在第二行有序区间,equal_range打败了find还因为一个理由:equal_range花费对数时间,而find花费线性时间。

对于multiset和multimap,当你在搜索第一个等于特定值的对象的那一行,这个表列出了find和lower_bound两个算法作为候选。 已对于这个任务find是通常的选择,而且你可能已经注意到在set和map那一列里,这项只有find。但是对于multi容器,如果不只有一个值存在,find并不保证能识别出容器里的等于给定值的第一个元素;它只识别这些元素中的一个。如果你真的需要找到等于给定值的第一个元素,你应该使用lower_bound,而且你必须手动的对第二部分做等价检测,条款19的内容可以帮你确认你已经找到了你要找的值。(你可以用equal_range来避免作手动等价检测,但是调用equal_range的花费比调用lower_bound多得多。)

在count、find、binary_search、lower_bound、upper_bound和equal_range中做出选择很简单。当你调用时,选择算法还是成员函数可以给你需要的行为和性能,而且是最少的工作。按照这个建议做(或参考那个表格),你就不会再有困惑。

 
// Core algorithmic facilities -*- C++ -*- // Copyright (C) 2001-2014 Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free // software; you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the // Free Software Foundation; either version 3, or (at your option) // any later version. // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // Under Section 7 of GPL version 3, you are granted additional // permissions described in the GCC Runtime Library Exception, version // 3.1, as published by the Free Software Foundation. // You should have received a copy of the GNU General Public License and // a copy of the GCC Runtime Library Exception along with this program; // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see // <http://www.gnu.org/licenses/>. /* * * Copyright (c) 1994 * Hewlett-Packard Company * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Hewlett-Packard Company makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * * * Copyright (c) 1996-1998 * Silicon Graphics Computer Systems, Inc. * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies and * that both that copyright notice and this permission notice appear * in supporting documentation. Silicon Graphics makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. */ /** @file bits/stl_algobase.h * This is an internal header file, included by other library headers. * Do not attempt to use it directly. @headername{algorithm} */ #ifndef _STL_ALGOBASE_H #define _STL_ALGOBASE_H 1 #include <bits/c++config.h> #include <bits/functexcept.h> #include <bits/cpp_type_traits.h> #include <ext/type_traits.h> #include <ext/numeric_traits.h> #include <bits/stl_pair.h> #include <bits/stl_iterator_base_types.h> #include <bits/stl_iterator_base_funcs.h> #include <bits/stl_iterator.h> #include <bits/concept_check.h> #include <debug/debug.h> #include <bits/move.h> // For std::swap and _GLIBCXX_MOVE #include <bits/predefined_ops.h> namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION #if __cplusplus < 201103L // See http://gcc.gnu.org/ml/libstdc++/2004-08/msg00167.html: in a // nutshell, we are partially implementing the resolution of DR 187, // when it's safe, i.e., the value_types are equal. template<bool _BoolType> struct __iter_swap { template<typename _ForwardIterator1, typename _ForwardIterator2> static void iter_swap(_ForwardIterator1 __a, _ForwardIterator2 __b) { typedef typename iterator_traits<_ForwardIterator1>::value_type _ValueType1; _ValueType1 __tmp = _GLIBCXX_MOVE(*__a); *__a = _GLIBCXX_MOVE(*__b); *__b = _GLIBCXX_MOVE(__tmp); } }; template<> struct __iter_swap<true> { template<typename _ForwardIterator1, typename _ForwardIterator2> static void iter_swap(_ForwardIterator1 __a, _ForwardIterator2 __b) { swap(*__a, *__b); } }; #endif /** * @brief Swaps the contents of two iterators. * @ingroup mutating_algorithms * @param __a An iterator. * @param __b Another iterator. * @return Nothing. * * This function swaps the values pointed to by two iterators, not the * iterators themselves. */ template<typename _ForwardIterator1, typename _ForwardIterator2> inline void iter_swap(_ForwardIterator1 __a, _ForwardIterator2 __b) { // concept requirements __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< _ForwardIterator1>) __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< _ForwardIterator2>) #if __cplusplus < 201103L typedef typename iterator_traits<_ForwardIterator1>::value_type _ValueType1; typedef typename iterator_traits<_ForwardIterator2>::value_type _ValueType2; __glibcxx_function_requires(_ConvertibleConcept<_ValueType1, _ValueType2>) __glibcxx_function_requires(_ConvertibleConcept<_ValueType2, _ValueType1>) typedef typename iterator_traits<_ForwardIterator1>::reference _ReferenceType1; typedef typename iterator_traits<_ForwardIterator2>::reference _ReferenceType2; std::__iter_swap<__are_same<_ValueType1, _ValueType2>::__value && __are_same<_ValueType1&, _ReferenceType1>::__value && __are_same<_ValueType2&, _ReferenceType2>::__value>:: iter_swap(__a, __b); #else swap(*__a, *__b); #endif } /** * @brief Swap the elements of two sequences. * @ingroup mutating_algorithms * @param __first1 A forward iterator. * @param __last1 A forward iterator. * @param __first2 A forward iterator. * @return An iterator equal to @p first2+(last1-first1). * * Swaps each element in the range @p [first1,last1) with the * corresponding element in the range @p [first2,(last1-first1)). * The ranges must not overlap. */ template<typename _ForwardIterator1, typename _ForwardIterator2> _ForwardIterator2 swap_ranges(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) { // concept requirements __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< _ForwardIterator1>) __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< _ForwardIterator2>) __glibcxx_requires_valid_range(__first1, __last1); for (; __first1 != __last1; ++__first1, ++__first2) std::iter_swap(__first1, __first2); return __first2; } /** * @brief This does what you think it does. * @ingroup sorting_algorithms * @param __a A thing of arbitrary type. * @param __b Another thing of arbitrary type. * @return The lesser of the parameters. * * This is the simple classic generic implementation. It will work on * temporary expressions, since they are only evaluated once, unlike a * preprocessor macro. */ template<typename _Tp> inline const _Tp& min(const _Tp& __a, const _Tp& __b) { // concept requirements __glibcxx_function_requires(_LessThanComparableConcept<_Tp>) //return __b < __a ? __b : __a; if (__b < __a) return __b; return __a; } /** * @brief This does what you think it does. * @ingroup sorting_algorithms * @param __a A thing of arbitrary type. * @param __b Another thing of arbitrary type. * @return The greater of the parameters. * * This is the simple classic generic implementation. It will work on * temporary expressions, since they are only evaluated once, unlike a * preprocessor macro. */ template<typename _Tp> inline const _Tp& max(const _Tp& __a, const _Tp& __b) { // concept requirements __glibcxx_function_requires(_LessThanComparableConcept<_Tp>) //return __a < __b ? __b : __a; if (__a < __b) return __b; return __a; } /** * @brief This does what you think it does. * @ingroup sorting_algorithms * @param __a A thing of arbitrary type. * @param __b Another thing of arbitrary type. * @param __comp A @link comparison_functors comparison functor@endlink. * @return The lesser of the parameters. * * This will work on temporary expressions, since they are only evaluated * once, unlike a preprocessor macro. */ template<typename _Tp, typename _Compare> inline const _Tp& min(const _Tp& __a, const _Tp& __b, _Compare __comp) { //return __comp(__b, __a) ? __b : __a; if (__comp(__b, __a)) return __b; return __a; } /** * @brief This does what you think it does. * @ingroup sorting_algorithms * @param __a A thing of arbitrary type. * @param __b Another thing of arbitrary type. * @param __comp A @link comparison_functors comparison functor@endlink. * @return The greater of the parameters. * * This will work on temporary expressions, since they are only evaluated * once, unlike a preprocessor macro. */ template<typename _Tp, typename _Compare> inline const _Tp& max(const _Tp& __a, const _Tp& __b, _Compare __comp) { //return __comp(__a, __b) ? __b : __a; if (__comp(__a, __b)) return __b; return __a; } // If _Iterator is a __normal_iterator return its base (a plain pointer, // normally) otherwise return it untouched. See copy, fill, ... template<typename _Iterator> struct _Niter_base : _Iter_base<_Iterator, __is_normal_iterator<_Iterator>::__value> { }; template<typename _Iterator> inline typename _Niter_base<_Iterator>::iterator_type __niter_base(_Iterator __it) { return std::_Niter_base<_Iterator>::_S_base(__it); } // Likewise, for move_iterator. template<typename _Iterator> struct _Miter_base : _Iter_base<_Iterator, __is_move_iterator<_Iterator>::__value> { }; template<typename _Iterator> inline typename _Miter_base<_Iterator>::iterator_type __miter_base(_Iterator __it) { return std::_Miter_base<_Iterator>::_S_base(__it); } // All of these auxiliary structs serve two purposes. (1) Replace // calls to copy with memmove whenever possible. (Memmove, not memcpy, // because the input and output ranges are permitted to overlap.) // (2) If we're using random access iterators, then write the loop as // a for loop with an explicit count. template<bool, bool, typename> struct __copy_move { template<typename _II, typename _OI> static _OI __copy_m(_II __first, _II __last, _OI __result) { for (; __first != __last; ++__result, ++__first) *__result = *__first; return __result; } }; #if __cplusplus >= 201103L template<typename _Category> struct __copy_move<true, false, _Category> { template<typename _II, typename _OI> static _OI __copy_m(_II __first, _II __last, _OI __result) { for (; __first != __last; ++__result, ++__first) *__result = std::move(*__first); return __result; } }; #endif template<> struct __copy_move<false, false, random_access_iterator_tag> { template<typename _II, typename _OI> static _OI __copy_m(_II __first, _II __last, _OI __result) { typedef typename iterator_traits<_II>::difference_type _Distance; for(_Distance __n = __last - __first; __n > 0; --__n) { *__result = *__first; ++__first; ++__result; } return __result; } }; #if __cplusplus >= 201103L template<> struct __copy_move<true, false, random_access_iterator_tag> { template<typename _II, typename _OI> static _OI __copy_m(_II __first, _II __last, _OI __result) { typedef typename iterator_traits<_II>::difference_type _Distance; for(_Distance __n = __last - __first; __n > 0; --__n) { *__result = std::move(*__first); ++__first; ++__result; } return __result; } }; #endif template<bool _IsMove> struct __copy_move<_IsMove, true, random_access_iterator_tag> { template<typename _Tp> static _Tp* __copy_m(const _Tp* __first, const _Tp* __last, _Tp* __result) { #if __cplusplus >= 201103L // trivial types can have deleted assignment static_assert( is_copy_assignable<_Tp>::value, "type is not assignable" ); #endif const ptrdiff_t _Num = __last - __first; if (_Num) __builtin_memmove(__result, __first, sizeof(_Tp) * _Num); return __result + _Num; } }; template<bool _IsMove, typename _II, typename _OI> inline _OI __copy_move_a(_II __first, _II __last, _OI __result) { typedef typename iterator_traits<_II>::value_type _ValueTypeI; typedef typename iterator_traits<_OI>::value_type _ValueTypeO; typedef typename iterator_traits<_II>::iterator_category _Category; const bool __simple = (__is_trivial(_ValueTypeI) && __is_pointer<_II>::__value && __is_pointer<_OI>::__value && __are_same<_ValueTypeI, _ValueTypeO>::__value); return std::__copy_move<_IsMove, __simple, _Category>::__copy_m(__first, __last, __result); } // Helpers for streambuf iterators (either istream or ostream). // NB: avoid including <iosfwd>, relatively large. template<typename _CharT> struct char_traits; template<typename _CharT, typename _Traits> class istreambuf_iterator; template<typename _CharT, typename _Traits> class ostreambuf_iterator; template<bool _IsMove, typename _CharT> typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value, ostreambuf_iterator<_CharT, char_traits<_CharT> > >::__type __copy_move_a2(_CharT*, _CharT*, ostreambuf_iterator<_CharT, char_traits<_CharT> >); template<bool _IsMove, typename _CharT> typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value, ostreambuf_iterator<_CharT, char_traits<_CharT> > >::__type __copy_move_a2(const _CharT*, const _CharT*, ostreambuf_iterator<_CharT, char_traits<_CharT> >); template<bool _IsMove, typename _CharT> typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value, _CharT*>::__type __copy_move_a2(istreambuf_iterator<_CharT, char_traits<_CharT> >, istreambuf_iterator<_CharT, char_traits<_CharT> >, _CharT*); template<bool _IsMove, typename _II, typename _OI> inline _OI __copy_move_a2(_II __first, _II __last, _OI __result) { return _OI(std::__copy_move_a<_IsMove>(std::__niter_base(__first), std::__niter_base(__last), std::__niter_base(__result))); } /** * @brief Copies the range [first,last) into result. * @ingroup mutating_algorithms * @param __first An input iterator. * @param __last An input iterator. * @param __result An output iterator. * @return result + (first - last) * * This inline function will boil down to a call to @c memmove whenever * possible. Failing that, if random access iterators are passed, then the * loop count will be known (and therefore a candidate for compiler * optimizations such as unrolling). Result may not be contained within * [first,last); the copy_backward function should be used instead. * * Note that the end of the output range is permitted to be contained * within [first,last). */ template<typename _II, typename _OI> inline _OI copy(_II __first, _II __last, _OI __result) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_II>) __glibcxx_function_requires(_OutputIteratorConcept<_OI, typename iterator_traits<_II>::value_type>) __glibcxx_requires_valid_range(__first, __last); return (std::__copy_move_a2<__is_move_iterator<_II>::__value> (std::__miter_base(__first), std::__miter_base(__last), __result)); } #if __cplusplus >= 201103L /** * @brief Moves the range [first,last) into result. * @ingroup mutating_algorithms * @param __first An input iterator. * @param __last An input iterator. * @param __result An output iterator. * @return result + (first - last) * * This inline function will boil down to a call to @c memmove whenever * possible. Failing that, if random access iterators are passed, then the * loop count will be known (and therefore a candidate for compiler * optimizations such as unrolling). Result may not be contained within * [first,last); the move_backward function should be used instead. * * Note that the end of the output range is permitted to be contained * within [first,last). */ template<typename _II, typename _OI> inline _OI move(_II __first, _II __last, _OI __result) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_II>) __glibcxx_function_requires(_OutputIteratorConcept<_OI, typename iterator_traits<_II>::value_type>) __glibcxx_requires_valid_range(__first, __last); return std::__copy_move_a2<true>(std::__miter_base(__first), std::__miter_base(__last), __result); } #define _GLIBCXX_MOVE3(_Tp, _Up, _Vp) std::move(_Tp, _Up, _Vp) #else #define _GLIBCXX_MOVE3(_Tp, _Up, _Vp) std::copy(_Tp, _Up, _Vp) #endif template<bool, bool, typename> struct __copy_move_backward { template<typename _BI1, typename _BI2> static _BI2 __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result) { while (__first != __last) *--__result = *--__last; return __result; } }; #if __cplusplus >= 201103L template<typename _Category> struct __copy_move_backward<true, false, _Category> { template<typename _BI1, typename _BI2> static _BI2 __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result) { while (__first != __last) *--__result = std::move(*--__last); return __result; } }; #endif template<> struct __copy_move_backward<false, false, random_access_iterator_tag> { template<typename _BI1, typename _BI2> static _BI2 __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result) { typename iterator_traits<_BI1>::difference_type __n; for (__n = __last - __first; __n > 0; --__n) *--__result = *--__last; return __result; } }; #if __cplusplus >= 201103L template<> struct __copy_move_backward<true, false, random_access_iterator_tag> { template<typename _BI1, typename _BI2> static _BI2 __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result) { typename iterator_traits<_BI1>::difference_type __n; for (__n = __last - __first; __n > 0; --__n) *--__result = std::move(*--__last); return __result; } }; #endif template<bool _IsMove> struct __copy_move_backward<_IsMove, true, random_access_iterator_tag> { template<typename _Tp> static _Tp* __copy_move_b(const _Tp* __first, const _Tp* __last, _Tp* __result) { #if __cplusplus >= 201103L // trivial types can have deleted assignment static_assert( is_copy_assignable<_Tp>::value, "type is not assignable" ); #endif const ptrdiff_t _Num = __last - __first; if (_Num) __builtin_memmove(__result - _Num, __first, sizeof(_Tp) * _Num); return __result - _Num; } }; template<bool _IsMove, typename _BI1, typename _BI2> inline _BI2 __copy_move_backward_a(_BI1 __first, _BI1 __last, _BI2 __result) { typedef typename iterator_traits<_BI1>::value_type _ValueType1; typedef typename iterator_traits<_BI2>::value_type _ValueType2; typedef typename iterator_traits<_BI1>::iterator_category _Category; const bool __simple = (__is_trivial(_ValueType1) && __is_pointer<_BI1>::__value && __is_pointer<_BI2>::__value && __are_same<_ValueType1, _ValueType2>::__value); return std::__copy_move_backward<_IsMove, __simple, _Category>::__copy_move_b(__first, __last, __result); } template<bool _IsMove, typename _BI1, typename _BI2> inline _BI2 __copy_move_backward_a2(_BI1 __first, _BI1 __last, _BI2 __result) { return _BI2(std::__copy_move_backward_a<_IsMove> (std::__niter_base(__first), std::__niter_base(__last), std::__niter_base(__result))); } /** * @brief Copies the range [first,last) into result. * @ingroup mutating_algorithms * @param __first A bidirectional iterator. * @param __last A bidirectional iterator. * @param __result A bidirectional iterator. * @return result - (first - last) * * The function has the same effect as copy, but starts at the end of the * range and works its way to the start, returning the start of the result. * This inline function will boil down to a call to @c memmove whenever * possible. Failing that, if random access iterators are passed, then the * loop count will be known (and therefore a candidate for compiler * optimizations such as unrolling). * * Result may not be in the range (first,last]. Use copy instead. Note * that the start of the output range may overlap [first,last). */ template<typename _BI1, typename _BI2> inline _BI2 copy_backward(_BI1 __first, _BI1 __last, _BI2 __result) { // concept requirements __glibcxx_function_requires(_BidirectionalIteratorConcept<_BI1>) __glibcxx_function_requires(_Mutable_BidirectionalIteratorConcept<_BI2>) __glibcxx_function_requires(_ConvertibleConcept< typename iterator_traits<_BI1>::value_type, typename iterator_traits<_BI2>::value_type>) __glibcxx_requires_valid_range(__first, __last); return (std::__copy_move_backward_a2<__is_move_iterator<_BI1>::__value> (std::__miter_base(__first), std::__miter_base(__last), __result)); } #if __cplusplus >= 201103L /** * @brief Moves the range [first,last) into result. * @ingroup mutating_algorithms * @param __first A bidirectional iterator. * @param __last A bidirectional iterator. * @param __result A bidirectional iterator. * @return result - (first - last) * * The function has the same effect as move, but starts at the end of the * range and works its way to the start, returning the start of the result. * This inline function will boil down to a call to @c memmove whenever * possible. Failing that, if random access iterators are passed, then the * loop count will be known (and therefore a candidate for compiler * optimizations such as unrolling). * * Result may not be in the range (first,last]. Use move instead. Note * that the start of the output range may overlap [first,last). */ template<typename _BI1, typename _BI2> inline _BI2 move_backward(_BI1 __first, _BI1 __last, _BI2 __result) { // concept requirements __glibcxx_function_requires(_BidirectionalIteratorConcept<_BI1>) __glibcxx_function_requires(_Mutable_BidirectionalIteratorConcept<_BI2>) __glibcxx_function_requires(_ConvertibleConcept< typename iterator_traits<_BI1>::value_type, typename iterator_traits<_BI2>::value_type>) __glibcxx_requires_valid_range(__first, __last); return std::__copy_move_backward_a2<true>(std::__miter_base(__first), std::__miter_base(__last), __result); } #define _GLIBCXX_MOVE_BACKWARD3(_Tp, _Up, _Vp) std::move_backward(_Tp, _Up, _Vp) #else #define _GLIBCXX_MOVE_BACKWARD3(_Tp, _Up, _Vp) std::copy_backward(_Tp, _Up, _Vp) #endif template<typename _ForwardIterator, typename _Tp> inline typename __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, void>::__type __fill_a(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { for (; __first != __last; ++__first) *__first = __value; } template<typename _ForwardIterator, typename _Tp> inline typename __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, void>::__type __fill_a(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { const _Tp __tmp = __value; for (; __first != __last; ++__first) *__first = __tmp; } // Specialization: for char types we can use memset. template<typename _Tp> inline typename __gnu_cxx::__enable_if<__is_byte<_Tp>::__value, void>::__type __fill_a(_Tp* __first, _Tp* __last, const _Tp& __c) { const _Tp __tmp = __c; __builtin_memset(__first, static_cast<unsigned char>(__tmp), __last - __first); } /** * @brief Fills the range [first,last) with copies of value. * @ingroup mutating_algorithms * @param __first A forward iterator. * @param __last A forward iterator. * @param __value A reference-to-const of arbitrary type. * @return Nothing. * * This function fills a range with copies of the same value. For char * types filling contiguous areas of memory, this becomes an inline call * to @c memset or @c wmemset. */ template<typename _ForwardIterator, typename _Tp> inline void fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) { // concept requirements __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< _ForwardIterator>) __glibcxx_requires_valid_range(__first, __last); std::__fill_a(std::__niter_base(__first), std::__niter_base(__last), __value); } template<typename _OutputIterator, typename _Size, typename _Tp> inline typename __gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value) { for (__decltype(__n + 0) __niter = __n; __niter > 0; --__niter, ++__first) *__first = __value; return __first; } template<typename _OutputIterator, typename _Size, typename _Tp> inline typename __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, _OutputIterator>::__type __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value) { const _Tp __tmp = __value; for (__decltype(__n + 0) __niter = __n; __niter > 0; --__niter, ++__first) *__first = __tmp; return __first; } template<typename _Size, typename _Tp> inline typename __gnu_cxx::__enable_if<__is_byte<_Tp>::__value, _Tp*>::__type __fill_n_a(_Tp* __first, _Size __n, const _Tp& __c) { std::__fill_a(__first, __first + __n, __c); return __first + __n; } /** * @brief Fills the range [first,first+n) with copies of value. * @ingroup mutating_algorithms * @param __first An output iterator. * @param __n The count of copies to perform. * @param __value A reference-to-const of arbitrary type. * @return The iterator at first+n. * * This function fills a range with copies of the same value. For char * types filling contiguous areas of memory, this becomes an inline call * to @c memset or @ wmemset. * * _GLIBCXX_RESOLVE_LIB_DEFECTS * DR 865. More algorithms that throw away information */ template<typename _OI, typename _Size, typename _Tp> inline _OI fill_n(_OI __first, _Size __n, const _Tp& __value) { // concept requirements __glibcxx_function_requires(_OutputIteratorConcept<_OI, _Tp>) return _OI(std::__fill_n_a(std::__niter_base(__first), __n, __value)); } template<bool _BoolType> struct __equal { template<typename _II1, typename _II2> static bool equal(_II1 __first1, _II1 __last1, _II2 __first2) { for (; __first1 != __last1; ++__first1, ++__first2) if (!(*__first1 == *__first2)) return false; return true; } }; template<> struct __equal<true> { template<typename _Tp> static bool equal(const _Tp* __first1, const _Tp* __last1, const _Tp* __first2) { return !__builtin_memcmp(__first1, __first2, sizeof(_Tp) * (__last1 - __first1)); } }; template<typename _II1, typename _II2> inline bool __equal_aux(_II1 __first1, _II1 __last1, _II2 __first2) { typedef typename iterator_traits<_II1>::value_type _ValueType1; typedef typename iterator_traits<_II2>::value_type _ValueType2; const bool __simple = ((__is_integer<_ValueType1>::__value || __is_pointer<_ValueType1>::__value) && __is_pointer<_II1>::__value && __is_pointer<_II2>::__value && __are_same<_ValueType1, _ValueType2>::__value); return std::__equal<__simple>::equal(__first1, __last1, __first2); } template<typename, typename> struct __lc_rai { template<typename _II1, typename _II2> static _II1 __newlast1(_II1, _II1 __last1, _II2, _II2) { return __last1; } template<typename _II> static bool __cnd2(_II __first, _II __last) { return __first != __last; } }; template<> struct __lc_rai<random_access_iterator_tag, random_access_iterator_tag> { template<typename _RAI1, typename _RAI2> static _RAI1 __newlast1(_RAI1 __first1, _RAI1 __last1, _RAI2 __first2, _RAI2 __last2) { const typename iterator_traits<_RAI1>::difference_type __diff1 = __last1 - __first1; const typename iterator_traits<_RAI2>::difference_type __diff2 = __last2 - __first2; return __diff2 < __diff1 ? __first1 + __diff2 : __last1; } template<typename _RAI> static bool __cnd2(_RAI, _RAI) { return true; } }; template<typename _II1, typename _II2, typename _Compare> bool __lexicographical_compare_impl(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2, _Compare __comp) { typedef typename iterator_traits<_II1>::iterator_category _Category1; typedef typename iterator_traits<_II2>::iterator_category _Category2; typedef std::__lc_rai<_Category1, _Category2> __rai_type; __last1 = __rai_type::__newlast1(__first1, __last1, __first2, __last2); for (; __first1 != __last1 && __rai_type::__cnd2(__first2, __last2); ++__first1, ++__first2) { if (__comp(__first1, __first2)) return true; if (__comp(__first2, __first1)) return false; } return __first1 == __last1 && __first2 != __last2; } template<bool _BoolType> struct __lexicographical_compare { template<typename _II1, typename _II2> static bool __lc(_II1, _II1, _II2, _II2); }; template<bool _BoolType> template<typename _II1, typename _II2> bool __lexicographical_compare<_BoolType>:: __lc(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2) { return std::__lexicographical_compare_impl(__first1, __last1, __first2, __last2, __gnu_cxx::__ops::__iter_less_iter()); } template<> struct __lexicographical_compare<true> { template<typename _Tp, typename _Up> static bool __lc(const _Tp* __first1, const _Tp* __last1, const _Up* __first2, const _Up* __last2) { const size_t __len1 = __last1 - __first1; const size_t __len2 = __last2 - __first2; const int __result = __builtin_memcmp(__first1, __first2, std::min(__len1, __len2)); return __result != 0 ? __result < 0 : __len1 < __len2; } }; template<typename _II1, typename _II2> inline bool __lexicographical_compare_aux(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2) { typedef typename iterator_traits<_II1>::value_type _ValueType1; typedef typename iterator_traits<_II2>::value_type _ValueType2; const bool __simple = (__is_byte<_ValueType1>::__value && __is_byte<_ValueType2>::__value && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed && __is_pointer<_II1>::__value && __is_pointer<_II2>::__value); return std::__lexicographical_compare<__simple>::__lc(__first1, __last1, __first2, __last2); } template<typename _ForwardIterator, typename _Tp, typename _Compare> _ForwardIterator __lower_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __val, _Compare __comp) { typedef typename iterator_traits<_ForwardIterator>::difference_type _DistanceType; _DistanceType __len = std::distance(__first, __last); while (__len > 0) { _DistanceType __half = __len >> 1; _ForwardIterator __middle = __first; std::advance(__middle, __half); if (__comp(__middle, __val)) { __first = __middle; ++__first; __len = __len - __half - 1; } else __len = __half; } return __first; } /** * @brief Finds the first position in which @a val could be inserted * without changing the ordering. * @param __first An iterator. * @param __last Another iterator. * @param __val The search term. * @return An iterator pointing to the first element <em>not less * than</em> @a val, or end() if every element is less than * @a val. * @ingroup binary_search_algorithms */ template<typename _ForwardIterator, typename _Tp> inline _ForwardIterator lower_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __val) { // concept requirements __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) __glibcxx_function_requires(_LessThanOpConcept< typename iterator_traits<_ForwardIterator>::value_type, _Tp>) __glibcxx_requires_partitioned_lower(__first, __last, __val); return std::__lower_bound(__first, __last, __val, __gnu_cxx::__ops::__iter_less_val()); } /// This is a helper function for the sort routines and for random.tcc. // Precondition: __n > 0. inline _GLIBCXX_CONSTEXPR int __lg(int __n) { return sizeof(int) * __CHAR_BIT__ - 1 - __builtin_clz(__n); } inline _GLIBCXX_CONSTEXPR unsigned __lg(unsigned __n) { return sizeof(int) * __CHAR_BIT__ - 1 - __builtin_clz(__n); } inline _GLIBCXX_CONSTEXPR long __lg(long __n) { return sizeof(long) * __CHAR_BIT__ - 1 - __builtin_clzl(__n); } inline _GLIBCXX_CONSTEXPR unsigned long __lg(unsigned long __n) { return sizeof(long) * __CHAR_BIT__ - 1 - __builtin_clzl(__n); } inline _GLIBCXX_CONSTEXPR long long __lg(long long __n) { return sizeof(long long) * __CHAR_BIT__ - 1 - __builtin_clzll(__n); } inline _GLIBCXX_CONSTEXPR unsigned long long __lg(unsigned long long __n) { return sizeof(long long) * __CHAR_BIT__ - 1 - __builtin_clzll(__n); } _GLIBCXX_END_NAMESPACE_VERSION _GLIBCXX_BEGIN_NAMESPACE_ALGO /** * @brief Tests a range for element-wise equality. * @ingroup non_mutating_algorithms * @param __first1 An input iterator. * @param __last1 An input iterator. * @param __first2 An input iterator. * @return A boolean true or false. * * This compares the elements of two ranges using @c == and returns true or * false depending on whether all of the corresponding elements of the * ranges are equal. */ template<typename _II1, typename _II2> inline bool equal(_II1 __first1, _II1 __last1, _II2 __first2) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_II1>) __glibcxx_function_requires(_InputIteratorConcept<_II2>) __glibcxx_function_requires(_EqualOpConcept< typename iterator_traits<_II1>::value_type, typename iterator_traits<_II2>::value_type>) __glibcxx_requires_valid_range(__first1, __last1); return std::__equal_aux(std::__niter_base(__first1), std::__niter_base(__last1), std::__niter_base(__first2)); } /** * @brief Tests a range for element-wise equality. * @ingroup non_mutating_algorithms * @param __first1 An input iterator. * @param __last1 An input iterator. * @param __first2 An input iterator. * @param __binary_pred A binary predicate @link functors * functor@endlink. * @return A boolean true or false. * * This compares the elements of two ranges using the binary_pred * parameter, and returns true or * false depending on whether all of the corresponding elements of the * ranges are equal. */ template<typename _IIter1, typename _IIter2, typename _BinaryPredicate> inline bool equal(_IIter1 __first1, _IIter1 __last1, _IIter2 __first2, _BinaryPredicate __binary_pred) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_IIter1>) __glibcxx_function_requires(_InputIteratorConcept<_IIter2>) __glibcxx_requires_valid_range(__first1, __last1); for (; __first1 != __last1; ++__first1, ++__first2) if (!bool(__binary_pred(*__first1, *__first2))) return false; return true; } #if __cplusplus > 201103L #define __cpp_lib_robust_nonmodifying_seq_ops 201304 /** * @brief Tests a range for element-wise equality. * @ingroup non_mutating_algorithms * @param __first1 An input iterator. * @param __last1 An input iterator. * @param __first2 An input iterator. * @param __last2 An input iterator. * @return A boolean true or false. * * This compares the elements of two ranges using @c == and returns true or * false depending on whether all of the corresponding elements of the * ranges are equal. */ template<typename _II1, typename _II2> inline bool equal(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_II1>) __glibcxx_function_requires(_InputIteratorConcept<_II2>) __glibcxx_function_requires(_EqualOpConcept< typename iterator_traits<_II1>::value_type, typename iterator_traits<_II2>::value_type>) __glibcxx_requires_valid_range(__first1, __last1); __glibcxx_requires_valid_range(__first2, __last2); using _RATag = random_access_iterator_tag; using _Cat1 = typename iterator_traits<_II1>::iterator_category; using _Cat2 = typename iterator_traits<_II2>::iterator_category; using _RAIters = __and_<is_same<_Cat1, _RATag>, is_same<_Cat2, _RATag>>; if (_RAIters()) { auto __d1 = std::distance(__first1, __last1); auto __d2 = std::distance(__first2, __last2); if (__d1 != __d2) return false; return _GLIBCXX_STD_A::equal(__first1, __last1, __first2); } for (; __first1 != __last1 && __first2 != __last2; ++__first1, ++__first2) if (!(*__first1 == *__first2)) return false; return __first1 == __last1 && __first2 == __last2; } /** * @brief Tests a range for element-wise equality. * @ingroup non_mutating_algorithms * @param __first1 An input iterator. * @param __last1 An input iterator. * @param __first2 An input iterator. * @param __last2 An input iterator. * @param __binary_pred A binary predicate @link functors * functor@endlink. * @return A boolean true or false. * * This compares the elements of two ranges using the binary_pred * parameter, and returns true or * false depending on whether all of the corresponding elements of the * ranges are equal. */ template<typename _IIter1, typename _IIter2, typename _BinaryPredicate> inline bool equal(_IIter1 __first1, _IIter1 __last1, _IIter2 __first2, _IIter2 __last2, _BinaryPredicate __binary_pred) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_IIter1>) __glibcxx_function_requires(_InputIteratorConcept<_IIter2>) __glibcxx_requires_valid_range(__first1, __last1); __glibcxx_requires_valid_range(__first2, __last2); using _RATag = random_access_iterator_tag; using _Cat1 = typename iterator_traits<_IIter1>::iterator_category; using _Cat2 = typename iterator_traits<_IIter2>::iterator_category; using _RAIters = __and_<is_same<_Cat1, _RATag>, is_same<_Cat2, _RATag>>; if (_RAIters()) { auto __d1 = std::distance(__first1, __last1); auto __d2 = std::distance(__first2, __last2); if (__d1 != __d2) return false; return _GLIBCXX_STD_A::equal(__first1, __last1, __first2, __binary_pred); } for (; __first1 != __last1 && __first2 != __last2; ++__first1, ++__first2) if (!bool(__binary_pred(*__first1, *__first2))) return false; return __first1 == __last1 && __first2 == __last2; } #endif /** * @brief Performs @b dictionary comparison on ranges. * @ingroup sorting_algorithms * @param __first1 An input iterator. * @param __last1 An input iterator. * @param __first2 An input iterator. * @param __last2 An input iterator. * @return A boolean true or false. * * Returns true if the sequence of elements defined by the <em>range * [first1,last1) is lexicographically less than the sequence of elements * defined by the range [first2,last2). Returns false otherwise.</em> * (Quoted from [25.3.8]/1.) If the iterators are all character pointers, * then this is an inline call to @c memcmp. */ template<typename _II1, typename _II2> inline bool lexicographical_compare(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2) { #ifdef _GLIBCXX_CONCEPT_CHECKS // concept requirements typedef typename iterator_traits<_II1>::value_type _ValueType1; typedef typename iterator_traits<_II2>::value_type _ValueType2; #endif __glibcxx_function_requires(_InputIteratorConcept<_II1>) __glibcxx_function_requires(_InputIteratorConcept<_II2>) __glibcxx_function_requires(_LessThanOpConcept<_ValueType1, _ValueType2>) __glibcxx_function_requires(_LessThanOpConcept<_ValueType2, _ValueType1>) __glibcxx_requires_valid_range(__first1, __last1); __glibcxx_requires_valid_range(__first2, __last2); return std::__lexicographical_compare_aux(std::__niter_base(__first1), std::__niter_base(__last1), std::__niter_base(__first2), std::__niter_base(__last2)); } /** * @brief Performs @b dictionary comparison on ranges. * @ingroup sorting_algorithms * @param __first1 An input iterator. * @param __last1 An input iterator. * @param __first2 An input iterator. * @param __last2 An input iterator. * @param __comp A @link comparison_functors comparison functor@endlink. * @return A boolean true or false. * * The same as the four-parameter @c lexicographical_compare, but uses the * comp parameter instead of @c <. */ template<typename _II1, typename _II2, typename _Compare> inline bool lexicographical_compare(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2, _Compare __comp) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_II1>) __glibcxx_function_requires(_InputIteratorConcept<_II2>) __glibcxx_requires_valid_range(__first1, __last1); __glibcxx_requires_valid_range(__first2, __last2); return std::__lexicographical_compare_impl (__first1, __last1, __first2, __last2, __gnu_cxx::__ops::__iter_comp_iter(__comp)); } template<typename _InputIterator1, typename _InputIterator2, typename _BinaryPredicate> pair<_InputIterator1, _InputIterator2> __mismatch(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate __binary_pred) { while (__first1 != __last1 && __binary_pred(__first1, __first2)) { ++__first1; ++__first2; } return pair<_InputIterator1, _InputIterator2>(__first1, __first2); } /** * @brief Finds the places in ranges which don't match. * @ingroup non_mutating_algorithms * @param __first1 An input iterator. * @param __last1 An input iterator. * @param __first2 An input iterator. * @return A pair of iterators pointing to the first mismatch. * * This compares the elements of two ranges using @c == and returns a pair * of iterators. The first iterator points into the first range, the * second iterator points into the second range, and the elements pointed * to by the iterators are not equal. */ template<typename _InputIterator1, typename _InputIterator2> inline pair<_InputIterator1, _InputIterator2> mismatch(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) __glibcxx_function_requires(_EqualOpConcept< typename iterator_traits<_InputIterator1>::value_type, typename iterator_traits<_InputIterator2>::value_type>) __glibcxx_requires_valid_range(__first1, __last1); return _GLIBCXX_STD_A::__mismatch(__first1, __last1, __first2, __gnu_cxx::__ops::__iter_equal_to_iter()); } /** * @brief Finds the places in ranges which don't match. * @ingroup non_mutating_algorithms * @param __first1 An input iterator. * @param __last1 An input iterator. * @param __first2 An input iterator. * @param __binary_pred A binary predicate @link functors * functor@endlink. * @return A pair of iterators pointing to the first mismatch. * * This compares the elements of two ranges using the binary_pred * parameter, and returns a pair * of iterators. The first iterator points into the first range, the * second iterator points into the second range, and the elements pointed * to by the iterators are not equal. */ template<typename _InputIterator1, typename _InputIterator2, typename _BinaryPredicate> inline pair<_InputIterator1, _InputIterator2> mismatch(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _BinaryPredicate __binary_pred) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) __glibcxx_requires_valid_range(__first1, __last1); return _GLIBCXX_STD_A::__mismatch(__first1, __last1, __first2, __gnu_cxx::__ops::__iter_comp_iter(__binary_pred)); } #if __cplusplus > 201103L template<typename _InputIterator1, typename _InputIterator2, typename _BinaryPredicate> pair<_InputIterator1, _InputIterator2> __mismatch(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, _BinaryPredicate __binary_pred) { while (__first1 != __last1 && __first2 != __last2 && __binary_pred(__first1, __first2)) { ++__first1; ++__first2; } return pair<_InputIterator1, _InputIterator2>(__first1, __first2); } /** * @brief Finds the places in ranges which don't match. * @ingroup non_mutating_algorithms * @param __first1 An input iterator. * @param __last1 An input iterator. * @param __first2 An input iterator. * @param __last2 An input iterator. * @return A pair of iterators pointing to the first mismatch. * * This compares the elements of two ranges using @c == and returns a pair * of iterators. The first iterator points into the first range, the * second iterator points into the second range, and the elements pointed * to by the iterators are not equal. */ template<typename _InputIterator1, typename _InputIterator2> inline pair<_InputIterator1, _InputIterator2> mismatch(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) __glibcxx_function_requires(_EqualOpConcept< typename iterator_traits<_InputIterator1>::value_type, typename iterator_traits<_InputIterator2>::value_type>) __glibcxx_requires_valid_range(__first1, __last1); __glibcxx_requires_valid_range(__first2, __last2); return _GLIBCXX_STD_A::__mismatch(__first1, __last1, __first2, __last2, __gnu_cxx::__ops::__iter_equal_to_iter()); } /** * @brief Finds the places in ranges which don't match. * @ingroup non_mutating_algorithms * @param __first1 An input iterator. * @param __last1 An input iterator. * @param __first2 An input iterator. * @param __last2 An input iterator. * @param __binary_pred A binary predicate @link functors * functor@endlink. * @return A pair of iterators pointing to the first mismatch. * * This compares the elements of two ranges using the binary_pred * parameter, and returns a pair * of iterators. The first iterator points into the first range, the * second iterator points into the second range, and the elements pointed * to by the iterators are not equal. */ template<typename _InputIterator1, typename _InputIterator2, typename _BinaryPredicate> inline pair<_InputIterator1, _InputIterator2> mismatch(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2, _BinaryPredicate __binary_pred) { // concept requirements __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) __glibcxx_requires_valid_range(__first1, __last1); __glibcxx_requires_valid_range(__first2, __last2); return _GLIBCXX_STD_A::__mismatch(__first1, __last1, __first2, __last2, __gnu_cxx::__ops::__iter_comp_iter(__binary_pred)); } #endif _GLIBCXX_END_NAMESPACE_ALGO } // namespace std // NB: This file is included within many other C++ includes, as a way // of getting the base algorithms. So, make sure that parallel bits // come in too if requested. #ifdef _GLIBCXX_PARALLEL # include <parallel/algobase.h> #endif #endif
最新发布
12-20
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值