Merge branch 'next' of ssh://git.code.sf.net/p/flightgear/simgear into next
This commit is contained in:
@@ -14,3 +14,4 @@ CTestTestfile.cmake
|
|||||||
install_manifest.txt
|
install_manifest.txt
|
||||||
build*
|
build*
|
||||||
Build
|
Build
|
||||||
|
CMakeLists.txt.user
|
||||||
|
|||||||
+40
-8
@@ -7,6 +7,9 @@ if(COMMAND cmake_policy)
|
|||||||
if(POLICY CMP0042)
|
if(POLICY CMP0042)
|
||||||
cmake_policy(SET CMP0042 NEW)
|
cmake_policy(SET CMP0042 NEW)
|
||||||
endif()
|
endif()
|
||||||
|
if(POLICY CMP0067)
|
||||||
|
cmake_policy(SET CMP0067 NEW)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
@@ -135,6 +138,16 @@ include (DetectArch)
|
|||||||
# keep the compatability link option as the default
|
# 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)
|
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)
|
if (MSVC)
|
||||||
GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_BINARY_DIR} PATH)
|
GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_BINARY_DIR} PATH)
|
||||||
if (CMAKE_CL_64)
|
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")
|
message(FATAL_ERROR "Your compiler lacks C++11 std::isnan, please update it")
|
||||||
endif()
|
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)
|
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||||
set(WARNING_FLAGS_CXX "-Wall -fPIC")
|
set(WARNING_FLAGS_CXX "-Wall -fPIC")
|
||||||
set(WARNING_FLAGS_C "-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)
|
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4)
|
||||||
message(WARNING "GCC 4.4 will be required soon, please upgrade")
|
message(WARNING "GCC 4.4 will be required soon, please upgrade")
|
||||||
endif()
|
endif()
|
||||||
@@ -386,10 +420,6 @@ if (CLANG)
|
|||||||
# fix Boost compilation :(
|
# fix Boost compilation :(
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
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(ENABLE_SIMD)
|
||||||
if (X86 OR X86_64)
|
if (X86 OR X86_64)
|
||||||
set(CMAKE_C_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse")
|
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_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}")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MSVC_LD_FLAGS}")
|
||||||
|
|
||||||
|
include(CheckCXXFeatures)
|
||||||
|
|
||||||
# use BEFORE to ensure local directories are used first,
|
# use BEFORE to ensure local directories are used first,
|
||||||
# ahead of system-installed libs
|
# ahead of system-installed libs
|
||||||
include_directories(BEFORE ${PROJECT_BINARY_DIR}/simgear)
|
include_directories(BEFORE ${PROJECT_BINARY_DIR}/simgear)
|
||||||
|
|||||||
@@ -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
|
documentation. It has a .cxx extension so that emacs will happily
|
||||||
autoindent correctly. */
|
autoindent correctly. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \namespace simgear
|
||||||
|
* \brief \ref index "SimGear" main namespace.
|
||||||
|
*/
|
||||||
/** \mainpage SimGear
|
/** \mainpage SimGear
|
||||||
* Simulation, Visualization, and Game development libraries.
|
* Simulation, Visualization, and Game development libraries.
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ foreach( mylibfolder
|
|||||||
nasal/cppbind
|
nasal/cppbind
|
||||||
props
|
props
|
||||||
serial
|
serial
|
||||||
|
std
|
||||||
structure
|
structure
|
||||||
threads
|
threads
|
||||||
timing
|
timing
|
||||||
|
|||||||
@@ -87,19 +87,47 @@ void testBasic()
|
|||||||
SG_CHECK_EQUAL(atAntiMeridian2.get_chunk_lon(), -180);
|
SG_CHECK_EQUAL(atAntiMeridian2.get_chunk_lon(), -180);
|
||||||
SG_CHECK_EQUAL(atAntiMeridian2.get_x(), 0);
|
SG_CHECK_EQUAL(atAntiMeridian2.get_x(), 0);
|
||||||
|
|
||||||
// check comparisom operator overload
|
// check comparison operator overload
|
||||||
SGBucket b4(5.11, 55.1);
|
SGBucket b4(5.11, 55.1);
|
||||||
SG_VERIFY(b1 == b4); // should be equal
|
SG_VERIFY(b1 == b4); // should be equal
|
||||||
SG_VERIFY(b1 == b1);
|
SG_VERIFY(b1 == b1);
|
||||||
SG_VERIFY(b1 != defBuck);
|
SG_VERIFY(b1 != defBuck);
|
||||||
SG_VERIFY(b1 != b2);
|
SG_VERIFY(b1 != b2);
|
||||||
|
|
||||||
// check wrapping/clipping of inputs
|
// check wrapping/clipping of inputs
|
||||||
SGBucket wrapMeridian(-200.0, 45.0);
|
SGBucket wrapMeridian(-200.0, 45.0);
|
||||||
SG_CHECK_EQUAL(wrapMeridian.get_chunk_lon(), 160);
|
SG_CHECK_EQUAL(wrapMeridian.get_chunk_lon(), 160);
|
||||||
|
|
||||||
SGBucket clipPole(48.9, 91);
|
SGBucket clipPole(48.9, 91);
|
||||||
SG_CHECK_EQUAL(clipPole.get_chunk_lat(), 89);
|
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()
|
void testPolar()
|
||||||
@@ -153,7 +181,6 @@ void testPolar()
|
|||||||
|
|
||||||
SGBucket b7(200, 89.88);
|
SGBucket b7(200, 89.88);
|
||||||
SG_CHECK_EQUAL(b7.get_chunk_lon(), -168);
|
SG_CHECK_EQUAL(b7.get_chunk_lon(), -168);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// test the tiles just below the pole (between 86 & 89 degrees N/S)
|
// test the tiles just below the pole (between 86 & 89 degrees N/S)
|
||||||
@@ -220,7 +247,7 @@ void testPolarOffset()
|
|||||||
|
|
||||||
SG_CHECK_EQUAL(b2.gen_index(), sgBucketOffset(-11.7, -89.6, -2, 0));
|
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 b3(-170, 89.1);
|
||||||
SGBucket b4(b3.sibling(-1, 0));
|
SGBucket b4(b3.sibling(-1, 0));
|
||||||
SG_CHECK_EQUAL(b4.get_chunk_lat(), 89);
|
SG_CHECK_EQUAL(b4.get_chunk_lat(), 89);
|
||||||
@@ -263,8 +290,59 @@ void testOffsetWrap()
|
|||||||
SG_CHECK_EQUAL(b2.get_x(), 7);
|
SG_CHECK_EQUAL(b2.get_x(), 7);
|
||||||
SG_CHECK_EQUAL(b2.get_y(), 6);
|
SG_CHECK_EQUAL(b2.get_y(), 6);
|
||||||
SG_CHECK_EQUAL(b2.gen_index(), sgBucketOffset(-179.8, 16.8, -2, 0));
|
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[])
|
int main(int argc, char* argv[])
|
||||||
@@ -277,8 +355,8 @@ int main(int argc, char* argv[])
|
|||||||
testOffset();
|
testOffset();
|
||||||
testOffsetWrap();
|
testOffsetWrap();
|
||||||
testPolarOffset();
|
testPolarOffset();
|
||||||
|
testSiblings();
|
||||||
|
|
||||||
cout << "all tests passed OK" << endl;
|
cout << "all tests passed OK" << endl;
|
||||||
return 0; // passed
|
return 0; // passed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,6 @@ set(HEADERS
|
|||||||
CanvasText.hxx
|
CanvasText.hxx
|
||||||
)
|
)
|
||||||
|
|
||||||
set(DETAIL_HEADERS
|
|
||||||
detail/add_segment_variadic.hxx
|
|
||||||
)
|
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
CanvasElement.cxx
|
CanvasElement.cxx
|
||||||
CanvasGroup.cxx
|
CanvasGroup.cxx
|
||||||
@@ -23,7 +19,6 @@ set(SOURCES
|
|||||||
)
|
)
|
||||||
|
|
||||||
simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}")
|
simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}")
|
||||||
simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEADERS}")
|
|
||||||
|
|
||||||
add_boost_test(canvas_element
|
add_boost_test(canvas_element
|
||||||
SOURCES canvas_element_test.cpp
|
SOURCES canvas_element_test.cpp
|
||||||
|
|||||||
@@ -740,52 +740,63 @@ namespace canvas
|
|||||||
return _path->getTransformedBounds(m);
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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_
|
#define CANVAS_PATH_HXX_
|
||||||
|
|
||||||
#include "CanvasElement.hxx"
|
#include "CanvasElement.hxx"
|
||||||
#include <boost/preprocessor/iteration/iterate.hpp>
|
|
||||||
#include <simgear/math/SGRect.hxx>
|
#include <simgear/math/SGRect.hxx>
|
||||||
|
#include <initializer_list>
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
@@ -44,10 +44,8 @@ namespace canvas
|
|||||||
|
|
||||||
virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const;
|
virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const;
|
||||||
|
|
||||||
#define BOOST_PP_ITERATION_LIMITS (0, 6)
|
/** Add a segment with the given command and coordinates */
|
||||||
#define BOOST_PP_FILENAME_1 \
|
Path& addSegment(uint8_t cmd, std::initializer_list<float> coords = {});
|
||||||
<simgear/canvas/elements/detail/add_segment_variadic.hxx>
|
|
||||||
#include BOOST_PP_ITERATE()
|
|
||||||
|
|
||||||
/** Move path cursor */
|
/** Move path cursor */
|
||||||
Path& moveTo(float x_abs, float y_abs);
|
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() )
|
if( hfw.empty() )
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
naContext c = naNewContext();
|
|
||||||
try
|
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 )
|
catch( std::exception const& ex )
|
||||||
{
|
{
|
||||||
@@ -202,7 +202,6 @@ namespace canvas
|
|||||||
"NasalWidget.heightForWidth: callback error: '" << ex.what() << "'"
|
"NasalWidget.heightForWidth: callback error: '" << ex.what() << "'"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
naFreeContext(c);
|
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -262,8 +261,8 @@ namespace canvas
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
nasal::Context c;
|
nasal::Context ctx;
|
||||||
_set_geometry(nasal::to_nasal(c, this), rect);
|
_set_geometry(ctx.to_me(this), rect);
|
||||||
_flags &= ~LAYOUT_DIRTY;
|
_flags &= ~LAYOUT_DIRTY;
|
||||||
}
|
}
|
||||||
catch( std::exception const& ex )
|
catch( std::exception const& ex )
|
||||||
|
|||||||
@@ -21,4 +21,9 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_test(metar ${EXECUTABLE_OUTPUT_PATH}/test_metar)
|
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)
|
endif(ENABLE_TESTS)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
* @brief Precipitation effects to draw rain and snow.
|
* @brief Precipitation effects to draw rain and snow.
|
||||||
*
|
*
|
||||||
* @par Licences
|
* @par License
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License as
|
* modify it under the terms of the GNU General Public License as
|
||||||
* published by the Free Software Foundation; either version 2 of the
|
* published by the Free Software Foundation; either version 2 of the
|
||||||
@@ -25,7 +25,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precipitation.hxx"
|
#include "precipitation.hxx"
|
||||||
//#include "visual_enviro.hxx"
|
|
||||||
|
|
||||||
#include <simgear/constants.h>
|
#include <simgear/constants.h>
|
||||||
#include <osg/ClipNode>
|
#include <osg/ClipNode>
|
||||||
@@ -65,7 +64,7 @@ bool SGPrecipitation::getEnabled() const
|
|||||||
*/
|
*/
|
||||||
osg::Group* SGPrecipitation::build(void)
|
osg::Group* SGPrecipitation::build(void)
|
||||||
{
|
{
|
||||||
osg::Group* group = new osg::Group;
|
osg::ref_ptr<osg::Group> group = new osg::Group;
|
||||||
|
|
||||||
_precipitationEffect->snow(0);
|
_precipitationEffect->snow(0);
|
||||||
_precipitationEffect->rain(0);
|
_precipitationEffect->rain(0);
|
||||||
@@ -73,8 +72,9 @@ osg::Group* SGPrecipitation::build(void)
|
|||||||
if (_clip_distance!=0.0)
|
if (_clip_distance!=0.0)
|
||||||
{
|
{
|
||||||
osg::ref_ptr<osg::ClipNode> clipNode = new osg::ClipNode;
|
osg::ref_ptr<osg::ClipNode> clipNode = new osg::ClipNode;
|
||||||
clipNode->addClipPlane( new osg::ClipPlane( 0 ) );
|
osg::ref_ptr<osg::ClipPlane> clipPlane = new osg::ClipPlane(0);
|
||||||
clipNode->getClipPlane(0)->setClipPlane( 0.0, 0.0, -1.0, -_clip_distance );
|
clipNode->addClipPlane(clipPlane.get());
|
||||||
|
clipNode->getClipPlane(0)->setClipPlane(0.0, 0.0, -1.0, -_clip_distance);
|
||||||
clipNode->setReferenceFrame(osg::ClipNode::ABSOLUTE_RF);
|
clipNode->setReferenceFrame(osg::ClipNode::ABSOLUTE_RF);
|
||||||
clipNode->addChild(_precipitationEffect.get());
|
clipNode->addChild(_precipitationEffect.get());
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ osg::Group* SGPrecipitation::build(void)
|
|||||||
|
|
||||||
group->setNodeMask( ~(simgear::CASTSHADOW_BIT | simgear::MODELLIGHT_BIT) );
|
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
|
* @brief Define the illumination multiplier
|
||||||
*
|
*
|
||||||
* This function permits you to define and change the rain droplet size
|
* This function permits you to define and change the brightness
|
||||||
* which is used if external droplet size control is enabled
|
* of the precipitation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void SGPrecipitation::setIllumination(float illumination)
|
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
|
* This function permits you to define and change the clip plane distance.
|
||||||
* which is used if external droplet size control is enabled
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void SGPrecipitation::setClipDistance(float 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
|
* Be careful, if snow and rain intensity are greater than '0', snow effect
|
||||||
* will be first.
|
* 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)
|
bool SGPrecipitation::update(void)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
class SGPrecipitation : public osg::Referenced
|
class SGPrecipitation : public osg::Referenced
|
||||||
{
|
{
|
||||||
private:
|
protected:
|
||||||
bool _freeze;
|
bool _freeze;
|
||||||
bool _enabled;
|
bool _enabled;
|
||||||
bool _droplet_external;
|
bool _droplet_external;
|
||||||
@@ -66,7 +66,7 @@ public:
|
|||||||
void setIllumination(float);
|
void setIllumination(float);
|
||||||
void setClipDistance(float);
|
void setClipDistance(float);
|
||||||
|
|
||||||
void setEnabled( bool );
|
void setEnabled(bool);
|
||||||
bool getEnabled() const;
|
bool getEnabled() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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 <simgear_config.h>
|
||||||
#include "sg_netChannel.hxx"
|
#include "sg_netChannel.hxx"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cerrno>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
|
||||||
@@ -259,17 +261,9 @@ NetChannelPoller::removeChannel(NetChannel* channel)
|
|||||||
assert(channel->poller == this);
|
assert(channel->poller == this);
|
||||||
channel->poller = NULL;
|
channel->poller = NULL;
|
||||||
|
|
||||||
// portability: MSVC throws assertion failure when empty
|
auto it = std::find(channels.begin(), channels.end(), channel);
|
||||||
if (channels.empty()) {
|
if (it != channels.end()) {
|
||||||
return;
|
channels.erase(it);
|
||||||
}
|
|
||||||
|
|
||||||
ChannelList::iterator it = channels.begin();
|
|
||||||
for (; it != channels.end(); ++it) {
|
|
||||||
if (*it == channel) {
|
|
||||||
channels.erase(it);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -183,15 +183,6 @@ public:
|
|||||||
int requestContentLength;
|
int requestContentLength;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EraseIfClosed
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
bool operator()(simgear::NetChannel* chan) const
|
|
||||||
{
|
|
||||||
return chan->isClosed();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class TestServer : public NetChannel
|
class TestServer : public NetChannel
|
||||||
{
|
{
|
||||||
@@ -202,7 +193,6 @@ public:
|
|||||||
{
|
{
|
||||||
Socket::initSockets();
|
Socket::initSockets();
|
||||||
|
|
||||||
|
|
||||||
open();
|
open();
|
||||||
bind(NULL, 2000); // localhost, any port
|
bind(NULL, 2000); // localhost, any port
|
||||||
listen(16);
|
listen(16);
|
||||||
@@ -212,6 +202,7 @@ public:
|
|||||||
|
|
||||||
virtual ~TestServer()
|
virtual ~TestServer()
|
||||||
{
|
{
|
||||||
|
_poller.removeChannel(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool writable (void) { return false ; }
|
virtual bool writable (void) { return false ; }
|
||||||
@@ -231,15 +222,16 @@ public:
|
|||||||
{
|
{
|
||||||
_poller.poll();
|
_poller.poll();
|
||||||
|
|
||||||
typename std::vector<T*>::iterator it;
|
auto it = std::remove_if(_channels.begin(), _channels.end(), [&](T* channel) {
|
||||||
it = std::remove_if(_channels.begin(), _channels.end(), EraseIfClosed());
|
if (channel->isClosed()) {
|
||||||
|
_poller.removeChannel(channel);
|
||||||
for (typename std::vector<T*>::iterator it2 = it; it2 != _channels.end(); ++it2) {
|
delete channel;
|
||||||
delete *it2;
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
_channels.erase(it, _channels.end());
|
_channels.erase(it, _channels.end());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int connectCount()
|
int connectCount()
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
include (SimGearComponent)
|
include (SimGearComponent)
|
||||||
|
|
||||||
set(HEADERS
|
set(HEADERS
|
||||||
|
cppbind_fwd.hxx
|
||||||
Ghost.hxx
|
Ghost.hxx
|
||||||
NasalCallContext.hxx
|
NasalCallContext.hxx
|
||||||
NasalContext.hxx
|
NasalContext.hxx
|
||||||
NasalHash.hxx
|
NasalHash.hxx
|
||||||
|
NasalMe.hxx
|
||||||
|
NasalMethodHolder.hxx
|
||||||
NasalObject.hxx
|
NasalObject.hxx
|
||||||
NasalObjectHolder.hxx
|
NasalObjectHolder.hxx
|
||||||
NasalString.hxx
|
NasalString.hxx
|
||||||
@@ -13,9 +16,7 @@ set(HEADERS
|
|||||||
)
|
)
|
||||||
|
|
||||||
set(DETAIL_HEADERS
|
set(DETAIL_HEADERS
|
||||||
detail/from_nasal_function_templates.hxx
|
|
||||||
detail/from_nasal_helper.hxx
|
detail/from_nasal_helper.hxx
|
||||||
detail/functor_templates.hxx
|
|
||||||
detail/nasal_traits.hxx
|
detail/nasal_traits.hxx
|
||||||
detail/to_nasal_helper.hxx
|
detail/to_nasal_helper.hxx
|
||||||
)
|
)
|
||||||
|
|||||||
+210
-198
@@ -24,17 +24,16 @@
|
|||||||
#include "NasalObjectHolder.hxx"
|
#include "NasalObjectHolder.hxx"
|
||||||
|
|
||||||
#include <simgear/debug/logstream.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/SGWeakReferenced.hxx>
|
||||||
#include <simgear/structure/SGWeakPtr.hxx>
|
#include <simgear/structure/SGWeakPtr.hxx>
|
||||||
|
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
#include <boost/call_traits.hpp>
|
#include <boost/call_traits.hpp>
|
||||||
#include <boost/function.hpp>
|
#include <boost/function.hpp>
|
||||||
#include <boost/lambda/lambda.hpp>
|
|
||||||
#include <boost/mpl/has_xxx.hpp>
|
#include <boost/mpl/has_xxx.hpp>
|
||||||
#include <boost/preprocessor/iteration/iterate.hpp>
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/utility/enable_if.hpp>
|
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
@@ -62,10 +61,7 @@ namespace osg
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline typename boost::enable_if<
|
inline std::enable_if_t<std::is_pointer<T>::value, T>
|
||||||
boost::is_pointer<T>,
|
|
||||||
T
|
|
||||||
>::type
|
|
||||||
get_pointer(T ptr)
|
get_pointer(T ptr)
|
||||||
{
|
{
|
||||||
return ptr;
|
return ptr;
|
||||||
@@ -101,8 +97,8 @@ namespace nasal
|
|||||||
class GhostMetadata
|
class GhostMetadata
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef void(*Deleter)(void*);
|
using Deleter = void(*)(void*);
|
||||||
typedef std::vector<std::pair<Deleter, void*> > DestroyList;
|
using DestroyList = std::vector<std::pair<Deleter, void*>>;
|
||||||
|
|
||||||
static DestroyList _destroy_list;
|
static DestroyList _destroy_list;
|
||||||
|
|
||||||
@@ -154,19 +150,6 @@ namespace nasal
|
|||||||
};
|
};
|
||||||
|
|
||||||
BOOST_MPL_HAS_XXX_TRAIT_DEF(element_type)
|
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.
|
/** @brief Destroy all ghost queued for deletion.
|
||||||
@@ -178,8 +161,8 @@ namespace nasal
|
|||||||
*/
|
*/
|
||||||
void ghostProcessDestroyList();
|
void ghostProcessDestroyList();
|
||||||
|
|
||||||
typedef SGSharedPtr<internal::MethodHolder> MethodHolderPtr;
|
using MethodHolderPtr = SGSharedPtr<internal::MethodHolder>;
|
||||||
typedef SGWeakPtr<internal::MethodHolder> MethodHolderWeakPtr;
|
using MethodHolderWeakPtr = SGWeakPtr<internal::MethodHolder>;
|
||||||
|
|
||||||
// Dummy template to create shorter and easy to understand compile errors if
|
// Dummy template to create shorter and easy to understand compile errors if
|
||||||
// trying to wrap the wrong type as a Ghost.
|
// trying to wrap the wrong type as a Ghost.
|
||||||
@@ -187,9 +170,10 @@ namespace nasal
|
|||||||
class Ghost
|
class Ghost
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BOOST_STATIC_ASSERT(("Ghost can only wrap shared pointer!"
|
static_assert(
|
||||||
&& is_strong_ref<T>::value
|
is_strong_ref<T>::value,
|
||||||
));
|
"Ghost can only wrap shared pointer!"
|
||||||
|
);
|
||||||
|
|
||||||
static Ghost& init(const std::string& name);
|
static Ghost& init(const std::string& name);
|
||||||
static bool isInit();
|
static bool isInit();
|
||||||
@@ -209,7 +193,7 @@ namespace nasal
|
|||||||
* int myMember();
|
* int myMember();
|
||||||
* void doSomethingElse(const nasal::CallContext& ctx);
|
* void doSomethingElse(const nasal::CallContext& ctx);
|
||||||
* }
|
* }
|
||||||
* typedef boost::shared_ptr<MyClass> MyClassPtr;
|
* using MyClassPtr = boost::shared_ptr<MyClass>;
|
||||||
*
|
*
|
||||||
* std::string myOtherFreeMember(int num);
|
* std::string myOtherFreeMember(int num);
|
||||||
*
|
*
|
||||||
@@ -235,29 +219,25 @@ namespace nasal
|
|||||||
* @endcode
|
* @endcode
|
||||||
*/
|
*/
|
||||||
template<class T>
|
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
|
public internal::GhostMetadata
|
||||||
{
|
{
|
||||||
// Shared pointer required for Ghost (no weak pointer!)
|
|
||||||
BOOST_STATIC_ASSERT((is_strong_ref<T>::value));
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef typename T::element_type raw_type;
|
using raw_type = typename T::element_type;
|
||||||
typedef typename shared_ptr_traits<T>::strong_ref strong_ref;
|
using strong_ref = typename shared_ptr_traits<T>::strong_ref;
|
||||||
typedef typename shared_ptr_traits<T>::weak_ref weak_ref;
|
using weak_ref = typename shared_ptr_traits<T>::weak_ref;
|
||||||
typedef naRef (raw_type::*member_func_t)(const CallContext&);
|
using member_func_t = naRef (raw_type::*)(const CallContext&);
|
||||||
typedef naRef (*free_func_t)(raw_type&, const CallContext&);
|
using free_func_t = naRef (*)(raw_type&, const CallContext&);
|
||||||
typedef boost::function<naRef(raw_type&, naContext)> getter_t;
|
using getter_t = boost::function<naRef(raw_type&, naContext)>;
|
||||||
typedef boost::function<void( raw_type&, naContext, naRef)> setter_t;
|
using setter_t = boost::function<void( raw_type&, naContext, naRef)>;
|
||||||
typedef boost::function<naRef(raw_type&, const CallContext&)> method_t;
|
using method_t = boost::function<naRef(raw_type&, const CallContext&)>;
|
||||||
typedef boost::function<bool( raw_type&,
|
using fallback_getter_t =
|
||||||
naContext,
|
boost::function<bool(raw_type&, naContext, const std::string&, naRef&)>;
|
||||||
const std::string&,
|
using fallback_setter_t =
|
||||||
naRef& )> fallback_getter_t;
|
boost::function<bool(raw_type&, naContext, const std::string&, naRef)>;
|
||||||
typedef boost::function<bool( raw_type&,
|
|
||||||
naContext,
|
template<class Ret, class... Args>
|
||||||
const std::string&,
|
using method_variadic_t = boost::function<Ret (raw_type&, Args...)>;
|
||||||
naRef )> fallback_setter_t;
|
|
||||||
|
|
||||||
class MethodHolder:
|
class MethodHolder:
|
||||||
public internal::MethodHolder
|
public internal::MethodHolder
|
||||||
@@ -269,8 +249,8 @@ namespace nasal
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
typedef SGSharedPtr<MethodHolder> SharedPtr;
|
using SharedPtr = SGSharedPtr<MethodHolder>;
|
||||||
typedef SGWeakPtr<MethodHolder> WeakPtr;
|
using WeakPtr = SGWeakPtr<MethodHolder>;
|
||||||
|
|
||||||
method_t _method;
|
method_t _method;
|
||||||
|
|
||||||
@@ -369,7 +349,7 @@ namespace nasal
|
|||||||
MethodHolderPtr func;
|
MethodHolderPtr func;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<std::string, member_t> MemberMap;
|
using MemberMap = std::map<std::string, member_t>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a new ghost type.
|
* Register a new ghost type.
|
||||||
@@ -406,19 +386,18 @@ namespace nasal
|
|||||||
* @endcode
|
* @endcode
|
||||||
*/
|
*/
|
||||||
template<class BaseGhost>
|
template<class BaseGhost>
|
||||||
typename boost::enable_if
|
std::enable_if_t<
|
||||||
<
|
std::is_base_of<GhostMetadata, BaseGhost>::value,
|
||||||
boost::is_base_of<GhostMetadata, BaseGhost>,
|
Ghost&
|
||||||
Ghost
|
>
|
||||||
>::type&
|
|
||||||
bases()
|
bases()
|
||||||
{
|
{
|
||||||
BOOST_STATIC_ASSERT
|
static_assert(
|
||||||
((
|
std::is_base_of<typename BaseGhost::raw_type, raw_type>::value,
|
||||||
boost::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();
|
BaseGhost* base = BaseGhost::getSingletonPtr();
|
||||||
base->addDerived(
|
base->addDerived(
|
||||||
@@ -429,17 +408,14 @@ namespace nasal
|
|||||||
|
|
||||||
// Replace any getter that is not available in the current class.
|
// Replace any getter that is not available in the current class.
|
||||||
// TODO check if this is the correct behavior of function overriding
|
// TODO check if this is the correct behavior of function overriding
|
||||||
for( typename BaseGhost::MemberMap::const_iterator member =
|
for(auto const& base_member: base->_members)
|
||||||
base->_members.begin();
|
|
||||||
member != base->_members.end();
|
|
||||||
++member )
|
|
||||||
{
|
{
|
||||||
if( _members.find(member->first) == _members.end() )
|
if( _members.find(base_member.first) == _members.end() )
|
||||||
_members[member->first] = member_t
|
_members[base_member.first] = member_t
|
||||||
(
|
(
|
||||||
member->second.getter,
|
base_member.second.getter,
|
||||||
member->second.setter,
|
base_member.second.setter,
|
||||||
member->second.func
|
base_member.second.func
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,17 +440,16 @@ namespace nasal
|
|||||||
* @endcode
|
* @endcode
|
||||||
*/
|
*/
|
||||||
template<class Base>
|
template<class Base>
|
||||||
typename boost::disable_if
|
std::enable_if_t<
|
||||||
<
|
!std::is_base_of<GhostMetadata, Base>::value,
|
||||||
boost::is_base_of<GhostMetadata, Base>,
|
Ghost&
|
||||||
Ghost
|
>
|
||||||
>::type&
|
|
||||||
bases()
|
bases()
|
||||||
{
|
{
|
||||||
BOOST_STATIC_ASSERT
|
static_assert(
|
||||||
((
|
std::is_base_of<typename Ghost<Base>::raw_type, raw_type>::value,
|
||||||
boost::is_base_of<typename Ghost<Base>::raw_type, raw_type>::value
|
"Not a base class!"
|
||||||
));
|
);
|
||||||
|
|
||||||
return bases< Ghost<Base> >();
|
return bases< Ghost<Base> >();
|
||||||
}
|
}
|
||||||
@@ -770,7 +745,7 @@ namespace nasal
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Register anything that accepts an object instance and a
|
* 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.
|
* Nasal.
|
||||||
*
|
*
|
||||||
* @code{cpp}
|
* @code{cpp}
|
||||||
@@ -791,14 +766,73 @@ namespace nasal
|
|||||||
return method(name, boost::bind(method_invoker<Ret>, func, _1, _2));
|
return method(name, boost::bind(method_invoker<Ret>, func, _1, _2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build dependency for CMake, gcc, etc.
|
/**
|
||||||
#define SG_DONT_DO_ANYTHING
|
* Bind any callable entity accepting an instance of raw_type and an
|
||||||
# include <simgear/nasal/cppbind/detail/functor_templates.hxx>
|
* arbitrary number of arguments as method.
|
||||||
#undef SG_DONT_DO_ANYTHING
|
*
|
||||||
|
* 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)
|
template<class Ret, class... Args>
|
||||||
#define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/functor_templates.hxx>
|
Ghost& method( const std::string& name,
|
||||||
#include BOOST_PP_ITERATE()
|
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
|
* Create a shared pointer on the heap to handle the reference counting
|
||||||
@@ -806,11 +840,11 @@ namespace nasal
|
|||||||
*/
|
*/
|
||||||
template<class RefType>
|
template<class RefType>
|
||||||
static
|
static
|
||||||
typename boost::enable_if_c<
|
std::enable_if_t<
|
||||||
boost::is_same<RefType, strong_ref>::value
|
std::is_same<RefType, strong_ref>::value
|
||||||
|| boost::is_same<RefType, weak_ref>::value,
|
|| std::is_same<RefType, weak_ref>::value,
|
||||||
naRef
|
naRef
|
||||||
>::type
|
>
|
||||||
makeGhost(naContext c, RefType const& ref_ptr)
|
makeGhost(naContext c, RefType const& ref_ptr)
|
||||||
{
|
{
|
||||||
strong_ref ref(ref_ptr);
|
strong_ref ref(ref_ptr);
|
||||||
@@ -848,10 +882,9 @@ namespace nasal
|
|||||||
}
|
}
|
||||||
|
|
||||||
// otherwise try the derived classes
|
// otherwise try the derived classes
|
||||||
for( typename DerivedList::reverse_iterator
|
for( auto derived = getSingletonPtr()->_derived_types.rbegin();
|
||||||
derived = getSingletonPtr()->_derived_types.rbegin();
|
derived != getSingletonPtr()->_derived_types.rend();
|
||||||
derived != getSingletonPtr()->_derived_types.rend();
|
++derived )
|
||||||
++derived )
|
|
||||||
{
|
{
|
||||||
strong_ref ref = (derived->from_nasal)(c, me);
|
strong_ref ref = (derived->from_nasal)(c, me);
|
||||||
|
|
||||||
@@ -865,13 +898,10 @@ namespace nasal
|
|||||||
if( !naIsVector(na_parents) )
|
if( !naIsVector(na_parents) )
|
||||||
return strong_ref();
|
return strong_ref();
|
||||||
|
|
||||||
typedef std::vector<naRef> naRefs;
|
auto parents = from_nasal<std::vector<naRef>>(c, na_parents);
|
||||||
naRefs parents = from_nasal<naRefs>(c, na_parents);
|
for(auto parent: parents)
|
||||||
for( naRefs::const_iterator parent = parents.begin();
|
|
||||||
parent != parents.end();
|
|
||||||
++parent )
|
|
||||||
{
|
{
|
||||||
strong_ref ref = fromNasal(c, *parent);
|
strong_ref ref = fromNasal(c, parent);
|
||||||
if( get_pointer(ref) )
|
if( get_pointer(ref) )
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
@@ -923,8 +953,9 @@ namespace nasal
|
|||||||
static naGhostType _ghost_type_strong, //!< Stored as shared pointer
|
static naGhostType _ghost_type_strong, //!< Stored as shared pointer
|
||||||
_ghost_type_weak; //!< Stored as weak shared pointer
|
_ghost_type_weak; //!< Stored as weak shared pointer
|
||||||
|
|
||||||
typedef naRef (*to_nasal_t)(naContext, const strong_ref&, bool);
|
using to_nasal_t = naRef (*)(naContext, const strong_ref&, bool);
|
||||||
typedef strong_ref (*from_nasal_t)(naContext, naRef);
|
using from_nasal_t = strong_ref (*)(naContext, naRef);
|
||||||
|
|
||||||
struct DerivedInfo
|
struct DerivedInfo
|
||||||
{
|
{
|
||||||
to_nasal_t to_nasal;
|
to_nasal_t to_nasal;
|
||||||
@@ -937,7 +968,7 @@ namespace nasal
|
|||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<DerivedInfo> DerivedList;
|
using DerivedList = std::vector<DerivedInfo>;
|
||||||
DerivedList _derived_types;
|
DerivedList _derived_types;
|
||||||
|
|
||||||
static bool isInstance(naGhostType* ghost_type, bool& is_weak)
|
static bool isInstance(naGhostType* ghost_type, bool& is_weak)
|
||||||
@@ -951,13 +982,10 @@ namespace nasal
|
|||||||
|
|
||||||
template<class RefPtr, bool is_weak>
|
template<class RefPtr, bool is_weak>
|
||||||
static
|
static
|
||||||
typename boost::enable_if_c<
|
std::enable_if_t<!is_weak, RefPtr>
|
||||||
!is_weak,
|
|
||||||
RefPtr
|
|
||||||
>::type
|
|
||||||
getPtr(void* ptr)
|
getPtr(void* ptr)
|
||||||
{
|
{
|
||||||
typedef shared_ptr_storage<strong_ref> storage_type;
|
using storage_type = shared_ptr_storage<strong_ref>;
|
||||||
if( ptr )
|
if( ptr )
|
||||||
return storage_type::template get<RefPtr>(
|
return storage_type::template get<RefPtr>(
|
||||||
static_cast<typename storage_type::storage_type*>(ptr)
|
static_cast<typename storage_type::storage_type*>(ptr)
|
||||||
@@ -968,13 +996,13 @@ namespace nasal
|
|||||||
|
|
||||||
template<class RefPtr, bool is_weak>
|
template<class RefPtr, bool is_weak>
|
||||||
static
|
static
|
||||||
typename boost::enable_if_c<
|
std::enable_if_t<
|
||||||
is_weak && supports_weak_ref<T>::value,
|
is_weak && supports_weak_ref<T>::value,
|
||||||
RefPtr
|
RefPtr
|
||||||
>::type
|
>
|
||||||
getPtr(void* ptr)
|
getPtr(void* ptr)
|
||||||
{
|
{
|
||||||
typedef shared_ptr_storage<weak_ref> storage_type;
|
using storage_type = shared_ptr_storage<weak_ref>;
|
||||||
if( ptr )
|
if( ptr )
|
||||||
return storage_type::template get<RefPtr>(
|
return storage_type::template get<RefPtr>(
|
||||||
static_cast<typename storage_type::storage_type*>(ptr)
|
static_cast<typename storage_type::storage_type*>(ptr)
|
||||||
@@ -985,10 +1013,10 @@ namespace nasal
|
|||||||
|
|
||||||
template<class RefPtr, bool is_weak>
|
template<class RefPtr, bool is_weak>
|
||||||
static
|
static
|
||||||
typename boost::enable_if_c<
|
std::enable_if_t<
|
||||||
is_weak && !supports_weak_ref<T>::value,
|
is_weak && !supports_weak_ref<T>::value,
|
||||||
RefPtr
|
RefPtr
|
||||||
>::type
|
>
|
||||||
getPtr(void* ptr)
|
getPtr(void* ptr)
|
||||||
{
|
{
|
||||||
return RefPtr();
|
return RefPtr();
|
||||||
@@ -1004,10 +1032,10 @@ namespace nasal
|
|||||||
|
|
||||||
template<class BaseGhost>
|
template<class BaseGhost>
|
||||||
static
|
static
|
||||||
typename boost::enable_if
|
std::enable_if_t<
|
||||||
< boost::is_polymorphic<typename BaseGhost::raw_type>,
|
std::is_polymorphic<typename BaseGhost::raw_type>::value,
|
||||||
naRef
|
naRef
|
||||||
>::type
|
>
|
||||||
toNasal( naContext c,
|
toNasal( naContext c,
|
||||||
const typename BaseGhost::strong_ref& base_ref,
|
const typename BaseGhost::strong_ref& base_ref,
|
||||||
bool strong )
|
bool strong )
|
||||||
@@ -1016,10 +1044,10 @@ namespace nasal
|
|||||||
|
|
||||||
// Check first if passed pointer can by converted to instance of class
|
// Check first if passed pointer can by converted to instance of class
|
||||||
// this ghost wraps.
|
// this ghost wraps.
|
||||||
if( !boost::is_same
|
if( !std::is_same<
|
||||||
< typename BaseGhost::raw_type,
|
typename BaseGhost::raw_type,
|
||||||
typename Ghost::raw_type
|
typename Ghost::raw_type
|
||||||
>::value
|
>::value
|
||||||
&& dynamic_cast<const typename Ghost::raw_type*>(ptr) != ptr )
|
&& dynamic_cast<const typename Ghost::raw_type*>(ptr) != ptr )
|
||||||
return naNil();
|
return naNil();
|
||||||
|
|
||||||
@@ -1038,10 +1066,9 @@ namespace nasal
|
|||||||
static_pointer_cast<typename Ghost::raw_type>(base_ref);
|
static_pointer_cast<typename Ghost::raw_type>(base_ref);
|
||||||
|
|
||||||
// Now check if we can further downcast to one of our derived classes.
|
// Now check if we can further downcast to one of our derived classes.
|
||||||
for( typename DerivedList::reverse_iterator
|
for( auto derived = getSingletonPtr()->_derived_types.rbegin();
|
||||||
derived = getSingletonPtr()->_derived_types.rbegin();
|
derived != getSingletonPtr()->_derived_types.rend();
|
||||||
derived != getSingletonPtr()->_derived_types.rend();
|
++derived )
|
||||||
++derived )
|
|
||||||
{
|
{
|
||||||
naRef ghost = (derived->to_nasal)(c, ref, strong);
|
naRef ghost = (derived->to_nasal)(c, ref, strong);
|
||||||
|
|
||||||
@@ -1058,13 +1085,13 @@ namespace nasal
|
|||||||
|
|
||||||
template<class BaseGhost>
|
template<class BaseGhost>
|
||||||
static
|
static
|
||||||
typename boost::disable_if
|
std::enable_if_t<
|
||||||
< boost::is_polymorphic<typename BaseGhost::raw_type>,
|
!std::is_polymorphic<typename BaseGhost::raw_type>::value,
|
||||||
naRef
|
naRef
|
||||||
>::type
|
>
|
||||||
toNasal( naContext c,
|
toNasal( naContext c,
|
||||||
const typename BaseGhost::strong_ref& ref,
|
const typename BaseGhost::strong_ref& ref,
|
||||||
bool strong )
|
bool strong )
|
||||||
{
|
{
|
||||||
// For non polymorphic classes there is no possibility to get the actual
|
// For non polymorphic classes there is no possibility to get the actual
|
||||||
// dynamic type, therefore we can only use its static type.
|
// dynamic type, therefore we can only use its static type.
|
||||||
@@ -1087,7 +1114,7 @@ namespace nasal
|
|||||||
template<class Ret>
|
template<class Ret>
|
||||||
getter_t to_getter(Ret (raw_type::*getter)() const)
|
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;
|
naRef(*to_nasal_)(naContext, param_type) = &to_nasal;
|
||||||
|
|
||||||
// Getter signature: naRef(raw_type&, naContext)
|
// Getter signature: naRef(raw_type&, naContext)
|
||||||
@@ -1140,7 +1167,7 @@ namespace nasal
|
|||||||
*/
|
*/
|
||||||
template<class Ret>
|
template<class Ret>
|
||||||
static
|
static
|
||||||
typename boost::disable_if<boost::is_void<Ret>, naRef>::type
|
std::enable_if_t<!std::is_void<Ret>::value, naRef>
|
||||||
method_invoker
|
method_invoker
|
||||||
(
|
(
|
||||||
const boost::function<Ret (raw_type&, const CallContext&)>& func,
|
const boost::function<Ret (raw_type&, const CallContext&)>& func,
|
||||||
@@ -1148,7 +1175,7 @@ namespace nasal
|
|||||||
const CallContext& ctx
|
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>
|
template<class Ret>
|
||||||
static
|
static
|
||||||
typename boost::enable_if<boost::is_void<Ret>, naRef>::type
|
std::enable_if_t<std::is_void<Ret>::value, naRef>
|
||||||
method_invoker
|
method_invoker
|
||||||
(
|
(
|
||||||
const boost::function<Ret (raw_type&, const CallContext&)>& func,
|
const boost::function<Ret (raw_type&, const CallContext&)>& func,
|
||||||
@@ -1174,10 +1201,10 @@ namespace nasal
|
|||||||
*/
|
*/
|
||||||
template<class Arg>
|
template<class Arg>
|
||||||
static
|
static
|
||||||
typename boost::disable_if<
|
std::enable_if_t<
|
||||||
internal::reduced_is_same<Arg, CallContext>,
|
!std::is_same<std::remove_cvref_t<Arg>, CallContext>::value,
|
||||||
typename from_nasal_ptr<Arg>::return_type
|
typename from_nasal_ptr<Arg>::return_type
|
||||||
>::type
|
>
|
||||||
arg_from_nasal(const CallContext& ctx, size_t index)
|
arg_from_nasal(const CallContext& ctx, size_t index)
|
||||||
{
|
{
|
||||||
return ctx.requireArg<Arg>(index);
|
return ctx.requireArg<Arg>(index);
|
||||||
@@ -1188,19 +1215,21 @@ namespace nasal
|
|||||||
*/
|
*/
|
||||||
template<class Arg>
|
template<class Arg>
|
||||||
static
|
static
|
||||||
typename boost::enable_if<
|
std::enable_if_t<
|
||||||
internal::reduced_is_same<Arg, CallContext>,
|
std::is_same<std::remove_cvref_t<Arg>, CallContext>::value,
|
||||||
typename from_nasal_ptr<Arg>::return_type
|
typename from_nasal_ptr<Arg>::return_type
|
||||||
>::type
|
>
|
||||||
arg_from_nasal(const CallContext& ctx, size_t)
|
arg_from_nasal(const CallContext& ctx, size_t)
|
||||||
{
|
{
|
||||||
// Either const CallContext& or CallContext, non-const reference
|
// Either const CallContext& or CallContext, non-const reference
|
||||||
// does not make sense.
|
// 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;
|
return ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::unique_ptr<Ghost> GhostPtr;
|
using GhostPtr = std::unique_ptr<Ghost>;
|
||||||
MemberMap _members;
|
MemberMap _members;
|
||||||
fallback_getter_t _fallback_getter;
|
fallback_getter_t _fallback_getter;
|
||||||
fallback_setter_t _fallback_setter;
|
fallback_setter_t _fallback_setter;
|
||||||
@@ -1240,13 +1269,10 @@ namespace nasal
|
|||||||
|
|
||||||
template<bool is_weak>
|
template<bool is_weak>
|
||||||
static
|
static
|
||||||
typename boost::enable_if_c<
|
std::enable_if_t<!is_weak, naRef>
|
||||||
!is_weak,
|
|
||||||
naRef
|
|
||||||
>::type
|
|
||||||
create(naContext c, const strong_ref& ref_ptr)
|
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,
|
return naNewGhost2( c,
|
||||||
&Ghost::_ghost_type_strong,
|
&Ghost::_ghost_type_strong,
|
||||||
storage_type::ref(ref_ptr) );
|
storage_type::ref(ref_ptr) );
|
||||||
@@ -1254,13 +1280,13 @@ namespace nasal
|
|||||||
|
|
||||||
template<bool is_weak>
|
template<bool is_weak>
|
||||||
static
|
static
|
||||||
typename boost::enable_if_c<
|
std::enable_if_t<
|
||||||
is_weak && supports_weak_ref<T>::value,
|
is_weak && supports_weak_ref<T>::value,
|
||||||
naRef
|
naRef
|
||||||
>::type
|
>
|
||||||
create(naContext c, const strong_ref& ref_ptr)
|
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,
|
return naNewGhost2( c,
|
||||||
&Ghost::_ghost_type_weak,
|
&Ghost::_ghost_type_weak,
|
||||||
storage_type::ref(ref_ptr) );
|
storage_type::ref(ref_ptr) );
|
||||||
@@ -1268,10 +1294,10 @@ namespace nasal
|
|||||||
|
|
||||||
template<bool is_weak>
|
template<bool is_weak>
|
||||||
static
|
static
|
||||||
typename boost::enable_if_c<
|
std::enable_if_t<
|
||||||
is_weak && !supports_weak_ref<T>::value,
|
is_weak && !supports_weak_ref<T>::value,
|
||||||
naRef
|
naRef
|
||||||
>::type
|
>
|
||||||
create(naContext, const strong_ref&)
|
create(naContext, const strong_ref&)
|
||||||
{
|
{
|
||||||
return naNil();
|
return naNil();
|
||||||
@@ -1280,7 +1306,7 @@ namespace nasal
|
|||||||
template<class Type>
|
template<class Type>
|
||||||
static void destroy(void *ptr)
|
static void destroy(void *ptr)
|
||||||
{
|
{
|
||||||
typedef shared_ptr_storage<Type> storage_type;
|
using storage_type = shared_ptr_storage<Type>;
|
||||||
storage_type::unref(
|
storage_type::unref(
|
||||||
static_cast<typename storage_type::storage_type*>(ptr)
|
static_cast<typename storage_type::storage_type*>(ptr)
|
||||||
);
|
);
|
||||||
@@ -1322,9 +1348,7 @@ namespace nasal
|
|||||||
// return "";
|
// return "";
|
||||||
// }
|
// }
|
||||||
|
|
||||||
typename MemberMap::iterator member =
|
auto member = getSingletonPtr()->_members.find(key_str);
|
||||||
getSingletonPtr()->_members.find(key_str);
|
|
||||||
|
|
||||||
if( member == getSingletonPtr()->_members.end() )
|
if( member == getSingletonPtr()->_members.end() )
|
||||||
{
|
{
|
||||||
fallback_getter_t fallback_get = getSingletonPtr()->_fallback_getter;
|
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 std::string key = nasal::from_nasal<std::string>(c, field);
|
||||||
const MemberMap& members = getSingletonPtr()->_members;
|
const MemberMap& members = getSingletonPtr()->_members;
|
||||||
|
|
||||||
typename MemberMap::const_iterator member = members.find(key);
|
auto member = members.find(key);
|
||||||
if( member == members.end() )
|
if( member == members.end() )
|
||||||
{
|
{
|
||||||
fallback_setter_t fallback_set = getSingletonPtr()->_fallback_setter;
|
fallback_setter_t fallback_set = getSingletonPtr()->_fallback_setter;
|
||||||
@@ -1415,13 +1439,11 @@ namespace nasal
|
|||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
naGhostType
|
naGhostType
|
||||||
Ghost<T, typename boost::enable_if<is_strong_ref<T> >::type>
|
Ghost<T, std::enable_if_t<is_strong_ref<T>::value>>::_ghost_type_strong;
|
||||||
::_ghost_type_strong;
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
naGhostType
|
naGhostType
|
||||||
Ghost<T, typename boost::enable_if<is_strong_ref<T> >::type>
|
Ghost<T, std::enable_if_t<is_strong_ref<T>::value>>::_ghost_type_weak;
|
||||||
::_ghost_type_weak;
|
|
||||||
|
|
||||||
} // namespace nasal
|
} // namespace nasal
|
||||||
|
|
||||||
@@ -1430,15 +1452,13 @@ namespace nasal
|
|||||||
* Convert every shared pointer to a ghost.
|
* Convert every shared pointer to a ghost.
|
||||||
*/
|
*/
|
||||||
template<class T>
|
template<class T>
|
||||||
typename boost::enable_if<
|
std::enable_if_t<
|
||||||
nasal::internal::has_element_type<
|
nasal::internal::has_element_type<std::remove_cvref_t<T>>::value,
|
||||||
typename nasal::internal::reduced_type<T>::type
|
|
||||||
>,
|
|
||||||
naRef
|
naRef
|
||||||
>::type
|
>
|
||||||
to_nasal_helper(naContext c, T ptr)
|
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);
|
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).
|
* Convert nasal ghosts/hashes to shared pointer (of a ghost).
|
||||||
*/
|
*/
|
||||||
template<class T>
|
template<class T>
|
||||||
typename boost::enable_if<
|
std::enable_if_t<
|
||||||
nasal::internal::has_element_type<
|
nasal::internal::has_element_type<std::remove_cvref_t<T>>::value,
|
||||||
typename nasal::internal::reduced_type<T>::type
|
|
||||||
>,
|
|
||||||
T
|
T
|
||||||
>::type
|
>
|
||||||
from_nasal_helper(naContext c, naRef ref, const T*)
|
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));
|
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.
|
* Convert any pointer to a SGReferenced based object to a ghost.
|
||||||
*/
|
*/
|
||||||
template<class T>
|
template<class T>
|
||||||
typename boost::enable_if_c<
|
std::enable_if_t<
|
||||||
boost::is_base_of<SGReferenced, T>::value
|
std::is_base_of<SGReferenced, T>::value
|
||||||
|| boost::is_base_of<SGWeakReferenced, T>::value,
|
|| std::is_base_of<SGWeakReferenced, T>::value,
|
||||||
naRef
|
naRef
|
||||||
>::type
|
>
|
||||||
to_nasal_helper(naContext c, T* ptr)
|
to_nasal_helper(naContext c, T* ptr)
|
||||||
{
|
{
|
||||||
return nasal::Ghost<SGSharedPtr<T> >::makeGhost(c, SGSharedPtr<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).
|
* Convert nasal ghosts/hashes to pointer (of a SGReferenced based ghost).
|
||||||
*/
|
*/
|
||||||
template<class T>
|
template<class T>
|
||||||
typename boost::enable_if_c<
|
std::enable_if_t<
|
||||||
boost::is_base_of<
|
std::is_base_of<SGReferenced, std::remove_pointer_t<T>>::value
|
||||||
SGReferenced,
|
|| std::is_base_of<SGWeakReferenced, std::remove_pointer_t<T>>::value,
|
||||||
typename boost::remove_pointer<T>::type
|
|
||||||
>::value
|
|
||||||
|| boost::is_base_of<
|
|
||||||
SGWeakReferenced,
|
|
||||||
typename boost::remove_pointer<T>::type
|
|
||||||
>::value,
|
|
||||||
T
|
T
|
||||||
>::type
|
>
|
||||||
from_nasal_helper(naContext c, naRef ref, const T*)
|
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));
|
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.
|
* Convert any pointer to a osg::Referenced based object to a ghost.
|
||||||
*/
|
*/
|
||||||
template<class T>
|
template<class T>
|
||||||
typename boost::enable_if<
|
std::enable_if_t<
|
||||||
boost::is_base_of<osg::Referenced, T>,
|
std::is_base_of<osg::Referenced, T>::value,
|
||||||
naRef
|
naRef
|
||||||
>::type
|
>
|
||||||
to_nasal_helper(naContext c, T* ptr)
|
to_nasal_helper(naContext c, T* ptr)
|
||||||
{
|
{
|
||||||
return nasal::Ghost<osg::ref_ptr<T> >::makeGhost(c, osg::ref_ptr<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).
|
* Convert nasal ghosts/hashes to pointer (of a osg::Referenced based ghost).
|
||||||
*/
|
*/
|
||||||
template<class T>
|
template<class T>
|
||||||
typename boost::enable_if<
|
std::enable_if_t<
|
||||||
boost::is_base_of<osg::Referenced, typename boost::remove_pointer<T>::type>,
|
std::is_base_of<osg::Referenced, std::remove_pointer_t<T>>::value,
|
||||||
T
|
T
|
||||||
>::type
|
>
|
||||||
from_nasal_helper(naContext c, naRef ref, const T*)
|
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));
|
return T(nasal::Ghost<TypeRef>::fromNasalChecked(c, ref));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,8 +20,7 @@
|
|||||||
#ifndef SG_NASAL_CALL_CONTEXT_HXX_
|
#ifndef SG_NASAL_CALL_CONTEXT_HXX_
|
||||||
#define SG_NASAL_CALL_CONTEXT_HXX_
|
#define SG_NASAL_CALL_CONTEXT_HXX_
|
||||||
|
|
||||||
#include "from_nasal.hxx"
|
#include "NasalContext.hxx"
|
||||||
#include "to_nasal.hxx"
|
|
||||||
|
|
||||||
namespace nasal
|
namespace nasal
|
||||||
{
|
{
|
||||||
@@ -29,11 +28,12 @@ namespace nasal
|
|||||||
/**
|
/**
|
||||||
* Context passed to a function/method being called from Nasal
|
* Context passed to a function/method being called from Nasal
|
||||||
*/
|
*/
|
||||||
class CallContext
|
class CallContext:
|
||||||
|
public ContextWrapper
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CallContext(naContext c, naRef me, size_t argc, naRef* args):
|
CallContext(naContext c, naRef me, size_t argc, naRef* args):
|
||||||
c(c),
|
ContextWrapper(c),
|
||||||
me(me),
|
me(me),
|
||||||
argc(argc),
|
argc(argc),
|
||||||
args(args)
|
args(args)
|
||||||
@@ -102,28 +102,14 @@ namespace nasal
|
|||||||
requireArg(size_t index) const
|
requireArg(size_t index) const
|
||||||
{
|
{
|
||||||
if( index >= argc )
|
if( index >= argc )
|
||||||
naRuntimeError(c, "Missing required arg #%d", index);
|
runtimeError("Missing required arg #%d", index);
|
||||||
|
|
||||||
return from_nasal<T>(args[index]);
|
return from_nasal<T>(args[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
naRef me;
|
||||||
naRef to_nasal(T arg) const
|
size_t argc;
|
||||||
{
|
naRef *args;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace nasal
|
} // namespace nasal
|
||||||
|
|||||||
@@ -17,13 +17,79 @@
|
|||||||
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
|
||||||
#include "NasalContext.hxx"
|
#include "NasalContext.hxx"
|
||||||
|
#include "NasalHash.hxx"
|
||||||
|
#include "NasalString.hxx"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace nasal
|
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():
|
Context::Context():
|
||||||
_ctx(naNewContext())
|
ContextWrapper(naNewContext())
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -32,18 +98,7 @@ namespace nasal
|
|||||||
Context::~Context()
|
Context::~Context()
|
||||||
{
|
{
|
||||||
naFreeContext(_ctx);
|
naFreeContext(_ctx);
|
||||||
}
|
_ctx = nullptr;
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
Context::operator naContext()
|
|
||||||
{
|
|
||||||
return _ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
Hash Context::newHash()
|
|
||||||
{
|
|
||||||
return Hash(_ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace nasal
|
} // namespace nasal
|
||||||
|
|||||||
@@ -19,28 +19,110 @@
|
|||||||
#ifndef SG_NASAL_CONTEXT_HXX_
|
#ifndef SG_NASAL_CONTEXT_HXX_
|
||||||
#define 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
|
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:
|
public:
|
||||||
Context();
|
Context();
|
||||||
~Context();
|
~Context();
|
||||||
|
|
||||||
operator naContext();
|
Context(const Context&) = delete;
|
||||||
|
Context& operator=(const Context&) = delete;
|
||||||
Hash newHash();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
naContext _ctx;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace nasal
|
} // namespace nasal
|
||||||
|
|
||||||
|
#include "from_nasal.hxx"
|
||||||
|
#include "to_nasal.hxx"
|
||||||
|
|
||||||
#endif /* SG_NASAL_CONTEXT_HXX_ */
|
#endif /* SG_NASAL_CONTEXT_HXX_ */
|
||||||
|
|||||||
@@ -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_ */
|
||||||
@@ -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;
|
bool valid() const;
|
||||||
|
|
||||||
template<class Ret, class ... Args>
|
template<class Ret, class... Args>
|
||||||
Ret callMethod(const std::string& name, Args ... args)
|
Ret callMethod(const std::string& name, Args ... args)
|
||||||
{
|
{
|
||||||
if( !_nasal_impl.valid() )
|
if( !_nasal_impl.valid() )
|
||||||
return Ret();
|
return Ret();
|
||||||
|
|
||||||
Context ctx;
|
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
|
ctx, _nasal_impl.get_naRef(), name
|
||||||
);
|
);
|
||||||
if( func )
|
if( func )
|
||||||
return func(nasal::to_nasal(ctx, this), args...);
|
return func(Me(ctx.to_nasal(this)), args...);
|
||||||
|
|
||||||
return Ret();
|
return Ret();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ namespace nasal
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
using Ref = SGSharedPtr<ObjectHolder<Base>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param obj Object to save
|
* @param obj Object to save
|
||||||
*/
|
*/
|
||||||
@@ -84,7 +86,7 @@ namespace nasal
|
|||||||
*
|
*
|
||||||
* @param obj Object to save
|
* @param obj Object to save
|
||||||
*/
|
*/
|
||||||
static SGSharedPtr<ObjectHolder<Base> > makeShared(naRef obj);
|
static Ref makeShared(naRef obj);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
naRef _ref;
|
naRef _ref;
|
||||||
@@ -155,10 +157,10 @@ namespace nasal
|
|||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
template<class Base>
|
template<class Base>
|
||||||
SGSharedPtr<ObjectHolder<Base> >
|
typename ObjectHolder<Base>::Ref
|
||||||
ObjectHolder<Base>::makeShared(naRef obj)
|
ObjectHolder<Base>::makeShared(naRef obj)
|
||||||
{
|
{
|
||||||
return SGSharedPtr<ObjectHolder<Base> >( new ObjectHolder<Base>(obj) );
|
return Ref( new ObjectHolder<Base>(obj) );
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace nasal
|
} // namespace nasal
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace nasal
|
|||||||
*
|
*
|
||||||
* @param str Existing Nasal String
|
* @param str Existing Nasal String
|
||||||
*/
|
*/
|
||||||
String(naRef str);
|
explicit String(naRef str);
|
||||||
|
|
||||||
const char* c_str() const;
|
const char* c_str() const;
|
||||||
const char* begin() const;
|
const char* begin() const;
|
||||||
|
|||||||
@@ -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/SGMath.hxx>
|
||||||
#include <simgear/math/SGRect.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/NasalObjectHolder.hxx>
|
||||||
#include <simgear/nasal/cppbind/to_nasal.hxx>
|
|
||||||
#include <simgear/structure/exception.hxx>
|
#include <simgear/structure/exception.hxx>
|
||||||
#include <simgear/structure/SGSharedPtr.hxx>
|
#include <simgear/structure/SGSharedPtr.hxx>
|
||||||
|
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
#include <boost/call_traits.hpp>
|
|
||||||
#include <boost/function.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/type_traits.hpp>
|
||||||
#include <boost/utility/enable_if.hpp>
|
#include <boost/utility/enable_if.hpp>
|
||||||
|
|
||||||
@@ -48,8 +43,6 @@ class SGPath;
|
|||||||
|
|
||||||
namespace nasal
|
namespace nasal
|
||||||
{
|
{
|
||||||
class Hash;
|
|
||||||
class String;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thrown when converting a type from/to Nasal has failed
|
* Thrown when converting a type from/to Nasal has failed
|
||||||
@@ -76,27 +69,19 @@ namespace nasal
|
|||||||
std::string _msg;
|
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.
|
* Simple pass through for unified handling also of naRef.
|
||||||
*/
|
*/
|
||||||
inline naRef from_nasal_helper(naContext, naRef ref, const naRef*)
|
inline naRef from_nasal_helper(naContext, naRef ref, const naRef*)
|
||||||
{ return ref; }
|
{ 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
|
* Convert Nasal string to std::string
|
||||||
*/
|
*/
|
||||||
@@ -125,43 +110,33 @@ namespace nasal
|
|||||||
*/
|
*/
|
||||||
bool from_nasal_helper(naContext c, naRef ref, const bool*);
|
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.
|
* Convert a Nasal function to a boost::function with the given signature.
|
||||||
*
|
*
|
||||||
* @tparam Sig Signature of returned function (arguments and return value
|
* @tparam Sig Signature of returned function (arguments and return value
|
||||||
* are automatically converted using from_nasal/to_nasal)
|
* are automatically converted using from_nasal/to_nasal)
|
||||||
*/
|
*/
|
||||||
template<class Sig>
|
template<class Ret, class... Args>
|
||||||
boost::function<Sig>
|
boost::function<Ret (Args...)>
|
||||||
from_nasal_helper(naContext c, naRef ref, boost::function<Sig>*)
|
from_nasal_helper(naContext c, naRef ref, const boost::function<Ret (Args...)>*)
|
||||||
{
|
{
|
||||||
if( naIsNil(ref) )
|
if( naIsNil(ref) )
|
||||||
return boost::function<Sig>();
|
return {};
|
||||||
|
|
||||||
if( !naIsCode(ref)
|
if( !naIsCode(ref)
|
||||||
&& !naIsCCode(ref)
|
&& !naIsCCode(ref)
|
||||||
&& !naIsFunc(ref) )
|
&& !naIsFunc(ref) )
|
||||||
throw bad_nasal_cast("not a function");
|
throw bad_nasal_cast("not a function");
|
||||||
|
|
||||||
return detail::boostFunctionFromNasal(ref, static_cast<Sig*>(0));
|
return NasalMethodHolder<Ret, Args...>(ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Sig>
|
template<class Ret, class... Args>
|
||||||
typename boost::enable_if< boost::is_function<Sig>,
|
boost::function<Ret (Args...)>
|
||||||
boost::function<Sig>
|
from_nasal_helper(naContext c, naRef ref, Ret (*const)(Args...))
|
||||||
>::type
|
|
||||||
from_nasal_helper(naContext c, naRef ref, Sig*)
|
|
||||||
{
|
{
|
||||||
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]);
|
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
|
} // namespace nasal
|
||||||
|
|
||||||
#endif /* SG_FROM_NASAL_HELPER_HXX_ */
|
#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_
|
#ifndef SG_NASAL_TRAITS_HXX_
|
||||||
#define SG_NASAL_TRAITS_HXX_
|
#define SG_NASAL_TRAITS_HXX_
|
||||||
|
|
||||||
#include <boost/mpl/logical.hpp>
|
#include <simgear/std/type_traits.hxx>
|
||||||
#include <boost/type_traits/integral_constant.hpp>
|
|
||||||
#include <boost/type_traits/is_base_of.hpp>
|
|
||||||
#include <boost/utility/enable_if.hpp>
|
|
||||||
|
|
||||||
// Forward declarations
|
// Forward declarations
|
||||||
class SGReferenced;
|
class SGReferenced;
|
||||||
@@ -56,12 +53,11 @@ namespace osg
|
|||||||
namespace nasal
|
namespace nasal
|
||||||
{
|
{
|
||||||
template<class T>
|
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)\
|
#define SG_MAKE_TRAIT(templ,type,attr)\
|
||||||
template templ\
|
template templ\
|
||||||
struct attr< type >:\
|
struct attr< type >: public std::true_type {};
|
||||||
public boost::integral_constant<bool, true> {};
|
|
||||||
|
|
||||||
SG_MAKE_TRAIT(<class T>, SGVec2<T>, is_vec2)
|
SG_MAKE_TRAIT(<class T>, SGVec2<T>, is_vec2)
|
||||||
SG_MAKE_TRAIT(<>, osg::Vec2b, is_vec2)
|
SG_MAKE_TRAIT(<>, osg::Vec2b, is_vec2)
|
||||||
@@ -75,42 +71,34 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2)
|
|||||||
struct shared_ptr_traits;
|
struct shared_ptr_traits;
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
struct is_strong_ref:
|
struct is_strong_ref: public std::false_type {};
|
||||||
public boost::integral_constant<bool, false>
|
|
||||||
{};
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
struct is_weak_ref:
|
struct is_weak_ref: public std::false_type {};
|
||||||
public boost::integral_constant<bool, false>
|
|
||||||
{};
|
|
||||||
|
|
||||||
#define SG_MAKE_SHARED_PTR_TRAIT(strong, weak, intrusive)\
|
#define SG_MAKE_SHARED_PTR_TRAIT(strong, weak, intrusive)\
|
||||||
template<class T>\
|
template<class T>\
|
||||||
struct shared_ptr_traits<strong<T> >\
|
struct shared_ptr_traits<strong<T> >\
|
||||||
{\
|
{\
|
||||||
typedef strong<T> strong_ref;\
|
using strong_ref = strong<T>;\
|
||||||
typedef weak<T> weak_ref;\
|
using weak_ref = weak<T>;\
|
||||||
typedef T element_type;\
|
using element_type = T;\
|
||||||
typedef boost::integral_constant<bool, true> is_strong;\
|
using is_strong = std::true_type;\
|
||||||
typedef boost::integral_constant<bool, intrusive> is_intrusive;\
|
using is_intrusive = std::bool_constant<intrusive>;\
|
||||||
};\
|
};\
|
||||||
template<class T>\
|
template<class T>\
|
||||||
struct shared_ptr_traits<weak<T> >\
|
struct shared_ptr_traits<weak<T> >\
|
||||||
{\
|
{\
|
||||||
typedef strong<T> strong_ref;\
|
using strong_ref = strong<T>;\
|
||||||
typedef weak<T> weak_ref;\
|
using weak_ref = weak<T>;\
|
||||||
typedef T element_type;\
|
using element_type = T;\
|
||||||
typedef boost::integral_constant<bool, false> is_strong;\
|
using is_strong = std::false_type;\
|
||||||
typedef boost::integral_constant<bool, intrusive> is_intrusive;\
|
using is_intrusive = std::bool_constant<intrusive>;\
|
||||||
};\
|
};\
|
||||||
template<class T>\
|
template<class T>\
|
||||||
struct is_strong_ref<strong<T> >:\
|
struct is_strong_ref<strong<T> >: public std::true_type {};\
|
||||||
public boost::integral_constant<bool, true>\
|
|
||||||
{};\
|
|
||||||
template<class T>\
|
template<class T>\
|
||||||
struct is_weak_ref<weak<T> >:\
|
struct is_weak_ref<weak<T> >: public std::true_type {};
|
||||||
public boost::integral_constant<bool, true>\
|
|
||||||
{};
|
|
||||||
|
|
||||||
SG_MAKE_SHARED_PTR_TRAIT(SGSharedPtr, SGWeakPtr, true)
|
SG_MAKE_SHARED_PTR_TRAIT(SGSharedPtr, SGWeakPtr, true)
|
||||||
SG_MAKE_SHARED_PTR_TRAIT(osg::ref_ptr, osg::observer_ptr, 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
|
#undef SG_MAKE_SHARED_PTR_TRAIT
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
struct supports_weak_ref:
|
struct supports_weak_ref: public std::true_type {};
|
||||||
public boost::integral_constant<bool, true>
|
|
||||||
{};
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
struct supports_weak_ref<SGSharedPtr<T> >:
|
struct supports_weak_ref<SGSharedPtr<T> >:
|
||||||
public boost::integral_constant<
|
public std::bool_constant<std::is_base_of<SGWeakReferenced, T>::value>
|
||||||
bool,
|
|
||||||
boost::is_base_of<SGWeakReferenced, T>::value
|
|
||||||
>
|
|
||||||
{};
|
{};
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
struct shared_ptr_storage
|
struct shared_ptr_storage
|
||||||
{
|
{
|
||||||
typedef T storage_type;
|
using storage_type = T;
|
||||||
typedef typename T::element_type element_type;
|
using element_type = typename T::element_type;
|
||||||
typedef typename shared_ptr_traits<T>::strong_ref strong_ref;
|
using strong_ref = typename shared_ptr_traits<T>::strong_ref;
|
||||||
typedef typename shared_ptr_traits<T>::weak_ref weak_ref;
|
using weak_ref = typename shared_ptr_traits<T>::weak_ref;
|
||||||
|
|
||||||
template<class U>
|
template<class U>
|
||||||
static storage_type* ref(U ptr)
|
static storage_type* ref(U ptr)
|
||||||
@@ -151,39 +134,30 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2)
|
|||||||
|
|
||||||
template<class U>
|
template<class U>
|
||||||
static
|
static
|
||||||
typename boost::enable_if<
|
std::enable_if_t<std::is_same<U, element_type*>::value, element_type*>
|
||||||
boost::is_same<U, element_type*>,
|
|
||||||
element_type*
|
|
||||||
>::type
|
|
||||||
get(storage_type* ptr)
|
get(storage_type* ptr)
|
||||||
{
|
{
|
||||||
return get_pointer(*ptr);
|
return get_pointer(*ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class U>
|
template<class U>
|
||||||
static
|
static
|
||||||
typename boost::enable_if<
|
std::enable_if_t<
|
||||||
boost::mpl::or_<
|
std::is_same<U, strong_ref>::value
|
||||||
boost::is_same<U, strong_ref>,
|
|| (std::is_same<U, weak_ref>::value && supports_weak_ref<U>::value),
|
||||||
boost::mpl::and_<
|
|
||||||
boost::is_same<U, weak_ref>,
|
|
||||||
supports_weak_ref<U>
|
|
||||||
>
|
|
||||||
>,
|
|
||||||
U
|
U
|
||||||
>::type
|
>
|
||||||
get(storage_type* ptr)
|
get(storage_type* ptr)
|
||||||
{
|
{
|
||||||
return U(*ptr);
|
return U(*ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class U>
|
template<class U>
|
||||||
static
|
static
|
||||||
typename boost::enable_if<
|
std::enable_if_t<
|
||||||
boost::mpl::and_<
|
std::is_same<U, weak_ref>::value && !supports_weak_ref<U>::value,
|
||||||
boost::is_same<U, weak_ref>,
|
|
||||||
boost::mpl::not_<supports_weak_ref<U> >
|
|
||||||
>,
|
|
||||||
U
|
U
|
||||||
>::type
|
>
|
||||||
get(storage_type* ptr)
|
get(storage_type* ptr)
|
||||||
{
|
{
|
||||||
return U();
|
return U();
|
||||||
@@ -195,46 +169,37 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2)
|
|||||||
template<class T>
|
template<class T>
|
||||||
struct intrusive_ptr_storage
|
struct intrusive_ptr_storage
|
||||||
{
|
{
|
||||||
typedef typename T::element_type storage_type;
|
using storage_type = typename T::element_type;
|
||||||
typedef typename T::element_type element_type;
|
using element_type = typename T::element_type;
|
||||||
typedef typename shared_ptr_traits<T>::strong_ref strong_ref;
|
using strong_ref = typename shared_ptr_traits<T>::strong_ref;
|
||||||
typedef typename shared_ptr_traits<T>::weak_ref weak_ref;
|
using weak_ref = typename shared_ptr_traits<T>::weak_ref;
|
||||||
|
|
||||||
template<class U>
|
template<class U>
|
||||||
static
|
static
|
||||||
typename boost::enable_if<
|
std::enable_if_t<std::is_same<U, element_type*>::value, element_type*>
|
||||||
boost::is_same<U, element_type*>,
|
|
||||||
element_type*
|
|
||||||
>::type
|
|
||||||
get(storage_type* ptr)
|
get(storage_type* ptr)
|
||||||
{
|
{
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class U>
|
template<class U>
|
||||||
static
|
static
|
||||||
typename boost::enable_if<
|
std::enable_if_t<
|
||||||
boost::mpl::or_<
|
std::is_same<U, strong_ref>::value
|
||||||
boost::is_same<U, strong_ref>,
|
|| (std::is_same<U, weak_ref>::value && supports_weak_ref<U>::value),
|
||||||
boost::mpl::and_<
|
|
||||||
boost::is_same<U, weak_ref>,
|
|
||||||
supports_weak_ref<U>
|
|
||||||
>
|
|
||||||
>,
|
|
||||||
U
|
U
|
||||||
>::type
|
>
|
||||||
get(storage_type* ptr)
|
get(storage_type* ptr)
|
||||||
{
|
{
|
||||||
return U(ptr);
|
return U(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class U>
|
template<class U>
|
||||||
static
|
static
|
||||||
typename boost::enable_if<
|
std::enable_if_t<
|
||||||
boost::mpl::and_<
|
std::is_same<U, weak_ref>::value && !supports_weak_ref<U>::value,
|
||||||
boost::is_same<U, weak_ref>,
|
|
||||||
boost::mpl::not_<supports_weak_ref<U> >
|
|
||||||
>,
|
|
||||||
U
|
U
|
||||||
>::type
|
>
|
||||||
get(storage_type* ptr)
|
get(storage_type* ptr)
|
||||||
{
|
{
|
||||||
return U();
|
return U();
|
||||||
@@ -246,8 +211,8 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2)
|
|||||||
struct shared_ptr_storage<SGSharedPtr<T> >:
|
struct shared_ptr_storage<SGSharedPtr<T> >:
|
||||||
public internal::intrusive_ptr_storage<SGSharedPtr<T> >
|
public internal::intrusive_ptr_storage<SGSharedPtr<T> >
|
||||||
{
|
{
|
||||||
typedef T storage_type;
|
using storage_type = T;
|
||||||
typedef T element_type;
|
using element_type = T;
|
||||||
|
|
||||||
static storage_type* ref(element_type* ptr)
|
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> >:
|
struct shared_ptr_storage<osg::ref_ptr<T> >:
|
||||||
public internal::intrusive_ptr_storage<osg::ref_ptr<T> >
|
public internal::intrusive_ptr_storage<osg::ref_ptr<T> >
|
||||||
{
|
{
|
||||||
typedef T storage_type;
|
using storage_type = T;
|
||||||
typedef T element_type;
|
using element_type = T;
|
||||||
|
|
||||||
|
|
||||||
static storage_type* ref(element_type* ptr)
|
static storage_type* ref(element_type* ptr)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
#include <simgear/math/SGMath.hxx>
|
#include <simgear/math/SGMath.hxx>
|
||||||
#include <simgear/math/SGRect.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/function/function_fwd.hpp>
|
||||||
#include <boost/utility/enable_if.hpp>
|
#include <boost/utility/enable_if.hpp>
|
||||||
@@ -40,8 +40,6 @@ class SGPath;
|
|||||||
|
|
||||||
namespace nasal
|
namespace nasal
|
||||||
{
|
{
|
||||||
class CallContext;
|
|
||||||
class Hash;
|
|
||||||
|
|
||||||
typedef boost::function<naRef (CallContext)> free_function_t;
|
typedef boost::function<naRef (CallContext)> free_function_t;
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
#define SG_FROM_NASAL_HXX_
|
#define SG_FROM_NASAL_HXX_
|
||||||
|
|
||||||
#include <simgear/nasal/cppbind/detail/from_nasal_helper.hxx>
|
#include <simgear/nasal/cppbind/detail/from_nasal_helper.hxx>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace nasal
|
namespace nasal
|
||||||
{
|
{
|
||||||
@@ -52,8 +53,8 @@ namespace nasal
|
|||||||
template<class Var>
|
template<class Var>
|
||||||
struct from_nasal_ptr
|
struct from_nasal_ptr
|
||||||
{
|
{
|
||||||
typedef typename boost::remove_const
|
typedef typename std::remove_const
|
||||||
< typename boost::remove_reference<Var>::type
|
< typename std::remove_reference<Var>::type
|
||||||
>::type return_type;
|
>::type return_type;
|
||||||
typedef return_type(*type)(naContext, naRef);
|
typedef return_type(*type)(naContext, naRef);
|
||||||
|
|
||||||
|
|||||||
@@ -20,50 +20,29 @@
|
|||||||
#ifndef SG_NASAL_TESTCONTEXT_HXX_
|
#ifndef SG_NASAL_TESTCONTEXT_HXX_
|
||||||
#define SG_NASAL_TESTCONTEXT_HXX_
|
#define SG_NASAL_TESTCONTEXT_HXX_
|
||||||
|
|
||||||
#include <simgear/nasal/cppbind/NasalCallContext.hxx>
|
#include <simgear/nasal/cppbind/NasalContext.hxx>
|
||||||
|
|
||||||
class TestContext:
|
class TestContext:
|
||||||
public nasal::CallContext
|
public nasal::Context
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TestContext():
|
|
||||||
CallContext(naNewContext(), naNil(), 0, 0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
~TestContext()
|
|
||||||
{
|
|
||||||
naFreeContext(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
void runGC()
|
void runGC()
|
||||||
{
|
{
|
||||||
naFreeContext(c);
|
naFreeContext(_ctx);
|
||||||
naGC();
|
naGC();
|
||||||
c = naNewContext();
|
_ctx = naNewContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T = naRef>
|
||||||
T from_str(const std::string& str)
|
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)
|
template<class T = naRef>
|
||||||
{
|
|
||||||
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>
|
|
||||||
T exec(const std::string& code)
|
T exec(const std::string& code)
|
||||||
{
|
{
|
||||||
return from_nasal<T>(exec(code, naNil()));
|
return from_nasal<T>(execImpl(code, nasal::Me{}));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
@@ -71,6 +50,26 @@ class TestContext:
|
|||||||
{
|
{
|
||||||
return from_nasal<T>(to_nasal(str));
|
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_ */
|
#endif /* SG_NASAL_TESTCONTEXT_HXX_ */
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#define BOOST_TEST_MODULE cppbind
|
#define BOOST_TEST_MODULE cppbind
|
||||||
#include <BoostTestTargetConfig.h>
|
#include <BoostTestTargetConfig.h>
|
||||||
|
|
||||||
|
#include "TestContext.hxx"
|
||||||
|
|
||||||
#include <simgear/nasal/cppbind/Ghost.hxx>
|
#include <simgear/nasal/cppbind/Ghost.hxx>
|
||||||
#include <simgear/nasal/cppbind/NasalHash.hxx>
|
#include <simgear/nasal/cppbind/NasalHash.hxx>
|
||||||
#include <simgear/nasal/cppbind/NasalString.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 )
|
BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
|
||||||
{
|
{
|
||||||
naContext c = naNewContext();
|
TestContext c;
|
||||||
naRef r;
|
naRef r;
|
||||||
|
|
||||||
using namespace nasal;
|
using namespace nasal;
|
||||||
|
|
||||||
r = to_nasal(c, ENUM_ANOTHER);
|
r = c.to_nasal(ENUM_ANOTHER);
|
||||||
BOOST_CHECK_EQUAL(from_nasal<int>(c, r), 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( 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( 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(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(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};
|
float test_data[3] = {0, 4, 2};
|
||||||
r = to_nasal(c, test_data);
|
r = c.to_nasal(test_data);
|
||||||
|
|
||||||
SGVec2f vec(0,2);
|
SGVec2f vec(0,2);
|
||||||
r = to_nasal(c, vec);
|
r = c.to_nasal(vec);
|
||||||
BOOST_CHECK_EQUAL(from_nasal<SGVec2f>(c, r), vec);
|
BOOST_CHECK_EQUAL(c.from_nasal<SGVec2f>(r), vec);
|
||||||
|
|
||||||
std::vector<int> std_vec;
|
std::vector<int> std_vec;
|
||||||
r = to_nasal(c, std_vec);
|
r = c.to_nasal(std_vec);
|
||||||
|
|
||||||
r = to_nasal(c, "string");
|
r = c.to_nasal("string");
|
||||||
BOOST_CHECK_THROW(from_nasal<int>(c, r), bad_nasal_cast);
|
BOOST_CHECK_THROW(c.from_nasal<int>(r), bad_nasal_cast);
|
||||||
|
|
||||||
Hash hash(c);
|
Hash hash(c);
|
||||||
hash.set("vec", r);
|
hash.set("vec", r);
|
||||||
@@ -171,10 +173,10 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
|
|||||||
it1 = it2;
|
it1 = it2;
|
||||||
it3 = it2;
|
it3 = it2;
|
||||||
|
|
||||||
r = to_nasal(c, hash);
|
r = c.to_nasal(hash);
|
||||||
BOOST_REQUIRE( naIsHash(r) );
|
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("vec"), "string");
|
||||||
BOOST_CHECK_EQUAL(string_map.at("name"), "my-name");
|
BOOST_CHECK_EQUAL(string_map.at("name"), "my-name");
|
||||||
BOOST_CHECK_EQUAL(string_map.at("string"), "blub");
|
BOOST_CHECK_EQUAL(string_map.at("string"), "blub");
|
||||||
@@ -216,7 +218,7 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
|
|||||||
// passed on to function
|
// passed on to function
|
||||||
typedef boost::function<int (Me, int)> MeIntFunc;
|
typedef boost::function<int (Me, int)> MeIntFunc;
|
||||||
MeIntFunc fmeint = hash.get<MeIntFunc>("func");
|
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
|
// Test exposing classes to Nasal
|
||||||
@@ -260,81 +262,81 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
|
|||||||
Ghost<SGWeakRefBasedPtr>::init("SGWeakRefBasedPtr");
|
Ghost<SGWeakRefBasedPtr>::init("SGWeakRefBasedPtr");
|
||||||
|
|
||||||
SGWeakRefBasedPtr weak_ptr(new SGWeakReferenceBasedClass());
|
SGWeakRefBasedPtr weak_ptr(new SGWeakReferenceBasedClass());
|
||||||
naRef nasal_ref = to_nasal(c, weak_ptr),
|
naRef nasal_ref = c.to_nasal(weak_ptr),
|
||||||
nasal_ptr = to_nasal(c, weak_ptr.get());
|
nasal_ptr = c.to_nasal(weak_ptr.get());
|
||||||
|
|
||||||
BOOST_REQUIRE( naIsGhost(nasal_ref) );
|
BOOST_REQUIRE( naIsGhost(nasal_ref) );
|
||||||
BOOST_REQUIRE( naIsGhost(nasal_ptr) );
|
BOOST_REQUIRE( naIsGhost(nasal_ptr) );
|
||||||
|
|
||||||
SGWeakRefBasedPtr ptr1 = from_nasal<SGWeakRefBasedPtr>(c, nasal_ref),
|
SGWeakRefBasedPtr ptr1 = c.from_nasal<SGWeakRefBasedPtr>(nasal_ref),
|
||||||
ptr2 = from_nasal<SGWeakRefBasedPtr>(c, nasal_ptr);
|
ptr2 = c.from_nasal<SGWeakRefBasedPtr>(nasal_ptr);
|
||||||
|
|
||||||
BOOST_CHECK_EQUAL(weak_ptr, ptr1);
|
BOOST_CHECK_EQUAL(weak_ptr, ptr1);
|
||||||
BOOST_CHECK_EQUAL(weak_ptr, ptr2);
|
BOOST_CHECK_EQUAL(weak_ptr, ptr2);
|
||||||
|
|
||||||
|
|
||||||
BOOST_REQUIRE( Ghost<BasePtr>::isInit() );
|
BOOST_REQUIRE( Ghost<BasePtr>::isInit() );
|
||||||
nasal::to_nasal(c, DoubleDerived2Ptr());
|
c.to_nasal(DoubleDerived2Ptr());
|
||||||
|
|
||||||
BasePtr d( new Derived );
|
BasePtr d( new Derived );
|
||||||
naRef derived = to_nasal(c, d);
|
naRef derived = c.to_nasal(d);
|
||||||
BOOST_REQUIRE( naIsGhost(derived) );
|
BOOST_REQUIRE( naIsGhost(derived) );
|
||||||
BOOST_CHECK_EQUAL( std::string("DerivedPtr"), naGhost_type(derived)->name );
|
BOOST_CHECK_EQUAL( std::string("DerivedPtr"), naGhost_type(derived)->name );
|
||||||
|
|
||||||
// Get member function from ghost...
|
// Get member function from ghost...
|
||||||
naRef thisGetter = naNil();
|
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) );
|
BOOST_CHECK( naIsFunc(thisGetter) );
|
||||||
|
|
||||||
// ...and check if it really gets passed the correct instance
|
// ...and check if it really gets passed the correct instance
|
||||||
typedef boost::function<unsigned long (Me)> MemFunc;
|
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_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 );
|
BasePtr d2( new DoubleDerived );
|
||||||
derived = to_nasal(c, d2);
|
derived = c.to_nasal(d2);
|
||||||
BOOST_CHECK( naIsGhost(derived) );
|
BOOST_CHECK( naIsGhost(derived) );
|
||||||
BOOST_CHECK_EQUAL( std::string("DoubleDerivedPtr"),
|
BOOST_CHECK_EQUAL( std::string("DoubleDerivedPtr"),
|
||||||
naGhost_type(derived)->name );
|
naGhost_type(derived)->name );
|
||||||
|
|
||||||
BasePtr d3( new DoubleDerived2 );
|
BasePtr d3( new DoubleDerived2 );
|
||||||
derived = to_nasal(c, d3);
|
derived = c.to_nasal(d3);
|
||||||
BOOST_CHECK( naIsGhost(derived) );
|
BOOST_CHECK( naIsGhost(derived) );
|
||||||
BOOST_CHECK_EQUAL( std::string("DoubleDerived2Ptr"),
|
BOOST_CHECK_EQUAL( std::string("DoubleDerived2Ptr"),
|
||||||
naGhost_type(derived)->name );
|
naGhost_type(derived)->name );
|
||||||
|
|
||||||
SGRefBasedPtr ref_based( new SGReferenceBasedClass );
|
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( 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() );
|
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_EQUAL( c.from_nasal<BasePtr>(derived), d3 );
|
||||||
BOOST_CHECK_NE( from_nasal<BasePtr>(c, derived), d2 );
|
BOOST_CHECK_NE( c.from_nasal<BasePtr>(derived), d2 );
|
||||||
BOOST_CHECK_EQUAL( from_nasal<DerivedPtr>(c, derived),
|
BOOST_CHECK_EQUAL( c.from_nasal<DerivedPtr>(derived),
|
||||||
boost::dynamic_pointer_cast<Derived>(d3) );
|
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::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;
|
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;
|
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;
|
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;
|
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 dict =
|
||||||
simgear::StringMap("hello", "value")
|
simgear::StringMap("hello", "value")
|
||||||
("key2", "value2");
|
("key2", "value2");
|
||||||
naRef na_dict = to_nasal(c, dict);
|
naRef na_dict = c.to_nasal(dict);
|
||||||
BOOST_REQUIRE( naIsHash(na_dict) );
|
BOOST_REQUIRE( naIsHash(na_dict) );
|
||||||
BOOST_CHECK_EQUAL( Hash(na_dict, c).get<std::string>("key2"), "value2" );
|
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);
|
Hash obj(c);
|
||||||
obj.set("parents", parents);
|
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)
|
// Check recursive parents (aka parent-of-parent)
|
||||||
std::vector<naRef> parents2;
|
std::vector<naRef> parents2;
|
||||||
parents2.push_back(obj.get_naRef());
|
parents2.push_back(obj.get_naRef());
|
||||||
Hash derived_obj(c);
|
Hash derived_obj(c);
|
||||||
derived_obj.set("parents", parents2);
|
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;
|
std::vector<naRef> nasal_objects;
|
||||||
nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d) );
|
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, d2) );
|
||||||
nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d3) );
|
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[0], d );
|
||||||
BOOST_CHECK_EQUAL( objects[1], d2 );
|
BOOST_CHECK_EQUAL( objects[1], d2 );
|
||||||
BOOST_CHECK_EQUAL( objects[2], d3 );
|
BOOST_CHECK_EQUAL( objects[2], d3 );
|
||||||
|
|
||||||
{
|
// Calling fallback setter for unset values
|
||||||
// Calling fallback setter for unset values
|
BOOST_CHECK_EQUAL( c.exec<int>("me.test = 3;", Me{derived}), 3 );
|
||||||
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());
|
|
||||||
|
|
||||||
BOOST_REQUIRE( !naGetError(c) ); // TODO real error check (this seems to
|
// Calling generic (fallback) getter
|
||||||
// always return 0...
|
BOOST_CHECK_EQUAL( c.exec<std::string>("var a = me.get_test;", Me{derived}),
|
||||||
BOOST_CHECK_EQUAL( from_nasal<int>(c, ret), 3 );
|
"generic-get" );
|
||||||
}
|
|
||||||
{
|
|
||||||
// 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" );
|
|
||||||
}
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// Test nasal::CallContext
|
// Test nasal::CallContext
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
int int_vec[] = {1,2,3};
|
int int_vec[] = {1,2,3};
|
||||||
std::map<std::string, std::string> map;
|
std::map<std::string, std::string> map;
|
||||||
naRef args[] = {
|
naRef args[] = {
|
||||||
to_nasal(c, std::string("test-arg")),
|
c.to_nasal(std::string("test-arg")),
|
||||||
to_nasal(c, 4),
|
c.to_nasal(4),
|
||||||
to_nasal(c, int_vec),
|
c.to_nasal(int_vec),
|
||||||
to_nasal(c, map)
|
c.to_nasal(map)
|
||||||
};
|
};
|
||||||
CallContext cc(c, naNil(), sizeof(args)/sizeof(args[0]), args);
|
CallContext cc(c, naNil(), sizeof(args)/sizeof(args[0]), args);
|
||||||
BOOST_CHECK_EQUAL( cc.requireArg<std::string>(0), "test-arg" );
|
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.isVector(2) );
|
||||||
BOOST_CHECK( cc.isHash(3) );
|
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) );
|
BOOST_CHECK( naIsVector(args_vec) );
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// Test nasal::String
|
// Test nasal::String
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
String string( to_nasal(c, "Test") );
|
String string( c.to_nasal("Test") );
|
||||||
BOOST_CHECK_EQUAL( from_nasal<std::string>(c, string.get_naRef()), "Test" );
|
BOOST_CHECK_EQUAL( c.from_nasal<std::string>(string.get_naRef()), "Test" );
|
||||||
BOOST_CHECK_EQUAL( string.c_str(), std::string("Test") );
|
BOOST_CHECK_EQUAL( string.c_str(), std::string("Test") );
|
||||||
BOOST_CHECK( string.starts_with(string) );
|
BOOST_CHECK( string.starts_with(string) );
|
||||||
BOOST_CHECK( string.starts_with(String(c, "T")) );
|
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, "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")), 0 );
|
||||||
BOOST_CHECK_EQUAL( string.find_first_not_of(String(c, "abc"), 20), String::npos );
|
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
|
#define BOOST_TEST_MODULE cppbind
|
||||||
#include <BoostTestTargetConfig.h>
|
#include <BoostTestTargetConfig.h>
|
||||||
|
|
||||||
|
#include "TestContext.hxx"
|
||||||
|
|
||||||
#include <simgear/nasal/cppbind/Ghost.hxx>
|
#include <simgear/nasal/cppbind/Ghost.hxx>
|
||||||
#include <simgear/nasal/cppbind/NasalContext.hxx>
|
#include <simgear/nasal/cppbind/NasalContext.hxx>
|
||||||
|
|
||||||
|
#include <boost/make_shared.hpp>
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/weak_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);
|
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)
|
static naRef createTestGhost(TestContext& c, intptr_t p)
|
||||||
{
|
{
|
||||||
active_instances.insert(p);
|
active_instances.insert(p);
|
||||||
return naNewGhost(c.c, &ghost_type, (void*)p);
|
return naNewGhost(c, &ghost_type, (void*)p);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|||||||
+15
-10
@@ -1,3 +1,6 @@
|
|||||||
|
///@file
|
||||||
|
/// The Nasal scripting language
|
||||||
|
///
|
||||||
#ifndef _NASAL_H
|
#ifndef _NASAL_H
|
||||||
#define _NASAL_H
|
#define _NASAL_H
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@@ -15,12 +18,14 @@ extern "C" {
|
|||||||
#define GCC_PURE
|
#define GCC_PURE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** Nasal context pointer */
|
||||||
typedef struct Context* naContext;
|
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);
|
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)
|
typedef naRef (*naCFunctionU)
|
||||||
(naContext ctx, naRef me, int argc, naRef* args, void* user_data);
|
(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_cset(naRef hash, char* key, naRef val);
|
||||||
void naHash_delete(naRef hash, naRef key);
|
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
|
* @see ::naNewVector
|
||||||
*/
|
*/
|
||||||
@@ -273,25 +278,25 @@ typedef struct naGhostType {
|
|||||||
} naGhostType;
|
} naGhostType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a ghost for an object without any attributes. If ::t contains pointers
|
* Create a ghost for an object without any attributes. If @p t contains
|
||||||
* to get_member or set_member function they will be ignored.
|
* pointers to get_member or set_member function they will be ignored.
|
||||||
*/
|
*/
|
||||||
naRef naNewGhost(naContext c, naGhostType* t, void* ghost);
|
naRef naNewGhost(naContext c, naGhostType* t, void* ghost);
|
||||||
/**
|
/**
|
||||||
* Create a ghost for an object. This version uses the get_member and set_member
|
* 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
|
* function pointers in @p t upon trying to get or set a member respectively
|
||||||
* Nasal.
|
* from Nasal.
|
||||||
*/
|
*/
|
||||||
naRef naNewGhost2(naContext c, naGhostType* t, void* ghost);
|
naRef naNewGhost2(naContext c, naGhostType* t, void* ghost);
|
||||||
naGhostType* naGhost_type(naRef ghost);
|
naGhostType* naGhost_type(naRef ghost);
|
||||||
void* naGhost_ptr(naRef ghost);
|
void* naGhost_ptr(naRef ghost);
|
||||||
/**
|
/**
|
||||||
* Attach a nasal object to the given ghost. Binds the lifetime of @a data to
|
* Attach a nasal object to the given ghost. Binds the lifetime of @p data to
|
||||||
* the lifetime of the @a ghost.
|
* the lifetime of the @p ghost.
|
||||||
*/
|
*/
|
||||||
void naGhost_setData(naRef ghost, naRef data);
|
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().
|
* naGhost_setData().
|
||||||
*/
|
*/
|
||||||
naRef naGhost_data(naRef ghost);
|
naRef naGhost_data(naRef ghost);
|
||||||
|
|||||||
@@ -554,12 +554,10 @@ void Root::addDelegate(simgear::pkg::Delegate *aDelegate)
|
|||||||
|
|
||||||
void Root::removeDelegate(simgear::pkg::Delegate *aDelegate)
|
void Root::removeDelegate(simgear::pkg::Delegate *aDelegate)
|
||||||
{
|
{
|
||||||
DelegateVec::iterator it = std::find(d->delegates.begin(),
|
auto it = std::find(d->delegates.begin(), d->delegates.end(), aDelegate);
|
||||||
d->delegates.end(), aDelegate);
|
if (it != d->delegates.end()) {
|
||||||
if (it == d->delegates.end()) {
|
d->delegates.erase(it);
|
||||||
throw sg_exception("unknown delegate in removeDelegate");
|
|
||||||
}
|
}
|
||||||
d->delegates.erase(it);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Root::setLocale(const std::string& aLocale)
|
void Root::setLocale(const std::string& aLocale)
|
||||||
|
|||||||
+14
-12
@@ -99,9 +99,9 @@ inline T parseString(const std::string& str)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
//
|
||||||
* Property value types.
|
// Property value types
|
||||||
*/
|
//
|
||||||
|
|
||||||
#ifdef NONE
|
#ifdef NONE
|
||||||
#pragma warn A sloppy coder has defined NONE as a macro!
|
#pragma warn A sloppy coder has defined NONE as a macro!
|
||||||
@@ -148,6 +148,7 @@ inline T parseString(const std::string& str)
|
|||||||
#undef STRING
|
#undef STRING
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// Property system which associates property names with values.
|
||||||
namespace props
|
namespace props
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@@ -2144,17 +2145,18 @@ inline SGPropertyNode* makeChild(SGPropertyNode* parent, const char* name,
|
|||||||
return parent->getChild(name, index, true);
|
return parent->getChild(name, index, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility function for creation of a child property node using a
|
|
||||||
* relative path.
|
|
||||||
*/
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
template<typename StringType>
|
/**
|
||||||
inline SGPropertyNode* makeNode(SGPropertyNode* parent, const StringType& name)
|
* Utility function for creation of a child property node using a
|
||||||
{
|
* relative path.
|
||||||
return parent->getNode(name, true);
|
*/
|
||||||
}
|
template<typename StringType>
|
||||||
|
inline SGPropertyNode*
|
||||||
|
makeNode(SGPropertyNode* parent, const StringType& name)
|
||||||
|
{
|
||||||
|
return parent->getNode(name, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For boost::hash
|
// For boost::hash
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
///@file
|
||||||
|
/// Support classes for parsing effects.
|
||||||
|
///
|
||||||
// Copyright (C) 2009 Tim Moore timoore@redhat.com
|
// Copyright (C) 2009 Tim Moore timoore@redhat.com
|
||||||
//
|
//
|
||||||
// This library is free software; you can redistribute it and/or
|
// This library is free software; you can redistribute it and/or
|
||||||
@@ -39,9 +42,6 @@
|
|||||||
#include <simgear/structure/Singleton.hxx>
|
#include <simgear/structure/Singleton.hxx>
|
||||||
|
|
||||||
#include "Effect.hxx"
|
#include "Effect.hxx"
|
||||||
/**
|
|
||||||
* Support classes for parsing effects.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -77,9 +77,9 @@ osg::Vec2d eventToWindowCoords(const osgGA::GUIEventAdapter& ea)
|
|||||||
SGPropertyNode* modelRoot,
|
SGPropertyNode* modelRoot,
|
||||||
SGSharedPtr<SGCondition const> condition) :
|
SGSharedPtr<SGCondition const> condition) :
|
||||||
SGPickCallback(PriorityPanel),
|
SGPickCallback(PriorityPanel),
|
||||||
|
_condition(condition),
|
||||||
_repeatable(configNode->getBoolValue("repeatable", false)),
|
_repeatable(configNode->getBoolValue("repeatable", false)),
|
||||||
_repeatInterval(configNode->getDoubleValue("interval-sec", 0.1)),
|
_repeatInterval(configNode->getDoubleValue("interval-sec", 0.1))
|
||||||
_condition(condition)
|
|
||||||
{
|
{
|
||||||
std::vector<SGPropertyNode_ptr> bindings;
|
std::vector<SGPropertyNode_ptr> bindings;
|
||||||
|
|
||||||
@@ -264,7 +264,8 @@ public:
|
|||||||
SGPropertyNode* modelRoot,
|
SGPropertyNode* modelRoot,
|
||||||
osg::Group *node,
|
osg::Group *node,
|
||||||
SGSharedPtr<SGCondition const> condition)
|
SGSharedPtr<SGCondition const> condition)
|
||||||
: _node(node), _condition(condition)
|
: _condition(condition)
|
||||||
|
, _node(node)
|
||||||
{
|
{
|
||||||
SG_LOG(SG_INPUT, SG_DEBUG, "Configuring VNC callback");
|
SG_LOG(SG_INPUT, SG_DEBUG, "Configuring VNC callback");
|
||||||
const char *cornernames[3] = {"top-left", "top-right", "bottom-left"};
|
const char *cornernames[3] = {"top-left", "top-right", "bottom-left"};
|
||||||
@@ -765,7 +766,8 @@ private:
|
|||||||
class SGKnobAnimation::UpdateCallback : public osg::NodeCallback {
|
class SGKnobAnimation::UpdateCallback : public osg::NodeCallback {
|
||||||
public:
|
public:
|
||||||
UpdateCallback(SGExpressiond const* animationValue, SGSharedPtr<SGCondition const> condition) :
|
UpdateCallback(SGExpressiond const* animationValue, SGSharedPtr<SGCondition const> condition) :
|
||||||
_animationValue(animationValue), _condition(condition)
|
_condition(condition),
|
||||||
|
_animationValue(animationValue)
|
||||||
{
|
{
|
||||||
setName("SGKnobAnimation::UpdateCallback");
|
setName("SGKnobAnimation::UpdateCallback");
|
||||||
}
|
}
|
||||||
@@ -899,9 +901,9 @@ class TouchPickCallback : public SGPickCallback {
|
|||||||
public:
|
public:
|
||||||
TouchPickCallback(const SGPropertyNode* configNode,
|
TouchPickCallback(const SGPropertyNode* configNode,
|
||||||
SGPropertyNode* modelRoot) :
|
SGPropertyNode* modelRoot) :
|
||||||
|
SGPickCallback(PriorityPanel),
|
||||||
_repeatable(configNode->getBoolValue("repeatable", false)),
|
_repeatable(configNode->getBoolValue("repeatable", false)),
|
||||||
_repeatInterval(configNode->getDoubleValue("interval-sec", 0.1)),
|
_repeatInterval(configNode->getDoubleValue("interval-sec", 0.1))
|
||||||
SGPickCallback(PriorityPanel)
|
|
||||||
{
|
{
|
||||||
std::vector<SGPropertyNode_ptr> bindings;
|
std::vector<SGPropertyNode_ptr> bindings;
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,15 @@
|
|||||||
#cmakedefine HAVE_TIMEGM
|
#cmakedefine HAVE_TIMEGM
|
||||||
|
|
||||||
#cmakedefine HAVE_STD_ISNAN
|
#cmakedefine HAVE_STD_ISNAN
|
||||||
|
#cmakedefine HAVE_WORKING_STD_REGEX
|
||||||
#cmakedefine HAVE_WINDOWS_H
|
#cmakedefine HAVE_WINDOWS_H
|
||||||
#cmakedefine HAVE_MKDTEMP
|
#cmakedefine HAVE_MKDTEMP
|
||||||
#cmakedefine HAVE_AL_EXT_H
|
#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
|
#cmakedefine GCC_ATOMIC_BUILTINS_FOUND
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
@@ -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_ */
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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_ */
|
||||||
@@ -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/exception.hxx>
|
||||||
#include <simgear/structure/Singleton.hxx>
|
#include <simgear/structure/Singleton.hxx>
|
||||||
|
|
||||||
/// Expression tree implementation.
|
|
||||||
|
|
||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
|
/// Expression tree implementation.
|
||||||
namespace expression
|
namespace expression
|
||||||
{
|
{
|
||||||
enum Type {
|
enum Type {
|
||||||
|
|||||||
@@ -29,9 +29,10 @@ namespace simgear
|
|||||||
/**
|
/**
|
||||||
* Handle a list of callbacks like a single boost::function.
|
* 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...)>:
|
class function_list<Ret(Args...)>:
|
||||||
public std::vector<boost::function<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
|
* Handle a list of callbacks with the same signature as the given
|
||||||
* boost::function type.
|
* boost::function type.
|
||||||
*/
|
*/
|
||||||
template<class Ret, class ... Args>
|
template<class Ret, class... Args>
|
||||||
class function_list<boost::function<Ret(Args...)>>:
|
class function_list<boost::function<Ret(Args...)>>:
|
||||||
public function_list<Ret(Args...)>
|
public function_list<Ret(Args...)>
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user