// // Copyright (c) ZeroC, Inc. All rights reserved. // #ifndef FILTER_I_H #define FILTER_I_H #include #include #include #include #include #include namespace Glacier2 { template class FilterT : public P { public: FilterT(const std::vector&); // // Slice to C++ mapping. // virtual void add(std::vector, const Ice::Current&) override; virtual void remove(std::vector, const Ice::Current&) override; virtual std::vector get(const Ice::Current&) override; // // Internal functions. // bool match(const T& candidate) const { std::lock_guard lg(_mutex); // // Empty vectors mean no filtering, so all matches will succeed. // if(_items.size() == 0) { return true; } return binary_search(_items.begin(), _items.end(), candidate); } bool empty() const { std::lock_guard lg(_mutex); return _items.size() == 0; } private: std::vector _items; mutable std::mutex _mutex; }; template FilterT::FilterT(const std::vector& accept): _items(accept) { sort(_items.begin(), _items.end()); _items.erase(unique(_items.begin(), _items.end()), _items.end()); } template void FilterT::add(std::vector additions, const Ice::Current&) { // // Sort the filter elements first, erasing duplicates. Then we can // simply use the STL merge algorithm to add to our list of filters. // std::vector newItems(additions); sort(newItems.begin(), newItems.end()); newItems.erase(unique(newItems.begin(), newItems.end()), newItems.end()); std::lock_guard lg(_mutex); std::vector merged(_items.size() + newItems.size()); merge(newItems.begin(), newItems.end(), _items.begin(), _items.end(), merged.begin()); merged.erase(unique(merged.begin(), merged.end()), merged.end()); swap(_items, merged); } template void FilterT::remove(std::vector deletions, const Ice::Current&) { // // Our removal algorithm depends on the filter elements to be // removed to be sorted in the same order as our current elements. // std::vector toRemove(deletions); sort(toRemove.begin(), toRemove.end()); toRemove.erase(unique(toRemove.begin(), toRemove.end()), toRemove.end()); std::lock_guard lg(_mutex); // // Our vectors are both sorted, so if we keep track of our first // match between the current set and the set of items to be removed, // we do not need to traverse the whole of the current set each // time. We also use a list of deletions instead of erasing things // itemwise. // typename std::vector::const_iterator r = toRemove.begin(); typename std::vector::iterator mark = _items.begin(); std::list::iterator> deleteList; while(r != toRemove.end()) { typename std::vector::iterator i = mark; while(i != _items.end() && r != toRemove.end()) { if(*r == *i) { // // We want this list to be in LIFO order because we are // going to erase things from the tail forward. // deleteList.push_front(i); ++i; ++r; mark = i; } else { ++i; } } if(r == toRemove.end()) { break; } ++r; } for(const auto& item : deleteList) { _items.erase(item); } } template std::vector FilterT::get(const Ice::Current&) { std::lock_guard lg(_mutex); return _items; } using IdentitySetI = FilterT; using StringSetI = FilterT; } #endif