From 401bd1c6439bd9d77d36643722e29cde94a30e61 Mon Sep 17 00:00:00 2001 From: xDraconian Date: Thu, 21 Dec 2017 13:38:29 -0600 Subject: [PATCH 01/23] Simgear::test_bucket code coverage Lines: 82.1% >> 98.7% Functions: 83.0% >> 100.0% No memory leaks --- simgear/bucket/test_bucket.cxx | 146 +++++++++++++++++++++++++-------- 1 file changed, 112 insertions(+), 34 deletions(-) diff --git a/simgear/bucket/test_bucket.cxx b/simgear/bucket/test_bucket.cxx index 81990069..fd292a7d 100644 --- a/simgear/bucket/test_bucket.cxx +++ b/simgear/bucket/test_bucket.cxx @@ -53,7 +53,7 @@ void testBasic() SG_CHECK_EQUAL(b1.gen_index(), 3040320); SG_CHECK_EQUAL(b1.gen_base_path(), "e000n50/e005n55"); SG_VERIFY(b1.isValid()); - + SGBucket b2(-10.1, -43.8); SG_CHECK_EQUAL(b2.get_chunk_lon(), -11); SG_CHECK_EQUAL(b2.get_chunk_lat(), -44); @@ -62,7 +62,7 @@ void testBasic() SG_CHECK_EQUAL(b2.get_y(), 1); SG_CHECK_EQUAL(b2.gen_base_path(), "w020s50/w011s44"); SG_VERIFY(b2.isValid()); - + SGBucket b3(123.48, 9.01); SG_CHECK_EQUAL(b3.get_chunk_lon(), 123); SG_CHECK_EQUAL(b3.get_chunk_lat(), 9); @@ -70,10 +70,10 @@ void testBasic() SG_CHECK_EQUAL(b3.get_y(), 0); SG_CHECK_EQUAL(b3.gen_base_path(), "e120n00/e123n09"); SG_VERIFY(b3.isValid()); - + SGBucket defBuck; SG_VERIFY(!defBuck.isValid()); - + b3.make_bad(); SG_VERIFY(!b3.isValid()); @@ -87,19 +87,47 @@ void testBasic() SG_CHECK_EQUAL(atAntiMeridian2.get_chunk_lon(), -180); SG_CHECK_EQUAL(atAntiMeridian2.get_x(), 0); -// check comparisom operator overload + // check comparison operator overload SGBucket b4(5.11, 55.1); SG_VERIFY(b1 == b4); // should be equal SG_VERIFY(b1 == b1); SG_VERIFY(b1 != defBuck); SG_VERIFY(b1 != b2); - -// check wrapping/clipping of inputs + + // check wrapping/clipping of inputs SGBucket wrapMeridian(-200.0, 45.0); SG_CHECK_EQUAL(wrapMeridian.get_chunk_lon(), 160); SGBucket clipPole(48.9, 91); SG_CHECK_EQUAL(clipPole.get_chunk_lat(), 89); + + // test override of a bucket's geod + auto geod = SGGeod::fromDegFt(-86.678, 36.1248, 599.0); +#ifndef NO_DEPRECATED_API + SGBucket bna_airport; + bna_airport.set_bucket(geod); +#else + SGBucket bna_airport(geod); +#endif + SG_VERIFY(bna_airport.isValid()); + SG_CHECK_EQUAL(bna_airport.get_chunk_lon(), -87); // left origin of the 1-degree chunk + SG_CHECK_EQUAL(bna_airport.get_chunk_lat(), 36); // bottom origin of the 1-degree chunk + SG_CHECK_EQUAL(bna_airport.get_x(), 1); // buckets are 0.25 deg wide at the W87 parallel + // we're 0.322 deg from the origin (second bucket) + SG_CHECK_EQUAL(bna_airport.get_y(), 0); // buckets are always 0.125 deg tall + // we're 0.1248 deg from the origin (first bucket) + SG_CHECK_EQUAL(bna_airport.gen_base_path(), "w090n30/w087n36"); + SG_CHECK_EQUAL_EP2(bna_airport.get_width_m(), 22479.1, 0.1); + SG_CHECK_EQUAL_EP2(bna_airport.get_height_m(), 13914.9, 0.1); + SG_CHECK_EQUAL(bna_airport.gen_index_str(), "1531777"); // 0x175F81 = b01011101|01111110|000|001 + // = 93-180 | 126-90 | 0 | 1 + // = -87 | 36 | 0 | 1 + + // test stream output + cout << "[TEST] BNA Airport: " << bna_airport << endl; + auto center = bna_airport.get_center(); + cout << "[TEST] BNA lon: " << center.getLongitudeDeg() << endl; + cout << "[TEST] BNA lat: " << center.getLatitudeDeg() << endl; } void testPolar() @@ -110,17 +138,17 @@ void testPolar() SG_CHECK_EQUAL(b1.get_chunk_lon(), 0); SG_CHECK_EQUAL(b1.get_x(), 0); SG_CHECK_EQUAL(b1.get_y(), 7); - + SG_CHECK_EQUAL_EP(b1.get_highest_lat(), 90.0); SG_CHECK_EQUAL_EP(b1.get_width_m(), 10.0); - + SG_CHECK_EQUAL(b2.get_chunk_lat(), 89); SG_CHECK_EQUAL(b2.get_chunk_lon(), 0); SG_CHECK_EQUAL(b2.get_x(), 0); SG_CHECK_EQUAL(b2.get_y(), 7); - + SG_CHECK_EQUAL(b1.gen_index(), b2.gen_index()); - + SGGeod actualNorthPole1 = b1.get_corner(2); SGGeod actualNorthPole2 = b1.get_corner(3); SG_CHECK_EQUAL_EP(actualNorthPole1.getLatitudeDeg(), 90.0); @@ -131,11 +159,11 @@ void testPolar() SGBucket b3(-2, 89.88); SGBucket b4(-7, 89.88); SG_CHECK_EQUAL(b3.gen_index(), b4.gen_index()); - + // south pole SGBucket b5(-170, -89.88); SGBucket b6(-179, -89.88); - + SG_CHECK_EQUAL(b5.get_chunk_lat(), -90); SG_CHECK_EQUAL(b5.get_chunk_lon(), -180); SG_CHECK_EQUAL(b5.get_x(), 0); @@ -143,17 +171,16 @@ void testPolar() SG_CHECK_EQUAL(b5.gen_index(), b6.gen_index()); SG_CHECK_EQUAL_EP(b5.get_highest_lat(), -90.0); SG_CHECK_EQUAL_EP(b5.get_width_m(), 10.0); - + SGGeod actualSouthPole1 = b5.get_corner(0); SGGeod actualSouthPole2 = b5.get_corner(1); SG_CHECK_EQUAL_EP(actualSouthPole1.getLatitudeDeg(), -90.0); SG_CHECK_EQUAL_EP(actualSouthPole1.getLongitudeDeg(), -180); SG_CHECK_EQUAL_EP(actualSouthPole2.getLatitudeDeg(), -90.0); SG_CHECK_EQUAL_EP(actualSouthPole2.getLongitudeDeg(), -168); - + SGBucket b7(200, 89.88); SG_CHECK_EQUAL(b7.get_chunk_lon(), -168); - } // test the tiles just below the pole (between 86 & 89 degrees N/S) @@ -167,7 +194,7 @@ void testNearPolar() SGBucket b3(176.1, 88.5); SG_CHECK_EQUAL(b3.get_chunk_lon(), 176); - + SGBucket b4(-178, 88.5); SG_CHECK_EQUAL(b4.get_chunk_lon(), -180); } @@ -181,7 +208,7 @@ void testOffset() SG_CHECK_EQUAL(b1.get_chunk_lon(), -60); SG_CHECK_EQUAL(b1.get_x(), 1); SG_CHECK_EQUAL(b1.get_y(), 7); - + // offset vertically SGBucket b2(b1.sibling(0, 1)); SG_CHECK_EQUAL(b2.get_chunk_lat(), 22); @@ -190,7 +217,7 @@ void testOffset() SG_CHECK_EQUAL(b2.get_y(), 0); SG_CHECK_EQUAL(b2.gen_index(), sgBucketOffset(-59.8, 21.9, 0, 1)); - + // offset vertically and horizontally. We compute horizontal (x) // movement at the target latitude, so this should move 0.25 * -3 degrees, // NOT 0.125 * -3 degrees. @@ -199,7 +226,7 @@ void testOffset() SG_CHECK_EQUAL(b3.get_chunk_lon(), -61); SG_CHECK_EQUAL(b3.get_x(), 1); SG_CHECK_EQUAL(b3.get_y(), 0); - + SG_CHECK_EQUAL(b3.gen_index(), sgBucketOffset(-59.8, 21.9, -3, 1)); } @@ -210,40 +237,40 @@ void testPolarOffset() SG_CHECK_EQUAL(b1.get_chunk_lon(), -12); SG_CHECK_EQUAL(b1.get_x(), 0); SG_CHECK_EQUAL(b1.get_y(), 3); - + // offset horizontally SGBucket b2(b1.sibling(-2, 0)); SG_CHECK_EQUAL(b2.get_chunk_lat(), -90); SG_CHECK_EQUAL(b2.get_chunk_lon(), -36); SG_CHECK_EQUAL(b2.get_x(), 0); SG_CHECK_EQUAL(b2.get_y(), 3); - + SG_CHECK_EQUAL(b2.gen_index(), sgBucketOffset(-11.7, -89.6, -2, 0)); - -// offset and wrap + + // offset and wrap SGBucket b3(-170, 89.1); SGBucket b4(b3.sibling(-1, 0)); SG_CHECK_EQUAL(b4.get_chunk_lat(), 89); SG_CHECK_EQUAL(b4.get_chunk_lon(), 168); SG_CHECK_EQUAL(b4.get_x(), 0); SG_CHECK_EQUAL(b4.get_y(), 0); - + SG_CHECK_EQUAL(b4.gen_index(), sgBucketOffset(-170, 89.1, -1, 0)); - + SGBucket b5(177, 87.3); SGBucket b6(b5.sibling(1, 1)); SG_CHECK_EQUAL(b6.get_chunk_lat(), 87); SG_CHECK_EQUAL(b6.get_chunk_lon(), -180); SG_CHECK_EQUAL(b6.get_x(), 0); SG_CHECK_EQUAL(b6.get_y(), 3); - + SG_CHECK_EQUAL(b6.gen_index(), sgBucketOffset(177, 87.3, 1, 1)); // offset vertically towards the pole SGBucket b7(b1.sibling(0, -5)); SG_VERIFY(!b7.isValid()); - + SG_VERIFY(!SGBucket(0, 90).sibling(0, 1).isValid()); } @@ -256,29 +283,80 @@ void testOffsetWrap() SG_CHECK_EQUAL(b1.get_chunk_lon(), -180); SG_CHECK_EQUAL(b1.get_x(), 1); SG_CHECK_EQUAL(b1.get_y(), 6); - + SGBucket b2(b1.sibling(-2, 0)); SG_CHECK_EQUAL(b2.get_chunk_lat(), 16); SG_CHECK_EQUAL(b2.get_chunk_lon(), 179); SG_CHECK_EQUAL(b2.get_x(), 7); SG_CHECK_EQUAL(b2.get_y(), 6); SG_CHECK_EQUAL(b2.gen_index(), sgBucketOffset(-179.8, 16.8, -2, 0)); - - +} + +void testSiblings() +{ + SGBucket bna_airport(-86.678, 36.1248); + SG_VERIFY(bna_airport.isValid()); + + // retrieve the sibling two positions north-east of my position + auto sib1 = bna_airport.sibling(2, 2); + SG_CHECK_EQUAL(sib1.get_chunk_lon(), bna_airport.get_chunk_lon()); + SG_CHECK_EQUAL(sib1.get_chunk_lat(), bna_airport.get_chunk_lat()); + SG_CHECK_EQUAL(sib1.get_x(), 3); // my x-pos (1) + 2 = 3 + SG_CHECK_EQUAL(sib1.get_y(), 2); // my y-pos (0) + 2 = 2 + SG_CHECK_EQUAL(sib1.gen_base_path(), bna_airport.gen_base_path()); + + // retrieve the one sibling two positions to the north-east + std::vector siblings; + bna_airport.siblings(2, 2, siblings); + SG_CHECK_EQUAL(siblings.size(), static_cast::size_type>(1)); + siblings.clear(); + + // retrieve the one sibling at the chunk origin of sib1 + sib1.siblings(-2, -2, siblings); + SG_CHECK_EQUAL(siblings.size(), static_cast::size_type>(1)); + siblings.clear(); + + // calculate delta between two buckets + int dx = 0; + int dy = 0; + sgBucketDiff(bna_airport, sib1, &dx, &dy); + SG_CHECK_EQUAL(dx, 2); + SG_CHECK_EQUAL(dy, 2); + + // retrieve all siblings between two geodetic locations + auto geod_bna = SGGeod::fromDegFt(-86.678, 36.1248, 599.0); + auto geod_m54 = SGGeod::fromDegFt(-86.317, 36.1908, 122.0); + sgGetBuckets(geod_bna, geod_m54, siblings); + SG_CHECK_EQUAL(siblings.size(), static_cast::size_type>(4)); + siblings.clear(); + + // edge cases + + // ensure you cannot retrieve the sibling of an invalid bucket + SGBucket bad; + auto bad_sib = bad.sibling(1, 1); + SG_CHECK_EQUAL(bad_sib.get_chunk_lon(), -1000); + SG_CHECK_EQUAL(bad.siblings(2, 2, siblings), 0); + + // if we drop below the 22nd parallel, the bucket widths are half the size + // expect this to retrieve two buckets + bna_airport.siblings(0, -160, siblings); + SG_CHECK_EQUAL(siblings.size(), static_cast::size_type>(2)); + siblings.clear(); } int main(int argc, char* argv[]) { testBucketSpans(); - + testBasic(); testPolar(); testNearPolar(); testOffset(); testOffsetWrap(); testPolarOffset(); - + testSiblings(); + cout << "all tests passed OK" << endl; return 0; // passed } - From ab1e2d49abdf5b1aca9035a51d9d73d687f0eba7 Mon Sep 17 00:00:00 2001 From: Florent Rougon Date: Fri, 29 Dec 2017 13:46:42 +0100 Subject: [PATCH 02/23] Add a CMake check for a working implementation Define HAVE_WORKING_STD_REGEX if, and only if is usable. Normally, should be available and working in any compliant C++11 implementation, however at least g++ 4.8[1] lies about its C++11 compliance: its is utterly unusable, see [2] and [3] for details. [1] Which appears to be (precisely 4.8.5) the version shipped in CentOS 7, and used on FlightGear's current Jenkins installation. [2] https://stackoverflow.com/a/12665408/4756009 [3] https://sourceforge.net/p/flightgear/mailman/message/36170781/ --- CMakeLists.txt | 27 +++++++++++++++++++++++++++ simgear/simgear_config_cmake.h.in | 1 + 2 files changed, 28 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e15718b6..bbf4e46c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -351,6 +351,33 @@ if (NOT ${HAVE_STD_ISNAN}) message(FATAL_ERROR "Your compiler lacks C++11 std::isnan, please update it") endif() +# Check if the implementation in the C++ standard library is usable. +# This is necessary because g++ 4.8 lies about its C++11 compliance: its +# is utterly unusable, cf. [1]. +# The big preprocessor test essentially comes from [2], and gcc upstream devs +# appear to back it (see comments following [2], as well as [3]). +# +# [1] https://stackoverflow.com/a/12665408/4756009 +# [2] https://stackoverflow.com/a/41186162/4756009 +# [3] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78905 +check_cxx_source_compiles( + "#include + #include + +int main() { + #if __cplusplus >= 201103L && \ + (!defined(__GLIBCXX__) || \ + (__cplusplus >= 201402L) || \ + defined(_GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT) || \ + defined(_GLIBCXX_REGEX_STATE_LIMIT) || \ + (defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE > 4)) + return EXIT_SUCCESS; + #else + nullptr = void; // intentionally trigger a compilation error + #endif +}" + HAVE_WORKING_STD_REGEX) + if(CMAKE_COMPILER_IS_GNUCXX) set(WARNING_FLAGS_CXX "-Wall -fPIC") set(WARNING_FLAGS_C "-Wall -fPIC") diff --git a/simgear/simgear_config_cmake.h.in b/simgear/simgear_config_cmake.h.in index ba28e761..0282aca1 100644 --- a/simgear/simgear_config_cmake.h.in +++ b/simgear/simgear_config_cmake.h.in @@ -11,6 +11,7 @@ #cmakedefine HAVE_TIMEGM #cmakedefine HAVE_STD_ISNAN +#cmakedefine HAVE_WORKING_STD_REGEX #cmakedefine HAVE_WINDOWS_H #cmakedefine HAVE_MKDTEMP #cmakedefine HAVE_AL_EXT_H From 52b8f6095363d2646eaeab9ad84915ed9002fcc4 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Fri, 22 Dec 2017 08:49:21 +0100 Subject: [PATCH 03/23] Add std::index_sequence for C++11 Will be required for nasal::Ghost --- CMakeLists.txt | 26 +++++--- simgear/misc/CMakeLists.txt | 4 ++ simgear/misc/integer_sequence.hxx | 86 ++++++++++++++++++++++++++ simgear/misc/integer_sequence_test.cxx | 47 ++++++++++++++ simgear/simgear_config_cmake.h.in | 2 +- 5 files changed, 156 insertions(+), 9 deletions(-) create mode 100644 simgear/misc/integer_sequence.hxx create mode 100644 simgear/misc/integer_sequence_test.cxx diff --git a/CMakeLists.txt b/CMakeLists.txt index bbf4e46c..9f1a0b2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,6 +135,16 @@ include (DetectArch) # keep the compatability link option as the default option(OSG_FSTREAM_EXPORT_FIXED "Set to ON if the osgDB fstream export patch is applied" OFF) +if (CMAKE_COMPILER_IS_GNUCXX OR CLANG) + if (CMAKE_VERSION VERSION_LESS 3.1) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++${CMAKE_CXX_STANDARD}") + elseif (CMAKE_VERSION VERSION_LESS 3.8) + # policy CMP0067 (try_compile does not honor CMAKE_CXX_STANDARD) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++${CMAKE_CXX_STANDARD}") + endif() +endif() + + if (MSVC) GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_BINARY_DIR} PATH) if (CMAKE_CL_64) @@ -382,10 +392,6 @@ if(CMAKE_COMPILER_IS_GNUCXX) set(WARNING_FLAGS_CXX "-Wall -fPIC") set(WARNING_FLAGS_C "-Wall -fPIC") - if (CMAKE_VERSION VERSION_LESS 3.1) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - endif() - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4) message(WARNING "GCC 4.4 will be required soon, please upgrade") endif() @@ -413,10 +419,6 @@ if (CLANG) # fix Boost compilation :( set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") - if (CMAKE_VERSION VERSION_LESS 3.1) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - endif() - if(ENABLE_SIMD) if (X86 OR X86_64) set(CMAKE_C_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse") @@ -489,6 +491,14 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS_C} ${MSVC_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS_CXX} ${MSVC_FLAGS} ${BOOST_CXX_FLAGS}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MSVC_LD_FLAGS}") +check_cxx_source_compiles(" + #include + #include + std::make_index_sequence<0> t; + int main() { return 0; }" + HAVE_STD_INDEX_SEQUENCE +) + # use BEFORE to ensure local directories are used first, # ahead of system-installed libs include_directories(BEFORE ${PROJECT_BINARY_DIR}/simgear) diff --git a/simgear/misc/CMakeLists.txt b/simgear/misc/CMakeLists.txt index 2931a3b3..3c5bfedd 100644 --- a/simgear/misc/CMakeLists.txt +++ b/simgear/misc/CMakeLists.txt @@ -56,6 +56,10 @@ add_executable(test_CSSBorder CSSBorder_test.cxx) add_test(CSSBorder ${EXECUTABLE_OUTPUT_PATH}/test_CSSBorder) target_link_libraries(test_CSSBorder ${TEST_LIBS}) +add_executable(test_integer_sequence integer_sequence_test.cxx) +add_test(integer_sequence ${EXECUTABLE_OUTPUT_PATH}/test_integer_sequence) +target_link_libraries(test_integer_sequence ${TEST_LIBS}) + add_executable(test_tabbed_values tabbed_values_test.cxx) add_test(tabbed_values ${EXECUTABLE_OUTPUT_PATH}/test_tabbed_values) target_link_libraries(test_tabbed_values ${TEST_LIBS}) diff --git a/simgear/misc/integer_sequence.hxx b/simgear/misc/integer_sequence.hxx new file mode 100644 index 00000000..300fc9ea --- /dev/null +++ b/simgear/misc/integer_sequence.hxx @@ -0,0 +1,86 @@ +///@file +/// Metaprogramming Integer sequence (Is in C++14 but not C++11) +// +// Copyright (C) 2017 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SIMGEAR_MISC_INTEGER_SEQUENCE_HXX_ +#define SIMGEAR_MISC_INTEGER_SEQUENCE_HXX_ + +#include +#include + +#ifndef HAVE_STD_INDEX_SEQUENCE +# include + +namespace std +{ + template + struct integer_sequence + { + static_assert( + std::is_integral::value, + "std::integer_sequence can only be instantiated with an an integral type" + ); + + typedef T value_type; + static constexpr size_t size() noexcept { return sizeof...(Ints); } + }; +} + +namespace simgear { namespace detail +{ + template + struct append; + + template + struct append, Int> + { + using type = std::integer_sequence; + }; + + template + struct sequence_gen + { + using type = + typename append::type, N - 1>::type; + }; + + template + struct sequence_gen + { + using type = std::integer_sequence; + }; +}} + +namespace std +{ + template + using index_sequence = integer_sequence; + + template + using make_integer_sequence = + typename simgear::detail::sequence_gen::type; + + template + using make_index_sequence = make_integer_sequence; + + template + using index_sequence_for = make_index_sequence; +} +#endif + +#endif /* SIMGEAR_MISC_INTEGER_SEQUENCE_HXX_ */ diff --git a/simgear/misc/integer_sequence_test.cxx b/simgear/misc/integer_sequence_test.cxx new file mode 100644 index 00000000..82463f50 --- /dev/null +++ b/simgear/misc/integer_sequence_test.cxx @@ -0,0 +1,47 @@ +#include "integer_sequence.hxx" + +#include + +template +void print(const T& v, std::size_t i) +{ + std::cout << "arg #" << i << ": '" << v << "', "; +} + +template +void doIt_impl(Args ... args, std::index_sequence) +{ + std::initializer_list{(print(args, Is), '0')...}; +} + +template +void doIt(Args ... args) +{ + static_assert(sizeof...(Args) == std::index_sequence_for::size(), ""); + + doIt_impl(args..., std::index_sequence_for{}); +} + +int main(int argc, char* argv[]) +{ + static_assert(std::is_same::value_type, char>::value, ""); + static_assert(std::is_same::value_type, long long>::value, ""); + static_assert(std::is_same::value_type, std::size_t>::value, ""); + + static_assert(std::is_same, std::index_sequence<>>::value, ""); + static_assert(std::is_same, std::index_sequence<0>>::value, ""); + static_assert(std::is_same, std::index_sequence<0, 1>>::value, ""); + static_assert(std::is_same, std::index_sequence<0, 1, 2>>::value, ""); + static_assert(std::is_same, std::index_sequence<0, 1, 2, 3>>::value, ""); + static_assert(std::is_same, std::index_sequence<0, 1, 2, 3, 4>>::value, ""); + static_assert(std::is_same, std::index_sequence<0, 1, 2, 3, 4, 5>>::value, ""); + static_assert(std::is_same, std::index_sequence<0, 1, 2, 3, 4, 5, 6>>::value, ""); + static_assert(std::is_same, std::index_sequence<0, 1, 2, 3, 4, 5, 6, 7>>::value, ""); + + static_assert(std::make_index_sequence<5>::size() == 5, ""); + static_assert(std::index_sequence_for::size() == 3, ""); + + std::cout << std::make_integer_sequence::size() << std::endl; + doIt(1, 2, 3, "hallo", 3.4, 3.52f); + return 0; +} diff --git a/simgear/simgear_config_cmake.h.in b/simgear/simgear_config_cmake.h.in index 0282aca1..b68991da 100644 --- a/simgear/simgear_config_cmake.h.in +++ b/simgear/simgear_config_cmake.h.in @@ -15,7 +15,7 @@ #cmakedefine HAVE_WINDOWS_H #cmakedefine HAVE_MKDTEMP #cmakedefine HAVE_AL_EXT_H - +#cmakedefine HAVE_STD_INDEX_SEQUENCE #cmakedefine GCC_ATOMIC_BUILTINS_FOUND From ebd2cdb7a712190b1e6f6c4a1e82e780b8c55042 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Tue, 2 Jan 2018 09:12:38 +0100 Subject: [PATCH 04/23] SGPickAnimation: fix member initialization order --- simgear/scene/model/SGPickAnimation.cxx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/simgear/scene/model/SGPickAnimation.cxx b/simgear/scene/model/SGPickAnimation.cxx index e5408007..6551500f 100644 --- a/simgear/scene/model/SGPickAnimation.cxx +++ b/simgear/scene/model/SGPickAnimation.cxx @@ -77,9 +77,9 @@ osg::Vec2d eventToWindowCoords(const osgGA::GUIEventAdapter& ea) SGPropertyNode* modelRoot, SGSharedPtr condition) : SGPickCallback(PriorityPanel), + _condition(condition), _repeatable(configNode->getBoolValue("repeatable", false)), - _repeatInterval(configNode->getDoubleValue("interval-sec", 0.1)), - _condition(condition) + _repeatInterval(configNode->getDoubleValue("interval-sec", 0.1)) { std::vector bindings; @@ -264,7 +264,8 @@ public: SGPropertyNode* modelRoot, osg::Group *node, SGSharedPtr condition) - : _node(node), _condition(condition) + : _condition(condition) + , _node(node) { SG_LOG(SG_INPUT, SG_DEBUG, "Configuring VNC callback"); const char *cornernames[3] = {"top-left", "top-right", "bottom-left"}; @@ -765,7 +766,8 @@ private: class SGKnobAnimation::UpdateCallback : public osg::NodeCallback { public: UpdateCallback(SGExpressiond const* animationValue, SGSharedPtr condition) : - _animationValue(animationValue), _condition(condition) + _condition(condition), + _animationValue(animationValue) { setName("SGKnobAnimation::UpdateCallback"); } @@ -899,9 +901,9 @@ class TouchPickCallback : public SGPickCallback { public: TouchPickCallback(const SGPropertyNode* configNode, SGPropertyNode* modelRoot) : + SGPickCallback(PriorityPanel), _repeatable(configNode->getBoolValue("repeatable", false)), - _repeatInterval(configNode->getDoubleValue("interval-sec", 0.1)), - SGPickCallback(PriorityPanel) + _repeatInterval(configNode->getDoubleValue("interval-sec", 0.1)) { std::vector bindings; From ca30d6bb3d8686b29c3d1716d5c69b811a0c8a3b Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Tue, 2 Jan 2018 11:36:37 +0100 Subject: [PATCH 05/23] Add missing simgear_config.h include Required for HAVE_STD_INDEX_SEQUENCE to be properly set. --- simgear/misc/integer_sequence.hxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/simgear/misc/integer_sequence.hxx b/simgear/misc/integer_sequence.hxx index 300fc9ea..7f372785 100644 --- a/simgear/misc/integer_sequence.hxx +++ b/simgear/misc/integer_sequence.hxx @@ -20,6 +20,8 @@ #ifndef SIMGEAR_MISC_INTEGER_SEQUENCE_HXX_ #define SIMGEAR_MISC_INTEGER_SEQUENCE_HXX_ +#include + #include #include From 7547ad0391f71c15961590430ee1ba7ee098810a Mon Sep 17 00:00:00 2001 From: Florent Rougon Date: Wed, 3 Jan 2018 00:34:52 +0100 Subject: [PATCH 06/23] Improve formatting of the HAVE_WORKING_STD_REGEX test Indent the test code in a nicer way and shorten it, taking advantage of this guarantee from the C++ standard: If control reaches the end of main without encountering a return statement, the effect is that of executing return 0. -> no need for "#include " nor for "return EXIT_SUCCESS". --- CMakeLists.txt | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f1a0b2a..da7fb268 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -372,20 +372,18 @@ endif() # [3] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78905 check_cxx_source_compiles( "#include - #include -int main() { - #if __cplusplus >= 201103L && \ - (!defined(__GLIBCXX__) || \ - (__cplusplus >= 201402L) || \ - defined(_GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT) || \ - defined(_GLIBCXX_REGEX_STATE_LIMIT) || \ - (defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE > 4)) - return EXIT_SUCCESS; - #else - nullptr = void; // intentionally trigger a compilation error - #endif -}" + int main() { + #if __cplusplus >= 201103L && \ + (!defined(__GLIBCXX__) || \ + (__cplusplus >= 201402L) || \ + defined(_GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT) || \ + defined(_GLIBCXX_REGEX_STATE_LIMIT) || \ + (defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE > 4)) + #else + nullptr = void; // intentionally trigger a compilation error + #endif + }" HAVE_WORKING_STD_REGEX) if(CMAKE_COMPILER_IS_GNUCXX) From e7356223bbc3aaba7e605252f1104fc41329ff65 Mon Sep 17 00:00:00 2001 From: Alessandro Menti Date: Wed, 3 Jan 2018 11:54:04 +0100 Subject: [PATCH 07/23] CMakeLists.txt: explicitly enable the CMP0067 (C/C++ standard flags) policy Explicitly enable the CMP0067 policy to have try_compile use the correct C/C++ standard flags; otherwise, CMake will default to not honoring those, causing the C/C++ checks to be compiled with no standard flags and SimGear to be compiled with them. This causes errors if we try to detect a new prototype which is only present in C++14 and above). --- CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index da7fb268..8d2e049b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,9 @@ if(COMMAND cmake_policy) if(POLICY CMP0042) cmake_policy(SET CMP0042 NEW) endif() + if(POLICY CMP0067) + cmake_policy(SET CMP0067 NEW) + endif() endif() From 7f7c6329146a354ab760238151635da3272d3266 Mon Sep 17 00:00:00 2001 From: xDraconian Date: Sat, 30 Dec 2017 08:56:17 -0600 Subject: [PATCH 08/23] Simgear::test_precipitation test coverage Lines: 0.0% >> 92.3% Functions: 0.0% >> 97.1% Memory leaks resolved - reclaiming 169kb in 126 blocks No memory leaks remain --- simgear/environment/precipitation.cxx | 23 +- simgear/environment/precipitation.hxx | 4 +- simgear/environment/test_precipitation.cxx | 239 +++++++++++++++++++++ 3 files changed, 252 insertions(+), 14 deletions(-) create mode 100644 simgear/environment/test_precipitation.cxx diff --git a/simgear/environment/precipitation.cxx b/simgear/environment/precipitation.cxx index 8ffa2210..1a2b8130 100644 --- a/simgear/environment/precipitation.cxx +++ b/simgear/environment/precipitation.cxx @@ -7,7 +7,7 @@ * * @brief Precipitation effects to draw rain and snow. * - * @par Licences + * @par License * 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 2 of the @@ -25,7 +25,6 @@ */ #include "precipitation.hxx" -//#include "visual_enviro.hxx" #include #include @@ -65,7 +64,7 @@ bool SGPrecipitation::getEnabled() const */ osg::Group* SGPrecipitation::build(void) { - osg::Group* group = new osg::Group; + osg::ref_ptr group = new osg::Group; _precipitationEffect->snow(0); _precipitationEffect->rain(0); @@ -73,8 +72,9 @@ osg::Group* SGPrecipitation::build(void) if (_clip_distance!=0.0) { osg::ref_ptr clipNode = new osg::ClipNode; - clipNode->addClipPlane( new osg::ClipPlane( 0 ) ); - clipNode->getClipPlane(0)->setClipPlane( 0.0, 0.0, -1.0, -_clip_distance ); + osg::ref_ptr clipPlane = new osg::ClipPlane(0); + clipNode->addClipPlane(clipPlane.get()); + clipNode->getClipPlane(0)->setClipPlane(0.0, 0.0, -1.0, -_clip_distance); clipNode->setReferenceFrame(osg::ClipNode::ABSOLUTE_RF); clipNode->addChild(_precipitationEffect.get()); @@ -87,7 +87,7 @@ osg::Group* SGPrecipitation::build(void) group->setNodeMask( ~(simgear::CASTSHADOW_BIT | simgear::MODELLIGHT_BIT) ); - return group; + return group.release(); } @@ -140,8 +140,8 @@ void SGPrecipitation::setRainDropletSize(float size) /** * @brief Define the illumination multiplier * - * This function permits you to define and change the rain droplet size - * which is used if external droplet size control is enabled + * This function permits you to define and change the brightness + * of the precipitation. */ void SGPrecipitation::setIllumination(float illumination) @@ -163,10 +163,9 @@ void SGPrecipitation::setSnowFlakeSize(float size) /** - * @brief Define the rain droplet size + * @brief Define the clip plane distance * - * This function permits you to define and change the rain droplet size - * which is used if external droplet size control is enabled + * This function permits you to define and change the clip plane distance. */ void SGPrecipitation::setClipDistance(float distance) @@ -224,7 +223,7 @@ void SGPrecipitation::setWindProperty(double heading, double speed) * Be careful, if snow and rain intensity are greater than '0', snow effect * will be first. * - * The settings come from the osgParticule/PrecipitationEffect.cpp exemple. + * The settings come from the osgParticle/PrecipitationEffect.cpp example. */ bool SGPrecipitation::update(void) { diff --git a/simgear/environment/precipitation.hxx b/simgear/environment/precipitation.hxx index fb3e2b59..6207a8d9 100644 --- a/simgear/environment/precipitation.hxx +++ b/simgear/environment/precipitation.hxx @@ -34,7 +34,7 @@ class SGPrecipitation : public osg::Referenced { -private: +protected: bool _freeze; bool _enabled; bool _droplet_external; @@ -66,7 +66,7 @@ public: void setIllumination(float); void setClipDistance(float); - void setEnabled( bool ); + void setEnabled(bool); bool getEnabled() const; }; diff --git a/simgear/environment/test_precipitation.cxx b/simgear/environment/test_precipitation.cxx new file mode 100644 index 00000000..5b7d2096 --- /dev/null +++ b/simgear/environment/test_precipitation.cxx @@ -0,0 +1,239 @@ +/************************************************************************** + * test_precipitation.cxx -- unit-tests for SGPrecipitation class + * + * Copyright (C) 2017 Scott Giese (xDraconian) - + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + **************************************************************************/ + +#include +#include + +#include + +#include +#include + +#include "precipitation.hxx" + +using std::cout; +using std::cerr; +using std::endl; + + +class SGPrecipitationTestFixture : public SGPrecipitation +{ +public: + osg::ref_ptr _group; + + void test_configuration() + { + _group = build(); + + SG_VERIFY(getEnabled()); + SG_VERIFY(_precipitationEffect); + SG_CHECK_EQUAL_EP(_rain_intensity, 0.0f); + SG_CHECK_EQUAL_EP(_snow_intensity, 0.0f); + SG_VERIFY(!_freeze); + } + + void test_rain() + { + int count = 500; + + do { + if (--count == 0) { + cerr << "error: method setRainIntensity took too long."; + exit(EXIT_FAILURE); + } + + float saveRainIntensity = _rain_intensity; + + setRainIntensity(0.4f); + update(); + + SG_CHECK_GE(_rain_intensity, saveRainIntensity); + } while (std::fabs(_rain_intensity - 0.4f) > 0.00001f); + + SG_CHECK_EQUAL_EP2(_rain_intensity, 0.4f, 0.00001f); + } + + void test_rain_external() + { + int count = 500; + + do { + if (--count == 0) { + cerr << "error: method setRainIntensity-external took too long."; + exit(EXIT_FAILURE); + } + + float saveRainIntensity = _rain_intensity; + + setRainIntensity(0.25f); + update(); + + SG_CHECK_LE(_rain_intensity, saveRainIntensity); + } while (std::fabs(_rain_intensity - 0.25f) > 0.00001f); + + // call once more to ensure we have intensity precisely set + setRainIntensity(0.25f); + update(); + + SG_CHECK_EQUAL_EP2(_rain_intensity, 0.25f, 0.00001f); + } + + void test_freeze() + { + float saveParticleSize = _precipitationEffect->getParticleSize(); + float saveParticleSpeed = std::fabs(_precipitationEffect->getParticleSpeed()); + + // change rain to snow + // expect particle size to increase + // expect particle speed to decrease + setFreezing(true); + update(); + + SG_CHECK_GT(_precipitationEffect->getParticleSize(), saveParticleSize); + SG_CHECK_LT(std::fabs(_precipitationEffect->getParticleSpeed()), saveParticleSpeed); + } + + void test_snow() + { + int count = 500; + + do { + if (--count == 0) { + cerr << "error: method setSnowIntensity took too long."; + exit(EXIT_FAILURE); + } + + float saveSnowIntensity = _snow_intensity; + + // not a typo - when freezing is enabled, snow intensity is keep in sync with rain intensity + setRainIntensity(0.3f); + update(); + + SG_CHECK_LE(_snow_intensity, saveSnowIntensity); + } while (std::fabs(_snow_intensity - 0.3f) > 0.00001f); + + SG_CHECK_EQUAL_EP2(_snow_intensity, 0.3f, 0.00001f); + } + + void test_snow_external() + { + setRainDropletSize(0.025f); + setSnowFlakeSize(0.04f); + setDropletExternal(true); + + int count = 600; + + do { + if (--count == 0) { + cerr << "error: method setSnowIntensity-external took too long."; + exit(EXIT_FAILURE); + } + + float saveSnowIntensity = _snow_intensity; + + setSnowIntensity(0.55f); + update(); + + SG_CHECK_GE(_snow_intensity, saveSnowIntensity); + } while (std::fabs(_snow_intensity - 0.55f) > 0.00001f); + + // call once more to ensure we have intensity precisely set + setSnowIntensity(0.55f); + update(); + + SG_CHECK_EQUAL_EP2(_snow_intensity, 0.55f, 0.00001f); + } + + void test_unfreeze() + { + float saveParticleSize = _precipitationEffect->getParticleSize(); + float saveParticleSpeed = std::fabs(_precipitationEffect->getParticleSpeed()); + + // change snow to rain + // expect particle size to decrease + // expect particle speed to increase + setFreezing(false); + update(); + + SG_CHECK_LT(_precipitationEffect->getParticleSize(), saveParticleSize); + SG_CHECK_GT(std::fabs(_precipitationEffect->getParticleSpeed()), saveParticleSpeed); + } + + void test_no_precipitation() + { + setEnabled(false); + SG_VERIFY(!getEnabled()); + + update(); + + // intensity drops to zero, so we should see this reflected in the particles + SG_CHECK_EQUAL_EP(_precipitationEffect->getParticleSize(), 0.01f); + SG_CHECK_EQUAL_EP(_precipitationEffect->getParticleSpeed(), -2.0f); + + setEnabled(true); + } + + void test_illumination() + { + setIllumination(0.87f); + SG_CHECK_EQUAL_EP(_illumination, 0.87f); + } + + void test_clipping() + { + setClipDistance(6.5); + SG_CHECK_EQUAL_EP(_clip_distance, 6.5f); + } + + void test_wind() + { + setWindProperty(87.0f, 0.7f); + auto vec = _wind_vec; + SG_CHECK_EQUAL_EP2(vec[0], 0.011166f, 0.00001f); + SG_CHECK_EQUAL_EP2(vec[1], -0.213068f, 0.00001f); + SG_CHECK_EQUAL_EP2(vec[2], 0.0f, 0.00001f); + } +}; + + +int main(int argc, char* argv[]) +{ + auto fixture = std::unique_ptr(new SGPrecipitationTestFixture); + + fixture->test_configuration(); + fixture->test_rain(); + fixture->test_freeze(); + fixture->test_snow(); + fixture->test_unfreeze(); + fixture->test_no_precipitation(); + + fixture->test_snow_external(); + fixture->test_rain_external(); + fixture->test_illumination(); + fixture->test_clipping(); + fixture->test_wind(); + fixture->test_no_precipitation(); + + cout << "all tests passed OK" << endl; + + return EXIT_SUCCESS; +} From a88b9181b67f2a64fe990542e208f4b4e1f828e1 Mon Sep 17 00:00:00 2001 From: xDraconian Date: Thu, 4 Jan 2018 08:18:43 +0100 Subject: [PATCH 09/23] Enable the test 'test_precipitation' --- simgear/environment/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/simgear/environment/CMakeLists.txt b/simgear/environment/CMakeLists.txt index 4c499af6..ddb53166 100644 --- a/simgear/environment/CMakeLists.txt +++ b/simgear/environment/CMakeLists.txt @@ -21,4 +21,9 @@ else() endif() add_test(metar ${EXECUTABLE_OUTPUT_PATH}/test_metar) + +add_executable(test_precipitation test_precipitation.cxx) +target_link_libraries(test_precipitation ${TEST_LIBS}) +add_test(precipitation ${EXECUTABLE_OUTPUT_PATH}/test_precipitation) + endif(ENABLE_TESTS) From da099d431268f2ab1084f332f4331a64758b902f Mon Sep 17 00:00:00 2001 From: James Turner Date: Sun, 7 Jan 2018 16:10:50 +0000 Subject: [PATCH 10/23] Correct use of remove_if in the test-server Should fix erratic crashes of some tests. --- simgear/io/test_HTTP.hxx | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/simgear/io/test_HTTP.hxx b/simgear/io/test_HTTP.hxx index 11b25171..3cb925c0 100644 --- a/simgear/io/test_HTTP.hxx +++ b/simgear/io/test_HTTP.hxx @@ -183,15 +183,6 @@ public: int requestContentLength; }; -class EraseIfClosed -{ -public: - bool operator()(simgear::NetChannel* chan) const - { - return chan->isClosed(); - } -}; - template class TestServer : public NetChannel { @@ -202,7 +193,6 @@ public: { Socket::initSockets(); - open(); bind(NULL, 2000); // localhost, any port listen(16); @@ -212,6 +202,7 @@ public: virtual ~TestServer() { + _poller.removeChannel(this); } virtual bool writable (void) { return false ; } @@ -231,15 +222,16 @@ public: { _poller.poll(); - typename std::vector::iterator it; - it = std::remove_if(_channels.begin(), _channels.end(), EraseIfClosed()); - - for (typename std::vector::iterator it2 = it; it2 != _channels.end(); ++it2) { - delete *it2; - } + auto it = std::remove_if(_channels.begin(), _channels.end(), [&](T* channel) { + if (channel->isClosed()) { + _poller.removeChannel(channel); + delete channel; + return true; + } + return false; + }); _channels.erase(it, _channels.end()); - } int connectCount() From 455753c77476bc3e8922a85be56a357bff709602 Mon Sep 17 00:00:00 2001 From: Florent Rougon Date: Mon, 8 Jan 2018 10:26:18 +0100 Subject: [PATCH 11/23] Simplify code in NetChannelPoller::removeChannel() Remove an apparently bogus portability workaround (which was presumably targetting one of the bugs fixed in the previous commit [1]) and further simplify the code using std::find(). [1] https://sourceforge.net/p/flightgear/simgear/ci/da099d431268f2ab1084f332f4331a64758b902f/ --- simgear/io/sg_netChannel.cxx | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/simgear/io/sg_netChannel.cxx b/simgear/io/sg_netChannel.cxx index a4a3d221..44673e11 100644 --- a/simgear/io/sg_netChannel.cxx +++ b/simgear/io/sg_netChannel.cxx @@ -32,10 +32,12 @@ #include #include "sg_netChannel.hxx" +#include #include + #include +#include #include -#include #include @@ -258,18 +260,10 @@ NetChannelPoller::removeChannel(NetChannel* channel) assert(channel); assert(channel->poller == this); channel->poller = NULL; - - // portability: MSVC throws assertion failure when empty - if (channels.empty()) { - return; - } - ChannelList::iterator it = channels.begin(); - for (; it != channels.end(); ++it) { - if (*it == channel) { - channels.erase(it); - return; - } + auto it = std::find(channels.begin(), channels.end(), channel); + if (it != channels.end()) { + channels.erase(it); } } From 99ee3d9deceaa2d8939e7e6e6832727f66f68706 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Tue, 9 Jan 2018 09:16:02 +0100 Subject: [PATCH 12/23] cppbind: nasal::Context refactoring and doxygen improvements. --- simgear/nasal/cppbind/Ghost.hxx | 4 +- simgear/nasal/cppbind/NasalCallContext.hxx | 30 +--- simgear/nasal/cppbind/NasalContext.cxx | 61 +++++-- simgear/nasal/cppbind/NasalContext.hxx | 75 +++++++-- simgear/nasal/cppbind/NasalString.hxx | 2 +- .../cppbind/detail/from_nasal_helper.hxx | 2 +- simgear/nasal/cppbind/test/TestContext.hxx | 59 ++++--- simgear/nasal/cppbind/test/cppbind_test.cxx | 153 +++++++++--------- simgear/nasal/cppbind/test/nasal_gc_test.cxx | 2 +- simgear/nasal/nasal.h | 25 +-- 10 files changed, 243 insertions(+), 170 deletions(-) diff --git a/simgear/nasal/cppbind/Ghost.hxx b/simgear/nasal/cppbind/Ghost.hxx index c1875bf6..bab88891 100644 --- a/simgear/nasal/cppbind/Ghost.hxx +++ b/simgear/nasal/cppbind/Ghost.hxx @@ -770,7 +770,7 @@ namespace nasal /** * Register anything that accepts an object instance and a - * nasal::CallContext whith automatic conversion of the return type to + * nasal::CallContext with automatic conversion of the return type to * Nasal. * * @code{cpp} @@ -1148,7 +1148,7 @@ namespace nasal const CallContext& ctx ) { - return (*to_nasal_ptr::get())(ctx.c, func(obj, ctx)); + return (*to_nasal_ptr::get())(ctx.c_ctx(), func(obj, ctx)); }; /** diff --git a/simgear/nasal/cppbind/NasalCallContext.hxx b/simgear/nasal/cppbind/NasalCallContext.hxx index ea4e1967..a7781eac 100644 --- a/simgear/nasal/cppbind/NasalCallContext.hxx +++ b/simgear/nasal/cppbind/NasalCallContext.hxx @@ -20,8 +20,7 @@ #ifndef SG_NASAL_CALL_CONTEXT_HXX_ #define SG_NASAL_CALL_CONTEXT_HXX_ -#include "from_nasal.hxx" -#include "to_nasal.hxx" +#include "NasalContext.hxx" namespace nasal { @@ -29,11 +28,12 @@ namespace nasal /** * Context passed to a function/method being called from Nasal */ - class CallContext + class CallContext: + public ContextWrapper { public: CallContext(naContext c, naRef me, size_t argc, naRef* args): - c(c), + ContextWrapper(c), me(me), argc(argc), args(args) @@ -102,28 +102,14 @@ namespace nasal requireArg(size_t index) const { if( index >= argc ) - naRuntimeError(c, "Missing required arg #%d", index); + runtimeError("Missing required arg #%d", index); return from_nasal(args[index]); } - template - naRef to_nasal(T arg) const - { - return nasal::to_nasal(c, arg); - } - - template - typename from_nasal_ptr::return_type - from_nasal(naRef ref) const - { - return (*from_nasal_ptr::get())(c, ref); - } - - naContext c; - naRef me; - size_t argc; - naRef *args; + naRef me; + size_t argc; + naRef *args; }; } // namespace nasal diff --git a/simgear/nasal/cppbind/NasalContext.cxx b/simgear/nasal/cppbind/NasalContext.cxx index d2a82d88..fe0e4755 100644 --- a/simgear/nasal/cppbind/NasalContext.cxx +++ b/simgear/nasal/cppbind/NasalContext.cxx @@ -17,13 +17,59 @@ // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA #include "NasalContext.hxx" +#include "NasalHash.hxx" +#include "NasalString.hxx" + +#include namespace nasal { + //---------------------------------------------------------------------------- + ContextWrapper::ContextWrapper(naContext ctx): + _ctx(ctx) + { + assert(_ctx); + } + + //---------------------------------------------------------------------------- + ContextWrapper::operator naContext() + { + return _ctx; + } + + //---------------------------------------------------------------------------- + naContext ContextWrapper::c_ctx() const + { + return const_cast(_ctx); + } + + //---------------------------------------------------------------------------- + Hash ContextWrapper::newHash() + { + return Hash(_ctx); + } + + //---------------------------------------------------------------------------- + String ContextWrapper::newString(const char* str) + { + return String(_ctx, str); + } + + //---------------------------------------------------------------------------- + naRef ContextWrapper::newVector(std::initializer_list vals) + { + naRef vec = naNewVector(_ctx); + naVec_setsize(_ctx, vec, vals.size()); + int i = 0; + for(naRef val: vals) + naVec_set(vec, i++, val); + return vec; + } + //---------------------------------------------------------------------------- Context::Context(): - _ctx(naNewContext()) + ContextWrapper(naNewContext()) { } @@ -32,18 +78,7 @@ namespace nasal Context::~Context() { naFreeContext(_ctx); - } - - //---------------------------------------------------------------------------- - Context::operator naContext() - { - return _ctx; - } - - //---------------------------------------------------------------------------- - Hash Context::newHash() - { - return Hash(_ctx); + _ctx = nullptr; } } // namespace nasal diff --git a/simgear/nasal/cppbind/NasalContext.hxx b/simgear/nasal/cppbind/NasalContext.hxx index c5e8e56c..e9379c9f 100644 --- a/simgear/nasal/cppbind/NasalContext.hxx +++ b/simgear/nasal/cppbind/NasalContext.hxx @@ -19,26 +19,83 @@ #ifndef SG_NASAL_CONTEXT_HXX_ #define SG_NASAL_CONTEXT_HXX_ -#include "NasalHash.hxx" +#include "from_nasal.hxx" +#include "to_nasal.hxx" namespace nasal { + class Hash; + class String; /** - * Manage lifetime and encapsulate a Nasal context. + * Wraps a nasal ::naContext without taking ownership/managing its lifetime */ - class Context + class ContextWrapper + { + public: + explicit ContextWrapper(naContext ctx); + + operator naContext(); + + /** Convert to non-const ::naContext for usage with C-APIs */ + naContext c_ctx() const; + + Hash newHash(); + String newString(const char* str); + + /** Create a new nasal vector and fill it with the given values */ + template + naRef newVector(Vals ... vals) + { + return newVector({to_nasal(vals)...}); + } + + /** Raise a nasal runtime error */ + template + void runtimeError(const char* fmt, Args ... args) const + { + naRuntimeError(c_ctx(), fmt, args...); + } + + template + naRef to_nasal(T arg) const + { + return nasal::to_nasal(_ctx, arg); + } + + template + naRef to_nasal(const T(&array)[N]) const + { + return nasal::to_nasal(_ctx, array); + } + + template + typename from_nasal_ptr::return_type + from_nasal(naRef ref) const + { + return (*from_nasal_ptr::get())(_ctx, ref); + } + + protected: + naContext _ctx; + + // Not exposed to avoid confusion of intializer_list to variadic + // arguments + naRef newVector(std::initializer_list vals); + }; + + /** + * Creates and manages the lifetime of a ::naContext + */ + class Context: + public ContextWrapper { public: Context(); ~Context(); - operator naContext(); - - Hash newHash(); - - protected: - naContext _ctx; + Context(const Context&) = delete; + Context& operator=(const Context&) = delete; }; } // namespace nasal diff --git a/simgear/nasal/cppbind/NasalString.hxx b/simgear/nasal/cppbind/NasalString.hxx index 81153f23..4e593aab 100644 --- a/simgear/nasal/cppbind/NasalString.hxx +++ b/simgear/nasal/cppbind/NasalString.hxx @@ -47,7 +47,7 @@ namespace nasal * * @param str Existing Nasal String */ - String(naRef str); + explicit String(naRef str); const char* c_str() const; const char* begin() const; diff --git a/simgear/nasal/cppbind/detail/from_nasal_helper.hxx b/simgear/nasal/cppbind/detail/from_nasal_helper.hxx index ecfeb2ff..3cf03dd2 100644 --- a/simgear/nasal/cppbind/detail/from_nasal_helper.hxx +++ b/simgear/nasal/cppbind/detail/from_nasal_helper.hxx @@ -84,7 +84,7 @@ namespace nasal { naRef _ref; - Me(naRef ref): + Me(naRef ref = naNil()): _ref(ref) {} diff --git a/simgear/nasal/cppbind/test/TestContext.hxx b/simgear/nasal/cppbind/test/TestContext.hxx index 69c2113e..5a90d590 100644 --- a/simgear/nasal/cppbind/test/TestContext.hxx +++ b/simgear/nasal/cppbind/test/TestContext.hxx @@ -20,50 +20,29 @@ #ifndef SG_NASAL_TESTCONTEXT_HXX_ #define SG_NASAL_TESTCONTEXT_HXX_ -#include +#include class TestContext: - public nasal::CallContext + public nasal::Context { public: - TestContext(): - CallContext(naNewContext(), naNil(), 0, 0) - {} - - ~TestContext() - { - naFreeContext(c); - } - void runGC() { - naFreeContext(c); + naFreeContext(_ctx); naGC(); - c = naNewContext(); + _ctx = naNewContext(); } - template - T from_str(const std::string& str) + template + T exec(const std::string& code, nasal::Me me) { - return from_nasal(to_nasal(str)); + return from_nasal(execImpl(code, me)); } - naRef exec(const std::string& code_str, nasal::Me me) - { - int err_line = -1; - naRef code = naParseCode( c, to_nasal(""), 0, - (char*)code_str.c_str(), code_str.length(), - &err_line ); - if( !naIsCode(code) ) - throw std::runtime_error("Failed to parse code: " + code_str); - - return naCallMethod(code, me, 0, 0, naNil()); - } - - template + template T exec(const std::string& code) { - return from_nasal(exec(code, naNil())); + return from_nasal(execImpl(code, {})); } template @@ -71,6 +50,26 @@ class TestContext: { return from_nasal(to_nasal(str)); } + + protected: + naRef execImpl(const std::string& code_str, nasal::Me me) + { + int err_line = -1; + naRef code = naParseCode( _ctx, to_nasal(""), 0, + (char*)code_str.c_str(), code_str.length(), + &err_line ); + if( !naIsCode(code) ) + throw std::runtime_error("Failed to parse code: " + code_str); + + naRef ret = naCallMethod(code, me, 0, 0, naNil()); + + if( char* err = naGetError(_ctx) ) + throw std::runtime_error( + "Failed to executed code: " + std::string(err) + ); + + return ret; + } }; #endif /* SG_NASAL_TESTCONTEXT_HXX_ */ diff --git a/simgear/nasal/cppbind/test/cppbind_test.cxx b/simgear/nasal/cppbind/test/cppbind_test.cxx index b4371f18..397c4e35 100644 --- a/simgear/nasal/cppbind/test/cppbind_test.cxx +++ b/simgear/nasal/cppbind/test/cppbind_test.cxx @@ -1,6 +1,8 @@ #define BOOST_TEST_MODULE cppbind #include +#include "TestContext.hxx" + #include #include #include @@ -117,42 +119,42 @@ naRef f_freeFunction(nasal::CallContext c) { return c.requireArg(0); } BOOST_AUTO_TEST_CASE( cppbind_misc_testing ) { - naContext c = naNewContext(); + TestContext c; naRef r; using namespace nasal; - r = to_nasal(c, ENUM_ANOTHER); - BOOST_CHECK_EQUAL(from_nasal(c, r), ENUM_ANOTHER); + r = c.to_nasal(ENUM_ANOTHER); + BOOST_CHECK_EQUAL(c.from_nasal(r), ENUM_ANOTHER); - r = to_nasal(c, "Test"); + r = c.to_nasal("Test"); BOOST_CHECK( strncmp("Test", naStr_data(r), naStr_len(r)) == 0 ); - BOOST_CHECK_EQUAL(from_nasal(c, r), "Test"); + BOOST_CHECK_EQUAL(c.from_nasal(r), "Test"); - r = to_nasal(c, std::string("Test")); + r = c.to_nasal(std::string("Test")); BOOST_CHECK( strncmp("Test", naStr_data(r), naStr_len(r)) == 0 ); - BOOST_CHECK_EQUAL(from_nasal(c, r), "Test"); + BOOST_CHECK_EQUAL(c.from_nasal(r), "Test"); - r = to_nasal(c, 42); + r = c.to_nasal(42); BOOST_CHECK_EQUAL(naNumValue(r).num, 42); - BOOST_CHECK_EQUAL(from_nasal(c, r), 42); + BOOST_CHECK_EQUAL(c.from_nasal(r), 42); - r = to_nasal(c, 4.2f); + r = c.to_nasal(4.2f); BOOST_CHECK_EQUAL(naNumValue(r).num, 4.2f); - BOOST_CHECK_EQUAL(from_nasal(c, r), 4.2f); + BOOST_CHECK_EQUAL(c.from_nasal(r), 4.2f); float test_data[3] = {0, 4, 2}; - r = to_nasal(c, test_data); + r = c.to_nasal(test_data); SGVec2f vec(0,2); - r = to_nasal(c, vec); - BOOST_CHECK_EQUAL(from_nasal(c, r), vec); + r = c.to_nasal(vec); + BOOST_CHECK_EQUAL(c.from_nasal(r), vec); std::vector std_vec; - r = to_nasal(c, std_vec); + r = c.to_nasal(std_vec); - r = to_nasal(c, "string"); - BOOST_CHECK_THROW(from_nasal(c, r), bad_nasal_cast); + r = c.to_nasal("string"); + BOOST_CHECK_THROW(c.from_nasal(r), bad_nasal_cast); Hash hash(c); hash.set("vec", r); @@ -171,10 +173,10 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing ) it1 = it2; it3 = it2; - r = to_nasal(c, hash); + r = c.to_nasal(hash); BOOST_REQUIRE( naIsHash(r) ); - simgear::StringMap string_map = from_nasal(c, r); + simgear::StringMap string_map = c.from_nasal(r); BOOST_CHECK_EQUAL(string_map.at("vec"), "string"); BOOST_CHECK_EQUAL(string_map.at("name"), "my-name"); BOOST_CHECK_EQUAL(string_map.at("string"), "blub"); @@ -260,81 +262,81 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing ) Ghost::init("SGWeakRefBasedPtr"); SGWeakRefBasedPtr weak_ptr(new SGWeakReferenceBasedClass()); - naRef nasal_ref = to_nasal(c, weak_ptr), - nasal_ptr = to_nasal(c, weak_ptr.get()); + naRef nasal_ref = c.to_nasal(weak_ptr), + nasal_ptr = c.to_nasal(weak_ptr.get()); BOOST_REQUIRE( naIsGhost(nasal_ref) ); BOOST_REQUIRE( naIsGhost(nasal_ptr) ); - SGWeakRefBasedPtr ptr1 = from_nasal(c, nasal_ref), - ptr2 = from_nasal(c, nasal_ptr); + SGWeakRefBasedPtr ptr1 = c.from_nasal(nasal_ref), + ptr2 = c.from_nasal(nasal_ptr); BOOST_CHECK_EQUAL(weak_ptr, ptr1); BOOST_CHECK_EQUAL(weak_ptr, ptr2); BOOST_REQUIRE( Ghost::isInit() ); - nasal::to_nasal(c, DoubleDerived2Ptr()); + c.to_nasal(DoubleDerived2Ptr()); BasePtr d( new Derived ); - naRef derived = to_nasal(c, d); + naRef derived = c.to_nasal(d); BOOST_REQUIRE( naIsGhost(derived) ); BOOST_CHECK_EQUAL( std::string("DerivedPtr"), naGhost_type(derived)->name ); // Get member function from ghost... naRef thisGetter = naNil(); - BOOST_CHECK( naMember_get(c, derived, to_nasal(c, "this"), &thisGetter) ); + BOOST_CHECK( naMember_get(c, derived, c.to_nasal("this"), &thisGetter) ); BOOST_CHECK( naIsFunc(thisGetter) ); // ...and check if it really gets passed the correct instance typedef boost::function MemFunc; - MemFunc fGetThis = from_nasal(c, thisGetter); + MemFunc fGetThis = c.from_nasal(thisGetter); BOOST_REQUIRE( fGetThis ); BOOST_CHECK_EQUAL( fGetThis(derived), (unsigned long)d.get() ); BasePtr d2( new DoubleDerived ); - derived = to_nasal(c, d2); + derived = c.to_nasal(d2); BOOST_CHECK( naIsGhost(derived) ); BOOST_CHECK_EQUAL( std::string("DoubleDerivedPtr"), naGhost_type(derived)->name ); BasePtr d3( new DoubleDerived2 ); - derived = to_nasal(c, d3); + derived = c.to_nasal(d3); BOOST_CHECK( naIsGhost(derived) ); BOOST_CHECK_EQUAL( std::string("DoubleDerived2Ptr"), naGhost_type(derived)->name ); SGRefBasedPtr ref_based( new SGReferenceBasedClass ); - naRef na_ref_based = to_nasal(c, ref_based.get()); + naRef na_ref_based = c.to_nasal(ref_based.get()); BOOST_CHECK( naIsGhost(na_ref_based) ); - BOOST_CHECK_EQUAL( from_nasal(c, na_ref_based), + BOOST_CHECK_EQUAL( c.from_nasal(na_ref_based), ref_based.get() ); - BOOST_CHECK_EQUAL( from_nasal(c, na_ref_based), ref_based ); + BOOST_CHECK_EQUAL( c.from_nasal(na_ref_based), ref_based ); - BOOST_CHECK_EQUAL( from_nasal(c, derived), d3 ); - BOOST_CHECK_NE( from_nasal(c, derived), d2 ); - BOOST_CHECK_EQUAL( from_nasal(c, derived), + BOOST_CHECK_EQUAL( c.from_nasal(derived), d3 ); + BOOST_CHECK_NE( c.from_nasal(derived), d2 ); + BOOST_CHECK_EQUAL( c.from_nasal(derived), boost::dynamic_pointer_cast(d3) ); - BOOST_CHECK_EQUAL( from_nasal(c, derived), + BOOST_CHECK_EQUAL( c.from_nasal(derived), boost::dynamic_pointer_cast(d3) ); - BOOST_CHECK_THROW( from_nasal(c, derived), bad_nasal_cast ); + BOOST_CHECK_THROW( c.from_nasal(derived), bad_nasal_cast ); std::map instances; - BOOST_CHECK( naIsHash(to_nasal(c, instances)) ); + BOOST_CHECK( naIsHash(c.to_nasal(instances)) ); std::map instances_d; - BOOST_CHECK( naIsHash(to_nasal(c, instances_d)) ); + BOOST_CHECK( naIsHash(c.to_nasal(instances_d)) ); std::map int_map; - BOOST_CHECK( naIsHash(to_nasal(c, int_map)) ); + BOOST_CHECK( naIsHash(c.to_nasal(int_map)) ); std::map > int_vector_map; - BOOST_CHECK( naIsHash(to_nasal(c, int_vector_map)) ); + BOOST_CHECK( naIsHash(c.to_nasal(int_vector_map)) ); simgear::StringMap dict = simgear::StringMap("hello", "value") ("key2", "value2"); - naRef na_dict = to_nasal(c, dict); + naRef na_dict = c.to_nasal(dict); BOOST_REQUIRE( naIsHash(na_dict) ); BOOST_CHECK_EQUAL( Hash(na_dict, c).get("key2"), "value2" ); @@ -346,65 +348,44 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing ) Hash obj(c); obj.set("parents", parents); - BOOST_CHECK_EQUAL( from_nasal(c, obj.get_naRef()), d3 ); + BOOST_CHECK_EQUAL( c.from_nasal(obj.get_naRef()), d3 ); // Check recursive parents (aka parent-of-parent) std::vector parents2; parents2.push_back(obj.get_naRef()); Hash derived_obj(c); derived_obj.set("parents", parents2); - BOOST_CHECK_EQUAL( from_nasal(c, derived_obj.get_naRef()), d3 ); + BOOST_CHECK_EQUAL( c.from_nasal(derived_obj.get_naRef()), d3 ); std::vector nasal_objects; nasal_objects.push_back( Ghost::makeGhost(c, d) ); nasal_objects.push_back( Ghost::makeGhost(c, d2) ); nasal_objects.push_back( Ghost::makeGhost(c, d3) ); - naRef obj_vec = to_nasal(c, nasal_objects); + naRef obj_vec = c.to_nasal(nasal_objects); - std::vector objects = from_nasal >(c, obj_vec); + std::vector objects = c.from_nasal >(obj_vec); BOOST_CHECK_EQUAL( objects[0], d ); BOOST_CHECK_EQUAL( objects[1], d2 ); BOOST_CHECK_EQUAL( objects[2], d3 ); - { - // Calling fallback setter for unset values - const char* src_code = "me.test = 3;"; - int errLine = -1; - naRef code = naParseCode( c, to_nasal(c, "source.nas"), 0, - (char*)src_code, strlen(src_code), - &errLine ); - ret = naCallMethod(code, derived, 0, 0, naNil()); + // Calling fallback setter for unset values + BOOST_CHECK_EQUAL( c.exec("me.test = 3;", derived), 3 ); - BOOST_REQUIRE( !naGetError(c) ); // TODO real error check (this seems to - // always return 0... - BOOST_CHECK_EQUAL( from_nasal(c, ret), 3 ); - } - { - // Calling generic (fallback) getter - const char* src_code = "var a = me.get_test;"; - int errLine = -1; - naRef code = naParseCode( c, to_nasal(c, "source.nas"), 0, - (char*)src_code, strlen(src_code), - &errLine ); - ret = naCallMethod(code, derived, 0, 0, naNil()); - - BOOST_REQUIRE( !naGetError(c) ); // TODO real error check (this seems to - // always return 0... - BOOST_CHECK_EQUAL( from_nasal(c, ret), "generic-get" ); - } + // Calling generic (fallback) getter + BOOST_CHECK_EQUAL( c.exec("var a = me.get_test;", derived), + "generic-get" ); //---------------------------------------------------------------------------- // Test nasal::CallContext //---------------------------------------------------------------------------- - int int_vec[] = {1,2,3}; std::map map; naRef args[] = { - to_nasal(c, std::string("test-arg")), - to_nasal(c, 4), - to_nasal(c, int_vec), - to_nasal(c, map) + c.to_nasal(std::string("test-arg")), + c.to_nasal(4), + c.to_nasal(int_vec), + c.to_nasal(map) }; CallContext cc(c, naNil(), sizeof(args)/sizeof(args[0]), args); BOOST_CHECK_EQUAL( cc.requireArg(0), "test-arg" ); @@ -419,15 +400,15 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing ) BOOST_CHECK( cc.isVector(2) ); BOOST_CHECK( cc.isHash(3) ); - naRef args_vec = nasal::to_nasal(c, args); + naRef args_vec = c.to_nasal(args); BOOST_CHECK( naIsVector(args_vec) ); //---------------------------------------------------------------------------- // Test nasal::String //---------------------------------------------------------------------------- - String string( to_nasal(c, "Test") ); - BOOST_CHECK_EQUAL( from_nasal(c, string.get_naRef()), "Test" ); + String string( c.to_nasal("Test") ); + BOOST_CHECK_EQUAL( c.from_nasal(string.get_naRef()), "Test" ); BOOST_CHECK_EQUAL( string.c_str(), std::string("Test") ); BOOST_CHECK( string.starts_with(string) ); BOOST_CHECK( string.starts_with(String(c, "T")) ); @@ -453,6 +434,16 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing ) BOOST_CHECK_EQUAL( string.find_first_not_of(String(c, "Tse"), 2), 3 ); BOOST_CHECK_EQUAL( string.find_first_not_of(String(c, "abc")), 0 ); BOOST_CHECK_EQUAL( string.find_first_not_of(String(c, "abc"), 20), String::npos ); - - naFreeContext(c); +} + +BOOST_AUTO_TEST_CASE( cppbind_context ) +{ + nasal::Context ctx; + naRef vec = ctx.newVector(1, 2, 3.4, "test"); + BOOST_REQUIRE( naIsVector(vec) ); + + BOOST_CHECK_EQUAL(ctx.from_nasal(naVec_get(vec, 0)), 1); + BOOST_CHECK_EQUAL(ctx.from_nasal(naVec_get(vec, 1)), 2); + BOOST_CHECK_EQUAL(ctx.from_nasal(naVec_get(vec, 2)), 3.4); + BOOST_CHECK_EQUAL(ctx.from_nasal(naVec_get(vec, 3)), "test"); } diff --git a/simgear/nasal/cppbind/test/nasal_gc_test.cxx b/simgear/nasal/cppbind/test/nasal_gc_test.cxx index 0d6e2e09..8288e671 100644 --- a/simgear/nasal/cppbind/test/nasal_gc_test.cxx +++ b/simgear/nasal/cppbind/test/nasal_gc_test.cxx @@ -25,7 +25,7 @@ static naGhostType ghost_type = { static naRef createTestGhost(TestContext& c, intptr_t p) { active_instances.insert(p); - return naNewGhost(c.c, &ghost_type, (void*)p); + return naNewGhost(c, &ghost_type, (void*)p); } //------------------------------------------------------------------------------ diff --git a/simgear/nasal/nasal.h b/simgear/nasal/nasal.h index 7be9bb4f..6f3e3bfa 100644 --- a/simgear/nasal/nasal.h +++ b/simgear/nasal/nasal.h @@ -1,3 +1,6 @@ +///@file +/// The Nasal scripting language +/// #ifndef _NASAL_H #define _NASAL_H #ifdef __cplusplus @@ -15,12 +18,14 @@ extern "C" { #define GCC_PURE #endif +/** Nasal context pointer */ typedef struct Context* naContext; -// The function signature for an extension function: +/** Function signature for an extension function */ typedef naRef (*naCFunction)(naContext ctx, naRef me, int argc, naRef* args); -// The function signature for an extension function with userdata passed back: +/** Function signature for an extension function with @p user_data passed back + */ typedef naRef (*naCFunctionU) (naContext ctx, naRef me, int argc, naRef* args, void* user_data); @@ -258,7 +263,7 @@ void naHash_set(naRef hash, naRef key, naRef val); void naHash_cset(naRef hash, char* key, naRef val); void naHash_delete(naRef hash, naRef key); /** - * Store the keys in ::hash into the vector at ::dst + * Store the keys in @p hash into the vector at @p dst * * @see ::naNewVector */ @@ -273,25 +278,25 @@ typedef struct naGhostType { } naGhostType; /** - * Create a ghost for an object without any attributes. If ::t contains pointers - * to get_member or set_member function they will be ignored. + * Create a ghost for an object without any attributes. If @p t contains + * pointers to get_member or set_member function they will be ignored. */ naRef naNewGhost(naContext c, naGhostType* t, void* ghost); /** * Create a ghost for an object. This version uses the get_member and set_member - * function pointers in ::t upon trying to get or set a member respectively from - * Nasal. + * function pointers in @p t upon trying to get or set a member respectively + * from Nasal. */ naRef naNewGhost2(naContext c, naGhostType* t, void* ghost); naGhostType* naGhost_type(naRef ghost); void* naGhost_ptr(naRef ghost); /** - * Attach a nasal object to the given ghost. Binds the lifetime of @a data to - * the lifetime of the @a ghost. + * Attach a nasal object to the given ghost. Binds the lifetime of @p data to + * the lifetime of the @p ghost. */ void naGhost_setData(naRef ghost, naRef data); /** - * Retrieve the object attached to the @a ghost, previously set with + * Retrieve the object attached to the @p ghost, previously set with * naGhost_setData(). */ naRef naGhost_data(naRef ghost); From 19cc797c419e8d1c579565d242643904bb2c5dd8 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Fri, 12 Jan 2018 07:57:17 +0100 Subject: [PATCH 13/23] cppbind: fix exporting integer_sequence and small codingstyle fixes --- simgear/misc/CMakeLists.txt | 1 + simgear/misc/integer_sequence.hxx | 4 ++-- simgear/misc/integer_sequence_test.cxx | 4 ++-- simgear/nasal/cppbind/NasalContext.hxx | 4 ++-- simgear/nasal/cppbind/NasalObject.hxx | 2 +- simgear/structure/function_list.hxx | 4 ++-- 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/simgear/misc/CMakeLists.txt b/simgear/misc/CMakeLists.txt index 3c5bfedd..c6b0d73a 100644 --- a/simgear/misc/CMakeLists.txt +++ b/simgear/misc/CMakeLists.txt @@ -9,6 +9,7 @@ set(HEADERS SVGpreserveAspectRatio.hxx argparse.hxx interpolator.hxx + integer_sequence.hxx make_new.hxx sg_dir.hxx sg_hash.hxx diff --git a/simgear/misc/integer_sequence.hxx b/simgear/misc/integer_sequence.hxx index 7f372785..47f63c43 100644 --- a/simgear/misc/integer_sequence.hxx +++ b/simgear/misc/integer_sequence.hxx @@ -20,7 +20,7 @@ #ifndef SIMGEAR_MISC_INTEGER_SEQUENCE_HXX_ #define SIMGEAR_MISC_INTEGER_SEQUENCE_HXX_ -#include +#include #include #include @@ -48,7 +48,7 @@ namespace simgear { namespace detail template struct append; - template + template struct append, Int> { using type = std::integer_sequence; diff --git a/simgear/misc/integer_sequence_test.cxx b/simgear/misc/integer_sequence_test.cxx index 82463f50..74ccd3c2 100644 --- a/simgear/misc/integer_sequence_test.cxx +++ b/simgear/misc/integer_sequence_test.cxx @@ -8,13 +8,13 @@ void print(const T& v, std::size_t i) std::cout << "arg #" << i << ": '" << v << "', "; } -template +template void doIt_impl(Args ... args, std::index_sequence) { std::initializer_list{(print(args, Is), '0')...}; } -template +template void doIt(Args ... args) { static_assert(sizeof...(Args) == std::index_sequence_for::size(), ""); diff --git a/simgear/nasal/cppbind/NasalContext.hxx b/simgear/nasal/cppbind/NasalContext.hxx index e9379c9f..d3a3aee5 100644 --- a/simgear/nasal/cppbind/NasalContext.hxx +++ b/simgear/nasal/cppbind/NasalContext.hxx @@ -44,14 +44,14 @@ namespace nasal String newString(const char* str); /** Create a new nasal vector and fill it with the given values */ - template + template naRef newVector(Vals ... vals) { return newVector({to_nasal(vals)...}); } /** Raise a nasal runtime error */ - template + template void runtimeError(const char* fmt, Args ... args) const { naRuntimeError(c_ctx(), fmt, args...); diff --git a/simgear/nasal/cppbind/NasalObject.hxx b/simgear/nasal/cppbind/NasalObject.hxx index 565c1670..c48812cf 100644 --- a/simgear/nasal/cppbind/NasalObject.hxx +++ b/simgear/nasal/cppbind/NasalObject.hxx @@ -45,7 +45,7 @@ namespace nasal bool valid() const; - template + template Ret callMethod(const std::string& name, Args ... args) { if( !_nasal_impl.valid() ) diff --git a/simgear/structure/function_list.hxx b/simgear/structure/function_list.hxx index 5268d2ca..89347636 100644 --- a/simgear/structure/function_list.hxx +++ b/simgear/structure/function_list.hxx @@ -31,7 +31,7 @@ namespace simgear * * @tparam Sig Function signature. */ - template + template class function_list: public std::vector> { @@ -54,7 +54,7 @@ namespace simgear * Handle a list of callbacks with the same signature as the given * boost::function type. */ - template + template class function_list>: public function_list { From b989f4085df6205c556e2466a47bd72d817b76d3 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Fri, 12 Jan 2018 08:31:07 +0100 Subject: [PATCH 14/23] Various doxygen improvements/fixes. --- DoxygenMain.cxx | 4 ++++ simgear/props/props.hxx | 26 +++++++++++++----------- simgear/scene/material/EffectBuilder.hxx | 6 +++--- simgear/structure/SGExpression.hxx | 3 +-- simgear/structure/function_list.hxx | 3 ++- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/DoxygenMain.cxx b/DoxygenMain.cxx index 592e9409..8ad79316 100644 --- a/DoxygenMain.cxx +++ b/DoxygenMain.cxx @@ -2,6 +2,10 @@ documentation. It has a .cxx extension so that emacs will happily autoindent correctly. */ +/** + * \namespace simgear + * \brief \ref index "SimGear" main namespace. + */ /** \mainpage SimGear * Simulation, Visualization, and Game development libraries. diff --git a/simgear/props/props.hxx b/simgear/props/props.hxx index 1f56e80e..4c2bb242 100644 --- a/simgear/props/props.hxx +++ b/simgear/props/props.hxx @@ -99,9 +99,9 @@ inline T parseString(const std::string& str) return result; } -/** - * Property value types. - */ +// +// Property value types +// #ifdef NONE #pragma warn A sloppy coder has defined NONE as a macro! @@ -148,6 +148,7 @@ inline T parseString(const std::string& str) #undef STRING #endif +/// Property system which associates property names with values. namespace props { /** @@ -2144,17 +2145,18 @@ inline SGPropertyNode* makeChild(SGPropertyNode* parent, const char* name, return parent->getChild(name, index, true); } -/** - * Utility function for creation of a child property node using a - * relative path. - */ namespace simgear { -template -inline SGPropertyNode* makeNode(SGPropertyNode* parent, const StringType& name) -{ - return parent->getNode(name, true); -} + /** + * Utility function for creation of a child property node using a + * relative path. + */ + template + inline SGPropertyNode* + makeNode(SGPropertyNode* parent, const StringType& name) + { + return parent->getNode(name, true); + } } // For boost::hash diff --git a/simgear/scene/material/EffectBuilder.hxx b/simgear/scene/material/EffectBuilder.hxx index 84003109..c3aec49c 100644 --- a/simgear/scene/material/EffectBuilder.hxx +++ b/simgear/scene/material/EffectBuilder.hxx @@ -1,3 +1,6 @@ +///@file +/// Support classes for parsing effects. +/// // Copyright (C) 2009 Tim Moore timoore@redhat.com // // This library is free software; you can redistribute it and/or @@ -39,9 +42,6 @@ #include #include "Effect.hxx" -/** - * Support classes for parsing effects. - */ namespace simgear { diff --git a/simgear/structure/SGExpression.hxx b/simgear/structure/SGExpression.hxx index 2cfa3dc8..bbe9c037 100644 --- a/simgear/structure/SGExpression.hxx +++ b/simgear/structure/SGExpression.hxx @@ -36,10 +36,9 @@ #include #include -/// Expression tree implementation. - namespace simgear { + /// Expression tree implementation. namespace expression { enum Type { diff --git a/simgear/structure/function_list.hxx b/simgear/structure/function_list.hxx index 89347636..da9933d6 100644 --- a/simgear/structure/function_list.hxx +++ b/simgear/structure/function_list.hxx @@ -29,7 +29,8 @@ namespace simgear /** * Handle a list of callbacks like a single boost::function. * - * @tparam Sig Function signature. + * @tparam Ret Return type of the callbacks + * @tparam Args Parameter types of the callbacks */ template class function_list: From 4cedd0a346dfabc65575b31f431a480e316532db Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Fri, 12 Jan 2018 08:32:57 +0100 Subject: [PATCH 15/23] cppbind: refactor Ghost::method to use variadic templates --- simgear/nasal/cppbind/CMakeLists.txt | 3 +- simgear/nasal/cppbind/Ghost.hxx | 78 ++++++++++++-- .../cppbind/detail/functor_templates.hxx | 101 ------------------ .../nasal/cppbind/test/cppbind_test_ghost.cxx | 44 ++++++++ 4 files changed, 115 insertions(+), 111 deletions(-) delete mode 100644 simgear/nasal/cppbind/detail/functor_templates.hxx diff --git a/simgear/nasal/cppbind/CMakeLists.txt b/simgear/nasal/cppbind/CMakeLists.txt index 5ef4a5aa..d25679a6 100644 --- a/simgear/nasal/cppbind/CMakeLists.txt +++ b/simgear/nasal/cppbind/CMakeLists.txt @@ -15,7 +15,6 @@ set(HEADERS set(DETAIL_HEADERS detail/from_nasal_function_templates.hxx detail/from_nasal_helper.hxx - detail/functor_templates.hxx detail/nasal_traits.hxx detail/to_nasal_helper.hxx ) @@ -51,4 +50,4 @@ add_boost_test(nasal_gc_test add_boost_test(nasal_num SOURCES test/nasal_num_test.cxx LIBRARIES ${TEST_LIBS} -) \ No newline at end of file +) diff --git a/simgear/nasal/cppbind/Ghost.hxx b/simgear/nasal/cppbind/Ghost.hxx index bab88891..f09e79c6 100644 --- a/simgear/nasal/cppbind/Ghost.hxx +++ b/simgear/nasal/cppbind/Ghost.hxx @@ -24,6 +24,7 @@ #include "NasalObjectHolder.hxx" #include +#include #include #include @@ -32,7 +33,6 @@ #include #include #include -#include #include #include @@ -259,6 +259,9 @@ namespace nasal const std::string&, naRef )> fallback_setter_t; + template + using method_variadic_t = boost::function; + class MethodHolder: public internal::MethodHolder { @@ -791,14 +794,73 @@ namespace nasal return method(name, boost::bind(method_invoker, func, _1, _2)); } - // Build dependency for CMake, gcc, etc. -#define SG_DONT_DO_ANYTHING -# include -#undef SG_DONT_DO_ANYTHING + /** + * Bind any callable entity accepting an instance of raw_type and an + * arbitrary number of arguments as method. + * + * The std::index_sequence specifies the order of the arguments + */ + template + Ghost& method( const std::string& name, + const method_variadic_t& func, + std::index_sequence ) + { + return method + ( + name, + typename boost::function + ( boost::bind( + func, + _1, + boost::bind(&Ghost::arg_from_nasal, _2, Indices)... + )) + ); + } -#define BOOST_PP_ITERATION_LIMITS (0, 9) -#define BOOST_PP_FILENAME_1 -#include BOOST_PP_ITERATE() + template + Ghost& method( const std::string& name, + const method_variadic_t& func ) + { + return method(name, func, std::index_sequence_for{}); + } + + /**\ + * Bind a member function with an arbitrary number of arguments as method. + */ + template + Ghost& method( const std::string& name, + Ret (raw_type::*fn)(Args...) ) + { + return method(name, method_variadic_t(fn)); + } + + template + Ghost& method( const std::string& name, + Ret (raw_type::*fn)(Args...) const ) + { + return method(name, method_variadic_t(fn)); + } + + /** + * Bind free function accepting an instance of raw_type and an arbitrary + * number of arguments as method. + */ + template + Ghost& method + ( + const std::string& name, + Ret (*fn)(Type, Args ... args) + ) + { + static_assert( + boost::is_convertible::value, + //|| boost::is_convertible::value + // TODO check how to do it with pointer... + "First parameter can not be converted from the Ghost raw_type" + ); + + return method(name, method_variadic_t(fn)); + } /** * Create a shared pointer on the heap to handle the reference counting diff --git a/simgear/nasal/cppbind/detail/functor_templates.hxx b/simgear/nasal/cppbind/detail/functor_templates.hxx deleted file mode 100644 index e17b7d49..00000000 --- a/simgear/nasal/cppbind/detail/functor_templates.hxx +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef SG_NASAL_GHOST_HXX_ -# error Nasal cppbind - do not include this file! -#endif - -#ifndef SG_DONT_DO_ANYTHING -#define n BOOST_PP_ITERATION() - -#define SG_GHOST_FUNC_TYPE\ - boost::function - - /** - * Bind any callable entity accepting an instance of raw_type and an arbitrary - * number of arguments as method. - */ - template< - class Ret - BOOST_PP_ENUM_TRAILING_PARAMS(n, class A) - > - Ghost& method(const std::string& name, const SG_GHOST_FUNC_TYPE& func) - { -#if defined(SG_GCC_VERSION) && SG_GCC_VERSION < 40407 - // The old version of g++ used on Jenkins (16.11.2012) only compiles this - // version. -# define SG_GHOST_REQUIRE_ARG(z, n, dummy)\ - boost::bind(&arg_from_nasal, _2, n) -#else - // VS (2008, 2010, ... ?) only allow this version. -# define SG_GHOST_REQUIRE_ARG(z, n, dummy)\ - boost::bind(&Ghost::arg_from_nasal, _2, n) -#endif - - return method - ( - name, - typename boost::function - ( boost::bind( - func, - _1 - BOOST_PP_ENUM_TRAILING(n, SG_GHOST_REQUIRE_ARG, 0) - )) - ); - -#undef SG_GHOST_REQUIRE_ARG - } - -#define SG_GHOST_MEM_FN(cv)\ - /**\ - * Bind a member function with an arbitrary number of arguments as method.\ - */\ - template<\ - class Ret\ - BOOST_PP_ENUM_TRAILING_PARAMS(n, class A)\ - >\ - Ghost& method\ - (\ - const std::string& name,\ - Ret (raw_type::*fn)(BOOST_PP_ENUM_PARAMS(n,A)) cv\ - )\ - {\ - return method<\ - Ret\ - BOOST_PP_ENUM_TRAILING_PARAMS(n,A)\ - >(name, SG_GHOST_FUNC_TYPE(fn));\ - } - -// Work around MSVC warning C4003: not enough actual parameters for macro -// We really do not want to pass a parameter, even if MSVC can not believe it. -#define SG_GHOST_NO_CV - - SG_GHOST_MEM_FN(const) - SG_GHOST_MEM_FN(SG_GHOST_NO_CV) - -#undef SG_GHOST_MEM_FN -#undef SG_GHOST_NO_CV - - /** - * Bind free function accepting an instance of raw_type and an arbitrary - * number of arguments as method. - */ - template< - class Ret, - class Type - BOOST_PP_ENUM_TRAILING_PARAMS(n, class A) - > - Ghost& method - ( - const std::string& name, - Ret (*fn)(Type BOOST_PP_ENUM_TRAILING_PARAMS(n,A)) - ) - { - BOOST_STATIC_ASSERT - (( boost::is_convertible::value - //|| boost::is_convertible::value - // TODO check how to do it with pointer... - )); - return method(name, SG_GHOST_FUNC_TYPE(fn)); - } - -#undef n -#undef SG_GHOST_TYPEDEF_FUNC_TYPE -#endif // SG_DONT_DO_ANYTHING diff --git a/simgear/nasal/cppbind/test/cppbind_test_ghost.cxx b/simgear/nasal/cppbind/test/cppbind_test_ghost.cxx index d74f6a14..85546946 100644 --- a/simgear/nasal/cppbind/test/cppbind_test_ghost.cxx +++ b/simgear/nasal/cppbind/test/cppbind_test_ghost.cxx @@ -1,9 +1,12 @@ #define BOOST_TEST_MODULE cppbind #include +#include "TestContext.hxx" + #include #include +#include #include #include @@ -186,3 +189,44 @@ BOOST_AUTO_TEST_CASE( storage_traits ) nasal::shared_ptr_storage::unref(d_weak); } + +BOOST_AUTO_TEST_CASE( bind_methods ) +{ + struct TestClass + { + int arg1; + std::string arg2; + std::string arg3; + int arg4; + + void set(int a1, const std::string& a2, const std::string& a3, int a4) + { + arg1 = a1; + arg2 = a2; + arg3 = a3; + arg4 = a4; + } + }; + using TestClassPtr = boost::shared_ptr; + auto set_func = boost::function< + void (TestClass&, int, const std::string&, const std::string&, int) + >(&TestClass::set); + nasal::Ghost::init("TestClass") + .method("set", set_func) + .method("setReverse", set_func, std::index_sequence<3,2,1,0>{}); + + TestContext ctx; + auto test = boost::make_shared(); + + ctx.exec("me.set(1, \"s2\", \"s3\", 4);", ctx.to_nasal(test)); + BOOST_CHECK_EQUAL(test->arg1, 1); + BOOST_CHECK_EQUAL(test->arg2, "s2"); + BOOST_CHECK_EQUAL(test->arg3, "s3"); + BOOST_CHECK_EQUAL(test->arg4, 4); + + ctx.exec("me.setReverse(1, \"s2\", \"s3\", 4);", ctx.to_nasal(test)); + BOOST_CHECK_EQUAL(test->arg1, 4); + BOOST_CHECK_EQUAL(test->arg2, "s3"); + BOOST_CHECK_EQUAL(test->arg3, "s2"); + BOOST_CHECK_EQUAL(test->arg4, 1); +} From 51a91bfa8a11b35c548e771319f1572d26d57aa2 Mon Sep 17 00:00:00 2001 From: James Turner Date: Wed, 10 Jan 2018 07:37:33 +0000 Subject: [PATCH 16/23] Ignore CmakeList.txt.user files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5ba354be..1ba3b2e3 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ CTestTestfile.cmake install_manifest.txt build* Build +CMakeLists.txt.user From 5a72a7d9f484c807e45ebd85b2b93e8580ef798e Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Tue, 16 Jan 2018 09:01:55 +0100 Subject: [PATCH 17/23] canvas: Refactor Path::addSegment with std::initializer_list --- simgear/canvas/elements/CMakeLists.txt | 5 ---- simgear/canvas/elements/CanvasPath.cxx | 27 +++++++++++++------ simgear/canvas/elements/CanvasPath.hxx | 8 +++--- .../elements/detail/add_segment_variadic.hxx | 21 --------------- 4 files changed, 22 insertions(+), 39 deletions(-) delete mode 100644 simgear/canvas/elements/detail/add_segment_variadic.hxx diff --git a/simgear/canvas/elements/CMakeLists.txt b/simgear/canvas/elements/CMakeLists.txt index 2b537c0c..43ff1c1a 100644 --- a/simgear/canvas/elements/CMakeLists.txt +++ b/simgear/canvas/elements/CMakeLists.txt @@ -9,10 +9,6 @@ set(HEADERS CanvasText.hxx ) -set(DETAIL_HEADERS - detail/add_segment_variadic.hxx -) - set(SOURCES CanvasElement.cxx CanvasGroup.cxx @@ -23,7 +19,6 @@ set(SOURCES ) simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}") -simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEADERS}") add_boost_test(canvas_element SOURCES canvas_element_test.cpp diff --git a/simgear/canvas/elements/CanvasPath.cxx b/simgear/canvas/elements/CanvasPath.cxx index cbf5f42c..188f70d6 100644 --- a/simgear/canvas/elements/CanvasPath.cxx +++ b/simgear/canvas/elements/CanvasPath.cxx @@ -740,52 +740,63 @@ namespace canvas return _path->getTransformedBounds(m); } + //---------------------------------------------------------------------------- + Path& Path::addSegment(uint8_t cmd, std::initializer_list coords) + { + _node->addChild("cmd")->setIntValue(cmd); + + for(float coord: coords) + _node->addChild("coord")->setFloatValue(coord); + + return *this; + } + //---------------------------------------------------------------------------- Path& Path::moveTo(float x_abs, float y_abs) { - return addSegment(VG_MOVE_TO_ABS, x_abs, y_abs); + return addSegment(VG_MOVE_TO_ABS, {x_abs, y_abs}); } //---------------------------------------------------------------------------- Path& Path::move(float x_rel, float y_rel) { - return addSegment(VG_MOVE_TO_REL, x_rel, y_rel); + return addSegment(VG_MOVE_TO_REL, {x_rel, y_rel}); } //---------------------------------------------------------------------------- Path& Path::lineTo(float x_abs, float y_abs) { - return addSegment(VG_LINE_TO_ABS, x_abs, y_abs); + return addSegment(VG_LINE_TO_ABS, {x_abs, y_abs}); } //---------------------------------------------------------------------------- Path& Path::line(float x_rel, float y_rel) { - return addSegment(VG_LINE_TO_REL, x_rel, y_rel); + return addSegment(VG_LINE_TO_REL, {x_rel, y_rel}); } //---------------------------------------------------------------------------- Path& Path::horizTo(float x_abs) { - return addSegment(VG_HLINE_TO_ABS, x_abs); + return addSegment(VG_HLINE_TO_ABS, {x_abs}); } //---------------------------------------------------------------------------- Path& Path::horiz(float x_rel) { - return addSegment(VG_HLINE_TO_REL, x_rel); + return addSegment(VG_HLINE_TO_REL, {x_rel}); } //---------------------------------------------------------------------------- Path& Path::vertTo(float y_abs) { - return addSegment(VG_VLINE_TO_ABS, y_abs); + return addSegment(VG_VLINE_TO_ABS, {y_abs}); } //---------------------------------------------------------------------------- Path& Path::vert(float y_rel) { - return addSegment(VG_VLINE_TO_REL, y_rel); + return addSegment(VG_VLINE_TO_REL, {y_rel}); } //---------------------------------------------------------------------------- diff --git a/simgear/canvas/elements/CanvasPath.hxx b/simgear/canvas/elements/CanvasPath.hxx index f31380ba..2b7804f9 100644 --- a/simgear/canvas/elements/CanvasPath.hxx +++ b/simgear/canvas/elements/CanvasPath.hxx @@ -20,8 +20,8 @@ #define CANVAS_PATH_HXX_ #include "CanvasElement.hxx" -#include #include +#include namespace simgear { @@ -44,10 +44,8 @@ namespace canvas virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const; -#define BOOST_PP_ITERATION_LIMITS (0, 6) -#define BOOST_PP_FILENAME_1 \ - -#include BOOST_PP_ITERATE() + /** Add a segment with the given command and coordinates */ + Path& addSegment(uint8_t cmd, std::initializer_list coords = {}); /** Move path cursor */ Path& moveTo(float x_abs, float y_abs); diff --git a/simgear/canvas/elements/detail/add_segment_variadic.hxx b/simgear/canvas/elements/detail/add_segment_variadic.hxx deleted file mode 100644 index cb4f434e..00000000 --- a/simgear/canvas/elements/detail/add_segment_variadic.hxx +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef CANVAS_PATH_HXX_ -# error Canvas - do not include this file! -#endif - -#define n BOOST_PP_ITERATION() - -Path& addSegment( uint8_t cmd - BOOST_PP_COMMA_IF(n) - BOOST_PP_ENUM_PARAMS(n, float coord) ) -{ - _node->addChild("cmd")->setIntValue(cmd); - -#define SG_CANVAS_PATH_SET_COORD(z, n, dummy)\ - _node->addChild("coord")->setFloatValue(coord##n); - - BOOST_PP_REPEAT(n, SG_CANVAS_PATH_SET_COORD, 0) -#undef SG_CANVAS_PATH_SET_COORD - return *this; -} - -#undef n From 5f8f5a1c333e57d5b57357ad8753a53db255bebc Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Fri, 19 Jan 2018 09:07:07 +0100 Subject: [PATCH 18/23] cppbind: More refactoring and finally getting rid of boost.preprocessor --- simgear/canvas/layout/NasalWidget.cxx | 9 +- simgear/nasal/cppbind/CMakeLists.txt | 4 +- simgear/nasal/cppbind/NasalContext.cxx | 20 +++ simgear/nasal/cppbind/NasalContext.hxx | 35 ++++- simgear/nasal/cppbind/NasalMe.hxx | 44 ++++++ simgear/nasal/cppbind/NasalMethodHolder.hxx | 75 ++++++++++ simgear/nasal/cppbind/NasalObject.hxx | 4 +- simgear/nasal/cppbind/NasalObjectHolder.hxx | 8 +- simgear/nasal/cppbind/cppbind_fwd.hxx | 54 ++++++++ .../detail/from_nasal_function_templates.hxx | 131 ------------------ .../cppbind/detail/from_nasal_helper.hxx | 78 +++-------- simgear/nasal/cppbind/from_nasal.hxx | 5 +- simgear/nasal/cppbind/test/TestContext.hxx | 2 +- simgear/nasal/cppbind/test/cppbind_test.cxx | 8 +- .../nasal/cppbind/test/cppbind_test_ghost.cxx | 4 +- 15 files changed, 267 insertions(+), 214 deletions(-) create mode 100644 simgear/nasal/cppbind/NasalMe.hxx create mode 100644 simgear/nasal/cppbind/NasalMethodHolder.hxx create mode 100644 simgear/nasal/cppbind/cppbind_fwd.hxx delete mode 100644 simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx diff --git a/simgear/canvas/layout/NasalWidget.cxx b/simgear/canvas/layout/NasalWidget.cxx index 65ded50b..9e984642 100644 --- a/simgear/canvas/layout/NasalWidget.cxx +++ b/simgear/canvas/layout/NasalWidget.cxx @@ -189,10 +189,10 @@ namespace canvas if( hfw.empty() ) return -1; - naContext c = naNewContext(); try { - return hfw(nasal::to_nasal(c, const_cast(this)), w); + nasal::Context ctx; + return hfw(ctx.to_me(const_cast(this)), w); } catch( std::exception const& ex ) { @@ -202,7 +202,6 @@ namespace canvas "NasalWidget.heightForWidth: callback error: '" << ex.what() << "'" ); } - naFreeContext(c); return -1; } @@ -262,8 +261,8 @@ namespace canvas try { - nasal::Context c; - _set_geometry(nasal::to_nasal(c, this), rect); + nasal::Context ctx; + _set_geometry(ctx.to_me(this), rect); _flags &= ~LAYOUT_DIRTY; } catch( std::exception const& ex ) diff --git a/simgear/nasal/cppbind/CMakeLists.txt b/simgear/nasal/cppbind/CMakeLists.txt index d25679a6..08f09937 100644 --- a/simgear/nasal/cppbind/CMakeLists.txt +++ b/simgear/nasal/cppbind/CMakeLists.txt @@ -1,10 +1,13 @@ include (SimGearComponent) set(HEADERS + cppbind_fwd.hxx Ghost.hxx NasalCallContext.hxx NasalContext.hxx NasalHash.hxx + NasalMe.hxx + NasalMethodHolder.hxx NasalObject.hxx NasalObjectHolder.hxx NasalString.hxx @@ -13,7 +16,6 @@ set(HEADERS ) set(DETAIL_HEADERS - detail/from_nasal_function_templates.hxx detail/from_nasal_helper.hxx detail/nasal_traits.hxx detail/to_nasal_helper.hxx diff --git a/simgear/nasal/cppbind/NasalContext.cxx b/simgear/nasal/cppbind/NasalContext.cxx index fe0e4755..dbbaa7c5 100644 --- a/simgear/nasal/cppbind/NasalContext.cxx +++ b/simgear/nasal/cppbind/NasalContext.cxx @@ -56,6 +56,26 @@ namespace nasal return String(_ctx, str); } + //---------------------------------------------------------------------------- + naRef ContextWrapper::callMethod( Me me, + naRef code, + std::initializer_list args ) + { + naRef ret = naCallMethodCtx( + _ctx, + code, + me, + args.size(), + const_cast(args.begin()), + naNil() // locals + ); + + if( const char* error = naGetError(_ctx) ) + throw std::runtime_error(error); + + return ret; + } + //---------------------------------------------------------------------------- naRef ContextWrapper::newVector(std::initializer_list vals) { diff --git a/simgear/nasal/cppbind/NasalContext.hxx b/simgear/nasal/cppbind/NasalContext.hxx index d3a3aee5..4cbcc8cc 100644 --- a/simgear/nasal/cppbind/NasalContext.hxx +++ b/simgear/nasal/cppbind/NasalContext.hxx @@ -19,13 +19,14 @@ #ifndef SG_NASAL_CONTEXT_HXX_ #define SG_NASAL_CONTEXT_HXX_ -#include "from_nasal.hxx" -#include "to_nasal.hxx" +#include "cppbind_fwd.hxx" +#include "NasalMe.hxx" + +#include +#include namespace nasal { - class Hash; - class String; /** * Wraps a nasal ::naContext without taking ownership/managing its lifetime @@ -63,12 +64,18 @@ namespace nasal return nasal::to_nasal(_ctx, arg); } - template + template naRef to_nasal(const T(&array)[N]) const { return nasal::to_nasal(_ctx, array); } + template + Me to_me(T arg) const + { + return Me{ to_nasal(arg) }; + } + template typename from_nasal_ptr::return_type from_nasal(naRef ref) const @@ -76,6 +83,21 @@ namespace nasal return (*from_nasal_ptr::get())(_ctx, ref); } + naRef callMethod(Me me, naRef code, std::initializer_list args); + + template + Ret callMethod( Me me, + naRef code, + typename boost::call_traits::param_type ... args ) + { + // TODO warn if with Ret == void something different to nil is returned? + return from_nasal(callMethod( + me, + code, + { to_nasal::param_type>(args)... } + )); + } + protected: naContext _ctx; @@ -100,4 +122,7 @@ namespace nasal } // namespace nasal +#include "from_nasal.hxx" +#include "to_nasal.hxx" + #endif /* SG_NASAL_CONTEXT_HXX_ */ diff --git a/simgear/nasal/cppbind/NasalMe.hxx b/simgear/nasal/cppbind/NasalMe.hxx new file mode 100644 index 00000000..953a372e --- /dev/null +++ b/simgear/nasal/cppbind/NasalMe.hxx @@ -0,0 +1,44 @@ +///@file +// +// Copyright (C) 2018 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_NASAL_ME_HXX_ +#define SG_NASAL_ME_HXX_ + +#include + +namespace nasal +{ + + /** + * Wrap a naRef to indicate it references the self/me object in Nasal method + * calls. + */ + struct Me + { + naRef _ref; + + explicit Me(naRef ref = naNil()): + _ref(ref) + {} + + operator naRef() { return _ref; } + }; + +} // namespace nasal + +#endif /* SG_NASAL_ME_HXX_ */ diff --git a/simgear/nasal/cppbind/NasalMethodHolder.hxx b/simgear/nasal/cppbind/NasalMethodHolder.hxx new file mode 100644 index 00000000..74c1a90a --- /dev/null +++ b/simgear/nasal/cppbind/NasalMethodHolder.hxx @@ -0,0 +1,75 @@ +///@file +// +// Copyright (C) 2018 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_NASAL_METHOD_HOLDER_HXX_ +#define SG_NASAL_METHOD_HOLDER_HXX_ + +#include "NasalContext.hxx" +#include "NasalObjectHolder.hxx" + +namespace nasal +{ + + /** + * Hold any callable function in Nasal and call it from C++ + */ + template + class NasalMethodHolder + { + using Holder = ObjectHolder; + + public: + NasalMethodHolder(naRef code): + _code(Holder::makeShared(code)) + {} + + /** + * @brief Call the function with the given arguments + * + * If the first argument is nasal::Me it will be passed as 'me' object and + * not as argument. + */ + Ret operator()(Args ... args) + { + return call(args...); + } + + private: + Holder::Ref _code; + + template + Ret call(Me self, CArgs ... args) + { + nasal::Context ctx; + return ctx.callMethod( + self, + _code->get_naRef(), + args... + ); + } + + template + Ret call(CArgs ... args) + { + return call(Me{}, args...); + } + }; + +} // namespace nasal + +#endif /* SG_NASAL_METHOD_HOLDER_HXX_ */ diff --git a/simgear/nasal/cppbind/NasalObject.hxx b/simgear/nasal/cppbind/NasalObject.hxx index c48812cf..4d965d9c 100644 --- a/simgear/nasal/cppbind/NasalObject.hxx +++ b/simgear/nasal/cppbind/NasalObject.hxx @@ -52,11 +52,11 @@ namespace nasal return Ret(); Context ctx; - auto func = get_member>( + auto func = get_member>( ctx, _nasal_impl.get_naRef(), name ); if( func ) - return func(nasal::to_nasal(ctx, this), args...); + return func(Me(ctx.to_nasal(this)), args...); return Ret(); } diff --git a/simgear/nasal/cppbind/NasalObjectHolder.hxx b/simgear/nasal/cppbind/NasalObjectHolder.hxx index 9b36bcf7..23ab9a79 100644 --- a/simgear/nasal/cppbind/NasalObjectHolder.hxx +++ b/simgear/nasal/cppbind/NasalObjectHolder.hxx @@ -42,6 +42,8 @@ namespace nasal { public: + using Ref = SGSharedPtr>; + /** * @param obj Object to save */ @@ -84,7 +86,7 @@ namespace nasal * * @param obj Object to save */ - static SGSharedPtr > makeShared(naRef obj); + static Ref makeShared(naRef obj); protected: naRef _ref; @@ -155,10 +157,10 @@ namespace nasal //---------------------------------------------------------------------------- template - SGSharedPtr > + typename ObjectHolder::Ref ObjectHolder::makeShared(naRef obj) { - return SGSharedPtr >( new ObjectHolder(obj) ); + return Ref( new ObjectHolder(obj) ); } } // namespace nasal diff --git a/simgear/nasal/cppbind/cppbind_fwd.hxx b/simgear/nasal/cppbind/cppbind_fwd.hxx new file mode 100644 index 00000000..e081bddc --- /dev/null +++ b/simgear/nasal/cppbind/cppbind_fwd.hxx @@ -0,0 +1,54 @@ +///@file +/// Nasal C++ Bindings forward declarations +/// +// Copyright (C) 2018 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SG_NASAL_CPPBIND_FWD_HXX_ +#define SG_NASAL_CPPBIND_FWD_HXX_ + +#include +#include + +namespace nasal +{ + + class CallContext; + class Context; + class ContextWrapper; + class Hash; + class Me; + class Object; + class String; + + template + class Ghost; + + template + naRef to_nasal(naContext c, T arg); + + template + naRef to_nasal(naContext c, const T(&array)[N]); + + template + T from_nasal(naContext c, naRef ref); + + template + struct from_nasal_ptr; + +} // namespace nasal + +#endif /* SG_NASAL_CPPBIND_FWD_HXX_ */ diff --git a/simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx b/simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx deleted file mode 100644 index 83f1216b..00000000 --- a/simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx +++ /dev/null @@ -1,131 +0,0 @@ -#ifndef SG_FROM_NASAL_HELPER_HXX_ -# error Nasal cppbind - do not include this file! -#endif - -#ifndef SG_DONT_DO_ANYTHING -#define n BOOST_PP_ITERATION() - -#ifndef SG_BOOST_FUNCTION_FROM_NASAL_FWD -# define SG_CALL_TRAITS_PARAM(z, n, dummy)\ - typename boost::call_traits::param_type a##n -# define SG_CALL_ARG(z, n, dummy)\ - to_nasal::param_type>(ctx, a##n) - - template< - class Ret - BOOST_PP_ENUM_TRAILING_PARAMS(n, class A) - > - typename boost::disable_if, Ret>::type - callNasalMethod( const ObjectHolder* holder, - Me self - BOOST_PP_ENUM_TRAILING(n, SG_CALL_TRAITS_PARAM, 0) ) - { - naContext ctx = naNewContext(); -#if n - naRef args[n] = { - BOOST_PP_ENUM(n, SG_CALL_ARG, 0) - }; -#else - naRef* args = NULL; -#endif - - naRef result = - naCallMethodCtx(ctx, holder->get_naRef(), self, n, args, naNil()); - - const char* error = naGetError(ctx); - std::string error_str(error ? error : ""); - - Ret r = Ret(); - if( !error ) - r = from_nasal_helper(ctx, result, static_cast(0)); - - naFreeContext(ctx); - - if( error ) - throw std::runtime_error(error_str); - - return r; - } - - template< - class Ret - BOOST_PP_ENUM_TRAILING_PARAMS(n, class A) - > - typename boost::enable_if, Ret>::type - callNasalMethod( const ObjectHolder* holder, - Me self - BOOST_PP_ENUM_TRAILING(n, SG_CALL_TRAITS_PARAM, 0) ) - { - callNasalMethod< - naRef // do not do any conversion and just ignore the return value - // TODO warn if something different to nil is returned? - BOOST_PP_COMMA_IF(n) - BOOST_PP_ENUM_PARAMS(n, A) - > - ( - holder, - self - BOOST_PP_ENUM_TRAILING_PARAMS(n, a) - ); - } - -# undef SG_CALL_TRAITS_PARAM -# undef SG_CALL_ARG -#endif - - template< - class Ret - BOOST_PP_ENUM_TRAILING_PARAMS(n, class A) - > - typename boost::disable_if< - // free function if first argument is not nasal::Me or no argument at all - boost::is_same, - boost::function - >::type - boostFunctionFromNasal(naRef code, Ret (*)(BOOST_PP_ENUM_PARAMS(n, A))) -#ifdef SG_BOOST_FUNCTION_FROM_NASAL_FWD - ; -#else - { - return boost::bind - ( - &callNasalMethod, - ObjectHolder::makeShared(code), - boost::bind(naNil) - BOOST_PP_COMMA_IF(n) - BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PP_INC(n), _) - ); - } -#endif - -#if n > 0 - template< - class Ret - BOOST_PP_ENUM_TRAILING_PARAMS(n, class A) - > - typename boost::enable_if< - // method if type of first argument is nasal::Me - boost::is_same, - boost::function - >::type - boostFunctionFromNasal(naRef code, Ret (*)(BOOST_PP_ENUM_PARAMS(n, A))) -#ifdef SG_BOOST_FUNCTION_FROM_NASAL_FWD - ; -#else - { - return boost::bind - ( - &callNasalMethod< - Ret - BOOST_PP_COMMA_IF(BOOST_PP_DEC(n)) - BOOST_PP_ENUM_SHIFTED_PARAMS(n, A) - >, - ObjectHolder::makeShared(code), - BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PP_INC(n), _) - ); - } -#endif -#endif - -#undef n -#endif // SG_DONT_DO_ANYTHING diff --git a/simgear/nasal/cppbind/detail/from_nasal_helper.hxx b/simgear/nasal/cppbind/detail/from_nasal_helper.hxx index 3cf03dd2..9eee0690 100644 --- a/simgear/nasal/cppbind/detail/from_nasal_helper.hxx +++ b/simgear/nasal/cppbind/detail/from_nasal_helper.hxx @@ -24,20 +24,15 @@ #include #include -#include +#include +#include +#include #include -#include #include #include #include -#include #include -#include -#include -#include -#include -#include #include #include @@ -76,27 +71,19 @@ namespace nasal std::string _msg; }; - /** - * Wrap a naRef to indicate it references the self/me object in Nasal method - * calls. - */ - struct Me - { - naRef _ref; - - Me(naRef ref = naNil()): - _ref(ref) - {} - - operator naRef() { return _ref; } - }; - /** * Simple pass through for unified handling also of naRef. */ inline naRef from_nasal_helper(naContext, naRef ref, const naRef*) { return ref; } + /** + * Ignore return value + */ + // TODO show some warning when something is returned but ignored? + inline void from_nasal_helper(naContext, naRef, const void*) + {} + /** * Convert Nasal string to std::string */ @@ -125,43 +112,33 @@ namespace nasal */ bool from_nasal_helper(naContext c, naRef ref, const bool*); - namespace detail - { -#define SG_BOOST_FUNCTION_FROM_NASAL_FWD -#define BOOST_PP_ITERATION_LIMITS (0, 9) -#define BOOST_PP_FILENAME_1 -#include BOOST_PP_ITERATE() -#undef SG_BOOST_FUNCTION_FROM_NASAL_FWD - } - /** * Convert a Nasal function to a boost::function with the given signature. * * @tparam Sig Signature of returned function (arguments and return value * are automatically converted using from_nasal/to_nasal) */ - template - boost::function - from_nasal_helper(naContext c, naRef ref, boost::function*) + template + boost::function + from_nasal_helper(naContext c, naRef ref, const boost::function*) { if( naIsNil(ref) ) - return boost::function(); + return {}; if( !naIsCode(ref) && !naIsCCode(ref) && !naIsFunc(ref) ) throw bad_nasal_cast("not a function"); - return detail::boostFunctionFromNasal(ref, static_cast(0)); + return NasalMethodHolder(ref); } - template - typename boost::enable_if< boost::is_function, - boost::function - >::type - from_nasal_helper(naContext c, naRef ref, Sig*) + template + boost::function + from_nasal_helper(naContext c, naRef ref, Ret (*const)(Args...)) { - return from_nasal_helper(c, ref, static_cast*>(0)); + return + from_nasal_helper(c, ref, static_cast*>(0)); } /** @@ -227,21 +204,6 @@ namespace nasal return SGRect(vec[0], vec[1], vec[2], vec[3]); } - // Helpers for wrapping calls to Nasal functions into boost::function - namespace detail - { - // Dummy include to add a build dependency on this file for gcc/CMake/etc. -#define SG_DONT_DO_ANYTHING -# include -#undef SG_DONT_DO_ANYTHING - - // Now the actual include (we are limited to 8 arguments (+me) here because - // boost::bind has an upper limit of 9) -#define BOOST_PP_ITERATION_LIMITS (0, 8) -#define BOOST_PP_FILENAME_1 -#include BOOST_PP_ITERATE() - } - } // namespace nasal #endif /* SG_FROM_NASAL_HELPER_HXX_ */ diff --git a/simgear/nasal/cppbind/from_nasal.hxx b/simgear/nasal/cppbind/from_nasal.hxx index cd9a9fe4..a5025827 100644 --- a/simgear/nasal/cppbind/from_nasal.hxx +++ b/simgear/nasal/cppbind/from_nasal.hxx @@ -21,6 +21,7 @@ #define SG_FROM_NASAL_HXX_ #include +#include namespace nasal { @@ -52,8 +53,8 @@ namespace nasal template struct from_nasal_ptr { - typedef typename boost::remove_const - < typename boost::remove_reference::type + typedef typename std::remove_const + < typename std::remove_reference::type >::type return_type; typedef return_type(*type)(naContext, naRef); diff --git a/simgear/nasal/cppbind/test/TestContext.hxx b/simgear/nasal/cppbind/test/TestContext.hxx index 5a90d590..2bc4e7a8 100644 --- a/simgear/nasal/cppbind/test/TestContext.hxx +++ b/simgear/nasal/cppbind/test/TestContext.hxx @@ -42,7 +42,7 @@ class TestContext: template T exec(const std::string& code) { - return from_nasal(execImpl(code, {})); + return from_nasal(execImpl(code, nasal::Me{})); } template diff --git a/simgear/nasal/cppbind/test/cppbind_test.cxx b/simgear/nasal/cppbind/test/cppbind_test.cxx index 397c4e35..f2c704ef 100644 --- a/simgear/nasal/cppbind/test/cppbind_test.cxx +++ b/simgear/nasal/cppbind/test/cppbind_test.cxx @@ -218,7 +218,7 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing ) // passed on to function typedef boost::function MeIntFunc; MeIntFunc fmeint = hash.get("func"); - BOOST_CHECK_EQUAL(fmeint(naNil(), 5), 5); + BOOST_CHECK_EQUAL(fmeint(Me{}, 5), 5); //---------------------------------------------------------------------------- // Test exposing classes to Nasal @@ -292,7 +292,7 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing ) typedef boost::function MemFunc; MemFunc fGetThis = c.from_nasal(thisGetter); BOOST_REQUIRE( fGetThis ); - BOOST_CHECK_EQUAL( fGetThis(derived), (unsigned long)d.get() ); + BOOST_CHECK_EQUAL( fGetThis(Me{derived}), (unsigned long)d.get() ); BasePtr d2( new DoubleDerived ); derived = c.to_nasal(d2); @@ -369,10 +369,10 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing ) BOOST_CHECK_EQUAL( objects[2], d3 ); // Calling fallback setter for unset values - BOOST_CHECK_EQUAL( c.exec("me.test = 3;", derived), 3 ); + BOOST_CHECK_EQUAL( c.exec("me.test = 3;", Me{derived}), 3 ); // Calling generic (fallback) getter - BOOST_CHECK_EQUAL( c.exec("var a = me.get_test;", derived), + BOOST_CHECK_EQUAL( c.exec("var a = me.get_test;", Me{derived}), "generic-get" ); //---------------------------------------------------------------------------- diff --git a/simgear/nasal/cppbind/test/cppbind_test_ghost.cxx b/simgear/nasal/cppbind/test/cppbind_test_ghost.cxx index 85546946..45bf105b 100644 --- a/simgear/nasal/cppbind/test/cppbind_test_ghost.cxx +++ b/simgear/nasal/cppbind/test/cppbind_test_ghost.cxx @@ -218,13 +218,13 @@ BOOST_AUTO_TEST_CASE( bind_methods ) TestContext ctx; auto test = boost::make_shared(); - ctx.exec("me.set(1, \"s2\", \"s3\", 4);", ctx.to_nasal(test)); + ctx.exec("me.set(1, \"s2\", \"s3\", 4);", ctx.to_me(test)); BOOST_CHECK_EQUAL(test->arg1, 1); BOOST_CHECK_EQUAL(test->arg2, "s2"); BOOST_CHECK_EQUAL(test->arg3, "s3"); BOOST_CHECK_EQUAL(test->arg4, 4); - ctx.exec("me.setReverse(1, \"s2\", \"s3\", 4);", ctx.to_nasal(test)); + ctx.exec("me.setReverse(1, \"s2\", \"s3\", 4);", ctx.to_me(test)); BOOST_CHECK_EQUAL(test->arg1, 4); BOOST_CHECK_EQUAL(test->arg2, "s3"); BOOST_CHECK_EQUAL(test->arg3, "s2"); From 3dca9b8a6862877fcd62e9f83c35510e19195ec1 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Fri, 19 Jan 2018 10:24:33 +0100 Subject: [PATCH 19/23] cppbind: Make Mac and Windows happy and add forward declaration --- simgear/nasal/cppbind/cppbind_fwd.hxx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/simgear/nasal/cppbind/cppbind_fwd.hxx b/simgear/nasal/cppbind/cppbind_fwd.hxx index e081bddc..c57b8fbb 100644 --- a/simgear/nasal/cppbind/cppbind_fwd.hxx +++ b/simgear/nasal/cppbind/cppbind_fwd.hxx @@ -22,6 +22,7 @@ #include #include +#include namespace nasal { @@ -30,7 +31,7 @@ namespace nasal class Context; class ContextWrapper; class Hash; - class Me; + struct Me; class Object; class String; @@ -49,6 +50,9 @@ namespace nasal template struct from_nasal_ptr; + template + T get_member(naContext c, naRef obj, const std::string& name); + } // namespace nasal #endif /* SG_NASAL_CPPBIND_FWD_HXX_ */ From 8a128a57cd5040583e92f7c6519fde4693ca9f3b Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Fri, 19 Jan 2018 10:34:37 +0100 Subject: [PATCH 20/23] cppbind: forward declarations --- simgear/nasal/cppbind/cppbind_fwd.hxx | 2 ++ simgear/nasal/cppbind/detail/from_nasal_helper.hxx | 2 -- simgear/nasal/cppbind/detail/to_nasal_helper.hxx | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/simgear/nasal/cppbind/cppbind_fwd.hxx b/simgear/nasal/cppbind/cppbind_fwd.hxx index c57b8fbb..4f122fba 100644 --- a/simgear/nasal/cppbind/cppbind_fwd.hxx +++ b/simgear/nasal/cppbind/cppbind_fwd.hxx @@ -27,6 +27,8 @@ namespace nasal { + class bad_nasal_cast; + class CallContext; class Context; class ContextWrapper; diff --git a/simgear/nasal/cppbind/detail/from_nasal_helper.hxx b/simgear/nasal/cppbind/detail/from_nasal_helper.hxx index 9eee0690..436dcb3c 100644 --- a/simgear/nasal/cppbind/detail/from_nasal_helper.hxx +++ b/simgear/nasal/cppbind/detail/from_nasal_helper.hxx @@ -43,8 +43,6 @@ class SGPath; namespace nasal { - class Hash; - class String; /** * Thrown when converting a type from/to Nasal has failed diff --git a/simgear/nasal/cppbind/detail/to_nasal_helper.hxx b/simgear/nasal/cppbind/detail/to_nasal_helper.hxx index f34d9fb6..7d54fcb6 100644 --- a/simgear/nasal/cppbind/detail/to_nasal_helper.hxx +++ b/simgear/nasal/cppbind/detail/to_nasal_helper.hxx @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include @@ -40,8 +40,6 @@ class SGPath; namespace nasal { - class CallContext; - class Hash; typedef boost::function free_function_t; From 9078a085c3b3e0035506c764f6cef06032c0148e Mon Sep 17 00:00:00 2001 From: James Turner Date: Sat, 20 Jan 2018 16:19:13 +0000 Subject: [PATCH 21/23] Kill exception if removeDelegate fails This simplifies logic when changing the package::Root --- simgear/package/Root.cxx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/simgear/package/Root.cxx b/simgear/package/Root.cxx index ec167000..a0918525 100644 --- a/simgear/package/Root.cxx +++ b/simgear/package/Root.cxx @@ -554,12 +554,10 @@ void Root::addDelegate(simgear::pkg::Delegate *aDelegate) void Root::removeDelegate(simgear::pkg::Delegate *aDelegate) { - DelegateVec::iterator it = std::find(d->delegates.begin(), - d->delegates.end(), aDelegate); - if (it == d->delegates.end()) { - throw sg_exception("unknown delegate in removeDelegate"); + auto it = std::find(d->delegates.begin(), d->delegates.end(), aDelegate); + if (it != d->delegates.end()) { + d->delegates.erase(it); } - d->delegates.erase(it); } void Root::setLocale(const std::string& aLocale) From af5833cbc52d9ecdf0ac2aea75e3e7858ff1a157 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Sun, 21 Jan 2018 13:02:43 +0100 Subject: [PATCH 22/23] cppbind: Refactor to use C++11+ type_traits --- CMakeLists.txt | 8 +- CMakeModules/CheckCXXFeatures.cmake | 30 ++ simgear/CMakeLists.txt | 1 + simgear/misc/CMakeLists.txt | 5 - simgear/nasal/cppbind/Ghost.hxx | 299 ++++++++---------- simgear/nasal/cppbind/detail/nasal_traits.hxx | 137 +++----- simgear/simgear_config_cmake.h.in | 4 + simgear/std/CMakeLists.txt | 21 ++ simgear/{misc => std}/integer_sequence.hxx | 8 +- .../{misc => std}/integer_sequence_test.cxx | 3 +- simgear/std/type_traits.hxx | 67 ++++ simgear/std/type_traits_test.cxx | 24 ++ 12 files changed, 332 insertions(+), 275 deletions(-) create mode 100644 CMakeModules/CheckCXXFeatures.cmake create mode 100644 simgear/std/CMakeLists.txt rename simgear/{misc => std}/integer_sequence.hxx (93%) rename simgear/{misc => std}/integer_sequence_test.cxx (97%) create mode 100644 simgear/std/type_traits.hxx create mode 100644 simgear/std/type_traits_test.cxx diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d2e049b..d9160c0f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -492,13 +492,7 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS_C} ${MSVC_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS_CXX} ${MSVC_FLAGS} ${BOOST_CXX_FLAGS}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MSVC_LD_FLAGS}") -check_cxx_source_compiles(" - #include - #include - std::make_index_sequence<0> t; - int main() { return 0; }" - HAVE_STD_INDEX_SEQUENCE -) +include(CheckCXXFeatures) # use BEFORE to ensure local directories are used first, # ahead of system-installed libs diff --git a/CMakeModules/CheckCXXFeatures.cmake b/CMakeModules/CheckCXXFeatures.cmake new file mode 100644 index 00000000..0757da83 --- /dev/null +++ b/CMakeModules/CheckCXXFeatures.cmake @@ -0,0 +1,30 @@ +check_cxx_source_compiles(" + #include + #include + std::make_index_sequence<0> t; + int main() {}" HAVE_STD_INDEX_SEQUENCE +) + +check_cxx_source_compiles(" + #include + std::remove_cv_t t; + int main() {}" HAVE_STD_REMOVE_CV_T +) + +check_cxx_source_compiles(" + #include + std::remove_cvref_t t; + int main() {}" HAVE_STD_REMOVE_CVREF_T +) + +check_cxx_source_compiles(" + #include + std::enable_if_t t; + int main() {}" HAVE_STD_ENABLE_IF_T +) + +check_cxx_source_compiles(" + #include + std::bool_constant t; + int main() {}" HAVE_STD_BOOL_CONSTANT +) \ No newline at end of file diff --git a/simgear/CMakeLists.txt b/simgear/CMakeLists.txt index 6c7cb495..6f8d2933 100644 --- a/simgear/CMakeLists.txt +++ b/simgear/CMakeLists.txt @@ -15,6 +15,7 @@ foreach( mylibfolder nasal/cppbind props serial + std structure threads timing diff --git a/simgear/misc/CMakeLists.txt b/simgear/misc/CMakeLists.txt index c6b0d73a..2931a3b3 100644 --- a/simgear/misc/CMakeLists.txt +++ b/simgear/misc/CMakeLists.txt @@ -9,7 +9,6 @@ set(HEADERS SVGpreserveAspectRatio.hxx argparse.hxx interpolator.hxx - integer_sequence.hxx make_new.hxx sg_dir.hxx sg_hash.hxx @@ -57,10 +56,6 @@ add_executable(test_CSSBorder CSSBorder_test.cxx) add_test(CSSBorder ${EXECUTABLE_OUTPUT_PATH}/test_CSSBorder) target_link_libraries(test_CSSBorder ${TEST_LIBS}) -add_executable(test_integer_sequence integer_sequence_test.cxx) -add_test(integer_sequence ${EXECUTABLE_OUTPUT_PATH}/test_integer_sequence) -target_link_libraries(test_integer_sequence ${TEST_LIBS}) - add_executable(test_tabbed_values tabbed_values_test.cxx) add_test(tabbed_values ${EXECUTABLE_OUTPUT_PATH}/test_tabbed_values) target_link_libraries(test_tabbed_values ${TEST_LIBS}) diff --git a/simgear/nasal/cppbind/Ghost.hxx b/simgear/nasal/cppbind/Ghost.hxx index f09e79c6..59fab718 100644 --- a/simgear/nasal/cppbind/Ghost.hxx +++ b/simgear/nasal/cppbind/Ghost.hxx @@ -24,17 +24,16 @@ #include "NasalObjectHolder.hxx" #include -#include +#include +#include #include #include #include #include #include -#include #include #include -#include #include @@ -62,10 +61,7 @@ namespace osg } template -inline typename boost::enable_if< - boost::is_pointer, - T ->::type +inline std::enable_if_t::value, T> get_pointer(T ptr) { return ptr; @@ -101,8 +97,8 @@ namespace nasal class GhostMetadata { public: - typedef void(*Deleter)(void*); - typedef std::vector > DestroyList; + using Deleter = void(*)(void*); + using DestroyList = std::vector>; static DestroyList _destroy_list; @@ -154,19 +150,6 @@ namespace nasal }; BOOST_MPL_HAS_XXX_TRAIT_DEF(element_type) - - template - struct reduced_type - { - typedef typename boost::remove_cv< - typename boost::remove_reference::type - >::type type; - }; - - template - struct reduced_is_same: - public boost::is_same::type, T2> - {}; } /** @brief Destroy all ghost queued for deletion. @@ -178,8 +161,8 @@ namespace nasal */ void ghostProcessDestroyList(); - typedef SGSharedPtr MethodHolderPtr; - typedef SGWeakPtr MethodHolderWeakPtr; + using MethodHolderPtr = SGSharedPtr; + using MethodHolderWeakPtr = SGWeakPtr; // Dummy template to create shorter and easy to understand compile errors if // trying to wrap the wrong type as a Ghost. @@ -187,9 +170,10 @@ namespace nasal class Ghost { public: - BOOST_STATIC_ASSERT(("Ghost can only wrap shared pointer!" - && is_strong_ref::value - )); + static_assert( + is_strong_ref::value, + "Ghost can only wrap shared pointer!" + ); static Ghost& init(const std::string& name); static bool isInit(); @@ -209,7 +193,7 @@ namespace nasal * int myMember(); * void doSomethingElse(const nasal::CallContext& ctx); * } - * typedef boost::shared_ptr MyClassPtr; + * using MyClassPtr = boost::shared_ptr; * * std::string myOtherFreeMember(int num); * @@ -235,29 +219,22 @@ namespace nasal * @endcode */ template - class Ghost >::type>: + class Ghost::value>>: public internal::GhostMetadata { - // Shared pointer required for Ghost (no weak pointer!) - BOOST_STATIC_ASSERT((is_strong_ref::value)); - public: - typedef typename T::element_type raw_type; - typedef typename shared_ptr_traits::strong_ref strong_ref; - typedef typename shared_ptr_traits::weak_ref weak_ref; - typedef naRef (raw_type::*member_func_t)(const CallContext&); - typedef naRef (*free_func_t)(raw_type&, const CallContext&); - typedef boost::function getter_t; - typedef boost::function setter_t; - typedef boost::function method_t; - typedef boost::function fallback_getter_t; - typedef boost::function fallback_setter_t; + using raw_type = typename T::element_type; + using strong_ref = typename shared_ptr_traits::strong_ref; + using weak_ref = typename shared_ptr_traits::weak_ref; + using member_func_t = naRef (raw_type::*)(const CallContext&); + using free_func_t = naRef (*)(raw_type&, const CallContext&); + using getter_t = boost::function; + using setter_t = boost::function; + using method_t = boost::function; + using fallback_getter_t = + boost::function; + using fallback_setter_t = + boost::function; template using method_variadic_t = boost::function; @@ -272,8 +249,8 @@ namespace nasal protected: - typedef SGSharedPtr SharedPtr; - typedef SGWeakPtr WeakPtr; + using SharedPtr = SGSharedPtr; + using WeakPtr = SGWeakPtr; method_t _method; @@ -372,7 +349,7 @@ namespace nasal MethodHolderPtr func; }; - typedef std::map MemberMap; + using MemberMap = std::map; /** * Register a new ghost type. @@ -409,19 +386,18 @@ namespace nasal * @endcode */ template - typename boost::enable_if - < - boost::is_base_of, - Ghost - >::type& + std::enable_if_t< + std::is_base_of::value, + Ghost& + > bases() { - BOOST_STATIC_ASSERT - (( - boost::is_base_of::value - )); + static_assert( + std::is_base_of::value, + "Not a base class!" + ); - typedef typename BaseGhost::strong_ref base_ref; + using base_ref = typename BaseGhost::strong_ref; BaseGhost* base = BaseGhost::getSingletonPtr(); base->addDerived( @@ -467,17 +443,16 @@ namespace nasal * @endcode */ template - typename boost::disable_if - < - boost::is_base_of, - Ghost - >::type& + std::enable_if_t< + !std::is_base_of::value, + Ghost& + > bases() { - BOOST_STATIC_ASSERT - (( - boost::is_base_of::raw_type, raw_type>::value - )); + static_assert( + std::is_base_of::raw_type, raw_type>::value, + "Not a base class!" + ); return bases< Ghost >(); } @@ -853,10 +828,10 @@ namespace nasal ) { static_assert( - boost::is_convertible::value, - //|| boost::is_convertible::value + std::is_convertible::value, + //|| std::is_convertible::value // TODO check how to do it with pointer... - "First parameter can not be converted from the Ghost raw_type" + "First parameter can not be converted from the Ghost raw_type!" ); return method(name, method_variadic_t(fn)); @@ -868,11 +843,11 @@ namespace nasal */ template static - typename boost::enable_if_c< - boost::is_same::value - || boost::is_same::value, + std::enable_if_t< + std::is_same::value + || std::is_same::value, naRef - >::type + > makeGhost(naContext c, RefType const& ref_ptr) { strong_ref ref(ref_ptr); @@ -927,13 +902,10 @@ namespace nasal if( !naIsVector(na_parents) ) return strong_ref(); - typedef std::vector naRefs; - naRefs parents = from_nasal(c, na_parents); - for( naRefs::const_iterator parent = parents.begin(); - parent != parents.end(); - ++parent ) + auto parents = from_nasal>(c, na_parents); + for(auto parent: parents) { - strong_ref ref = fromNasal(c, *parent); + strong_ref ref = fromNasal(c, parent); if( get_pointer(ref) ) return ref; } @@ -985,8 +957,9 @@ namespace nasal static naGhostType _ghost_type_strong, //!< Stored as shared pointer _ghost_type_weak; //!< Stored as weak shared pointer - typedef naRef (*to_nasal_t)(naContext, const strong_ref&, bool); - typedef strong_ref (*from_nasal_t)(naContext, naRef); + using to_nasal_t = naRef (*)(naContext, const strong_ref&, bool); + using from_nasal_t = strong_ref (*)(naContext, naRef); + struct DerivedInfo { to_nasal_t to_nasal; @@ -999,7 +972,7 @@ namespace nasal {} }; - typedef std::vector DerivedList; + using DerivedList = std::vector; DerivedList _derived_types; static bool isInstance(naGhostType* ghost_type, bool& is_weak) @@ -1013,13 +986,10 @@ namespace nasal template static - typename boost::enable_if_c< - !is_weak, - RefPtr - >::type + std::enable_if_t getPtr(void* ptr) { - typedef shared_ptr_storage storage_type; + using storage_type = shared_ptr_storage; if( ptr ) return storage_type::template get( static_cast(ptr) @@ -1030,13 +1000,13 @@ namespace nasal template static - typename boost::enable_if_c< + std::enable_if_t< is_weak && supports_weak_ref::value, RefPtr - >::type + > getPtr(void* ptr) { - typedef shared_ptr_storage storage_type; + using storage_type = shared_ptr_storage; if( ptr ) return storage_type::template get( static_cast(ptr) @@ -1047,10 +1017,10 @@ namespace nasal template static - typename boost::enable_if_c< + std::enable_if_t< is_weak && !supports_weak_ref::value, RefPtr - >::type + > getPtr(void* ptr) { return RefPtr(); @@ -1066,10 +1036,10 @@ namespace nasal template static - typename boost::enable_if - < boost::is_polymorphic, - naRef - >::type + std::enable_if_t< + std::is_polymorphic::value, + naRef + > toNasal( naContext c, const typename BaseGhost::strong_ref& base_ref, bool strong ) @@ -1078,10 +1048,10 @@ namespace nasal // Check first if passed pointer can by converted to instance of class // this ghost wraps. - if( !boost::is_same - < typename BaseGhost::raw_type, - typename Ghost::raw_type - >::value + if( !std::is_same< + typename BaseGhost::raw_type, + typename Ghost::raw_type + >::value && dynamic_cast(ptr) != ptr ) return naNil(); @@ -1120,13 +1090,13 @@ namespace nasal template static - typename boost::disable_if - < boost::is_polymorphic, - naRef - >::type - toNasal( naContext c, - const typename BaseGhost::strong_ref& ref, - bool strong ) + std::enable_if_t< + !std::is_polymorphic::value, + naRef + > + toNasal( naContext c, + const typename BaseGhost::strong_ref& ref, + bool strong ) { // For non polymorphic classes there is no possibility to get the actual // dynamic type, therefore we can only use its static type. @@ -1149,7 +1119,7 @@ namespace nasal template getter_t to_getter(Ret (raw_type::*getter)() const) { - typedef typename boost::call_traits::param_type param_type; + using param_type = typename boost::call_traits::param_type; naRef(*to_nasal_)(naContext, param_type) = &to_nasal; // Getter signature: naRef(raw_type&, naContext) @@ -1202,7 +1172,7 @@ namespace nasal */ template static - typename boost::disable_if, naRef>::type + std::enable_if_t::value, naRef> method_invoker ( const boost::function& func, @@ -1218,7 +1188,7 @@ namespace nasal */ template static - typename boost::enable_if, naRef>::type + std::enable_if_t::value, naRef> method_invoker ( const boost::function& func, @@ -1236,10 +1206,10 @@ namespace nasal */ template static - typename boost::disable_if< - internal::reduced_is_same, + std::enable_if_t< + !std::is_same, CallContext>::value, typename from_nasal_ptr::return_type - >::type + > arg_from_nasal(const CallContext& ctx, size_t index) { return ctx.requireArg(index); @@ -1250,19 +1220,21 @@ namespace nasal */ template static - typename boost::enable_if< - internal::reduced_is_same, + std::enable_if_t< + std::is_same, CallContext>::value, typename from_nasal_ptr::return_type - >::type + > arg_from_nasal(const CallContext& ctx, size_t) { // Either const CallContext& or CallContext, non-const reference // does not make sense. - BOOST_STATIC_ASSERT( (!boost::is_same::value) ); + static_assert( + !boost::is_same::value, + "Only const reference and value make sense!"); return ctx; }; - typedef std::unique_ptr GhostPtr; + using GhostPtr = std::unique_ptr; MemberMap _members; fallback_getter_t _fallback_getter; fallback_setter_t _fallback_setter; @@ -1302,13 +1274,10 @@ namespace nasal template static - typename boost::enable_if_c< - !is_weak, - naRef - >::type + std::enable_if_t create(naContext c, const strong_ref& ref_ptr) { - typedef shared_ptr_storage storage_type; + using storage_type = shared_ptr_storage; return naNewGhost2( c, &Ghost::_ghost_type_strong, storage_type::ref(ref_ptr) ); @@ -1316,13 +1285,13 @@ namespace nasal template static - typename boost::enable_if_c< + std::enable_if_t< is_weak && supports_weak_ref::value, naRef - >::type + > create(naContext c, const strong_ref& ref_ptr) { - typedef shared_ptr_storage storage_type; + using storage_type = shared_ptr_storage; return naNewGhost2( c, &Ghost::_ghost_type_weak, storage_type::ref(ref_ptr) ); @@ -1330,10 +1299,10 @@ namespace nasal template static - typename boost::enable_if_c< + std::enable_if_t< is_weak && !supports_weak_ref::value, naRef - >::type + > create(naContext, const strong_ref&) { return naNil(); @@ -1342,7 +1311,7 @@ namespace nasal template static void destroy(void *ptr) { - typedef shared_ptr_storage storage_type; + using storage_type = shared_ptr_storage; storage_type::unref( static_cast(ptr) ); @@ -1477,13 +1446,11 @@ namespace nasal template naGhostType - Ghost >::type> - ::_ghost_type_strong; + Ghost::value>>::_ghost_type_strong; template naGhostType - Ghost >::type> - ::_ghost_type_weak; + Ghost::value>>::_ghost_type_weak; } // namespace nasal @@ -1492,15 +1459,13 @@ namespace nasal * Convert every shared pointer to a ghost. */ template -typename boost::enable_if< - nasal::internal::has_element_type< - typename nasal::internal::reduced_type::type - >, +std::enable_if_t< + nasal::internal::has_element_type>::value, naRef ->::type +> to_nasal_helper(naContext c, T ptr) { - typedef typename nasal::shared_ptr_traits::strong_ref strong_ref; + using strong_ref = typename nasal::shared_ptr_traits::strong_ref; return nasal::Ghost::makeGhost(c, ptr); } @@ -1508,15 +1473,13 @@ to_nasal_helper(naContext c, T ptr) * Convert nasal ghosts/hashes to shared pointer (of a ghost). */ template -typename boost::enable_if< - nasal::internal::has_element_type< - typename nasal::internal::reduced_type::type - >, +std::enable_if_t< + nasal::internal::has_element_type>::value, T ->::type +> from_nasal_helper(naContext c, naRef ref, const T*) { - typedef typename nasal::shared_ptr_traits::strong_ref strong_ref; + using strong_ref = typename nasal::shared_ptr_traits::strong_ref; return T(nasal::Ghost::fromNasalChecked(c, ref)); } @@ -1524,11 +1487,11 @@ from_nasal_helper(naContext c, naRef ref, const T*) * Convert any pointer to a SGReferenced based object to a ghost. */ template -typename boost::enable_if_c< - boost::is_base_of::value - || boost::is_base_of::value, +std::enable_if_t< + std::is_base_of::value + || std::is_base_of::value, naRef ->::type +> to_nasal_helper(naContext c, T* ptr) { return nasal::Ghost >::makeGhost(c, SGSharedPtr(ptr)); @@ -1538,20 +1501,14 @@ to_nasal_helper(naContext c, T* ptr) * Convert nasal ghosts/hashes to pointer (of a SGReferenced based ghost). */ template -typename boost::enable_if_c< - boost::is_base_of< - SGReferenced, - typename boost::remove_pointer::type - >::value - || boost::is_base_of< - SGWeakReferenced, - typename boost::remove_pointer::type - >::value, +std::enable_if_t< + std::is_base_of>::value + || std::is_base_of>::value, T ->::type +> from_nasal_helper(naContext c, naRef ref, const T*) { - typedef SGSharedPtr::type> TypeRef; + using TypeRef = SGSharedPtr>; return T(nasal::Ghost::fromNasalChecked(c, ref)); } @@ -1559,10 +1516,10 @@ from_nasal_helper(naContext c, naRef ref, const T*) * Convert any pointer to a osg::Referenced based object to a ghost. */ template -typename boost::enable_if< - boost::is_base_of, +std::enable_if_t< + std::is_base_of::value, naRef ->::type +> to_nasal_helper(naContext c, T* ptr) { return nasal::Ghost >::makeGhost(c, osg::ref_ptr(ptr)); @@ -1572,13 +1529,13 @@ to_nasal_helper(naContext c, T* ptr) * Convert nasal ghosts/hashes to pointer (of a osg::Referenced based ghost). */ template -typename boost::enable_if< - boost::is_base_of::type>, +std::enable_if_t< + std::is_base_of>::value, T ->::type +> from_nasal_helper(naContext c, naRef ref, const T*) { - typedef osg::ref_ptr::type> TypeRef; + using TypeRef = osg::ref_ptr>; return T(nasal::Ghost::fromNasalChecked(c, ref)); } diff --git a/simgear/nasal/cppbind/detail/nasal_traits.hxx b/simgear/nasal/cppbind/detail/nasal_traits.hxx index 26767d76..17e18ecd 100644 --- a/simgear/nasal/cppbind/detail/nasal_traits.hxx +++ b/simgear/nasal/cppbind/detail/nasal_traits.hxx @@ -20,10 +20,7 @@ #ifndef SG_NASAL_TRAITS_HXX_ #define SG_NASAL_TRAITS_HXX_ -#include -#include -#include -#include +#include // Forward declarations class SGReferenced; @@ -56,12 +53,11 @@ namespace osg namespace nasal { template - struct is_vec2: public boost::integral_constant {}; + struct is_vec2: public std::false_type {}; #define SG_MAKE_TRAIT(templ,type,attr)\ template templ\ - struct attr< type >:\ - public boost::integral_constant {}; + struct attr< type >: public std::true_type {}; SG_MAKE_TRAIT(, SGVec2, is_vec2) SG_MAKE_TRAIT(<>, osg::Vec2b, is_vec2) @@ -75,42 +71,34 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2) struct shared_ptr_traits; template - struct is_strong_ref: - public boost::integral_constant - {}; + struct is_strong_ref: public std::false_type {}; template - struct is_weak_ref: - public boost::integral_constant - {}; + struct is_weak_ref: public std::false_type {}; #define SG_MAKE_SHARED_PTR_TRAIT(strong, weak, intrusive)\ template\ struct shared_ptr_traits >\ {\ - typedef strong strong_ref;\ - typedef weak weak_ref;\ - typedef T element_type;\ - typedef boost::integral_constant is_strong;\ - typedef boost::integral_constant is_intrusive;\ + using strong_ref = strong;\ + using weak_ref = weak;\ + using element_type = T;\ + using is_strong = std::true_type;\ + using is_intrusive = std::bool_constant;\ };\ template\ struct shared_ptr_traits >\ {\ - typedef strong strong_ref;\ - typedef weak weak_ref;\ - typedef T element_type;\ - typedef boost::integral_constant is_strong;\ - typedef boost::integral_constant is_intrusive;\ + using strong_ref = strong;\ + using weak_ref = weak;\ + using element_type = T;\ + using is_strong = std::false_type;\ + using is_intrusive = std::bool_constant;\ };\ template\ - struct is_strong_ref >:\ - public boost::integral_constant\ - {};\ + struct is_strong_ref >: public std::true_type {};\ template\ - struct is_weak_ref >:\ - public boost::integral_constant\ - {}; + struct is_weak_ref >: public std::true_type {}; SG_MAKE_SHARED_PTR_TRAIT(SGSharedPtr, SGWeakPtr, true) SG_MAKE_SHARED_PTR_TRAIT(osg::ref_ptr, osg::observer_ptr, true) @@ -119,25 +107,20 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2) #undef SG_MAKE_SHARED_PTR_TRAIT template - struct supports_weak_ref: - public boost::integral_constant - {}; + struct supports_weak_ref: public std::true_type {}; template struct supports_weak_ref >: - public boost::integral_constant< - bool, - boost::is_base_of::value - > + public std::bool_constant::value> {}; template struct shared_ptr_storage { - typedef T storage_type; - typedef typename T::element_type element_type; - typedef typename shared_ptr_traits::strong_ref strong_ref; - typedef typename shared_ptr_traits::weak_ref weak_ref; + using storage_type = T; + using element_type = typename T::element_type; + using strong_ref = typename shared_ptr_traits::strong_ref; + using weak_ref = typename shared_ptr_traits::weak_ref; template static storage_type* ref(U ptr) @@ -151,39 +134,30 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2) template static - typename boost::enable_if< - boost::is_same, - element_type* - >::type + std::enable_if_t::value, element_type*> get(storage_type* ptr) { return get_pointer(*ptr); } + template static - typename boost::enable_if< - boost::mpl::or_< - boost::is_same, - boost::mpl::and_< - boost::is_same, - supports_weak_ref - > - >, + std::enable_if_t< + std::is_same::value + || (std::is_same::value && supports_weak_ref::value), U - >::type + > get(storage_type* ptr) { return U(*ptr); } + template static - typename boost::enable_if< - boost::mpl::and_< - boost::is_same, - boost::mpl::not_ > - >, + std::enable_if_t< + std::is_same::value && !supports_weak_ref::value, U - >::type + > get(storage_type* ptr) { return U(); @@ -195,46 +169,37 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2) template struct intrusive_ptr_storage { - typedef typename T::element_type storage_type; - typedef typename T::element_type element_type; - typedef typename shared_ptr_traits::strong_ref strong_ref; - typedef typename shared_ptr_traits::weak_ref weak_ref; + using storage_type = typename T::element_type; + using element_type = typename T::element_type; + using strong_ref = typename shared_ptr_traits::strong_ref; + using weak_ref = typename shared_ptr_traits::weak_ref; template static - typename boost::enable_if< - boost::is_same, - element_type* - >::type + std::enable_if_t::value, element_type*> get(storage_type* ptr) { return ptr; } + template static - typename boost::enable_if< - boost::mpl::or_< - boost::is_same, - boost::mpl::and_< - boost::is_same, - supports_weak_ref - > - >, + std::enable_if_t< + std::is_same::value + || (std::is_same::value && supports_weak_ref::value), U - >::type + > get(storage_type* ptr) { return U(ptr); } + template static - typename boost::enable_if< - boost::mpl::and_< - boost::is_same, - boost::mpl::not_ > - >, + std::enable_if_t< + std::is_same::value && !supports_weak_ref::value, U - >::type + > get(storage_type* ptr) { return U(); @@ -246,8 +211,8 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2) struct shared_ptr_storage >: public internal::intrusive_ptr_storage > { - typedef T storage_type; - typedef T element_type; + using storage_type = T; + using element_type = T; static storage_type* ref(element_type* ptr) { @@ -265,8 +230,8 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2) struct shared_ptr_storage >: public internal::intrusive_ptr_storage > { - typedef T storage_type; - typedef T element_type; + using storage_type = T; + using element_type = T; static storage_type* ref(element_type* ptr) diff --git a/simgear/simgear_config_cmake.h.in b/simgear/simgear_config_cmake.h.in index b68991da..c3668638 100644 --- a/simgear/simgear_config_cmake.h.in +++ b/simgear/simgear_config_cmake.h.in @@ -16,6 +16,10 @@ #cmakedefine HAVE_MKDTEMP #cmakedefine HAVE_AL_EXT_H #cmakedefine HAVE_STD_INDEX_SEQUENCE +#cmakedefine HAVE_STD_REMOVE_CV_T +#cmakedefine HAVE_STD_REMOVE_CVREF_T +#cmakedefine HAVE_STD_ENABLE_IF_T +#cmakedefine HAVE_STD_BOOL_CONSTANT #cmakedefine GCC_ATOMIC_BUILTINS_FOUND diff --git a/simgear/std/CMakeLists.txt b/simgear/std/CMakeLists.txt new file mode 100644 index 00000000..ad47054e --- /dev/null +++ b/simgear/std/CMakeLists.txt @@ -0,0 +1,21 @@ +include (SimGearComponent) + +set(HEADERS + integer_sequence.hxx + type_traits.hxx +) + +set(SOURCES +) + +simgear_component(std std "${SOURCES}" "${HEADERS}") + +if(ENABLE_TESTS) + add_executable(test_integer_sequence integer_sequence_test.cxx) + add_test(integer_sequence ${EXECUTABLE_OUTPUT_PATH}/test_integer_sequence) + target_link_libraries(test_integer_sequence ${TEST_LIBS}) + + add_executable(test_type_traits type_traits_test.cxx) + add_test(type_traits ${EXECUTABLE_OUTPUT_PATH}/test_type_traits) + target_link_libraries(test_type_traits ${TEST_LIBS}) +endif() diff --git a/simgear/misc/integer_sequence.hxx b/simgear/std/integer_sequence.hxx similarity index 93% rename from simgear/misc/integer_sequence.hxx rename to simgear/std/integer_sequence.hxx index 47f63c43..8272dd43 100644 --- a/simgear/misc/integer_sequence.hxx +++ b/simgear/std/integer_sequence.hxx @@ -17,13 +17,13 @@ // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA -#ifndef SIMGEAR_MISC_INTEGER_SEQUENCE_HXX_ -#define SIMGEAR_MISC_INTEGER_SEQUENCE_HXX_ +#ifndef SIMGEAR_STD_INTEGER_SEQUENCE_HXX_ +#define SIMGEAR_STD_INTEGER_SEQUENCE_HXX_ #include +#include "type_traits.hxx" #include -#include #ifndef HAVE_STD_INDEX_SEQUENCE # include @@ -85,4 +85,4 @@ namespace std } #endif -#endif /* SIMGEAR_MISC_INTEGER_SEQUENCE_HXX_ */ +#endif /* SIMGEAR_STD_INTEGER_SEQUENCE_HXX_ */ diff --git a/simgear/misc/integer_sequence_test.cxx b/simgear/std/integer_sequence_test.cxx similarity index 97% rename from simgear/misc/integer_sequence_test.cxx rename to simgear/std/integer_sequence_test.cxx index 74ccd3c2..9447fdb8 100644 --- a/simgear/misc/integer_sequence_test.cxx +++ b/simgear/std/integer_sequence_test.cxx @@ -1,5 +1,4 @@ -#include "integer_sequence.hxx" - +#include #include template diff --git a/simgear/std/type_traits.hxx b/simgear/std/type_traits.hxx new file mode 100644 index 00000000..8146bada --- /dev/null +++ b/simgear/std/type_traits.hxx @@ -0,0 +1,67 @@ +///@file +/// Type Traits (Provide features of later C++ standards) +// +// Copyright (C) 2017 Thomas Geymayer +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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 +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + +#ifndef SIMGEAR_STD_TYPE_TRAITS_HXX_ +#define SIMGEAR_STD_TYPE_TRAITS_HXX_ + +#include +#include + +namespace std +{ +#ifndef HAVE_STD_REMOVE_CV_T + template + using remove_cv_t = typename remove_cv::type; + + template + using remove_const_t = typename remove_const::type; + + template + using remove_volatile_t = typename remove_volatile::type; + + template + using remove_reference_t = typename remove_reference::type; + + template< class T > + using remove_pointer_t = typename remove_pointer::type; +#endif + +#ifndef HAVE_STD_REMOVE_CVREF_T + template + struct remove_cvref + { + using type = remove_cv_t>; + }; + + template + using remove_cvref_t = typename remove_cvref::type; +#endif + +#ifndef HAVE_STD_ENABLE_IF_T + template + using enable_if_t = typename enable_if::type; +#endif + +#ifndef HAVE_STD_BOOL_CONSTANT + template + using bool_constant = integral_constant; +#endif +} + +#endif /* SIMGEAR_STD_TYPE_TRAITS_HXX_ */ diff --git a/simgear/std/type_traits_test.cxx b/simgear/std/type_traits_test.cxx new file mode 100644 index 00000000..f27f8f0c --- /dev/null +++ b/simgear/std/type_traits_test.cxx @@ -0,0 +1,24 @@ +#include + +using namespace std; + +template +void assert_same() +{ + static_assert(is_same::value, ""); +} + +int main(int argc, char* argv[]) +{ + assert_same, int>(); + assert_same, int volatile>(); + assert_same, int const>(); + assert_same, int const volatile>(); + assert_same, int const volatile>(); + assert_same, int>(); + + assert_same, double>(); + assert_same, integral_constant>(); + + return 0; +} From db3725880e5d22f0c002575b79f6fe09c85deb43 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Sun, 21 Jan 2018 14:20:33 +0100 Subject: [PATCH 23/23] cppbind: simplify with 'auto' --- simgear/nasal/cppbind/Ghost.hxx | 35 +++++++++++++-------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/simgear/nasal/cppbind/Ghost.hxx b/simgear/nasal/cppbind/Ghost.hxx index 59fab718..c1ebbed2 100644 --- a/simgear/nasal/cppbind/Ghost.hxx +++ b/simgear/nasal/cppbind/Ghost.hxx @@ -408,17 +408,14 @@ namespace nasal // Replace any getter that is not available in the current class. // TODO check if this is the correct behavior of function overriding - for( typename BaseGhost::MemberMap::const_iterator member = - base->_members.begin(); - member != base->_members.end(); - ++member ) + for(auto const& base_member: base->_members) { - if( _members.find(member->first) == _members.end() ) - _members[member->first] = member_t + if( _members.find(base_member.first) == _members.end() ) + _members[base_member.first] = member_t ( - member->second.getter, - member->second.setter, - member->second.func + base_member.second.getter, + base_member.second.setter, + base_member.second.func ); } @@ -885,10 +882,9 @@ namespace nasal } // otherwise try the derived classes - for( typename DerivedList::reverse_iterator - derived = getSingletonPtr()->_derived_types.rbegin(); - derived != getSingletonPtr()->_derived_types.rend(); - ++derived ) + for( auto derived = getSingletonPtr()->_derived_types.rbegin(); + derived != getSingletonPtr()->_derived_types.rend(); + ++derived ) { strong_ref ref = (derived->from_nasal)(c, me); @@ -1070,10 +1066,9 @@ namespace nasal static_pointer_cast(base_ref); // Now check if we can further downcast to one of our derived classes. - for( typename DerivedList::reverse_iterator - derived = getSingletonPtr()->_derived_types.rbegin(); - derived != getSingletonPtr()->_derived_types.rend(); - ++derived ) + for( auto derived = getSingletonPtr()->_derived_types.rbegin(); + derived != getSingletonPtr()->_derived_types.rend(); + ++derived ) { naRef ghost = (derived->to_nasal)(c, ref, strong); @@ -1353,9 +1348,7 @@ namespace nasal // return ""; // } - typename MemberMap::iterator member = - getSingletonPtr()->_members.find(key_str); - + auto member = getSingletonPtr()->_members.find(key_str); if( member == getSingletonPtr()->_members.end() ) { fallback_getter_t fallback_get = getSingletonPtr()->_fallback_getter; @@ -1405,7 +1398,7 @@ namespace nasal const std::string key = nasal::from_nasal(c, field); const MemberMap& members = getSingletonPtr()->_members; - typename MemberMap::const_iterator member = members.find(key); + auto member = members.find(key); if( member == members.end() ) { fallback_setter_t fallback_set = getSingletonPtr()->_fallback_setter;