Merge branch 'next' of ssh://git.code.sf.net/p/flightgear/simgear into next

This commit is contained in:
gallaert
2018-01-21 20:06:46 +00:00
51 changed files with 1578 additions and 920 deletions

1
.gitignore vendored
View File

@@ -14,3 +14,4 @@ CTestTestfile.cmake
install_manifest.txt
build*
Build
CMakeLists.txt.user

View File

@@ -7,6 +7,9 @@ if(COMMAND cmake_policy)
if(POLICY CMP0042)
cmake_policy(SET CMP0042 NEW)
endif()
if(POLICY CMP0067)
cmake_policy(SET CMP0067 NEW)
endif()
endif()
@@ -135,6 +138,16 @@ include (DetectArch)
# keep the compatability link option as the default
option(OSG_FSTREAM_EXPORT_FIXED "Set to ON if the osgDB fstream export patch is applied" OFF)
if (CMAKE_COMPILER_IS_GNUCXX OR CLANG)
if (CMAKE_VERSION VERSION_LESS 3.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++${CMAKE_CXX_STANDARD}")
elseif (CMAKE_VERSION VERSION_LESS 3.8)
# policy CMP0067 (try_compile does not honor CMAKE_CXX_STANDARD)
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++${CMAKE_CXX_STANDARD}")
endif()
endif()
if (MSVC)
GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_BINARY_DIR} PATH)
if (CMAKE_CL_64)
@@ -351,14 +364,35 @@ if (NOT ${HAVE_STD_ISNAN})
message(FATAL_ERROR "Your compiler lacks C++11 std::isnan, please update it")
endif()
# Check if the <regex> implementation in the C++ standard library is usable.
# This is necessary because g++ 4.8 lies about its C++11 compliance: its
# <regex> is utterly unusable, cf. [1].
# The big preprocessor test essentially comes from [2], and gcc upstream devs
# appear to back it (see comments following [2], as well as [3]).
#
# [1] https://stackoverflow.com/a/12665408/4756009
# [2] https://stackoverflow.com/a/41186162/4756009
# [3] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78905
check_cxx_source_compiles(
"#include <regex>
int main() {
#if __cplusplus >= 201103L && \
(!defined(__GLIBCXX__) || \
(__cplusplus >= 201402L) || \
defined(_GLIBCXX_REGEX_DFS_QUANTIFIERS_LIMIT) || \
defined(_GLIBCXX_REGEX_STATE_LIMIT) || \
(defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE > 4))
#else
nullptr = void; // intentionally trigger a compilation error
#endif
}"
HAVE_WORKING_STD_REGEX)
if(CMAKE_COMPILER_IS_GNUCXX)
set(WARNING_FLAGS_CXX "-Wall -fPIC")
set(WARNING_FLAGS_C "-Wall -fPIC")
if (CMAKE_VERSION VERSION_LESS 3.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif()
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4)
message(WARNING "GCC 4.4 will be required soon, please upgrade")
endif()
@@ -386,10 +420,6 @@ if (CLANG)
# fix Boost compilation :(
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
if (CMAKE_VERSION VERSION_LESS 3.1)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif()
if(ENABLE_SIMD)
if (X86 OR X86_64)
set(CMAKE_C_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse")
@@ -462,6 +492,8 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS_C} ${MSVC_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS_CXX} ${MSVC_FLAGS} ${BOOST_CXX_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MSVC_LD_FLAGS}")
include(CheckCXXFeatures)
# use BEFORE to ensure local directories are used first,
# ahead of system-installed libs
include_directories(BEFORE ${PROJECT_BINARY_DIR}/simgear)

View File

@@ -0,0 +1,30 @@
check_cxx_source_compiles("
#include <utility>
#include <type_traits>
std::make_index_sequence<0> t;
int main() {}" HAVE_STD_INDEX_SEQUENCE
)
check_cxx_source_compiles("
#include <type_traits>
std::remove_cv_t<const int> t;
int main() {}" HAVE_STD_REMOVE_CV_T
)
check_cxx_source_compiles("
#include <type_traits>
std::remove_cvref_t<const int&> t;
int main() {}" HAVE_STD_REMOVE_CVREF_T
)
check_cxx_source_compiles("
#include <type_traits>
std::enable_if_t<true, int> t;
int main() {}" HAVE_STD_ENABLE_IF_T
)
check_cxx_source_compiles("
#include <type_traits>
std::bool_constant<true> t;
int main() {}" HAVE_STD_BOOL_CONSTANT
)

View File

@@ -2,6 +2,10 @@
documentation. It has a .cxx extension so that emacs will happily
autoindent correctly. */
/**
* \namespace simgear
* \brief \ref index "SimGear" main namespace.
*/
/** \mainpage SimGear
* Simulation, Visualization, and Game development libraries.

View File

@@ -15,6 +15,7 @@ foreach( mylibfolder
nasal/cppbind
props
serial
std
structure
threads
timing

View File

@@ -53,7 +53,7 @@ void testBasic()
SG_CHECK_EQUAL(b1.gen_index(), 3040320);
SG_CHECK_EQUAL(b1.gen_base_path(), "e000n50/e005n55");
SG_VERIFY(b1.isValid());
SGBucket b2(-10.1, -43.8);
SG_CHECK_EQUAL(b2.get_chunk_lon(), -11);
SG_CHECK_EQUAL(b2.get_chunk_lat(), -44);
@@ -62,7 +62,7 @@ void testBasic()
SG_CHECK_EQUAL(b2.get_y(), 1);
SG_CHECK_EQUAL(b2.gen_base_path(), "w020s50/w011s44");
SG_VERIFY(b2.isValid());
SGBucket b3(123.48, 9.01);
SG_CHECK_EQUAL(b3.get_chunk_lon(), 123);
SG_CHECK_EQUAL(b3.get_chunk_lat(), 9);
@@ -70,10 +70,10 @@ void testBasic()
SG_CHECK_EQUAL(b3.get_y(), 0);
SG_CHECK_EQUAL(b3.gen_base_path(), "e120n00/e123n09");
SG_VERIFY(b3.isValid());
SGBucket defBuck;
SG_VERIFY(!defBuck.isValid());
b3.make_bad();
SG_VERIFY(!b3.isValid());
@@ -87,19 +87,47 @@ void testBasic()
SG_CHECK_EQUAL(atAntiMeridian2.get_chunk_lon(), -180);
SG_CHECK_EQUAL(atAntiMeridian2.get_x(), 0);
// check comparisom operator overload
// check comparison operator overload
SGBucket b4(5.11, 55.1);
SG_VERIFY(b1 == b4); // should be equal
SG_VERIFY(b1 == b1);
SG_VERIFY(b1 != defBuck);
SG_VERIFY(b1 != b2);
// check wrapping/clipping of inputs
// check wrapping/clipping of inputs
SGBucket wrapMeridian(-200.0, 45.0);
SG_CHECK_EQUAL(wrapMeridian.get_chunk_lon(), 160);
SGBucket clipPole(48.9, 91);
SG_CHECK_EQUAL(clipPole.get_chunk_lat(), 89);
// test override of a bucket's geod
auto geod = SGGeod::fromDegFt(-86.678, 36.1248, 599.0);
#ifndef NO_DEPRECATED_API
SGBucket bna_airport;
bna_airport.set_bucket(geod);
#else
SGBucket bna_airport(geod);
#endif
SG_VERIFY(bna_airport.isValid());
SG_CHECK_EQUAL(bna_airport.get_chunk_lon(), -87); // left origin of the 1-degree chunk
SG_CHECK_EQUAL(bna_airport.get_chunk_lat(), 36); // bottom origin of the 1-degree chunk
SG_CHECK_EQUAL(bna_airport.get_x(), 1); // buckets are 0.25 deg wide at the W87 parallel
// we're 0.322 deg from the origin (second bucket)
SG_CHECK_EQUAL(bna_airport.get_y(), 0); // buckets are always 0.125 deg tall
// we're 0.1248 deg from the origin (first bucket)
SG_CHECK_EQUAL(bna_airport.gen_base_path(), "w090n30/w087n36");
SG_CHECK_EQUAL_EP2(bna_airport.get_width_m(), 22479.1, 0.1);
SG_CHECK_EQUAL_EP2(bna_airport.get_height_m(), 13914.9, 0.1);
SG_CHECK_EQUAL(bna_airport.gen_index_str(), "1531777"); // 0x175F81 = b01011101|01111110|000|001
// = 93-180 | 126-90 | 0 | 1
// = -87 | 36 | 0 | 1
// test stream output
cout << "[TEST] BNA Airport: " << bna_airport << endl;
auto center = bna_airport.get_center();
cout << "[TEST] BNA lon: " << center.getLongitudeDeg() << endl;
cout << "[TEST] BNA lat: " << center.getLatitudeDeg() << endl;
}
void testPolar()
@@ -110,17 +138,17 @@ void testPolar()
SG_CHECK_EQUAL(b1.get_chunk_lon(), 0);
SG_CHECK_EQUAL(b1.get_x(), 0);
SG_CHECK_EQUAL(b1.get_y(), 7);
SG_CHECK_EQUAL_EP(b1.get_highest_lat(), 90.0);
SG_CHECK_EQUAL_EP(b1.get_width_m(), 10.0);
SG_CHECK_EQUAL(b2.get_chunk_lat(), 89);
SG_CHECK_EQUAL(b2.get_chunk_lon(), 0);
SG_CHECK_EQUAL(b2.get_x(), 0);
SG_CHECK_EQUAL(b2.get_y(), 7);
SG_CHECK_EQUAL(b1.gen_index(), b2.gen_index());
SGGeod actualNorthPole1 = b1.get_corner(2);
SGGeod actualNorthPole2 = b1.get_corner(3);
SG_CHECK_EQUAL_EP(actualNorthPole1.getLatitudeDeg(), 90.0);
@@ -131,11 +159,11 @@ void testPolar()
SGBucket b3(-2, 89.88);
SGBucket b4(-7, 89.88);
SG_CHECK_EQUAL(b3.gen_index(), b4.gen_index());
// south pole
SGBucket b5(-170, -89.88);
SGBucket b6(-179, -89.88);
SG_CHECK_EQUAL(b5.get_chunk_lat(), -90);
SG_CHECK_EQUAL(b5.get_chunk_lon(), -180);
SG_CHECK_EQUAL(b5.get_x(), 0);
@@ -143,17 +171,16 @@ void testPolar()
SG_CHECK_EQUAL(b5.gen_index(), b6.gen_index());
SG_CHECK_EQUAL_EP(b5.get_highest_lat(), -90.0);
SG_CHECK_EQUAL_EP(b5.get_width_m(), 10.0);
SGGeod actualSouthPole1 = b5.get_corner(0);
SGGeod actualSouthPole2 = b5.get_corner(1);
SG_CHECK_EQUAL_EP(actualSouthPole1.getLatitudeDeg(), -90.0);
SG_CHECK_EQUAL_EP(actualSouthPole1.getLongitudeDeg(), -180);
SG_CHECK_EQUAL_EP(actualSouthPole2.getLatitudeDeg(), -90.0);
SG_CHECK_EQUAL_EP(actualSouthPole2.getLongitudeDeg(), -168);
SGBucket b7(200, 89.88);
SG_CHECK_EQUAL(b7.get_chunk_lon(), -168);
}
// test the tiles just below the pole (between 86 & 89 degrees N/S)
@@ -167,7 +194,7 @@ void testNearPolar()
SGBucket b3(176.1, 88.5);
SG_CHECK_EQUAL(b3.get_chunk_lon(), 176);
SGBucket b4(-178, 88.5);
SG_CHECK_EQUAL(b4.get_chunk_lon(), -180);
}
@@ -181,7 +208,7 @@ void testOffset()
SG_CHECK_EQUAL(b1.get_chunk_lon(), -60);
SG_CHECK_EQUAL(b1.get_x(), 1);
SG_CHECK_EQUAL(b1.get_y(), 7);
// offset vertically
SGBucket b2(b1.sibling(0, 1));
SG_CHECK_EQUAL(b2.get_chunk_lat(), 22);
@@ -190,7 +217,7 @@ void testOffset()
SG_CHECK_EQUAL(b2.get_y(), 0);
SG_CHECK_EQUAL(b2.gen_index(), sgBucketOffset(-59.8, 21.9, 0, 1));
// offset vertically and horizontally. We compute horizontal (x)
// movement at the target latitude, so this should move 0.25 * -3 degrees,
// NOT 0.125 * -3 degrees.
@@ -199,7 +226,7 @@ void testOffset()
SG_CHECK_EQUAL(b3.get_chunk_lon(), -61);
SG_CHECK_EQUAL(b3.get_x(), 1);
SG_CHECK_EQUAL(b3.get_y(), 0);
SG_CHECK_EQUAL(b3.gen_index(), sgBucketOffset(-59.8, 21.9, -3, 1));
}
@@ -210,40 +237,40 @@ void testPolarOffset()
SG_CHECK_EQUAL(b1.get_chunk_lon(), -12);
SG_CHECK_EQUAL(b1.get_x(), 0);
SG_CHECK_EQUAL(b1.get_y(), 3);
// offset horizontally
SGBucket b2(b1.sibling(-2, 0));
SG_CHECK_EQUAL(b2.get_chunk_lat(), -90);
SG_CHECK_EQUAL(b2.get_chunk_lon(), -36);
SG_CHECK_EQUAL(b2.get_x(), 0);
SG_CHECK_EQUAL(b2.get_y(), 3);
SG_CHECK_EQUAL(b2.gen_index(), sgBucketOffset(-11.7, -89.6, -2, 0));
// offset and wrap
// offset and wrap
SGBucket b3(-170, 89.1);
SGBucket b4(b3.sibling(-1, 0));
SG_CHECK_EQUAL(b4.get_chunk_lat(), 89);
SG_CHECK_EQUAL(b4.get_chunk_lon(), 168);
SG_CHECK_EQUAL(b4.get_x(), 0);
SG_CHECK_EQUAL(b4.get_y(), 0);
SG_CHECK_EQUAL(b4.gen_index(), sgBucketOffset(-170, 89.1, -1, 0));
SGBucket b5(177, 87.3);
SGBucket b6(b5.sibling(1, 1));
SG_CHECK_EQUAL(b6.get_chunk_lat(), 87);
SG_CHECK_EQUAL(b6.get_chunk_lon(), -180);
SG_CHECK_EQUAL(b6.get_x(), 0);
SG_CHECK_EQUAL(b6.get_y(), 3);
SG_CHECK_EQUAL(b6.gen_index(), sgBucketOffset(177, 87.3, 1, 1));
// offset vertically towards the pole
SGBucket b7(b1.sibling(0, -5));
SG_VERIFY(!b7.isValid());
SG_VERIFY(!SGBucket(0, 90).sibling(0, 1).isValid());
}
@@ -256,29 +283,80 @@ void testOffsetWrap()
SG_CHECK_EQUAL(b1.get_chunk_lon(), -180);
SG_CHECK_EQUAL(b1.get_x(), 1);
SG_CHECK_EQUAL(b1.get_y(), 6);
SGBucket b2(b1.sibling(-2, 0));
SG_CHECK_EQUAL(b2.get_chunk_lat(), 16);
SG_CHECK_EQUAL(b2.get_chunk_lon(), 179);
SG_CHECK_EQUAL(b2.get_x(), 7);
SG_CHECK_EQUAL(b2.get_y(), 6);
SG_CHECK_EQUAL(b2.gen_index(), sgBucketOffset(-179.8, 16.8, -2, 0));
}
void testSiblings()
{
SGBucket bna_airport(-86.678, 36.1248);
SG_VERIFY(bna_airport.isValid());
// retrieve the sibling two positions north-east of my position
auto sib1 = bna_airport.sibling(2, 2);
SG_CHECK_EQUAL(sib1.get_chunk_lon(), bna_airport.get_chunk_lon());
SG_CHECK_EQUAL(sib1.get_chunk_lat(), bna_airport.get_chunk_lat());
SG_CHECK_EQUAL(sib1.get_x(), 3); // my x-pos (1) + 2 = 3
SG_CHECK_EQUAL(sib1.get_y(), 2); // my y-pos (0) + 2 = 2
SG_CHECK_EQUAL(sib1.gen_base_path(), bna_airport.gen_base_path());
// retrieve the one sibling two positions to the north-east
std::vector<SGBucket> siblings;
bna_airport.siblings(2, 2, siblings);
SG_CHECK_EQUAL(siblings.size(), static_cast<std::vector<SGBucket>::size_type>(1));
siblings.clear();
// retrieve the one sibling at the chunk origin of sib1
sib1.siblings(-2, -2, siblings);
SG_CHECK_EQUAL(siblings.size(), static_cast<std::vector<SGBucket>::size_type>(1));
siblings.clear();
// calculate delta between two buckets
int dx = 0;
int dy = 0;
sgBucketDiff(bna_airport, sib1, &dx, &dy);
SG_CHECK_EQUAL(dx, 2);
SG_CHECK_EQUAL(dy, 2);
// retrieve all siblings between two geodetic locations
auto geod_bna = SGGeod::fromDegFt(-86.678, 36.1248, 599.0);
auto geod_m54 = SGGeod::fromDegFt(-86.317, 36.1908, 122.0);
sgGetBuckets(geod_bna, geod_m54, siblings);
SG_CHECK_EQUAL(siblings.size(), static_cast<std::vector<SGBucket>::size_type>(4));
siblings.clear();
// edge cases
// ensure you cannot retrieve the sibling of an invalid bucket
SGBucket bad;
auto bad_sib = bad.sibling(1, 1);
SG_CHECK_EQUAL(bad_sib.get_chunk_lon(), -1000);
SG_CHECK_EQUAL(bad.siblings(2, 2, siblings), 0);
// if we drop below the 22nd parallel, the bucket widths are half the size
// expect this to retrieve two buckets
bna_airport.siblings(0, -160, siblings);
SG_CHECK_EQUAL(siblings.size(), static_cast<std::vector<SGBucket>::size_type>(2));
siblings.clear();
}
int main(int argc, char* argv[])
{
testBucketSpans();
testBasic();
testPolar();
testNearPolar();
testOffset();
testOffsetWrap();
testPolarOffset();
testSiblings();
cout << "all tests passed OK" << endl;
return 0; // passed
}

View File

@@ -9,10 +9,6 @@ set(HEADERS
CanvasText.hxx
)
set(DETAIL_HEADERS
detail/add_segment_variadic.hxx
)
set(SOURCES
CanvasElement.cxx
CanvasGroup.cxx
@@ -23,7 +19,6 @@ set(SOURCES
)
simgear_scene_component(canvas-elements canvas/elements "${SOURCES}" "${HEADERS}")
simgear_component(canvas-elements/detail canvas/elements/detail "" "${DETAIL_HEADERS}")
add_boost_test(canvas_element
SOURCES canvas_element_test.cpp

View File

@@ -740,52 +740,63 @@ namespace canvas
return _path->getTransformedBounds(m);
}
//----------------------------------------------------------------------------
Path& Path::addSegment(uint8_t cmd, std::initializer_list<float> coords)
{
_node->addChild("cmd")->setIntValue(cmd);
for(float coord: coords)
_node->addChild("coord")->setFloatValue(coord);
return *this;
}
//----------------------------------------------------------------------------
Path& Path::moveTo(float x_abs, float y_abs)
{
return addSegment(VG_MOVE_TO_ABS, x_abs, y_abs);
return addSegment(VG_MOVE_TO_ABS, {x_abs, y_abs});
}
//----------------------------------------------------------------------------
Path& Path::move(float x_rel, float y_rel)
{
return addSegment(VG_MOVE_TO_REL, x_rel, y_rel);
return addSegment(VG_MOVE_TO_REL, {x_rel, y_rel});
}
//----------------------------------------------------------------------------
Path& Path::lineTo(float x_abs, float y_abs)
{
return addSegment(VG_LINE_TO_ABS, x_abs, y_abs);
return addSegment(VG_LINE_TO_ABS, {x_abs, y_abs});
}
//----------------------------------------------------------------------------
Path& Path::line(float x_rel, float y_rel)
{
return addSegment(VG_LINE_TO_REL, x_rel, y_rel);
return addSegment(VG_LINE_TO_REL, {x_rel, y_rel});
}
//----------------------------------------------------------------------------
Path& Path::horizTo(float x_abs)
{
return addSegment(VG_HLINE_TO_ABS, x_abs);
return addSegment(VG_HLINE_TO_ABS, {x_abs});
}
//----------------------------------------------------------------------------
Path& Path::horiz(float x_rel)
{
return addSegment(VG_HLINE_TO_REL, x_rel);
return addSegment(VG_HLINE_TO_REL, {x_rel});
}
//----------------------------------------------------------------------------
Path& Path::vertTo(float y_abs)
{
return addSegment(VG_VLINE_TO_ABS, y_abs);
return addSegment(VG_VLINE_TO_ABS, {y_abs});
}
//----------------------------------------------------------------------------
Path& Path::vert(float y_rel)
{
return addSegment(VG_VLINE_TO_REL, y_rel);
return addSegment(VG_VLINE_TO_REL, {y_rel});
}
//----------------------------------------------------------------------------

View File

@@ -20,8 +20,8 @@
#define CANVAS_PATH_HXX_
#include "CanvasElement.hxx"
#include <boost/preprocessor/iteration/iterate.hpp>
#include <simgear/math/SGRect.hxx>
#include <initializer_list>
namespace simgear
{
@@ -44,10 +44,8 @@ namespace canvas
virtual osg::BoundingBox getTransformedBounds(const osg::Matrix& m) const;
#define BOOST_PP_ITERATION_LIMITS (0, 6)
#define BOOST_PP_FILENAME_1 \
<simgear/canvas/elements/detail/add_segment_variadic.hxx>
#include BOOST_PP_ITERATE()
/** Add a segment with the given command and coordinates */
Path& addSegment(uint8_t cmd, std::initializer_list<float> coords = {});
/** Move path cursor */
Path& moveTo(float x_abs, float y_abs);

View File

@@ -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

View File

@@ -189,10 +189,10 @@ namespace canvas
if( hfw.empty() )
return -1;
naContext c = naNewContext();
try
{
return hfw(nasal::to_nasal(c, const_cast<NasalWidget*>(this)), w);
nasal::Context ctx;
return hfw(ctx.to_me(const_cast<NasalWidget*>(this)), w);
}
catch( std::exception const& ex )
{
@@ -202,7 +202,6 @@ namespace canvas
"NasalWidget.heightForWidth: callback error: '" << ex.what() << "'"
);
}
naFreeContext(c);
return -1;
}
@@ -262,8 +261,8 @@ namespace canvas
try
{
nasal::Context c;
_set_geometry(nasal::to_nasal(c, this), rect);
nasal::Context ctx;
_set_geometry(ctx.to_me(this), rect);
_flags &= ~LAYOUT_DIRTY;
}
catch( std::exception const& ex )

View File

@@ -21,4 +21,9 @@ else()
endif()
add_test(metar ${EXECUTABLE_OUTPUT_PATH}/test_metar)
add_executable(test_precipitation test_precipitation.cxx)
target_link_libraries(test_precipitation ${TEST_LIBS})
add_test(precipitation ${EXECUTABLE_OUTPUT_PATH}/test_precipitation)
endif(ENABLE_TESTS)

View File

@@ -7,7 +7,7 @@
*
* @brief Precipitation effects to draw rain and snow.
*
* @par Licences
* @par License
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
@@ -25,7 +25,6 @@
*/
#include "precipitation.hxx"
//#include "visual_enviro.hxx"
#include <simgear/constants.h>
#include <osg/ClipNode>
@@ -65,7 +64,7 @@ bool SGPrecipitation::getEnabled() const
*/
osg::Group* SGPrecipitation::build(void)
{
osg::Group* group = new osg::Group;
osg::ref_ptr<osg::Group> group = new osg::Group;
_precipitationEffect->snow(0);
_precipitationEffect->rain(0);
@@ -73,8 +72,9 @@ osg::Group* SGPrecipitation::build(void)
if (_clip_distance!=0.0)
{
osg::ref_ptr<osg::ClipNode> clipNode = new osg::ClipNode;
clipNode->addClipPlane( new osg::ClipPlane( 0 ) );
clipNode->getClipPlane(0)->setClipPlane( 0.0, 0.0, -1.0, -_clip_distance );
osg::ref_ptr<osg::ClipPlane> clipPlane = new osg::ClipPlane(0);
clipNode->addClipPlane(clipPlane.get());
clipNode->getClipPlane(0)->setClipPlane(0.0, 0.0, -1.0, -_clip_distance);
clipNode->setReferenceFrame(osg::ClipNode::ABSOLUTE_RF);
clipNode->addChild(_precipitationEffect.get());
@@ -87,7 +87,7 @@ osg::Group* SGPrecipitation::build(void)
group->setNodeMask( ~(simgear::CASTSHADOW_BIT | simgear::MODELLIGHT_BIT) );
return group;
return group.release();
}
@@ -140,8 +140,8 @@ void SGPrecipitation::setRainDropletSize(float size)
/**
* @brief Define the illumination multiplier
*
* This function permits you to define and change the rain droplet size
* which is used if external droplet size control is enabled
* This function permits you to define and change the brightness
* of the precipitation.
*/
void SGPrecipitation::setIllumination(float illumination)
@@ -163,10 +163,9 @@ void SGPrecipitation::setSnowFlakeSize(float size)
/**
* @brief Define the rain droplet size
* @brief Define the clip plane distance
*
* This function permits you to define and change the rain droplet size
* which is used if external droplet size control is enabled
* This function permits you to define and change the clip plane distance.
*/
void SGPrecipitation::setClipDistance(float distance)
@@ -224,7 +223,7 @@ void SGPrecipitation::setWindProperty(double heading, double speed)
* Be careful, if snow and rain intensity are greater than '0', snow effect
* will be first.
*
* The settings come from the osgParticule/PrecipitationEffect.cpp exemple.
* The settings come from the osgParticle/PrecipitationEffect.cpp example.
*/
bool SGPrecipitation::update(void)
{

View File

@@ -34,7 +34,7 @@
class SGPrecipitation : public osg::Referenced
{
private:
protected:
bool _freeze;
bool _enabled;
bool _droplet_external;
@@ -66,7 +66,7 @@ public:
void setIllumination(float);
void setClipDistance(float);
void setEnabled( bool );
void setEnabled(bool);
bool getEnabled() const;
};

View File

@@ -0,0 +1,239 @@
/**************************************************************************
* test_precipitation.cxx -- unit-tests for SGPrecipitation class
*
* Copyright (C) 2017 Scott Giese (xDraconian) - <scttgs0@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $Id$
**************************************************************************/
#include <cmath>
#include <memory>
#include <osg/Group>
#include <simgear/constants.h>
#include <simgear/misc/test_macros.hxx>
#include "precipitation.hxx"
using std::cout;
using std::cerr;
using std::endl;
class SGPrecipitationTestFixture : public SGPrecipitation
{
public:
osg::ref_ptr<osg::Group> _group;
void test_configuration()
{
_group = build();
SG_VERIFY(getEnabled());
SG_VERIFY(_precipitationEffect);
SG_CHECK_EQUAL_EP(_rain_intensity, 0.0f);
SG_CHECK_EQUAL_EP(_snow_intensity, 0.0f);
SG_VERIFY(!_freeze);
}
void test_rain()
{
int count = 500;
do {
if (--count == 0) {
cerr << "error: method setRainIntensity took too long.";
exit(EXIT_FAILURE);
}
float saveRainIntensity = _rain_intensity;
setRainIntensity(0.4f);
update();
SG_CHECK_GE(_rain_intensity, saveRainIntensity);
} while (std::fabs(_rain_intensity - 0.4f) > 0.00001f);
SG_CHECK_EQUAL_EP2(_rain_intensity, 0.4f, 0.00001f);
}
void test_rain_external()
{
int count = 500;
do {
if (--count == 0) {
cerr << "error: method setRainIntensity-external took too long.";
exit(EXIT_FAILURE);
}
float saveRainIntensity = _rain_intensity;
setRainIntensity(0.25f);
update();
SG_CHECK_LE(_rain_intensity, saveRainIntensity);
} while (std::fabs(_rain_intensity - 0.25f) > 0.00001f);
// call once more to ensure we have intensity precisely set
setRainIntensity(0.25f);
update();
SG_CHECK_EQUAL_EP2(_rain_intensity, 0.25f, 0.00001f);
}
void test_freeze()
{
float saveParticleSize = _precipitationEffect->getParticleSize();
float saveParticleSpeed = std::fabs(_precipitationEffect->getParticleSpeed());
// change rain to snow
// expect particle size to increase
// expect particle speed to decrease
setFreezing(true);
update();
SG_CHECK_GT(_precipitationEffect->getParticleSize(), saveParticleSize);
SG_CHECK_LT(std::fabs(_precipitationEffect->getParticleSpeed()), saveParticleSpeed);
}
void test_snow()
{
int count = 500;
do {
if (--count == 0) {
cerr << "error: method setSnowIntensity took too long.";
exit(EXIT_FAILURE);
}
float saveSnowIntensity = _snow_intensity;
// not a typo - when freezing is enabled, snow intensity is keep in sync with rain intensity
setRainIntensity(0.3f);
update();
SG_CHECK_LE(_snow_intensity, saveSnowIntensity);
} while (std::fabs(_snow_intensity - 0.3f) > 0.00001f);
SG_CHECK_EQUAL_EP2(_snow_intensity, 0.3f, 0.00001f);
}
void test_snow_external()
{
setRainDropletSize(0.025f);
setSnowFlakeSize(0.04f);
setDropletExternal(true);
int count = 600;
do {
if (--count == 0) {
cerr << "error: method setSnowIntensity-external took too long.";
exit(EXIT_FAILURE);
}
float saveSnowIntensity = _snow_intensity;
setSnowIntensity(0.55f);
update();
SG_CHECK_GE(_snow_intensity, saveSnowIntensity);
} while (std::fabs(_snow_intensity - 0.55f) > 0.00001f);
// call once more to ensure we have intensity precisely set
setSnowIntensity(0.55f);
update();
SG_CHECK_EQUAL_EP2(_snow_intensity, 0.55f, 0.00001f);
}
void test_unfreeze()
{
float saveParticleSize = _precipitationEffect->getParticleSize();
float saveParticleSpeed = std::fabs(_precipitationEffect->getParticleSpeed());
// change snow to rain
// expect particle size to decrease
// expect particle speed to increase
setFreezing(false);
update();
SG_CHECK_LT(_precipitationEffect->getParticleSize(), saveParticleSize);
SG_CHECK_GT(std::fabs(_precipitationEffect->getParticleSpeed()), saveParticleSpeed);
}
void test_no_precipitation()
{
setEnabled(false);
SG_VERIFY(!getEnabled());
update();
// intensity drops to zero, so we should see this reflected in the particles
SG_CHECK_EQUAL_EP(_precipitationEffect->getParticleSize(), 0.01f);
SG_CHECK_EQUAL_EP(_precipitationEffect->getParticleSpeed(), -2.0f);
setEnabled(true);
}
void test_illumination()
{
setIllumination(0.87f);
SG_CHECK_EQUAL_EP(_illumination, 0.87f);
}
void test_clipping()
{
setClipDistance(6.5);
SG_CHECK_EQUAL_EP(_clip_distance, 6.5f);
}
void test_wind()
{
setWindProperty(87.0f, 0.7f);
auto vec = _wind_vec;
SG_CHECK_EQUAL_EP2(vec[0], 0.011166f, 0.00001f);
SG_CHECK_EQUAL_EP2(vec[1], -0.213068f, 0.00001f);
SG_CHECK_EQUAL_EP2(vec[2], 0.0f, 0.00001f);
}
};
int main(int argc, char* argv[])
{
auto fixture = std::unique_ptr<SGPrecipitationTestFixture>(new SGPrecipitationTestFixture);
fixture->test_configuration();
fixture->test_rain();
fixture->test_freeze();
fixture->test_snow();
fixture->test_unfreeze();
fixture->test_no_precipitation();
fixture->test_snow_external();
fixture->test_rain_external();
fixture->test_illumination();
fixture->test_clipping();
fixture->test_wind();
fixture->test_no_precipitation();
cout << "all tests passed OK" << endl;
return EXIT_SUCCESS;
}

View File

@@ -32,10 +32,12 @@
#include <simgear_config.h>
#include "sg_netChannel.hxx"
#include <algorithm>
#include <memory>
#include <cassert>
#include <cerrno>
#include <cstring>
#include <errno.h>
#include <simgear/debug/logstream.hxx>
@@ -258,18 +260,10 @@ NetChannelPoller::removeChannel(NetChannel* channel)
assert(channel);
assert(channel->poller == this);
channel->poller = NULL;
// portability: MSVC throws assertion failure when empty
if (channels.empty()) {
return;
}
ChannelList::iterator it = channels.begin();
for (; it != channels.end(); ++it) {
if (*it == channel) {
channels.erase(it);
return;
}
auto it = std::find(channels.begin(), channels.end(), channel);
if (it != channels.end()) {
channels.erase(it);
}
}

View File

@@ -183,15 +183,6 @@ public:
int requestContentLength;
};
class EraseIfClosed
{
public:
bool operator()(simgear::NetChannel* chan) const
{
return chan->isClosed();
}
};
template <class T>
class TestServer : public NetChannel
{
@@ -202,7 +193,6 @@ public:
{
Socket::initSockets();
open();
bind(NULL, 2000); // localhost, any port
listen(16);
@@ -212,6 +202,7 @@ public:
virtual ~TestServer()
{
_poller.removeChannel(this);
}
virtual bool writable (void) { return false ; }
@@ -231,15 +222,16 @@ public:
{
_poller.poll();
typename std::vector<T*>::iterator it;
it = std::remove_if(_channels.begin(), _channels.end(), EraseIfClosed());
for (typename std::vector<T*>::iterator it2 = it; it2 != _channels.end(); ++it2) {
delete *it2;
}
auto it = std::remove_if(_channels.begin(), _channels.end(), [&](T* channel) {
if (channel->isClosed()) {
_poller.removeChannel(channel);
delete channel;
return true;
}
return false;
});
_channels.erase(it, _channels.end());
}
int connectCount()

View File

@@ -1,10 +1,13 @@
include (SimGearComponent)
set(HEADERS
cppbind_fwd.hxx
Ghost.hxx
NasalCallContext.hxx
NasalContext.hxx
NasalHash.hxx
NasalMe.hxx
NasalMethodHolder.hxx
NasalObject.hxx
NasalObjectHolder.hxx
NasalString.hxx
@@ -13,9 +16,7 @@ set(HEADERS
)
set(DETAIL_HEADERS
detail/from_nasal_function_templates.hxx
detail/from_nasal_helper.hxx
detail/functor_templates.hxx
detail/nasal_traits.hxx
detail/to_nasal_helper.hxx
)
@@ -51,4 +52,4 @@ add_boost_test(nasal_gc_test
add_boost_test(nasal_num
SOURCES test/nasal_num_test.cxx
LIBRARIES ${TEST_LIBS}
)
)

View File

@@ -24,17 +24,16 @@
#include "NasalObjectHolder.hxx"
#include <simgear/debug/logstream.hxx>
#include <simgear/std/integer_sequence.hxx>
#include <simgear/std/type_traits.hxx>
#include <simgear/structure/SGWeakReferenced.hxx>
#include <simgear/structure/SGWeakPtr.hxx>
#include <boost/bind.hpp>
#include <boost/call_traits.hpp>
#include <boost/function.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/mpl/has_xxx.hpp>
#include <boost/preprocessor/iteration/iterate.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility/enable_if.hpp>
#include <map>
@@ -62,10 +61,7 @@ namespace osg
}
template<class T>
inline typename boost::enable_if<
boost::is_pointer<T>,
T
>::type
inline std::enable_if_t<std::is_pointer<T>::value, T>
get_pointer(T ptr)
{
return ptr;
@@ -101,8 +97,8 @@ namespace nasal
class GhostMetadata
{
public:
typedef void(*Deleter)(void*);
typedef std::vector<std::pair<Deleter, void*> > DestroyList;
using Deleter = void(*)(void*);
using DestroyList = std::vector<std::pair<Deleter, void*>>;
static DestroyList _destroy_list;
@@ -154,19 +150,6 @@ namespace nasal
};
BOOST_MPL_HAS_XXX_TRAIT_DEF(element_type)
template<class T>
struct reduced_type
{
typedef typename boost::remove_cv<
typename boost::remove_reference<T>::type
>::type type;
};
template<class T1, class T2>
struct reduced_is_same:
public boost::is_same<typename reduced_type<T1>::type, T2>
{};
}
/** @brief Destroy all ghost queued for deletion.
@@ -178,8 +161,8 @@ namespace nasal
*/
void ghostProcessDestroyList();
typedef SGSharedPtr<internal::MethodHolder> MethodHolderPtr;
typedef SGWeakPtr<internal::MethodHolder> MethodHolderWeakPtr;
using MethodHolderPtr = SGSharedPtr<internal::MethodHolder>;
using MethodHolderWeakPtr = SGWeakPtr<internal::MethodHolder>;
// Dummy template to create shorter and easy to understand compile errors if
// trying to wrap the wrong type as a Ghost.
@@ -187,9 +170,10 @@ namespace nasal
class Ghost
{
public:
BOOST_STATIC_ASSERT(("Ghost can only wrap shared pointer!"
&& is_strong_ref<T>::value
));
static_assert(
is_strong_ref<T>::value,
"Ghost can only wrap shared pointer!"
);
static Ghost& init(const std::string& name);
static bool isInit();
@@ -209,7 +193,7 @@ namespace nasal
* int myMember();
* void doSomethingElse(const nasal::CallContext& ctx);
* }
* typedef boost::shared_ptr<MyClass> MyClassPtr;
* using MyClassPtr = boost::shared_ptr<MyClass>;
*
* std::string myOtherFreeMember(int num);
*
@@ -235,29 +219,25 @@ namespace nasal
* @endcode
*/
template<class T>
class Ghost<T, typename boost::enable_if<is_strong_ref<T> >::type>:
class Ghost<T, std::enable_if_t<is_strong_ref<T>::value>>:
public internal::GhostMetadata
{
// Shared pointer required for Ghost (no weak pointer!)
BOOST_STATIC_ASSERT((is_strong_ref<T>::value));
public:
typedef typename T::element_type raw_type;
typedef typename shared_ptr_traits<T>::strong_ref strong_ref;
typedef typename shared_ptr_traits<T>::weak_ref weak_ref;
typedef naRef (raw_type::*member_func_t)(const CallContext&);
typedef naRef (*free_func_t)(raw_type&, const CallContext&);
typedef boost::function<naRef(raw_type&, naContext)> getter_t;
typedef boost::function<void( raw_type&, naContext, naRef)> setter_t;
typedef boost::function<naRef(raw_type&, const CallContext&)> method_t;
typedef boost::function<bool( raw_type&,
naContext,
const std::string&,
naRef& )> fallback_getter_t;
typedef boost::function<bool( raw_type&,
naContext,
const std::string&,
naRef )> fallback_setter_t;
using raw_type = typename T::element_type;
using strong_ref = typename shared_ptr_traits<T>::strong_ref;
using weak_ref = typename shared_ptr_traits<T>::weak_ref;
using member_func_t = naRef (raw_type::*)(const CallContext&);
using free_func_t = naRef (*)(raw_type&, const CallContext&);
using getter_t = boost::function<naRef(raw_type&, naContext)>;
using setter_t = boost::function<void( raw_type&, naContext, naRef)>;
using method_t = boost::function<naRef(raw_type&, const CallContext&)>;
using fallback_getter_t =
boost::function<bool(raw_type&, naContext, const std::string&, naRef&)>;
using fallback_setter_t =
boost::function<bool(raw_type&, naContext, const std::string&, naRef)>;
template<class Ret, class... Args>
using method_variadic_t = boost::function<Ret (raw_type&, Args...)>;
class MethodHolder:
public internal::MethodHolder
@@ -269,8 +249,8 @@ namespace nasal
protected:
typedef SGSharedPtr<MethodHolder> SharedPtr;
typedef SGWeakPtr<MethodHolder> WeakPtr;
using SharedPtr = SGSharedPtr<MethodHolder>;
using WeakPtr = SGWeakPtr<MethodHolder>;
method_t _method;
@@ -369,7 +349,7 @@ namespace nasal
MethodHolderPtr func;
};
typedef std::map<std::string, member_t> MemberMap;
using MemberMap = std::map<std::string, member_t>;
/**
* Register a new ghost type.
@@ -406,19 +386,18 @@ namespace nasal
* @endcode
*/
template<class BaseGhost>
typename boost::enable_if
<
boost::is_base_of<GhostMetadata, BaseGhost>,
Ghost
>::type&
std::enable_if_t<
std::is_base_of<GhostMetadata, BaseGhost>::value,
Ghost&
>
bases()
{
BOOST_STATIC_ASSERT
((
boost::is_base_of<typename BaseGhost::raw_type, raw_type>::value
));
static_assert(
std::is_base_of<typename BaseGhost::raw_type, raw_type>::value,
"Not a base class!"
);
typedef typename BaseGhost::strong_ref base_ref;
using base_ref = typename BaseGhost::strong_ref;
BaseGhost* base = BaseGhost::getSingletonPtr();
base->addDerived(
@@ -429,17 +408,14 @@ namespace nasal
// Replace any getter that is not available in the current class.
// TODO check if this is the correct behavior of function overriding
for( typename BaseGhost::MemberMap::const_iterator member =
base->_members.begin();
member != base->_members.end();
++member )
for(auto const& base_member: base->_members)
{
if( _members.find(member->first) == _members.end() )
_members[member->first] = member_t
if( _members.find(base_member.first) == _members.end() )
_members[base_member.first] = member_t
(
member->second.getter,
member->second.setter,
member->second.func
base_member.second.getter,
base_member.second.setter,
base_member.second.func
);
}
@@ -464,17 +440,16 @@ namespace nasal
* @endcode
*/
template<class Base>
typename boost::disable_if
<
boost::is_base_of<GhostMetadata, Base>,
Ghost
>::type&
std::enable_if_t<
!std::is_base_of<GhostMetadata, Base>::value,
Ghost&
>
bases()
{
BOOST_STATIC_ASSERT
((
boost::is_base_of<typename Ghost<Base>::raw_type, raw_type>::value
));
static_assert(
std::is_base_of<typename Ghost<Base>::raw_type, raw_type>::value,
"Not a base class!"
);
return bases< Ghost<Base> >();
}
@@ -770,7 +745,7 @@ namespace nasal
/**
* Register anything that accepts an object instance and a
* nasal::CallContext whith automatic conversion of the return type to
* nasal::CallContext with automatic conversion of the return type to
* Nasal.
*
* @code{cpp}
@@ -791,14 +766,73 @@ namespace nasal
return method(name, boost::bind(method_invoker<Ret>, func, _1, _2));
}
// Build dependency for CMake, gcc, etc.
#define SG_DONT_DO_ANYTHING
# include <simgear/nasal/cppbind/detail/functor_templates.hxx>
#undef SG_DONT_DO_ANYTHING
/**
* Bind any callable entity accepting an instance of raw_type and an
* arbitrary number of arguments as method.
*
* The std::index_sequence specifies the order of the arguments
*/
template<class Ret, class... Args, std::size_t... Indices>
Ghost& method( const std::string& name,
const method_variadic_t<Ret, Args...>& func,
std::index_sequence<Indices...> )
{
return method<Ret>
(
name,
typename boost::function<Ret (raw_type&, const CallContext&)>
( boost::bind(
func,
_1,
boost::bind(&Ghost::arg_from_nasal<Args>, _2, Indices)...
))
);
}
#define BOOST_PP_ITERATION_LIMITS (0, 9)
#define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/functor_templates.hxx>
#include BOOST_PP_ITERATE()
template<class Ret, class... Args>
Ghost& method( const std::string& name,
const method_variadic_t<Ret, Args...>& func )
{
return method(name, func, std::index_sequence_for<Args...>{});
}
/**\
* Bind a member function with an arbitrary number of arguments as method.
*/
template<class Ret, class... Args>
Ghost& method( const std::string& name,
Ret (raw_type::*fn)(Args...) )
{
return method(name, method_variadic_t<Ret, Args...>(fn));
}
template<class Ret, class... Args>
Ghost& method( const std::string& name,
Ret (raw_type::*fn)(Args...) const )
{
return method(name, method_variadic_t<Ret, Args...>(fn));
}
/**
* Bind free function accepting an instance of raw_type and an arbitrary
* number of arguments as method.
*/
template<class Ret, class Type, class... Args>
Ghost& method
(
const std::string& name,
Ret (*fn)(Type, Args ... args)
)
{
static_assert(
std::is_convertible<raw_type&, Type>::value,
//|| std::is_convertible<raw_type*, Type>::value
// TODO check how to do it with pointer...
"First parameter can not be converted from the Ghost raw_type!"
);
return method(name, method_variadic_t<Ret, Args...>(fn));
}
/**
* Create a shared pointer on the heap to handle the reference counting
@@ -806,11 +840,11 @@ namespace nasal
*/
template<class RefType>
static
typename boost::enable_if_c<
boost::is_same<RefType, strong_ref>::value
|| boost::is_same<RefType, weak_ref>::value,
std::enable_if_t<
std::is_same<RefType, strong_ref>::value
|| std::is_same<RefType, weak_ref>::value,
naRef
>::type
>
makeGhost(naContext c, RefType const& ref_ptr)
{
strong_ref ref(ref_ptr);
@@ -848,10 +882,9 @@ namespace nasal
}
// otherwise try the derived classes
for( typename DerivedList::reverse_iterator
derived = getSingletonPtr()->_derived_types.rbegin();
derived != getSingletonPtr()->_derived_types.rend();
++derived )
for( auto derived = getSingletonPtr()->_derived_types.rbegin();
derived != getSingletonPtr()->_derived_types.rend();
++derived )
{
strong_ref ref = (derived->from_nasal)(c, me);
@@ -865,13 +898,10 @@ namespace nasal
if( !naIsVector(na_parents) )
return strong_ref();
typedef std::vector<naRef> naRefs;
naRefs parents = from_nasal<naRefs>(c, na_parents);
for( naRefs::const_iterator parent = parents.begin();
parent != parents.end();
++parent )
auto parents = from_nasal<std::vector<naRef>>(c, na_parents);
for(auto parent: parents)
{
strong_ref ref = fromNasal(c, *parent);
strong_ref ref = fromNasal(c, parent);
if( get_pointer(ref) )
return ref;
}
@@ -923,8 +953,9 @@ namespace nasal
static naGhostType _ghost_type_strong, //!< Stored as shared pointer
_ghost_type_weak; //!< Stored as weak shared pointer
typedef naRef (*to_nasal_t)(naContext, const strong_ref&, bool);
typedef strong_ref (*from_nasal_t)(naContext, naRef);
using to_nasal_t = naRef (*)(naContext, const strong_ref&, bool);
using from_nasal_t = strong_ref (*)(naContext, naRef);
struct DerivedInfo
{
to_nasal_t to_nasal;
@@ -937,7 +968,7 @@ namespace nasal
{}
};
typedef std::vector<DerivedInfo> DerivedList;
using DerivedList = std::vector<DerivedInfo>;
DerivedList _derived_types;
static bool isInstance(naGhostType* ghost_type, bool& is_weak)
@@ -951,13 +982,10 @@ namespace nasal
template<class RefPtr, bool is_weak>
static
typename boost::enable_if_c<
!is_weak,
RefPtr
>::type
std::enable_if_t<!is_weak, RefPtr>
getPtr(void* ptr)
{
typedef shared_ptr_storage<strong_ref> storage_type;
using storage_type = shared_ptr_storage<strong_ref>;
if( ptr )
return storage_type::template get<RefPtr>(
static_cast<typename storage_type::storage_type*>(ptr)
@@ -968,13 +996,13 @@ namespace nasal
template<class RefPtr, bool is_weak>
static
typename boost::enable_if_c<
std::enable_if_t<
is_weak && supports_weak_ref<T>::value,
RefPtr
>::type
>
getPtr(void* ptr)
{
typedef shared_ptr_storage<weak_ref> storage_type;
using storage_type = shared_ptr_storage<weak_ref>;
if( ptr )
return storage_type::template get<RefPtr>(
static_cast<typename storage_type::storage_type*>(ptr)
@@ -985,10 +1013,10 @@ namespace nasal
template<class RefPtr, bool is_weak>
static
typename boost::enable_if_c<
std::enable_if_t<
is_weak && !supports_weak_ref<T>::value,
RefPtr
>::type
>
getPtr(void* ptr)
{
return RefPtr();
@@ -1004,10 +1032,10 @@ namespace nasal
template<class BaseGhost>
static
typename boost::enable_if
< boost::is_polymorphic<typename BaseGhost::raw_type>,
naRef
>::type
std::enable_if_t<
std::is_polymorphic<typename BaseGhost::raw_type>::value,
naRef
>
toNasal( naContext c,
const typename BaseGhost::strong_ref& base_ref,
bool strong )
@@ -1016,10 +1044,10 @@ namespace nasal
// Check first if passed pointer can by converted to instance of class
// this ghost wraps.
if( !boost::is_same
< typename BaseGhost::raw_type,
typename Ghost::raw_type
>::value
if( !std::is_same<
typename BaseGhost::raw_type,
typename Ghost::raw_type
>::value
&& dynamic_cast<const typename Ghost::raw_type*>(ptr) != ptr )
return naNil();
@@ -1038,10 +1066,9 @@ namespace nasal
static_pointer_cast<typename Ghost::raw_type>(base_ref);
// Now check if we can further downcast to one of our derived classes.
for( typename DerivedList::reverse_iterator
derived = getSingletonPtr()->_derived_types.rbegin();
derived != getSingletonPtr()->_derived_types.rend();
++derived )
for( auto derived = getSingletonPtr()->_derived_types.rbegin();
derived != getSingletonPtr()->_derived_types.rend();
++derived )
{
naRef ghost = (derived->to_nasal)(c, ref, strong);
@@ -1058,13 +1085,13 @@ namespace nasal
template<class BaseGhost>
static
typename boost::disable_if
< boost::is_polymorphic<typename BaseGhost::raw_type>,
naRef
>::type
toNasal( naContext c,
const typename BaseGhost::strong_ref& ref,
bool strong )
std::enable_if_t<
!std::is_polymorphic<typename BaseGhost::raw_type>::value,
naRef
>
toNasal( naContext c,
const typename BaseGhost::strong_ref& ref,
bool strong )
{
// For non polymorphic classes there is no possibility to get the actual
// dynamic type, therefore we can only use its static type.
@@ -1087,7 +1114,7 @@ namespace nasal
template<class Ret>
getter_t to_getter(Ret (raw_type::*getter)() const)
{
typedef typename boost::call_traits<Ret>::param_type param_type;
using param_type = typename boost::call_traits<Ret>::param_type;
naRef(*to_nasal_)(naContext, param_type) = &to_nasal;
// Getter signature: naRef(raw_type&, naContext)
@@ -1140,7 +1167,7 @@ namespace nasal
*/
template<class Ret>
static
typename boost::disable_if<boost::is_void<Ret>, naRef>::type
std::enable_if_t<!std::is_void<Ret>::value, naRef>
method_invoker
(
const boost::function<Ret (raw_type&, const CallContext&)>& func,
@@ -1148,7 +1175,7 @@ namespace nasal
const CallContext& ctx
)
{
return (*to_nasal_ptr<Ret>::get())(ctx.c, func(obj, ctx));
return (*to_nasal_ptr<Ret>::get())(ctx.c_ctx(), func(obj, ctx));
};
/**
@@ -1156,7 +1183,7 @@ namespace nasal
*/
template<class Ret>
static
typename boost::enable_if<boost::is_void<Ret>, naRef>::type
std::enable_if_t<std::is_void<Ret>::value, naRef>
method_invoker
(
const boost::function<Ret (raw_type&, const CallContext&)>& func,
@@ -1174,10 +1201,10 @@ namespace nasal
*/
template<class Arg>
static
typename boost::disable_if<
internal::reduced_is_same<Arg, CallContext>,
std::enable_if_t<
!std::is_same<std::remove_cvref_t<Arg>, CallContext>::value,
typename from_nasal_ptr<Arg>::return_type
>::type
>
arg_from_nasal(const CallContext& ctx, size_t index)
{
return ctx.requireArg<Arg>(index);
@@ -1188,19 +1215,21 @@ namespace nasal
*/
template<class Arg>
static
typename boost::enable_if<
internal::reduced_is_same<Arg, CallContext>,
std::enable_if_t<
std::is_same<std::remove_cvref_t<Arg>, CallContext>::value,
typename from_nasal_ptr<Arg>::return_type
>::type
>
arg_from_nasal(const CallContext& ctx, size_t)
{
// Either const CallContext& or CallContext, non-const reference
// does not make sense.
BOOST_STATIC_ASSERT( (!boost::is_same<Arg, CallContext&>::value) );
static_assert(
!boost::is_same<Arg, CallContext&>::value,
"Only const reference and value make sense!");
return ctx;
};
typedef std::unique_ptr<Ghost> GhostPtr;
using GhostPtr = std::unique_ptr<Ghost>;
MemberMap _members;
fallback_getter_t _fallback_getter;
fallback_setter_t _fallback_setter;
@@ -1240,13 +1269,10 @@ namespace nasal
template<bool is_weak>
static
typename boost::enable_if_c<
!is_weak,
naRef
>::type
std::enable_if_t<!is_weak, naRef>
create(naContext c, const strong_ref& ref_ptr)
{
typedef shared_ptr_storage<strong_ref> storage_type;
using storage_type = shared_ptr_storage<strong_ref>;
return naNewGhost2( c,
&Ghost::_ghost_type_strong,
storage_type::ref(ref_ptr) );
@@ -1254,13 +1280,13 @@ namespace nasal
template<bool is_weak>
static
typename boost::enable_if_c<
std::enable_if_t<
is_weak && supports_weak_ref<T>::value,
naRef
>::type
>
create(naContext c, const strong_ref& ref_ptr)
{
typedef shared_ptr_storage<weak_ref> storage_type;
using storage_type = shared_ptr_storage<weak_ref>;
return naNewGhost2( c,
&Ghost::_ghost_type_weak,
storage_type::ref(ref_ptr) );
@@ -1268,10 +1294,10 @@ namespace nasal
template<bool is_weak>
static
typename boost::enable_if_c<
std::enable_if_t<
is_weak && !supports_weak_ref<T>::value,
naRef
>::type
>
create(naContext, const strong_ref&)
{
return naNil();
@@ -1280,7 +1306,7 @@ namespace nasal
template<class Type>
static void destroy(void *ptr)
{
typedef shared_ptr_storage<Type> storage_type;
using storage_type = shared_ptr_storage<Type>;
storage_type::unref(
static_cast<typename storage_type::storage_type*>(ptr)
);
@@ -1322,9 +1348,7 @@ namespace nasal
// return "";
// }
typename MemberMap::iterator member =
getSingletonPtr()->_members.find(key_str);
auto member = getSingletonPtr()->_members.find(key_str);
if( member == getSingletonPtr()->_members.end() )
{
fallback_getter_t fallback_get = getSingletonPtr()->_fallback_getter;
@@ -1374,7 +1398,7 @@ namespace nasal
const std::string key = nasal::from_nasal<std::string>(c, field);
const MemberMap& members = getSingletonPtr()->_members;
typename MemberMap::const_iterator member = members.find(key);
auto member = members.find(key);
if( member == members.end() )
{
fallback_setter_t fallback_set = getSingletonPtr()->_fallback_setter;
@@ -1415,13 +1439,11 @@ namespace nasal
template<class T>
naGhostType
Ghost<T, typename boost::enable_if<is_strong_ref<T> >::type>
::_ghost_type_strong;
Ghost<T, std::enable_if_t<is_strong_ref<T>::value>>::_ghost_type_strong;
template<class T>
naGhostType
Ghost<T, typename boost::enable_if<is_strong_ref<T> >::type>
::_ghost_type_weak;
Ghost<T, std::enable_if_t<is_strong_ref<T>::value>>::_ghost_type_weak;
} // namespace nasal
@@ -1430,15 +1452,13 @@ namespace nasal
* Convert every shared pointer to a ghost.
*/
template<class T>
typename boost::enable_if<
nasal::internal::has_element_type<
typename nasal::internal::reduced_type<T>::type
>,
std::enable_if_t<
nasal::internal::has_element_type<std::remove_cvref_t<T>>::value,
naRef
>::type
>
to_nasal_helper(naContext c, T ptr)
{
typedef typename nasal::shared_ptr_traits<T>::strong_ref strong_ref;
using strong_ref = typename nasal::shared_ptr_traits<T>::strong_ref;
return nasal::Ghost<strong_ref>::makeGhost(c, ptr);
}
@@ -1446,15 +1466,13 @@ to_nasal_helper(naContext c, T ptr)
* Convert nasal ghosts/hashes to shared pointer (of a ghost).
*/
template<class T>
typename boost::enable_if<
nasal::internal::has_element_type<
typename nasal::internal::reduced_type<T>::type
>,
std::enable_if_t<
nasal::internal::has_element_type<std::remove_cvref_t<T>>::value,
T
>::type
>
from_nasal_helper(naContext c, naRef ref, const T*)
{
typedef typename nasal::shared_ptr_traits<T>::strong_ref strong_ref;
using strong_ref = typename nasal::shared_ptr_traits<T>::strong_ref;
return T(nasal::Ghost<strong_ref>::fromNasalChecked(c, ref));
}
@@ -1462,11 +1480,11 @@ from_nasal_helper(naContext c, naRef ref, const T*)
* Convert any pointer to a SGReferenced based object to a ghost.
*/
template<class T>
typename boost::enable_if_c<
boost::is_base_of<SGReferenced, T>::value
|| boost::is_base_of<SGWeakReferenced, T>::value,
std::enable_if_t<
std::is_base_of<SGReferenced, T>::value
|| std::is_base_of<SGWeakReferenced, T>::value,
naRef
>::type
>
to_nasal_helper(naContext c, T* ptr)
{
return nasal::Ghost<SGSharedPtr<T> >::makeGhost(c, SGSharedPtr<T>(ptr));
@@ -1476,20 +1494,14 @@ to_nasal_helper(naContext c, T* ptr)
* Convert nasal ghosts/hashes to pointer (of a SGReferenced based ghost).
*/
template<class T>
typename boost::enable_if_c<
boost::is_base_of<
SGReferenced,
typename boost::remove_pointer<T>::type
>::value
|| boost::is_base_of<
SGWeakReferenced,
typename boost::remove_pointer<T>::type
>::value,
std::enable_if_t<
std::is_base_of<SGReferenced, std::remove_pointer_t<T>>::value
|| std::is_base_of<SGWeakReferenced, std::remove_pointer_t<T>>::value,
T
>::type
>
from_nasal_helper(naContext c, naRef ref, const T*)
{
typedef SGSharedPtr<typename boost::remove_pointer<T>::type> TypeRef;
using TypeRef = SGSharedPtr<std::remove_pointer_t<T>>;
return T(nasal::Ghost<TypeRef>::fromNasalChecked(c, ref));
}
@@ -1497,10 +1509,10 @@ from_nasal_helper(naContext c, naRef ref, const T*)
* Convert any pointer to a osg::Referenced based object to a ghost.
*/
template<class T>
typename boost::enable_if<
boost::is_base_of<osg::Referenced, T>,
std::enable_if_t<
std::is_base_of<osg::Referenced, T>::value,
naRef
>::type
>
to_nasal_helper(naContext c, T* ptr)
{
return nasal::Ghost<osg::ref_ptr<T> >::makeGhost(c, osg::ref_ptr<T>(ptr));
@@ -1510,13 +1522,13 @@ to_nasal_helper(naContext c, T* ptr)
* Convert nasal ghosts/hashes to pointer (of a osg::Referenced based ghost).
*/
template<class T>
typename boost::enable_if<
boost::is_base_of<osg::Referenced, typename boost::remove_pointer<T>::type>,
std::enable_if_t<
std::is_base_of<osg::Referenced, std::remove_pointer_t<T>>::value,
T
>::type
>
from_nasal_helper(naContext c, naRef ref, const T*)
{
typedef osg::ref_ptr<typename boost::remove_pointer<T>::type> TypeRef;
using TypeRef = osg::ref_ptr<std::remove_pointer_t<T>>;
return T(nasal::Ghost<TypeRef>::fromNasalChecked(c, ref));
}

View File

@@ -20,8 +20,7 @@
#ifndef SG_NASAL_CALL_CONTEXT_HXX_
#define SG_NASAL_CALL_CONTEXT_HXX_
#include "from_nasal.hxx"
#include "to_nasal.hxx"
#include "NasalContext.hxx"
namespace nasal
{
@@ -29,11 +28,12 @@ namespace nasal
/**
* Context passed to a function/method being called from Nasal
*/
class CallContext
class CallContext:
public ContextWrapper
{
public:
CallContext(naContext c, naRef me, size_t argc, naRef* args):
c(c),
ContextWrapper(c),
me(me),
argc(argc),
args(args)
@@ -102,28 +102,14 @@ namespace nasal
requireArg(size_t index) const
{
if( index >= argc )
naRuntimeError(c, "Missing required arg #%d", index);
runtimeError("Missing required arg #%d", index);
return from_nasal<T>(args[index]);
}
template<class T>
naRef to_nasal(T arg) const
{
return nasal::to_nasal(c, arg);
}
template<class T>
typename from_nasal_ptr<T>::return_type
from_nasal(naRef ref) const
{
return (*from_nasal_ptr<T>::get())(c, ref);
}
naContext c;
naRef me;
size_t argc;
naRef *args;
naRef me;
size_t argc;
naRef *args;
};
} // namespace nasal

View File

@@ -17,13 +17,79 @@
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#include "NasalContext.hxx"
#include "NasalHash.hxx"
#include "NasalString.hxx"
#include <cassert>
namespace nasal
{
//----------------------------------------------------------------------------
ContextWrapper::ContextWrapper(naContext ctx):
_ctx(ctx)
{
assert(_ctx);
}
//----------------------------------------------------------------------------
ContextWrapper::operator naContext()
{
return _ctx;
}
//----------------------------------------------------------------------------
naContext ContextWrapper::c_ctx() const
{
return const_cast<naContext>(_ctx);
}
//----------------------------------------------------------------------------
Hash ContextWrapper::newHash()
{
return Hash(_ctx);
}
//----------------------------------------------------------------------------
String ContextWrapper::newString(const char* str)
{
return String(_ctx, str);
}
//----------------------------------------------------------------------------
naRef ContextWrapper::callMethod( Me me,
naRef code,
std::initializer_list<naRef> args )
{
naRef ret = naCallMethodCtx(
_ctx,
code,
me,
args.size(),
const_cast<naRef*>(args.begin()),
naNil() // locals
);
if( const char* error = naGetError(_ctx) )
throw std::runtime_error(error);
return ret;
}
//----------------------------------------------------------------------------
naRef ContextWrapper::newVector(std::initializer_list<naRef> vals)
{
naRef vec = naNewVector(_ctx);
naVec_setsize(_ctx, vec, vals.size());
int i = 0;
for(naRef val: vals)
naVec_set(vec, i++, val);
return vec;
}
//----------------------------------------------------------------------------
Context::Context():
_ctx(naNewContext())
ContextWrapper(naNewContext())
{
}
@@ -32,18 +98,7 @@ namespace nasal
Context::~Context()
{
naFreeContext(_ctx);
}
//----------------------------------------------------------------------------
Context::operator naContext()
{
return _ctx;
}
//----------------------------------------------------------------------------
Hash Context::newHash()
{
return Hash(_ctx);
_ctx = nullptr;
}
} // namespace nasal

View File

@@ -19,28 +19,110 @@
#ifndef SG_NASAL_CONTEXT_HXX_
#define SG_NASAL_CONTEXT_HXX_
#include "NasalHash.hxx"
#include "cppbind_fwd.hxx"
#include "NasalMe.hxx"
#include <boost/call_traits.hpp>
#include <initializer_list>
namespace nasal
{
/**
* Manage lifetime and encapsulate a Nasal context.
* Wraps a nasal ::naContext without taking ownership/managing its lifetime
*/
class Context
class ContextWrapper
{
public:
explicit ContextWrapper(naContext ctx);
operator naContext();
/** Convert to non-const ::naContext for usage with C-APIs */
naContext c_ctx() const;
Hash newHash();
String newString(const char* str);
/** Create a new nasal vector and fill it with the given values */
template<class... Vals>
naRef newVector(Vals ... vals)
{
return newVector({to_nasal(vals)...});
}
/** Raise a nasal runtime error */
template<class... Args>
void runtimeError(const char* fmt, Args ... args) const
{
naRuntimeError(c_ctx(), fmt, args...);
}
template<class T>
naRef to_nasal(T arg) const
{
return nasal::to_nasal(_ctx, arg);
}
template<class T, std::size_t N>
naRef to_nasal(const T(&array)[N]) const
{
return nasal::to_nasal(_ctx, array);
}
template<class T>
Me to_me(T arg) const
{
return Me{ to_nasal(arg) };
}
template<class T>
typename from_nasal_ptr<T>::return_type
from_nasal(naRef ref) const
{
return (*from_nasal_ptr<T>::get())(_ctx, ref);
}
naRef callMethod(Me me, naRef code, std::initializer_list<naRef> args);
template<class Ret, class... Args>
Ret callMethod( Me me,
naRef code,
typename boost::call_traits<Args>::param_type ... args )
{
// TODO warn if with Ret == void something different to nil is returned?
return from_nasal<Ret>(callMethod(
me,
code,
{ to_nasal<typename boost::call_traits<Args>::param_type>(args)... }
));
}
protected:
naContext _ctx;
// Not exposed to avoid confusion of intializer_list<naRef> to variadic
// arguments
naRef newVector(std::initializer_list<naRef> vals);
};
/**
* Creates and manages the lifetime of a ::naContext
*/
class Context:
public ContextWrapper
{
public:
Context();
~Context();
operator naContext();
Hash newHash();
protected:
naContext _ctx;
Context(const Context&) = delete;
Context& operator=(const Context&) = delete;
};
} // namespace nasal
#include "from_nasal.hxx"
#include "to_nasal.hxx"
#endif /* SG_NASAL_CONTEXT_HXX_ */

View File

@@ -0,0 +1,44 @@
///@file
//
// Copyright (C) 2018 Thomas Geymayer <tomgey@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#ifndef SG_NASAL_ME_HXX_
#define SG_NASAL_ME_HXX_
#include <simgear/nasal/nasal.h>
namespace nasal
{
/**
* Wrap a naRef to indicate it references the self/me object in Nasal method
* calls.
*/
struct Me
{
naRef _ref;
explicit Me(naRef ref = naNil()):
_ref(ref)
{}
operator naRef() { return _ref; }
};
} // namespace nasal
#endif /* SG_NASAL_ME_HXX_ */

View File

@@ -0,0 +1,75 @@
///@file
//
// Copyright (C) 2018 Thomas Geymayer <tomgey@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#ifndef SG_NASAL_METHOD_HOLDER_HXX_
#define SG_NASAL_METHOD_HOLDER_HXX_
#include "NasalContext.hxx"
#include "NasalObjectHolder.hxx"
namespace nasal
{
/**
* Hold any callable function in Nasal and call it from C++
*/
template<class Ret, class... Args>
class NasalMethodHolder
{
using Holder = ObjectHolder<SGReferenced>;
public:
NasalMethodHolder(naRef code):
_code(Holder::makeShared(code))
{}
/**
* @brief Call the function with the given arguments
*
* If the first argument is nasal::Me it will be passed as 'me' object and
* not as argument.
*/
Ret operator()(Args ... args)
{
return call(args...);
}
private:
Holder::Ref _code;
template<class... CArgs>
Ret call(Me self, CArgs ... args)
{
nasal::Context ctx;
return ctx.callMethod<Ret, CArgs...>(
self,
_code->get_naRef(),
args...
);
}
template<class... CArgs>
Ret call(CArgs ... args)
{
return call(Me{}, args...);
}
};
} // namespace nasal
#endif /* SG_NASAL_METHOD_HOLDER_HXX_ */

View File

@@ -45,18 +45,18 @@ namespace nasal
bool valid() const;
template<class Ret, class ... Args>
template<class Ret, class... Args>
Ret callMethod(const std::string& name, Args ... args)
{
if( !_nasal_impl.valid() )
return Ret();
Context ctx;
auto func = get_member<boost::function<Ret (nasal::Me, Args...)>>(
auto func = get_member<boost::function<Ret (Me, Args...)>>(
ctx, _nasal_impl.get_naRef(), name
);
if( func )
return func(nasal::to_nasal(ctx, this), args...);
return func(Me(ctx.to_nasal(this)), args...);
return Ret();
}

View File

@@ -42,6 +42,8 @@ namespace nasal
{
public:
using Ref = SGSharedPtr<ObjectHolder<Base>>;
/**
* @param obj Object to save
*/
@@ -84,7 +86,7 @@ namespace nasal
*
* @param obj Object to save
*/
static SGSharedPtr<ObjectHolder<Base> > makeShared(naRef obj);
static Ref makeShared(naRef obj);
protected:
naRef _ref;
@@ -155,10 +157,10 @@ namespace nasal
//----------------------------------------------------------------------------
template<class Base>
SGSharedPtr<ObjectHolder<Base> >
typename ObjectHolder<Base>::Ref
ObjectHolder<Base>::makeShared(naRef obj)
{
return SGSharedPtr<ObjectHolder<Base> >( new ObjectHolder<Base>(obj) );
return Ref( new ObjectHolder<Base>(obj) );
}
} // namespace nasal

View File

@@ -47,7 +47,7 @@ namespace nasal
*
* @param str Existing Nasal String
*/
String(naRef str);
explicit String(naRef str);
const char* c_str() const;
const char* begin() const;

View File

@@ -0,0 +1,60 @@
///@file
/// Nasal C++ Bindings forward declarations
///
// Copyright (C) 2018 Thomas Geymayer <tomgey@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#ifndef SG_NASAL_CPPBIND_FWD_HXX_
#define SG_NASAL_CPPBIND_FWD_HXX_
#include <simgear/nasal/nasal.h>
#include <cstddef>
#include <string>
namespace nasal
{
class bad_nasal_cast;
class CallContext;
class Context;
class ContextWrapper;
class Hash;
struct Me;
class Object;
class String;
template<class, class>
class Ghost;
template<class T>
naRef to_nasal(naContext c, T arg);
template<class T, std::size_t N>
naRef to_nasal(naContext c, const T(&array)[N]);
template<class T>
T from_nasal(naContext c, naRef ref);
template<class Var>
struct from_nasal_ptr;
template<class T>
T get_member(naContext c, naRef obj, const std::string& name);
} // namespace nasal
#endif /* SG_NASAL_CPPBIND_FWD_HXX_ */

View File

@@ -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

View File

@@ -24,20 +24,15 @@
#include <simgear/math/SGMath.hxx>
#include <simgear/math/SGRect.hxx>
#include <simgear/nasal/nasal.h>
#include <simgear/nasal/cppbind/NasalContext.hxx>
#include <simgear/nasal/cppbind/NasalMe.hxx>
#include <simgear/nasal/cppbind/NasalMethodHolder.hxx>
#include <simgear/nasal/cppbind/NasalObjectHolder.hxx>
#include <simgear/nasal/cppbind/to_nasal.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
#include <boost/bind.hpp>
#include <boost/call_traits.hpp>
#include <boost/function.hpp>
#include <boost/preprocessor/control/if.hpp>
#include <boost/preprocessor/iteration/iterate.hpp>
#include <boost/preprocessor/repetition/enum_trailing.hpp>
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
#include <boost/preprocessor/repetition/enum_shifted_params.hpp>
#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>
@@ -48,8 +43,6 @@ class SGPath;
namespace nasal
{
class Hash;
class String;
/**
* Thrown when converting a type from/to Nasal has failed
@@ -76,27 +69,19 @@ namespace nasal
std::string _msg;
};
/**
* Wrap a naRef to indicate it references the self/me object in Nasal method
* calls.
*/
struct Me
{
naRef _ref;
Me(naRef ref):
_ref(ref)
{}
operator naRef() { return _ref; }
};
/**
* Simple pass through for unified handling also of naRef.
*/
inline naRef from_nasal_helper(naContext, naRef ref, const naRef*)
{ return ref; }
/**
* Ignore return value
*/
// TODO show some warning when something is returned but ignored?
inline void from_nasal_helper(naContext, naRef, const void*)
{}
/**
* Convert Nasal string to std::string
*/
@@ -125,43 +110,33 @@ namespace nasal
*/
bool from_nasal_helper(naContext c, naRef ref, const bool*);
namespace detail
{
#define SG_BOOST_FUNCTION_FROM_NASAL_FWD
#define BOOST_PP_ITERATION_LIMITS (0, 9)
#define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx>
#include BOOST_PP_ITERATE()
#undef SG_BOOST_FUNCTION_FROM_NASAL_FWD
}
/**
* Convert a Nasal function to a boost::function with the given signature.
*
* @tparam Sig Signature of returned function (arguments and return value
* are automatically converted using from_nasal/to_nasal)
*/
template<class Sig>
boost::function<Sig>
from_nasal_helper(naContext c, naRef ref, boost::function<Sig>*)
template<class Ret, class... Args>
boost::function<Ret (Args...)>
from_nasal_helper(naContext c, naRef ref, const boost::function<Ret (Args...)>*)
{
if( naIsNil(ref) )
return boost::function<Sig>();
return {};
if( !naIsCode(ref)
&& !naIsCCode(ref)
&& !naIsFunc(ref) )
throw bad_nasal_cast("not a function");
return detail::boostFunctionFromNasal(ref, static_cast<Sig*>(0));
return NasalMethodHolder<Ret, Args...>(ref);
}
template<class Sig>
typename boost::enable_if< boost::is_function<Sig>,
boost::function<Sig>
>::type
from_nasal_helper(naContext c, naRef ref, Sig*)
template<class Ret, class... Args>
boost::function<Ret (Args...)>
from_nasal_helper(naContext c, naRef ref, Ret (*const)(Args...))
{
return from_nasal_helper(c, ref, static_cast<boost::function<Sig>*>(0));
return
from_nasal_helper(c, ref, static_cast<boost::function<Ret (Args...)>*>(0));
}
/**
@@ -227,21 +202,6 @@ namespace nasal
return SGRect<T>(vec[0], vec[1], vec[2], vec[3]);
}
// Helpers for wrapping calls to Nasal functions into boost::function
namespace detail
{
// Dummy include to add a build dependency on this file for gcc/CMake/etc.
#define SG_DONT_DO_ANYTHING
# include <simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx>
#undef SG_DONT_DO_ANYTHING
// Now the actual include (we are limited to 8 arguments (+me) here because
// boost::bind has an upper limit of 9)
#define BOOST_PP_ITERATION_LIMITS (0, 8)
#define BOOST_PP_FILENAME_1 <simgear/nasal/cppbind/detail/from_nasal_function_templates.hxx>
#include BOOST_PP_ITERATE()
}
} // namespace nasal
#endif /* SG_FROM_NASAL_HELPER_HXX_ */

View File

@@ -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

View File

@@ -20,10 +20,7 @@
#ifndef SG_NASAL_TRAITS_HXX_
#define SG_NASAL_TRAITS_HXX_
#include <boost/mpl/logical.hpp>
#include <boost/type_traits/integral_constant.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <boost/utility/enable_if.hpp>
#include <simgear/std/type_traits.hxx>
// Forward declarations
class SGReferenced;
@@ -56,12 +53,11 @@ namespace osg
namespace nasal
{
template<class T>
struct is_vec2: public boost::integral_constant<bool, false> {};
struct is_vec2: public std::false_type {};
#define SG_MAKE_TRAIT(templ,type,attr)\
template templ\
struct attr< type >:\
public boost::integral_constant<bool, true> {};
struct attr< type >: public std::true_type {};
SG_MAKE_TRAIT(<class T>, SGVec2<T>, is_vec2)
SG_MAKE_TRAIT(<>, osg::Vec2b, is_vec2)
@@ -75,42 +71,34 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2)
struct shared_ptr_traits;
template<class T>
struct is_strong_ref:
public boost::integral_constant<bool, false>
{};
struct is_strong_ref: public std::false_type {};
template<class T>
struct is_weak_ref:
public boost::integral_constant<bool, false>
{};
struct is_weak_ref: public std::false_type {};
#define SG_MAKE_SHARED_PTR_TRAIT(strong, weak, intrusive)\
template<class T>\
struct shared_ptr_traits<strong<T> >\
{\
typedef strong<T> strong_ref;\
typedef weak<T> weak_ref;\
typedef T element_type;\
typedef boost::integral_constant<bool, true> is_strong;\
typedef boost::integral_constant<bool, intrusive> is_intrusive;\
using strong_ref = strong<T>;\
using weak_ref = weak<T>;\
using element_type = T;\
using is_strong = std::true_type;\
using is_intrusive = std::bool_constant<intrusive>;\
};\
template<class T>\
struct shared_ptr_traits<weak<T> >\
{\
typedef strong<T> strong_ref;\
typedef weak<T> weak_ref;\
typedef T element_type;\
typedef boost::integral_constant<bool, false> is_strong;\
typedef boost::integral_constant<bool, intrusive> is_intrusive;\
using strong_ref = strong<T>;\
using weak_ref = weak<T>;\
using element_type = T;\
using is_strong = std::false_type;\
using is_intrusive = std::bool_constant<intrusive>;\
};\
template<class T>\
struct is_strong_ref<strong<T> >:\
public boost::integral_constant<bool, true>\
{};\
struct is_strong_ref<strong<T> >: public std::true_type {};\
template<class T>\
struct is_weak_ref<weak<T> >:\
public boost::integral_constant<bool, true>\
{};
struct is_weak_ref<weak<T> >: public std::true_type {};
SG_MAKE_SHARED_PTR_TRAIT(SGSharedPtr, SGWeakPtr, true)
SG_MAKE_SHARED_PTR_TRAIT(osg::ref_ptr, osg::observer_ptr, true)
@@ -119,25 +107,20 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2)
#undef SG_MAKE_SHARED_PTR_TRAIT
template<class T>
struct supports_weak_ref:
public boost::integral_constant<bool, true>
{};
struct supports_weak_ref: public std::true_type {};
template<class T>
struct supports_weak_ref<SGSharedPtr<T> >:
public boost::integral_constant<
bool,
boost::is_base_of<SGWeakReferenced, T>::value
>
public std::bool_constant<std::is_base_of<SGWeakReferenced, T>::value>
{};
template<class T>
struct shared_ptr_storage
{
typedef T storage_type;
typedef typename T::element_type element_type;
typedef typename shared_ptr_traits<T>::strong_ref strong_ref;
typedef typename shared_ptr_traits<T>::weak_ref weak_ref;
using storage_type = T;
using element_type = typename T::element_type;
using strong_ref = typename shared_ptr_traits<T>::strong_ref;
using weak_ref = typename shared_ptr_traits<T>::weak_ref;
template<class U>
static storage_type* ref(U ptr)
@@ -151,39 +134,30 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2)
template<class U>
static
typename boost::enable_if<
boost::is_same<U, element_type*>,
element_type*
>::type
std::enable_if_t<std::is_same<U, element_type*>::value, element_type*>
get(storage_type* ptr)
{
return get_pointer(*ptr);
}
template<class U>
static
typename boost::enable_if<
boost::mpl::or_<
boost::is_same<U, strong_ref>,
boost::mpl::and_<
boost::is_same<U, weak_ref>,
supports_weak_ref<U>
>
>,
std::enable_if_t<
std::is_same<U, strong_ref>::value
|| (std::is_same<U, weak_ref>::value && supports_weak_ref<U>::value),
U
>::type
>
get(storage_type* ptr)
{
return U(*ptr);
}
template<class U>
static
typename boost::enable_if<
boost::mpl::and_<
boost::is_same<U, weak_ref>,
boost::mpl::not_<supports_weak_ref<U> >
>,
std::enable_if_t<
std::is_same<U, weak_ref>::value && !supports_weak_ref<U>::value,
U
>::type
>
get(storage_type* ptr)
{
return U();
@@ -195,46 +169,37 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2)
template<class T>
struct intrusive_ptr_storage
{
typedef typename T::element_type storage_type;
typedef typename T::element_type element_type;
typedef typename shared_ptr_traits<T>::strong_ref strong_ref;
typedef typename shared_ptr_traits<T>::weak_ref weak_ref;
using storage_type = typename T::element_type;
using element_type = typename T::element_type;
using strong_ref = typename shared_ptr_traits<T>::strong_ref;
using weak_ref = typename shared_ptr_traits<T>::weak_ref;
template<class U>
static
typename boost::enable_if<
boost::is_same<U, element_type*>,
element_type*
>::type
std::enable_if_t<std::is_same<U, element_type*>::value, element_type*>
get(storage_type* ptr)
{
return ptr;
}
template<class U>
static
typename boost::enable_if<
boost::mpl::or_<
boost::is_same<U, strong_ref>,
boost::mpl::and_<
boost::is_same<U, weak_ref>,
supports_weak_ref<U>
>
>,
std::enable_if_t<
std::is_same<U, strong_ref>::value
|| (std::is_same<U, weak_ref>::value && supports_weak_ref<U>::value),
U
>::type
>
get(storage_type* ptr)
{
return U(ptr);
}
template<class U>
static
typename boost::enable_if<
boost::mpl::and_<
boost::is_same<U, weak_ref>,
boost::mpl::not_<supports_weak_ref<U> >
>,
std::enable_if_t<
std::is_same<U, weak_ref>::value && !supports_weak_ref<U>::value,
U
>::type
>
get(storage_type* ptr)
{
return U();
@@ -246,8 +211,8 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2)
struct shared_ptr_storage<SGSharedPtr<T> >:
public internal::intrusive_ptr_storage<SGSharedPtr<T> >
{
typedef T storage_type;
typedef T element_type;
using storage_type = T;
using element_type = T;
static storage_type* ref(element_type* ptr)
{
@@ -265,8 +230,8 @@ SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2)
struct shared_ptr_storage<osg::ref_ptr<T> >:
public internal::intrusive_ptr_storage<osg::ref_ptr<T> >
{
typedef T storage_type;
typedef T element_type;
using storage_type = T;
using element_type = T;
static storage_type* ref(element_type* ptr)

View File

@@ -24,7 +24,7 @@
#include <simgear/math/SGMath.hxx>
#include <simgear/math/SGRect.hxx>
#include <simgear/nasal/nasal.h>
#include <simgear/nasal/cppbind/cppbind_fwd.hxx>
#include <boost/function/function_fwd.hpp>
#include <boost/utility/enable_if.hpp>
@@ -40,8 +40,6 @@ class SGPath;
namespace nasal
{
class CallContext;
class Hash;
typedef boost::function<naRef (CallContext)> free_function_t;

View File

@@ -21,6 +21,7 @@
#define SG_FROM_NASAL_HXX_
#include <simgear/nasal/cppbind/detail/from_nasal_helper.hxx>
#include <type_traits>
namespace nasal
{
@@ -52,8 +53,8 @@ namespace nasal
template<class Var>
struct from_nasal_ptr
{
typedef typename boost::remove_const
< typename boost::remove_reference<Var>::type
typedef typename std::remove_const
< typename std::remove_reference<Var>::type
>::type return_type;
typedef return_type(*type)(naContext, naRef);

View File

@@ -20,50 +20,29 @@
#ifndef SG_NASAL_TESTCONTEXT_HXX_
#define SG_NASAL_TESTCONTEXT_HXX_
#include <simgear/nasal/cppbind/NasalCallContext.hxx>
#include <simgear/nasal/cppbind/NasalContext.hxx>
class TestContext:
public nasal::CallContext
public nasal::Context
{
public:
TestContext():
CallContext(naNewContext(), naNil(), 0, 0)
{}
~TestContext()
{
naFreeContext(c);
}
void runGC()
{
naFreeContext(c);
naFreeContext(_ctx);
naGC();
c = naNewContext();
_ctx = naNewContext();
}
template<class T>
T from_str(const std::string& str)
template<class T = naRef>
T exec(const std::string& code, nasal::Me me)
{
return from_nasal<T>(to_nasal(str));
return from_nasal<T>(execImpl(code, me));
}
naRef exec(const std::string& code_str, nasal::Me me)
{
int err_line = -1;
naRef code = naParseCode( c, to_nasal("<TextContext::exec>"), 0,
(char*)code_str.c_str(), code_str.length(),
&err_line );
if( !naIsCode(code) )
throw std::runtime_error("Failed to parse code: " + code_str);
return naCallMethod(code, me, 0, 0, naNil());
}
template<class T>
template<class T = naRef>
T exec(const std::string& code)
{
return from_nasal<T>(exec(code, naNil()));
return from_nasal<T>(execImpl(code, nasal::Me{}));
}
template<class T>
@@ -71,6 +50,26 @@ class TestContext:
{
return from_nasal<T>(to_nasal(str));
}
protected:
naRef execImpl(const std::string& code_str, nasal::Me me)
{
int err_line = -1;
naRef code = naParseCode( _ctx, to_nasal("<TextContext::exec>"), 0,
(char*)code_str.c_str(), code_str.length(),
&err_line );
if( !naIsCode(code) )
throw std::runtime_error("Failed to parse code: " + code_str);
naRef ret = naCallMethod(code, me, 0, 0, naNil());
if( char* err = naGetError(_ctx) )
throw std::runtime_error(
"Failed to executed code: " + std::string(err)
);
return ret;
}
};
#endif /* SG_NASAL_TESTCONTEXT_HXX_ */

View File

@@ -1,6 +1,8 @@
#define BOOST_TEST_MODULE cppbind
#include <BoostTestTargetConfig.h>
#include "TestContext.hxx"
#include <simgear/nasal/cppbind/Ghost.hxx>
#include <simgear/nasal/cppbind/NasalHash.hxx>
#include <simgear/nasal/cppbind/NasalString.hxx>
@@ -117,42 +119,42 @@ naRef f_freeFunction(nasal::CallContext c) { return c.requireArg<naRef>(0); }
BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
{
naContext c = naNewContext();
TestContext c;
naRef r;
using namespace nasal;
r = to_nasal(c, ENUM_ANOTHER);
BOOST_CHECK_EQUAL(from_nasal<int>(c, r), ENUM_ANOTHER);
r = c.to_nasal(ENUM_ANOTHER);
BOOST_CHECK_EQUAL(c.from_nasal<int>(r), ENUM_ANOTHER);
r = to_nasal(c, "Test");
r = c.to_nasal("Test");
BOOST_CHECK( strncmp("Test", naStr_data(r), naStr_len(r)) == 0 );
BOOST_CHECK_EQUAL(from_nasal<std::string>(c, r), "Test");
BOOST_CHECK_EQUAL(c.from_nasal<std::string>(r), "Test");
r = to_nasal(c, std::string("Test"));
r = c.to_nasal(std::string("Test"));
BOOST_CHECK( strncmp("Test", naStr_data(r), naStr_len(r)) == 0 );
BOOST_CHECK_EQUAL(from_nasal<std::string>(c, r), "Test");
BOOST_CHECK_EQUAL(c.from_nasal<std::string>(r), "Test");
r = to_nasal(c, 42);
r = c.to_nasal(42);
BOOST_CHECK_EQUAL(naNumValue(r).num, 42);
BOOST_CHECK_EQUAL(from_nasal<int>(c, r), 42);
BOOST_CHECK_EQUAL(c.from_nasal<int>(r), 42);
r = to_nasal(c, 4.2f);
r = c.to_nasal(4.2f);
BOOST_CHECK_EQUAL(naNumValue(r).num, 4.2f);
BOOST_CHECK_EQUAL(from_nasal<float>(c, r), 4.2f);
BOOST_CHECK_EQUAL(c.from_nasal<float>(r), 4.2f);
float test_data[3] = {0, 4, 2};
r = to_nasal(c, test_data);
r = c.to_nasal(test_data);
SGVec2f vec(0,2);
r = to_nasal(c, vec);
BOOST_CHECK_EQUAL(from_nasal<SGVec2f>(c, r), vec);
r = c.to_nasal(vec);
BOOST_CHECK_EQUAL(c.from_nasal<SGVec2f>(r), vec);
std::vector<int> std_vec;
r = to_nasal(c, std_vec);
r = c.to_nasal(std_vec);
r = to_nasal(c, "string");
BOOST_CHECK_THROW(from_nasal<int>(c, r), bad_nasal_cast);
r = c.to_nasal("string");
BOOST_CHECK_THROW(c.from_nasal<int>(r), bad_nasal_cast);
Hash hash(c);
hash.set("vec", r);
@@ -171,10 +173,10 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
it1 = it2;
it3 = it2;
r = to_nasal(c, hash);
r = c.to_nasal(hash);
BOOST_REQUIRE( naIsHash(r) );
simgear::StringMap string_map = from_nasal<simgear::StringMap>(c, r);
simgear::StringMap string_map = c.from_nasal<simgear::StringMap>(r);
BOOST_CHECK_EQUAL(string_map.at("vec"), "string");
BOOST_CHECK_EQUAL(string_map.at("name"), "my-name");
BOOST_CHECK_EQUAL(string_map.at("string"), "blub");
@@ -216,7 +218,7 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
// passed on to function
typedef boost::function<int (Me, int)> MeIntFunc;
MeIntFunc fmeint = hash.get<MeIntFunc>("func");
BOOST_CHECK_EQUAL(fmeint(naNil(), 5), 5);
BOOST_CHECK_EQUAL(fmeint(Me{}, 5), 5);
//----------------------------------------------------------------------------
// Test exposing classes to Nasal
@@ -260,81 +262,81 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
Ghost<SGWeakRefBasedPtr>::init("SGWeakRefBasedPtr");
SGWeakRefBasedPtr weak_ptr(new SGWeakReferenceBasedClass());
naRef nasal_ref = to_nasal(c, weak_ptr),
nasal_ptr = to_nasal(c, weak_ptr.get());
naRef nasal_ref = c.to_nasal(weak_ptr),
nasal_ptr = c.to_nasal(weak_ptr.get());
BOOST_REQUIRE( naIsGhost(nasal_ref) );
BOOST_REQUIRE( naIsGhost(nasal_ptr) );
SGWeakRefBasedPtr ptr1 = from_nasal<SGWeakRefBasedPtr>(c, nasal_ref),
ptr2 = from_nasal<SGWeakRefBasedPtr>(c, nasal_ptr);
SGWeakRefBasedPtr ptr1 = c.from_nasal<SGWeakRefBasedPtr>(nasal_ref),
ptr2 = c.from_nasal<SGWeakRefBasedPtr>(nasal_ptr);
BOOST_CHECK_EQUAL(weak_ptr, ptr1);
BOOST_CHECK_EQUAL(weak_ptr, ptr2);
BOOST_REQUIRE( Ghost<BasePtr>::isInit() );
nasal::to_nasal(c, DoubleDerived2Ptr());
c.to_nasal(DoubleDerived2Ptr());
BasePtr d( new Derived );
naRef derived = to_nasal(c, d);
naRef derived = c.to_nasal(d);
BOOST_REQUIRE( naIsGhost(derived) );
BOOST_CHECK_EQUAL( std::string("DerivedPtr"), naGhost_type(derived)->name );
// Get member function from ghost...
naRef thisGetter = naNil();
BOOST_CHECK( naMember_get(c, derived, to_nasal(c, "this"), &thisGetter) );
BOOST_CHECK( naMember_get(c, derived, c.to_nasal("this"), &thisGetter) );
BOOST_CHECK( naIsFunc(thisGetter) );
// ...and check if it really gets passed the correct instance
typedef boost::function<unsigned long (Me)> MemFunc;
MemFunc fGetThis = from_nasal<MemFunc>(c, thisGetter);
MemFunc fGetThis = c.from_nasal<MemFunc>(thisGetter);
BOOST_REQUIRE( fGetThis );
BOOST_CHECK_EQUAL( fGetThis(derived), (unsigned long)d.get() );
BOOST_CHECK_EQUAL( fGetThis(Me{derived}), (unsigned long)d.get() );
BasePtr d2( new DoubleDerived );
derived = to_nasal(c, d2);
derived = c.to_nasal(d2);
BOOST_CHECK( naIsGhost(derived) );
BOOST_CHECK_EQUAL( std::string("DoubleDerivedPtr"),
naGhost_type(derived)->name );
BasePtr d3( new DoubleDerived2 );
derived = to_nasal(c, d3);
derived = c.to_nasal(d3);
BOOST_CHECK( naIsGhost(derived) );
BOOST_CHECK_EQUAL( std::string("DoubleDerived2Ptr"),
naGhost_type(derived)->name );
SGRefBasedPtr ref_based( new SGReferenceBasedClass );
naRef na_ref_based = to_nasal(c, ref_based.get());
naRef na_ref_based = c.to_nasal(ref_based.get());
BOOST_CHECK( naIsGhost(na_ref_based) );
BOOST_CHECK_EQUAL( from_nasal<SGReferenceBasedClass*>(c, na_ref_based),
BOOST_CHECK_EQUAL( c.from_nasal<SGReferenceBasedClass*>(na_ref_based),
ref_based.get() );
BOOST_CHECK_EQUAL( from_nasal<SGRefBasedPtr>(c, na_ref_based), ref_based );
BOOST_CHECK_EQUAL( c.from_nasal<SGRefBasedPtr>(na_ref_based), ref_based );
BOOST_CHECK_EQUAL( from_nasal<BasePtr>(c, derived), d3 );
BOOST_CHECK_NE( from_nasal<BasePtr>(c, derived), d2 );
BOOST_CHECK_EQUAL( from_nasal<DerivedPtr>(c, derived),
BOOST_CHECK_EQUAL( c.from_nasal<BasePtr>(derived), d3 );
BOOST_CHECK_NE( c.from_nasal<BasePtr>(derived), d2 );
BOOST_CHECK_EQUAL( c.from_nasal<DerivedPtr>(derived),
boost::dynamic_pointer_cast<Derived>(d3) );
BOOST_CHECK_EQUAL( from_nasal<DoubleDerived2Ptr>(c, derived),
BOOST_CHECK_EQUAL( c.from_nasal<DoubleDerived2Ptr>(derived),
boost::dynamic_pointer_cast<DoubleDerived2>(d3) );
BOOST_CHECK_THROW( from_nasal<DoubleDerivedPtr>(c, derived), bad_nasal_cast );
BOOST_CHECK_THROW( c.from_nasal<DoubleDerivedPtr>(derived), bad_nasal_cast );
std::map<std::string, BasePtr> instances;
BOOST_CHECK( naIsHash(to_nasal(c, instances)) );
BOOST_CHECK( naIsHash(c.to_nasal(instances)) );
std::map<std::string, DerivedPtr> instances_d;
BOOST_CHECK( naIsHash(to_nasal(c, instances_d)) );
BOOST_CHECK( naIsHash(c.to_nasal(instances_d)) );
std::map<std::string, int> int_map;
BOOST_CHECK( naIsHash(to_nasal(c, int_map)) );
BOOST_CHECK( naIsHash(c.to_nasal(int_map)) );
std::map<std::string, std::vector<int> > int_vector_map;
BOOST_CHECK( naIsHash(to_nasal(c, int_vector_map)) );
BOOST_CHECK( naIsHash(c.to_nasal(int_vector_map)) );
simgear::StringMap dict =
simgear::StringMap("hello", "value")
("key2", "value2");
naRef na_dict = to_nasal(c, dict);
naRef na_dict = c.to_nasal(dict);
BOOST_REQUIRE( naIsHash(na_dict) );
BOOST_CHECK_EQUAL( Hash(na_dict, c).get<std::string>("key2"), "value2" );
@@ -346,65 +348,44 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
Hash obj(c);
obj.set("parents", parents);
BOOST_CHECK_EQUAL( from_nasal<BasePtr>(c, obj.get_naRef()), d3 );
BOOST_CHECK_EQUAL( c.from_nasal<BasePtr>(obj.get_naRef()), d3 );
// Check recursive parents (aka parent-of-parent)
std::vector<naRef> parents2;
parents2.push_back(obj.get_naRef());
Hash derived_obj(c);
derived_obj.set("parents", parents2);
BOOST_CHECK_EQUAL( from_nasal<BasePtr>(c, derived_obj.get_naRef()), d3 );
BOOST_CHECK_EQUAL( c.from_nasal<BasePtr>(derived_obj.get_naRef()), d3 );
std::vector<naRef> nasal_objects;
nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d) );
nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d2) );
nasal_objects.push_back( Ghost<BasePtr>::makeGhost(c, d3) );
naRef obj_vec = to_nasal(c, nasal_objects);
naRef obj_vec = c.to_nasal(nasal_objects);
std::vector<BasePtr> objects = from_nasal<std::vector<BasePtr> >(c, obj_vec);
std::vector<BasePtr> objects = c.from_nasal<std::vector<BasePtr> >(obj_vec);
BOOST_CHECK_EQUAL( objects[0], d );
BOOST_CHECK_EQUAL( objects[1], d2 );
BOOST_CHECK_EQUAL( objects[2], d3 );
{
// Calling fallback setter for unset values
const char* src_code = "me.test = 3;";
int errLine = -1;
naRef code = naParseCode( c, to_nasal(c, "source.nas"), 0,
(char*)src_code, strlen(src_code),
&errLine );
ret = naCallMethod(code, derived, 0, 0, naNil());
// Calling fallback setter for unset values
BOOST_CHECK_EQUAL( c.exec<int>("me.test = 3;", Me{derived}), 3 );
BOOST_REQUIRE( !naGetError(c) ); // TODO real error check (this seems to
// always return 0...
BOOST_CHECK_EQUAL( from_nasal<int>(c, ret), 3 );
}
{
// Calling generic (fallback) getter
const char* src_code = "var a = me.get_test;";
int errLine = -1;
naRef code = naParseCode( c, to_nasal(c, "source.nas"), 0,
(char*)src_code, strlen(src_code),
&errLine );
ret = naCallMethod(code, derived, 0, 0, naNil());
BOOST_REQUIRE( !naGetError(c) ); // TODO real error check (this seems to
// always return 0...
BOOST_CHECK_EQUAL( from_nasal<std::string>(c, ret), "generic-get" );
}
// Calling generic (fallback) getter
BOOST_CHECK_EQUAL( c.exec<std::string>("var a = me.get_test;", Me{derived}),
"generic-get" );
//----------------------------------------------------------------------------
// Test nasal::CallContext
//----------------------------------------------------------------------------
int int_vec[] = {1,2,3};
std::map<std::string, std::string> map;
naRef args[] = {
to_nasal(c, std::string("test-arg")),
to_nasal(c, 4),
to_nasal(c, int_vec),
to_nasal(c, map)
c.to_nasal(std::string("test-arg")),
c.to_nasal(4),
c.to_nasal(int_vec),
c.to_nasal(map)
};
CallContext cc(c, naNil(), sizeof(args)/sizeof(args[0]), args);
BOOST_CHECK_EQUAL( cc.requireArg<std::string>(0), "test-arg" );
@@ -419,15 +400,15 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
BOOST_CHECK( cc.isVector(2) );
BOOST_CHECK( cc.isHash(3) );
naRef args_vec = nasal::to_nasal(c, args);
naRef args_vec = c.to_nasal(args);
BOOST_CHECK( naIsVector(args_vec) );
//----------------------------------------------------------------------------
// Test nasal::String
//----------------------------------------------------------------------------
String string( to_nasal(c, "Test") );
BOOST_CHECK_EQUAL( from_nasal<std::string>(c, string.get_naRef()), "Test" );
String string( c.to_nasal("Test") );
BOOST_CHECK_EQUAL( c.from_nasal<std::string>(string.get_naRef()), "Test" );
BOOST_CHECK_EQUAL( string.c_str(), std::string("Test") );
BOOST_CHECK( string.starts_with(string) );
BOOST_CHECK( string.starts_with(String(c, "T")) );
@@ -453,6 +434,16 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
BOOST_CHECK_EQUAL( string.find_first_not_of(String(c, "Tse"), 2), 3 );
BOOST_CHECK_EQUAL( string.find_first_not_of(String(c, "abc")), 0 );
BOOST_CHECK_EQUAL( string.find_first_not_of(String(c, "abc"), 20), String::npos );
naFreeContext(c);
}
BOOST_AUTO_TEST_CASE( cppbind_context )
{
nasal::Context ctx;
naRef vec = ctx.newVector(1, 2, 3.4, "test");
BOOST_REQUIRE( naIsVector(vec) );
BOOST_CHECK_EQUAL(ctx.from_nasal<int>(naVec_get(vec, 0)), 1);
BOOST_CHECK_EQUAL(ctx.from_nasal<int>(naVec_get(vec, 1)), 2);
BOOST_CHECK_EQUAL(ctx.from_nasal<double>(naVec_get(vec, 2)), 3.4);
BOOST_CHECK_EQUAL(ctx.from_nasal<std::string>(naVec_get(vec, 3)), "test");
}

View File

@@ -1,9 +1,12 @@
#define BOOST_TEST_MODULE cppbind
#include <BoostTestTargetConfig.h>
#include "TestContext.hxx"
#include <simgear/nasal/cppbind/Ghost.hxx>
#include <simgear/nasal/cppbind/NasalContext.hxx>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
@@ -186,3 +189,44 @@ BOOST_AUTO_TEST_CASE( storage_traits )
nasal::shared_ptr_storage<DerivedWeakPtr>::unref(d_weak);
}
BOOST_AUTO_TEST_CASE( bind_methods )
{
struct TestClass
{
int arg1;
std::string arg2;
std::string arg3;
int arg4;
void set(int a1, const std::string& a2, const std::string& a3, int a4)
{
arg1 = a1;
arg2 = a2;
arg3 = a3;
arg4 = a4;
}
};
using TestClassPtr = boost::shared_ptr<TestClass>;
auto set_func = boost::function<
void (TestClass&, int, const std::string&, const std::string&, int)
>(&TestClass::set);
nasal::Ghost<TestClassPtr>::init("TestClass")
.method("set", set_func)
.method("setReverse", set_func, std::index_sequence<3,2,1,0>{});
TestContext ctx;
auto test = boost::make_shared<TestClass>();
ctx.exec("me.set(1, \"s2\", \"s3\", 4);", ctx.to_me(test));
BOOST_CHECK_EQUAL(test->arg1, 1);
BOOST_CHECK_EQUAL(test->arg2, "s2");
BOOST_CHECK_EQUAL(test->arg3, "s3");
BOOST_CHECK_EQUAL(test->arg4, 4);
ctx.exec("me.setReverse(1, \"s2\", \"s3\", 4);", ctx.to_me(test));
BOOST_CHECK_EQUAL(test->arg1, 4);
BOOST_CHECK_EQUAL(test->arg2, "s3");
BOOST_CHECK_EQUAL(test->arg3, "s2");
BOOST_CHECK_EQUAL(test->arg4, 1);
}

View File

@@ -25,7 +25,7 @@ static naGhostType ghost_type = {
static naRef createTestGhost(TestContext& c, intptr_t p)
{
active_instances.insert(p);
return naNewGhost(c.c, &ghost_type, (void*)p);
return naNewGhost(c, &ghost_type, (void*)p);
}
//------------------------------------------------------------------------------

View File

@@ -1,3 +1,6 @@
///@file
/// The Nasal scripting language
///
#ifndef _NASAL_H
#define _NASAL_H
#ifdef __cplusplus
@@ -15,12 +18,14 @@ extern "C" {
#define GCC_PURE
#endif
/** Nasal context pointer */
typedef struct Context* naContext;
// The function signature for an extension function:
/** Function signature for an extension function */
typedef naRef (*naCFunction)(naContext ctx, naRef me, int argc, naRef* args);
// The function signature for an extension function with userdata passed back:
/** Function signature for an extension function with @p user_data passed back
*/
typedef naRef (*naCFunctionU)
(naContext ctx, naRef me, int argc, naRef* args, void* user_data);
@@ -258,7 +263,7 @@ void naHash_set(naRef hash, naRef key, naRef val);
void naHash_cset(naRef hash, char* key, naRef val);
void naHash_delete(naRef hash, naRef key);
/**
* Store the keys in ::hash into the vector at ::dst
* Store the keys in @p hash into the vector at @p dst
*
* @see ::naNewVector
*/
@@ -273,25 +278,25 @@ typedef struct naGhostType {
} naGhostType;
/**
* Create a ghost for an object without any attributes. If ::t contains pointers
* to get_member or set_member function they will be ignored.
* Create a ghost for an object without any attributes. If @p t contains
* pointers to get_member or set_member function they will be ignored.
*/
naRef naNewGhost(naContext c, naGhostType* t, void* ghost);
/**
* Create a ghost for an object. This version uses the get_member and set_member
* function pointers in ::t upon trying to get or set a member respectively from
* Nasal.
* function pointers in @p t upon trying to get or set a member respectively
* from Nasal.
*/
naRef naNewGhost2(naContext c, naGhostType* t, void* ghost);
naGhostType* naGhost_type(naRef ghost);
void* naGhost_ptr(naRef ghost);
/**
* Attach a nasal object to the given ghost. Binds the lifetime of @a data to
* the lifetime of the @a ghost.
* Attach a nasal object to the given ghost. Binds the lifetime of @p data to
* the lifetime of the @p ghost.
*/
void naGhost_setData(naRef ghost, naRef data);
/**
* Retrieve the object attached to the @a ghost, previously set with
* Retrieve the object attached to the @p ghost, previously set with
* naGhost_setData().
*/
naRef naGhost_data(naRef ghost);

View File

@@ -554,12 +554,10 @@ void Root::addDelegate(simgear::pkg::Delegate *aDelegate)
void Root::removeDelegate(simgear::pkg::Delegate *aDelegate)
{
DelegateVec::iterator it = std::find(d->delegates.begin(),
d->delegates.end(), aDelegate);
if (it == d->delegates.end()) {
throw sg_exception("unknown delegate in removeDelegate");
auto it = std::find(d->delegates.begin(), d->delegates.end(), aDelegate);
if (it != d->delegates.end()) {
d->delegates.erase(it);
}
d->delegates.erase(it);
}
void Root::setLocale(const std::string& aLocale)

View File

@@ -99,9 +99,9 @@ inline T parseString(const std::string& str)
return result;
}
/**
* Property value types.
*/
//
// Property value types
//
#ifdef NONE
#pragma warn A sloppy coder has defined NONE as a macro!
@@ -148,6 +148,7 @@ inline T parseString(const std::string& str)
#undef STRING
#endif
/// Property system which associates property names with values.
namespace props
{
/**
@@ -2144,17 +2145,18 @@ inline SGPropertyNode* makeChild(SGPropertyNode* parent, const char* name,
return parent->getChild(name, index, true);
}
/**
* Utility function for creation of a child property node using a
* relative path.
*/
namespace simgear
{
template<typename StringType>
inline SGPropertyNode* makeNode(SGPropertyNode* parent, const StringType& name)
{
return parent->getNode(name, true);
}
/**
* Utility function for creation of a child property node using a
* relative path.
*/
template<typename StringType>
inline SGPropertyNode*
makeNode(SGPropertyNode* parent, const StringType& name)
{
return parent->getNode(name, true);
}
}
// For boost::hash

View File

@@ -1,3 +1,6 @@
///@file
/// Support classes for parsing effects.
///
// Copyright (C) 2009 Tim Moore timoore@redhat.com
//
// This library is free software; you can redistribute it and/or
@@ -39,9 +42,6 @@
#include <simgear/structure/Singleton.hxx>
#include "Effect.hxx"
/**
* Support classes for parsing effects.
*/
namespace simgear
{

View File

@@ -77,9 +77,9 @@ osg::Vec2d eventToWindowCoords(const osgGA::GUIEventAdapter& ea)
SGPropertyNode* modelRoot,
SGSharedPtr<SGCondition const> condition) :
SGPickCallback(PriorityPanel),
_condition(condition),
_repeatable(configNode->getBoolValue("repeatable", false)),
_repeatInterval(configNode->getDoubleValue("interval-sec", 0.1)),
_condition(condition)
_repeatInterval(configNode->getDoubleValue("interval-sec", 0.1))
{
std::vector<SGPropertyNode_ptr> bindings;
@@ -264,7 +264,8 @@ public:
SGPropertyNode* modelRoot,
osg::Group *node,
SGSharedPtr<SGCondition const> condition)
: _node(node), _condition(condition)
: _condition(condition)
, _node(node)
{
SG_LOG(SG_INPUT, SG_DEBUG, "Configuring VNC callback");
const char *cornernames[3] = {"top-left", "top-right", "bottom-left"};
@@ -765,7 +766,8 @@ private:
class SGKnobAnimation::UpdateCallback : public osg::NodeCallback {
public:
UpdateCallback(SGExpressiond const* animationValue, SGSharedPtr<SGCondition const> condition) :
_animationValue(animationValue), _condition(condition)
_condition(condition),
_animationValue(animationValue)
{
setName("SGKnobAnimation::UpdateCallback");
}
@@ -899,9 +901,9 @@ class TouchPickCallback : public SGPickCallback {
public:
TouchPickCallback(const SGPropertyNode* configNode,
SGPropertyNode* modelRoot) :
SGPickCallback(PriorityPanel),
_repeatable(configNode->getBoolValue("repeatable", false)),
_repeatInterval(configNode->getDoubleValue("interval-sec", 0.1)),
SGPickCallback(PriorityPanel)
_repeatInterval(configNode->getDoubleValue("interval-sec", 0.1))
{
std::vector<SGPropertyNode_ptr> bindings;

View File

@@ -11,10 +11,15 @@
#cmakedefine HAVE_TIMEGM
#cmakedefine HAVE_STD_ISNAN
#cmakedefine HAVE_WORKING_STD_REGEX
#cmakedefine HAVE_WINDOWS_H
#cmakedefine HAVE_MKDTEMP
#cmakedefine HAVE_AL_EXT_H
#cmakedefine HAVE_STD_INDEX_SEQUENCE
#cmakedefine HAVE_STD_REMOVE_CV_T
#cmakedefine HAVE_STD_REMOVE_CVREF_T
#cmakedefine HAVE_STD_ENABLE_IF_T
#cmakedefine HAVE_STD_BOOL_CONSTANT
#cmakedefine GCC_ATOMIC_BUILTINS_FOUND

View File

@@ -0,0 +1,21 @@
include (SimGearComponent)
set(HEADERS
integer_sequence.hxx
type_traits.hxx
)
set(SOURCES
)
simgear_component(std std "${SOURCES}" "${HEADERS}")
if(ENABLE_TESTS)
add_executable(test_integer_sequence integer_sequence_test.cxx)
add_test(integer_sequence ${EXECUTABLE_OUTPUT_PATH}/test_integer_sequence)
target_link_libraries(test_integer_sequence ${TEST_LIBS})
add_executable(test_type_traits type_traits_test.cxx)
add_test(type_traits ${EXECUTABLE_OUTPUT_PATH}/test_type_traits)
target_link_libraries(test_type_traits ${TEST_LIBS})
endif()

View File

@@ -0,0 +1,88 @@
///@file
/// Metaprogramming Integer sequence (Is in C++14 but not C++11)
//
// Copyright (C) 2017 Thomas Geymayer <tomgey@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#ifndef SIMGEAR_STD_INTEGER_SEQUENCE_HXX_
#define SIMGEAR_STD_INTEGER_SEQUENCE_HXX_
#include <simgear/simgear_config.h>
#include "type_traits.hxx"
#include <utility>
#ifndef HAVE_STD_INDEX_SEQUENCE
# include <cstddef>
namespace std
{
template<class T, T... Ints>
struct integer_sequence
{
static_assert(
std::is_integral<T>::value,
"std::integer_sequence can only be instantiated with an an integral type"
);
typedef T value_type;
static constexpr size_t size() noexcept { return sizeof...(Ints); }
};
}
namespace simgear { namespace detail
{
template<class T, class Seq, T El>
struct append;
template<class T, T... Ints, T Int>
struct append<T, std::integer_sequence<T, Ints...>, Int>
{
using type = std::integer_sequence<T, Ints..., Int>;
};
template<class T, std::size_t N>
struct sequence_gen
{
using type =
typename append<T, typename sequence_gen<T, N - 1>::type, N - 1>::type;
};
template<class T>
struct sequence_gen<T, 0>
{
using type = std::integer_sequence<T>;
};
}}
namespace std
{
template<size_t... Ints>
using index_sequence = integer_sequence<size_t, Ints...>;
template<class T, size_t N>
using make_integer_sequence =
typename simgear::detail::sequence_gen<T, N>::type;
template<size_t N>
using make_index_sequence = make_integer_sequence<size_t, N>;
template<class... T>
using index_sequence_for = make_index_sequence<sizeof...(T)>;
}
#endif
#endif /* SIMGEAR_STD_INTEGER_SEQUENCE_HXX_ */

View File

@@ -0,0 +1,46 @@
#include <simgear/std/integer_sequence.hxx>
#include <iostream>
template<class T>
void print(const T& v, std::size_t i)
{
std::cout << "arg #" << i << ": '" << v << "', ";
}
template<class... Args, std::size_t... Is>
void doIt_impl(Args ... args, std::index_sequence<Is...>)
{
std::initializer_list<char>{(print(args, Is), '0')...};
}
template<class... Args>
void doIt(Args ... args)
{
static_assert(sizeof...(Args) == std::index_sequence_for<Args...>::size(), "");
doIt_impl<Args...>(args..., std::index_sequence_for<Args...>{});
}
int main(int argc, char* argv[])
{
static_assert(std::is_same<std::integer_sequence<char>::value_type, char>::value, "");
static_assert(std::is_same<std::integer_sequence<long long>::value_type, long long>::value, "");
static_assert(std::is_same<std::index_sequence<>::value_type, std::size_t>::value, "");
static_assert(std::is_same<std::make_index_sequence<0>, std::index_sequence<>>::value, "");
static_assert(std::is_same<std::make_index_sequence<1>, std::index_sequence<0>>::value, "");
static_assert(std::is_same<std::make_index_sequence<2>, std::index_sequence<0, 1>>::value, "");
static_assert(std::is_same<std::make_index_sequence<3>, std::index_sequence<0, 1, 2>>::value, "");
static_assert(std::is_same<std::make_index_sequence<4>, std::index_sequence<0, 1, 2, 3>>::value, "");
static_assert(std::is_same<std::make_index_sequence<5>, std::index_sequence<0, 1, 2, 3, 4>>::value, "");
static_assert(std::is_same<std::make_index_sequence<6>, std::index_sequence<0, 1, 2, 3, 4, 5>>::value, "");
static_assert(std::is_same<std::make_index_sequence<7>, std::index_sequence<0, 1, 2, 3, 4, 5, 6>>::value, "");
static_assert(std::is_same<std::make_index_sequence<8>, std::index_sequence<0, 1, 2, 3, 4, 5, 6, 7>>::value, "");
static_assert(std::make_index_sequence<5>::size() == 5, "");
static_assert(std::index_sequence_for<float, int, double>::size() == 3, "");
std::cout << std::make_integer_sequence<int, 5>::size() << std::endl;
doIt(1, 2, 3, "hallo", 3.4, 3.52f);
return 0;
}

View File

@@ -0,0 +1,67 @@
///@file
/// Type Traits (Provide features of later C++ standards)
//
// Copyright (C) 2017 Thomas Geymayer <tomgey@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
#ifndef SIMGEAR_STD_TYPE_TRAITS_HXX_
#define SIMGEAR_STD_TYPE_TRAITS_HXX_
#include <simgear/simgear_config.h>
#include <type_traits>
namespace std
{
#ifndef HAVE_STD_REMOVE_CV_T
template<class T>
using remove_cv_t = typename remove_cv<T>::type;
template<class T>
using remove_const_t = typename remove_const<T>::type;
template<class T>
using remove_volatile_t = typename remove_volatile<T>::type;
template<class T>
using remove_reference_t = typename remove_reference<T>::type;
template< class T >
using remove_pointer_t = typename remove_pointer<T>::type;
#endif
#ifndef HAVE_STD_REMOVE_CVREF_T
template<class T>
struct remove_cvref
{
using type = remove_cv_t<remove_reference_t<T>>;
};
template<class T>
using remove_cvref_t = typename remove_cvref<T>::type;
#endif
#ifndef HAVE_STD_ENABLE_IF_T
template<bool B, class T = void>
using enable_if_t = typename enable_if<B, T>::type;
#endif
#ifndef HAVE_STD_BOOL_CONSTANT
template <bool B>
using bool_constant = integral_constant<bool, B>;
#endif
}
#endif /* SIMGEAR_STD_TYPE_TRAITS_HXX_ */

View File

@@ -0,0 +1,24 @@
#include <simgear/std/type_traits.hxx>
using namespace std;
template<class T, class U>
void assert_same()
{
static_assert(is_same<T, U>::value, "");
}
int main(int argc, char* argv[])
{
assert_same<remove_cv_t<int const volatile>, int>();
assert_same<remove_const_t<int const volatile>, int volatile>();
assert_same<remove_volatile_t<int const volatile>, int const>();
assert_same<remove_reference_t<int const volatile&>, int const volatile>();
assert_same<remove_pointer_t<int const volatile*>, int const volatile>();
assert_same<remove_cvref_t<int const volatile&>, int>();
assert_same<enable_if_t<true, double>, double>();
assert_same<bool_constant<true>, integral_constant<bool, true>>();
return 0;
}

View File

@@ -36,10 +36,9 @@
#include <simgear/structure/exception.hxx>
#include <simgear/structure/Singleton.hxx>
/// Expression tree implementation.
namespace simgear
{
/// Expression tree implementation.
namespace expression
{
enum Type {

View File

@@ -29,9 +29,10 @@ namespace simgear
/**
* Handle a list of callbacks like a single boost::function.
*
* @tparam Sig Function signature.
* @tparam Ret Return type of the callbacks
* @tparam Args Parameter types of the callbacks
*/
template<class Ret, class ... Args>
template<class Ret, class... Args>
class function_list<Ret(Args...)>:
public std::vector<boost::function<Ret(Args...)>>
{
@@ -54,7 +55,7 @@ namespace simgear
* Handle a list of callbacks with the same signature as the given
* boost::function type.
*/
template<class Ret, class ... Args>
template<class Ret, class... Args>
class function_list<boost::function<Ret(Args...)>>:
public function_list<Ret(Args...)>
{