summaryrefslogtreecommitdiff
path: root/src/range
diff options
context:
space:
mode:
authorBen Longbons <b.r.longbons@gmail.com>2014-03-30 23:14:12 -0700
committerBen Longbons <b.r.longbons@gmail.com>2014-03-31 10:18:49 -0700
commit1a651243bb2c8e18baa9aac30ac52a62185074e7 (patch)
treedd2c0bfc448faef129fb64edec9f64d2ab12bfe5 /src/range
parent769e8ac9c17779a15492d7fcfc1931c014670c2d (diff)
downloadtmwa-1a651243bb2c8e18baa9aac30ac52a62185074e7.tar.gz
tmwa-1a651243bb2c8e18baa9aac30ac52a62185074e7.tar.bz2
tmwa-1a651243bb2c8e18baa9aac30ac52a62185074e7.tar.xz
tmwa-1a651243bb2c8e18baa9aac30ac52a62185074e7.zip
Be stricter about most arrays
Diffstat (limited to 'src/range')
-rw-r--r--src/range/slice.cpp1
-rw-r--r--src/range/slice.hpp74
-rw-r--r--src/range/slice.tcc216
-rw-r--r--src/range/slice_test.cpp89
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]);
+}