From 34807ca9fccc7425573256645024722571ef4442 Mon Sep 17 00:00:00 2001 From: Ben Longbons Date: Thu, 26 Jun 2014 10:27:47 -0700 Subject: specialize inventory/storage indices --- src/generic/array.hpp | 94 ++++++++++++++++++++++++--- src/generic/array_test.cpp | 159 +++++++++++++++++++++++++++++++++++++++++++++ src/generic/enum.hpp | 60 ++--------------- src/generic/oops.cpp | 45 +++++++++++++ src/generic/oops.hpp | 43 ++++++++++++ src/generic/oops_test.cpp | 50 ++++++++++++++ 6 files changed, 386 insertions(+), 65 deletions(-) create mode 100644 src/generic/array_test.cpp create mode 100644 src/generic/oops.cpp create mode 100644 src/generic/oops.hpp create mode 100644 src/generic/oops_test.cpp (limited to 'src/generic') 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 # include -template -struct Array +# include "oops.hpp" + +template +struct ExclusiveIndexing +{ + using index_type = I; + constexpr static size_t index_to_offset(index_type idx) + { return static_cast(idx) - static_cast(be); } + constexpr static index_type offset_to_index(size_t off) + { return static_cast(off + static_cast(be)); } + constexpr static size_t alloc_size = index_to_offset(en) - index_to_offset(be); +}; + +template +using SimpleIndexing = ExclusiveIndexing; + +template +struct InclusiveIndexing +{ + using index_type = I; + constexpr static size_t index_to_offset(index_type idx) + { return static_cast(idx) - static_cast(lo); } + constexpr static index_type offset_to_index(size_t off) + { return static_cast(off + static_cast(lo)); } + constexpr static size_t alloc_size = index_to_offset(hi) - index_to_offset(lo) + 1; +}; + +template +struct EnumIndexing : ExclusiveIndexing(0), n> { - T data[n]; +}; + +template +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 +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 +using Array = GenericArray>; + #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 +// +// 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 . + +#include + +#include "../poison.hpp" + + +TEST(Array, simple) +{ + GenericArray> 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> 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> 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> a; + try + { + a[static_cast(-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 -struct earray -{ - constexpr static - size_t size() - { - return static_cast(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(v); - assert (i < size()); - return _data[i]; - } - - const T& operator[](E v) const - { - auto i = static_cast(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 +using earray = GenericArray>; template class eptr @@ -102,7 +50,7 @@ public: {} eptr(earray& 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 +// +// 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 . + +#include +#include +#include + +//#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 +// +// 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 . + +# include "fwd.hpp" + +# include + +# include + +# 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 +// +// 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 . + +#include + +#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)"); + } +} -- cgit v1.2.3-60-g2f50