// Copyright 2020 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef TOOLS_GN_VECTOR_UTILS_H_ #define TOOLS_GN_VECTOR_UTILS_H_ #include #include #include // A VectorSetSorter is a convenience class used to efficiently sort and // de-duplicate one or more sets of items of type T, then iterate over the // result, or get it as a simple vector. Usage is the following: // // For performance reasons, this implementation only stores pointers to the // input items in order to minimize memory usage. Callers should ensure the // items added to this sorter do not change until the instance is destroyed. // // 1) Create instance, passing an optional initial capacity. // // 2) Add items using one of the Add() methods, as many times as // necessary. Note that this records only pointers to said items // so their content should not change until the instance is destroyed. // // 3) Call IteratorOver() to iterate over all sorted and de-duplicated // items. // // 4) Alternatively, call AsVector() to return a new vector that contains // copies of the original sorted / deduplicated items. // template class VectorSetSorter { public: // Constructor. |initial_capacity| might be provided to minimize the number // of allocations performed by this instance, if the maximum number of // input items is known in advance. VectorSetSorter(size_t initial_capacity = 0) { ptrs_.reserve(initial_capacity); } // Add one single item to the sorter. void Add(const T& item) { ptrs_.push_back(&item); sorted_ = false; } // Add one range of items to the sorter. void Add(typename std::vector::const_iterator begin, typename std::vector::const_iterator end) { for (; begin != end; ++begin) ptrs_.push_back(&(*begin)); sorted_ = false; } // Add one range of items to the sorter. void Add(const T* start, const T* end) { for (; start != end; ++start) ptrs_.push_back(start); sorted_ = false; } // Iterate over all sorted items, removing duplicates from the loop. // |item_callback| is a callable that will be invoked for each item in the // result. template void IterateOver(ITEM_CALLBACK item_callback) { if (!sorted_) { Sort(); } const T* prev_item = nullptr; for (const T* item : ptrs_) { if (!prev_item || *prev_item != *item) { item_callback(*item); prev_item = item; } } } // Return the sorted and de-duplicated resulting set as a vector of items. // Note that this copies the input items. std::vector AsVector() { std::vector result; result.reserve(ptrs_.size()); IterateOver([&result](const T& item) { result.push_back(item); }); return result; } private: // Sort all items previously added to this instance. // Must be called after adding all desired items, and before // calling IterateOver() or AsVector(). void Sort() { std::sort(ptrs_.begin(), ptrs_.end(), [](const T* a, const T* b) { return *a < *b; }); sorted_ = true; } std::vector ptrs_; bool sorted_ = false; }; #endif // TOOLS_GN_VECTOR_UTILS_H_