From 00da6b5977574a0564169172227d8aab45be188f Mon Sep 17 00:00:00 2001 From: Ben Longbons Date: Sat, 3 Jan 2015 21:07:56 -0800 Subject: Switch MATCH to separate begin/end macros The for loop trick turned out to be very prone to infinite loops at runtime. It's better to force compiler errors even if it's ugly. --- src/compat/attr.hpp | 24 ---------------------- src/compat/attr_test.cpp | 50 ---------------------------------------------- src/compat/option.hpp | 49 ++++++++++++++++++++++++++++++++++++--------- src/compat/option_test.cpp | 32 ++++++++++++++++++----------- 4 files changed, 60 insertions(+), 95 deletions(-) delete mode 100644 src/compat/attr_test.cpp (limited to 'src/compat') diff --git a/src/compat/attr.hpp b/src/compat/attr.hpp index 9ddf654..5ebef6d 100644 --- a/src/compat/attr.hpp +++ b/src/compat/attr.hpp @@ -30,28 +30,4 @@ namespace tmwa #endif #define JOIN(a, b) a##b - -// first loop: -// declare flag 'guard' (initially true) -// declare flag 'broken' (initially false) -// condition is 'guard' must be true, which is the case only for the first iteration -// post checks 'broken' and if set, break the loop -// second loop: -// declare public 'var' variable -// condition is that 'guard' must be true -// post sets 'guard' to false to make this loop run only once -// third loop: -// enable broken flag; it will remain set if 'break' is in the loop -// condition is that 'broken' must be true -// post sets 'broken' to false, which then fails the condition -// if user has a 'break' inside, then 'broken' will be true -// in either case, go back to the second loop's post -#define WITH_VAR_INLOOP(ty, var, expr) \ - for (bool JOIN(var, _guard) = true, JOIN(var, _broken) = false; JOIN(var, _guard); ({if (JOIN(var, _broken)) { break; } })) \ - for (ty var = expr; JOIN(var, _guard); JOIN(var, _guard) = false) \ - for (JOIN(var, _broken) = true; JOIN(var, _broken); JOIN(var, _broken) = false) -#define WITH_VAR_NOLOOP(ty, var, expr) \ - for (bool JOIN(var, _guard) = true, JOIN(var, _broken) = false; JOIN(var, _guard); ({if (JOIN(var, _broken)) {abort();} })) \ - for (ty var = expr; JOIN(var, _guard); JOIN(var, _guard) = false) \ - for (JOIN(var, _broken) = true; JOIN(var, _broken); JOIN(var, _broken) = false) } // namespace tmwa diff --git a/src/compat/attr_test.cpp b/src/compat/attr_test.cpp deleted file mode 100644 index eb9042d..0000000 --- a/src/compat/attr_test.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "attr.hpp" -// attr_test.cpp - Tests for attributes -// -// 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" - - -namespace tmwa -{ -TEST(attr, withvar) -{ - int x = 41; - for (int i = 0; i < 2; ++i) - { - WITH_VAR_NOLOOP(auto, y, x + 1) - { - x = y; - } - } - EXPECT_EQ(x, 43); - for (int i = 0; i < 2; ++i) - { - if (i == 1) - WITH_VAR_INLOOP(auto, y, i) - { - x = y; - break; - } - } - EXPECT_EQ(x, 1); -} -} // namespace tmwa diff --git a/src/compat/option.hpp b/src/compat/option.hpp index 7beef6f..b6e7655 100644 --- a/src/compat/option.hpp +++ b/src/compat/option.hpp @@ -24,8 +24,6 @@ #include -#include "attr.hpp" - namespace tmwa { @@ -423,13 +421,46 @@ namespace option if (o.maybe_ref.is_none()) falsy; \ tmwa::option::option_unwrap(std::move(o)); \ }).maybe_ref_fun() -// immediately preceded by 'if'; not double-eval-safe -#define OPTION_IS_SOME_INLOOP(var, expr) \ - ((expr).is_some()) \ - WITH_VAR_INLOOP(auto&, var, *(expr).ptr_or(nullptr)) -#define OPTION_IS_SOME_NOLOOP(var, expr) \ - ((expr).is_some()) \ - WITH_VAR_NOLOOP(auto&, var, *(expr).ptr_or(nullptr)) + +#define OMATCH_BEGIN(expr) \ + { \ + auto&& _omatch_var = (expr); \ + switch (_omatch_var.is_some()) \ + { \ + { \ + { \ + /*}}}}*/ +#define OMATCH_END() \ + /*{{{{*/ \ + } \ + } \ + } \ + (void) _omatch_var; \ + } + +#define OMATCH_BEGIN_SOME(var, expr) \ + OMATCH_BEGIN (expr) \ + OMATCH_CASE_SOME (var) + +#define OMATCH_CASE_SOME(var) \ + /*{{{{*/ \ + } \ + break; \ + } \ + { \ + case true: \ + { \ + auto&& var = *_omatch_var.ptr_or(nullptr); \ + /*}}}}*/ +#define OMATCH_CASE_NONE() \ + /*{{{{*/ \ + } \ + break; \ + } \ + { \ + case false: \ + { \ + /*}}}}*/ } // namespace option //using option::Option; diff --git a/src/compat/option_test.cpp b/src/compat/option_test.cpp index f9cec0e..69f3a60 100644 --- a/src/compat/option_test.cpp +++ b/src/compat/option_test.cpp @@ -398,24 +398,32 @@ TEST(Option, unwrap) v = None; TRY_UNWRAP(fcr(), v = Some(1)); v = None; - if OPTION_IS_SOME_NOLOOP(o, v) + OMATCH_BEGIN (v) { - EXPECT_NE(o, o); - } - else - { - SUCCEED(); + OMATCH_CASE_SOME (o) + { + EXPECT_NE(o, o); + } + OMATCH_CASE_NONE () + { + SUCCEED(); + } } + OMATCH_END (); v = Some(1); - if OPTION_IS_SOME_NOLOOP(o, v) + OMATCH_BEGIN (v) { - EXPECT_EQ(o, 1); - } - else - { - FAIL(); + OMATCH_CASE_SOME (o) + { + EXPECT_EQ(o, 1); + } + OMATCH_CASE_NONE () + { + FAIL(); + } } + OMATCH_END (); } TEST(Option, flatten) -- cgit v1.2.3-60-g2f50