From 85245fe663953d20d1f84785936e47f09d8b757d Mon Sep 17 00:00:00 2001 From: Stephan Seitz <stephan.seitz@fau.de> Date: Fri, 8 Nov 2019 20:30:11 +0100 Subject: [PATCH] Add walberla::Variant --- src/core/Variant.h | 62 +++++++++++++++++++++++++++++ tests/core/CMakeLists.txt | 3 ++ tests/core/VariantTest.cpp | 81 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 src/core/Variant.h create mode 100644 tests/core/VariantTest.cpp diff --git a/src/core/Variant.h b/src/core/Variant.h new file mode 100644 index 000000000..6e4d580e4 --- /dev/null +++ b/src/core/Variant.h @@ -0,0 +1,62 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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) OPTIONAL later version. +// +// waLBerla is distributed in the hope that it will be useful, but WITHOUT +// OPTIONAL 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file Variant.h +//! \ingroup core +//! \author Stephan Seitz <stephan.seitz@fau.de> +// +//====================================================================================================================== + +#pragma once + + +#if __cpp_lib_variant +#define WALBERLA_USE_STD_VARIANT +#endif + +#if defined(WALBERLA_USE_STD_VARIANT) +#include <variant> +#else +#include <boost/variant.hpp> +#endif + + + +namespace walberla +{ + +#if defined(WALBERLA_USE_STD_VARIANT) +using std::variant; +using std::visit; +using std::get; +using std::holds_alternative; +using std::bad_variant_access; +#else +using boost::variant; +using boost::get; +template <class T, class... Types> +constexpr bool holds_alternative( const boost::variant<Types...>& v ) noexcept +{ + return v.type() == typeid( T ); +} +using bad_variant_access = boost::bad_get; +template<typename Visitor, typename... Variant> +decltype( auto ) visit( Visitor&& visitor, Variant&& ... variant ) +{ + return boost::apply_visitor( visitor, variant... ); +} +#endif + +} diff --git a/tests/core/CMakeLists.txt b/tests/core/CMakeLists.txt index 185fc8be0..fa77e164a 100644 --- a/tests/core/CMakeLists.txt +++ b/tests/core/CMakeLists.txt @@ -209,6 +209,9 @@ waLBerla_execute_test( NAME UNIQUEID PROCESSES 4) waLBerla_compile_test( FILES VersionTest.cpp ) waLBerla_execute_test( NAME VersionTest ) +waLBerla_compile_test( FILES VariantTest ) +waLBerla_execute_test( NAME VariantTest ) + ################## # load_balancing # ################## diff --git a/tests/core/VariantTest.cpp b/tests/core/VariantTest.cpp new file mode 100644 index 000000000..a879b5b98 --- /dev/null +++ b/tests/core/VariantTest.cpp @@ -0,0 +1,81 @@ +//====================================================================================================================== +// +// This file is part of waLBerla. waLBerla 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. +// +// waLBerla 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 waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>. +// +//! \file VariantTest.cpp +//! \ingroup core +//! \author Step +//! \brief Test if there are no typos in the collective header files "all.h" +// +//====================================================================================================================== + +#include "core/Variant.h" +#include "core/debug/all.h" + +#include <string> +#include <cassert> +#include <iostream> +#include <vector> + +using namespace std::literals; // C++ 14 +using var_t = walberla::variant<int, long, double, std::string>; + +int main( int /*argc*/, char** /*argv*/ ) +{ + walberla::debug::enterTestMode(); + + + + // Example from: https://en.cppreference.com/w/cpp/utility/variant (license (CC-BY-SA) and GPL) + walberla::variant<int, float> v, w; + v = 12; // v contains int + int i = walberla::get<int>( v ); +#ifdef WALBERLA_USE_STD_VARIANT + WALBERLA_CHECK( i == 12 ); // boost::variant cannot use == with variant and type +#endif + WALBERLA_CHECK( 0 == 12 - i ); + w = walberla::get<int>( v ); + w = v; +#ifdef WALBERLA_USE_STD_VARIANT + WALBERLA_CHECK( w == 12 ); // boost::variant cannot use == with variant and type +#endif + WALBERLA_CHECK( 0 == 12 - i ); + + // walberla::get<double>(v); // error: no double in [int, float] + // walberla::get<3>(v); // error: valid index values are 0 and 1 + + try { + walberla::get<float>( w ); // w contains int, not float: will throw + } catch ( const walberla::bad_variant_access& ) {} + + walberla::variant<std::string> x( "abc" ); // converting constructors work when unambiguous + x = "def"; // converting assignment also works when unambiguous + + std::cout << "hallo" << std::endl; + walberla::variant<std::string, bool> y( "abc" ); // casts to bool when passed a char const * + std::cout << "eoo" << std::endl; + WALBERLA_CHECK( walberla::holds_alternative<bool>( y ) ); // succeeds + y = "xyz"s; + WALBERLA_CHECK( walberla::holds_alternative<std::string>( y ) ); //succeeds + + std::cout << "bye" << std::endl; + std::vector<var_t> vec {10, 15l, 1.5, "hello"}; + + for ( auto& z : vec ) { + // 1. void visitor, only called for side-effects (here, for I/O) + walberla::visit( []( auto && arg ) {std::cout << arg;}, z ); + } + + return 0; +} -- GitLab