From 5f98218fe0ed95c93cd5fa605827d3d9d2da57ee Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Tue, 27 Jun 2017 12:06:53 +0200 Subject: [PATCH] add range class --- alib2std/src/extensions/range.hpp | 116 +++++++++++++++++++++ alib2std/src/range | 9 ++ alib2std/test-src/extensions/RangeTest.cpp | 82 +++++++++++++++ alib2std/test-src/extensions/RangeTest.h | 24 +++++ 4 files changed, 231 insertions(+) create mode 100644 alib2std/src/extensions/range.hpp create mode 100644 alib2std/src/range create mode 100644 alib2std/test-src/extensions/RangeTest.cpp create mode 100644 alib2std/test-src/extensions/RangeTest.h diff --git a/alib2std/src/extensions/range.hpp b/alib2std/src/extensions/range.hpp new file mode 100644 index 0000000000..5e08a279f3 --- /dev/null +++ b/alib2std/src/extensions/range.hpp @@ -0,0 +1,116 @@ +/* + * range.hpp as proposed http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3350.html by Jeffrey Yasskin <jyasskin@google.com> + * + * Created on: May 28, 2015 + * Author: Jan Travnicek + */ + +#ifndef __RANGE_HPP_ +#define __RANGE_HPP_ + +#include <utility> +#include <iterator> + +namespace std { + +template<typename Iterator> +class range { + Iterator m_begin; + Iterator m_end; +public: + // types + typedef typename iterator_traits< Iterator >::iterator_category iterator_category; + typedef typename iterator_traits< Iterator >::value_type value_type; + typedef typename iterator_traits< Iterator >::difference_type difference_type; + typedef typename iterator_traits< Iterator >::reference reference; + typedef typename iterator_traits< Iterator >::pointer pointer; + + // constructors + range() { + } + + constexpr range(Iterator begin, Iterator end) : m_begin ( begin ), m_end ( end ) { + } + + // iterator access + constexpr Iterator begin() const { + return m_begin; + } + + constexpr Iterator end() const { + return m_end; + } + + // element access + constexpr reference front() const { + return * m_begin; + } + + constexpr reference back() const { + return * ( m_end - 1 ); + } + + constexpr reference operator[](difference_type index) const { + return m_begin [ index ]; + } + + // size + constexpr bool empty() const { + return m_begin == m_end; + } + + constexpr difference_type size() const { + return std::distance ( m_begin, m_end ); + } + + // traversal from the beginning of the range + void pop_front() { + ++ m_begin; + } + + void pop_front(difference_type n) { + m_begin = m_begin + n; + } + + // traversal from the end of the range + void pop_back() { + -- m_end; + } + + void pop_back(difference_type n) { + m_end = m_end - n; + } + + // creating derived ranges + pair< range, range > split(difference_type index) const { + return std::make_pair ( slice ( 0, index ), slice ( index, 0 ) ); + } + + range slice(difference_type start, difference_type stop) const { + return range ( ( start >= 0 ? m_begin : m_end ) + start, ( stop > 0 ? m_begin : m_end ) + stop ); + } + + range slice(difference_type start) const { + return slice ( start, 0 ); + } +}; + +template < typename Iter > +std::range < Iter > make_range ( Iter begin, Iter end ) { + return std::range < Iter > ( begin, end ); +} + +template < typename Container > +auto make_range ( Container & container ) { + return std::make_range ( container.begin ( ), container.end ( ) ); +} + +template < typename Container > +auto make_range ( const Container & container ) { + return std::make_range ( container.begin ( ), container.end ( ) ); +} + +} /* namespace std */ + +#endif /* __RANGE_HPP_ */ + diff --git a/alib2std/src/range b/alib2std/src/range new file mode 100644 index 0000000000..0661f8a86b --- /dev/null +++ b/alib2std/src/range @@ -0,0 +1,9 @@ +#ifndef __ALIB_INTERNAL_STD_EXTENSION_ + #define __ALIB_INTERNAL_STD_EXTENSION_ + + #include "extensions/range.hpp" + + #undef __ALIB_INTERNAL_STD_EXTENSION_ +#else + +#endif /* __ALIB_INTERNAL_STD_EXTENSION_ */ diff --git a/alib2std/test-src/extensions/RangeTest.cpp b/alib2std/test-src/extensions/RangeTest.cpp new file mode 100644 index 0000000000..a70359d534 --- /dev/null +++ b/alib2std/test-src/extensions/RangeTest.cpp @@ -0,0 +1,82 @@ +#include "RangeTest.h" +#include <range> +#include <vector> +#include <list> + +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION ( RangeTest, "bits" ); +CPPUNIT_TEST_SUITE_REGISTRATION ( RangeTest ); + +void RangeTest::setUp ( ) { +} + +void RangeTest::tearDown ( ) { +} + +void RangeTest::constructorTest ( ) { + int arr[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + std::range < int * > ra1 ( arr, arr + sizeof ( arr ) / sizeof ( * arr ) ); + + std::vector < int > v1 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + std::range < std::vector < int >::iterator > rv1 ( v1.begin ( ), v1.end ( ) ); + + CPPUNIT_ASSERT ( ( std::equal ( ra1.begin ( ), ra1.end ( ), rv1.begin ( ), rv1.end ( ) ) ) ); + + auto rv2 = std::make_range ( v1 ); + + CPPUNIT_ASSERT ( ( std::equal ( rv1.begin ( ), rv1.end ( ), rv2.begin ( ), rv2.end ( ) ) ) ); +} + +void RangeTest::sizeTest ( ) { + int arr[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + std::range < int * > ra1 ( arr, arr + sizeof ( arr ) / sizeof ( * arr ) ); + + CPPUNIT_ASSERT ( ra1.size ( ) == 10 ); + + std::vector < int > v1 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + std::range < std::vector < int >::iterator > rv1 ( v1.begin ( ), v1.end ( ) ); + + CPPUNIT_ASSERT ( rv1.size ( ) == 10 ); + + std::list < int > l1 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + std::range < std::list < int >::iterator > rl1 ( l1.begin ( ), l1.end ( ) ); + + CPPUNIT_ASSERT ( rl1.size ( ) == 10 ); +} + +void RangeTest::splitTest ( ) { + std::vector < int > v1 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + auto r1 = std::make_range ( v1 ); + + std::vector < int > v2 = { 0, 1, 2 }; + + auto r2 = std::make_range ( v2 ); + + std::vector < int > v3 = { 3, 4, 5, 6, 7, 8, 9 }; + + auto r3 = std::make_range ( v3 ); + + auto splitted = r1.split ( 3 ); + + CPPUNIT_ASSERT ( ( std::equal ( splitted.first.begin ( ), splitted.first.end ( ), r2.begin ( ), r2.end ( ) ) ) ); + CPPUNIT_ASSERT ( ( std::equal ( splitted.second.begin ( ), splitted.second.end ( ), r3.begin ( ), r3.end ( ) ) ) ); +} + +void RangeTest::sliceTest ( ) { + std::vector < int > v1 = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + + auto r1 = std::make_range ( v1 ); + + std::vector < int > v2 = { 4, 5, 6 }; + + auto r2 = std::make_range ( v2 ); + + auto sliced = r1.slice ( 4, -3 ); + + CPPUNIT_ASSERT ( ( std::equal ( sliced.begin ( ), sliced.end ( ), r2.begin ( ), r2.end ( ) ) ) ); +} diff --git a/alib2std/test-src/extensions/RangeTest.h b/alib2std/test-src/extensions/RangeTest.h new file mode 100644 index 0000000000..e4cd64b6fc --- /dev/null +++ b/alib2std/test-src/extensions/RangeTest.h @@ -0,0 +1,24 @@ +#ifndef RANGE_TEST_H_ +#define RANGE_TEST_H_ + +#include <cppunit/extensions/HelperMacros.h> + +class RangeTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE ( RangeTest ); + CPPUNIT_TEST ( constructorTest ); + CPPUNIT_TEST ( sizeTest ); + CPPUNIT_TEST ( splitTest ); + CPPUNIT_TEST ( sliceTest ); + CPPUNIT_TEST_SUITE_END ( ); + +public: + void setUp ( ); + void tearDown ( ); + + void constructorTest ( ); + void sizeTest ( ); + void splitTest ( ); + void sliceTest ( ); +}; + +#endif // RANGE_TEST_H_ -- GitLab