mirror of
https://github.com/ETLCPP/etl.git
synced 2026-06-20 02:46:44 +08:00
Feature/add back insert iterator (#603)
* Add back_inserter implementation - Mainly a copy of the STL implementation found in LLVM. - Add test_back_insert_iterator unit test. * Add documentation and use ETL_OR_STD macro * Add MIT License in header * Move back_insert_iterator into iterator.h * Remove unused code * Strictly follow the C++ STL naming https://en.cppreference.com/w/cpp/iterator/back_insert_iterator Strictly following the C++ STL would have container_ be container. * Make the check for C++11 clearer * Run the unit test only for C++11 * Add front_insert_iterator - Make back_insert_iterator available to C++03 - Add ETL_CONSTEXPR17,ETL_NODISCARD and ETL_USING_CPP11 - Replace std:move usage by etl::move - Update doc * Use explicit namespace for adressof() and move().
This commit is contained in:
parent
eef3605297
commit
af98e175e2
@ -604,7 +604,191 @@ namespace etl
|
||||
return etl::move_iterator<TIterator>(itr);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif //ETL_USING_CPP11
|
||||
|
||||
//***************************************************************************
|
||||
// back_insert_iterator
|
||||
//***************************************************************************
|
||||
|
||||
/**
|
||||
* @brief Turns assignment into insertion.
|
||||
*
|
||||
* These are output iterators, constructed from a container-of-T.
|
||||
* Assigning a T to the iterator appends it to the container using push_back.
|
||||
*
|
||||
* @tparam TContainer
|
||||
*/
|
||||
template <class TContainer>
|
||||
class back_insert_iterator : public iterator<output_iterator_tag, void, void, void, void>
|
||||
{
|
||||
public:
|
||||
/// A nested typedef for the type of whatever container you used.
|
||||
typedef TContainer container_type;
|
||||
|
||||
/// The only way to create this %iterator is with a container.
|
||||
explicit ETL_CONSTEXPR17 back_insert_iterator(TContainer& c)
|
||||
: container(etl::addressof(c))
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* This kind of %iterator doesn't really have a @a position in the
|
||||
* container (you can think of the position as being permanently at
|
||||
* the end, if you like). Assigning a value to the %iterator will
|
||||
* always append the value to the end of the container.
|
||||
*
|
||||
* @param value An instance of whatever type container_type::const_reference is;
|
||||
* presumably a reference-to-const T for container<T>.
|
||||
* @return This %iterator, for chained operations.
|
||||
*/
|
||||
ETL_CONSTEXPR17 back_insert_iterator& operator=(const typename TContainer::value_type& value)
|
||||
{
|
||||
container->push_back(value);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
#if ETL_USING_CPP11
|
||||
ETL_CONSTEXPR17 back_insert_iterator& operator=(typename TContainer::reference value)
|
||||
{
|
||||
container->push_back(etl::move(value));
|
||||
return (*this);
|
||||
}
|
||||
#endif // ETL_USING_CPP11
|
||||
|
||||
/// Simply returns *this.
|
||||
ETL_NODISCARD ETL_CONSTEXPR17 back_insert_iterator& operator*()
|
||||
{
|
||||
return (*this);
|
||||
}
|
||||
|
||||
/// Simply returns *this. (This %iterator does not @a move.)
|
||||
ETL_CONSTEXPR17 back_insert_iterator& operator++()
|
||||
{
|
||||
return (*this);
|
||||
}
|
||||
|
||||
/// Simply returns *this. (This %iterator does not @a move.)
|
||||
ETL_CONSTEXPR17 back_insert_iterator operator++(int)
|
||||
{
|
||||
return (*this);
|
||||
}
|
||||
|
||||
protected:
|
||||
TContainer* container;
|
||||
};
|
||||
|
||||
/**
|
||||
* This wrapper function helps in creating back_insert_iterator instances.
|
||||
* Typing the name of the %iterator requires knowing the precise full
|
||||
* type of the container, which can be tedious and impedes generic
|
||||
* programming. Using this function lets you take advantage of automatic
|
||||
* template parameter deduction, making the compiler match the correct types for you.
|
||||
*
|
||||
* @tparam TContainer The container type.
|
||||
* @param container A container of arbitrary type.
|
||||
* @return An instance of back_insert_iterator working on @p container.
|
||||
*/
|
||||
template <class TContainer>
|
||||
ETL_NODISCARD ETL_CONSTEXPR17 inline ETL_OR_STD::back_insert_iterator<TContainer> back_inserter(TContainer& container)
|
||||
{
|
||||
return ETL_OR_STD::back_insert_iterator<TContainer>(container);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
// front_insert_iterator
|
||||
//***************************************************************************
|
||||
|
||||
/**
|
||||
* @brief Turns assignment into insertion.
|
||||
*
|
||||
* These are output iterators, constructed from a container-of-T.
|
||||
* Assigning a T to the iterator prepends it to the container using
|
||||
* push_front.
|
||||
*
|
||||
* Tip: Using the front_inserter function to create these iterators can
|
||||
* save typing.
|
||||
*
|
||||
* @tparam TContainer The container type.
|
||||
*/
|
||||
template <typename TContainer>
|
||||
class front_insert_iterator
|
||||
: public iterator<output_iterator_tag, void, void, void, void>
|
||||
{
|
||||
public:
|
||||
/// A nested typedef for the type of whatever container you used.
|
||||
typedef TContainer container_type;
|
||||
|
||||
/// The only way to create this %iterator is with a container.
|
||||
explicit ETL_CONSTEXPR17 front_insert_iterator(TContainer& c)
|
||||
: container(etl::addressof(c))
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* This kind of %iterator doesn't really have a @a position in the
|
||||
* container (you can think of the position as being permanently at
|
||||
* the front, if you like). Assigning a value to the %iterator will
|
||||
* always prepend the value to the front of the container.
|
||||
*
|
||||
* @param value An instance of whatever type
|
||||
* container_type::const_reference is; presumably a
|
||||
* reference-to-const T for container<T>.
|
||||
* @return This %iterator, for chained operations.
|
||||
*
|
||||
*/
|
||||
ETL_CONSTEXPR17 front_insert_iterator& operator=(const typename TContainer::value_type& value)
|
||||
{
|
||||
container->push_front(value);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
#if ETL_USING_CPP11
|
||||
ETL_CONSTEXPR17 front_insert_iterator& operator=(typename TContainer::reference value)
|
||||
{
|
||||
container->push_front(etl::move(value));
|
||||
return (*this);
|
||||
}
|
||||
#endif // ETL_USING_CPP11
|
||||
|
||||
/// Simply returns *this.
|
||||
ETL_NODISCARD ETL_CONSTEXPR17 front_insert_iterator& operator*()
|
||||
{
|
||||
return (*this);
|
||||
}
|
||||
|
||||
/// Simply returns *this. (This %iterator does not @a move.)
|
||||
ETL_CONSTEXPR17 front_insert_iterator& operator++()
|
||||
{
|
||||
return (*this);
|
||||
}
|
||||
|
||||
/// Simply returns *this. (This %iterator does not @a move.)
|
||||
ETL_CONSTEXPR17 front_insert_iterator operator++(int)
|
||||
{
|
||||
return (*this);
|
||||
}
|
||||
|
||||
protected:
|
||||
TContainer* container;
|
||||
};
|
||||
|
||||
/**
|
||||
* This wrapper function helps in creating front_insert_iterator instances.
|
||||
* Typing the name of the %iterator requires knowing the precise full
|
||||
* type of the container, which can be tedious and impedes generic
|
||||
* programming. Using this function lets you take advantage of automatic
|
||||
* template parameter deduction, making the compiler match the correct
|
||||
* types for you.
|
||||
*
|
||||
* @tparam TContainer The container type.
|
||||
* @param container A container of arbitrary type.
|
||||
* @return An instance of front_insert_iterator working on @p x.
|
||||
*/
|
||||
template <typename TContainer>
|
||||
ETL_NODISCARD ETL_CONSTEXPR17 inline ETL_OR_STD::front_insert_iterator<TContainer> front_inserter(TContainer& container)
|
||||
{
|
||||
return ETL_OR_STD::front_insert_iterator<TContainer>(container);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
// Helper templates.
|
||||
|
||||
@ -301,6 +301,28 @@ namespace
|
||||
CHECK(are_equal);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST_FIXTURE(SetupFixture, test_front_insert_iterator)
|
||||
{
|
||||
DataInt data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
DataInt expected = {81, 64, 49, 36, 25, 16, 9, 4, 1, 0};
|
||||
DataInt transformed;
|
||||
|
||||
auto squared = [](int value)
|
||||
{
|
||||
return value * value;
|
||||
};
|
||||
|
||||
etl::transform(data.cbegin(), data.cend(), etl::front_inserter(transformed), squared);
|
||||
|
||||
CHECK_EQUAL(expected.size(), transformed.size());
|
||||
|
||||
bool transformed_equals_expected = std::equal(transformed.begin(),
|
||||
transformed.end(),
|
||||
expected.begin());
|
||||
CHECK(transformed_equals_expected);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST_FIXTURE(SetupFixture, test_resize_up)
|
||||
{
|
||||
|
||||
@ -634,6 +634,29 @@ namespace
|
||||
CHECK(is_equal);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//*************************************************************************
|
||||
TEST_FIXTURE(SetupFixture, test_back_insert_iterator)
|
||||
{
|
||||
Data data={0,1,2,3,4,5,6,7,8,9};
|
||||
Data expected={0,1,4,9,16,25,36,49,64,81};
|
||||
Data transformed;
|
||||
|
||||
auto squared = [](int value){
|
||||
return value*value;
|
||||
};
|
||||
|
||||
etl::transform(data.cbegin(),data.cend(),etl::back_inserter(transformed),squared);
|
||||
|
||||
CHECK_EQUAL(expected.size(), transformed.size());
|
||||
|
||||
bool transformed_equals_expected = std::equal(transformed.begin(),
|
||||
transformed.end(),
|
||||
expected.begin());
|
||||
CHECK(transformed_equals_expected);
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST_FIXTURE(SetupFixture, test_emplace_back)
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user