| /* 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 <algorithm> |
| #include <cstddef> |
| #include <initializer_list> |
| #include <iterator> |
| #include <memory> |
| #include <stdexcept> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include <cm/string_view> |
| #include <cm/type_traits> |
| #include <cmext/iterator> |
| |
| #include "cmValue.h" |
| |
| template <typename T> |
| class BT; |
| class cmMakefile; |
| |
| /** |
| * 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<std::string>; |
| |
| 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 size_type const npos = static_cast<size_type>(-1); |
| |
| static cm::string_view element_separator; |
| |
| enum class EmptyElements |
| { |
| No, |
| Yes, |
| }; |
| enum class ExpandElements |
| { |
| No, |
| Yes, |
| }; |
| |
| cmList() = default; |
| cmList(cmList const&) = 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 <typename InputIterator> |
| cmList(InputIterator first, InputIterator last, |
| ExpandElements expandElements = ExpandElements::Yes, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| this->assign(first, last, expandElements, emptyElements); |
| } |
| template <typename InputIterator> |
| cmList(InputIterator first, InputIterator last, EmptyElements emptyElements) |
| : cmList(first, last, ExpandElements::Yes, emptyElements) |
| { |
| } |
| cmList(container_type const& init, |
| ExpandElements expandElements = ExpandElements::Yes, |
| EmptyElements emptyElements = EmptyElements::No) |
| : cmList(init.begin(), init.end(), expandElements, emptyElements) |
| { |
| } |
| cmList(container_type const& 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<std::string> init) { this->assign(init); } |
| |
| ~cmList() = default; |
| |
| cmList& operator=(cmList const&) = 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=(container_type const& init) |
| { |
| this->assign(init); |
| return *this; |
| } |
| cmList& operator=(container_type&& init) |
| { |
| this->assign(std::move(init)); |
| |
| return *this; |
| } |
| |
| cmList& operator=(std::initializer_list<std::string> 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 <typename InputIterator> |
| void assign(InputIterator first, InputIterator last, |
| ExpandElements expandElements = ExpandElements::Yes, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| this->clear(); |
| this->append(first, last, expandElements, emptyElements); |
| } |
| template <typename InputIterator> |
| void assign(InputIterator first, InputIterator last, |
| EmptyElements emptyElements) |
| { |
| this->assign(first, last, ExpandElements::Yes, emptyElements); |
| } |
| void assign(cmList const& init, |
| ExpandElements expandElements = ExpandElements::No, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| this->assign(init.begin(), init.end(), expandElements, emptyElements); |
| } |
| void assign(cmList const& 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(container_type const& init, |
| ExpandElements expandElements = ExpandElements::Yes, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| this->assign(init.begin(), init.end(), expandElements, emptyElements); |
| } |
| void assign(container_type const& 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<std::string> 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 container_type const&() 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<index_type> indexes) const |
| { |
| return this->GetItems( |
| std::vector<index_type>{ indexes.begin(), indexes.end() }); |
| } |
| template <typename InputIterator> |
| cmList get_items(InputIterator first, InputIterator last) const |
| { |
| return this->GetItems(std::vector<index_type>{ 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; } |
| container_type const& 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 <typename InputIterator> |
| 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 <typename InputIterator> |
| 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, cmList const& values, |
| ExpandElements expandElements = ExpandElements::No, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| return this->insert(pos, values.begin(), values.end(), expandElements, |
| emptyElements); |
| } |
| iterator insert(const_iterator pos, cmList const& 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, container_type const& values, |
| ExpandElements expandElements = ExpandElements::Yes, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| return this->insert(pos, values.begin(), values.end(), expandElements, |
| emptyElements); |
| } |
| iterator insert(const_iterator pos, container_type const& 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<std::string> 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 <typename InputIterator> |
| iterator append(InputIterator first, InputIterator last, |
| ExpandElements expandElements = ExpandElements::Yes, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| return this->insert(this->cend(), first, last, expandElements, |
| emptyElements); |
| } |
| template <typename InputIterator> |
| iterator append(InputIterator first, InputIterator last, |
| EmptyElements emptyElements) |
| { |
| return this->append(first, last, ExpandElements::Yes, emptyElements); |
| } |
| iterator append(cmList const& values, |
| ExpandElements expandElements = ExpandElements::No, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| return this->append(values.begin(), values.end(), expandElements, |
| emptyElements); |
| } |
| iterator append(cmList const& 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(container_type const& values, |
| ExpandElements expandElements = ExpandElements::Yes, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| return this->append(values.begin(), values.end(), expandElements, |
| emptyElements); |
| } |
| iterator append(container_type const& 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<std::string> 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 <typename InputIterator> |
| iterator prepend(InputIterator first, InputIterator last, |
| ExpandElements expandElements = ExpandElements::Yes, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| return this->insert(this->cbegin(), first, last, expandElements, |
| emptyElements); |
| } |
| template <typename InputIterator> |
| iterator prepend(InputIterator first, InputIterator last, |
| EmptyElements emptyElements) |
| { |
| return this->prepend(first, last, ExpandElements::Yes, emptyElements); |
| } |
| iterator prepend(cmList const& values, |
| ExpandElements expandElements = ExpandElements::No, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| return this->prepend(values.begin(), values.end(), expandElements, |
| emptyElements); |
| } |
| iterator prepend(cmList const& 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(container_type const& values, |
| ExpandElements expandElements = ExpandElements::Yes, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| return this->prepend(values.begin(), values.end(), expandElements, |
| emptyElements); |
| } |
| iterator prepend(container_type const& 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<std::string> 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 <typename... Args> |
| iterator emplace(const_iterator pos, Args&&... args) |
| { |
| return this->Values.emplace(pos, std::forward<Args>(args)...); |
| } |
| |
| template <typename... Args> |
| void emplace_back(Args&&... args) |
| { |
| this->Values.emplace_back(std::forward<Args>(args)...); |
| } |
| |
| // Inserts elements in the list |
| // Throw std::out_of_range if index is invalid |
| template <typename InputIterator> |
| cmList& insert_items(index_type index, InputIterator first, |
| InputIterator last, |
| ExpandElements expandElements = ExpandElements::Yes, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| auto const offset = |
| static_cast<difference_type>(this->ComputeInsertIndex(index)); |
| this->insert(this->begin() + offset, first, last, expandElements, |
| emptyElements); |
| return *this; |
| } |
| template <typename InputIterator> |
| 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<std::string> 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<index_type> indexes) |
| { |
| return this->RemoveItems( |
| std::vector<index_type>{ indexes.begin(), indexes.end() }); |
| } |
| cmList& remove_items(std::initializer_list<std::string> values) |
| { |
| return this->RemoveItems( |
| std::vector<std::string>{ values.begin(), values.end() }); |
| } |
| template <typename InputIterator> |
| cmList& remove_items(InputIterator first, InputIterator last) |
| { |
| return this->RemoveItems( |
| std::vector<typename InputIterator::value_type>{ 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(SortConfiguration const& config = SortConfiguration{}); |
| |
| // exception raised on error during transform operations |
| class transform_error : public std::runtime_error |
| { |
| public: |
| transform_error(std::string const& 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 std::string const& GetTag() = 0; |
| |
| // method NEW is used to allocate a selector of the needed type. |
| // For example: |
| // cmList::TransformSelector::New<AT>({1, 2, 5, 6}); |
| // or |
| // cmList::TransformSelector::New<REGEX>("^XX.*"); |
| static std::unique_ptr<TransformSelector> New(); |
| template <typename Type> |
| static std::unique_ptr<TransformSelector> New( |
| std::initializer_list<index_type>); |
| template <typename Type> |
| static std::unique_ptr<TransformSelector> New( |
| std::vector<index_type> const&); |
| template <typename Type> |
| static std::unique_ptr<TransformSelector> New(std::vector<index_type>&&); |
| |
| template <typename Type> |
| static std::unique_ptr<TransformSelector> New(std::string const&); |
| template <typename Type> |
| static std::unique_ptr<TransformSelector> New(std::string&&); |
| |
| cmMakefile* Makefile = nullptr; |
| |
| private: |
| static std::unique_ptr<TransformSelector> NewAT( |
| std::initializer_list<index_type> init); |
| static std::unique_ptr<TransformSelector> NewAT( |
| std::vector<index_type> const& init); |
| static std::unique_ptr<TransformSelector> NewAT( |
| std::vector<index_type>&& init); |
| |
| static std::unique_ptr<TransformSelector> NewFOR( |
| std::initializer_list<index_type> init); |
| static std::unique_ptr<TransformSelector> NewFOR( |
| std::vector<index_type> const& init); |
| static std::unique_ptr<TransformSelector> NewFOR( |
| std::vector<index_type>&& init); |
| |
| static std::unique_ptr<TransformSelector> NewREGEX( |
| std::string const& init); |
| static std::unique_ptr<TransformSelector> 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<TransformSelector> = {}); |
| cmList& transform(TransformAction action, std::string const& arg, |
| std::unique_ptr<TransformSelector> = {}); |
| cmList& transform(TransformAction action, std::string const& arg1, |
| std::string const& arg2, |
| std::unique_ptr<TransformSelector> = {}); |
| cmList& transform(TransformAction action, |
| std::vector<std::string> const& args, |
| std::unique_ptr<TransformSelector> = {}); |
| |
| 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<std::string>& container, |
| cm::string_view value, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| container.clear(); |
| cmList::append(container, value, emptyElements); |
| } |
| static void assign(std::vector<std::string>& container, |
| std::string const& value, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| container.clear(); |
| cmList::append(container, value, emptyElements); |
| } |
| static void assign(std::vector<std::string>& container, cmValue value, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| if (value) { |
| cmList::assign(container, *value, emptyElements); |
| } else { |
| container.clear(); |
| } |
| } |
| template <typename InputIterator> |
| static void assign(std::vector<std::string>& container, InputIterator first, |
| InputIterator last, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| container.clear(); |
| cmList::append(container, first, last, emptyElements); |
| } |
| |
| static std::vector<std::string>::iterator insert( |
| std::vector<std::string>& container, |
| std::vector<std::string>::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<std::string>::iterator insert( |
| std::vector<std::string>& container, |
| std::vector<std::string>::const_iterator pos, std::string const& value, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| return cmList::Insert(container, pos, value, ExpandElements::Yes, |
| emptyElements); |
| } |
| static std::vector<std::string>::iterator insert( |
| std::vector<std::string>& container, |
| std::vector<std::string>::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 <typename InputIterator> |
| static std::vector<std::string>::iterator insert( |
| std::vector<std::string>& container, |
| std::vector<std::string>::const_iterator pos, InputIterator first, |
| InputIterator last, EmptyElements emptyElements = EmptyElements::No) |
| { |
| return cmList::Insert(container, pos, first, last, ExpandElements::Yes, |
| emptyElements); |
| } |
| |
| static std::vector<std::string>::iterator append( |
| std::vector<std::string>& container, cm::string_view value, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| return cmList::insert(container, container.cend(), value, emptyElements); |
| } |
| static std::vector<std::string>::iterator append( |
| std::vector<std::string>& container, std::string const& value, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| return cmList::insert(container, container.cend(), value, emptyElements); |
| } |
| static std::vector<std::string>::iterator append( |
| std::vector<std::string>& container, cmValue value, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| if (value) { |
| return cmList::append(container, *value, emptyElements); |
| } |
| |
| return container.end(); |
| } |
| template <typename InputIterator> |
| static std::vector<std::string>::iterator append( |
| std::vector<std::string>& container, InputIterator first, |
| InputIterator last, EmptyElements emptyElements = EmptyElements::No) |
| { |
| return cmList::insert(container, container.cend(), first, last, |
| emptyElements); |
| } |
| |
| static std::vector<std::string>::iterator prepend( |
| std::vector<std::string>& container, cm::string_view value, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| return cmList::insert(container, container.cbegin(), value, emptyElements); |
| } |
| static std::vector<std::string>::iterator prepend( |
| std::vector<std::string>& container, std::string const& value, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| return cmList::insert(container, container.cbegin(), value, emptyElements); |
| } |
| static std::vector<std::string>::iterator prepend( |
| std::vector<std::string>& container, cmValue value, |
| EmptyElements emptyElements = EmptyElements::No) |
| { |
| if (value) { |
| return cmList::prepend(container, *value, emptyElements); |
| } |
| |
| return container.begin(); |
| } |
| template <typename InputIterator> |
| static std::vector<std::string>::iterator prepend( |
| std::vector<std::string>& 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 <typename InputIterator> |
| 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 <typename InputIterator> |
| 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 <typename Range, |
| cm::enable_if_t<cm::is_range<Range>::value, int> = 0> |
| static std::string to_string(Range const& r) |
| { |
| return cmList::Join(r, cmList::element_separator); |
| } |
| |
| // Non-members |
| // =========== |
| friend bool operator==(cmList const& lhs, cmList const& rhs) noexcept |
| { |
| return lhs.Values == rhs.Values; |
| } |
| friend bool operator!=(cmList const& lhs, cmList const& 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<index_type>&& indexes) const; |
| |
| cmList& RemoveItems(std::vector<index_type>&& indexes); |
| cmList& RemoveItems(std::vector<std::string>&& 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, |
| std::string const& value, |
| ExpandElements expandElements, |
| EmptyElements emptyElements) |
| { |
| auto tmp = value; |
| return cmList::Insert(container, pos, std::move(tmp), expandElements, |
| emptyElements); |
| } |
| template <typename InputIterator> |
| 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<decltype(delta)>(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<std::string> const&); |
| |
| template <typename Range> |
| 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 <typename InputIterator> |
| static std::string Join(InputIterator first, InputIterator last, |
| cm::string_view glue) |
| { |
| if (first == last) { |
| return std::string{}; |
| } |
| |
| auto const 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> |
| cmList::TransformSelector::New<cmList::TransformSelector::AT>( |
| std::initializer_list<index_type> init) |
| { |
| return cmList::TransformSelector::NewAT(init); |
| } |
| template <> |
| inline std::unique_ptr<cmList::TransformSelector> |
| cmList::TransformSelector::New<cmList::TransformSelector::AT>( |
| std::vector<index_type> const& init) |
| { |
| return cmList::TransformSelector::NewAT(init); |
| } |
| template <> |
| inline std::unique_ptr<cmList::TransformSelector> |
| cmList::TransformSelector::New<cmList::TransformSelector::AT>( |
| std::vector<index_type>&& init) |
| { |
| return cmList::TransformSelector::NewAT(std::move(init)); |
| } |
| |
| template <> |
| inline std::unique_ptr<cmList::TransformSelector> |
| cmList::TransformSelector::New<cmList::TransformSelector::FOR>( |
| std::initializer_list<index_type> init) |
| { |
| return cmList::TransformSelector::NewFOR(init); |
| } |
| template <> |
| inline std::unique_ptr<cmList::TransformSelector> |
| cmList::TransformSelector::New<cmList::TransformSelector::FOR>( |
| std::vector<index_type> const& init) |
| { |
| return cmList::TransformSelector::NewFOR(init); |
| } |
| template <> |
| inline std::unique_ptr<cmList::TransformSelector> |
| cmList::TransformSelector::New<cmList::TransformSelector::FOR>( |
| std::vector<index_type>&& init) |
| { |
| return cmList::TransformSelector::NewFOR(std::move(init)); |
| } |
| |
| template <> |
| inline std::unique_ptr<cmList::TransformSelector> |
| cmList::TransformSelector::New<cmList::TransformSelector::REGEX>( |
| std::string const& init) |
| { |
| return cmList::TransformSelector::NewREGEX(init); |
| } |
| template <> |
| inline std::unique_ptr<cmList::TransformSelector> |
| cmList::TransformSelector::New<cmList::TransformSelector::REGEX>( |
| std::string&& init) |
| { |
| return cmList::TransformSelector::NewREGEX(std::move(init)); |
| } |
| |
| // Non-member functions |
| // ==================== |
| inline std::vector<std::string>& operator+=(std::vector<std::string>& l, |
| cmList const& r) |
| { |
| l.insert(l.end(), r.begin(), r.end()); |
| return l; |
| } |
| inline std::vector<std::string>& operator+=(std::vector<std::string>& 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, std::string const& value) |
| { |
| list.erase(std::remove(list.begin(), list.end(), value), list.end()); |
| } |
| |
| template <typename Predicate> |
| 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 <typename InputIt, |
| cm::enable_if_t<cm::is_input_iterator<InputIt>::value, int> = 0> |
| void append(cmList& v, InputIt first, InputIt last) |
| { |
| v.append(first, last, cmList::ExpandElements::No); |
| } |
| |
| template <typename Range, |
| cm::enable_if_t<cm::is_input_range<Range>::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<InputIt>::value && |
| std::is_convertible<typename std::iterator_traits<InputIt>::value_type, |
| cmList::value_type>::value, |
| int> = 0> |
| void append(cmList& v, InputIt first, InputIt last) |
| { |
| v.append(first, last, cmList::ExpandElements::No); |
| } |
| |
| template <typename Range, |
| cm::enable_if_t<cm::is_input_range<Range>::value && |
| std::is_convertible<typename Range::value_type, |
| cmList::value_type>::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<std::string>& argsOut, |
| cmList::EmptyElements emptyElements = cmList::EmptyElements::No) |
| { |
| cmList::append(argsOut, arg, emptyElements); |
| } |
| inline void cmExpandList( |
| cmValue arg, std::vector<std::string>& argsOut, |
| cmList::EmptyElements emptyElements = cmList::EmptyElements::No) |
| { |
| cmList::append(argsOut, arg, emptyElements); |
| } |