blob: e1070960bccb4970552b23fb84a3baba753cbd99 [file] [log] [blame]
/* 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;
/**
* 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 const size_type 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(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 <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(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<std::string> 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<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(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<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 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<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; }
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 <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, 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<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(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<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(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<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(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<AT>({1, 2, 5, 6});
// or
// cmList::TransformSelector::New<REGEX>("^XX.*");
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&&);
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 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<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,
const std::string& 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{};
}
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>
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,
const cmList& 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, const std::string& 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);
}