/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #pragma once #include "cmConfigure.h" // IWYU pragma: keep #include #include #include #include #include #include #include #include #include #include #include #include #include "cmValue.h" template class BT; /** * CMake lists management * A CMake list is a string where list elements are separated by the ';' * character. * * For all operations, input arguments (single value like cm::string_view or * multiple values specified through pair of iterators) are, by default, * expanded. The expansion can be controlled by the cmList::ExpandElements * option. * * There ate some exceptions to this rule: * * When the input argument is a cmList instance, the value is not expanded. * * The following methods do not expand their argument: cmList::push_back, * cmList::emplace and cmList::emplace_back. */ class cmList { public: using container_type = std::vector; using value_type = container_type::value_type; using allocator_type = container_type::allocator_type; using index_type = std::ptrdiff_t; using size_type = container_type::size_type; using difference_type = container_type::difference_type; using reference = container_type::reference; using const_reference = container_type::const_reference; using iterator = container_type::iterator; using const_iterator = container_type::const_iterator; using reverse_iterator = container_type::reverse_iterator; using const_reverse_iterator = container_type::const_reverse_iterator; static const size_type npos = static_cast(-1); static cm::string_view element_separator; enum class EmptyElements { No, Yes, }; enum class ExpandElements { No, Yes, }; cmList() = default; cmList(const cmList&) = default; cmList(cmList&&) = default; cmList(cm::string_view value, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { this->assign(value, expandElements, emptyElements); } cmList(cm::string_view value, EmptyElements emptyElements) : cmList(value, ExpandElements::Yes, emptyElements) { } cmList(std::string const& value, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { this->assign(value, expandElements, emptyElements); } cmList(std::string const& value, EmptyElements emptyElements) : cmList(value, ExpandElements::Yes, emptyElements) { } cmList(cmValue list, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { if (list) { this->assign(*list, expandElements, emptyElements); } } cmList(cmValue list, EmptyElements emptyElements) : cmList(list, ExpandElements::Yes, emptyElements) { } template cmList(InputIterator first, InputIterator last, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { this->assign(first, last, expandElements, emptyElements); } template cmList(InputIterator first, InputIterator last, EmptyElements emptyElements) : cmList(first, last, ExpandElements::Yes, emptyElements) { } cmList(const container_type& init, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) : cmList(init.begin(), init.end(), expandElements, emptyElements) { } cmList(const container_type& init, EmptyElements emptyElements) : cmList(init, ExpandElements::Yes, emptyElements) { } cmList(container_type&& init, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) : cmList(std::make_move_iterator(init.begin()), std::make_move_iterator(init.end()), expandElements, emptyElements) { init.clear(); } cmList(container_type&& init, EmptyElements emptyElements) : cmList(std::move(init), ExpandElements::Yes, emptyElements) { } cmList(std::initializer_list init) { this->assign(init); } ~cmList() = default; cmList& operator=(const cmList&) = default; cmList& operator=(cmList&&) = default; cmList& operator=(cm::string_view value) { this->assign(value); return *this; } cmList& operator=(std::string const& value) { this->assign(value); return *this; } cmList& operator=(cmValue value) { if (value) { this->operator=(*value); } else { this->clear(); } return *this; } cmList& operator=(const container_type& init) { this->assign(init); return *this; } cmList& operator=(container_type&& init) { this->assign(std::move(init)); return *this; } cmList& operator=(std::initializer_list init) { this->assign(init); return *this; } void assign(cm::string_view value, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { this->clear(); this->append(value, expandElements, emptyElements); } void assign(cm::string_view value, EmptyElements emptyElements) { this->assign(value, ExpandElements::Yes, emptyElements); } void assign(std::string const& value, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { this->clear(); this->append(value, expandElements, emptyElements); } void assign(std::string const& value, EmptyElements emptyElements) { this->assign(value, ExpandElements::Yes, emptyElements); } void assign(cmValue value, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { if (value) { this->assign(*value, expandElements, emptyElements); } else { this->clear(); } } void assign(cmValue value, EmptyElements emptyElements) { this->assign(value, ExpandElements::Yes, emptyElements); } template void assign(InputIterator first, InputIterator last, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { this->clear(); this->append(first, last, expandElements, emptyElements); } template void assign(InputIterator first, InputIterator last, EmptyElements emptyElements) { this->assign(first, last, ExpandElements::Yes, emptyElements); } void assign(const cmList& init, ExpandElements expandElements = ExpandElements::No, EmptyElements emptyElements = EmptyElements::No) { this->assign(init.begin(), init.end(), expandElements, emptyElements); } void assign(const cmList& init, EmptyElements emptyElements) { this->assign(init, ExpandElements::No, emptyElements); } void assign(cmList&& init, ExpandElements expandElements = ExpandElements::No, EmptyElements emptyElements = EmptyElements::No) { this->assign(std::make_move_iterator(init.begin()), std::make_move_iterator(init.end()), expandElements, emptyElements); init.clear(); } void assign(cmList&& init, EmptyElements emptyElements) { this->assign(std::move(init), ExpandElements::No, emptyElements); } void assign(const container_type& init, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { this->assign(init.begin(), init.end(), expandElements, emptyElements); } void assign(const container_type& init, EmptyElements emptyElements) { this->assign(init, ExpandElements::Yes, emptyElements); } void assign(container_type&& init, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { this->assign(std::make_move_iterator(init.begin()), std::make_move_iterator(init.end()), expandElements, emptyElements); init.clear(); } void assign(container_type&& init, EmptyElements emptyElements) { this->assign(std::move(init), ExpandElements::Yes, emptyElements); } void assign(std::initializer_list init) { this->assign(init.begin(), init.end()); } // Conversions std::string to_string() const { return this->join(cmList::element_separator); } operator container_type&() & noexcept { return this->Values; } operator const container_type&() const& noexcept { return this->Values; } operator container_type&&() && noexcept { return std::move(this->Values); } // Element access reference at(size_type pos) { return this->Values.at(pos); } const_reference at(size_type pos) const { return this->Values.at(pos); } reference operator[](size_type pos) { return this->Values[pos]; } const_reference operator[](size_type pos) const { return this->Values[pos]; } reference get_item(index_type pos) { return this->Values.at(this->ComputeIndex(pos)); } const_reference get_item(index_type pos) const { return this->Values.at(this->ComputeIndex(pos)); } reference front() { return this->Values.front(); } const_reference front() const { return this->Values.front(); } reference back() { return this->Values.back(); } const_reference back() const { return this->Values.back(); } // extract sublist in range [first, last) cmList sublist(const_iterator first, const_iterator last) const { return cmList{ first, last, ExpandElements::No, EmptyElements::Yes }; } // Extract sublist in range [first, last) // Throw std::out_of_range if pos is invalid cmList sublist(size_type pos = 0, size_type length = npos) const; // Returns the list of elements // Throw std::out_of_range if any index is invalid cmList get_items(std::initializer_list indexes) const { return this->GetItems( std::vector{ indexes.begin(), indexes.end() }); } template cmList get_items(InputIterator first, InputIterator last) const { return this->GetItems(std::vector{ first, last }); } size_type find(cm::string_view value) const; size_type find(cmValue value) const { if (value) { return this->find(*value); } return npos; } container_type& data() noexcept { return this->Values; } const container_type& data() const noexcept { return this->Values; } // Iterators iterator begin() noexcept { return this->Values.begin(); } const_iterator begin() const noexcept { return this->Values.begin(); } const_iterator cbegin() const noexcept { return this->Values.cbegin(); } iterator end() noexcept { return this->Values.end(); } const_iterator end() const noexcept { return this->Values.end(); } const_iterator cend() const noexcept { return this->Values.cend(); } reverse_iterator rbegin() noexcept { return this->Values.rbegin(); } const_reverse_iterator rbegin() const noexcept { return this->Values.rbegin(); } const_reverse_iterator crbegin() const noexcept { return this->Values.crbegin(); } reverse_iterator rend() noexcept { return this->Values.rend(); } const_reverse_iterator rend() const noexcept { return this->Values.rend(); } const_reverse_iterator crend() const noexcept { return this->Values.crend(); } // Capacity bool empty() const noexcept { return this->Values.empty(); } size_type size() const noexcept { return this->Values.size(); } // Modifiers void clear() noexcept { this->Values.clear(); } iterator insert(const_iterator pos, cm::string_view value, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { return cmList::Insert(this->Values, pos, std::string(value), expandElements, emptyElements); } iterator insert(const_iterator pos, cm::string_view value, EmptyElements emptyElements) { return this->insert(pos, value, ExpandElements::Yes, emptyElements); } iterator insert(const_iterator pos, std::string const& value, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { return cmList::Insert(this->Values, pos, value, expandElements, emptyElements); } iterator insert(const_iterator pos, std::string const& value, EmptyElements emptyElements) { return this->insert(pos, value, ExpandElements::Yes, emptyElements); } iterator insert(const_iterator pos, cmValue value, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { if (value) { return this->insert(pos, *value, expandElements, emptyElements); } auto delta = std::distance(this->cbegin(), pos); return this->begin() + delta; } iterator insert(const_iterator pos, cmValue value, EmptyElements emptyElements) { return this->insert(pos, value, ExpandElements::Yes, emptyElements); } template iterator insert(const_iterator pos, InputIterator first, InputIterator last, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { return cmList::Insert(this->Values, pos, first, last, expandElements, emptyElements); } template iterator insert(const_iterator pos, InputIterator first, InputIterator last, EmptyElements emptyElements) { return this->insert(pos, first, last, ExpandElements::Yes, emptyElements); } iterator insert(const_iterator pos, const cmList& values, ExpandElements expandElements = ExpandElements::No, EmptyElements emptyElements = EmptyElements::No) { return this->insert(pos, values.begin(), values.end(), expandElements, emptyElements); } iterator insert(const_iterator pos, const cmList& values, EmptyElements emptyElements) { return this->insert(pos, values, ExpandElements::No, emptyElements); } iterator insert(const_iterator pos, cmList&& values, ExpandElements expandElements = ExpandElements::No, EmptyElements emptyElements = EmptyElements::No) { auto result = this->insert(pos, std::make_move_iterator(values.begin()), std::make_move_iterator(values.end()), expandElements, emptyElements); values.clear(); return result; } iterator insert(const_iterator pos, cmList&& values, EmptyElements emptyElements) { return this->insert(pos, std::move(values), ExpandElements::No, emptyElements); } iterator insert(const_iterator pos, const container_type& values, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { return this->insert(pos, values.begin(), values.end(), expandElements, emptyElements); } iterator insert(const_iterator pos, const container_type& values, EmptyElements emptyElements) { return this->insert(pos, values, ExpandElements::Yes, emptyElements); } iterator insert(const_iterator pos, container_type&& values, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { auto result = this->insert(pos, std::make_move_iterator(values.begin()), std::make_move_iterator(values.end()), expandElements, emptyElements); values.clear(); return result; } iterator insert(const_iterator pos, container_type&& values, EmptyElements emptyElements) { return this->insert(pos, std::move(values), ExpandElements::Yes, emptyElements); } iterator insert(const_iterator pos, std::initializer_list ilist) { return this->insert(pos, ilist.begin(), ilist.end()); } iterator append(cm::string_view value, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { return this->insert(this->cend(), value, expandElements, emptyElements); } iterator append(cm::string_view value, EmptyElements emptyElements) { return this->append(value, ExpandElements::Yes, emptyElements); } iterator append(std::string const& value, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { return this->insert(this->cend(), value, expandElements, emptyElements); } iterator append(std::string const& value, EmptyElements emptyElements) { return this->append(value, ExpandElements::Yes, emptyElements); } iterator append(cmValue value, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { if (value) { return this->append(*value, expandElements, emptyElements); } return this->end(); } iterator append(cmValue value, EmptyElements emptyElements) { return this->append(value, ExpandElements::Yes, emptyElements); } template iterator append(InputIterator first, InputIterator last, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { return this->insert(this->cend(), first, last, expandElements, emptyElements); } template iterator append(InputIterator first, InputIterator last, EmptyElements emptyElements) { return this->append(first, last, ExpandElements::Yes, emptyElements); } iterator append(const cmList& values, ExpandElements expandElements = ExpandElements::No, EmptyElements emptyElements = EmptyElements::No) { return this->append(values.begin(), values.end(), expandElements, emptyElements); } iterator append(const cmList& values, EmptyElements emptyElements) { return this->append(values, ExpandElements::No, emptyElements); } iterator append(cmList&& values, ExpandElements expandElements = ExpandElements::No, EmptyElements emptyElements = EmptyElements::No) { auto result = this->append(std::make_move_iterator(values.begin()), std::make_move_iterator(values.end()), expandElements, emptyElements); values.clear(); return result; } iterator append(cmList&& values, EmptyElements emptyElements) { return this->append(std::move(values), ExpandElements::No, emptyElements); } iterator append(const container_type& values, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { return this->append(values.begin(), values.end(), expandElements, emptyElements); } iterator append(const container_type& values, EmptyElements emptyElements) { return this->append(values, ExpandElements::Yes, emptyElements); } iterator append(container_type&& values, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { auto result = this->append(std::make_move_iterator(values.begin()), std::make_move_iterator(values.end()), expandElements, emptyElements); values.clear(); return result; } iterator append(container_type&& values, EmptyElements emptyElements) { return this->append(std::move(values), ExpandElements::Yes, emptyElements); } iterator append(std::initializer_list ilist) { return this->insert(this->cend(), ilist); } iterator prepend(cm::string_view value, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { return this->insert(this->cbegin(), value, expandElements, emptyElements); } iterator prepend(cm::string_view value, EmptyElements emptyElements) { return this->prepend(value, ExpandElements::Yes, emptyElements); } iterator prepend(std::string const& value, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { return this->insert(this->cbegin(), value, expandElements, emptyElements); } iterator prepend(std::string const& value, EmptyElements emptyElements) { return this->prepend(value, ExpandElements::Yes, emptyElements); } iterator prepend(cmValue value, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { if (value) { return this->prepend(*value, expandElements, emptyElements); } return this->begin(); } iterator prepend(cmValue value, EmptyElements emptyElements) { return this->prepend(value, ExpandElements::Yes, emptyElements); } template iterator prepend(InputIterator first, InputIterator last, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { return this->insert(this->cbegin(), first, last, expandElements, emptyElements); } template iterator prepend(InputIterator first, InputIterator last, EmptyElements emptyElements) { return this->prepend(first, last, ExpandElements::Yes, emptyElements); } iterator prepend(const cmList& values, ExpandElements expandElements = ExpandElements::No, EmptyElements emptyElements = EmptyElements::No) { return this->prepend(values.begin(), values.end(), expandElements, emptyElements); } iterator prepend(const cmList& values, EmptyElements emptyElements) { return this->prepend(values, ExpandElements::No, emptyElements); } iterator prepend(cmList&& values, ExpandElements expandElements = ExpandElements::No, EmptyElements emptyElements = EmptyElements::No) { auto result = this->prepend(std::make_move_iterator(values.begin()), std::make_move_iterator(values.end()), expandElements, emptyElements); values.clear(); return result; } iterator prepend(cmList&& values, EmptyElements emptyElements) { return this->prepend(std::move(values), ExpandElements::No, emptyElements); } iterator prepend(const container_type& values, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { return this->prepend(values.begin(), values.end(), expandElements, emptyElements); } iterator prepend(const container_type& values, EmptyElements emptyElements) { return this->prepend(values, ExpandElements::Yes, emptyElements); } iterator prepend(container_type&& values, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { auto result = this->prepend(std::make_move_iterator(values.begin()), std::make_move_iterator(values.end()), expandElements, emptyElements); values.clear(); return result; } iterator prepend(container_type&& values, EmptyElements emptyElements) { return this->prepend(std::move(values), ExpandElements::Yes, emptyElements); } iterator prepend(std::initializer_list ilist) { return this->insert(this->cbegin(), ilist); } void push_back(std::string const& value) { this->Values.push_back(value); } void push_back(cm::string_view value) { this->Values.push_back(std::string{ value }); } void push_back(std::string&& value) { this->Values.push_back(std::move(value)); } template iterator emplace(const_iterator pos, Args&&... args) { return this->Values.emplace(pos, std::forward(args)...); } template void emplace_back(Args&&... args) { this->Values.emplace_back(std::forward(args)...); } // Inserts elements in the list // Throw std::out_of_range if index is invalid template cmList& insert_items(index_type index, InputIterator first, InputIterator last, ExpandElements expandElements = ExpandElements::Yes, EmptyElements emptyElements = EmptyElements::No) { auto const offset = static_cast(this->ComputeInsertIndex(index)); this->insert(this->begin() + offset, first, last, expandElements, emptyElements); return *this; } template cmList& insert_items(index_type index, InputIterator first, InputIterator last, EmptyElements emptyElements) { this->insert(this->begin() + this->ComputeInsertIndex(index), first, last, ExpandElements::Yes, emptyElements); return *this; } cmList& insert_items(index_type index, std::initializer_list values) { return this->insert_items(index, values.begin(), values.end()); } iterator erase(const_iterator pos) { // convert const_iterator in iterator to please non standard c++11 // compilers (gcc 4.8 for example) auto pos2 = this->Values.begin() + std::distance(this->Values.cbegin(), pos); return this->Values.erase(pos2); } iterator erase(const_iterator first, const_iterator last) { // convert const_iterator in iterator to please non standard c++11 // compilers (gcc 4.8 for example) auto first2 = this->Values.begin() + std::distance(this->Values.cbegin(), first); auto last2 = this->Values.begin() + std::distance(this->Values.cbegin(), last); return this->Values.erase(first2, last2); } void pop_back() { this->Values.pop_back(); } void pop_front() { this->Values.erase(this->begin()); } // Removes elements from the list // Throw std::out_of_range if any index is invalid cmList& remove_items(std::initializer_list indexes) { return this->RemoveItems( std::vector{ indexes.begin(), indexes.end() }); } cmList& remove_items(std::initializer_list values) { return this->RemoveItems( std::vector{ values.begin(), values.end() }); } template cmList& remove_items(InputIterator first, InputIterator last) { return this->RemoveItems( std::vector{ first, last }); } cmList& remove_duplicates(); void resize(size_type count) { this->Values.resize(count); } enum class FilterMode { INCLUDE, EXCLUDE }; // Includes or removes items from the list // Throw std::invalid_argument if regular expression is invalid cmList& filter(cm::string_view regex, FilterMode mode); cmList& reverse() { std::reverse(this->Values.begin(), this->Values.end()); return *this; } struct SortConfiguration { enum class OrderMode { DEFAULT, ASCENDING, DESCENDING, } Order = OrderMode::DEFAULT; enum class CompareMethod { DEFAULT, STRING, FILE_BASENAME, NATURAL, } Compare = CompareMethod::DEFAULT; enum class CaseSensitivity { DEFAULT, SENSITIVE, INSENSITIVE, } Case = CaseSensitivity::DEFAULT; // declare the default constructor to work-around clang bug SortConfiguration(); SortConfiguration(OrderMode order, CompareMethod compare, CaseSensitivity caseSensitivity) : Order(order) , Compare(compare) , Case(caseSensitivity) { } }; cmList& sort(const SortConfiguration& config = SortConfiguration{}); // exception raised on error during transform operations class transform_error : public std::runtime_error { public: transform_error(const std::string& error) : std::runtime_error(error) { } }; class TransformSelector { public: using index_type = cmList::index_type; // define some structs used as template selector struct AT; struct FOR; struct REGEX; virtual ~TransformSelector() = default; virtual const std::string& GetTag() = 0; // method NEW is used to allocate a selector of the needed type. // For example: // cmList::TransformSelector::New({1, 2, 5, 6}); // or // cmList::TransformSelector::New("^XX.*"); template static std::unique_ptr New( std::initializer_list); template static std::unique_ptr New( std::vector const&); template static std::unique_ptr New(std::vector&&); template static std::unique_ptr New(std::string const&); template static std::unique_ptr New(std::string&&); private: static std::unique_ptr NewAT( std::initializer_list init); static std::unique_ptr NewAT( std::vector const& init); static std::unique_ptr NewAT( std::vector&& init); static std::unique_ptr NewFOR( std::initializer_list init); static std::unique_ptr NewFOR( std::vector const& init); static std::unique_ptr NewFOR( std::vector&& init); static std::unique_ptr NewREGEX( std::string const& init); static std::unique_ptr NewREGEX(std::string&& init); }; enum class TransformAction { APPEND, PREPEND, TOLOWER, TOUPPER, STRIP, GENEX_STRIP, REPLACE }; // Transforms the list by applying an action // Throw std::transform_error is any of arguments specified are invalid cmList& transform(TransformAction action, std::unique_ptr = {}); cmList& transform(TransformAction action, std::string const& arg, std::unique_ptr = {}); cmList& transform(TransformAction action, std::string const& arg1, std::string const& arg2, std::unique_ptr = {}); cmList& transform(TransformAction action, std::vector const& args, std::unique_ptr = {}); std::string join(cm::string_view glue) const { return cmList::Join(this->Values, glue); } void swap(cmList& other) noexcept { this->Values.swap(other.Values); } // static members // ============== // these methods can be used to store CMake list expansion directly in a // std::vector. static void assign(std::vector& container, cm::string_view value, EmptyElements emptyElements = EmptyElements::No) { container.clear(); cmList::append(container, value, emptyElements); } static void assign(std::vector& container, std::string const& value, EmptyElements emptyElements = EmptyElements::No) { container.clear(); cmList::append(container, value, emptyElements); } static void assign(std::vector& container, cmValue value, EmptyElements emptyElements = EmptyElements::No) { if (value) { cmList::assign(container, *value, emptyElements); } else { container.clear(); } } template static void assign(std::vector& container, InputIterator first, InputIterator last, EmptyElements emptyElements = EmptyElements::No) { container.clear(); cmList::append(container, first, last, emptyElements); } static std::vector::iterator insert( std::vector& container, std::vector::const_iterator pos, cm::string_view value, EmptyElements emptyElements = EmptyElements::No) { return cmList::Insert(container, pos, std::string(value), ExpandElements::Yes, emptyElements); } static std::vector::iterator insert( std::vector& container, std::vector::const_iterator pos, std::string const& value, EmptyElements emptyElements = EmptyElements::No) { return cmList::Insert(container, pos, value, ExpandElements::Yes, emptyElements); } static std::vector::iterator insert( std::vector& container, std::vector::const_iterator pos, cmValue value, EmptyElements emptyElements = EmptyElements::No) { if (value) { return cmList::insert(container, pos, *value, emptyElements); } auto delta = std::distance(container.cbegin(), pos); return container.begin() + delta; } template static std::vector::iterator insert( std::vector& container, std::vector::const_iterator pos, InputIterator first, InputIterator last, EmptyElements emptyElements = EmptyElements::No) { return cmList::Insert(container, pos, first, last, ExpandElements::Yes, emptyElements); } static std::vector::iterator append( std::vector& container, cm::string_view value, EmptyElements emptyElements = EmptyElements::No) { return cmList::insert(container, container.cend(), value, emptyElements); } static std::vector::iterator append( std::vector& container, std::string const& value, EmptyElements emptyElements = EmptyElements::No) { return cmList::insert(container, container.cend(), value, emptyElements); } static std::vector::iterator append( std::vector& container, cmValue value, EmptyElements emptyElements = EmptyElements::No) { if (value) { return cmList::append(container, *value, emptyElements); } return container.end(); } template static std::vector::iterator append( std::vector& container, InputIterator first, InputIterator last, EmptyElements emptyElements = EmptyElements::No) { return cmList::insert(container, container.cend(), first, last, emptyElements); } static std::vector::iterator prepend( std::vector& container, cm::string_view value, EmptyElements emptyElements = EmptyElements::No) { return cmList::insert(container, container.cbegin(), value, emptyElements); } static std::vector::iterator prepend( std::vector& container, std::string const& value, EmptyElements emptyElements = EmptyElements::No) { return cmList::insert(container, container.cbegin(), value, emptyElements); } static std::vector::iterator prepend( std::vector& container, cmValue value, EmptyElements emptyElements = EmptyElements::No) { if (value) { return cmList::prepend(container, *value, emptyElements); } return container.begin(); } template static std::vector::iterator prepend( std::vector& container, InputIterator first, InputIterator last, EmptyElements emptyElements = EmptyElements::No) { return cmList::insert(container, container.cbegin(), first, last, emptyElements); } // The following methods offer the possibility to extend a CMake list // but without any intermediate expansion. So the operation is simply a // string concatenation with special handling for the CMake list item // separator static std::string& append(std::string& list, std::string&& value); static std::string& append(std::string& list, cm::string_view value); template static std::string& append(std::string& list, InputIterator first, InputIterator last) { if (first == last) { return list; } return cmList::append( list, cmList::Join(first, last, cmList::element_separator)); } static std::string& prepend(std::string& list, std::string&& value); static std::string& prepend(std::string& list, cm::string_view value); template static std::string& prepend(std::string& list, InputIterator first, InputIterator last) { if (first == last) { return list; } return cmList::prepend( list, cmList::Join(first, last, cmList::element_separator)); } template ::value, int> = 0> static std::string to_string(Range const& r) { return cmList::Join(r, cmList::element_separator); } // Non-members // =========== friend inline bool operator==(const cmList& lhs, const cmList& rhs) noexcept { return lhs.Values == rhs.Values; } friend inline bool operator!=(const cmList& lhs, const cmList& rhs) noexcept { return lhs.Values != rhs.Values; } private: size_type ComputeIndex(index_type pos, bool boundCheck = true) const; size_type ComputeInsertIndex(index_type pos, bool boundCheck = true) const; cmList GetItems(std::vector&& indexes) const; cmList& RemoveItems(std::vector&& indexes); cmList& RemoveItems(std::vector&& items); static container_type::iterator Insert(container_type& container, container_type::const_iterator pos, std::string&& value, ExpandElements expandElements, EmptyElements emptyElements); static container_type::iterator Insert(container_type& container, container_type::const_iterator pos, const std::string& value, ExpandElements expandElements, EmptyElements emptyElements) { auto tmp = value; return cmList::Insert(container, pos, std::move(tmp), expandElements, emptyElements); } template static container_type::iterator Insert(container_type& container, container_type::const_iterator pos, InputIterator first, InputIterator last, ExpandElements expandElements, EmptyElements emptyElements) { auto delta = std::distance(container.cbegin(), pos); if (first == last) { return container.begin() + delta; } auto insertPos = container.begin() + delta; if (expandElements == ExpandElements::Yes) { for (; first != last; ++first) { auto size = container.size(); insertPos = cmList::Insert(container, insertPos, *first, expandElements, emptyElements); insertPos += static_cast(container.size() - size); } } else { for (; first != last; ++first) { if (!(*first).empty() || emptyElements == EmptyElements::Yes) { insertPos = container.insert(insertPos, *first); ++insertPos; } } } return container.begin() + delta; } static std::string const& ToString(std::string const& s) { return s; } static std::string ToString(cm::string_view s) { return std::string{ s }; } static std::string const& ToString(BT const&); template static std::string Join(Range const& r, cm::string_view glue) { if (cm::size(r) == 0) { return std::string{}; } return cmList::Join(std::begin(r), std::end(r), glue); } template static std::string Join(InputIterator first, InputIterator last, cm::string_view glue) { if (first == last) { return std::string{}; } const auto sep = std::string{ glue }; std::string joined = cmList::ToString(*first); for (auto it = std::next(first); it != last; ++it) { joined += sep; joined += cmList::ToString(*it); } return joined; } container_type Values; }; // specializations for cmList::TransformSelector allocators // ======================================================== template <> inline std::unique_ptr cmList::TransformSelector::New( std::initializer_list init) { return cmList::TransformSelector::NewAT(init); } template <> inline std::unique_ptr cmList::TransformSelector::New( std::vector const& init) { return cmList::TransformSelector::NewAT(init); } template <> inline std::unique_ptr cmList::TransformSelector::New( std::vector&& init) { return cmList::TransformSelector::NewAT(std::move(init)); } template <> inline std::unique_ptr cmList::TransformSelector::New( std::initializer_list init) { return cmList::TransformSelector::NewFOR(init); } template <> inline std::unique_ptr cmList::TransformSelector::New( std::vector const& init) { return cmList::TransformSelector::NewFOR(init); } template <> inline std::unique_ptr cmList::TransformSelector::New( std::vector&& init) { return cmList::TransformSelector::NewFOR(std::move(init)); } template <> inline std::unique_ptr cmList::TransformSelector::New( std::string const& init) { return cmList::TransformSelector::NewREGEX(init); } template <> inline std::unique_ptr cmList::TransformSelector::New( std::string&& init) { return cmList::TransformSelector::NewREGEX(std::move(init)); } // Non-member functions // ==================== inline std::vector& operator+=(std::vector& l, const cmList& r) { l.insert(l.end(), r.begin(), r.end()); return l; } inline std::vector& operator+=(std::vector& l, cmList&& r) { std::move(r.begin(), r.end(), std::back_inserter(l)); r.clear(); return l; } namespace std { inline void swap(cmList& lhs, cmList& rhs) noexcept { lhs.swap(rhs); } } // namespace std namespace cm { inline void erase(cmList& list, const std::string& value) { list.erase(std::remove(list.begin(), list.end(), value), list.end()); } template inline void erase_if(cmList& list, Predicate pred) { list.erase(std::remove_if(list.begin(), list.end(), pred), list.end()); } // // Provide a special implementation of cm::append because, in this case, // expansion must not be applied to the inserted elements // #if defined(__SUNPRO_CC) && defined(__sparc) // Oracle DeveloperStudio C++ compiler on Solaris/Sparc fails to compile // templates with constraints. // So, on this platform, use only simple templates. template ::value, int> = 0> void append(cmList& v, InputIt first, InputIt last) { v.append(first, last, cmList::ExpandElements::No); } template ::value, int> = 0> void append(cmList& v, Range const& r) { v.append(r.begin(), r.end(), cmList::ExpandElements::No); } #else template < typename InputIt, cm::enable_if_t< cm::is_input_iterator::value && std::is_convertible::value_type, cmList::value_type>::value, int> = 0> void append(cmList& v, InputIt first, InputIt last) { v.append(first, last, cmList::ExpandElements::No); } template ::value && std::is_convertible::value, int> = 0> void append(cmList& v, Range const& r) { v.append(r.begin(), r.end(), cmList::ExpandElements::No); } #endif } // namespace cm /** * Helper functions for legacy support. Use preferably cmList class directly * or the static methods of the class. */ inline void cmExpandList( cm::string_view arg, std::vector& argsOut, cmList::EmptyElements emptyElements = cmList::EmptyElements::No) { cmList::append(argsOut, arg, emptyElements); } inline void cmExpandList( cmValue arg, std::vector& argsOut, cmList::EmptyElements emptyElements = cmList::EmptyElements::No) { cmList::append(argsOut, arg, emptyElements); }