diff --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst --- a/libcxx/docs/ReleaseNotes.rst +++ b/libcxx/docs/ReleaseNotes.rst @@ -87,6 +87,9 @@ supported anymore. Please migrate to using the new support for :ref:`assertions ` instead. +- The experimental versions of ``boyer_moore_searcher`` and ``boyer_moore_horspool_searcher`` + will be removed in LLVM 17. + ABI Changes ----------- diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -231,6 +231,7 @@ __functional/bind_front.h __functional/binder1st.h __functional/binder2nd.h + __functional/boyer_moore_searcher.h __functional/compose.h __functional/default_searcher.h __functional/function.h diff --git a/libcxx/include/__functional/boyer_moore_searcher.h b/libcxx/include/__functional/boyer_moore_searcher.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__functional/boyer_moore_searcher.h @@ -0,0 +1,313 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_BOYER_MOORE_SEARCHER_H +#define _LIBCPP___FUNCTIONAL_BOYER_MOORE_SEARCHER_H + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#include <__algorithm/fill_n.h> +#include <__config> +#include <__functional/hash.h> +#include <__functional/operations.h> +#include <__iterator/distance.h> +#include <__iterator/iterator_traits.h> +#include <__memory/shared_ptr.h> +#include <__utility/pair.h> +#include +#include +#include + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 14 + +template +class _BMSkipTable; + +// General case for BM data searching; use a map +template +class _BMSkipTable<_Key, _Value, _Hash, _BinaryPredicate, false> { +private: + using value_type = _Value; + using key_type = _Key; + + const value_type __default_value_; + unordered_map<_Key, _Value, _Hash, _BinaryPredicate> __table_; + +public: + _LIBCPP_HIDE_FROM_ABI + explicit _BMSkipTable(size_t __sz, value_type __default_value, _Hash __hash, _BinaryPredicate __pred) + : __default_value_(__default_value), + __table_(__sz, __hash, __pred) {} + + _LIBCPP_HIDE_FROM_ABI void insert(const key_type& __key, value_type __val) { + __table_[__key] = __val; + } + + _LIBCPP_HIDE_FROM_ABI value_type operator[](const key_type& __key) const { + auto __it = __table_.find(__key); + return __it == __table_.end() ? __default_value_ : __it->second; + } +}; + +// Special case small numeric values; use an array +template +class _BMSkipTable<_Key, _Value, _Hash, _BinaryPredicate, true> { +private: + using value_type = _Value; + using key_type = _Key; + + using unsigned_key_type = make_unsigned_t; + std::array __table_; + static_assert(numeric_limits::max() < 256); + +public: + _LIBCPP_HIDE_FROM_ABI explicit _BMSkipTable(size_t, value_type __default_value, _Hash, _BinaryPredicate) { + std::fill_n(__table_.data(), __table_.size(), __default_value); + } + + _LIBCPP_HIDE_FROM_ABI void insert(key_type __key, value_type __val) { + __table_[static_cast(__key)] = __val; + } + + _LIBCPP_HIDE_FROM_ABI value_type operator[](key_type __key) const { + return __table_[static_cast(__key)]; + } +}; + +template ::value_type>, + class _BinaryPredicate = equal_to<>> +class _LIBCPP_TEMPLATE_VIS boyer_moore_searcher { +private: + using difference_type = typename std::iterator_traits<_RandomAccessIterator1>::difference_type; + using value_type = typename std::iterator_traits<_RandomAccessIterator1>::value_type; + using __skip_table_type = _BMSkipTable + && sizeof(value_type) == 1 + && is_same_v<_Hash, hash> + && is_same_v<_BinaryPredicate, equal_to<>>>; + +public: + boyer_moore_searcher(_RandomAccessIterator1 __first, + _RandomAccessIterator1 __last, + _Hash __hash = _Hash(), + _BinaryPredicate __pred = _BinaryPredicate()) + : __first_(__first), + __last_(__last), + __pred_(__pred), + __pattern_length_(__last - __first), + __skip_table_(std::make_shared<__skip_table_type>(__pattern_length_, -1, __hash, __pred_)), + __suffix_(std::__allocate_shared_unbounded_array( + allocator(), __pattern_length_ + 1)) { + difference_type __i = 0; + while (__first != __last) { + __skip_table_->insert(*__first, __i); + ++__first; + ++__i; + } + __build_suffix_table(__first_, __last_, __pred_); + } + + template + pair<_RandomAccessIterator2, _RandomAccessIterator2> + operator()(_RandomAccessIterator2 __first, _RandomAccessIterator2 __last) const { + static_assert(__is_same_uncvref::value_type, + typename iterator_traits<_RandomAccessIterator2>::value_type>::value, + "Corpus and Pattern iterators must point to the same type"); + if (__first == __last) + return std::make_pair(__last, __last); + if (__first_ == __last_) + return std::make_pair(__first, __first); + + if (__pattern_length_ > (__last - __first)) + return std::make_pair(__last, __last); + return __search(__first, __last); + } + +private: + _RandomAccessIterator1 __first_; + _RandomAccessIterator1 __last_; + _BinaryPredicate __pred_; + difference_type __pattern_length_; + shared_ptr<__skip_table_type> __skip_table_; + shared_ptr __suffix_; + + template + pair<_RandomAccessIterator2, _RandomAccessIterator2> + __search(_RandomAccessIterator2 __f, _RandomAccessIterator2 __l) const { + _RandomAccessIterator2 __current = __f; + const _RandomAccessIterator2 __last = __l - __pattern_length_; + const __skip_table_type& __skip_table = *__skip_table_; + + while (__current <= __last) { + difference_type __j = __pattern_length_; + while (__pred_(__first_[__j - 1], __current[__j - 1])) { + --__j; + if (__j == 0) + return std::make_pair(__current, __current + __pattern_length_); + } + + difference_type __k = __skip_table[__current[__j - 1]]; + difference_type __m = __j - __k - 1; + if (__k < __j && __m > __suffix_[__j]) + __current += __m; + else + __current += __suffix_[__j]; + } + return std::make_pair(__l, __l); + } + + template + void __compute_bm_prefix(_Iterator __first, _Iterator __last, _BinaryPredicate __pred, _Container& __prefix) { + const size_t __count = __last - __first; + + __prefix[0] = 0; + size_t __k = 0; + + for (size_t __i = 1; __i != __count; ++__i) { + while (__k > 0 && !__pred(__first[__k], __first[__i])) + __k = __prefix[__k - 1]; + + if (__pred(__first[__k], __first[__i])) + ++__k; + __prefix[__i] = __k; + } + } + + void __build_suffix_table(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _BinaryPredicate __pred) { + const size_t __count = __last - __first; + + if (__count == 0) + return; + + vector __scratch(__count); + + __compute_bm_prefix(__first, __last, __pred, __scratch); + for (size_t __i = 0; __i <= __count; ++__i) + __suffix_[__i] = __count - __scratch[__count - 1]; + + using _ReverseIter = reverse_iterator<_RandomAccessIterator1>; + __compute_bm_prefix(_ReverseIter(__last), _ReverseIter(__first), __pred, __scratch); + + for (size_t __i = 0; __i != __count; ++__i) { + const size_t __j = __count - __scratch[__i]; + const difference_type __k = __i - __scratch[__i] + 1; + + if (__suffix_[__j] > __k) + __suffix_[__j] = __k; + } + } +}; + +template ::value_type>, + class _BinaryPredicate = equal_to<>> +class _LIBCPP_TEMPLATE_VIS boyer_moore_horspool_searcher { +private: + using difference_type = typename iterator_traits<_RandomAccessIterator1>::difference_type; + using value_type = typename iterator_traits<_RandomAccessIterator1>::value_type; + using __skip_table_type = _BMSkipTable + && sizeof(value_type) == 1 + && is_same_v<_Hash, hash> + && is_same_v<_BinaryPredicate, equal_to<>>>; +public: + boyer_moore_horspool_searcher(_RandomAccessIterator1 __first, + _RandomAccessIterator1 __last, + _Hash __hash = _Hash(), + _BinaryPredicate __pred = _BinaryPredicate()) + : __first_(__first), + __last_(__last), + __pred_(__pred), + __pattern_length_(__last - __first), + __skip_table_(std::make_shared<__skip_table_type>(__pattern_length_, __pattern_length_, __hash, __pred_)) { + if (__first == __last) + return; + --__last; + difference_type __i = 0; + while (__first != __last) { + __skip_table_->insert(*__first, __pattern_length_ - 1 - __i); + ++__first; + ++__i; + } + } + + template + pair<_RandomAccessIterator2, _RandomAccessIterator2> + operator()(_RandomAccessIterator2 __first, _RandomAccessIterator2 __last) const { + static_assert(__is_same_uncvref::value_type, + typename std::iterator_traits<_RandomAccessIterator2>::value_type>::value, + "Corpus and Pattern iterators must point to the same type"); + if (__first == __last) + return std::make_pair(__last, __last); + if (__first_ == __last_) + return std::make_pair(__first, __first); + + if (__pattern_length_ > __last - __first) + return std::make_pair(__last, __last); + + return __search(__first, __last); + } + +private: + _RandomAccessIterator1 __first_; + _RandomAccessIterator1 __last_; + _BinaryPredicate __pred_; + difference_type __pattern_length_; + shared_ptr<__skip_table_type> __skip_table_; + + template + pair<_RandomAccessIterator2, _RandomAccessIterator2> + __search(_RandomAccessIterator2 __f, _RandomAccessIterator2 __l) const { + _RandomAccessIterator2 __current = __f; + const _RandomAccessIterator2 __last = __l - __pattern_length_; + const __skip_table_type& __skip_table = *__skip_table_; + + while (__current <= __last) { + difference_type __j = __pattern_length_; + while (__pred_(__first_[__j - 1], __current[__j - 1])) { + --__j; + if (__j == 0) + return std::make_pair(__current, __current + __pattern_length_); + } + __current += __skip_table[__current[__pattern_length_ - 1]]; + } + return std::make_pair(__l, __l); + } +}; + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP_STD_VER > 14 + +#endif // _LIBCPP___FUNCTIONAL_BOYER_MOORE_SEARCHER_H diff --git a/libcxx/include/experimental/functional b/libcxx/include/experimental/functional --- a/libcxx/include/experimental/functional +++ b/libcxx/include/experimental/functional @@ -79,10 +79,20 @@ _LIBCPP_BEGIN_NAMESPACE_LFTS +#ifdef _LIBCPP_NO_EXPERIMENTAL_DEPRECATION_WARNING_SEARCHERS +# define _LIBCPP_DEPRECATED_DEFAULT_SEARCHER +# define _LIBCPP_DEPRECATED_BOYER_MOORE_SEARCHER +# define _LIBCPP_DEPRECATED_BOYER_MOORE_HORSPOOL_SEARCHER +#else +# define _LIBCPP_DEPRECATED_DEFAULT_SEARCHER [[deprecated("std::exprerimental::default_searcher will be removed in LLVM 17. Use std::default_searcher instead")]] +# define _LIBCPP_DEPRECATED_BOYER_MOORE_SEARCHER [[deprecated("std::exprerimental::boyer_moore_searcher will be removed in LLVM 17. Use std::boyer_moore_searcher instead")]] +# define _LIBCPP_DEPRECATED_BOYER_MOORE_HORSPOOL_SEARCHER [[deprecated("std::exprerimental::boyer_moore_horspool_searcher will be removed in LLVM 17. Use std::boyer_moore_horspool_searcher instead")]] +#endif + #if _LIBCPP_STD_VER > 11 // default searcher template> -class _LIBCPP_TEMPLATE_VIS default_searcher { +class _LIBCPP_DEPRECATED_DEFAULT_SEARCHER _LIBCPP_TEMPLATE_VIS default_searcher { public: _LIBCPP_INLINE_VISIBILITY default_searcher(_ForwardIterator __f, _ForwardIterator __l, @@ -106,7 +116,7 @@ }; template> -_LIBCPP_INLINE_VISIBILITY +_LIBCPP_DEPRECATED_DEFAULT_SEARCHER _LIBCPP_INLINE_VISIBILITY default_searcher<_ForwardIterator, _BinaryPredicate> make_default_searcher( _ForwardIterator __f, _ForwardIterator __l, _BinaryPredicate __p = _BinaryPredicate ()) { @@ -179,7 +189,7 @@ template ::value_type>, class _BinaryPredicate = equal_to<>> -class _LIBCPP_TEMPLATE_VIS boyer_moore_searcher { +class _LIBCPP_DEPRECATED_BOYER_MOORE_SEARCHER _LIBCPP_TEMPLATE_VIS boyer_moore_searcher { private: typedef typename std::iterator_traits<_RandomAccessIterator1>::difference_type difference_type; typedef typename std::iterator_traits<_RandomAccessIterator1>::value_type value_type; @@ -316,7 +326,7 @@ template::value_type>, class _BinaryPredicate = equal_to<>> -_LIBCPP_INLINE_VISIBILITY +_LIBCPP_DEPRECATED_BOYER_MOORE_SEARCHER _LIBCPP_INLINE_VISIBILITY boyer_moore_searcher<_RandomAccessIterator, _Hash, _BinaryPredicate> make_boyer_moore_searcher( _RandomAccessIterator __f, _RandomAccessIterator __l, _Hash __hf = _Hash(), _BinaryPredicate __p = _BinaryPredicate ()) @@ -328,7 +338,7 @@ template ::value_type>, class _BinaryPredicate = equal_to<>> -class _LIBCPP_TEMPLATE_VIS boyer_moore_horspool_searcher { +class _LIBCPP_DEPRECATED_BOYER_MOORE_HORSPOOL_SEARCHER _LIBCPP_TEMPLATE_VIS boyer_moore_horspool_searcher { private: typedef typename std::iterator_traits<_RandomAccessIterator1>::difference_type difference_type; typedef typename std::iterator_traits<_RandomAccessIterator1>::value_type value_type; @@ -409,7 +419,7 @@ template::value_type>, class _BinaryPredicate = equal_to<>> -_LIBCPP_INLINE_VISIBILITY +_LIBCPP_DEPRECATED_BOYER_MOORE_HORSPOOL_SEARCHER _LIBCPP_INLINE_VISIBILITY boyer_moore_horspool_searcher<_RandomAccessIterator, _Hash, _BinaryPredicate> make_boyer_moore_horspool_searcher( _RandomAccessIterator __f, _RandomAccessIterator __l, _Hash __hf = _Hash(), _BinaryPredicate __p = _BinaryPredicate ()) diff --git a/libcxx/include/functional b/libcxx/include/functional --- a/libcxx/include/functional +++ b/libcxx/include/functional @@ -502,6 +502,7 @@ #include <__functional/bind_front.h> #include <__functional/binder1st.h> #include <__functional/binder2nd.h> +#include <__functional/boyer_moore_searcher.h> #include <__functional/compose.h> #include <__functional/default_searcher.h> #include <__functional/function.h> diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -579,6 +579,7 @@ module bind_front { private header "__functional/bind_front.h" } module binder1st { private header "__functional/binder1st.h" } module binder2nd { private header "__functional/binder2nd.h" } + module boyer_moore_searcher { private header "__functional/boyer_moore_searcher.h" } module compose { private header "__functional/compose.h" } module default_searcher { private header "__functional/default_searcher.h" } module function { private header "__functional/function.h" } diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -263,6 +263,7 @@ #include <__functional/bind_front.h> // expected-error@*:* {{use of private header from outside its module: '__functional/bind_front.h'}} #include <__functional/binder1st.h> // expected-error@*:* {{use of private header from outside its module: '__functional/binder1st.h'}} #include <__functional/binder2nd.h> // expected-error@*:* {{use of private header from outside its module: '__functional/binder2nd.h'}} +#include <__functional/boyer_moore_searcher.h> // expected-error@*:* {{use of private header from outside its module: '__functional/boyer_moore_searcher.h'}} #include <__functional/compose.h> // expected-error@*:* {{use of private header from outside its module: '__functional/compose.h'}} #include <__functional/default_searcher.h> // expected-error@*:* {{use of private header from outside its module: '__functional/default_searcher.h'}} #include <__functional/function.h> // expected-error@*:* {{use of private header from outside its module: '__functional/function.h'}} diff --git a/libcxx/test/std/utilities/function.objects/func.search/func.search.bm/default.pass.cpp b/libcxx/test/std/utilities/function.objects/func.search/func.search.bm/default.pass.cpp --- a/libcxx/test/std/utilities/function.objects/func.search/func.search.bm/default.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.search/func.search.bm/default.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: stdlib=libc++ // @@ -33,8 +32,8 @@ #include -#include #include +#include #include "test_macros.h" #include "test_iterators.h" diff --git a/libcxx/test/std/utilities/function.objects/func.search/func.search.bm/hash.pass.cpp b/libcxx/test/std/utilities/function.objects/func.search/func.search.bm/hash.pass.cpp --- a/libcxx/test/std/utilities/function.objects/func.search/func.search.bm/hash.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.search/func.search.bm/hash.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: stdlib=libc++ // @@ -33,8 +32,8 @@ #include -#include #include +#include #include "test_macros.h" #include "test_iterators.h" diff --git a/libcxx/test/std/utilities/function.objects/func.search/func.search.bm/hash.pred.pass.cpp b/libcxx/test/std/utilities/function.objects/func.search/func.search.bm/hash.pred.pass.cpp --- a/libcxx/test/std/utilities/function.objects/func.search/func.search.bm/hash.pred.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.search/func.search.bm/hash.pred.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: stdlib=libc++ // @@ -33,8 +32,8 @@ #include -#include #include +#include #include "test_macros.h" #include "test_iterators.h" diff --git a/libcxx/test/std/utilities/function.objects/func.search/func.search.bm/pred.pass.cpp b/libcxx/test/std/utilities/function.objects/func.search/func.search.bm/pred.pass.cpp --- a/libcxx/test/std/utilities/function.objects/func.search/func.search.bm/pred.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.search/func.search.bm/pred.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: stdlib=libc++ // @@ -33,8 +32,8 @@ #include -#include #include +#include #include "test_macros.h" #include "test_iterators.h" diff --git a/libcxx/test/std/utilities/function.objects/func.search/func.search.bmh/default.pass.cpp b/libcxx/test/std/utilities/function.objects/func.search/func.search.bmh/default.pass.cpp --- a/libcxx/test/std/utilities/function.objects/func.search/func.search.bmh/default.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.search/func.search.bmh/default.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: stdlib=libc++ // diff --git a/libcxx/test/std/utilities/function.objects/func.search/func.search.bmh/hash.pass.cpp b/libcxx/test/std/utilities/function.objects/func.search/func.search.bmh/hash.pass.cpp --- a/libcxx/test/std/utilities/function.objects/func.search/func.search.bmh/hash.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.search/func.search.bmh/hash.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: stdlib=libc++ // diff --git a/libcxx/test/std/utilities/function.objects/func.search/func.search.bmh/hash.pred.pass.cpp b/libcxx/test/std/utilities/function.objects/func.search/func.search.bmh/hash.pred.pass.cpp --- a/libcxx/test/std/utilities/function.objects/func.search/func.search.bmh/hash.pred.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.search/func.search.bmh/hash.pred.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: stdlib=libc++ // diff --git a/libcxx/test/std/utilities/function.objects/func.search/func.search.bmh/pred.pass.cpp b/libcxx/test/std/utilities/function.objects/func.search/func.search.bmh/pred.pass.cpp --- a/libcxx/test/std/utilities/function.objects/func.search/func.search.bmh/pred.pass.cpp +++ b/libcxx/test/std/utilities/function.objects/func.search/func.search.bmh/pred.pass.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14 -// XFAIL: stdlib=libc++ // diff --git a/libcxx/test/std/utilities/optional/optional.hash/enabled_hash.pass.cpp b/libcxx/test/std/utilities/optional/optional.hash/enabled_hash.pass.cpp --- a/libcxx/test/std/utilities/optional/optional.hash/enabled_hash.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.hash/enabled_hash.pass.cpp @@ -13,6 +13,7 @@ // Test that provides all of the arithmetic, enum, and pointer // hash specializations. +#include #include #include "poisoned_hash_helper.h"