// ***************************************************************************** // * This file is part of the FreeFileSync project. It is distributed under * // * GNU General Public License: http://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 "type_tools.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 V& map_add_or_update(M& map, const K& key, const V& value); //efficient add or update without "default-constructible" requirement (Effective STL, item 24) template void removeDuplicates(std::vector& v); //binary search returning an iterator template ForwardIterator binary_search(ForwardIterator first, ForwardIterator 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 bool equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2); template size_t hashBytes (ByteIterator first, ByteIterator last); template size_t hashBytesAppend(size_t 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))); } }; //######################## 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 V& map_add_or_update(M& map, const K& key, const V& value) //efficient add or update without "default-constructible" requirement (Effective STL, item 24) { auto it = map.lower_bound(key); if (it != map.end() && !(map.key_comp()(key, it->first))) { it->second = value; return it->second; } else return map.insert(it, typename M::value_type(key, value))->second; } template inline void removeDuplicates(std::vector& v) { std::sort(v.begin(), v.end()); v.erase(std::unique(v.begin(), v.end()), v.end()); } template inline ForwardIterator binary_search(ForwardIterator first, ForwardIterator last, const T& value, CompLess less) { 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; } } template inline bool equal(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2) { return last1 - first1 == last2 - first2 && std::equal(first1, last1, first2); } template inline size_t hashBytes(ByteIterator first, ByteIterator last) { //FNV-1a: http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function #ifdef ZEN_BUILD_32BIT const size_t basis = 2166136261U; #elif defined ZEN_BUILD_64BIT const size_t basis = 14695981039346656037ULL; #endif return hashBytesAppend(basis, first, last); } template inline size_t hashBytesAppend(size_t hashVal, ByteIterator first, ByteIterator last) { #ifdef ZEN_BUILD_32BIT const size_t prime = 16777619U; #elif defined ZEN_BUILD_64BIT const size_t prime = 1099511628211ULL; #endif static_assert(sizeof(typename std::iterator_traits::value_type) == 1, ""); for (; first != last; ++first) { hashVal ^= static_cast(*first); hashVal *= prime; } return hashVal; } } #endif //STL_TOOLS_H_84567184321434