// ***************************************************************************** // * This file is part of the FreeFileSync project. It is distributed under * // * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 * // * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved * // ***************************************************************************** #ifndef STL_TOOLS_H_84567184321434 #define STL_TOOLS_H_84567184321434 #include #include #include #include #include #include #include "string_traits.h" #include "build_info.h" //enhancements for namespace zen { //erase selected elements from any container: template void erase_if(std::vector& v, Predicate p); template void erase_if(std::set& s, Predicate p); template void erase_if(std::map& m, Predicate p); //append STL containers template void append(std::vector& v, const C& c); template void append(std::set& s, const C& c); template void append(std::map& m, const C& c); template void removeDuplicates(std::vector& v); template void removeDuplicates(std::vector& v, CompLess less); //binary search returning an iterator template Iterator binary_search(Iterator first, Iterator last, const T& value, CompLess less); template BidirectionalIterator find_last(BidirectionalIterator first, BidirectionalIterator last, const T& value); //replacement for std::find_end taking advantage of bidirectional iterators (and giving the algorithm a reasonable name) template BidirectionalIterator1 search_last(BidirectionalIterator1 first1, BidirectionalIterator1 last1, BidirectionalIterator2 first2, BidirectionalIterator2 last2); template Num hashBytes (ByteIterator first, ByteIterator last); template Num hashBytesAppend(Num hashVal, ByteIterator first, ByteIterator last); //support for custom string classes in std::unordered_set/map struct StringHash { template size_t operator()(const String& str) const { const auto* strFirst = strBegin(str); return hashBytes(reinterpret_cast(strFirst), reinterpret_cast(strFirst + strLength(str))); } }; //why, oh wy is there no std::optional::get()??? template inline T* get( std::optional& opt) { return opt ? &*opt : nullptr; } template inline const T* get(const std::optional& opt) { return opt ? &*opt : nullptr; } //######################## implementation ######################## template inline void erase_if(std::vector& v, Predicate p) { v.erase(std::remove_if(v.begin(), v.end(), p), v.end()); } namespace impl { template inline void set_or_map_erase_if(S& s, Predicate p) { for (auto it = s.begin(); it != s.end();) if (p(*it)) s.erase(it++); else ++it; } } template inline void erase_if(std::set& s, Predicate p) { impl::set_or_map_erase_if(s, p); } //don't make this any more generic! e.g. must not compile for std::vector!!! template inline void erase_if(std::map& m, Predicate p) { impl::set_or_map_erase_if(m, p); } template inline void append(std::vector& v, const C& c) { v.insert(v.end(), c.begin(), c.end()); } template inline void append(std::set& s, const C& c) { s.insert(c.begin(), c.end()); } template inline void append(std::map& m, const C& c) { m.insert(c.begin(), c.end()); } template inline void removeDuplicates(std::vector& v, CompLess less, CompEqual eq) { std::sort(v.begin(), v.end(), less); v.erase(std::unique(v.begin(), v.end(), eq), v.end()); } template inline void removeDuplicates(std::vector& v, CompLess less) { removeDuplicates(v, less, [&](const auto& lhs, const auto& rhs) { return !less(lhs, rhs) && !less(rhs, lhs); }); } template inline void removeDuplicates(std::vector& v) { removeDuplicates(v, std::less(), std::equal_to()); } template inline Iterator binary_search(Iterator first, Iterator last, const T& value, CompLess less) { static_assert(std::is_same_v::iterator_category, std::random_access_iterator_tag>); first = std::lower_bound(first, last, value, less); if (first != last && !less(value, *first)) return first; else return last; } template inline BidirectionalIterator find_last(const BidirectionalIterator first, const BidirectionalIterator last, const T& value) { for (BidirectionalIterator it = last; it != first;) //reverse iteration: 1. check 2. decrement 3. evaluate { --it; // if (*it == value) return it; } return last; } template inline BidirectionalIterator1 search_last(const BidirectionalIterator1 first1, BidirectionalIterator1 last1, const BidirectionalIterator2 first2, const BidirectionalIterator2 last2) { const BidirectionalIterator1 itNotFound = last1; //reverse iteration: 1. check 2. decrement 3. evaluate for (;;) { BidirectionalIterator1 it1 = last1; BidirectionalIterator2 it2 = last2; for (;;) { if (it2 == first2) return it1; if (it1 == first1) return itNotFound; --it1; --it2; if (*it1 != *it2) break; } --last1; } } //FNV-1a: http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function template inline Num hashBytes(ByteIterator first, ByteIterator last) { static_assert(IsInteger::value); static_assert(sizeof(Num) == 4 || sizeof(Num) == 8); //macOS: size_t is "unsigned long" constexpr Num base = sizeof(Num) == 4 ? 2166136261U : 14695981039346656037ULL; return hashBytesAppend(base, first, last); } template inline Num hashBytesAppend(Num hashVal, ByteIterator first, ByteIterator last) { static_assert(sizeof(typename std::iterator_traits::value_type) == 1); constexpr Num prime = sizeof(Num) == 4 ? 16777619U : 1099511628211ULL; for (; first != last; ++first) { hashVal ^= static_cast(*first); hashVal *= prime; } return hashVal; } } #endif //STL_TOOLS_H_84567184321434