Merge branch 'next' of ssh://git.code.sf.net/p/flightgear/simgear into next
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -14,3 +14,4 @@ CTestTestfile.cmake
|
||||
install_manifest.txt
|
||||
build*
|
||||
Build
|
||||
CMakeLists.txt.user
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -135,6 +138,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)
|
||||
@@ -351,14 +364,35 @@ if (NOT ${HAVE_STD_ISNAN})
|
||||
message(FATAL_ERROR "Your compiler lacks C++11 std::isnan, please update it")
|
||||
endif()
|
||||
|
||||
# Check if the <regex> implementation in the C++ standard library is usable.
|
||||
# This is necessary because g++ 4.8 lies about its C++11 compliance: its
|
||||
# <regex> 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 <regex>
|
||||
|
||||
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)
|
||||
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()
|
||||
@@ -386,10 +420,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")
|
||||
@@ -462,6 +492,8 @@ 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}")
|
||||
|
||||
include(CheckCXXFeatures)
|
||||
|
||||
# use BEFORE to ensure local directories are used first,
|
||||
# ahead of system-installed libs
|
||||
include_directories(BEFORE ${PROJECT_BINARY_DIR}/simgear)
|
||||
|
||||
30
CMakeModules/CheckCXXFeatures.cmake
Normal file
30
CMakeModules/CheckCXXFeatures.cmake
Normal file
@@ -0,0 +1,30 @@
|
||||
check_cxx_source_compiles("
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
std::make_index_sequence<0> t;
|
||||
int main() {}" HAVE_STD_INDEX_SEQUENCE
|
||||
)
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#include <type_traits>
|
||||
std::remove_cv_t<const int> t;
|
||||
int main() {}" HAVE_STD_REMOVE_CV_T
|
||||
)
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#include <type_traits>
|
||||
std::remove_cvref_t<const int&> t;
|
||||
int main() {}" HAVE_STD_REMOVE_CVREF_T
|
||||
)
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#include <type_traits>
|
||||
std::enable_if_t<true, int> t;
|
||||
int main() {}" HAVE_STD_ENABLE_IF_T
|
||||
)
|
||||
|
||||
check_cxx_source_compiles("
|
||||
#include <type_traits>
|
||||
std::bool_constant<true> t;
|
||||
int main() {}" HAVE_STD_BOOL_CONSTANT
|
||||
)
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ foreach( mylibfolder
|
||||
nasal/cppbind
|
||||
props
|
||||
serial
|
||||
std
|
||||
structure
|
||||
threads
|
||||
timing
|
||||
|
||||
@@ -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<SGBucket> siblings;
|
||||
bna_airport.siblings(2, 2, siblings);
|
||||
SG_CHECK_EQUAL(siblings.size(), static_cast<std::vector<SGBucket>::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<std::vector<SGBucket>::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<std::vector<SGBucket>::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<std::vector<SGBucket>::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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -740,52 +740,63 @@ namespace canvas
|
||||
return _path->getTransformedBounds(m);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Path& Path::addSegment(uint8_t cmd, std::initializer_list<float> 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});
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
#define CANVAS_PATH_HXX_
|
||||
|
||||
#include "CanvasElement.hxx"
|
||||
#include <boost/preprocessor/iteration/iterate.hpp>
|
||||
#include <simgear/math/SGRect.hxx>
|
||||
#include <initializer_list>
|
||||
|
||||
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 \
|
||||
<simgear/canvas/elements/detail/add_segment_variadic.hxx>
|
||||
#include BOOST_PP_ITERATE()
|
||||
/** Add a segment with the given command and coordinates */
|
||||
Path& addSegment(uint8_t cmd, std::initializer_list<float> coords = {});
|
||||
|
||||
/** Move path cursor */
|
||||
Path& moveTo(float x_abs, float y_abs);
|
||||
|
||||
@@ -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
|
||||
@@ -189,10 +189,10 @@ namespace canvas
|
||||
if( hfw.empty() )
|
||||
return -1;
|
||||
|
||||
naContext c = naNewContext();
|
||||
try
|
||||
{
|
||||
return hfw(nasal::to_nasal(c, const_cast<NasalWidget*>(this)), w);
|
||||
nasal::Context ctx;
|
||||
return hfw(ctx.to_me(const_cast<NasalWidget*>(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 )
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 <simgear/constants.h>
|
||||
#include <osg/ClipNode>
|
||||
@@ -65,7 +64,7 @@ bool SGPrecipitation::getEnabled() const
|
||||
*/
|
||||
osg::Group* SGPrecipitation::build(void)
|
||||
{
|
||||
osg::Group* group = new osg::Group;
|
||||
osg::ref_ptr<osg::Group> 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<osg::ClipNode> 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<osg::ClipPlane> 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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
239
simgear/environment/test_precipitation.cxx
Normal file
239
simgear/environment/test_precipitation.cxx
Normal file
@@ -0,0 +1,239 @@
|
||||
/**************************************************************************
|
||||
* test_precipitation.cxx -- unit-tests for SGPrecipitation class
|
||||
*
|
||||
* Copyright (C) 2017 Scott Giese (xDraconian) - <scttgs0@gmail.com>
|
||||
*
|
||||
* 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 <cmath>
|
||||
#include <memory>
|
||||
|
||||
#include <osg/Group>
|
||||
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/misc/test_macros.hxx>
|
||||
|
||||
#include "precipitation.hxx"
|
||||
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
|
||||
|
||||
class SGPrecipitationTestFixture : public SGPrecipitation
|
||||
{
|
||||
public:
|
||||
osg::ref_ptr<osg::Group> _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<SGPrecipitationTestFixture>(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;
|
||||
}
|
||||
@@ -32,10 +32,12 @@
|
||||
#include <simgear_config.h>
|
||||
#include "sg_netChannel.hxx"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include <cassert>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <errno.h>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -183,15 +183,6 @@ public:
|
||||
int requestContentLength;
|
||||
};
|
||||
|
||||
class EraseIfClosed
|
||||
{
|
||||
public:
|
||||
bool operator()(simgear::NetChannel* chan) const
|
||||
{
|
||||
return chan->isClosed();
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
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<T*>::iterator it;
|
||||
it = std::remove_if(_channels.begin(), _channels.end(), EraseIfClosed());
|
||||
|
||||
for (typename std::vector<T*>::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()
|
||||
|
||||
@@ -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,9 +16,7 @@ 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 +52,4 @@ add_boost_test(nasal_gc_test
|
||||
add_boost_test(nasal_num
|
||||
SOURCES test/nasal_num_test.cxx
|
||||
LIBRARIES ${TEST_LIBS}
|
||||
)
|
||||
)
|
||||
|
||||
@@ -24,17 +24,16 @@
|
||||
#include "NasalObjectHolder.hxx"
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/std/integer_sequence.hxx>
|
||||
#include <simgear/std/type_traits.hxx>
|
||||
#include <simgear/structure/SGWeakReferenced.hxx>
|
||||
#include <simgear/structure/SGWeakPtr.hxx>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/call_traits.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
#include <boost/mpl/has_xxx.hpp>
|
||||
#include <boost/preprocessor/iteration/iterate.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
|
||||
#include <map>
|
||||
|
||||
@@ -62,10 +61,7 @@ namespace osg
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline typename boost::enable_if<
|
||||
boost::is_pointer<T>,
|
||||
T
|
||||
>::type
|
||||
inline std::enable_if_t<std::is_pointer<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<std::pair<Deleter, void*> > DestroyList;
|
||||
using Deleter = void(*)(void*);
|
||||
using DestroyList = std::vector<std::pair<Deleter, void*>>;
|
||||
|
||||
static DestroyList _destroy_list;
|
||||
|
||||
@@ -154,19 +150,6 @@ namespace nasal
|
||||
};
|
||||
|
||||
BOOST_MPL_HAS_XXX_TRAIT_DEF(element_type)
|
||||
|
||||
template<class T>
|
||||
struct reduced_type
|
||||
{
|
||||
typedef typename boost::remove_cv<
|
||||
typename boost::remove_reference<T>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
template<class T1, class T2>
|
||||
struct reduced_is_same:
|
||||
public boost::is_same<typename reduced_type<T1>::type, T2>
|
||||
{};
|
||||
}
|
||||
|
||||
/** @brief Destroy all ghost queued for deletion.
|
||||
@@ -178,8 +161,8 @@ namespace nasal
|
||||
*/
|
||||
void ghostProcessDestroyList();
|
||||
|
||||
typedef SGSharedPtr<internal::MethodHolder> MethodHolderPtr;
|
||||
typedef SGWeakPtr<internal::MethodHolder> MethodHolderWeakPtr;
|
||||
using MethodHolderPtr = SGSharedPtr<internal::MethodHolder>;
|
||||
using MethodHolderWeakPtr = SGWeakPtr<internal::MethodHolder>;
|
||||
|
||||
// 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<T>::value
|
||||
));
|
||||
static_assert(
|
||||
is_strong_ref<T>::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<MyClass> MyClassPtr;
|
||||
* using MyClassPtr = boost::shared_ptr<MyClass>;
|
||||
*
|
||||
* std::string myOtherFreeMember(int num);
|
||||
*
|
||||
@@ -235,29 +219,25 @@ namespace nasal
|
||||
* @endcode
|
||||
*/
|
||||
template<class T>
|
||||
class Ghost<T, typename boost::enable_if<is_strong_ref<T> >::type>:
|
||||
class Ghost<T, std::enable_if_t<is_strong_ref<T>::value>>:
|
||||
public internal::GhostMetadata
|
||||
{
|
||||
// Shared pointer required for Ghost (no weak pointer!)
|
||||
BOOST_STATIC_ASSERT((is_strong_ref<T>::value));
|
||||
|
||||
public:
|
||||
typedef typename T::element_type raw_type;
|
||||
typedef typename shared_ptr_traits<T>::strong_ref strong_ref;
|
||||
typedef typename shared_ptr_traits<T>::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<naRef(raw_type&, naContext)> getter_t;
|
||||
typedef boost::function<void( raw_type&, naContext, naRef)> setter_t;
|
||||
typedef boost::function<naRef(raw_type&, const CallContext&)> method_t;
|
||||
typedef boost::function<bool( raw_type&,
|
||||
naContext,
|
||||
const std::string&,
|
||||
naRef& )> fallback_getter_t;
|
||||
typedef boost::function<bool( raw_type&,
|
||||
naContext,
|
||||
const std::string&,
|
||||
naRef )> fallback_setter_t;
|
||||
using raw_type = typename T::element_type;
|
||||
using strong_ref = typename shared_ptr_traits<T>::strong_ref;
|
||||
using weak_ref = typename shared_ptr_traits<T>::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<naRef(raw_type&, naContext)>;
|
||||
using setter_t = boost::function<void( raw_type&, naContext, naRef)>;
|
||||
using method_t = boost::function<naRef(raw_type&, const CallContext&)>;
|
||||
using fallback_getter_t =
|
||||
boost::function<bool(raw_type&, naContext, const std::string&, naRef&)>;
|
||||
using fallback_setter_t =
|
||||
boost::function<bool(raw_type&, naContext, const std::string&, naRef)>;
|
||||
|
||||
template<class Ret, class... Args>
|
||||
using method_variadic_t = boost::function<Ret (raw_type&, Args...)>;
|
||||
|
||||
class MethodHolder:
|
||||
public internal::MethodHolder
|
||||
@@ -269,8 +249,8 @@ namespace nasal
|
||||
|
||||
protected:
|
||||
|
||||
typedef SGSharedPtr<MethodHolder> SharedPtr;
|
||||
typedef SGWeakPtr<MethodHolder> WeakPtr;
|
||||
using SharedPtr = SGSharedPtr<MethodHolder>;
|
||||
using WeakPtr = SGWeakPtr<MethodHolder>;
|
||||
|
||||
method_t _method;
|
||||
|
||||
@@ -369,7 +349,7 @@ namespace nasal
|
||||
MethodHolderPtr func;
|
||||
};
|
||||
|
||||
typedef std::map<std::string, member_t> MemberMap;
|
||||
using MemberMap = std::map<std::string, member_t>;
|
||||
|
||||
/**
|
||||
* Register a new ghost type.
|
||||
@@ -406,19 +386,18 @@ namespace nasal
|
||||
* @endcode
|
||||
*/
|
||||
template<class BaseGhost>
|
||||
typename boost::enable_if
|
||||
<
|
||||
boost::is_base_of<GhostMetadata, BaseGhost>,
|
||||
Ghost
|
||||
>::type&
|
||||
std::enable_if_t<
|
||||
std::is_base_of<GhostMetadata, BaseGhost>::value,
|
||||
Ghost&
|
||||
>
|
||||
bases()
|
||||
{
|
||||
BOOST_STATIC_ASSERT
|
||||
((
|
||||
boost::is_base_of<typename BaseGhost::raw_type, raw_type>::value
|
||||
));
|
||||
static_assert(
|
||||
std::is_base_of<typename BaseGhost::raw_type, raw_type>::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(
|
||||
@@ -429,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
|
||||
);
|
||||
}
|
||||
|
||||
@@ -464,17 +440,16 @@ namespace nasal
|
||||
* @endcode
|
||||
*/
|
||||
template<class Base>
|
||||
typename boost::disable_if
|
||||
<
|
||||
boost::is_base_of<GhostMetadata, Base>,
|
||||
Ghost
|
||||
>::type&
|
||||
std::enable_if_t<
|
||||
!std::is_base_of<GhostMetadata, Base>::value,
|
||||
Ghost&
|
||||
>
|
||||
bases()
|
||||
{
|
||||
BOOST_STATIC_ASSERT
|
||||
((
|
||||
boost::is_base_of<typename Ghost<Base>::raw_type, raw_type>::value
|
||||
));
|
||||
static_assert(
|
||||
std::is_base_of<typename Ghost<Base>::raw_type, raw_type>::value,
|
||||
"Not a base class!"
|
||||
);
|
||||
|
||||
return bases< Ghost<Base> >();
|
||||
}
|
||||
@@ -770,7 +745,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}
|
||||
@@ -791,14 +766,73 @@ namespace nasal
|
||||
return method(name, boost::bind(method_invoker<Ret>, func, _1, _2));
|
||||
}
|
||||
|
||||
// Build dependency for CMake, gcc, etc.
|
||||
#define SG_DONT_DO_ANYTHING
|
||||
# include <simgear/nasal/cppbind/detail/functor_templates.hxx>
|
||||
#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<class Ret, class... Args, std::size_t... Indices>
|
||||
Ghost& method( const std::string& name,
|
||||
const method_variadic_t<Ret, Args...>& func,
|
||||
std::index_sequence<Indices...> )
|
||||
{
|
||||
return method<Ret>
|
||||
(
|
||||
name,
|
||||
typename boost::function<Ret (raw_type&, const CallContext&)>
|
||||
( boost::bind(
|
||||
func,
|
||||
_1,
|
||||
boost::bind(&Ghost::arg_from_nasal<Args>, _2, Indices)...
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
#define BOOST_PP_ITERATION_LIMITS (0, 9)
|
||||
#define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/functor_templates.hxx>
|
||||
#include BOOST_PP_ITERATE()
|
||||
template<class Ret, class... Args>
|
||||
Ghost& method( const std::string& name,
|
||||
const method_variadic_t<Ret, Args...>& func )
|
||||
{
|
||||
return method(name, func, std::index_sequence_for<Args...>{});
|
||||
}
|
||||
|
||||
/**\
|
||||
* Bind a member function with an arbitrary number of arguments as method.
|
||||
*/
|
||||
template<class Ret, class... Args>
|
||||
Ghost& method( const std::string& name,
|
||||
Ret (raw_type::*fn)(Args...) )
|
||||
{
|
||||
return method(name, method_variadic_t<Ret, Args...>(fn));
|
||||
}
|
||||
|
||||
template<class Ret, class... Args>
|
||||
Ghost& method( const std::string& name,
|
||||
Ret (raw_type::*fn)(Args...) const )
|
||||
{
|
||||
return method(name, method_variadic_t<Ret, Args...>(fn));
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind free function accepting an instance of raw_type and an arbitrary
|
||||
* number of arguments as method.
|
||||
*/
|
||||
template<class Ret, class Type, class... Args>
|
||||
Ghost& method
|
||||
(
|
||||
const std::string& name,
|
||||
Ret (*fn)(Type, Args ... args)
|
||||
)
|
||||
{
|
||||
static_assert(
|
||||
std::is_convertible<raw_type&, Type>::value,
|
||||
//|| std::is_convertible<raw_type*, Type>::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<Ret, Args...>(fn));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a shared pointer on the heap to handle the reference counting
|
||||
@@ -806,11 +840,11 @@ namespace nasal
|
||||
*/
|
||||
template<class RefType>
|
||||
static
|
||||
typename boost::enable_if_c<
|
||||
boost::is_same<RefType, strong_ref>::value
|
||||
|| boost::is_same<RefType, weak_ref>::value,
|
||||
std::enable_if_t<
|
||||
std::is_same<RefType, strong_ref>::value
|
||||
|| std::is_same<RefType, weak_ref>::value,
|
||||
naRef
|
||||
>::type
|
||||
>
|
||||
makeGhost(naContext c, RefType const& ref_ptr)
|
||||
{
|
||||
strong_ref ref(ref_ptr);
|
||||
@@ -848,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);
|
||||
|
||||
@@ -865,13 +898,10 @@ namespace nasal
|
||||
if( !naIsVector(na_parents) )
|
||||
return strong_ref();
|
||||
|
||||
typedef std::vector<naRef> naRefs;
|
||||
naRefs parents = from_nasal<naRefs>(c, na_parents);
|
||||
for( naRefs::const_iterator parent = parents.begin();
|
||||
parent != parents.end();
|
||||
++parent )
|
||||
auto parents = from_nasal<std::vector<naRef>>(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;
|
||||
}
|
||||
@@ -923,8 +953,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;
|
||||
@@ -937,7 +968,7 @@ namespace nasal
|
||||
{}
|
||||
};
|
||||
|
||||
typedef std::vector<DerivedInfo> DerivedList;
|
||||
using DerivedList = std::vector<DerivedInfo>;
|
||||
DerivedList _derived_types;
|
||||
|
||||
static bool isInstance(naGhostType* ghost_type, bool& is_weak)
|
||||
@@ -951,13 +982,10 @@ namespace nasal
|
||||
|
||||
template<class RefPtr, bool is_weak>
|
||||
static
|
||||
typename boost::enable_if_c<
|
||||
!is_weak,
|
||||
RefPtr
|
||||
>::type
|
||||
std::enable_if_t<!is_weak, RefPtr>
|
||||
getPtr(void* ptr)
|
||||
{
|
||||
typedef shared_ptr_storage<strong_ref> storage_type;
|
||||
using storage_type = shared_ptr_storage<strong_ref>;
|
||||
if( ptr )
|
||||
return storage_type::template get<RefPtr>(
|
||||
static_cast<typename storage_type::storage_type*>(ptr)
|
||||
@@ -968,13 +996,13 @@ namespace nasal
|
||||
|
||||
template<class RefPtr, bool is_weak>
|
||||
static
|
||||
typename boost::enable_if_c<
|
||||
std::enable_if_t<
|
||||
is_weak && supports_weak_ref<T>::value,
|
||||
RefPtr
|
||||
>::type
|
||||
>
|
||||
getPtr(void* ptr)
|
||||
{
|
||||
typedef shared_ptr_storage<weak_ref> storage_type;
|
||||
using storage_type = shared_ptr_storage<weak_ref>;
|
||||
if( ptr )
|
||||
return storage_type::template get<RefPtr>(
|
||||
static_cast<typename storage_type::storage_type*>(ptr)
|
||||
@@ -985,10 +1013,10 @@ namespace nasal
|
||||
|
||||
template<class RefPtr, bool is_weak>
|
||||
static
|
||||
typename boost::enable_if_c<
|
||||
std::enable_if_t<
|
||||
is_weak && !supports_weak_ref<T>::value,
|
||||
RefPtr
|
||||
>::type
|
||||
>
|
||||
getPtr(void* ptr)
|
||||
{
|
||||
return RefPtr();
|
||||
@@ -1004,10 +1032,10 @@ namespace nasal
|
||||
|
||||
template<class BaseGhost>
|
||||
static
|
||||
typename boost::enable_if
|
||||
< boost::is_polymorphic<typename BaseGhost::raw_type>,
|
||||
naRef
|
||||
>::type
|
||||
std::enable_if_t<
|
||||
std::is_polymorphic<typename BaseGhost::raw_type>::value,
|
||||
naRef
|
||||
>
|
||||
toNasal( naContext c,
|
||||
const typename BaseGhost::strong_ref& base_ref,
|
||||
bool strong )
|
||||
@@ -1016,10 +1044,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<const typename Ghost::raw_type*>(ptr) != ptr )
|
||||
return naNil();
|
||||
|
||||
@@ -1038,10 +1066,9 @@ namespace nasal
|
||||
static_pointer_cast<typename Ghost::raw_type>(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);
|
||||
|
||||
@@ -1058,13 +1085,13 @@ namespace nasal
|
||||
|
||||
template<class BaseGhost>
|
||||
static
|
||||
typename boost::disable_if
|
||||
< boost::is_polymorphic<typename BaseGhost::raw_type>,
|
||||
naRef
|
||||
>::type
|
||||
toNasal( naContext c,
|
||||
const typename BaseGhost::strong_ref& ref,
|
||||
bool strong )
|
||||
std::enable_if_t<
|
||||
!std::is_polymorphic<typename BaseGhost::raw_type>::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.
|
||||
@@ -1087,7 +1114,7 @@ namespace nasal
|
||||
template<class Ret>
|
||||
getter_t to_getter(Ret (raw_type::*getter)() const)
|
||||
{
|
||||
typedef typename boost::call_traits<Ret>::param_type param_type;
|
||||
using param_type = typename boost::call_traits<Ret>::param_type;
|
||||
naRef(*to_nasal_)(naContext, param_type) = &to_nasal;
|
||||
|
||||
// Getter signature: naRef(raw_type&, naContext)
|
||||
@@ -1140,7 +1167,7 @@ namespace nasal
|
||||
*/
|
||||
template<class Ret>
|
||||
static
|
||||
typename boost::disable_if<boost::is_void<Ret>, naRef>::type
|
||||
std::enable_if_t<!std::is_void<Ret>::value, naRef>
|
||||
method_invoker
|
||||
(
|
||||
const boost::function<Ret (raw_type&, const CallContext&)>& func,
|
||||
@@ -1148,7 +1175,7 @@ namespace nasal
|
||||
const CallContext& ctx
|
||||
)
|
||||
{
|
||||
return (*to_nasal_ptr<Ret>::get())(ctx.c, func(obj, ctx));
|
||||
return (*to_nasal_ptr<Ret>::get())(ctx.c_ctx(), func(obj, ctx));
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1156,7 +1183,7 @@ namespace nasal
|
||||
*/
|
||||
template<class Ret>
|
||||
static
|
||||
typename boost::enable_if<boost::is_void<Ret>, naRef>::type
|
||||
std::enable_if_t<std::is_void<Ret>::value, naRef>
|
||||
method_invoker
|
||||
(
|
||||
const boost::function<Ret (raw_type&, const CallContext&)>& func,
|
||||
@@ -1174,10 +1201,10 @@ namespace nasal
|
||||
*/
|
||||
template<class Arg>
|
||||
static
|
||||
typename boost::disable_if<
|
||||
internal::reduced_is_same<Arg, CallContext>,
|
||||
std::enable_if_t<
|
||||
!std::is_same<std::remove_cvref_t<Arg>, CallContext>::value,
|
||||
typename from_nasal_ptr<Arg>::return_type
|
||||
>::type
|
||||
>
|
||||
arg_from_nasal(const CallContext& ctx, size_t index)
|
||||
{
|
||||
return ctx.requireArg<Arg>(index);
|
||||
@@ -1188,19 +1215,21 @@ namespace nasal
|
||||
*/
|
||||
template<class Arg>
|
||||
static
|
||||
typename boost::enable_if<
|
||||
internal::reduced_is_same<Arg, CallContext>,
|
||||
std::enable_if_t<
|
||||
std::is_same<std::remove_cvref_t<Arg>, CallContext>::value,
|
||||
typename from_nasal_ptr<Arg>::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<Arg, CallContext&>::value) );
|
||||
static_assert(
|
||||
!boost::is_same<Arg, CallContext&>::value,
|
||||
"Only const reference and value make sense!");
|
||||
return ctx;
|
||||
};
|
||||
|
||||
typedef std::unique_ptr<Ghost> GhostPtr;
|
||||
using GhostPtr = std::unique_ptr<Ghost>;
|
||||
MemberMap _members;
|
||||
fallback_getter_t _fallback_getter;
|
||||
fallback_setter_t _fallback_setter;
|
||||
@@ -1240,13 +1269,10 @@ namespace nasal
|
||||
|
||||
template<bool is_weak>
|
||||
static
|
||||
typename boost::enable_if_c<
|
||||
!is_weak,
|
||||
naRef
|
||||
>::type
|
||||
std::enable_if_t<!is_weak, naRef>
|
||||
create(naContext c, const strong_ref& ref_ptr)
|
||||
{
|
||||
typedef shared_ptr_storage<strong_ref> storage_type;
|
||||
using storage_type = shared_ptr_storage<strong_ref>;
|
||||
return naNewGhost2( c,
|
||||
&Ghost::_ghost_type_strong,
|
||||
storage_type::ref(ref_ptr) );
|
||||
@@ -1254,13 +1280,13 @@ namespace nasal
|
||||
|
||||
template<bool is_weak>
|
||||
static
|
||||
typename boost::enable_if_c<
|
||||
std::enable_if_t<
|
||||
is_weak && supports_weak_ref<T>::value,
|
||||
naRef
|
||||
>::type
|
||||
>
|
||||
create(naContext c, const strong_ref& ref_ptr)
|
||||
{
|
||||
typedef shared_ptr_storage<weak_ref> storage_type;
|
||||
using storage_type = shared_ptr_storage<weak_ref>;
|
||||
return naNewGhost2( c,
|
||||
&Ghost::_ghost_type_weak,
|
||||
storage_type::ref(ref_ptr) );
|
||||
@@ -1268,10 +1294,10 @@ namespace nasal
|
||||
|
||||
template<bool is_weak>
|
||||
static
|
||||
typename boost::enable_if_c<
|
||||
std::enable_if_t<
|
||||
is_weak && !supports_weak_ref<T>::value,
|
||||
naRef
|
||||
>::type
|
||||
>
|
||||
create(naContext, const strong_ref&)
|
||||
{
|
||||
return naNil();
|
||||
@@ -1280,7 +1306,7 @@ namespace nasal
|
||||
template<class Type>
|
||||
static void destroy(void *ptr)
|
||||
{
|
||||
typedef shared_ptr_storage<Type> storage_type;
|
||||
using storage_type = shared_ptr_storage<Type>;
|
||||
storage_type::unref(
|
||||
static_cast<typename storage_type::storage_type*>(ptr)
|
||||
);
|
||||
@@ -1322,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;
|
||||
@@ -1374,7 +1398,7 @@ namespace nasal
|
||||
const std::string key = nasal::from_nasal<std::string>(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;
|
||||
@@ -1415,13 +1439,11 @@ namespace nasal
|
||||
|
||||
template<class T>
|
||||
naGhostType
|
||||
Ghost<T, typename boost::enable_if<is_strong_ref<T> >::type>
|
||||
::_ghost_type_strong;
|
||||
Ghost<T, std::enable_if_t<is_strong_ref<T>::value>>::_ghost_type_strong;
|
||||
|
||||
template<class T>
|
||||
naGhostType
|
||||
Ghost<T, typename boost::enable_if<is_strong_ref<T> >::type>
|
||||
::_ghost_type_weak;
|
||||
Ghost<T, std::enable_if_t<is_strong_ref<T>::value>>::_ghost_type_weak;
|
||||
|
||||
} // namespace nasal
|
||||
|
||||
@@ -1430,15 +1452,13 @@ namespace nasal
|
||||
* Convert every shared pointer to a ghost.
|
||||
*/
|
||||
template<class T>
|
||||
typename boost::enable_if<
|
||||
nasal::internal::has_element_type<
|
||||
typename nasal::internal::reduced_type<T>::type
|
||||
>,
|
||||
std::enable_if_t<
|
||||
nasal::internal::has_element_type<std::remove_cvref_t<T>>::value,
|
||||
naRef
|
||||
>::type
|
||||
>
|
||||
to_nasal_helper(naContext c, T ptr)
|
||||
{
|
||||
typedef typename nasal::shared_ptr_traits<T>::strong_ref strong_ref;
|
||||
using strong_ref = typename nasal::shared_ptr_traits<T>::strong_ref;
|
||||
return nasal::Ghost<strong_ref>::makeGhost(c, ptr);
|
||||
}
|
||||
|
||||
@@ -1446,15 +1466,13 @@ to_nasal_helper(naContext c, T ptr)
|
||||
* Convert nasal ghosts/hashes to shared pointer (of a ghost).
|
||||
*/
|
||||
template<class T>
|
||||
typename boost::enable_if<
|
||||
nasal::internal::has_element_type<
|
||||
typename nasal::internal::reduced_type<T>::type
|
||||
>,
|
||||
std::enable_if_t<
|
||||
nasal::internal::has_element_type<std::remove_cvref_t<T>>::value,
|
||||
T
|
||||
>::type
|
||||
>
|
||||
from_nasal_helper(naContext c, naRef ref, const T*)
|
||||
{
|
||||
typedef typename nasal::shared_ptr_traits<T>::strong_ref strong_ref;
|
||||
using strong_ref = typename nasal::shared_ptr_traits<T>::strong_ref;
|
||||
return T(nasal::Ghost<strong_ref>::fromNasalChecked(c, ref));
|
||||
}
|
||||
|
||||
@@ -1462,11 +1480,11 @@ from_nasal_helper(naContext c, naRef ref, const T*)
|
||||
* Convert any pointer to a SGReferenced based object to a ghost.
|
||||
*/
|
||||
template<class T>
|
||||
typename boost::enable_if_c<
|
||||
boost::is_base_of<SGReferenced, T>::value
|
||||
|| boost::is_base_of<SGWeakReferenced, T>::value,
|
||||
std::enable_if_t<
|
||||
std::is_base_of<SGReferenced, T>::value
|
||||
|| std::is_base_of<SGWeakReferenced, T>::value,
|
||||
naRef
|
||||
>::type
|
||||
>
|
||||
to_nasal_helper(naContext c, T* ptr)
|
||||
{
|
||||
return nasal::Ghost<SGSharedPtr<T> >::makeGhost(c, SGSharedPtr<T>(ptr));
|
||||
@@ -1476,20 +1494,14 @@ to_nasal_helper(naContext c, T* ptr)
|
||||
* Convert nasal ghosts/hashes to pointer (of a SGReferenced based ghost).
|
||||
*/
|
||||
template<class T>
|
||||
typename boost::enable_if_c<
|
||||
boost::is_base_of<
|
||||
SGReferenced,
|
||||
typename boost::remove_pointer<T>::type
|
||||
>::value
|
||||
|| boost::is_base_of<
|
||||
SGWeakReferenced,
|
||||
typename boost::remove_pointer<T>::type
|
||||
>::value,
|
||||
std::enable_if_t<
|
||||
std::is_base_of<SGReferenced, std::remove_pointer_t<T>>::value
|
||||
|| std::is_base_of<SGWeakReferenced, std::remove_pointer_t<T>>::value,
|
||||
T
|
||||
>::type
|
||||
>
|
||||
from_nasal_helper(naContext c, naRef ref, const T*)
|
||||
{
|
||||
typedef SGSharedPtr<typename boost::remove_pointer<T>::type> TypeRef;
|
||||
using TypeRef = SGSharedPtr<std::remove_pointer_t<T>>;
|
||||
return T(nasal::Ghost<TypeRef>::fromNasalChecked(c, ref));
|
||||
}
|
||||
|
||||
@@ -1497,10 +1509,10 @@ from_nasal_helper(naContext c, naRef ref, const T*)
|
||||
* Convert any pointer to a osg::Referenced based object to a ghost.
|
||||
*/
|
||||
template<class T>
|
||||
typename boost::enable_if<
|
||||
boost::is_base_of<osg::Referenced, T>,
|
||||
std::enable_if_t<
|
||||
std::is_base_of<osg::Referenced, T>::value,
|
||||
naRef
|
||||
>::type
|
||||
>
|
||||
to_nasal_helper(naContext c, T* ptr)
|
||||
{
|
||||
return nasal::Ghost<osg::ref_ptr<T> >::makeGhost(c, osg::ref_ptr<T>(ptr));
|
||||
@@ -1510,13 +1522,13 @@ to_nasal_helper(naContext c, T* ptr)
|
||||
* Convert nasal ghosts/hashes to pointer (of a osg::Referenced based ghost).
|
||||
*/
|
||||
template<class T>
|
||||
typename boost::enable_if<
|
||||
boost::is_base_of<osg::Referenced, typename boost::remove_pointer<T>::type>,
|
||||
std::enable_if_t<
|
||||
std::is_base_of<osg::Referenced, std::remove_pointer_t<T>>::value,
|
||||
T
|
||||
>::type
|
||||
>
|
||||
from_nasal_helper(naContext c, naRef ref, const T*)
|
||||
{
|
||||
typedef osg::ref_ptr<typename boost::remove_pointer<T>::type> TypeRef;
|
||||
using TypeRef = osg::ref_ptr<std::remove_pointer_t<T>>;
|
||||
return T(nasal::Ghost<TypeRef>::fromNasalChecked(c, ref));
|
||||
}
|
||||
|
||||
|
||||
@@ -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<T>(args[index]);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
naRef to_nasal(T arg) const
|
||||
{
|
||||
return nasal::to_nasal(c, arg);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
typename from_nasal_ptr<T>::return_type
|
||||
from_nasal(naRef ref) const
|
||||
{
|
||||
return (*from_nasal_ptr<T>::get())(c, ref);
|
||||
}
|
||||
|
||||
naContext c;
|
||||
naRef me;
|
||||
size_t argc;
|
||||
naRef *args;
|
||||
naRef me;
|
||||
size_t argc;
|
||||
naRef *args;
|
||||
};
|
||||
|
||||
} // namespace nasal
|
||||
|
||||
@@ -17,13 +17,79 @@
|
||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
|
||||
#include "NasalContext.hxx"
|
||||
#include "NasalHash.hxx"
|
||||
#include "NasalString.hxx"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace nasal
|
||||
{
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
ContextWrapper::ContextWrapper(naContext ctx):
|
||||
_ctx(ctx)
|
||||
{
|
||||
assert(_ctx);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
ContextWrapper::operator naContext()
|
||||
{
|
||||
return _ctx;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
naContext ContextWrapper::c_ctx() const
|
||||
{
|
||||
return const_cast<naContext>(_ctx);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Hash ContextWrapper::newHash()
|
||||
{
|
||||
return Hash(_ctx);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
String ContextWrapper::newString(const char* str)
|
||||
{
|
||||
return String(_ctx, str);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
naRef ContextWrapper::callMethod( Me me,
|
||||
naRef code,
|
||||
std::initializer_list<naRef> args )
|
||||
{
|
||||
naRef ret = naCallMethodCtx(
|
||||
_ctx,
|
||||
code,
|
||||
me,
|
||||
args.size(),
|
||||
const_cast<naRef*>(args.begin()),
|
||||
naNil() // locals
|
||||
);
|
||||
|
||||
if( const char* error = naGetError(_ctx) )
|
||||
throw std::runtime_error(error);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
naRef ContextWrapper::newVector(std::initializer_list<naRef> 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 +98,7 @@ namespace nasal
|
||||
Context::~Context()
|
||||
{
|
||||
naFreeContext(_ctx);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Context::operator naContext()
|
||||
{
|
||||
return _ctx;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
Hash Context::newHash()
|
||||
{
|
||||
return Hash(_ctx);
|
||||
_ctx = nullptr;
|
||||
}
|
||||
|
||||
} // namespace nasal
|
||||
|
||||
@@ -19,28 +19,110 @@
|
||||
#ifndef SG_NASAL_CONTEXT_HXX_
|
||||
#define SG_NASAL_CONTEXT_HXX_
|
||||
|
||||
#include "NasalHash.hxx"
|
||||
#include "cppbind_fwd.hxx"
|
||||
#include "NasalMe.hxx"
|
||||
|
||||
#include <boost/call_traits.hpp>
|
||||
#include <initializer_list>
|
||||
|
||||
namespace nasal
|
||||
{
|
||||
|
||||
/**
|
||||
* 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<class... Vals>
|
||||
naRef newVector(Vals ... vals)
|
||||
{
|
||||
return newVector({to_nasal(vals)...});
|
||||
}
|
||||
|
||||
/** Raise a nasal runtime error */
|
||||
template<class... Args>
|
||||
void runtimeError(const char* fmt, Args ... args) const
|
||||
{
|
||||
naRuntimeError(c_ctx(), fmt, args...);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
naRef to_nasal(T arg) const
|
||||
{
|
||||
return nasal::to_nasal(_ctx, arg);
|
||||
}
|
||||
|
||||
template<class T, std::size_t N>
|
||||
naRef to_nasal(const T(&array)[N]) const
|
||||
{
|
||||
return nasal::to_nasal(_ctx, array);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Me to_me(T arg) const
|
||||
{
|
||||
return Me{ to_nasal(arg) };
|
||||
}
|
||||
|
||||
template<class T>
|
||||
typename from_nasal_ptr<T>::return_type
|
||||
from_nasal(naRef ref) const
|
||||
{
|
||||
return (*from_nasal_ptr<T>::get())(_ctx, ref);
|
||||
}
|
||||
|
||||
naRef callMethod(Me me, naRef code, std::initializer_list<naRef> args);
|
||||
|
||||
template<class Ret, class... Args>
|
||||
Ret callMethod( Me me,
|
||||
naRef code,
|
||||
typename boost::call_traits<Args>::param_type ... args )
|
||||
{
|
||||
// TODO warn if with Ret == void something different to nil is returned?
|
||||
return from_nasal<Ret>(callMethod(
|
||||
me,
|
||||
code,
|
||||
{ to_nasal<typename boost::call_traits<Args>::param_type>(args)... }
|
||||
));
|
||||
}
|
||||
|
||||
protected:
|
||||
naContext _ctx;
|
||||
|
||||
// Not exposed to avoid confusion of intializer_list<naRef> to variadic
|
||||
// arguments
|
||||
naRef newVector(std::initializer_list<naRef> 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
|
||||
|
||||
#include "from_nasal.hxx"
|
||||
#include "to_nasal.hxx"
|
||||
|
||||
#endif /* SG_NASAL_CONTEXT_HXX_ */
|
||||
|
||||
44
simgear/nasal/cppbind/NasalMe.hxx
Normal file
44
simgear/nasal/cppbind/NasalMe.hxx
Normal file
@@ -0,0 +1,44 @@
|
||||
///@file
|
||||
//
|
||||
// Copyright (C) 2018 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// 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 <simgear/nasal/nasal.h>
|
||||
|
||||
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_ */
|
||||
75
simgear/nasal/cppbind/NasalMethodHolder.hxx
Normal file
75
simgear/nasal/cppbind/NasalMethodHolder.hxx
Normal file
@@ -0,0 +1,75 @@
|
||||
///@file
|
||||
//
|
||||
// Copyright (C) 2018 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// 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 Ret, class... Args>
|
||||
class NasalMethodHolder
|
||||
{
|
||||
using Holder = ObjectHolder<SGReferenced>;
|
||||
|
||||
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<class... CArgs>
|
||||
Ret call(Me self, CArgs ... args)
|
||||
{
|
||||
nasal::Context ctx;
|
||||
return ctx.callMethod<Ret, CArgs...>(
|
||||
self,
|
||||
_code->get_naRef(),
|
||||
args...
|
||||
);
|
||||
}
|
||||
|
||||
template<class... CArgs>
|
||||
Ret call(CArgs ... args)
|
||||
{
|
||||
return call(Me{}, args...);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace nasal
|
||||
|
||||
#endif /* SG_NASAL_METHOD_HOLDER_HXX_ */
|
||||
@@ -45,18 +45,18 @@ namespace nasal
|
||||
|
||||
bool valid() const;
|
||||
|
||||
template<class Ret, class ... Args>
|
||||
template<class Ret, class... Args>
|
||||
Ret callMethod(const std::string& name, Args ... args)
|
||||
{
|
||||
if( !_nasal_impl.valid() )
|
||||
return Ret();
|
||||
|
||||
Context ctx;
|
||||
auto func = get_member<boost::function<Ret (nasal::Me, Args...)>>(
|
||||
auto func = get_member<boost::function<Ret (Me, Args...)>>(
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -42,6 +42,8 @@ namespace nasal
|
||||
{
|
||||
public:
|
||||
|
||||
using Ref = SGSharedPtr<ObjectHolder<Base>>;
|
||||
|
||||
/**
|
||||
* @param obj Object to save
|
||||
*/
|
||||
@@ -84,7 +86,7 @@ namespace nasal
|
||||
*
|
||||
* @param obj Object to save
|
||||
*/
|
||||
static SGSharedPtr<ObjectHolder<Base> > makeShared(naRef obj);
|
||||
static Ref makeShared(naRef obj);
|
||||
|
||||
protected:
|
||||
naRef _ref;
|
||||
@@ -155,10 +157,10 @@ namespace nasal
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
template<class Base>
|
||||
SGSharedPtr<ObjectHolder<Base> >
|
||||
typename ObjectHolder<Base>::Ref
|
||||
ObjectHolder<Base>::makeShared(naRef obj)
|
||||
{
|
||||
return SGSharedPtr<ObjectHolder<Base> >( new ObjectHolder<Base>(obj) );
|
||||
return Ref( new ObjectHolder<Base>(obj) );
|
||||
}
|
||||
|
||||
} // namespace nasal
|
||||
|
||||
@@ -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;
|
||||
|
||||
60
simgear/nasal/cppbind/cppbind_fwd.hxx
Normal file
60
simgear/nasal/cppbind/cppbind_fwd.hxx
Normal file
@@ -0,0 +1,60 @@
|
||||
///@file
|
||||
/// Nasal C++ Bindings forward declarations
|
||||
///
|
||||
// Copyright (C) 2018 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// 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 <simgear/nasal/nasal.h>
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
namespace nasal
|
||||
{
|
||||
|
||||
class bad_nasal_cast;
|
||||
|
||||
class CallContext;
|
||||
class Context;
|
||||
class ContextWrapper;
|
||||
class Hash;
|
||||
struct Me;
|
||||
class Object;
|
||||
class String;
|
||||
|
||||
template<class, class>
|
||||
class Ghost;
|
||||
|
||||
template<class T>
|
||||
naRef to_nasal(naContext c, T arg);
|
||||
|
||||
template<class T, std::size_t N>
|
||||
naRef to_nasal(naContext c, const T(&array)[N]);
|
||||
|
||||
template<class T>
|
||||
T from_nasal(naContext c, naRef ref);
|
||||
|
||||
template<class Var>
|
||||
struct from_nasal_ptr;
|
||||
|
||||
template<class T>
|
||||
T get_member(naContext c, naRef obj, const std::string& name);
|
||||
|
||||
} // namespace nasal
|
||||
|
||||
#endif /* SG_NASAL_CPPBIND_FWD_HXX_ */
|
||||
@@ -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<A##n>::param_type a##n
|
||||
# define SG_CALL_ARG(z, n, dummy)\
|
||||
to_nasal<typename boost::call_traits<A##n>::param_type>(ctx, a##n)
|
||||
|
||||
template<
|
||||
class Ret
|
||||
BOOST_PP_ENUM_TRAILING_PARAMS(n, class A)
|
||||
>
|
||||
typename boost::disable_if<boost::is_void<Ret>, Ret>::type
|
||||
callNasalMethod( const ObjectHolder<SGReferenced>* 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<Ret*>(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<boost::is_void<Ret>, Ret>::type
|
||||
callNasalMethod( const ObjectHolder<SGReferenced>* 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_PP_IF(n, A0, void), Me>,
|
||||
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, A))>
|
||||
>::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_ENUM_TRAILING_PARAMS(n, A)>,
|
||||
ObjectHolder<SGReferenced>::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<A0, Me>,
|
||||
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, A))>
|
||||
>::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<SGReferenced>::makeShared(code),
|
||||
BOOST_PP_ENUM_SHIFTED_PARAMS(BOOST_PP_INC(n), _)
|
||||
);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#undef n
|
||||
#endif // SG_DONT_DO_ANYTHING
|
||||
@@ -24,20 +24,15 @@
|
||||
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
#include <simgear/math/SGRect.hxx>
|
||||
#include <simgear/nasal/nasal.h>
|
||||
#include <simgear/nasal/cppbind/NasalContext.hxx>
|
||||
#include <simgear/nasal/cppbind/NasalMe.hxx>
|
||||
#include <simgear/nasal/cppbind/NasalMethodHolder.hxx>
|
||||
#include <simgear/nasal/cppbind/NasalObjectHolder.hxx>
|
||||
#include <simgear/nasal/cppbind/to_nasal.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/call_traits.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/preprocessor/control/if.hpp>
|
||||
#include <boost/preprocessor/iteration/iterate.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_trailing.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_shifted_params.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
|
||||
@@ -48,8 +43,6 @@ class SGPath;
|
||||
|
||||
namespace nasal
|
||||
{
|
||||
class Hash;
|
||||
class String;
|
||||
|
||||
/**
|
||||
* Thrown when converting a type from/to Nasal has failed
|
||||
@@ -76,27 +69,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):
|
||||
_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 +110,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 <simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx>
|
||||
#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<class Sig>
|
||||
boost::function<Sig>
|
||||
from_nasal_helper(naContext c, naRef ref, boost::function<Sig>*)
|
||||
template<class Ret, class... Args>
|
||||
boost::function<Ret (Args...)>
|
||||
from_nasal_helper(naContext c, naRef ref, const boost::function<Ret (Args...)>*)
|
||||
{
|
||||
if( naIsNil(ref) )
|
||||
return boost::function<Sig>();
|
||||
return {};
|
||||
|
||||
if( !naIsCode(ref)
|
||||
&& !naIsCCode(ref)
|
||||
&& !naIsFunc(ref) )
|
||||
throw bad_nasal_cast("not a function");
|
||||
|
||||
return detail::boostFunctionFromNasal(ref, static_cast<Sig*>(0));
|
||||
return NasalMethodHolder<Ret, Args...>(ref);
|
||||
}
|
||||
|
||||
template<class Sig>
|
||||
typename boost::enable_if< boost::is_function<Sig>,
|
||||
boost::function<Sig>
|
||||
>::type
|
||||
from_nasal_helper(naContext c, naRef ref, Sig*)
|
||||
template<class Ret, class... Args>
|
||||
boost::function<Ret (Args...)>
|
||||
from_nasal_helper(naContext c, naRef ref, Ret (*const)(Args...))
|
||||
{
|
||||
return from_nasal_helper(c, ref, static_cast<boost::function<Sig>*>(0));
|
||||
return
|
||||
from_nasal_helper(c, ref, static_cast<boost::function<Ret (Args...)>*>(0));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,21 +202,6 @@ namespace nasal
|
||||
return SGRect<T>(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 <simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx>
|
||||
#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 <simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx>
|
||||
#include BOOST_PP_ITERATE()
|
||||
}
|
||||
|
||||
} // namespace nasal
|
||||
|
||||
#endif /* SG_FROM_NASAL_HELPER_HXX_ */
|
||||
|
||||
@@ -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<Ret (raw_type& BOOST_PP_ENUM_TRAILING_PARAMS(n,A))>
|
||||
|
||||
/**
|
||||
* 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<A##n>, _2, n)
|
||||
#else
|
||||
// VS (2008, 2010, ... ?) only allow this version.
|
||||
# define SG_GHOST_REQUIRE_ARG(z, n, dummy)\
|
||||
boost::bind(&Ghost::arg_from_nasal<A##n>, _2, n)
|
||||
#endif
|
||||
|
||||
return method<Ret>
|
||||
(
|
||||
name,
|
||||
typename boost::function<Ret (raw_type&, const CallContext&)>
|
||||
( 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<raw_type&, Type>::value
|
||||
//|| boost::is_convertible<raw_type*, Type>::value
|
||||
// TODO check how to do it with pointer...
|
||||
));
|
||||
return method<Ret>(name, SG_GHOST_FUNC_TYPE(fn));
|
||||
}
|
||||
|
||||
#undef n
|
||||
#undef SG_GHOST_TYPEDEF_FUNC_TYPE
|
||||
#endif // SG_DONT_DO_ANYTHING
|
||||
@@ -20,10 +20,7 @@
|
||||
#ifndef SG_NASAL_TRAITS_HXX_
|
||||
#define SG_NASAL_TRAITS_HXX_
|
||||
|
||||
#include <boost/mpl/logical.hpp>
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
#include <boost/type_traits/is_base_of.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <simgear/std/type_traits.hxx>
|
||||
|
||||
// Forward declarations
|
||||
class SGReferenced;
|
||||
@@ -56,12 +53,11 @@ namespace osg
|
||||
namespace nasal
|
||||
{
|
||||
template<class T>
|
||||
struct is_vec2: public boost::integral_constant<bool, false> {};
|
||||
struct is_vec2: public std::false_type {};
|
||||
|
||||
#define SG_MAKE_TRAIT(templ,type,attr)\
|
||||
template templ\
|
||||
struct attr< type >:\
|
||||
public boost::integral_constant<bool, true> {};
|
||||
struct attr< type >: public std::true_type {};
|
||||
|
||||
SG_MAKE_TRAIT(<class T>, SGVec2<T>, 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<class T>
|
||||
struct is_strong_ref:
|
||||
public boost::integral_constant<bool, false>
|
||||
{};
|
||||
struct is_strong_ref: public std::false_type {};
|
||||
|
||||
template<class T>
|
||||
struct is_weak_ref:
|
||||
public boost::integral_constant<bool, false>
|
||||
{};
|
||||
struct is_weak_ref: public std::false_type {};
|
||||
|
||||
#define SG_MAKE_SHARED_PTR_TRAIT(strong, weak, intrusive)\
|
||||
template<class T>\
|
||||
struct shared_ptr_traits<strong<T> >\
|
||||
{\
|
||||
typedef strong<T> strong_ref;\
|
||||
typedef weak<T> weak_ref;\
|
||||
typedef T element_type;\
|
||||
typedef boost::integral_constant<bool, true> is_strong;\
|
||||
typedef boost::integral_constant<bool, intrusive> is_intrusive;\
|
||||
using strong_ref = strong<T>;\
|
||||
using weak_ref = weak<T>;\
|
||||
using element_type = T;\
|
||||
using is_strong = std::true_type;\
|
||||
using is_intrusive = std::bool_constant<intrusive>;\
|
||||
};\
|
||||
template<class T>\
|
||||
struct shared_ptr_traits<weak<T> >\
|
||||
{\
|
||||
typedef strong<T> strong_ref;\
|
||||
typedef weak<T> weak_ref;\
|
||||
typedef T element_type;\
|
||||
typedef boost::integral_constant<bool, false> is_strong;\
|
||||
typedef boost::integral_constant<bool, intrusive> is_intrusive;\
|
||||
using strong_ref = strong<T>;\
|
||||
using weak_ref = weak<T>;\
|
||||
using element_type = T;\
|
||||
using is_strong = std::false_type;\
|
||||
using is_intrusive = std::bool_constant<intrusive>;\
|
||||
};\
|
||||
template<class T>\
|
||||
struct is_strong_ref<strong<T> >:\
|
||||
public boost::integral_constant<bool, true>\
|
||||
{};\
|
||||
struct is_strong_ref<strong<T> >: public std::true_type {};\
|
||||
template<class T>\
|
||||
struct is_weak_ref<weak<T> >:\
|
||||
public boost::integral_constant<bool, true>\
|
||||
{};
|
||||
struct is_weak_ref<weak<T> >: 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<class T>
|
||||
struct supports_weak_ref:
|
||||
public boost::integral_constant<bool, true>
|
||||
{};
|
||||
struct supports_weak_ref: public std::true_type {};
|
||||
|
||||
template<class T>
|
||||
struct supports_weak_ref<SGSharedPtr<T> >:
|
||||
public boost::integral_constant<
|
||||
bool,
|
||||
boost::is_base_of<SGWeakReferenced, T>::value
|
||||
>
|
||||
public std::bool_constant<std::is_base_of<SGWeakReferenced, T>::value>
|
||||
{};
|
||||
|
||||
template<class T>
|
||||
struct shared_ptr_storage
|
||||
{
|
||||
typedef T storage_type;
|
||||
typedef typename T::element_type element_type;
|
||||
typedef typename shared_ptr_traits<T>::strong_ref strong_ref;
|
||||
typedef typename shared_ptr_traits<T>::weak_ref weak_ref;
|
||||
using storage_type = T;
|
||||
using element_type = typename T::element_type;
|
||||
using strong_ref = typename shared_ptr_traits<T>::strong_ref;
|
||||
using weak_ref = typename shared_ptr_traits<T>::weak_ref;
|
||||
|
||||
template<class U>
|
||||
static storage_type* ref(U ptr)
|
||||
@@ -151,39 +134,30 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2)
|
||||
|
||||
template<class U>
|
||||
static
|
||||
typename boost::enable_if<
|
||||
boost::is_same<U, element_type*>,
|
||||
element_type*
|
||||
>::type
|
||||
std::enable_if_t<std::is_same<U, element_type*>::value, element_type*>
|
||||
get(storage_type* ptr)
|
||||
{
|
||||
return get_pointer(*ptr);
|
||||
}
|
||||
|
||||
template<class U>
|
||||
static
|
||||
typename boost::enable_if<
|
||||
boost::mpl::or_<
|
||||
boost::is_same<U, strong_ref>,
|
||||
boost::mpl::and_<
|
||||
boost::is_same<U, weak_ref>,
|
||||
supports_weak_ref<U>
|
||||
>
|
||||
>,
|
||||
std::enable_if_t<
|
||||
std::is_same<U, strong_ref>::value
|
||||
|| (std::is_same<U, weak_ref>::value && supports_weak_ref<U>::value),
|
||||
U
|
||||
>::type
|
||||
>
|
||||
get(storage_type* ptr)
|
||||
{
|
||||
return U(*ptr);
|
||||
}
|
||||
|
||||
template<class U>
|
||||
static
|
||||
typename boost::enable_if<
|
||||
boost::mpl::and_<
|
||||
boost::is_same<U, weak_ref>,
|
||||
boost::mpl::not_<supports_weak_ref<U> >
|
||||
>,
|
||||
std::enable_if_t<
|
||||
std::is_same<U, weak_ref>::value && !supports_weak_ref<U>::value,
|
||||
U
|
||||
>::type
|
||||
>
|
||||
get(storage_type* ptr)
|
||||
{
|
||||
return U();
|
||||
@@ -195,46 +169,37 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2)
|
||||
template<class T>
|
||||
struct intrusive_ptr_storage
|
||||
{
|
||||
typedef typename T::element_type storage_type;
|
||||
typedef typename T::element_type element_type;
|
||||
typedef typename shared_ptr_traits<T>::strong_ref strong_ref;
|
||||
typedef typename shared_ptr_traits<T>::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<T>::strong_ref;
|
||||
using weak_ref = typename shared_ptr_traits<T>::weak_ref;
|
||||
|
||||
template<class U>
|
||||
static
|
||||
typename boost::enable_if<
|
||||
boost::is_same<U, element_type*>,
|
||||
element_type*
|
||||
>::type
|
||||
std::enable_if_t<std::is_same<U, element_type*>::value, element_type*>
|
||||
get(storage_type* ptr)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template<class U>
|
||||
static
|
||||
typename boost::enable_if<
|
||||
boost::mpl::or_<
|
||||
boost::is_same<U, strong_ref>,
|
||||
boost::mpl::and_<
|
||||
boost::is_same<U, weak_ref>,
|
||||
supports_weak_ref<U>
|
||||
>
|
||||
>,
|
||||
std::enable_if_t<
|
||||
std::is_same<U, strong_ref>::value
|
||||
|| (std::is_same<U, weak_ref>::value && supports_weak_ref<U>::value),
|
||||
U
|
||||
>::type
|
||||
>
|
||||
get(storage_type* ptr)
|
||||
{
|
||||
return U(ptr);
|
||||
}
|
||||
|
||||
template<class U>
|
||||
static
|
||||
typename boost::enable_if<
|
||||
boost::mpl::and_<
|
||||
boost::is_same<U, weak_ref>,
|
||||
boost::mpl::not_<supports_weak_ref<U> >
|
||||
>,
|
||||
std::enable_if_t<
|
||||
std::is_same<U, weak_ref>::value && !supports_weak_ref<U>::value,
|
||||
U
|
||||
>::type
|
||||
>
|
||||
get(storage_type* ptr)
|
||||
{
|
||||
return U();
|
||||
@@ -246,8 +211,8 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2)
|
||||
struct shared_ptr_storage<SGSharedPtr<T> >:
|
||||
public internal::intrusive_ptr_storage<SGSharedPtr<T> >
|
||||
{
|
||||
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<osg::ref_ptr<T> >:
|
||||
public internal::intrusive_ptr_storage<osg::ref_ptr<T> >
|
||||
{
|
||||
typedef T storage_type;
|
||||
typedef T element_type;
|
||||
using storage_type = T;
|
||||
using element_type = T;
|
||||
|
||||
|
||||
static storage_type* ref(element_type* ptr)
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
#include <simgear/math/SGRect.hxx>
|
||||
#include <simgear/nasal/nasal.h>
|
||||
#include <simgear/nasal/cppbind/cppbind_fwd.hxx>
|
||||
|
||||
#include <boost/function/function_fwd.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
@@ -40,8 +40,6 @@ class SGPath;
|
||||
|
||||
namespace nasal
|
||||
{
|
||||
class CallContext;
|
||||
class Hash;
|
||||
|
||||
typedef boost::function<naRef (CallContext)> free_function_t;
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#define SG_FROM_NASAL_HXX_
|
||||
|
||||
#include <simgear/nasal/cppbind/detail/from_nasal_helper.hxx>
|
||||
#include <type_traits>
|
||||
|
||||
namespace nasal
|
||||
{
|
||||
@@ -52,8 +53,8 @@ namespace nasal
|
||||
template<class Var>
|
||||
struct from_nasal_ptr
|
||||
{
|
||||
typedef typename boost::remove_const
|
||||
< typename boost::remove_reference<Var>::type
|
||||
typedef typename std::remove_const
|
||||
< typename std::remove_reference<Var>::type
|
||||
>::type return_type;
|
||||
typedef return_type(*type)(naContext, naRef);
|
||||
|
||||
|
||||
@@ -20,50 +20,29 @@
|
||||
#ifndef SG_NASAL_TESTCONTEXT_HXX_
|
||||
#define SG_NASAL_TESTCONTEXT_HXX_
|
||||
|
||||
#include <simgear/nasal/cppbind/NasalCallContext.hxx>
|
||||
#include <simgear/nasal/cppbind/NasalContext.hxx>
|
||||
|
||||
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<class T>
|
||||
T from_str(const std::string& str)
|
||||
template<class T = naRef>
|
||||
T exec(const std::string& code, nasal::Me me)
|
||||
{
|
||||
return from_nasal<T>(to_nasal(str));
|
||||
return from_nasal<T>(execImpl(code, me));
|
||||
}
|
||||
|
||||
naRef exec(const std::string& code_str, nasal::Me me)
|
||||
{
|
||||
int err_line = -1;
|
||||
naRef code = naParseCode( c, to_nasal("<TextContext::exec>"), 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<class T>
|
||||
template<class T = naRef>
|
||||
T exec(const std::string& code)
|
||||
{
|
||||
return from_nasal<T>(exec(code, naNil()));
|
||||
return from_nasal<T>(execImpl(code, nasal::Me{}));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
@@ -71,6 +50,26 @@ class TestContext:
|
||||
{
|
||||
return from_nasal<T>(to_nasal(str));
|
||||
}
|
||||
|
||||
protected:
|
||||
naRef execImpl(const std::string& code_str, nasal::Me me)
|
||||
{
|
||||
int err_line = -1;
|
||||
naRef code = naParseCode( _ctx, to_nasal("<TextContext::exec>"), 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_ */
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#define BOOST_TEST_MODULE cppbind
|
||||
#include <BoostTestTargetConfig.h>
|
||||
|
||||
#include "TestContext.hxx"
|
||||
|
||||
#include <simgear/nasal/cppbind/Ghost.hxx>
|
||||
#include <simgear/nasal/cppbind/NasalHash.hxx>
|
||||
#include <simgear/nasal/cppbind/NasalString.hxx>
|
||||
@@ -117,42 +119,42 @@ naRef f_freeFunction(nasal::CallContext c) { return c.requireArg<naRef>(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<int>(c, r), ENUM_ANOTHER);
|
||||
r = c.to_nasal(ENUM_ANOTHER);
|
||||
BOOST_CHECK_EQUAL(c.from_nasal<int>(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<std::string>(c, r), "Test");
|
||||
BOOST_CHECK_EQUAL(c.from_nasal<std::string>(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<std::string>(c, r), "Test");
|
||||
BOOST_CHECK_EQUAL(c.from_nasal<std::string>(r), "Test");
|
||||
|
||||
r = to_nasal(c, 42);
|
||||
r = c.to_nasal(42);
|
||||
BOOST_CHECK_EQUAL(naNumValue(r).num, 42);
|
||||
BOOST_CHECK_EQUAL(from_nasal<int>(c, r), 42);
|
||||
BOOST_CHECK_EQUAL(c.from_nasal<int>(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<float>(c, r), 4.2f);
|
||||
BOOST_CHECK_EQUAL(c.from_nasal<float>(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<SGVec2f>(c, r), vec);
|
||||
r = c.to_nasal(vec);
|
||||
BOOST_CHECK_EQUAL(c.from_nasal<SGVec2f>(r), vec);
|
||||
|
||||
std::vector<int> std_vec;
|
||||
r = to_nasal(c, std_vec);
|
||||
r = c.to_nasal(std_vec);
|
||||
|
||||
r = to_nasal(c, "string");
|
||||
BOOST_CHECK_THROW(from_nasal<int>(c, r), bad_nasal_cast);
|
||||
r = c.to_nasal("string");
|
||||
BOOST_CHECK_THROW(c.from_nasal<int>(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<simgear::StringMap>(c, r);
|
||||
simgear::StringMap string_map = c.from_nasal<simgear::StringMap>(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");
|
||||
@@ -216,7 +218,7 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
|
||||
// passed on to function
|
||||
typedef boost::function<int (Me, int)> MeIntFunc;
|
||||
MeIntFunc fmeint = hash.get<MeIntFunc>("func");
|
||||
BOOST_CHECK_EQUAL(fmeint(naNil(), 5), 5);
|
||||
BOOST_CHECK_EQUAL(fmeint(Me{}, 5), 5);
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Test exposing classes to Nasal
|
||||
@@ -260,81 +262,81 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
|
||||
Ghost<SGWeakRefBasedPtr>::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<SGWeakRefBasedPtr>(c, nasal_ref),
|
||||
ptr2 = from_nasal<SGWeakRefBasedPtr>(c, nasal_ptr);
|
||||
SGWeakRefBasedPtr ptr1 = c.from_nasal<SGWeakRefBasedPtr>(nasal_ref),
|
||||
ptr2 = c.from_nasal<SGWeakRefBasedPtr>(nasal_ptr);
|
||||
|
||||
BOOST_CHECK_EQUAL(weak_ptr, ptr1);
|
||||
BOOST_CHECK_EQUAL(weak_ptr, ptr2);
|
||||
|
||||
|
||||
BOOST_REQUIRE( Ghost<BasePtr>::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<unsigned long (Me)> MemFunc;
|
||||
MemFunc fGetThis = from_nasal<MemFunc>(c, thisGetter);
|
||||
MemFunc fGetThis = c.from_nasal<MemFunc>(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 = 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<SGReferenceBasedClass*>(c, na_ref_based),
|
||||
BOOST_CHECK_EQUAL( c.from_nasal<SGReferenceBasedClass*>(na_ref_based),
|
||||
ref_based.get() );
|
||||
BOOST_CHECK_EQUAL( from_nasal<SGRefBasedPtr>(c, na_ref_based), ref_based );
|
||||
BOOST_CHECK_EQUAL( c.from_nasal<SGRefBasedPtr>(na_ref_based), ref_based );
|
||||
|
||||
BOOST_CHECK_EQUAL( from_nasal<BasePtr>(c, derived), d3 );
|
||||
BOOST_CHECK_NE( from_nasal<BasePtr>(c, derived), d2 );
|
||||
BOOST_CHECK_EQUAL( from_nasal<DerivedPtr>(c, derived),
|
||||
BOOST_CHECK_EQUAL( c.from_nasal<BasePtr>(derived), d3 );
|
||||
BOOST_CHECK_NE( c.from_nasal<BasePtr>(derived), d2 );
|
||||
BOOST_CHECK_EQUAL( c.from_nasal<DerivedPtr>(derived),
|
||||
boost::dynamic_pointer_cast<Derived>(d3) );
|
||||
BOOST_CHECK_EQUAL( from_nasal<DoubleDerived2Ptr>(c, derived),
|
||||
BOOST_CHECK_EQUAL( c.from_nasal<DoubleDerived2Ptr>(derived),
|
||||
boost::dynamic_pointer_cast<DoubleDerived2>(d3) );
|
||||
BOOST_CHECK_THROW( from_nasal<DoubleDerivedPtr>(c, derived), bad_nasal_cast );
|
||||
BOOST_CHECK_THROW( c.from_nasal<DoubleDerivedPtr>(derived), bad_nasal_cast );
|
||||
|
||||
std::map<std::string, BasePtr> instances;
|
||||
BOOST_CHECK( naIsHash(to_nasal(c, instances)) );
|
||||
BOOST_CHECK( naIsHash(c.to_nasal(instances)) );
|
||||
|
||||
std::map<std::string, DerivedPtr> instances_d;
|
||||
BOOST_CHECK( naIsHash(to_nasal(c, instances_d)) );
|
||||
BOOST_CHECK( naIsHash(c.to_nasal(instances_d)) );
|
||||
|
||||
std::map<std::string, int> int_map;
|
||||
BOOST_CHECK( naIsHash(to_nasal(c, int_map)) );
|
||||
BOOST_CHECK( naIsHash(c.to_nasal(int_map)) );
|
||||
|
||||
std::map<std::string, std::vector<int> > 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<std::string>("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<BasePtr>(c, obj.get_naRef()), d3 );
|
||||
BOOST_CHECK_EQUAL( c.from_nasal<BasePtr>(obj.get_naRef()), d3 );
|
||||
|
||||
// Check recursive parents (aka parent-of-parent)
|
||||
std::vector<naRef> parents2;
|
||||
parents2.push_back(obj.get_naRef());
|
||||
Hash derived_obj(c);
|
||||
derived_obj.set("parents", parents2);
|
||||
BOOST_CHECK_EQUAL( from_nasal<BasePtr>(c, derived_obj.get_naRef()), d3 );
|
||||
BOOST_CHECK_EQUAL( c.from_nasal<BasePtr>(derived_obj.get_naRef()), d3 );
|
||||
|
||||
std::vector<naRef> nasal_objects;
|
||||
nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d) );
|
||||
nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d2) );
|
||||
nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d3) );
|
||||
naRef obj_vec = to_nasal(c, nasal_objects);
|
||||
naRef obj_vec = c.to_nasal(nasal_objects);
|
||||
|
||||
std::vector<BasePtr> objects = from_nasal<std::vector<BasePtr> >(c, obj_vec);
|
||||
std::vector<BasePtr> objects = c.from_nasal<std::vector<BasePtr> >(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<int>("me.test = 3;", Me{derived}), 3 );
|
||||
|
||||
BOOST_REQUIRE( !naGetError(c) ); // TODO real error check (this seems to
|
||||
// always return 0...
|
||||
BOOST_CHECK_EQUAL( from_nasal<int>(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<std::string>(c, ret), "generic-get" );
|
||||
}
|
||||
// Calling generic (fallback) getter
|
||||
BOOST_CHECK_EQUAL( c.exec<std::string>("var a = me.get_test;", Me{derived}),
|
||||
"generic-get" );
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Test nasal::CallContext
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
int int_vec[] = {1,2,3};
|
||||
std::map<std::string, std::string> 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<std::string>(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<std::string>(c, string.get_naRef()), "Test" );
|
||||
String string( c.to_nasal("Test") );
|
||||
BOOST_CHECK_EQUAL( c.from_nasal<std::string>(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<int>(naVec_get(vec, 0)), 1);
|
||||
BOOST_CHECK_EQUAL(ctx.from_nasal<int>(naVec_get(vec, 1)), 2);
|
||||
BOOST_CHECK_EQUAL(ctx.from_nasal<double>(naVec_get(vec, 2)), 3.4);
|
||||
BOOST_CHECK_EQUAL(ctx.from_nasal<std::string>(naVec_get(vec, 3)), "test");
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#define BOOST_TEST_MODULE cppbind
|
||||
#include <BoostTestTargetConfig.h>
|
||||
|
||||
#include "TestContext.hxx"
|
||||
|
||||
#include <simgear/nasal/cppbind/Ghost.hxx>
|
||||
#include <simgear/nasal/cppbind/NasalContext.hxx>
|
||||
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/weak_ptr.hpp>
|
||||
|
||||
@@ -186,3 +189,44 @@ BOOST_AUTO_TEST_CASE( storage_traits )
|
||||
|
||||
nasal::shared_ptr_storage<DerivedWeakPtr>::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<TestClass>;
|
||||
auto set_func = boost::function<
|
||||
void (TestClass&, int, const std::string&, const std::string&, int)
|
||||
>(&TestClass::set);
|
||||
nasal::Ghost<TestClassPtr>::init("TestClass")
|
||||
.method("set", set_func)
|
||||
.method("setReverse", set_func, std::index_sequence<3,2,1,0>{});
|
||||
|
||||
TestContext ctx;
|
||||
auto test = boost::make_shared<TestClass>();
|
||||
|
||||
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_me(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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<typename StringType>
|
||||
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<typename StringType>
|
||||
inline SGPropertyNode*
|
||||
makeNode(SGPropertyNode* parent, const StringType& name)
|
||||
{
|
||||
return parent->getNode(name, true);
|
||||
}
|
||||
}
|
||||
|
||||
// For boost::hash
|
||||
|
||||
@@ -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 <simgear/structure/Singleton.hxx>
|
||||
|
||||
#include "Effect.hxx"
|
||||
/**
|
||||
* Support classes for parsing effects.
|
||||
*/
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
|
||||
@@ -77,9 +77,9 @@ osg::Vec2d eventToWindowCoords(const osgGA::GUIEventAdapter& ea)
|
||||
SGPropertyNode* modelRoot,
|
||||
SGSharedPtr<SGCondition const> 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<SGPropertyNode_ptr> bindings;
|
||||
|
||||
@@ -264,7 +264,8 @@ public:
|
||||
SGPropertyNode* modelRoot,
|
||||
osg::Group *node,
|
||||
SGSharedPtr<SGCondition const> 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<SGCondition const> 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<SGPropertyNode_ptr> bindings;
|
||||
|
||||
|
||||
@@ -11,10 +11,15 @@
|
||||
#cmakedefine HAVE_TIMEGM
|
||||
|
||||
#cmakedefine HAVE_STD_ISNAN
|
||||
#cmakedefine HAVE_WORKING_STD_REGEX
|
||||
#cmakedefine HAVE_WINDOWS_H
|
||||
#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
|
||||
|
||||
|
||||
21
simgear/std/CMakeLists.txt
Normal file
21
simgear/std/CMakeLists.txt
Normal file
@@ -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()
|
||||
88
simgear/std/integer_sequence.hxx
Normal file
88
simgear/std/integer_sequence.hxx
Normal file
@@ -0,0 +1,88 @@
|
||||
///@file
|
||||
/// Metaprogramming Integer sequence (Is in C++14 but not C++11)
|
||||
//
|
||||
// Copyright (C) 2017 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// 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_INTEGER_SEQUENCE_HXX_
|
||||
#define SIMGEAR_STD_INTEGER_SEQUENCE_HXX_
|
||||
|
||||
#include <simgear/simgear_config.h>
|
||||
#include "type_traits.hxx"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#ifndef HAVE_STD_INDEX_SEQUENCE
|
||||
# include <cstddef>
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<class T, T... Ints>
|
||||
struct integer_sequence
|
||||
{
|
||||
static_assert(
|
||||
std::is_integral<T>::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<class T, class Seq, T El>
|
||||
struct append;
|
||||
|
||||
template<class T, T... Ints, T Int>
|
||||
struct append<T, std::integer_sequence<T, Ints...>, Int>
|
||||
{
|
||||
using type = std::integer_sequence<T, Ints..., Int>;
|
||||
};
|
||||
|
||||
template<class T, std::size_t N>
|
||||
struct sequence_gen
|
||||
{
|
||||
using type =
|
||||
typename append<T, typename sequence_gen<T, N - 1>::type, N - 1>::type;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct sequence_gen<T, 0>
|
||||
{
|
||||
using type = std::integer_sequence<T>;
|
||||
};
|
||||
}}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<size_t... Ints>
|
||||
using index_sequence = integer_sequence<size_t, Ints...>;
|
||||
|
||||
template<class T, size_t N>
|
||||
using make_integer_sequence =
|
||||
typename simgear::detail::sequence_gen<T, N>::type;
|
||||
|
||||
template<size_t N>
|
||||
using make_index_sequence = make_integer_sequence<size_t, N>;
|
||||
|
||||
template<class... T>
|
||||
using index_sequence_for = make_index_sequence<sizeof...(T)>;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SIMGEAR_STD_INTEGER_SEQUENCE_HXX_ */
|
||||
46
simgear/std/integer_sequence_test.cxx
Normal file
46
simgear/std/integer_sequence_test.cxx
Normal file
@@ -0,0 +1,46 @@
|
||||
#include <simgear/std/integer_sequence.hxx>
|
||||
#include <iostream>
|
||||
|
||||
template<class T>
|
||||
void print(const T& v, std::size_t i)
|
||||
{
|
||||
std::cout << "arg #" << i << ": '" << v << "', ";
|
||||
}
|
||||
|
||||
template<class... Args, std::size_t... Is>
|
||||
void doIt_impl(Args ... args, std::index_sequence<Is...>)
|
||||
{
|
||||
std::initializer_list<char>{(print(args, Is), '0')...};
|
||||
}
|
||||
|
||||
template<class... Args>
|
||||
void doIt(Args ... args)
|
||||
{
|
||||
static_assert(sizeof...(Args) == std::index_sequence_for<Args...>::size(), "");
|
||||
|
||||
doIt_impl<Args...>(args..., std::index_sequence_for<Args...>{});
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
static_assert(std::is_same<std::integer_sequence<char>::value_type, char>::value, "");
|
||||
static_assert(std::is_same<std::integer_sequence<long long>::value_type, long long>::value, "");
|
||||
static_assert(std::is_same<std::index_sequence<>::value_type, std::size_t>::value, "");
|
||||
|
||||
static_assert(std::is_same<std::make_index_sequence<0>, std::index_sequence<>>::value, "");
|
||||
static_assert(std::is_same<std::make_index_sequence<1>, std::index_sequence<0>>::value, "");
|
||||
static_assert(std::is_same<std::make_index_sequence<2>, std::index_sequence<0, 1>>::value, "");
|
||||
static_assert(std::is_same<std::make_index_sequence<3>, std::index_sequence<0, 1, 2>>::value, "");
|
||||
static_assert(std::is_same<std::make_index_sequence<4>, std::index_sequence<0, 1, 2, 3>>::value, "");
|
||||
static_assert(std::is_same<std::make_index_sequence<5>, std::index_sequence<0, 1, 2, 3, 4>>::value, "");
|
||||
static_assert(std::is_same<std::make_index_sequence<6>, std::index_sequence<0, 1, 2, 3, 4, 5>>::value, "");
|
||||
static_assert(std::is_same<std::make_index_sequence<7>, std::index_sequence<0, 1, 2, 3, 4, 5, 6>>::value, "");
|
||||
static_assert(std::is_same<std::make_index_sequence<8>, 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<float, int, double>::size() == 3, "");
|
||||
|
||||
std::cout << std::make_integer_sequence<int, 5>::size() << std::endl;
|
||||
doIt(1, 2, 3, "hallo", 3.4, 3.52f);
|
||||
return 0;
|
||||
}
|
||||
67
simgear/std/type_traits.hxx
Normal file
67
simgear/std/type_traits.hxx
Normal file
@@ -0,0 +1,67 @@
|
||||
///@file
|
||||
/// Type Traits (Provide features of later C++ standards)
|
||||
//
|
||||
// Copyright (C) 2017 Thomas Geymayer <tomgey@gmail.com>
|
||||
//
|
||||
// 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 <simgear/simgear_config.h>
|
||||
#include <type_traits>
|
||||
|
||||
namespace std
|
||||
{
|
||||
#ifndef HAVE_STD_REMOVE_CV_T
|
||||
template<class T>
|
||||
using remove_cv_t = typename remove_cv<T>::type;
|
||||
|
||||
template<class T>
|
||||
using remove_const_t = typename remove_const<T>::type;
|
||||
|
||||
template<class T>
|
||||
using remove_volatile_t = typename remove_volatile<T>::type;
|
||||
|
||||
template<class T>
|
||||
using remove_reference_t = typename remove_reference<T>::type;
|
||||
|
||||
template< class T >
|
||||
using remove_pointer_t = typename remove_pointer<T>::type;
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STD_REMOVE_CVREF_T
|
||||
template<class T>
|
||||
struct remove_cvref
|
||||
{
|
||||
using type = remove_cv_t<remove_reference_t<T>>;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
using remove_cvref_t = typename remove_cvref<T>::type;
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STD_ENABLE_IF_T
|
||||
template<bool B, class T = void>
|
||||
using enable_if_t = typename enable_if<B, T>::type;
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STD_BOOL_CONSTANT
|
||||
template <bool B>
|
||||
using bool_constant = integral_constant<bool, B>;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* SIMGEAR_STD_TYPE_TRAITS_HXX_ */
|
||||
24
simgear/std/type_traits_test.cxx
Normal file
24
simgear/std/type_traits_test.cxx
Normal file
@@ -0,0 +1,24 @@
|
||||
#include <simgear/std/type_traits.hxx>
|
||||
|
||||
using namespace std;
|
||||
|
||||
template<class T, class U>
|
||||
void assert_same()
|
||||
{
|
||||
static_assert(is_same<T, U>::value, "");
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
assert_same<remove_cv_t<int const volatile>, int>();
|
||||
assert_same<remove_const_t<int const volatile>, int volatile>();
|
||||
assert_same<remove_volatile_t<int const volatile>, int const>();
|
||||
assert_same<remove_reference_t<int const volatile&>, int const volatile>();
|
||||
assert_same<remove_pointer_t<int const volatile*>, int const volatile>();
|
||||
assert_same<remove_cvref_t<int const volatile&>, int>();
|
||||
|
||||
assert_same<enable_if_t<true, double>, double>();
|
||||
assert_same<bool_constant<true>, integral_constant<bool, true>>();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -36,10 +36,9 @@
|
||||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/structure/Singleton.hxx>
|
||||
|
||||
/// Expression tree implementation.
|
||||
|
||||
namespace simgear
|
||||
{
|
||||
/// Expression tree implementation.
|
||||
namespace expression
|
||||
{
|
||||
enum Type {
|
||||
|
||||
@@ -29,9 +29,10 @@ 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 Ret, class ... Args>
|
||||
template<class Ret, class... Args>
|
||||
class function_list<Ret(Args...)>:
|
||||
public std::vector<boost::function<Ret(Args...)>>
|
||||
{
|
||||
@@ -54,7 +55,7 @@ namespace simgear
|
||||
* Handle a list of callbacks with the same signature as the given
|
||||
* boost::function type.
|
||||
*/
|
||||
template<class Ret, class ... Args>
|
||||
template<class Ret, class... Args>
|
||||
class function_list<boost::function<Ret(Args...)>>:
|
||||
public function_list<Ret(Args...)>
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user