diff options
Diffstat (limited to 'src/range')
-rw-r--r-- | src/range/slice.cpp | 1 | ||||
-rw-r--r-- | src/range/slice.hpp | 74 | ||||
-rw-r--r-- | src/range/slice.tcc | 216 | ||||
-rw-r--r-- | src/range/slice_test.cpp | 89 |
4 files changed, 380 insertions, 0 deletions
diff --git a/src/range/slice.cpp b/src/range/slice.cpp new file mode 100644 index 0000000..5b23447 --- /dev/null +++ b/src/range/slice.cpp @@ -0,0 +1 @@ +#include "slice.hpp" diff --git a/src/range/slice.hpp b/src/range/slice.hpp new file mode 100644 index 0000000..f645595 --- /dev/null +++ b/src/range/slice.hpp @@ -0,0 +1,74 @@ +#ifndef TMWA_GENERIC_SLICE_HPP +#define TMWA_GENERIC_SLICE_HPP +// slice.hpp - a borrowed array +// +// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +# include "../sanity.hpp" + +# include <cstddef> + +# include <type_traits> + +# include <vector> + +template<class T> +class Slice +{ + T *_begin; + T *_end; +public: + class iterator; + + Slice(std::nullptr_t); + Slice(T *b, T *e); + Slice(T *b, size_t l); + template<class U, typename=typename std::enable_if<sizeof(T) == sizeof(U) && std::is_base_of<T, U>::value>::type> + Slice(Slice<U> o); + template<size_t n, typename=typename std::enable_if<sizeof(T) != 1>::type> + Slice(T (&arr)[n]); + // TODO: come up with something else once using ranges (wrap all containers?) + Slice(std::vector<T>& vec); + + iterator begin() const; + iterator end() const; + T *data() const; + size_t size() const; + operator bool() const; + bool operator not() const; + T& front() const; + T& back() const; + T& pop_front(); + T& pop_back(); + __attribute__((deprecated("use iterators instead"))) + T& operator[](size_t o); + + Slice slice_t(size_t o) const; + Slice slice_h(size_t o) const; + Slice rslice_t(size_t no) const; + Slice rslice_h(size_t no) const; + Slice islice_t(iterator it) const; + Slice islice_h(iterator it) const; + Slice lslice(size_t o, size_t l) const; + Slice pslice(size_t b, size_t e) const; + Slice islice(iterator b, iterator e) const; +}; + +# include "slice.tcc" + +#endif // TMWA_GENERIC_SLICE_HPP diff --git a/src/range/slice.tcc b/src/range/slice.tcc new file mode 100644 index 0000000..3a1ceb5 --- /dev/null +++ b/src/range/slice.tcc @@ -0,0 +1,216 @@ +// strings/base.tcc - Inline functions for strings/base.hpp +// +// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com> +// +// This file is part of The Mana World (Athena server) +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +#include <cassert> + +#include <algorithm> + +// simple pointer-wrapping iterator +template<class T> +class Slice<T>::iterator +{ + typedef iterator X; + + T *_ptr; +public: + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T *pointer; + typedef T& reference; + typedef std::random_access_iterator_tag iterator_category; + + iterator(T *p=nullptr) : _ptr(p) {} + + // iterator + reference operator *() const { return *_ptr; } + X& operator ++() { ++_ptr; return *this; } + // equality comparable + friend bool operator == (X l, X r) { return l._ptr == r._ptr; } + // input iterator + friend bool operator != (X l, X r) { return !(l == r); } + pointer operator->() const { return _ptr; } + X operator++ (int) { X out = *this; ++*this; return out; } + // forward iterator is mostly semantical, and the ctor is above + // bidirectional iterator + X& operator --() { --_ptr; return *this; } + X operator-- (int) { X out = *this; --*this; return out; } + // random access iterator + X& operator += (difference_type n) { _ptr += n; return *this; } + friend X operator + (X a, difference_type n) { return a += n; } + friend X operator + (difference_type n, X a) { return a += n; } + X& operator -= (difference_type n) { _ptr -= n; return *this; } + friend X operator - (X a, difference_type n) { return a -= n; } + friend difference_type operator - (X b, X a) { return b._ptr - a._ptr; } + reference operator[](difference_type n) const { return _ptr[n]; } + friend bool operator < (X a, X b) { return a._ptr < b._ptr; } + friend bool operator > (X a, X b) { return b < a; } + friend bool operator >= (X a, X b) { return !(a < b); } + friend bool operator <= (X a, X b) { return !(a > b); } +}; + +template<class T> +Slice<T>::Slice(std::nullptr_t) : _begin(nullptr), _end(nullptr) +{} + +template<class T> +Slice<T>::Slice(T *b, T *e) : _begin(b), _end(e) +{} + +template<class T> +Slice<T>::Slice(T *b, size_t l) : _begin(b), _end(b + l) +{} + +template<class T> +template<class U, typename> +Slice<T>::Slice(Slice<U> o) : _begin(o.data()), _end(o.data() + o.size()) +{} + +template<class T> +template<size_t n, typename> +Slice<T>::Slice(T (&arr)[n]) : _begin(arr), _end(arr + n) +{} + +template<class T> +Slice<T>::Slice(std::vector<T>& vec) : _begin(&*vec.begin()), _end(&*vec.end()) +{} + + +template<class T> +typename Slice<T>::iterator Slice<T>::begin() const +{ + return _begin; +} + +template<class T> +typename Slice<T>::iterator Slice<T>::end() const +{ + return _end; +} + +template<class T> +T *Slice<T>::data() const +{ + return _begin; +} + +template<class T> +size_t Slice<T>::size() const +{ + return _end - _begin; +} + +template<class T> +Slice<T>::operator bool() const +{ + return _begin != _end; +} + +template<class T> +bool Slice<T>::operator not() const +{ + return _begin == _end; +} + +template<class T> +T& Slice<T>::front() const +{ + return _begin[0]; +} + +template<class T> +T& Slice<T>::back() const +{ + return _end[-1]; +} + +template<class T> +T& Slice<T>::pop_front() +{ + ++_begin; + return _begin[0 - 1]; +} + +template<class T> +T& Slice<T>::pop_back() +{ + --_end; + return _end[-1 + 1]; +} + +template<class T> +T& Slice<T>::operator[](size_t o) +{ + assert (o < size()); + return _begin[o]; +} + + +template<class T> +Slice<T> Slice<T>::slice_t(size_t o) const +{ + return Slice(_begin + o, _end); +} + +template<class T> +Slice<T> Slice<T>::slice_h(size_t o) const +{ + return Slice(_begin, _begin + o); +} + +template<class T> +Slice<T> Slice<T>::rslice_t(size_t no) const +{ + return Slice(_end - no, _end); +} + +template<class T> +Slice<T> Slice<T>::rslice_h(size_t no) const +{ + return Slice(_begin, _end - no); +} + +template<class T> +Slice<T> Slice<T>::islice_t(iterator it) const +{ + return Slice(&*it, _end); +} + +template<class T> +Slice<T> Slice<T>::islice_h(iterator it) const +{ + return Slice(_begin, &*it); +} + +template<class T> +Slice<T> Slice<T>::lslice(size_t o, size_t l) const +{ + return Slice(_begin + o, _begin + o + l); +} + +template<class T> +Slice<T> Slice<T>::pslice(size_t b, size_t e) const +{ + return Slice(_begin + b, _begin + e); +} + +template<class T> +Slice<T> Slice<T>::islice(iterator b, iterator e) const +{ + return Slice(&*b, &*e); +} diff --git a/src/range/slice_test.cpp b/src/range/slice_test.cpp new file mode 100644 index 0000000..5bd2748 --- /dev/null +++ b/src/range/slice_test.cpp @@ -0,0 +1,89 @@ +#include "slice.hpp" + +#include <gtest/gtest.h> + +TEST(slice, slice) +{ + int init[] = {1, 2, 3, 4, 5}; + + Slice<int> slice(std::begin(init), std::end(init)); + EXPECT_EQ(slice.data(), init); + EXPECT_EQ(slice.size(), 5); + + Slice<int> head = slice.slice_h(2); + Slice<int> tail = slice.slice_t(2); + EXPECT_EQ(head.size(), 2); + EXPECT_EQ(tail.size(), 3); + EXPECT_EQ(head.front(), 1); + EXPECT_EQ(head.back(), 2); + EXPECT_EQ(tail.front(), 3); + EXPECT_EQ(tail.back(), 5); + + head = slice.rslice_h(3); + tail = slice.rslice_t(3); + EXPECT_EQ(head.size(), 2); + EXPECT_EQ(tail.size(), 3); + EXPECT_EQ(head.front(), 1); + EXPECT_EQ(head.back(), 2); + EXPECT_EQ(tail.front(), 3); + EXPECT_EQ(tail.back(), 5); + + head = slice.islice_h(slice.begin() + 2); + tail = slice.islice_t(slice.end() - 3); + EXPECT_EQ(head.size(), 2); + EXPECT_EQ(tail.size(), 3); + EXPECT_EQ(head.front(), 1); + EXPECT_EQ(head.back(), 2); + EXPECT_EQ(tail.front(), 3); + EXPECT_EQ(tail.back(), 5); + + tail = slice.lslice(1, 3); + EXPECT_EQ(tail.size(), 3); + EXPECT_EQ(tail.front(), 2); + EXPECT_EQ(tail.back(), 4); + + tail = slice.pslice(1, 4); + EXPECT_EQ(tail.size(), 3); + EXPECT_EQ(tail.front(), 2); + EXPECT_EQ(tail.back(), 4); + + tail = slice.islice(slice.begin() + 1, slice.end() - 1); + EXPECT_EQ(tail.size(), 3); + EXPECT_EQ(tail.front(), 2); + EXPECT_EQ(tail.back(), 4); + + head = slice; + while (head) + { + size_t headsize = head.size(); + EXPECT_EQ(head.back(), headsize); + EXPECT_EQ(head.pop_back(), headsize); + } + + tail = slice; + while (!!tail) + { + size_t tailsize = tail.size(); + EXPECT_EQ(tail.front(), 6 - tailsize); + EXPECT_EQ(tail.pop_front(), 6 - tailsize); + } +} + +TEST(slice, cast) +{ + struct Foo + { + int x; + }; + struct Bar : Foo + { + }; + + Bar bars[2] = {Bar(), Bar()}; + + Slice<Bar> slice(bars, 2); + Slice<Foo> foos(slice); + + EXPECT_EQ(foos.size(), slice.size()); + EXPECT_EQ(&foos.end()[-1], &slice.end()[-1]); +} |