1292928Sdim// -*- C++ -*- 2292928Sdim//===-------------------------- functional --------------------------------===// 3292928Sdim// 4292928Sdim// The LLVM Compiler Infrastructure 5292928Sdim// 6292928Sdim// This file is dual licensed under the MIT and the University of Illinois Open 7292928Sdim// Source Licenses. See LICENSE.TXT for details. 8292928Sdim// 9292928Sdim//===----------------------------------------------------------------------===// 10292928Sdim 11292928Sdim#ifndef _LIBCPP_EXPERIMENTAL_FUNCTIONAL 12292928Sdim#define _LIBCPP_EXPERIMENTAL_FUNCTIONAL 13292928Sdim 14292928Sdim/* 15292928Sdim experimental/functional synopsis 16292928Sdim 17292928Sdim#include <algorithm> 18292928Sdim 19292928Sdimnamespace std { 20292928Sdimnamespace experimental { 21292928Sdiminline namespace fundamentals_v1 { 22292928Sdim 23292928Sdim // See C++14 20.9.9, Function object binders 24292928Sdim template <class T> constexpr bool is_bind_expression_v 25292928Sdim = is_bind_expression<T>::value; 26292928Sdim template <class T> constexpr int is_placeholder_v 27292928Sdim = is_placeholder<T>::value; 28292928Sdim 29292928Sdim // 4.2, Class template function 30292928Sdim template<class> class function; // undefined 31292928Sdim template<class R, class... ArgTypes> class function<R(ArgTypes...)>; 32292928Sdim 33292928Sdim template<class R, class... ArgTypes> 34292928Sdim void swap(function<R(ArgTypes...)>&, function<R(ArgTypes...)>&); 35292928Sdim 36292928Sdim template<class R, class... ArgTypes> 37292928Sdim bool operator==(const function<R(ArgTypes...)>&, nullptr_t) noexcept; 38292928Sdim template<class R, class... ArgTypes> 39292928Sdim bool operator==(nullptr_t, const function<R(ArgTypes...)>&) noexcept; 40292928Sdim template<class R, class... ArgTypes> 41292928Sdim bool operator!=(const function<R(ArgTypes...)>&, nullptr_t) noexcept; 42292928Sdim template<class R, class... ArgTypes> 43292928Sdim bool operator!=(nullptr_t, const function<R(ArgTypes...)>&) noexcept; 44292928Sdim 45292928Sdim // 4.3, Searchers 46292928Sdim template<class ForwardIterator, class BinaryPredicate = equal_to<>> 47292928Sdim class default_searcher; 48292928Sdim 49292928Sdim template<class RandomAccessIterator, 50292928Sdim class Hash = hash<typename iterator_traits<RandomAccessIterator>::value_type>, 51292928Sdim class BinaryPredicate = equal_to<>> 52292928Sdim class boyer_moore_searcher; 53292928Sdim 54292928Sdim template<class RandomAccessIterator, 55292928Sdim class Hash = hash<typename iterator_traits<RandomAccessIterator>::value_type>, 56292928Sdim class BinaryPredicate = equal_to<>> 57292928Sdim class boyer_moore_horspool_searcher; 58292928Sdim 59292928Sdim template<class ForwardIterator, class BinaryPredicate = equal_to<>> 60292928Sdim default_searcher<ForwardIterator, BinaryPredicate> 61292928Sdim make_default_searcher(ForwardIterator pat_first, ForwardIterator pat_last, 62292928Sdim BinaryPredicate pred = BinaryPredicate()); 63292928Sdim 64292928Sdim template<class RandomAccessIterator, 65292928Sdim class Hash = hash<typename iterator_traits<RandomAccessIterator>::value_type>, 66292928Sdim class BinaryPredicate = equal_to<>> 67292928Sdim boyer_moore_searcher<RandomAccessIterator, Hash, BinaryPredicate> 68292928Sdim make_boyer_moore_searcher( 69292928Sdim RandomAccessIterator pat_first, RandomAccessIterator pat_last, 70292928Sdim Hash hf = Hash(), BinaryPredicate pred = BinaryPredicate()); 71292928Sdim 72292928Sdim template<class RandomAccessIterator, 73292928Sdim class Hash = hash<typename iterator_traits<RandomAccessIterator>::value_type>, 74292928Sdim class BinaryPredicate = equal_to<>> 75292928Sdim boyer_moore_horspool_searcher<RandomAccessIterator, Hash, BinaryPredicate> 76292928Sdim make_boyer_moore_horspool_searcher( 77292928Sdim RandomAccessIterator pat_first, RandomAccessIterator pat_last, 78292928Sdim Hash hf = Hash(), BinaryPredicate pred = BinaryPredicate()); 79292928Sdim 80292928Sdim } // namespace fundamentals_v1 81292928Sdim } // namespace experimental 82292928Sdim 83292928Sdim template<class R, class... ArgTypes, class Alloc> 84292928Sdim struct uses_allocator<experimental::function<R(ArgTypes...)>, Alloc>; 85292928Sdim 86292928Sdim} // namespace std 87292928Sdim 88292928Sdim*/ 89292928Sdim 90292928Sdim#include <experimental/__config> 91292928Sdim#include <functional> 92292928Sdim 93292928Sdim#include <algorithm> 94292928Sdim#include <type_traits> 95292928Sdim#include <vector> 96292928Sdim#include <array> 97292928Sdim#include <unordered_map> 98292928Sdim 99292928Sdim#include <__undef_min_max> 100292928Sdim 101292928Sdim#include <__debug> 102292928Sdim 103292928Sdim#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 104292928Sdim#pragma GCC system_header 105292928Sdim#endif 106292928Sdim 107292928Sdim_LIBCPP_BEGIN_NAMESPACE_LFTS 108292928Sdim 109292928Sdim#if _LIBCPP_STD_VER > 11 110292928Sdim// default searcher 111292928Sdimtemplate<class _ForwardIterator, class _BinaryPredicate = equal_to<>> 112292928Sdim_LIBCPP_TYPE_VIS 113292928Sdimclass default_searcher { 114292928Sdimpublic: 115292928Sdim _LIBCPP_INLINE_VISIBILITY 116292928Sdim default_searcher(_ForwardIterator __f, _ForwardIterator __l, 117292928Sdim _BinaryPredicate __p = _BinaryPredicate()) 118292928Sdim : __first_(__f), __last_(__l), __pred_(__p) {} 119292928Sdim 120292928Sdim template <typename _ForwardIterator2> 121292928Sdim _LIBCPP_INLINE_VISIBILITY 122292928Sdim _ForwardIterator2 operator () (_ForwardIterator2 __f, _ForwardIterator2 __l) const 123292928Sdim { 124292928Sdim return _VSTD::search(__f, __l, __first_, __last_, __pred_); 125292928Sdim } 126292928Sdim 127292928Sdimprivate: 128292928Sdim _ForwardIterator __first_; 129292928Sdim _ForwardIterator __last_; 130292928Sdim _BinaryPredicate __pred_; 131292928Sdim }; 132292928Sdim 133292928Sdimtemplate<class _ForwardIterator, class _BinaryPredicate = equal_to<>> 134292928Sdim_LIBCPP_INLINE_VISIBILITY 135292928Sdimdefault_searcher<_ForwardIterator, _BinaryPredicate> 136292928Sdimmake_default_searcher( _ForwardIterator __f, _ForwardIterator __l, _BinaryPredicate __p = _BinaryPredicate ()) 137292928Sdim{ 138292928Sdim return default_searcher<_ForwardIterator, _BinaryPredicate>(__f, __l, __p); 139292928Sdim} 140292928Sdim 141292928Sdimtemplate<class _Key, class _Value, class _Hash, class _BinaryPredicate, bool /*useArray*/> class _BMSkipTable; 142292928Sdim 143292928Sdim// General case for BM data searching; use a map 144292928Sdimtemplate<class _Key, typename _Value, class _Hash, class _BinaryPredicate> 145292928Sdimclass _BMSkipTable<_Key, _Value, _Hash, _BinaryPredicate, false> { 146292928Sdimpublic: // TODO private: 147292928Sdim typedef _Value value_type; 148292928Sdim typedef _Key key_type; 149292928Sdim 150292928Sdim const _Value __default_value_; 151292928Sdim std::unordered_map<_Key, _Value, _Hash, _BinaryPredicate> __table; 152292928Sdim 153292928Sdimpublic: 154292928Sdim _LIBCPP_INLINE_VISIBILITY 155292928Sdim _BMSkipTable(std::size_t __sz, _Value __default, _Hash __hf, _BinaryPredicate __pred) 156292928Sdim : __default_value_(__default), __table(__sz, __hf, __pred) {} 157292928Sdim 158292928Sdim _LIBCPP_INLINE_VISIBILITY 159292928Sdim void insert(const key_type &__key, value_type __val) 160292928Sdim { 161292928Sdim __table [__key] = __val; // Would skip_.insert (val) be better here? 162292928Sdim } 163292928Sdim 164292928Sdim _LIBCPP_INLINE_VISIBILITY 165292928Sdim value_type operator [](const key_type & __key) const 166292928Sdim { 167292928Sdim auto __it = __table.find (__key); 168292928Sdim return __it == __table.end() ? __default_value_ : __it->second; 169292928Sdim } 170292928Sdim}; 171292928Sdim 172292928Sdim 173292928Sdim// Special case small numeric values; use an array 174292928Sdimtemplate<class _Key, typename _Value, class _Hash, class _BinaryPredicate> 175292928Sdimclass _BMSkipTable<_Key, _Value, _Hash, _BinaryPredicate, true> { 176292928Sdimprivate: 177292928Sdim typedef _Value value_type; 178292928Sdim typedef _Key key_type; 179292928Sdim 180292928Sdim typedef typename std::make_unsigned<key_type>::type unsigned_key_type; 181292928Sdim typedef std::array<value_type, _VSTD::numeric_limits<unsigned_key_type>::max()> skip_map; 182292928Sdim skip_map __table; 183292928Sdim 184292928Sdimpublic: 185292928Sdim _LIBCPP_INLINE_VISIBILITY 186292928Sdim _BMSkipTable(std::size_t /*__sz*/, _Value __default, _Hash /*__hf*/, _BinaryPredicate /*__pred*/) 187292928Sdim { 188292928Sdim std::fill_n(__table.begin(), __table.size(), __default); 189292928Sdim } 190292928Sdim 191292928Sdim _LIBCPP_INLINE_VISIBILITY 192292928Sdim void insert(key_type __key, value_type __val) 193292928Sdim { 194292928Sdim __table[static_cast<unsigned_key_type>(__key)] = __val; 195292928Sdim } 196292928Sdim 197292928Sdim _LIBCPP_INLINE_VISIBILITY 198292928Sdim value_type operator [](key_type __key) const 199292928Sdim { 200292928Sdim return __table[static_cast<unsigned_key_type>(__key)]; 201292928Sdim } 202292928Sdim}; 203292928Sdim 204292928Sdim 205292928Sdimtemplate <class _RandomAccessIterator1, 206292928Sdim class _Hash = hash<typename iterator_traits<_RandomAccessIterator1>::value_type>, 207292928Sdim class _BinaryPredicate = equal_to<>> 208292928Sdim_LIBCPP_TYPE_VIS 209292928Sdimclass boyer_moore_searcher { 210292928Sdimprivate: 211292928Sdim typedef typename std::iterator_traits<_RandomAccessIterator1>::difference_type difference_type; 212292928Sdim typedef typename std::iterator_traits<_RandomAccessIterator1>::value_type value_type; 213292928Sdim typedef _BMSkipTable<value_type, difference_type, _Hash, _BinaryPredicate, 214292928Sdim _VSTD::is_integral<value_type>::value && // what about enums? 215292928Sdim sizeof(value_type) == 1 && 216292928Sdim is_same<_Hash, hash<value_type>>::value && 217292928Sdim is_same<_BinaryPredicate, equal_to<>>::value 218292928Sdim > skip_table_type; 219292928Sdim 220292928Sdimpublic: 221292928Sdim boyer_moore_searcher(_RandomAccessIterator1 __f, _RandomAccessIterator1 __l, 222292928Sdim _Hash __hf = _Hash(), _BinaryPredicate __pred = _BinaryPredicate()) 223292928Sdim : __first_(__f), __last_(__l), __pred_(__pred), 224292928Sdim __pattern_length_(_VSTD::distance(__first_, __last_)), 225292928Sdim __skip_{make_shared<skip_table_type>(__pattern_length_, -1, __hf, __pred_)}, 226292928Sdim __suffix_{make_shared<vector<difference_type>>(__pattern_length_ + 1)} 227292928Sdim { 228292928Sdim // build the skip table 229292928Sdim for ( difference_type __i = 0; __f != __l; ++__f, (void) ++__i ) 230292928Sdim __skip_->insert(*__f, __i); 231292928Sdim 232292928Sdim this->__build_suffix_table ( __first_, __last_, __pred_ ); 233292928Sdim } 234292928Sdim 235292928Sdim template <typename _RandomAccessIterator2> 236292928Sdim _RandomAccessIterator2 237292928Sdim operator ()(_RandomAccessIterator2 __f, _RandomAccessIterator2 __l) const 238292928Sdim { 239292928Sdim static_assert ( std::is_same< 240292928Sdim typename std::decay<typename std::iterator_traits<_RandomAccessIterator1>::value_type>::type, 241292928Sdim typename std::decay<typename std::iterator_traits<_RandomAccessIterator2>::value_type>::type 242292928Sdim >::value, 243292928Sdim "Corpus and Pattern iterators must point to the same type" ); 244292928Sdim 245292928Sdim if (__f == __l ) return __l; // empty corpus 246292928Sdim if (__first_ == __last_) return __f; // empty pattern 247292928Sdim 248292928Sdim // If the pattern is larger than the corpus, we can't find it! 249292928Sdim if ( __pattern_length_ > _VSTD::distance (__f, __l)) 250292928Sdim return __l; 251292928Sdim 252292928Sdim // Do the search 253292928Sdim return this->__search(__f, __l); 254292928Sdim } 255292928Sdim 256292928Sdimpublic: // TODO private: 257292928Sdim _RandomAccessIterator1 __first_; 258292928Sdim _RandomAccessIterator1 __last_; 259292928Sdim _BinaryPredicate __pred_; 260292928Sdim difference_type __pattern_length_; 261292928Sdim shared_ptr<skip_table_type> __skip_; 262292928Sdim shared_ptr<vector<difference_type>> __suffix_; 263292928Sdim 264292928Sdim template <typename _RandomAccessIterator2> 265292928Sdim _RandomAccessIterator2 __search(_RandomAccessIterator2 __f, _RandomAccessIterator2 __l) const 266292928Sdim { 267292928Sdim _RandomAccessIterator2 __cur = __f; 268292928Sdim const _RandomAccessIterator2 __last = __l - __pattern_length_; 269292928Sdim const skip_table_type & __skip = *__skip_.get(); 270292928Sdim const vector<difference_type> & __suffix = *__suffix_.get(); 271292928Sdim 272292928Sdim while (__cur <= __last) 273292928Sdim { 274292928Sdim 275292928Sdim // Do we match right where we are? 276292928Sdim difference_type __j = __pattern_length_; 277292928Sdim while (__pred_(__first_ [__j-1], __cur [__j-1])) { 278292928Sdim __j--; 279292928Sdim // We matched - we're done! 280292928Sdim if ( __j == 0 ) 281292928Sdim return __cur; 282292928Sdim } 283292928Sdim 284292928Sdim // Since we didn't match, figure out how far to skip forward 285292928Sdim difference_type __k = __skip[__cur [ __j - 1 ]]; 286292928Sdim difference_type __m = __j - __k - 1; 287292928Sdim if (__k < __j && __m > __suffix[ __j ]) 288292928Sdim __cur += __m; 289292928Sdim else 290292928Sdim __cur += __suffix[ __j ]; 291292928Sdim } 292292928Sdim 293292928Sdim return __l; // We didn't find anything 294292928Sdim } 295292928Sdim 296292928Sdim 297292928Sdim template<typename _Iterator, typename _Container> 298292928Sdim void __compute_bm_prefix ( _Iterator __f, _Iterator __l, _BinaryPredicate __pred, _Container &__prefix ) 299292928Sdim { 300292928Sdim const std::size_t __count = _VSTD::distance(__f, __l); 301292928Sdim 302292928Sdim __prefix[0] = 0; 303292928Sdim std::size_t __k = 0; 304292928Sdim for ( std::size_t __i = 1; __i < __count; ++__i ) 305292928Sdim { 306292928Sdim while ( __k > 0 && !__pred ( __f[__k], __f[__i] )) 307292928Sdim __k = __prefix [ __k - 1 ]; 308292928Sdim 309292928Sdim if ( __pred ( __f[__k], __f[__i] )) 310292928Sdim __k++; 311292928Sdim __prefix [ __i ] = __k; 312292928Sdim } 313292928Sdim } 314292928Sdim 315292928Sdim void __build_suffix_table(_RandomAccessIterator1 __f, _RandomAccessIterator1 __l, 316292928Sdim _BinaryPredicate __pred) 317292928Sdim { 318292928Sdim const std::size_t __count = _VSTD::distance(__f, __l); 319292928Sdim vector<difference_type> & __suffix = *__suffix_.get(); 320292928Sdim if (__count > 0) 321292928Sdim { 322292928Sdim _VSTD::vector<value_type> __scratch(__count); 323292928Sdim 324292928Sdim __compute_bm_prefix(__f, __l, __pred, __scratch); 325292928Sdim for ( std::size_t __i = 0; __i <= __count; __i++ ) 326292928Sdim __suffix[__i] = __count - __scratch[__count-1]; 327292928Sdim 328292928Sdim typedef _VSTD::reverse_iterator<_RandomAccessIterator1> _RevIter; 329292928Sdim __compute_bm_prefix(_RevIter(__l), _RevIter(__f), __pred, __scratch); 330292928Sdim 331292928Sdim for ( std::size_t __i = 0; __i < __count; __i++ ) 332292928Sdim { 333292928Sdim const std::size_t __j = __count - __scratch[__i]; 334292928Sdim const difference_type __k = __i - __scratch[__i] + 1; 335292928Sdim 336292928Sdim if (__suffix[__j] > __k) 337292928Sdim __suffix[__j] = __k; 338292928Sdim } 339292928Sdim } 340292928Sdim } 341292928Sdim 342292928Sdim}; 343292928Sdim 344292928Sdimtemplate<class _RandomAccessIterator, 345292928Sdim class _Hash = hash<typename iterator_traits<_RandomAccessIterator>::value_type>, 346292928Sdim class _BinaryPredicate = equal_to<>> 347292928Sdim_LIBCPP_INLINE_VISIBILITY 348292928Sdimboyer_moore_searcher<_RandomAccessIterator, _Hash, _BinaryPredicate> 349292928Sdimmake_boyer_moore_searcher( _RandomAccessIterator __f, _RandomAccessIterator __l, 350292928Sdim _Hash __hf = _Hash(), _BinaryPredicate __p = _BinaryPredicate ()) 351292928Sdim{ 352292928Sdim return boyer_moore_searcher<_RandomAccessIterator, _Hash, _BinaryPredicate>(__f, __l, __hf, __p); 353292928Sdim} 354292928Sdim 355292928Sdim// boyer-moore-horspool 356292928Sdimtemplate <class _RandomAccessIterator1, 357292928Sdim class _Hash = hash<typename iterator_traits<_RandomAccessIterator1>::value_type>, 358292928Sdim class _BinaryPredicate = equal_to<>> 359292928Sdim_LIBCPP_TYPE_VIS 360292928Sdimclass boyer_moore_horspool_searcher { 361292928Sdimprivate: 362292928Sdim typedef typename std::iterator_traits<_RandomAccessIterator1>::difference_type difference_type; 363292928Sdim typedef typename std::iterator_traits<_RandomAccessIterator1>::value_type value_type; 364292928Sdim typedef _BMSkipTable<value_type, difference_type, _Hash, _BinaryPredicate, 365292928Sdim _VSTD::is_integral<value_type>::value && // what about enums? 366292928Sdim sizeof(value_type) == 1 && 367292928Sdim is_same<_Hash, hash<value_type>>::value && 368292928Sdim is_same<_BinaryPredicate, equal_to<>>::value 369292928Sdim > skip_table_type; 370292928Sdim 371292928Sdimpublic: 372292928Sdim boyer_moore_horspool_searcher(_RandomAccessIterator1 __f, _RandomAccessIterator1 __l, 373292928Sdim _Hash __hf = _Hash(), _BinaryPredicate __pred = _BinaryPredicate()) 374292928Sdim : __first_(__f), __last_(__l), __pred_(__pred), 375292928Sdim __pattern_length_(_VSTD::distance(__first_, __last_)), 376292928Sdim __skip_{_VSTD::make_shared<skip_table_type>(__pattern_length_, __pattern_length_, __hf, __pred_)} 377292928Sdim { 378292928Sdim // build the skip table 379292928Sdim if ( __f != __l ) 380292928Sdim { 381292928Sdim __l = __l - 1; 382292928Sdim for ( difference_type __i = 0; __f != __l; ++__f, (void) ++__i ) 383292928Sdim __skip_->insert(*__f, __pattern_length_ - 1 - __i); 384292928Sdim } 385292928Sdim } 386292928Sdim 387292928Sdim template <typename _RandomAccessIterator2> 388292928Sdim _RandomAccessIterator2 389292928Sdim operator ()(_RandomAccessIterator2 __f, _RandomAccessIterator2 __l) const 390292928Sdim { 391292928Sdim static_assert ( std::is_same< 392292928Sdim typename std::decay<typename std::iterator_traits<_RandomAccessIterator1>::value_type>::type, 393292928Sdim typename std::decay<typename std::iterator_traits<_RandomAccessIterator2>::value_type>::type 394292928Sdim >::value, 395292928Sdim "Corpus and Pattern iterators must point to the same type" ); 396292928Sdim 397292928Sdim if (__f == __l ) return __l; // empty corpus 398292928Sdim if (__first_ == __last_) return __f; // empty pattern 399292928Sdim 400292928Sdim // If the pattern is larger than the corpus, we can't find it! 401292928Sdim if ( __pattern_length_ > _VSTD::distance (__f, __l)) 402292928Sdim return __l; 403292928Sdim 404292928Sdim // Do the search 405292928Sdim return this->__search(__f, __l); 406292928Sdim } 407292928Sdim 408292928Sdimprivate: 409292928Sdim _RandomAccessIterator1 __first_; 410292928Sdim _RandomAccessIterator1 __last_; 411292928Sdim _BinaryPredicate __pred_; 412292928Sdim difference_type __pattern_length_; 413292928Sdim shared_ptr<skip_table_type> __skip_; 414292928Sdim 415292928Sdim template <typename _RandomAccessIterator2> 416292928Sdim _RandomAccessIterator2 __search ( _RandomAccessIterator2 __f, _RandomAccessIterator2 __l ) const { 417292928Sdim _RandomAccessIterator2 __cur = __f; 418292928Sdim const _RandomAccessIterator2 __last = __l - __pattern_length_; 419292928Sdim const skip_table_type & __skip = *__skip_.get(); 420292928Sdim 421292928Sdim while (__cur <= __last) 422292928Sdim { 423292928Sdim // Do we match right where we are? 424292928Sdim difference_type __j = __pattern_length_; 425292928Sdim while (__pred_(__first_[__j-1], __cur[__j-1])) 426292928Sdim { 427292928Sdim __j--; 428292928Sdim // We matched - we're done! 429292928Sdim if ( __j == 0 ) 430292928Sdim return __cur; 431292928Sdim } 432292928Sdim __cur += __skip[__cur[__pattern_length_-1]]; 433292928Sdim } 434292928Sdim 435292928Sdim return __l; 436292928Sdim } 437292928Sdim}; 438292928Sdim 439292928Sdimtemplate<class _RandomAccessIterator, 440292928Sdim class _Hash = hash<typename iterator_traits<_RandomAccessIterator>::value_type>, 441292928Sdim class _BinaryPredicate = equal_to<>> 442292928Sdim_LIBCPP_INLINE_VISIBILITY 443292928Sdimboyer_moore_horspool_searcher<_RandomAccessIterator, _Hash, _BinaryPredicate> 444292928Sdimmake_boyer_moore_horspool_searcher( _RandomAccessIterator __f, _RandomAccessIterator __l, 445292928Sdim _Hash __hf = _Hash(), _BinaryPredicate __p = _BinaryPredicate ()) 446292928Sdim{ 447292928Sdim return boyer_moore_horspool_searcher<_RandomAccessIterator, _Hash, _BinaryPredicate>(__f, __l, __hf, __p); 448292928Sdim} 449292928Sdim 450292928Sdim#endif // _LIBCPP_STD_VER > 11 451292928Sdim 452292928Sdim_LIBCPP_END_NAMESPACE_LFTS 453292928Sdim 454292928Sdim#endif /* _LIBCPP_EXPERIMENTAL_FUNCTIONAL */ 455