diff options
Diffstat (limited to 'src/generic')
-rw-r--r-- | src/generic/array.hpp | 94 | ||||
-rw-r--r-- | src/generic/array_test.cpp | 159 | ||||
-rw-r--r-- | src/generic/enum.hpp | 60 | ||||
-rw-r--r-- | src/generic/oops.cpp | 45 | ||||
-rw-r--r-- | src/generic/oops.hpp | 43 | ||||
-rw-r--r-- | src/generic/oops_test.cpp | 50 |
6 files changed, 386 insertions, 65 deletions
diff --git a/src/generic/array.hpp b/src/generic/array.hpp index e6fefae..5e4dd67 100644 --- a/src/generic/array.hpp +++ b/src/generic/array.hpp @@ -24,18 +24,94 @@ # include <cassert> # include <cstddef> -template<class T, size_t n> -struct Array +# include "oops.hpp" + +template<class I, I be, I en> +struct ExclusiveIndexing +{ + using index_type = I; + constexpr static size_t index_to_offset(index_type idx) + { return static_cast<size_t>(idx) - static_cast<size_t>(be); } + constexpr static index_type offset_to_index(size_t off) + { return static_cast<I>(off + static_cast<size_t>(be)); } + constexpr static size_t alloc_size = index_to_offset(en) - index_to_offset(be); +}; + +template<size_t n> +using SimpleIndexing = ExclusiveIndexing<size_t, 0, n>; + +template<class I, I lo, I hi> +struct InclusiveIndexing +{ + using index_type = I; + constexpr static size_t index_to_offset(index_type idx) + { return static_cast<size_t>(idx) - static_cast<size_t>(lo); } + constexpr static index_type offset_to_index(size_t off) + { return static_cast<I>(off + static_cast<size_t>(lo)); } + constexpr static size_t alloc_size = index_to_offset(hi) - index_to_offset(lo) + 1; +}; + +template<class E, E n=E::COUNT> +struct EnumIndexing : ExclusiveIndexing<E, static_cast<E>(0), n> { - T data[n]; +}; + +template<class I, size_t limit> +struct InventoryIndexing +{ + using index_type = I; + constexpr static size_t index_to_offset(index_type idx) + { return idx.get0(); } + constexpr static index_type offset_to_index(size_t off) + { return I::from(off); } + constexpr static size_t alloc_size = limit; +}; + +template<class T, class I> +struct GenericArray +{ + T data[I::alloc_size]; public: - T& operator [](size_t i) { assert (i < n); return data[i]; } - const T& operator [](size_t i) const { assert (i < n); return data[i]; } + T *begin() + { return data + 0; } + T *end() + { return data + I::alloc_size; } + const T *begin() const + { return data + 0; } + const T *end() const + { return data + I::alloc_size; } + size_t size() const + { return I::alloc_size; } + + T& operator [](typename I::index_type i_) + { + size_t i = I::index_to_offset(i_); + ALLEGE ("index in bounds", i < size()); + return data[i]; + } + const T& operator [](typename I::index_type i_) const + { + size_t i = I::index_to_offset(i_); + ALLEGE ("index in bounds", i < size()); + return data[i]; + } - T *begin() { return data + 0; } - T *end() { return data + n; } - const T *begin() const { return data + 0; } - const T *end() const { return data + n; } + friend bool operator == (GenericArray& lhs, GenericArray& rhs) + { + for (size_t i = 0; i < I::alloc_size; ++i) + { + if (lhs.data[i] != rhs.data[i]) + return false; + } + return true; + } + friend bool operator != (GenericArray& lhs, GenericArray& rhs) + { + return !(lhs == rhs); + } }; +template<class T, size_t n> +using Array = GenericArray<T, SimpleIndexing<n>>; + #endif // TMWA_GENERIC_ARRAY_HPP diff --git a/src/generic/array_test.cpp b/src/generic/array_test.cpp new file mode 100644 index 0000000..7b5ffca --- /dev/null +++ b/src/generic/array_test.cpp @@ -0,0 +1,159 @@ +#include "array.hpp" +// array_test.cpp - Testsuite for a simple bounds-checked array. +// +// Copyright © 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 <gtest/gtest.h> + +#include "../poison.hpp" + + +TEST(Array, simple) +{ + GenericArray<int, SimpleIndexing<3>> a; + try + { + a[0]; + a[1]; + a[2]; + SUCCEED(); + } + catch (const AssertionError&) + { + FAIL(); + } + try + { + a[3]; + FAIL(); + } + catch (const AssertionError&) + { + SUCCEED(); + } +} + +TEST(Array, inclusive1) +{ + GenericArray<int, InclusiveIndexing<int, 1, 3>> a; + try + { + a[0]; + FAIL(); + } + catch (const AssertionError&) + { + SUCCEED(); + } + try + { + a[1]; + a[2]; + a[3]; + SUCCEED(); + } + catch (const AssertionError&) + { + FAIL(); + } + try + { + a[4]; + FAIL(); + } + catch (const AssertionError&) + { + SUCCEED(); + } +} + +TEST(Array, negative) +{ + GenericArray<int, InclusiveIndexing<int, -1, 1>> a; + try + { + a[-2]; + FAIL(); + } + catch (const AssertionError&) + { + SUCCEED(); + } + try + { + a[-1]; + a[0]; + a[1]; + SUCCEED(); + } + catch (const AssertionError&) + { + FAIL(); + } + try + { + a[2]; + FAIL(); + } + catch (const AssertionError&) + { + SUCCEED(); + } +} + +TEST(Array, enum) +{ + enum class Blah + { + FOO, + BAR, + BAZ, + COUNT, + }; + + GenericArray<int, EnumIndexing<Blah>> a; + try + { + a[static_cast<Blah>(-1)]; + FAIL(); + } + catch (const AssertionError&) + { + SUCCEED(); + } + try + { + a[Blah::FOO]; + a[Blah::BAR]; + a[Blah::BAZ]; + SUCCEED(); + } + catch (const AssertionError&) + { + FAIL(); + } + try + { + a[Blah::COUNT]; + FAIL(); + } + catch (const AssertionError&) + { + SUCCEED(); + } +} diff --git a/src/generic/enum.hpp b/src/generic/enum.hpp index 5f075bc..1e83c24 100644 --- a/src/generic/enum.hpp +++ b/src/generic/enum.hpp @@ -29,62 +29,10 @@ # include "../compat/iter.hpp" -template<class T, class E, E max> -struct earray -{ - constexpr static - size_t size() - { - return static_cast<size_t>(max); - } - - // no ctor/dtor and one public member variable for easy initialization - T _data[size()]; +# include "array.hpp" - T& operator[](E v) - { - auto i = static_cast<size_t>(v); - assert (i < size()); - return _data[i]; - } - - const T& operator[](E v) const - { - auto i = static_cast<size_t>(v); - assert (i < size()); - return _data[i]; - } - - T *begin() - { - return _data; - } - - T *end() - { - return _data + size(); - } - - const T *begin() const - { - return _data; - } - - const T *end() const - { - return _data + size(); - } - - friend bool operator == (const earray& l, const earray& r) - { - return std::equal(l.begin(), l.end(), r.begin()); - } - - friend bool operator != (const earray& l, const earray& r) - { - return !(l == r); - } -}; +template<class T, class E, E max> +using earray = GenericArray<T, EnumIndexing<E, max>>; template<class T, class E, E max> class eptr @@ -102,7 +50,7 @@ public: {} eptr(earray<T, E, max>& arr) - : _data(arr._data) + : _data(arr.data) {} T& operator [](E v) const diff --git a/src/generic/oops.cpp b/src/generic/oops.cpp new file mode 100644 index 0000000..95fdcad --- /dev/null +++ b/src/generic/oops.cpp @@ -0,0 +1,45 @@ +#include "oops.hpp" +// oops.cpp - Stuff that shouldn't happen. +// +// Copyright © 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 <cstdlib> +#include <cstring> +#include <cstdio> + +//#include "../poison.hpp" + + +static +std::string do_asprintf(const char *desc, const char *expr, + const char *file, size_t line, const char *function) +{ + char *what = nullptr; + int len = asprintf(&what, "%s:%zu: error: in '%s', incorrectly alleged that '%s' (%s)", + file, line, function, desc, expr); + if (len == -1) + abort(); + std::string out = what; + free(what); + return out; +} + +AssertionError::AssertionError(const char *desc, const char *expr, + const char *file, size_t line, const char *function) +: std::runtime_error(do_asprintf(desc, expr, file, line, function)) +{} diff --git a/src/generic/oops.hpp b/src/generic/oops.hpp new file mode 100644 index 0000000..231a4e4 --- /dev/null +++ b/src/generic/oops.hpp @@ -0,0 +1,43 @@ +#ifndef TMWA_GENERIC_OOPS_HPP +#define TMWA_GENERIC_OOPS_HPP +// oops.hpp - Stuff that shouldn't happen. +// +// Copyright © 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 "fwd.hpp" + +# include <cstddef> + +# include <stdexcept> + +# include "oops.hpp" + + +class AssertionError : public std::runtime_error +{ + const char *_what; +public: + AssertionError(const char *desc, const char *expr, + const char *file, size_t line, const char *function); +}; + +# define ALLEGE(desc, expr) \ + if (expr) {} \ + else throw AssertionError(desc, #expr, __FILE__, __LINE__, __PRETTY_FUNCTION__) + +#endif // TMWA_GENERIC_OOPS_HPP diff --git a/src/generic/oops_test.cpp b/src/generic/oops_test.cpp new file mode 100644 index 0000000..d16db04 --- /dev/null +++ b/src/generic/oops_test.cpp @@ -0,0 +1,50 @@ +#include "oops.hpp" +// oops_test.cpp - Testsuite for stuff that shouldn't happen. +// +// Copyright © 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 <gtest/gtest.h> + +#include "../poison.hpp" + +TEST(oops, okay) +{ + try + { + ALLEGE ("the sky is gray", true); + SUCCEED(); + } + catch (const AssertionError& e) + { + FAIL(); + } +} + +TEST(oops, uhoh) +{ + try + { + ALLEGE ("the sky is falling", 1 == 0); + FAIL(); + } + catch (const AssertionError& e) + { + ASSERT_STREQ(strstr(e.what(), "src/generic/"), + "src/generic/oops_test.cpp:42: error: in 'virtual void oops_uhoh_Test::TestBody()', incorrectly alleged that 'the sky is falling' (1 == 0)"); + } +} |