Compare commits

..

15 Commits

Author SHA1 Message Date
Torsten Dreyer
9a8c10cb0b New version: 2018.3.3 2019-07-28 22:43:16 +02:00
Erik Hofman
fd32023437 Do not attempt to deregister the same emitter more than once 2019-01-26 10:17:11 +01:00
Erik Hofman
c1ee4a9172 Use AAX_PROCESSED since AAX_STOPPED is only a request to stop but the library decides when it is actually stopped. And AeonWave has become more picky about destroying emitters which aren't completely processed yet since MIDI support was added. 2019-01-26 10:16:38 +01:00
Richard Harrison
a5b32f8eb2 Fix for deleting referenced object from model registry
This should have been in the previous commit - However I managed to mess up the merging of this module due to other changes related to the DDS texture cache.
2019-01-25 21:39:03 +00:00
Richard Harrison
4a86368c8f Fix null ref during load.
This happened a few times
2019-01-25 21:39:03 +00:00
Richard Harrison
3730cc48a5 Fix particles active even when disabled during load.
Possibly this could be fixed better by using the plugin string data - but there is nothing that currently set this; and it seems easier to use the particle callback enabled flag.
2019-01-25 21:39:03 +00:00
Richard Harrison
8a55c2f44f Fix for deleting still referenced object
ref https://sourceforge.net/p/flightgear/codetickets/2105/

Use the thread safe versions (getRef) of the objectcache methods
2019-01-25 21:39:03 +00:00
Erik Hofman
ef1cbae22b Split up SIMD support in ENABLE_SIMD which enables sse2 support for the compiler and ENABLE_SIMD_CODE which enables the hand crafted SIMD math functions which defaults to OFF now since compilers have catched up on generating optimized vectorized SIMD code. 2019-01-15 11:01:24 +01:00
James Turner
61f322f201 Bump patch version to 2018.3.2 2019-01-06 16:14:10 +00:00
Stuart Buchanan
becbef96f5 Fix effects for MP models - ticket 2076
https://sourceforge.net/p/flightgear/codetickets/2076/

Effects were being instantiated by the loader for
all models, rather than just simple .ac/.obj models.
2018-11-06 17:44:06 +00:00
James Turner
89b3fadf0f Fix for assert with empty systems
Empty subsystem groups didn’t set their init state correctly, leading
to an assert on post-init. Fix this and add a test for it.

https://sourceforge.net/p/flightgear/codetickets/2043/
2018-10-23 15:30:32 +01:00
James Turner
4a1a9ea9c1 Catalogs: allow migration to alternate IDs 2018-10-17 16:24:26 +01:00
James Turner
efc609577f Packages: check for existing update when scheduling
This is fixing an issue identified in the launcher in a secondary way,
to ensure if another user of the API tries to schedule an already
scheduled package, we ignore the second request.
2018-10-17 16:24:20 +01:00
James Turner
6ffc501566 Mac: Set CMake OS-X deployment target correctly
Also raises the OS-X min version to 10.9 for libc++ compat
2018-10-17 16:24:15 +01:00
James Turner
9785cadbd0 Fix a debug message left in the terrasync code 2018-10-05 10:41:39 +01:00
263 changed files with 4577 additions and 14200 deletions

2
.gitignore vendored
View File

@@ -15,5 +15,3 @@ install_manifest.txt
build*
Build
CMakeLists.txt.user
3rdparty/expat_2.2.6/
nbproject

View File

@@ -1,7 +1,7 @@
configure_file (
"${PROJECT_SOURCE_DIR}/3rdparty/expat/expat_config_cmake.in"
"${PROJECT_BINARY_DIR}/3rdparty/expat/simgear_expat_config.h"
"${PROJECT_BINARY_DIR}/3rdparty/expat/expat_config.h"
)
set(expat_sources

View File

@@ -18,8 +18,6 @@
#include "amigaconfig.h"
#elif defined(__WATCOMC__)
#include "watcomconfig.h"
#elif defined(HAVE_SIMGEAR_EXPAT_CONFIG_H)
#include "simgear_expat_config.h"
#elif defined(HAVE_EXPAT_CONFIG_H)
#include "expat_config.h"
#endif /* ndef COMPILED_FROM_DSP */

View File

@@ -12,8 +12,6 @@
#include "amigaconfig.h"
#elif defined(__WATCOMC__)
#include "watcomconfig.h"
#elif defined(HAVE_SIMGEAR_EXPAT_CONFIG_H)
#include "simgear_expat_config.h"
#else
#ifdef HAVE_EXPAT_CONFIG_H
#include "expat_config.h"

View File

@@ -12,8 +12,6 @@
#include "amigaconfig.h"
#elif defined(__WATCOMC__)
#include "watcomconfig.h"
#elif defined(HAVE_SIMGEAR_EXPAT_CONFIG_H)
#include "simgear_expat_config.h"
#else
#ifdef HAVE_EXPAT_CONFIG_H
#include "expat_config.h"

View File

@@ -24,7 +24,7 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#if defined(_WINDOWS) || defined(WINDOWS)
#ifdef WINDOWS
# include <winsock2.h> /* includes <windows.h> */
# include <iphlpapi.h> /* for dns server addresses etc */
#else
@@ -53,7 +53,7 @@ static void dns_set_srch_internal(struct dns_ctx *ctx, char *srch) {
dns_add_srch(ctx, srch);
}
#if defined(_WINDOWS) || defined(WINDOWS)
#ifdef WINDOWS
#ifndef NO_IPHLPAPI
/* Apparently, some systems does not have proper headers for IPHLPAIP to work.
@@ -217,7 +217,7 @@ int dns_init(struct dns_ctx *ctx, int do_open) {
ctx = &dns_defctx;
dns_reset(ctx);
#if defined(_WINDOWS) || defined(WINDOWS)
#ifdef WINDOWS
if (dns_initns_iphlpapi(ctx) != 0)
dns_initns_registry(ctx);
/*XXX WINDOWS: probably good to get default domain and search list too...

View File

@@ -24,7 +24,7 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#if defined(_WINDOWS) || defined(WINDOWS)
#ifdef WINDOWS
# include <winsock2.h> /* includes <windows.h> */
# include <ws2tcpip.h> /* needed for struct in6_addr */
#else
@@ -392,7 +392,7 @@ dns_set_tmcbck(struct dns_ctx *ctx, dns_utm_fn *fn, void *data) {
}
static unsigned dns_nonrandom_32(void) {
#if defined(_WINDOWS) || defined(WINDOWS)
#ifdef WINDOWS
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
return ft.dwLowDateTime;
@@ -551,7 +551,7 @@ int dns_open(struct dns_ctx *ctx) {
ctx->dnsc_qstatus = DNS_E_TEMPFAIL;
return -1;
}
#if defined(_WINDOWS) || defined(WINDOWS)
#ifdef WINDOWS
{ unsigned long on = 1;
if (ioctlsocket(sock, FIONBIO, &on) == SOCKET_ERROR) {
closesocket(sock);
@@ -991,7 +991,7 @@ again: /* receive the reply */
* or remote. On local errors, we should stop, while
* remote errors should be ignored (for now anyway).
*/
#if defined(_WINDOWS) || defined(WINDOWS)
#ifdef WINDOWS
if (WSAGetLastError() == WSAEWOULDBLOCK)
#else
if (errno == EAGAIN)

View File

@@ -27,7 +27,7 @@
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#if !defined(_WINDOWS) && !defined(WINDOWS)
#ifndef WINDOWS
# include <sys/types.h>
# include <netinet/in.h>
#endif

View File

@@ -10,9 +10,6 @@ if(COMMAND cmake_policy)
if(POLICY CMP0067)
cmake_policy(SET CMP0067 NEW)
endif()
if(POLICY CMP0093)
cmake_policy(SET CMP0093 NEW)
endif()
endif()
@@ -137,7 +134,6 @@ if (NOT ENABLE_SIMD AND ENABLE_SIMD_CODE)
endif()
include (DetectArch)
include (ExportDebugSymbols)
# until the fstream fix is applied and generally available in OSG,
# keep the compatability link option as the default
@@ -154,7 +150,7 @@ endif()
if (MSVC)
GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_BINARY_DIR} DIRECTORY)
GET_FILENAME_COMPONENT(PARENT_DIR ${PROJECT_BINARY_DIR} PATH)
if (CMAKE_CL_64)
SET(TEST_3RDPARTY_DIR "${PARENT_DIR}/3rdparty.x64")
else (CMAKE_CL_64)
@@ -165,11 +161,6 @@ if (MSVC)
else (EXISTS ${TEST_3RDPARTY_DIR})
set(MSVC_3RDPARTY_ROOT NOT_FOUND CACHE PATH "Location where the third-party dependencies are extracted")
endif (EXISTS ${TEST_3RDPARTY_DIR})
# override CMake default RelWithDebInfo flags. This is important to ensure
# good performance
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "/Zi /O2 /Ob2 /D NDEBUG")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "/Zi /O2 /Ob2 /D NDEBUG")
else (MSVC)
set(MSVC_3RDPARTY_ROOT NOT_FOUND CACHE PATH "Location where the third-party dependencies are extracted")
endif (MSVC)
@@ -182,17 +173,15 @@ if (MSVC AND MSVC_3RDPARTY_ROOT)
set( OSG_MSVC "msvc" )
if (${MSVC_VERSION_MAJOR} EQUAL "19")
if (${MSVC_VERSION_MINOR} GREATER_EQUAL "20")
set( OSG_MSVC ${OSG_MSVC}142 )
elseif (${MSVC_VERSION_MINOR} GREATER_EQUAL "10")
set( OSG_MSVC ${OSG_MSVC}141 )
else ()
if (${MSVC_VERSION_MINOR} EQUAL "00")
set( OSG_MSVC ${OSG_MSVC}140 )
else ()
set( OSG_MSVC ${OSG_MSVC}141 )
endif ()
elseif (${MSVC_VERSION_MAJOR} EQUAL "18")
set( OSG_MSVC ${OSG_MSVC}120 )
else ()
message(FATAL_ERROR "Visual Studio 2013 or higher is required")
message(FATAL_ERROR "Visual Studio 2013/15/17 is required")
endif ()
if (CMAKE_CL_64)
@@ -209,7 +198,7 @@ if (MSVC AND MSVC_3RDPARTY_ROOT)
# if this variable was not set by the user, set it to 3rdparty root's
# parent dir, which is the normal location for people using our
# windows-3rd-party repo
get_filename_component(MSVC_ROOT_PARENT_DIR ${MSVC_3RDPARTY_ROOT} DIRECTORY)
GET_FILENAME_COMPONENT(MSVC_ROOT_PARENT_DIR ${MSVC_3RDPARTY_ROOT} PATH)
set(BOOST_INCLUDEDIR ${MSVC_ROOT_PARENT_DIR})
message(STATUS "BOOST_INCLUDEDIR is ${BOOST_INCLUDEDIR}")
endif()
@@ -282,6 +271,9 @@ if (SYSTEM_EXPAT)
else()
message(STATUS "Using built-in expat code")
# XML_STATIC is important to avoid sg_expat_external.h
# declaring symbols as declspec(import)
add_definitions(-DHAVE_EXPAT_CONFIG_H -DXML_STATIC)
set(EXPAT_INCLUDE_DIRS
${PROJECT_SOURCE_DIR}/3rdparty/expat
${PROJECT_BINARY_DIR}/3rdparty/expat)
@@ -300,10 +292,11 @@ endif()
if(ENABLE_RTI)
find_package(PkgConfig)
if(PKG_CONFIG_FOUND)
SET(ENV{PKG_CONFIG_PATH} "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/pkgconfig:$ENV{PKG_CONFIG_PATH}")
SET(ENV{PKG_CONFIG_PATH} "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig:$ENV{PKG_CONFIG_PATH}")
pkg_check_modules(RTI hla-rti13)
endif(PKG_CONFIG_FOUND)
if(RTI_FOUND)
SET(RTI_INCLUDE_DIR "${RTI_INCLUDE_DIRS}")
message(STATUS "RTI: ENABLED")
else()
message(STATUS "RTI: DISABLED")
@@ -445,18 +438,15 @@ if (CLANG)
# fix Boost compilation :(
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
# override CMake default RelWithDebInfo flags.
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -g -DNDEBUG")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 -g -DNDEBUG")
if (ENABLE_SIMD)
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_C_FLAGS
"${CMAKE_C_FLAGS} -O0 -fno-omit-frame-pointer -fno-inline-functions")
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -O0 -fno-omit-frame-pointer -fno-inline-functions")
elseif (ENABLE_SIMD)
if (X86 OR X86_64)
set(CMAKE_C_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse -ftree-vectorize -ftree-slp-vectorize")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -msse2 -mfpmath=sse -ftree-vectorize -ftree-slp-vectorize")
# propogate to the RelWithDebInfo flags
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELEASE} -g -DNDEBUG")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELEASE} -g -DNDEBUG")
endif()
endif()
endif()
@@ -531,10 +521,6 @@ include(CheckCXXFeatures)
# ahead of system-installed libs
include_directories(BEFORE ${PROJECT_BINARY_DIR}/simgear)
if(${CMAKE_SYSTEM_NAME} MATCHES "OpenBSD")
include_directories("/usr/X11R6/include")
endif()
add_definitions(-DHAVE_CONFIG_H)
# configure a header file to pass some of the CMake settings

View File

@@ -46,17 +46,11 @@ set(BOOST_TEST_TARGET_PREFIX "test")
if(NOT Boost_FOUND)
find_package(Boost 1.34.0 QUIET)
endif()
if (NOT Boost_VERSION_MACRO)
# Compatibility with pre CMP0093 (CMake 3.15)
set(Boost_VERSION_MACRO ${Boost_VERSION})
endif()
if("${Boost_VERSION_MACRO}0" LESS "1034000")
if("${Boost_VERSION}0" LESS "1034000")
set(_shared_msg
"NOTE: boost::test-based targets and tests cannot "
"be added: boost >= 1.34.0 required but not found. "
"(found: '${Boost_VERSION_MACRO}'; want >=103400) ")
"(found: '${Boost_VERSION}'; want >=103400) ")
if(ENABLE_TESTS)
message(FATAL_ERROR
${_shared_msg}
@@ -72,7 +66,7 @@ endif()
include(GetForceIncludeDefinitions)
include(CopyResourcesToBuildTree)
if(Boost_FOUND AND NOT "${Boost_VERSION_MACRO}0" LESS "1034000")
if(Boost_FOUND AND NOT "${Boost_VERSION}0" LESS "1034000")
set(_boosttesttargets_libs)
set(_boostConfig "BoostTestTargetsIncluded.h")
if(NOT Boost_UNIT_TEST_FRAMEWORK_LIBRARY)
@@ -86,7 +80,7 @@ if(Boost_FOUND AND NOT "${Boost_VERSION_MACRO}0" LESS "1034000")
set(_boostConfig "BoostTestTargetsDynamic.h")
endif()
endif()
get_filename_component(_moddir ${CMAKE_CURRENT_LIST_FILE} DIRECTORY)
get_filename_component(_moddir ${CMAKE_CURRENT_LIST_FILE} PATH)
configure_file("${_moddir}/${_boostConfig}"
"${CMAKE_CURRENT_BINARY_DIR}/BoostTestTargetConfig.h"
COPYONLY)
@@ -135,7 +129,7 @@ function(add_boost_test _name)
"Syntax error in use of add_boost_test: at least one source file required!")
endif()
if(Boost_FOUND AND NOT "${Boost_VERSION_MACRO}0" LESS "1034000")
if(Boost_FOUND AND NOT "${Boost_VERSION}0" LESS "1034000")
include_directories(${Boost_INCLUDE_DIRS})
@@ -227,7 +221,7 @@ function(add_boost_test _name)
set(_test_command ${_target_name})
endif()
if(TESTS AND ( "${Boost_VERSION_MACRO}" VERSION_GREATER "103799" ))
if(TESTS AND ( "${Boost_VERSION}" VERSION_GREATER "103799" ))
foreach(_test ${TESTS})
add_test(
${_name}-${_test}

View File

@@ -30,12 +30,12 @@ function(copy_resources_to_build_tree _target)
endif()
get_target_property(_path ${_target} LOCATION)
get_filename_component(_path "${_path}" DIRECTORY)
get_filename_component(_path "${_path}" PATH)
if(NOT MSVC AND NOT "${CMAKE_GENERATOR}" MATCHES "Makefiles")
foreach(_config ${CMAKE_CONFIGURATION_TYPES})
get_target_property(_path${_config} ${_target} LOCATION_${_config})
get_filename_component(_path${_config} "${_path${_config}}" DIRECTORY)
get_filename_component(_path${_config} "${_path${_config}}" PATH)
add_custom_command(TARGET ${_target}
POST_BUILD
COMMAND

View File

@@ -1,26 +0,0 @@
# placehodler target for other ones to depend upon
add_custom_target(
debug_symbols
)
function(export_debug_symbols target)
if (NOT SIMGEAR_SHARED)
return()
endif()
if (APPLE)
add_custom_target(${target}.dSYM
COMMENT "Generating dSYM files for ${target}"
COMMAND dsymutil --out=${target}.dSYM $<TARGET_FILE:${target}>
DEPENDS $<TARGET_FILE:${target}>
)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${target}.dSYM DESTINATION symbols OPTIONAL)
add_dependencies(debug_symbols ${target}.dSYM)
endif()
endfunction()

568
Doxyfile

File diff suppressed because it is too large Load Diff

View File

@@ -18,16 +18,6 @@ set(USE_AEONWAVE @USE_AEONWAVE@)
set(ENABLE_SIMD @ENABLE_SIMD@)
# OpenRTI support
set(ENABLE_RTI @ENABLE_RTI@)
if(ENABLE_RTI)
set(RTI_FOUND @RTI_FOUND@)
if(RTI_FOUND)
set(RTI_INCLUDE_DIRS @RTI_INCLUDE_DIRS@)
set(RTI_LDFLAGS @RTI_LDFLAGS@)
endif(RTI_FOUND)
endif(ENABLE_RTI)
# Alternative terrain engine based on pagedLOD
set(ENABLE_GDAL @ENABLE_GDAL@)

View File

@@ -6,7 +6,6 @@ foreach( mylibfolder
bvh
debug
embedded_resources
emesary
ephemeris
io
magvar
@@ -65,9 +64,6 @@ if(SIMGEAR_SHARED)
set_property(TARGET SimGearScene PROPERTY VERSION ${SIMGEAR_VERSION})
set_property(TARGET SimGearScene PROPERTY SOVERSION ${SIMGEAR_SOVERSION})
endif()
export_debug_symbols(SimGearCore)
export_debug_symbols(SimGearScene)
else()
message(STATUS "Library building mode: STATIC LIBRARIES")
@@ -118,22 +114,11 @@ target_include_directories(SimGearCore BEFORE PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include>)
# so simgear/simgear_config.h is found
target_include_directories(SimGearCore BEFORE PUBLIC
$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>
$<INSTALL_INTERFACE:include>)
target_include_directories(SimGearCore PUBLIC
${Boost_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIR})
target_include_directories(SimGearCore PRIVATE
${EXPAT_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS})
if (NOT SYSTEM_EXPAT)
# XML_STATIC is important to avoid sg_expat_external.h
# declaring symbols as declspec(import)
target_compile_definitions(SimGearCore PRIVATE HAVE_SIMGEAR_EXPAT_CONFIG_H XML_STATIC)
endif()
install(TARGETS SimGearCore
EXPORT SimGearTargets
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
@@ -158,10 +143,9 @@ if (NOT SIMGEAR_HEADLESS)
endif()
endif()
# we expose ZLib in some of our headers
target_link_libraries(SimGearCore PUBLIC ${ZLIB_LIBRARY})
target_link_libraries(SimGearCore PRIVATE
target_link_libraries(SimGearCore
${ZLIB_LIBRARY}
${RT_LIBRARY}
${DL_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
@@ -170,29 +154,29 @@ target_link_libraries(SimGearCore PRIVATE
${WINSOCK_LIBRARY})
if(SYSTEM_EXPAT)
target_link_libraries(SimGearCore PRIVATE ${EXPAT_LIBRARIES})
target_link_libraries(SimGearCore
${EXPAT_LIBRARIES})
endif()
if(ENABLE_DNS AND SYSTEM_UDNS)
target_link_libraries(SimGearCore PRIVATE ${UDNS_LIBRARIES})
target_link_libraries(SimGearCore
${UDNS_LIBRARIES})
endif()
if(NOT SIMGEAR_HEADLESS)
target_include_directories(SimGearScene PRIVATE ${PROJECT_SOURCE_DIR}/simgear/canvas/ShivaVG/include)
target_link_libraries(SimGearScene PUBLIC
target_link_libraries(SimGearScene
SimGearCore
${OPENSCENEGRAPH_LIBRARIES}
)
target_link_libraries(SimGearScene PRIVATE
${ZLIB_LIBRARY}
${OPENSCENEGRAPH_LIBRARIES}
${OPENAL_LIBRARY}
${OPENGL_LIBRARY}
${JPEG_LIBRARY})
if(ENABLE_GDAL)
target_link_libraries(SimGearScene PRIVATE ${GDAL_LIBRARIES})
target_link_libraries(SimGearScene
${GDAL_LIBRARIES})
endif()
# only actually needed by canvas/KeyboardEvent.cxx
@@ -204,5 +188,5 @@ if(ENABLE_RTI)
set_property(SOURCE hla/RTI13InteractionClass.cxx hla/RTI13ObjectClass.cxx
hla/RTI13ObjectInstance.cxx hla/RTI13Federate.cxx
hla/RTI13FederateFactory.cxx
APPEND PROPERTY COMPILE_FLAGS "-I${RTI_INCLUDE_DIRS}")
APPEND PROPERTY COMPILE_FLAGS "-I${RTI_INCLUDE_DIR}")
endif(ENABLE_RTI)

View File

@@ -20,9 +20,9 @@
#include "BVHPager.hxx"
#include <list>
#include <mutex>
#include <simgear/threads/SGThread.hxx>
#include <simgear/threads/SGGuard.hxx>
#include "BVHPageNode.hxx"
#include "BVHPageRequest.hxx"
@@ -37,12 +37,12 @@ struct BVHPager::_PrivateData : protected SGThread {
struct _LockedQueue {
void _push(const _Request& request)
{
std::lock_guard<std::mutex> scopeLock(_mutex);
SGGuard<SGMutex> scopeLock(_mutex);
_requestList.push_back(request);
}
_Request _pop()
{
std::lock_guard<std::mutex> scopeLock(_mutex);
SGGuard<SGMutex> scopeLock(_mutex);
if (_requestList.empty())
return _Request();
_Request request;
@@ -51,7 +51,7 @@ struct BVHPager::_PrivateData : protected SGThread {
return request;
}
private:
std::mutex _mutex;
SGMutex _mutex;
_RequestList _requestList;
};
@@ -62,7 +62,7 @@ struct BVHPager::_PrivateData : protected SGThread {
}
void _push(const _Request& request)
{
std::lock_guard<std::mutex> scopeLock(_mutex);
SGGuard<SGMutex> scopeLock(_mutex);
bool needSignal = _requestList.empty();
_requestList.push_back(request);
if (needSignal)
@@ -70,7 +70,7 @@ struct BVHPager::_PrivateData : protected SGThread {
}
_Request _pop()
{
std::lock_guard<std::mutex> scopeLock(_mutex);
SGGuard<SGMutex> scopeLock(_mutex);
while (_requestList.empty())
_waitCondition.wait(_mutex);
_Request request;
@@ -79,7 +79,7 @@ struct BVHPager::_PrivateData : protected SGThread {
return request;
}
private:
std::mutex _mutex;
SGMutex _mutex;
SGWaitCondition _waitCondition;
_RequestList _requestList;
};

View File

@@ -28,39 +28,42 @@ namespace simgear
namespace canvas
{
class CanvasMgr : public PropertyBasedMgr
{
public:
/**
* @param node Root node of branch used to control canvasses
*/
CanvasMgr(SGPropertyNode_ptr node);
class CanvasMgr:
public PropertyBasedMgr
{
public:
/**
* Create a new canvas
*
* @param name Name of the new canvas
*/
CanvasPtr createCanvas(const std::string& name = "");
/**
* @param node Root node of branch used to control canvasses
*/
CanvasMgr(SGPropertyNode_ptr node);
/**
* Get ::Canvas by index
*
* @param index Index of texture node in /canvas/by-index/
*/
CanvasPtr getCanvas(size_t index) const;
/**
* Create a new canvas
*
* @param name Name of the new canvas
*/
CanvasPtr createCanvas(const std::string& name = "");
/**
* Get ::Canvas by name
*
* @param name Value of child node "name" in
* /canvas/by-index/texture[i]/name
*/
CanvasPtr getCanvas(const std::string& name) const;
/**
* Get ::Canvas by index
*
* @param index Index of texture node in /canvas/by-index/
*/
CanvasPtr getCanvas(size_t index) const;
protected:
void elementCreated(PropertyBasedElementPtr element) override;
};
/**
* Get ::Canvas by name
*
* @param name Value of child node "name" in
* /canvas/by-index/texture[i]/name
*/
CanvasPtr getCanvas(const std::string& name) const;
protected:
void elementCreated(PropertyBasedElementPtr element) override;
};
} // namespace canvas
} // namespace simgear

View File

@@ -68,8 +68,8 @@ namespace canvas
Element* parent = 0 );
virtual ~Window();
void update(double delta_time_sec) override;
void valueChanged(SGPropertyNode* node) override;
virtual void update(double delta_time_sec);
virtual void valueChanged(SGPropertyNode* node);
const SGVec2<float> getPosition() const;
const SGRect<float> getScreenRegion() const;
@@ -84,8 +84,8 @@ namespace canvas
bool isResizable() const;
bool isCapturingEvents() const;
void setVisible(bool visible) override;
bool isVisible() const override;
virtual void setVisible(bool visible);
virtual bool isVisible() const;
/**
* Moves window on top of all other windows with the same z-index.

View File

@@ -250,16 +250,10 @@ namespace canvas
if( !texture )
{
// It shouldn't be necessary to allocate an image for the
// texture that is the target of dynamic rendering, but
// otherwise OSG won't construct all the mipmaps for the texture
// and dynamic mipmap generation doesn't work.
osg::Image* image = new osg::Image;
image->allocateImage(_size_x, _size_y, 1, GL_RGBA, GL_UNSIGNED_BYTE);
texture = new osg::Texture2D;
texture->setResizeNonPowerOfTwoHint(false);
texture->setImage(image);
texture->setUnRefImageDataAfterApply(true);
texture->setTextureSize(_size_x, _size_y);
texture->setInternalFormat(GL_RGBA);
}
updateSampling();

View File

@@ -31,11 +31,6 @@
// FreeBSD
#define VG_API_FREEBSD
#elif defined(__OpenBSD__)
// FreeBSD
#define VG_API_OPENBSD
#else
// Unsupported system

View File

@@ -34,7 +34,7 @@
#include <math.h>
#include <float.h>
#if !defined(VG_API_MACOSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
#if !defined(VG_API_MACOSX) && !defined(__FreeBSD__)
# include <malloc.h>
#endif
@@ -161,7 +161,7 @@ SHfloat getMaxFloat();
/* OpenGL headers */
#if defined(VG_API_LINUX) || defined(VG_API_FREEBSD) || defined(VG_API_OPENBSD)
#if defined(VG_API_LINUX) || defined(VG_API_FREEBSD)
#include <GL/gl.h>
#include <GL/glx.h>
#elif defined(VG_API_MACOSX)

View File

@@ -1193,7 +1193,7 @@ VG_API_CALL VGboolean vgInterpolatePath(VGPath dstPath, VGPath startPath,
SHfloat *procData1, *procData2;
SHint procSegCount1=0, procSegCount2=0;
SHint procDataCount1=0, procDataCount2=0;
SHuint8 *newSegs, *newData=0;
SHuint8 *newSegs, *newData;
void *userData[4];
SHint segment1, segment2;
SHint segindex, s,d,i;

View File

@@ -26,9 +26,11 @@
#include <osg/ref_ptr>
#include <osgText/Font>
#include <functional>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <map>
#include <memory>
#include <vector>
namespace simgear
@@ -60,8 +62,8 @@ namespace canvas
#define SG_FWD_DECL(name)\
class name;\
typedef std::shared_ptr<name> name##Ptr;\
typedef std::weak_ptr<name> name##WeakPtr;
typedef boost::shared_ptr<name> name##Ptr;\
typedef boost::weak_ptr<name> name##WeakPtr;
SG_FWD_DECL(Placement)
SG_FWD_DECL(SystemAdapter)
@@ -83,10 +85,10 @@ namespace canvas
typedef osg::ref_ptr<osgText::Font> FontPtr;
typedef std::vector<PlacementPtr> Placements;
typedef std::function<Placements( SGPropertyNode*,
CanvasPtr )> PlacementFactory;
typedef boost::function<Placements( SGPropertyNode*,
CanvasPtr )> PlacementFactory;
typedef std::function<void(const EventPtr&)> EventListener;
typedef boost::function<void(const EventPtr&)> EventListener;
} // namespace canvas
} // namespace simgear

View File

@@ -29,6 +29,9 @@
#include <osg/BoundingBox>
#include <osg/MatrixTransform>
#include <boost/bind.hpp>
#include <boost/function.hpp>
namespace osg
{
class Drawable;
@@ -59,9 +62,9 @@ namespace canvas
OSGUserData(ElementPtr element);
};
typedef std::function<bool(Element&, const SGPropertyNode*)>
typedef boost::function<bool(Element&, const SGPropertyNode*)>
StyleSetterFunc;
typedef std::function<void(Element&, const SGPropertyNode*)>
typedef boost::function<void(Element&, const SGPropertyNode*)>
StyleSetterFuncUnchecked;
struct StyleSetter:
public SGReferenced
@@ -316,7 +319,7 @@ namespace canvas
StyleSetter
addStyle( const std::string& name,
const std::string& type,
const std::function<void (Derived&, T2)>& setter,
const boost::function<void (Derived&, T2)>& setter,
bool inheritable = true )
{
StyleInfo& style_info = _style_setters[ name ];
@@ -342,10 +345,13 @@ namespace canvas
if( style->func )
style = style->next = new StyleSetter;
style->func = std::bind(&type_match<Derived>::call,
std::placeholders::_1,
std::placeholders::_2,
bindStyleSetter<T1>(name, setter));
style->func = boost::bind
(
&type_match<Derived>::call,
_1,
_2,
bindStyleSetter<T1>(name, setter)
);
return *style;
}
@@ -357,7 +363,7 @@ namespace canvas
StyleSetter
addStyle( const std::string& name,
const std::string& type,
const std::function<void (Derived&, T)>& setter,
const boost::function<void (Derived&, T)>& setter,
bool inheritable = true )
{
return addStyle<T, T>(name, type, setter, inheritable);
@@ -378,7 +384,7 @@ namespace canvas
(
name,
type,
std::function<void (Derived&, T)>(setter),
boost::function<void (Derived&, T)>(setter),
inheritable
);
}
@@ -399,7 +405,7 @@ namespace canvas
(
name,
type,
std::function<void (Derived&, T2)>(setter),
boost::function<void (Derived&, T2)>(setter),
inheritable
);
}
@@ -418,7 +424,7 @@ namespace canvas
(
name,
type,
std::function<void (Derived&, const std::string&)>(setter),
boost::function<void (Derived&, const std::string&)>(setter),
inheritable
);
}
@@ -481,7 +487,7 @@ namespace canvas
StyleSetter
addStyle( const std::string& name,
const std::string& type,
const std::function<void (Other&, T2)>& setter,
const boost::function<void (Other&, T2)>& setter,
OtherRef Derived::*instance_ref,
bool inheritable = true )
{
@@ -511,7 +517,7 @@ namespace canvas
(
name,
type,
std::function<void (Other&, const std::string&)>(setter),
boost::function<void (Other&, const std::string&)>(setter),
instance_ref,
inheritable
);
@@ -519,37 +525,44 @@ namespace canvas
template<typename T, class Derived, class Other, class OtherRef>
static
std::function<void (Derived&, T)>
boost::function<void (Derived&, T)>
bindOther( void (Other::*setter)(T), OtherRef Derived::*instance_ref )
{
return std::bind(setter,
std::bind(instance_ref, std::placeholders::_1),
std::placeholders::_2);
return boost::bind(setter, boost::bind(instance_ref, _1), _2);
}
template<typename T, class Derived, class Other, class OtherRef>
static
std::function<void (Derived&, T)>
bindOther( const std::function<void (Other&, T)>& setter,
boost::function<void (Derived&, T)>
bindOther( const boost::function<void (Other&, T)>& setter,
OtherRef Derived::*instance_ref )
{
return std::bind(setter,
std::bind(&reference_from_pointer<Other, OtherRef>,
std::bind(instance_ref, std::placeholders::_1)),
std::placeholders::_2);
return boost::bind
(
setter,
boost::bind
(
&reference_from_pointer<Other, OtherRef>,
boost::bind(instance_ref, _1)
),
_2
);
}
template<typename T1, typename T2, class Derived>
static
StyleSetterFuncUnchecked
bindStyleSetter( const std::string& name,
const std::function<void (Derived&, T2)>& setter )
const boost::function<void (Derived&, T2)>& setter )
{
return std::bind(setter,
// We will only call setters with Derived instances, so we can safely
// cast here.
std::bind(&derived_cast<Derived>, std::placeholders::_1),
std::bind(&getValue<T1>, std::placeholders::_2));
return boost::bind
(
setter,
// We will only call setters with Derived instances, so we can safely
// cast here.
boost::bind(&derived_cast<Derived>, _1),
boost::bind(&getValue<T1>, _2)
);
}
bool isStyleEmpty(const SGPropertyNode* child) const;

View File

@@ -838,143 +838,5 @@ namespace canvas
return false;
}
void Image::fillRect(const SGRect<int>& rect, const std::string& c)
{
osg::Vec4 color(1,1,1,1);
if(!c.empty() && !parseColor(c, color))
return;
fillRect(rect, color);
}
void fillRow(GLubyte* row, GLuint pixel, GLuint width, GLuint pixelBytes)
{
GLubyte* dst = row;
for (int x = 0; x < width; ++x) {
memcpy(dst, &pixel, pixelBytes);
dst += pixelBytes;
}
}
SGRect<int> intersectRect(const SGRect<int>& a, const SGRect<int>& b)
{
SGVec2<int> m1 = max(a.getMin(), b.getMin());
SGVec2<int> m2 = min(a.getMax(), b.getMax());
return SGRect<int>(m1, m2);
}
void Image::fillRect(const SGRect<int>& rect, const osg::Vec4& color)
{
osg::ref_ptr<osg::Image> image = _texture->getImage();
if (!image) {
allocateImage();
image = _texture->getImage();
}
if (image->getDataVariance() != osg::Object::DYNAMIC) {
image->setDataVariance(osg::Object::DYNAMIC);
}
const auto format = image->getInternalTextureFormat();
auto clippedRect = intersectRect(rect, SGRect<int>(0, 0, image->s(), image->t()));
if ((clippedRect.width() == 0) || (clippedRect.height() == 0)) {
return;
}
GLubyte* rowData = nullptr;
size_t rowByteSize = 0;
GLuint pixelWidth = clippedRect.width();
GLuint pixel = 0;
GLuint pixelBytes = 0;
switch (format) {
case GL_RGBA8:
case GL_RGBA:
rowByteSize = pixelWidth * 4;
rowData = static_cast<GLubyte*>(alloca(rowByteSize));
// assume litte-endian, so read out backwards, hence when we memcpy
// the data, it ends up in RGBA order
pixel = color.asABGR();
pixelBytes = 4;
fillRow(rowData, pixel, pixelWidth, pixelBytes);
break;
case GL_RGB8:
case GL_RGB:
rowByteSize = pixelWidth * 3;
rowData = static_cast<GLubyte*>(alloca(rowByteSize));
pixel = color.asABGR();
pixelBytes = 3;
fillRow(rowData, pixel, pixelWidth, pixelBytes);
break;
default:
SG_LOG(SG_IO, SG_WARN, "Image::fillRect: unsupported internal image format:" << format);
return;
}
for (int row=clippedRect.t(); row < clippedRect.b(); ++row) {
GLubyte* imageData = image->data(clippedRect.l(), row);
memcpy(imageData, rowData, rowByteSize);
}
image->dirty();
auto c = getCanvas().lock();
c->enableRendering(true); // force a repaint
}
void Image::setPixel(int x, int y, const std::string& c)
{
osg::Vec4 color(1,1,1,1);
if(!c.empty() && !parseColor(c, color))
return;
setPixel(x, y, color);
}
void Image::setPixel(int x, int y, const osg::Vec4& color)
{
osg::ref_ptr<osg::Image> image = _texture->getImage();
if (!image) {
allocateImage();
image = _texture->getImage();
}
if (image->getDataVariance() != osg::Object::DYNAMIC) {
image->setDataVariance(osg::Object::DYNAMIC);
}
image->setColor(color, x, y);
}
void Image::dirtyPixels()
{
osg::ref_ptr<osg::Image> image = _texture->getImage();
if (!image)
return;
image->dirty();
auto c = getCanvas().lock();
c->enableRendering(true); // force a repaint
}
void Image::allocateImage()
{
osg::Image* image = new osg::Image;
// default to RGBA
image->allocateImage(_node->getIntValue("size[0]"), _node->getIntValue("size[1]"), 1, GL_RGBA, GL_UNSIGNED_BYTE);
image->setInternalTextureFormat(GL_RGBA);
_texture->setImage(image);
}
osg::ref_ptr<osg::Image> Image::getImage() const
{
if (!_texture)
return {};
return _texture->getImage();
}
} // namespace canvas
} // namespace simgear

View File

@@ -101,28 +101,6 @@ namespace canvas
*/
void setSourceRect(const SGRect<float>& sourceRect);
/**
* fill the specified rectangle of the image, with an RGB value
*/
void fillRect(const SGRect<int>& rect, const std::string& color);
/**
* fill the specified rectangle of the image, with an RGB value
*/
void fillRect(const SGRect<int>& rect, const osg::Vec4& color);
void setPixel(int x, int y, const std::string& color);
void setPixel(int x, int y, const osg::Vec4& color);
/**
* mark the image pixels as modified, so the canvas is re-painted
*/
void dirtyPixels();
osg::ref_ptr<osg::Image> getImage() const;
// void setRow(int row, int offset, )
protected:
enum ImageAttributes
{
@@ -147,8 +125,6 @@ namespace canvas
HTTP::Request& request,
const std::string& type );
void allocateImage();
osg::ref_ptr<osg::Texture2D> _texture;
// TODO optionally forward events to canvas
CanvasWeakPtr _src_canvas;

View File

@@ -53,31 +53,26 @@ namespace canvas
TextLine lineAt(size_t i) const;
/// Get nearest line to given y-coordinate
#if OSG_VERSION_LESS_THAN(3,6,5)
TextLine nearestLine(float pos_y) const;
SGVec2i sizeForWidth(int w) const;
#else
TextLine nearestLine(float pos_y);
SGVec2i sizeForWidth(int w);
#endif
SGVec2i sizeForWidth(int w) const;
osg::BoundingBox
#if OSG_VERSION_LESS_THAN(3,3,2)
osg::BoundingBox computeBound() const override;
computeBound()
#else
osg::BoundingBox computeBoundingBox() const override;
computeBoundingBox()
#endif
const override;
protected:
friend class TextLine;
canvas::Text *_text_element;
#if OSG_VERSION_LESS_THAN(3,5,6)
void computePositions(unsigned int contextID) const override;
#else
void computePositionsImplementation() override;
#endif
};
void computePositions(unsigned int contextID) const override;
};
class TextLine
{
@@ -127,7 +122,6 @@ namespace canvas
_quads = &text->_textureGlyphQuadMap.begin()->second;
#if OSG_VERSION_LESS_THAN(3,5,6)
GlyphQuads::LineNumbers const& line_numbers = _quads->_lineNumbers;
GlyphQuads::LineNumbers::const_iterator begin_it =
std::lower_bound(line_numbers.begin(), line_numbers.end(), _line);
@@ -139,9 +133,6 @@ namespace canvas
_begin = begin_it - line_numbers.begin();
_end = std::upper_bound(begin_it, line_numbers.end(), _line)
- line_numbers.begin();
#else
// TODO: Need 3.5.6 version of this
#endif
}
//----------------------------------------------------------------------------
@@ -170,40 +161,34 @@ namespace canvas
if( empty() )
return pos;
#if OSG_VERSION_GREATER_OR_EQUAL(3,5,6)
// TODO: need 3.5.6 version of this.
#else
#if OSG_VERSION_LESS_THAN(3,3,5)
GlyphQuads::Coords2 const& coords = _quads->_coords;
GlyphQuads::Coords2 const& coords = _quads->_coords;
#else
GlyphQuads::Coords2 refCoords = _quads->_coords;
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
GlyphQuads::Coords2 refCoords = _quads->_coords;
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
#endif
size_t global_i = _begin + i;
size_t global_i = _begin + i;
if( global_i == _begin )
// before first character of line
pos.x() = coords[_begin * 4].x();
else if( global_i == _end )
// After Last character of line
pos.x() = coords[(_end - 1) * 4 + 2].x();
else
{
float prev_l = coords[(global_i - 1) * 4].x(),
prev_r = coords[(global_i - 1) * 4 + 2].x(),
cur_l = coords[global_i * 4].x();
if (global_i == _begin)
// before first character of line
pos.x() = coords[_begin * 4].x();
else if (global_i == _end)
// After Last character of line
pos.x() = coords[(_end - 1) * 4 + 2].x();
if( prev_l == prev_r )
// If previous character width is zero set to begin of next character
// (Happens eg. with spaces)
pos.x() = cur_l;
else
{
float prev_l = coords[(global_i - 1) * 4].x(),
prev_r = coords[(global_i - 1) * 4 + 2].x(),
cur_l = coords[global_i * 4].x();
if (prev_l == prev_r)
// If previous character width is zero set to begin of next character
// (Happens eg. with spaces)
pos.x() = cur_l;
else
// position at center between characters
pos.x() = 0.5 * (prev_r + cur_l);
}
#endif
// position at center between characters
pos.x() = 0.5 * (prev_r + cur_l);
}
return pos;
}
@@ -211,22 +196,17 @@ namespace canvas
//----------------------------------------------------------------------------
osg::Vec2 TextLine::nearestCursor(float x) const
{
if (empty())
if( empty() )
return cursorPos(0);
#if OSG_VERSION_GREATER_OR_EQUAL(3,5,6)
// TODO: need 3.5.7 version of this.
return cursorPos(0);
#else
#if OSG_VERSION_LESS_THAN(3,3,5)
GlyphQuads::Glyphs const& glyphs = _quads->_glyphs;
#if OSG_VERSION_LESS_THAN(3,3,5)
GlyphQuads::Coords2 const& coords = _quads->_coords;
#else
GlyphQuads::Coords2 refCoords = _quads->_coords;
GlyphQuads::Coords2::element_type &coords = *refCoords.get();
#endif
GlyphQuads::Glyphs const& glyphs = _quads->_glyphs;
float const HIT_FRACTION = 0.6;
float const character_width = _text->getCharacterHeight()
* _text->getCharacterAspectRatio();
@@ -245,7 +225,6 @@ namespace canvas
}
return cursorPos(i - _begin);
#endif
}
//----------------------------------------------------------------------------
@@ -324,16 +303,9 @@ namespace canvas
}
//----------------------------------------------------------------------------
#if OSG_VERSION_LESS_THAN(3,6,5)
TextLine Text::TextOSG::nearestLine(float pos_y) const
{
osgText::Font const* font = getActiveFont();
#else
TextLine Text::TextOSG::nearestLine(float pos_y)
{
auto font = getActiveFont();
#endif
if( !font || lineCount() <= 0 )
return TextLine(0, this);
@@ -355,21 +327,12 @@ namespace canvas
// simplified version of osgText::Text::computeGlyphRepresentation() to
// just calculate the size for a given weight. Glpyh calculations/creating
// is not necessary for this...
#if OSG_VERSION_LESS_THAN(3,6,5)
SGVec2i Text::TextOSG::sizeForWidth(int w) const
#else
SGVec2i Text::TextOSG::sizeForWidth(int w)
#endif
{
if( _text.empty() )
return SGVec2i(0, 0);
#if OSG_VERSION_LESS_THAN(3,6,5)
osgText::Font* activefont = const_cast<osgText::Font*>(getActiveFont());
#else
auto activefont = getActiveFont();
#endif
if( !activefont )
return SGVec2i(-1, -1);
@@ -649,16 +612,19 @@ namespace canvas
}
//----------------------------------------------------------------------------
osg::BoundingBox
#if OSG_VERSION_LESS_THAN(3,3,2)
osg::BoundingBox Text::TextOSG::computeBound() const
Text::TextOSG::computeBound()
#else
osg::BoundingBox Text::TextOSG::computeBoundingBox() const
Text::TextOSG::computeBoundingBox()
#endif
const
{
osg::BoundingBox bb =
#if OSG_VERSION_LESS_THAN(3,3,2)
osg::BoundingBox bb = osgText::Text::computeBound();
osgText::Text::computeBound();
#else
osg::BoundingBox bb = osgText::Text::computeBoundingBox();
osgText::Text::computeBoundingBox();
#endif
#if OSG_VERSION_LESS_THAN(3,1,0)
@@ -674,7 +640,7 @@ namespace canvas
return bb;
}
#if OSG_VERSION_LESS_THAN(3,5,6)
//----------------------------------------------------------------------------
void Text::TextOSG::computePositions(unsigned int contextID) const
{
if( _textureGlyphQuadMap.empty() || _layout == VERTICAL )
@@ -744,14 +710,6 @@ namespace canvas
return osgText::Text::computePositions(contextID);
}
#else
void Text::TextOSG::computePositionsImplementation()
{
TextBase::computePositionsImplementation();
}
#endif
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
const std::string Text::TYPE_NAME = "text";

View File

@@ -18,9 +18,6 @@
#include <simgear_config.h>
#include "Layout.hxx"
#include <algorithm>
#include <simgear/debug/logstream.hxx>
namespace simgear

View File

@@ -150,7 +150,7 @@ namespace canvas
//----------------------------------------------------------------------------
bool NasalWidget::hasHeightForWidth() const
{
return _height_for_width || _min_height_for_width;
return !_height_for_width.empty() || !_min_height_for_width.empty();
}
//----------------------------------------------------------------------------
@@ -186,7 +186,7 @@ namespace canvas
int NasalWidget::callHeightForWidthFunc( const HeightForWidthFunc& hfw,
int w ) const
{
if( !hfw )
if( hfw.empty() )
return -1;
try
@@ -239,17 +239,17 @@ namespace canvas
//----------------------------------------------------------------------------
int NasalWidget::heightForWidthImpl(int w) const
{
return callHeightForWidthFunc( _height_for_width
? _height_for_width
: _min_height_for_width, w );
return callHeightForWidthFunc( _height_for_width.empty()
? _min_height_for_width
: _height_for_width, w );
}
//----------------------------------------------------------------------------
int NasalWidget::minimumHeightForWidthImpl(int w) const
{
return callHeightForWidthFunc( _min_height_for_width
? _min_height_for_width
: _height_for_width, w );
return callHeightForWidthFunc( _min_height_for_width.empty()
? _height_for_width
: _min_height_for_width, w );
}

View File

@@ -40,8 +40,8 @@ namespace canvas
{
public:
typedef std::function<void (nasal::Me, const SGRecti&)> SetGeometryFunc;
typedef std::function<int (nasal::Me, int)> HeightForWidthFunc;
typedef boost::function<void (nasal::Me, const SGRecti&)> SetGeometryFunc;
typedef boost::function<int (nasal::Me, int)> HeightForWidthFunc;
/**
*

View File

@@ -18,29 +18,30 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
#include <simgear_config.h>
#include <simgear/debug/BufferedLogCallback.hxx>
#include <boost/foreach.hpp>
#include <simgear/sg_inlines.h>
#include <simgear/threads/SGThread.hxx>
#include <simgear/threads/SGGuard.hxx>
#include <cstdlib> // for malloc
#include <cstring>
#include <mutex>
namespace simgear
{
class BufferedLogCallback::BufferedLogCallbackPrivate
{
public:
std::mutex m_mutex;
SGMutex m_mutex;
vector_cstring m_buffer;
unsigned int m_stamp;
unsigned int m_maxLength;
};
BufferedLogCallback::BufferedLogCallback(sgDebugClass c, sgDebugPriority p) :
simgear::LogCallback(c,p),
d(new BufferedLogCallbackPrivate)
@@ -51,19 +52,19 @@ BufferedLogCallback::BufferedLogCallback(sgDebugClass c, sgDebugPriority p) :
BufferedLogCallback::~BufferedLogCallback()
{
for (auto msg : d->m_buffer) {
BOOST_FOREACH(unsigned char* msg, d->m_buffer) {
free(msg);
}
}
void BufferedLogCallback::operator()(sgDebugClass c, sgDebugPriority p,
void BufferedLogCallback::operator()(sgDebugClass c, sgDebugPriority p,
const char* file, int line, const std::string& aMessage)
{
SG_UNUSED(file);
SG_UNUSED(line);
if (!shouldLog(c, p)) return;
vector_cstring::value_type msg;
if (aMessage.size() >= d->m_maxLength) {
msg = (vector_cstring::value_type) malloc(d->m_maxLength);
@@ -72,29 +73,29 @@ void BufferedLogCallback::operator()(sgDebugClass c, sgDebugPriority p,
} else {
msg = (vector_cstring::value_type) strdup(aMessage.c_str());
}
std::lock_guard<std::mutex> g(d->m_mutex);
SGGuard<SGMutex> g(d->m_mutex);
d->m_buffer.push_back(msg);
d->m_stamp++;
}
unsigned int BufferedLogCallback::stamp() const
{
return d->m_stamp;
}
unsigned int BufferedLogCallback::threadsafeCopy(vector_cstring& aOutput)
{
std::lock_guard<std::mutex> g(d->m_mutex);
SGGuard<SGMutex> g(d->m_mutex);
size_t sz = d->m_buffer.size();
aOutput.resize(sz);
memcpy(aOutput.data(), d->m_buffer.data(), sz * sizeof(vector_cstring::value_type));
return d->m_stamp;
}
}
void BufferedLogCallback::truncateAt(unsigned int t)
{
d->m_maxLength = t;
}
} // of namespace simgear

View File

@@ -6,10 +6,10 @@ using namespace osg;
/**
* merge OSG output into our logging system, so it gets recorded to file,
* and so we can display a GUI console with renderer issues, especially
* shader compilation warnings and errors.
*/
* merge OSG output into our logging system, so it gets recorded to file,
* and so we can display a GUI console with renderer issues, especially
* shader compilation warnings and errors.
*/
class NotifyLogger : public osg::NotifyHandler
{
public:
@@ -22,33 +22,24 @@ public:
if (strstr(message, "the final reference count was")) {
// as this is going to segfault ignore the translation of severity and always output the message.
SG_LOG(SG_GL, SG_ALERT, message);
#ifndef DEBUG
throw new std::string(message);
//int* trigger_segfault = 0;
//*trigger_segfault = 0;
#endif
int* trigger_segfault = 0;
*trigger_segfault = 0;
return;
}
char*tmessage = strdup(message);
char*lf = strrchr(tmessage, '\n');
if (lf)
*lf = 0;
SG_LOG(SG_OSG, translateSeverity(severity), tmessage);
free(tmessage);
SG_LOG(SG_GL, translateSeverity(severity), message);
}
private:
sgDebugPriority translateSeverity(osg::NotifySeverity severity) {
switch (severity) {
case osg::ALWAYS:
case osg::FATAL: return SG_ALERT;
case osg::WARN: return SG_WARN;
case osg::NOTICE:
case osg::INFO: return SG_INFO;
case osg::DEBUG_FP:
case osg::DEBUG_INFO: return SG_DEBUG;
default: return SG_ALERT;
case osg::ALWAYS:
case osg::FATAL: return SG_ALERT;
case osg::WARN: return SG_WARN;
case osg::NOTICE:
case osg::INFO: return SG_INFO;
case osg::DEBUG_FP:
case osg::DEBUG_INFO: return SG_DEBUG;
default: return SG_ALERT;
}
}
};

View File

@@ -35,10 +35,7 @@ typedef enum {
SG_TERRASYNC = 0x01000000,
SG_PARTICLES = 0x02000000,
SG_HEADLESS = 0x04000000,
// SG_OSG (OSG notify) - will always be displayed regardless of FG log settings as OSG log level is configured
// separately and thus it makes more sense to allow these message through.
SG_OSG = 0x08000000,
SG_UNDEFD = 0x10000000, // For range checking
SG_UNDEFD = 0x08000000, // For range checking
SG_ALL = 0xFFFFFFFF
} sgDebugClass;

View File

@@ -24,21 +24,20 @@
#include "logstream.hxx"
#include <cstring>
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <mutex>
#include <boost/foreach.hpp>
#include <simgear/sg_inlines.h>
#include <simgear/threads/SGThread.hxx>
#include <simgear/threads/SGQueue.hxx>
#include <simgear/threads/SGGuard.hxx>
#include <simgear/io/iostreams/sgstream.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/misc/strutils.hxx>
#include <simgear/timing/timestamp.hxx>
#if defined (SG_WINDOWS)
// for AllocConsole, OutputDebugString
@@ -62,12 +61,7 @@ LogCallback::LogCallback(sgDebugClass c, sgDebugPriority p) :
bool LogCallback::shouldLog(sgDebugClass c, sgDebugPriority p) const
{
if ((c & m_class) != 0 && p >= m_priority)
return true;
if (c == SG_OSG) // always have OSG logging as it OSG logging is configured separately.
return true;
return false;
return ((c & m_class) != 0 && p >= m_priority);
}
void LogCallback::setLogLevels( sgDebugClass c, sgDebugPriority p )
@@ -75,18 +69,6 @@ void LogCallback::setLogLevels( sgDebugClass c, sgDebugPriority p )
m_priority = p;
m_class = c;
}
const char* LogCallback::debugPriorityToString(sgDebugPriority p)
{
switch (p) {
case SG_ALERT: return "ALRT";
case SG_BULK: return "BULK";
case SG_DEBUG: return "DBUG";
case SG_INFO: return "INFO";
case SG_POPUP: return "POPU";
case SG_WARN: return "WARN";
default: return "UNKN";
}
}
const char* LogCallback::debugClassToString(sgDebugClass c)
{
@@ -119,7 +101,6 @@ const char* LogCallback::debugClassToString(sgDebugClass c)
case SG_TERRASYNC: return "terrasync";
case SG_PARTICLES: return "particles";
case SG_HEADLESS: return "headless";
case SG_OSG: return "OSG";
default: return "unknown";
}
}
@@ -131,48 +112,18 @@ const char* LogCallback::debugClassToString(sgDebugClass c)
class FileLogCallback : public simgear::LogCallback
{
public:
SGTimeStamp logTimer;
FileLogCallback(const SGPath& aPath, sgDebugClass c, sgDebugPriority p) :
simgear::LogCallback(c, p)
{
m_file.open(aPath, std::ios_base::out | std::ios_base::trunc);
logTimer.stamp();
}
virtual void operator()(sgDebugClass c, sgDebugPriority p,
const char* file, int line, const std::string& message)
{
if (!shouldLog(c, p)) return;
// fprintf(stderr, "%7.2f [%.8s]:%-10s %s\n", logTimer.elapsedMSec() / 1000.0, debugPriorityToString(p), debugClassToString(c), aMessage.c_str());
m_file
<< std::fixed
<< std::setprecision(2)
<< std::setw(8)
<< std::right
<< (logTimer.elapsedMSec() / 1000.0)
<< std::setw(8)
<< std::left
<< " ["+std::string(debugPriorityToString(p))+"]:"
<< std::setw(10)
<< std::left
<< debugClassToString(c)
;
if (file) {
/* <line> can be -ve to indicate that m_fileLine was false, but we
want to show file:line information regardless of m_fileLine. */
m_file
<< file
<< ":"
<< abs(line)
<< ": "
;
}
m_file
<< message << std::endl;
//m_file << debugClassToString(c) << ":" << (int)p
// << ":" << file << ":" << line << ":" << message << std::endl;
m_file << debugClassToString(c) << ":" << (int) p
<< ":" << file << ":" << line << ":" << message << std::endl;
}
private:
sg_ofstream m_file;
@@ -181,12 +132,9 @@ private:
class StderrLogCallback : public simgear::LogCallback
{
public:
SGTimeStamp logTimer;
StderrLogCallback(sgDebugClass c, sgDebugPriority p) :
simgear::LogCallback(c, p)
{
logTimer.stamp();
}
#if defined (SG_WINDOWS)
@@ -200,15 +148,8 @@ public:
const char* file, int line, const std::string& aMessage)
{
if (!shouldLog(c, p)) return;
//fprintf(stderr, "%s\n", aMessage.c_str());
if (file && line > 0) {
fprintf(stderr, "%8.2f %s:%i: [%.8s]:%-10s %s\n", logTimer.elapsedMSec()/1000.0, file, line, debugPriorityToString(p), debugClassToString(c), aMessage.c_str());
}
else {
fprintf(stderr, "%8.2f [%.8s]:%-10s %s\n", logTimer.elapsedMSec()/1000.0, debugPriorityToString(p), debugClassToString(c), aMessage.c_str());
}
// file, line, aMessage.c_str());
fprintf(stderr, "%s\n", aMessage.c_str());
//fprintf(stderr, "%s:%d:%s:%d:%s\n", debugClassToString(c), p,
// file, line, aMessage.c_str());
fflush(stderr);
@@ -302,10 +243,10 @@ public:
* window; stdout/stderr will not appear (except in logfiles as they do now)
* 4) When started from the Console (with --console) open a new console window
* 5) Ensure that IO redirection still works when started from the console
*
*
* Notes:
* 1) fgfs needs to be a GUI subsystem app - which it already is
* 2) What can't be done is to make the cmd prompt run fgfs synchronously;
* 2) What can't be done is to make the cmd prompt run fgfs synchronously;
* this is only something that can be done via "start /wait fgfs".
*/
@@ -329,7 +270,7 @@ public:
}
} else {
/*
* Attempt to attach to the console process of the parent process; when launched from cmd.exe this should be the console,
* Attempt to attach to the console process of the parent process; when launched from cmd.exe this should be the console,
* when launched via the RUN menu explorer, or another GUI app that wasn't started from the console this will fail.
* When it fails we will redirect to the NUL device. This is to ensure that we have valid streams.
* Later on in the initialisation sequence the --console option will be processed and this will cause the requestConsole() to
@@ -359,7 +300,7 @@ public:
if (!stdout_isNull){
if (!m_stdout_isRedirectedAlready)
freopen("conout$", "w", stdout);
else
else
/*
* for already redirected streams we need to attach the stream to the OS handle that is open.
* - this comes from part of the answer http://stackoverflow.com/a/13841522
@@ -378,7 +319,7 @@ public:
}
}
//http://stackoverflow.com/a/25927081
//Clear the error state for each of the C++ standard stream objects.
//Clear the error state for each of the C++ standard stream objects.
std::wcout.clear();
std::cout.clear();
std::wcerr.clear();
@@ -387,14 +328,9 @@ public:
m_callbacks.push_back(new StderrLogCallback(m_logClass, m_logPriority));
m_consoleCallbacks.push_back(m_callbacks.back());
#if defined (SG_WINDOWS)
const char* winDebugEnv = ::getenv("SG_WINDEBUG");
const bool b = winDebugEnv ? simgear::strutils::to_bool(std::string{winDebugEnv}) : false;
if (b) {
m_callbacks.push_back(new WinDebugLogCallback(m_logClass, m_logPriority));
m_consoleCallbacks.push_back(m_callbacks.back());
}
#if defined (SG_WINDOWS) && !defined(NDEBUG)
m_callbacks.push_back(new WinDebugLogCallback(m_logClass, m_logPriority));
m_consoleCallbacks.push_back(m_callbacks.back());
#endif
}
@@ -403,7 +339,7 @@ public:
removeCallbacks();
}
std::mutex m_lock;
SGMutex m_lock;
SGBlockingQueue<LogEntry> m_entries;
// log entries posted during startup
@@ -425,14 +361,13 @@ public:
bool m_stdout_isRedirectedAlready = false;
#endif
bool m_developerMode = false;
bool m_fileLine = false;
// test suite mode.
bool m_testMode = false;
void startLog()
{
std::lock_guard<std::mutex> g(m_lock);
SGGuard<SGMutex> g(m_lock);
if (m_isRunning) return;
m_isRunning = true;
start();
@@ -444,11 +379,8 @@ public:
return;
}
{
std::lock_guard<std::mutex> g(m_lock);
m_startupLogging = on;
m_startupEntries.clear();
}
m_startupLogging = on;
m_startupEntries.clear();
}
virtual void run()
@@ -457,17 +389,16 @@ public:
LogEntry entry(m_entries.pop());
// special marker entry detected, terminate the thread since we are
// making a configuration change or quitting the app
if ((entry.debugClass == SG_NONE) && entry.file && !strcmp(entry.file, "done")) {
if ((entry.debugClass == SG_NONE) && !strcmp(entry.file, "done")) {
return;
}
{
std::lock_guard<std::mutex> g(m_lock);
if (m_startupLogging) {
// save to the startup list for not-yet-added callbacks to
// pull down on startup
m_startupEntries.push_back(entry);
}
if (m_startupLogging) {
// save to the startup list for not-yet-added callbacks to
// pull down on startup
m_startupEntries.push_back(entry);
}
// submit to each installed callback in turn
for (simgear::LogCallback* cb : m_callbacks) {
(*cb)(entry.debugClass, entry.debugPriority,
@@ -478,16 +409,14 @@ public:
bool stop()
{
{
std::lock_guard<std::mutex> g(m_lock);
if (!m_isRunning) {
return false;
}
// log a special marker value, which will cause the thread to wakeup,
// and then exit
log(SG_NONE, SG_ALERT, "done", -1, "");
SGGuard<SGMutex> g(m_lock);
if (!m_isRunning) {
return false;
}
// log a special marker value, which will cause the thread to wakeup,
// and then exit
log(SG_NONE, SG_ALERT, "done", -1, "");
join();
m_isRunning = false;
@@ -531,7 +460,7 @@ public:
PauseThread pause(this);
m_logPriority = p;
m_logClass = c;
for (auto cb : m_consoleCallbacks) {
BOOST_FOREACH(simgear::LogCallback* cb, m_consoleCallbacks) {
cb->setLogLevels(c, p);
}
}
@@ -541,10 +470,6 @@ public:
// Testing mode, so always log.
if (m_testMode) return true;
// SG_OSG (OSG notify) - will always be displayed regardless of FG log settings as OSG log level is configured
// separately and thus it makes more sense to allow these message through.
if (static_cast<unsigned>(p) == static_cast<unsigned>(SG_OSG)) return true;
p = translatePriority(p);
if (p >= SG_INFO) return true;
return ((c & m_logClass) != 0 && p >= m_logPriority);
@@ -554,10 +479,6 @@ public:
const char* fileName, int line, const std::string& msg)
{
p = translatePriority(p);
if (!m_fileLine) {
/* This prevents output of file:line in StderrLogCallback. */
line = -line;
}
LogEntry entry(c, p, fileName, line, msg);
m_entries.push(entry);
}
@@ -569,7 +490,7 @@ public:
}
if (in == SG_DEV_ALERT) {
return m_developerMode ? SG_ALERT : SG_WARN;
return m_developerMode ? SG_POPUP : SG_WARN;
}
return in;
@@ -579,7 +500,7 @@ public:
/////////////////////////////////////////////////////////////////////////////
static std::unique_ptr<logstream> global_logstream;
static std::mutex global_logStreamLock;
static SGMutex global_logStreamLock;
logstream::logstream()
{
@@ -604,10 +525,6 @@ void logstream::setDeveloperMode(bool devMode)
d->m_developerMode = devMode;
}
void logstream::setFileLine(bool fileLine)
{
d->m_fileLine = fileLine;
}
void
logstream::addCallback(simgear::LogCallback* cb)
@@ -747,7 +664,7 @@ sglog()
// http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
// in the absence of portable memory barrier ops in Simgear,
// let's keep this correct & safe
std::lock_guard<std::mutex> g(global_logStreamLock);
SGGuard<SGMutex> g(global_logStreamLock);
if( !global_logstream )
global_logstream.reset(new logstream);
@@ -821,14 +738,14 @@ namespace simgear
{
void requestConsole()
{
{
sglog().requestConsole();
}
void shutdownLogging()
{
std::lock_guard<std::mutex> g(global_logStreamLock);
SGGuard<SGMutex> g(global_logStreamLock);
global_logstream.reset();
}

View File

@@ -52,7 +52,6 @@ protected:
bool shouldLog(sgDebugClass c, sgDebugPriority p) const;
static const char* debugClassToString(sgDebugClass c);
static const char* debugPriorityToString(sgDebugPriority p);
private:
sgDebugClass m_class;
sgDebugPriority m_priority;
@@ -112,12 +111,6 @@ public:
*/
void setDeveloperMode(bool devMode);
/**
* set output of file:line mode on/off. If on, all log messages are
* prefixed by the file:line of the caller of SG_LOG().
*/
void setFileLine(bool fileLine);
/**
* the core logging method
*/
@@ -210,11 +203,9 @@ logstream& sglog();
} } while(0)
#ifdef FG_NDEBUG
# define SG_LOG(C,P,M) do { if((P) == SG_POPUP) SG_LOGX(C,P,M) } while(0)
# define SG_LOG_NAN(C,P,M) SG_LOG(C,P,M)
# define SG_HEXDUMP(C,P,MEM,LEN)
#else
# define SG_LOG(C,P,M) SG_LOGX(C,P,M)
# define SG_LOG_NAN(C,P,M) do { SG_LOGX(C,P,M); throw std::overflow_error(M); } while(0)
# define SG_LOG_HEXDUMP(C,P,MEM,LEN) if(sglog().would_log(C,P)) sglog().hexdump(C, P, __FILE__, __LINE__, MEM, LEN)
#endif

View File

@@ -1,33 +0,0 @@
include (SimGearComponent)
set(HEADERS
Emesary.hxx
INotification.hxx
IReceiver.hxx
ITransmitter.hxx
ReceiptStatus.hxx
Transmitter.hxx
notifications.hxx
)
set(SOURCES
Emesary.cxx
)
simgear_component(emesary emesary "${SOURCES}" "${HEADERS}")
if(ENABLE_TESTS)
add_executable(test_emesary test_emesary.cxx)
set_target_properties(test_emesary PROPERTIES
COMPILE_DEFINITIONS "SRC_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}\"" )
target_link_libraries(test_emesary ${TEST_LIBS})
add_test(emesary ${EXECUTABLE_OUTPUT_PATH}/test_emesary)
endif(ENABLE_TESTS)

View File

@@ -1,31 +0,0 @@
/*---------------------------------------------------------------------------
*
* Title : Emesary - class based inter-object communication
*
* File Type : Implementation File
*
* Description : Emesary main.
* : This only needs to instance the GlobalTransmitter as all of the
* : logic is in the header files (by design)
*
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
*
* Author : Richard Harrison (richard@zaretto.com)
*
* Creation Date : 18 March 2002
*
* Version : $Header: $
*
* Copyright © 2002 Richard Harrison All Rights Reserved.
*
*---------------------------------------------------------------------------*/
#include "simgear/emesary/Emesary.hxx"
namespace simgear
{
namespace Emesary
{
}
}

View File

@@ -1,48 +0,0 @@
#ifndef EMESARY_hxx
#define EMESARY_hxx
/*---------------------------------------------------------------------------
*
* Title : Emesary - class based inter-object communication
*
* File Type : Implementation File
*
* Description : Provides generic inter-object communication. For an object to receive a message it
* : must first register with a Transmitter, such as GlobalTransmitter, and implement the
* : IReceiver interface. That's it.
* : To send a message use a Transmitter with an object. That's all there is to it.
*
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
*
* Author : Richard Harrison (richard@zaretto.com)
*
* Creation Date : 18 March 2002, rewrite 2017, simgear version 2019
*
* Version : $Header: $
*
* Copyright (C)2019 Richard Harrison Licenced under GPL2 or later.
*
*---------------------------------------------------------------------------*/
#include <typeinfo>
#include "ReceiptStatus.hxx"
#include "INotification.hxx"
#include "IReceiver.hxx"
#include "ITransmitter.hxx"
#include "Transmitter.hxx"
#include <simgear/structure/Singleton.hxx>
namespace simgear
{
namespace Emesary
{
class GlobalTransmitter : public simgear::Singleton<Transmitter>
{
public:
GlobalTransmitter()
{
}
virtual ~GlobalTransmitter() {}
};
}
}
#endif

View File

@@ -1,54 +0,0 @@
#ifndef INOTIFICATION_hxx
#define INOTIFICATION_hxx
/*---------------------------------------------------------------------------
*
* Title : Emesary - Notification base class
*
* File Type : Implementation File
*
* Description : Base class (interface) for all Notifications.
* : This is also compatible with the usual implementation of how we
* : implement queued notifications.
*
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
*
* Author : Richard Harrison (richard@zaretto.com)
*
* Creation Date : 18 March 2002, rewrite 2017, simgear version 2019
*
* Version : $Header: $
*
* Copyright (C)2019 Richard Harrison Licenced under GPL2 or later.
*
*---------------------------------------------------------------------------*/
namespace simgear
{
namespace Emesary
{
/// Interface (base class) for all notifications.
class INotification
{
public:
// text representation of notification type. must be unique across all notifications
virtual const char *GetType() = 0;
/// Used to control the sending of notifications. If this returns false then the Transmitter
/// should not send this notification.
virtual bool IsReadyToSend() { return true; }
/// Used to control the timeout. If this notification has timed out - then the processor is entitled
/// to true.
virtual bool IsTimedOut() { return false; }
/// when this notification has completed the processing recipient must set this to true.
/// the processing recipient is responsible for follow on notifications.
/// a notification can remain as complete until the transmit queue decides to remove it from the queue.
/// there is no requirement that elements are removed immediately upon completion merely that once complete
/// the transmitter should not notify any more elements.
/// The current notification loop may be completed - following the usual convention unless Completed or Abort
/// is returned as the status.
virtual bool IsComplete() { return true; }
};
}
}
#endif

View File

@@ -1,47 +0,0 @@
#ifndef IRECEIVER_hxx
#define IRECEIVER_hxx
/*---------------------------------------------------------------------------
*
* Title : Emesary - Receiver base class
*
* File Type : Implementation File
*
* Description : Base class for all recipients.
*
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
*
* Author : Richard Harrison (richard@zaretto.com)
*
* Creation Date : 18 March 2002, rewrite 2017, simgear version 2019
*
* Version : $Header: $
*
* Copyright (C)2019 Richard Harrison Licenced under GPL2 or later.
*
*---------------------------------------------------------------------------*/
namespace simgear
{
namespace Emesary
{
/// Interface (base class) for a recipeint.
class IReceiver
{
public:
/// Receive notification - must be implemented
virtual ReceiptStatus Receive(INotification& message) = 0;
/// Called when registered at a transmitter
virtual void OnRegisteredAtTransmitter(class Transmitter *p)
{
}
/// Called when de-registered at a transmitter
virtual void OnDeRegisteredAtTransmitter(class Transmitter *p)
{
}
};
}
}
#endif

View File

@@ -1,52 +0,0 @@
#ifndef ITRANSMITTER_hxx
#define ITRANSMITTER_hxx
/*---------------------------------------------------------------------------
*
* Title : Emesary - Transmitter base class
*
* File Type : Implementation File
*
* Description : Base class for all transmitters.
*
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
*
* Author : Richard Harrison (richard@zaretto.com)
*
* Creation Date : 18 March 2002, rewrite 2017, simgear version 2019
*
* Version : $Header: $
*
* Copyright (C)2019 Richard Harrison Licenced under GPL2 or later.
*
*---------------------------------------------------------------------------*/
namespace simgear
{
namespace Emesary
{
/// Interface (base clasee) for a transmitter.
/// Transmits Message derived objects. Each instance of this class provides a
/// event/databus to which any number of receivers can attach to.
class ITransmitter
{
public:
// Registers a recipient to receive message from this transmitter
virtual void Register(IReceiver& R) = 0;
// Removes a recipient from from this transmitter
virtual void DeRegister(IReceiver& R) = 0;
//Notify all registered recipients. Stop when receipt status of abort or finished are received.
//The receipt status from this method will be
// - OK > message handled
// - Fail > message not handled. A status of Abort from a recipient will result in our status
// being fail as Abort means that the message was not and cannot be handled, and
// allows for usages such as access controls.
virtual ReceiptStatus NotifyAll(INotification& M) = 0;
/// number of recipients
virtual int Count() = 0;
};
}
}
#endif

View File

@@ -1,54 +0,0 @@
#ifndef RECEIPTSTATUS_hxx
#define RECEIPTSTATUS_hxx
/*---------------------------------------------------------------------------
*
* Title : Emesary - Transmitter base class
*
* File Type : Implementation File
*
* Description : Defines the receipt status that can be returned from
* : a receive method.
*
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
*
* Author : Richard Harrison (richard@zaretto.com)
*
* Creation Date : 18 March 2002, rewrite 2017, simgear version 2019
*
* Version : $Header: $
*
* Copyright (C)2019 Richard Harrison Licenced under GPL2 or later.
*
*---------------------------------------------------------------------------*/
namespace simgear
{
namespace Emesary
{
enum ReceiptStatus
{
/// Processing completed successfully
ReceiptStatusOK = 0,
/// Individual item failure
ReceiptStatusFail = 1,
/// Fatal error; stop processing any further recipieints of this message. Implicitly fail
ReceiptStatusAbort = 2,
/// Definitive completion - do not send message to any further recipieints
ReceiptStatusFinished = 3,
/// Return value when method doesn't process a message.
ReceiptStatusNotProcessed = 4,
/// Message has been sent but the return status cannot be determined as it has not been processed by the recipient.
/// e.g. a queue or outgoing bridge
ReceiptStatusPending = 5,
/// Message has been definitively handled but the return value cannot be determined. The message will not be sent any further
/// e.g. a point to point forwarding bridge
ReceiptStatusPendingFinished = 6,
};
}
}
#endif

View File

@@ -1,203 +0,0 @@
#ifndef TRANSMITTER_hxx
#define TRANSMITTER_hxx
/*---------------------------------------------------------------------------
*
* Title : Emesary - Transmitter base class
*
* File Type : Implementation File
*
* Description : Defines the receipt status that can be returned from
* : a receive method.
*
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
*
* Author : Richard Harrison (richard@zaretto.com)
*
* Creation Date : 18 March 2002, rewrite 2017, simgear version 2019
*
* Version : $Header: $
*
* Copyright (C)2019 Richard Harrison Licenced under GPL2 or later.
*
*---------------------------------------------------------------------------*/
#include <algorithm>
#include <string>
#include <list>
#include <set>
#include <vector>
#include <atomic>
#include <mutex>
namespace simgear
{
namespace Emesary
{
// Implementation of a ITransmitter
class Transmitter : public ITransmitter
{
protected:
typedef std::list<IReceiver *> RecipientList;
RecipientList recipient_list;
RecipientList deleted_recipients;
int CurrentRecipientIndex = 0;
std::mutex _lock;
std::atomic<int> receiveDepth;
std::atomic<int> sentMessageCount;
void UnlockList()
{
_lock.unlock();
}
void LockList()
{
_lock.lock();
}
public:
Transmitter() : receiveDepth(0), sentMessageCount(0)
{
}
virtual ~Transmitter()
{
}
// Registers an object to receive messsages from this transmitter.
// This object is added to the top of the list of objects to be notified. This is deliberate as
// the sequence of registration and message receipt can influence the way messages are processing
// when ReceiptStatus of Abort or Finished are encountered. So it was a deliberate decision that the
// most recently registered recipients should process the messages/events first.
virtual void Register(IReceiver& r)
{
LockList();
recipient_list.push_back(&r);
r.OnRegisteredAtTransmitter(this);
if (std::find(deleted_recipients.begin(), deleted_recipients.end(), &r) != deleted_recipients.end())
deleted_recipients.remove(&r);
UnlockList();
}
// Removes an object from receving message from this transmitter
virtual void DeRegister(IReceiver& R)
{
LockList();
//printf("Remove %x\n", &R);
if (recipient_list.size())
{
if (std::find(recipient_list.begin(), recipient_list.end(), &R) != recipient_list.end())
{
recipient_list.remove(&R);
R.OnDeRegisteredAtTransmitter(this);
if (std::find(deleted_recipients.begin(), deleted_recipients.end(), &R) == deleted_recipients.end())
deleted_recipients.push_back(&R);
}
}
UnlockList();
}
// Notify all registered recipients. Stop when receipt status of abort or finished are received.
// The receipt status from this method will be
// - OK > message handled
// - Fail > message not handled. A status of Abort from a recipient will result in our status
// being fail as Abort means that the message was not and cannot be handled, and
// allows for usages such as access controls.
virtual ReceiptStatus NotifyAll(INotification& M)
{
ReceiptStatus return_status = ReceiptStatusNotProcessed;
sentMessageCount++;
try
{
LockList();
if (receiveDepth == 0)
deleted_recipients.clear();
receiveDepth++;
std::vector<IReceiver*> temp(recipient_list.size());
int idx = 0;
for (RecipientList::iterator i = recipient_list.begin(); i != recipient_list.end(); i++)
{
temp[idx++] = *i;
}
UnlockList();
int tempSize = temp.size();
for (int index = 0; index < tempSize; index++)
{
IReceiver* R = temp[index];
LockList();
if (deleted_recipients.size())
{
if (std::find(deleted_recipients.begin(), deleted_recipients.end(), R) != deleted_recipients.end())
{
UnlockList();
continue;
}
}
UnlockList();
if (R)
{
ReceiptStatus rstat = R->Receive(M);
switch (rstat)
{
case ReceiptStatusFail:
return_status = ReceiptStatusFail;
break;
case ReceiptStatusPending:
return_status = ReceiptStatusPending;
break;
case ReceiptStatusPendingFinished:
return rstat;
case ReceiptStatusNotProcessed:
break;
case ReceiptStatusOK:
if (return_status == ReceiptStatusNotProcessed)
return_status = rstat;
break;
case ReceiptStatusAbort:
return ReceiptStatusAbort;
case ReceiptStatusFinished:
return ReceiptStatusOK;
}
}
}
}
catch (...)
{
throw;
// return_status = ReceiptStatusAbort;
}
receiveDepth--;
return return_status;
}
// number of currently registered recipients
virtual int Count()
{
LockList();
return recipient_list.size();
UnlockList();
}
// number of sent messages.
int SentMessageCount()
{
return sentMessageCount;
}
// ascertain if a receipt status can be interpreted as failure.
static bool Failed(ReceiptStatus receiptStatus)
{
//
// failed is either Fail or Abort.
// NotProcessed isn't a failure because it hasn't been processed.
return receiptStatus == ReceiptStatusFail
|| receiptStatus == ReceiptStatusAbort;
}
};
}
}
#endif

View File

@@ -1,68 +0,0 @@
#ifndef NOTIFICATIONS_hxx
#define NOTIFICATIONS_hxx
/*---------------------------------------------------------------------------
*
* Title : Emesary - class based inter-object communication
*
* File Type : Implementation File
*
* Description : simgear notifications
*
* References : http://www.chateau-logic.com/content/class-based-inter-object-communication
*
* Author : Richard Harrison (richard@zaretto.com)
*
* Creation Date : 18 March 2002, rewrite 2017
*
* Version : $Header: $
*
* Copyright <20> 2002 - 2017 Richard Harrison All Rights Reserved.
*
*---------------------------------------------------------------------------*/
#include "INotification.hxx"
namespace simgear
{
namespace Notifications
{
class MainLoopNotification : public simgear::Emesary::INotification
{
public:
enum Type { Started, Stopped, Begin, End };
MainLoopNotification(Type v) : _type(v) {}
virtual Type GetValue() { return _type; }
virtual const char *GetType() { return "MainLoop"; }
protected:
Type _type;
};
class NasalGarbageCollectionConfigurationNotification : public simgear::Emesary::INotification
{
public:
NasalGarbageCollectionConfigurationNotification(bool canWait, bool active) : CanWait(canWait), Active(active) {}
virtual bool GetCanWait() { return CanWait; }
virtual bool GetActive() { return Active; }
virtual const char *GetType() { return "NasalGarbageCollectionConfiguration"; }
virtual bool SetWait(bool wait) {
if (wait == CanWait)
return false;
CanWait = wait;
return true;
}
virtual bool SetActive(bool active) {
if (active == Active)
return false;
Active = active;
return true;
}
public:
bool CanWait;
bool Active;
};
}
}
#endif

View File

@@ -1,130 +0,0 @@
////////////////////////////////////////////////////////////////////////
// Test harness for Emesary.
////////////////////////////////////////////////////////////////////////
#include <simgear_config.h>
#include <simgear/compiler.h>
#include <iostream>
#include <simgear/threads/SGThread.hxx>
#include <simgear/emesary/Emesary.hxx>
using std::cout;
using std::cerr;
using std::endl;
std::atomic<int> nthread {0};
std::atomic<int> noperations {0};
const int MaxIterations = 9999;
class TestThreadNotification : public simgear::Emesary::INotification
{
protected:
const char *baseValue;
public:
TestThreadNotification(const char *v) : baseValue(v) {}
virtual const char* GetType () { return baseValue; }
};
class TestThreadRecipient : public simgear::Emesary::IReceiver
{
public:
TestThreadRecipient() : receiveCount(0)
{
}
std::atomic<int> receiveCount;
virtual simgear::Emesary::ReceiptStatus Receive(simgear::Emesary::INotification &n)
{
if (n.GetType() == (const char*)this)
{
// Unused: TestThreadNotification *tn = dynamic_cast<TestThreadNotification *>(&n);
receiveCount++;
TestThreadNotification onwardNotification("AL");
simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(onwardNotification);
return simgear::Emesary::ReceiptStatusOK;
}
return simgear::Emesary::ReceiptStatusOK;
}
};
class EmesaryTestThread : public SGThread
{
protected:
virtual void run() {
int threadId = nthread.fetch_add(1);
//System.Threading.Interlocked.Increment(ref nthread);
//var rng = new Random();
TestThreadRecipient r;
char temp[100];
sprintf(temp, "Notif %d", threadId);
printf("starting thread %s\n", temp);
TestThreadNotification tn((const char*)&r);
for (int i = 0; i < MaxIterations; i++)
{
simgear::Emesary::GlobalTransmitter::instance()->Register(r);
simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(tn);
simgear::Emesary::GlobalTransmitter::instance()->DeRegister(r);
//System.Threading.Thread.Sleep(rng.Next(MaxSleep));
noperations++;
}
printf("%s invocations %d\n", temp, (int)r.receiveCount);
printf("finish thread %s\n", temp);
}
};
class EmesaryTest
{
public:
void Emesary_MultiThreadTransmitterTest()
{
int num_threads = 12;
std::list<EmesaryTestThread*> threads;
for (int i = 0; i < num_threads; i++)
{
EmesaryTestThread *thread = new EmesaryTestThread();
threads.push_back(thread);
thread->start();
}
for (std::list<EmesaryTestThread*>::iterator i = threads.begin(); i != threads.end(); i++)
{
(*i)->join();
}
}
};
void testEmesaryThreaded()
{
TestThreadRecipient r;
TestThreadNotification tn((const char*)&r);
simgear::Emesary::GlobalTransmitter::instance()->Register(r);
for (int i = 0; i < MaxIterations*MaxIterations; i++)
{
simgear::Emesary::GlobalTransmitter::instance()->NotifyAll(tn);
//System.Threading.Thread.Sleep(rng.Next(MaxSleep));
noperations++;
}
simgear::Emesary::GlobalTransmitter::instance()->DeRegister(r);
printf("invocations %d\n", simgear::Emesary::GlobalTransmitter::instance()->SentMessageCount());
EmesaryTest t;
t.Emesary_MultiThreadTransmitterTest();
}
int main(int ac, char ** av)
{
testEmesaryThreaded();
std::cout << "all tests passed" << std::endl;
return 0;
}

View File

@@ -38,12 +38,9 @@
# include <simgear_config.h>
#endif
#include <iomanip>
#include <string>
#include <time.h>
#include <cstring>
#include <ostream>
#include <sstream>
#include <simgear/debug/logstream.hxx>
#include <simgear/structure/exception.hxx>
@@ -158,320 +155,6 @@ SGMetar::~SGMetar()
}
static const char *azimuthName(double d)
{
const char *dir[] = {
"N", "NNE", "NE", "ENE",
"E", "ESE", "SE", "SSE",
"S", "SSW", "SW", "WSW",
"W", "WNW", "NW", "NNW"
};
d += 11.25;
while (d < 0)
d += 360;
while (d >= 360)
d -= 360;
return dir[int(d / 22.5)];
}
// round double to 10^g
static double rnd(double r, int g = 0)
{
double f = pow(10.0, g);
return f * floor(r / f + 0.5);
}
/* A manipulator that can use spaces to emulate tab characters. */
struct Tab
{
/* If <stops> is 0, we simply insert tab characters. Otherwise we insert
spaces to align with the next column at multiple of <stops>. */
explicit Tab(int stops)
:
_stops(stops)
{}
int _stops;
};
std::ostream& operator << (std::ostream& out, const Tab& t)
{
if (t._stops == 0) {
return out << '\t';
}
std::ostringstream& out2 = *(std::ostringstream*) &out;
std::string s = out2.str();
if (t._stops < 0) {
if (!s.size() || s[s.size()-1] != ' ') {
out << ' ';
}
return out;
}
auto nl = s.rfind('\n');
if (nl < 0) nl = 0;
int column = 0;
for (auto i = nl+1; i != s.size(); ++i) {
if (s[i] == '\t')
column = (column + t._stops) / t._stops * t._stops;
else
column += 1;
}
int column2 = (column + t._stops) / t._stops * t._stops;
for (int i=column; i<column2; ++i) {
out << ' ';
}
return out;
}
/* Manipulator for SGMetarVisibility using a Tab. */
struct SGMetarVisibilityManip
{
explicit SGMetarVisibilityManip(const SGMetarVisibility& v, const Tab& tab)
:
_v(v),
_tab(tab)
{}
const SGMetarVisibility& _v;
const Tab& _tab;
};
std::ostream& operator << (std::ostream& out, const SGMetarVisibilityManip& v)
{
int m = v._v.getModifier();
const char *mod;
if (m == SGMetarVisibility::GREATER_THAN)
mod = ">=";
else if (m == SGMetarVisibility::LESS_THAN)
mod = "<";
else
mod = "";
out << mod;
double dist = rnd(v._v.getVisibility_m(), 1);
if (dist < 1000.0)
out << rnd(dist, 1) << " m";
else
out << rnd(dist / 1000.0, -1) << " km";
const char *dir = "";
int i;
if ((i = v._v.getDirection()) != -1) {
dir = azimuthName(i);
out << " " << dir;
}
out << v._tab << v._tab << v._tab << v._tab << v._tab;
out << mod << rnd(v._v.getVisibility_sm(), -1) << " US-miles " << dir;
return out;
}
std::string SGMetar::getDescription(int tabstops) const
{
std::ostringstream out;
const char *s;
char buf[256];
double d;
int i, lineno;
Tab tab(tabstops);
if ((i = getReportType()) == SGMetar::AUTO)
out << "(METAR automatically generated)\n";
else if (i == SGMetar::COR)
out << "(METAR manually corrected)\n";
else if (i == SGMetar::RTD)
out << "(METAR routine delayed)\n";
out << "Airport-Id:" << tab << tab << getId() << "\n";
// date/time
int year = getYear();
int month = getMonth();
out << "Report time:" << tab << tab << year << '/' << month << '/' << getDay();
out << ' ' << getHour() << ':';
out << std::setw(2) << std::setfill('0') << getMinute() << " UTC\n";
// visibility
SGMetarVisibility minvis = getMinVisibility();
SGMetarVisibility maxvis = getMaxVisibility();
double min = minvis.getVisibility_m();
double max = maxvis.getVisibility_m();
if (min != NaN) {
if (max != NaN) {
out << "min. Visibility:" << tab << SGMetarVisibilityManip(minvis, tab) << "\n";
out << "max. Visibility:" << tab << SGMetarVisibilityManip(maxvis, tab) << "\n";
} else {
out << "Visibility:" << tab << tab << SGMetarVisibilityManip(minvis, tab) << "\n";
}
}
// directed visibility
const SGMetarVisibility *dirvis = getDirVisibility();
for (i = 0; i < 8; i++, dirvis++)
if (dirvis->getVisibility_m() != NaN)
out << tab << tab << tab << SGMetarVisibilityManip(*dirvis, tab) << "\n";
// vertical visibility
SGMetarVisibility vertvis = getVertVisibility();
if ((d = vertvis.getVisibility_ft()) != NaN)
out << "Vert. visibility:" << tab << SGMetarVisibilityManip(vertvis, tab) << "\n";
else if (vertvis.getModifier() == SGMetarVisibility::NOGO)
out << "Vert. visibility:" << tab << "impossible to determine" << "\n";
// wind
d = getWindSpeed_kmh();
out << "Wind:" << tab << tab << tab;
if (d < .1)
out << "none" << "\n";
else {
if ((i = getWindDir()) == -1)
out << "from variable directions";
else
out << "from the " << azimuthName(i) << " (" << i << " deg)";
out << " at " << rnd(d, -1) << " km/h";
out << tab << tab << rnd(getWindSpeed_kt(), -1) << " kt";
out << " = " << rnd(getWindSpeed_mph(), -1) << " mph";
out << " = " << rnd(getWindSpeed_mps(), -1) << " m/s";
out << "\n";
d = getGustSpeed_kmh();
if (d != NaN && d != 0) {
out << tab << tab << tab << "with gusts at " << rnd(d, -1) << " km/h";
out << tab << tab << tab << rnd(getGustSpeed_kt(), -1) << " kt";
out << " = " << rnd(getGustSpeed_mph(), -1) << " mph";
out << " = " << rnd(getGustSpeed_mps(), -1) << " m/s";
out << "\n";
}
int from = getWindRangeFrom();
int to = getWindRangeTo();
if (from != to) {
out << tab << tab << tab << "variable from " << azimuthName(from);
out << " to " << azimuthName(to);
out << " (" << from << "deg --" << to << " deg)" << "\n";
}
}
// temperature/humidity/air pressure
if ((d = getTemperature_C()) != NaN) {
out << "Temperature:" << tab << tab << d << " C" << tab << tab << tab << tab << tab;
out << rnd(getTemperature_F(), -1) << " F" << "\n";
if ((d = getDewpoint_C()) != NaN) {
out << "Dewpoint:" << tab << tab << d << " C" << tab << tab << tab << tab << tab;
out << rnd(getDewpoint_F(), -1) << " F" << "\n";
out << "Rel. Humidity: " << tab << tab << rnd(getRelHumidity()) << " %" << "\n";
}
}
if ((d = getPressure_hPa()) != NaN) {
out << "Pressure:" << tab << tab << rnd(d) << " hPa" << tab << tab << tab << tab;
out << rnd(getPressure_inHg(), -2) << " in. Hg" << "\n";
}
// weather phenomena
vector<string> wv = getWeather();
vector<string>::iterator weather;
for (i = 0, weather = wv.begin(); weather != wv.end(); weather++, i++) {
out << (i ? ", " : "Weather:") << tab << tab << weather->c_str();
}
if (i)
out << "\n";
// cloud layers
const char *coverage_string[5] = {
"clear skies", "few clouds", "scattered clouds", "broken clouds", "sky overcast"
};
vector<SGMetarCloud> cv = getClouds();
vector<SGMetarCloud>::iterator cloud;
for (lineno = 0, cloud = cv.begin(); cloud != cv.end(); cloud++, lineno++) {
if (lineno) out << tab << tab << tab;
else out << "Sky condition:" << tab << tab;
if ((i = cloud->getCoverage()) != -1)
out << coverage_string[i];
if ((d = cloud->getAltitude_ft()) != NaN)
out << " at " << rnd(d, 1) << " ft";
if ((s = cloud->getTypeLongString()))
out << " (" << s << ')';
if (d != NaN)
out << tab << tab << tab << rnd(cloud->getAltitude_m(), 1) << " m";
out << "\n";
}
// runways
map<string, SGMetarRunway> rm = getRunways();
map<string, SGMetarRunway>::iterator runway;
for (runway = rm.begin(); runway != rm.end(); runway++) {
lineno = 0;
if (!strcmp(runway->first.c_str(), "ALL"))
out << "All runways:" << tab << tab;
else
out << "Runway " << runway->first << ":" << tab << tab;
SGMetarRunway rwy = runway->second;
// assemble surface string
vector<string> surface;
if ((s = rwy.getDepositString()) && strlen(s))
surface.push_back(s);
if ((s = rwy.getExtentString()) && strlen(s))
surface.push_back(s);
if ((d = rwy.getDepth()) != NaN) {
sprintf(buf, "%.1lf mm", d * 1000.0);
surface.push_back(buf);
}
if ((s = rwy.getFrictionString()) && strlen(s))
surface.push_back(s);
if ((d = rwy.getFriction()) != NaN) {
sprintf(buf, "friction: %.2lf", d);
surface.push_back(buf);
}
if (! surface.empty()) {
vector<string>::iterator rwysurf = surface.begin();
for (i = 0; rwysurf != surface.end(); rwysurf++, i++) {
if (i)
out << ", ";
out << *rwysurf;
}
lineno++;
}
// assemble visibility string
SGMetarVisibility minvis = rwy.getMinVisibility();
SGMetarVisibility maxvis = rwy.getMaxVisibility();
if ((d = minvis.getVisibility_m()) != NaN) {
if (lineno++)
out << "\n" << tab << tab << tab;
out << SGMetarVisibilityManip(minvis, tab);
}
if (maxvis.getVisibility_m() != d) {
out << "\n" << tab << tab << tab << SGMetarVisibilityManip(maxvis, tab) << "\n";
lineno++;
}
if (rwy.getWindShear()) {
if (lineno++)
out << "\n" << tab << tab << tab;
out << "critical wind shear" << "\n";
}
out << "\n";
}
out << "\n";
return out.str();
}
void SGMetar::useCurrentDate()
{
struct tm now;

View File

@@ -235,11 +235,6 @@ public:
inline const std::vector<std::string>& getWeather() const { return _weather; }
inline const std::vector<struct Weather> getWeather2() const { return _weather2; }
/* Returns human-readable description. If tabtops is 0, we use tab
characters. If +ve we use spaces to pad to multiple of <tabstops>. If
-1 all sequences of tabs are represented by a single space. */
std::string getDescription(int tabstops) const;
protected:
std::string _url;
int _grpcount;

View File

@@ -44,10 +44,6 @@ SGPrecipitation::SGPrecipitation() :
void SGPrecipitation::setEnabled( bool value )
{
_enabled = value;
if (!_enabled) {
_precipitationEffect->snow(0);
_precipitationEffect->rain(0);
}
}
void SGPrecipitation::setDropletExternal( bool value )
@@ -68,9 +64,6 @@ bool SGPrecipitation::getEnabled() const
*/
osg::Group* SGPrecipitation::build(void)
{
if (!_enabled)
return nullptr;
osg::ref_ptr<osg::Group> group = new osg::Group;
_precipitationEffect->snow(0);
@@ -234,9 +227,6 @@ void SGPrecipitation::setWindProperty(double heading, double speed)
*/
bool SGPrecipitation::update(void)
{
if (!_enabled)
return false;
if (this->_freeze) {
if (this->_rain_intensity > 0) {
this->_snow_intensity = this->_rain_intensity;

View File

@@ -191,11 +191,52 @@ SGEnviro::~SGEnviro(void) {
// OSGFIXME
return;
list_of_lightning::iterator iLightning;
for( iLightning = lightnings.begin() ; iLightning != lightnings.end() ; ++iLightning ) {
delete (*iLightning);
}
lightnings.clear();
}
void SGEnviro::startOfFrame( SGVec3f p, SGVec3f up, double lon, double lat, double alt, double delta_time) {
// OSGFIXME
return;
view_in_cloud = false;
// ask the impostor cache to do some cleanup
last_cloud_turbulence = cloud_turbulence;
cloud_turbulence = 0.0;
elapsed_time += delta_time;
min_time_before_lt -= delta_time;
dt = delta_time;
#if 0
sgMat4 T1, LON, LAT;
sgVec3 axis;
sgMakeTransMat4( T1, p );
sgSetVec3( axis, 0.0, 0.0, 1.0 );
sgMakeRotMat4( LON, lon, axis );
sgSetVec3( axis, 0.0, 1.0, 0.0 );
sgMakeRotMat4( LAT, 90.0 - lat, axis );
sgMat4 TRANSFORM;
sgCopyMat4( TRANSFORM, T1 );
sgPreMultMat4( TRANSFORM, LON );
sgPreMultMat4( TRANSFORM, LAT );
sgCoord pos;
sgSetCoord( &pos, TRANSFORM );
sgMakeCoordMat4( transform, &pos );
#endif
last_lon = lon;
last_lat = lat;
last_alt = alt;
radarEcho.clear();
precipitation_max_alt = 400.0;
}
void SGEnviro::endOfFrame(void) {
@@ -250,6 +291,10 @@ void SGEnviro::set_lightning_enable_state(bool enable) {
void SGEnviro::setLight(SGVec4f adj_fog_color) {
// OSGFIXME
return;
fog_color = adj_fog_color;
if( false ) {
// ssgGetLight( 0 ) -> setColour( GL_DIFFUSE, l->scene_diffuse() );
}
}
#if 0
void SGEnviro::callback_cloud(float heading, float alt, float radius, int family, float dist, int cloudId) {
@@ -386,6 +431,9 @@ void SGEnviro::set_sampleGroup(SGSampleGroup *sgr) {
void SGEnviro::drawPrecipitation(double rain_norm, double snow_norm, double hail_norm, double pitch, double roll, double heading, double hspeed) {
// OSGFIXME
return;
if( precipitation_enable_state && rain_norm > 0.0)
if( precipitation_max_alt >= last_alt )
drawRain(pitch, roll, heading, hspeed, rain_norm);
}
@@ -423,6 +471,10 @@ void SGLightning::lt_Render(void) {
void SGEnviro::addLightning(double lon, double lat, double alt) {
// OSGFIXME
return;
if( lightnings.size() > 10)
return;
SGLightning *lt= new SGLightning(lon, lat, alt);
lightnings.push_back(lt);
}
void SGEnviro::drawLightning(void) {

View File

@@ -31,7 +31,7 @@
// Constructor
SGEphemeris::SGEphemeris( const SGPath& path ) {
SGEphemeris::SGEphemeris( const std::string &path ) {
our_sun = new Star;
moon = new MoonPos;
mercury = new Mercury;
@@ -44,7 +44,7 @@ SGEphemeris::SGEphemeris( const SGPath& path ) {
nplanets = 7;
for ( int i = 0; i < nplanets; ++i )
planets[i] = SGVec3d::zeros();
stars = new SGStarData(path);
stars = new SGStarData( SGPath(path) );
}

View File

@@ -97,7 +97,7 @@ public:
* calling the constructor you need to provide a path pointing to
* your star database file.
* @param path path to your star database */
SGEphemeris( const SGPath &path );
SGEphemeris( const std::string &path );
/** Destructor */
~SGEphemeris( void );

View File

@@ -19,13 +19,11 @@
# include <simgear_config.h>
#endif
#include <mutex>
#include <simgear/compiler.h>
#include "RTIFederateFactoryRegistry.hxx"
#include "simgear/threads/SGThread.hxx"
#include "simgear/threads/SGGuard.hxx"
#include "RTIFederate.hxx"
namespace simgear {
@@ -41,7 +39,7 @@ RTIFederateFactoryRegistry::~RTIFederateFactoryRegistry()
SGSharedPtr<RTIFederate>
RTIFederateFactoryRegistry::create(const std::string& name, const std::list<std::string>& stringList) const
{
std::lock_guard<std::mutex> guard(_mutex);
SGGuard<SGMutex> guard(_mutex);
for (FederateFactoryList::const_iterator i = _federateFactoryList.begin(); i != _federateFactoryList.end(); ++i) {
SGSharedPtr<RTIFederate> federate = (*i)->create(name, stringList);
if (!federate.valid())
@@ -54,7 +52,7 @@ RTIFederateFactoryRegistry::create(const std::string& name, const std::list<std:
void
RTIFederateFactoryRegistry::registerFactory(RTIFederateFactory* factory)
{
std::lock_guard<std::mutex> guard(_mutex);
SGGuard<SGMutex> guard(_mutex);
_federateFactoryList.push_back(factory);
}

View File

@@ -33,7 +33,9 @@
#include <errno.h>
#include <map>
#include <stdexcept>
#include <mutex>
#include <boost/foreach.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <simgear/simgear_config.h>
@@ -121,9 +123,6 @@ Client::Client() :
setUserAgent("SimGear-" SG_STRINGIZE(SIMGEAR_VERSION));
static bool didInitCurlGlobal = false;
static std::mutex initMutex;
std::lock_guard<std::mutex> g(initMutex);
if (!didInitCurlGlobal) {
curl_global_init(CURL_GLOBAL_ALL);
didInitCurlGlobal = true;
@@ -180,15 +179,15 @@ void Client::update(int waitTimeout)
&curlWriteFDs,
&curlErrorFDs,
&maxFD);
struct timeval timeout;
long t;
curl_multi_timeout(d->curlMulti, &t);
if ((t < 0) || (t > waitTimeout)) {
t = waitTimeout;
}
timeout.tv_sec = t / 1000;
timeout.tv_usec = (t % 1000) * 1000;
::select(maxFD, &curlReadFDs, &curlWriteFDs, &curlErrorFDs, &timeout);
@@ -271,18 +270,9 @@ void Client::makeRequest(const Request_ptr& r)
curl_easy_setopt(curlRequest, CURLOPT_HEADERFUNCTION, requestHeaderCallback);
curl_easy_setopt(curlRequest, CURLOPT_HEADERDATA, r.get());
#if !defined(CURL_MAX_READ_SIZE)
const int CURL_MAX_READ_SIZE = 512 * 1024;
#endif
curl_easy_setopt(curlRequest, CURLOPT_BUFFERSIZE, CURL_MAX_READ_SIZE);
curl_easy_setopt(curlRequest, CURLOPT_USERAGENT, d->userAgent.c_str());
curl_easy_setopt(curlRequest, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
if (sglog().would_log(SG_TERRASYNC, SG_DEBUG)) {
curl_easy_setopt(curlRequest, CURLOPT_VERBOSE, 1);
}
curl_easy_setopt(curlRequest, CURLOPT_FOLLOWLOCATION, 1);
if (!d->proxy.empty()) {
@@ -295,7 +285,7 @@ void Client::makeRequest(const Request_ptr& r)
}
}
const std::string method = strutils::lowercase (r->method());
std::string method = boost::to_lower_copy(r->method());
if (method == "get") {
curl_easy_setopt(curlRequest, CURLOPT_HTTPGET, 1);
} else if (method == "put") {
@@ -482,26 +472,12 @@ size_t Client::requestReadCallback(char *ptr, size_t size, size_t nmemb, void *u
return actualBytes;
}
bool isRedirectStatus(int code)
{
return ((code >= 300) && (code < 400));
}
size_t Client::requestHeaderCallback(char *rawBuffer, size_t size, size_t nitems, void *userdata)
{
size_t byteSize = size * nitems;
Request* req = static_cast<Request*>(userdata);
std::string h = strutils::simplify(std::string(rawBuffer, byteSize));
if (req->readyState() >= HTTP::Request::HEADERS_RECEIVED) {
// this can happen with chunked transfers (secondary chunks)
// or redirects
if (isRedirectStatus(req->responseCode())) {
req->responseStart(h);
return byteSize;
}
}
if (req->readyState() == HTTP::Request::OPENED) {
req->responseStart(h);
return byteSize;
@@ -528,8 +504,8 @@ size_t Client::requestHeaderCallback(char *rawBuffer, size_t size, size_t nitems
return byteSize;
}
const std::string key = strutils::simplify(h.substr(0, colonPos));
const std::string lkey = strutils::lowercase (key);
std::string key = strutils::simplify(h.substr(0, colonPos));
std::string lkey = boost::to_lower_copy(key);
std::string value = strutils::strip(h.substr(colonPos + 1));
req->responseHeader(lkey, value);

View File

@@ -34,11 +34,9 @@
#include "simgear/debug/logstream.hxx"
#include "simgear/misc/strutils.hxx"
#include <simgear/misc/sg_dir.hxx>
#include <simgear/io/HTTPClient.hxx>
#include <simgear/io/sg_file.hxx>
#include <simgear/io/untar.hxx>
#include <simgear/io/iostreams/sgstream.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/timing/timestamp.hxx>
@@ -178,8 +176,7 @@ class HTTPDirectory
enum Type
{
FileType,
DirectoryType,
TarballType
DirectoryType
};
ChildInfo(Type ty, const std::string & nameData, const std::string & hashData) :
@@ -189,7 +186,7 @@ class HTTPDirectory
{
}
ChildInfo(const ChildInfo& other) = default;
ChildInfo(const ChildInfo& other) = default;
void setSize(const std::string & sizeData)
{
@@ -314,41 +311,59 @@ public:
void updateChildrenBasedOnHash()
{
copyInstalledChildren();
//SG_LOG(SG_TERRASYNC, SG_DEBUG, "updated children for:" << relativePath());
ChildInfoList toBeUpdated;
copyInstalledChildren();
simgear::Dir d(absolutePath());
PathList fsChildren = d.children(0);
PathList orphans = d.children(0);
string_list toBeUpdated, orphans,
indexNames = indexChildren();
simgear::Dir d(absolutePath());
PathList fsChildren = d.children(0);
ChildInfoList::const_iterator it;
for (it=children.begin(); it != children.end(); ++it) {
// Check if the file exists
PathList::const_iterator p = std::find_if(fsChildren.begin(), fsChildren.end(), LocalFileMatcher(*it));
if (p == fsChildren.end()) {
// File or directory does not exist on local disk, so needs to be updated.
toBeUpdated.push_back(ChildInfo(*it));
} else if (hashForChild(*it) != it->hash) {
// File/directory exists, but hash doesn't match.
toBeUpdated.push_back(ChildInfo(*it));
orphans.erase(std::remove(orphans.begin(), orphans.end(), *p), orphans.end());
} else {
// File/Directory exists and hash is valid.
orphans.erase(std::remove(orphans.begin(), orphans.end(), *p), orphans.end());
for (const auto& child : fsChildren) {
const auto& fileName = child.file();
if ((fileName == ".dirindex") || (fileName == ".hashes")) {
continue;
}
if (it->type == ChildInfo::DirectoryType) {
// If it's a directory,perform a recursive check.
HTTPDirectory* childDir = childDirectory(it->name);
childDir->updateChildrenBasedOnHash();
}
}
}
ChildInfo info(child.isDir() ? ChildInfo::DirectoryType : ChildInfo::FileType,
fileName, "");
info.path = child;
std::string hash = hashForChild(info);
// We now have a list of entries that need to be updated, and a list
// of orphan files that should be removed.
removeOrphans(orphans);
scheduleUpdates(toBeUpdated);
ChildInfoList::iterator c = findIndexChild(fileName);
if (c == children.end()) {
orphans.push_back(fileName);
} else if (c->hash != hash) {
#if 0
SG_LOG(SG_TERRASYNC, SG_DEBUG, "hash mismatch'" << fileName);
// file exists, but hash mismatch, schedule update
if (!hash.empty()) {
SG_LOG(SG_TERRASYNC, SG_DEBUG, "file exists but hash is wrong for:" << fileName);
SG_LOG(SG_TERRASYNC, SG_DEBUG, "on disk:" << hash << " vs in info:" << c->hash);
}
#endif
toBeUpdated.push_back(fileName);
} else {
// file exists and hash is valid. If it's a directory,
// perform a recursive check.
if (c->type == ChildInfo::DirectoryType) {
HTTPDirectory* childDir = childDirectory(fileName);
childDir->updateChildrenBasedOnHash();
}
}
// remove existing file system children from the index list,
// so we can detect new children
// https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Erase-Remove
indexNames.erase(std::remove(indexNames.begin(), indexNames.end(), fileName), indexNames.end());
} // of real children iteration
// all remaining names in indexChilden are new children
toBeUpdated.insert(toBeUpdated.end(), indexNames.begin(), indexNames.end());
removeOrphans(orphans);
scheduleUpdates(toBeUpdated);
}
HTTPDirectory* childDirectory(const std::string& name)
@@ -357,12 +372,10 @@ public:
return _repository->getOrCreateDirectory(childPath);
}
void removeOrphans(const PathList orphans)
void removeOrphans(const string_list& orphans)
{
PathList::const_iterator it;
string_list::const_iterator it;
for (it = orphans.begin(); it != orphans.end(); ++it) {
if (it->file() == ".dirindex") continue;
if (it->file() == ".hash") continue;
removeChild(*it);
}
}
@@ -378,20 +391,21 @@ public:
return r;
}
void scheduleUpdates(const ChildInfoList names)
void scheduleUpdates(const string_list& names)
{
ChildInfoList::const_iterator it;
string_list::const_iterator it;
for (it = names.begin(); it != names.end(); ++it) {
if (it->type == ChildInfo::FileType) {
_repository->updateFile(this, it->name, it->sizeInBytes);
} else if (it->type == ChildInfo::DirectoryType){
HTTPDirectory* childDir = childDirectory(it->name);
_repository->updateDir(childDir, it->hash, it->sizeInBytes);
} else if (it->type == ChildInfo::TarballType) {
// Download a tarball just as a file.
_repository->updateFile(this, it->name, it->sizeInBytes);
ChildInfoList::iterator cit = findIndexChild(*it);
if (cit == children.end()) {
SG_LOG(SG_TERRASYNC, SG_WARN, "scheduleUpdate, unknown child:" << *it);
continue;
}
if (cit->type == ChildInfo::FileType) {
_repository->updateFile(this, *it, cit->sizeInBytes);
} else {
SG_LOG(SG_TERRASYNC, SG_ALERT, "Coding error! Unknown Child type to schedule update");
HTTPDirectory* childDir = childDirectory(*it);
_repository->updateDir(childDir, cit->hash, cit->sizeInBytes);
}
}
}
@@ -416,58 +430,12 @@ public:
SG_LOG(SG_TERRASYNC, SG_WARN, "updated file but not found in dir:" << _relativePath << " " << file);
} else {
if (it->hash != hash) {
SG_LOG(SG_TERRASYNC, SG_INFO, "Checksum error for " << absolutePath() << "/" << file << " " << it->hash << " " << hash);
// we don't erase the file on a hash mismatch, because if we're syncing during the
// we don't erase the file on a hash mismatch, becuase if we're syncing during the
// middle of a server-side update, the downloaded file may actually become valid.
_repository->failedToUpdateChild(_relativePath, HTTPRepository::REPO_ERROR_CHECKSUM);
} else {
_repository->updatedFileContents(it->path, hash);
_repository->totalDownloaded += sz;
SGPath p = SGPath(absolutePath(), file);
if ((p.extension() == "tgz") || (p.extension() == "zip")) {
// We require that any compressed files have the same filename as the file or directory
// they expand to, so we can remove the old file/directory before extracting the new
// data.
SGPath removePath = SGPath(p.base());
bool pathAvailable = true;
if (removePath.exists()) {
if (removePath.isDir()) {
simgear::Dir pd(removePath);
pathAvailable = pd.removeChildren();
} else {
pathAvailable = removePath.remove();
}
}
if (pathAvailable) {
// If this is a tarball, then extract it.
SGBinaryFile f(p);
if (! f.open(SG_IO_IN)) SG_LOG(SG_TERRASYNC, SG_ALERT, "Unable to open " << p << " to extract");
SG_LOG(SG_TERRASYNC, SG_INFO, "Extracting " << absolutePath() << "/" << file << " to " << p.dir());
SGPath extractDir = p.dir();
ArchiveExtractor ex(extractDir);
uint8_t* buf = (uint8_t*) alloca(128);
while (!f.eof()) {
size_t bufSize = f.read((char*) buf, 128);
ex.extractBytes(buf, bufSize);
}
ex.flush();
if (! ex.isAtEndOfArchive()) {
SG_LOG(SG_TERRASYNC, SG_ALERT, "Corrupt tarball " << p);
}
if (ex.hasError()) {
SG_LOG(SG_TERRASYNC, SG_ALERT, "Error extracting " << p);
}
} else {
SG_LOG(SG_TERRASYNC, SG_ALERT, "Unable to remove old file/directory " << removePath);
} // of pathAvailable
} // of handling tgz files
} // of hash matches
} // of found in child list
}
@@ -490,16 +458,6 @@ private:
{ return info.name == name; }
};
struct LocalFileMatcher
{
LocalFileMatcher(const ChildInfo ci) : childInfo(ci) {}
ChildInfo childInfo;
bool operator()(const SGPath path) const {
return path.file() == childInfo.name;
}
};
ChildInfoList::iterator findIndexChild(const std::string& name)
{
return std::find_if(children.begin(), children.end(), ChildWithName(name));
@@ -561,8 +519,8 @@ private:
continue;
}
if (typeData != "f" && typeData != "d" && typeData != "t" ) {
SG_LOG(SG_TERRASYNC, SG_WARN, "malformed .dirindex file: invalid type in line '" << line << "', expected 't', 'd' or 'f', (ignoring line)"
if (typeData != "f" && typeData != "d" ) {
SG_LOG(SG_TERRASYNC, SG_WARN, "malformed .dirindex file: invalid type in line '" << line << "', expected 'd' or 'f', (ignoring line)"
<< "\n\tparsing:" << p.utf8Str());
continue;
}
@@ -575,12 +533,8 @@ private:
continue;
}
ChildInfo ci = ChildInfo(ChildInfo::FileType, tokens[1], tokens[2]);
if (typeData == "d") ci.type = ChildInfo::DirectoryType;
if (typeData == "t") ci.type = ChildInfo::TarballType;
children.emplace_back(ci);
children.back().path = absolutePath() / tokens[1];
children.emplace_back(ChildInfo(typeData == "f" ? ChildInfo::FileType : ChildInfo::DirectoryType, tokens[1], tokens[2]));
children.back().path = absolutePath() / tokens[1];
if (tokens.size() > 3) {
children.back().setSize(tokens[3]);
}
@@ -589,36 +543,40 @@ private:
return true;
}
void removeChild(SGPath path)
void removeChild(const std::string& name)
{
SGPath p(absolutePath());
p.append(name);
bool ok;
SG_LOG(SG_TERRASYNC, SG_WARN, "Removing:" << path);
std::string fpath = _relativePath + "/" + path.file();
if (path.isDir()) {
ok = _repository->deleteDirectory(fpath, path);
std::string fpath = _relativePath + "/" + name;
if (p.isDir()) {
ok = _repository->deleteDirectory(fpath, p);
} else {
// remove the hash cache entry
_repository->updatedFileContents(path, std::string());
ok = path.remove();
_repository->updatedFileContents(p, std::string());
ok = p.remove();
}
if (!ok) {
SG_LOG(SG_TERRASYNC, SG_WARN, "removal failed for:" << path);
throw sg_io_exception("Failed to remove existing file/dir:", path);
SG_LOG(SG_TERRASYNC, SG_WARN, "removal failed for:" << p);
throw sg_io_exception("Failed to remove existing file/dir:", p);
}
}
std::string hashForChild(const ChildInfo& child) const
{
SGPath p(child.path);
if (child.type == ChildInfo::DirectoryType) p.append(".dirindex");
if (child.type == ChildInfo::TarballType) p.concat(".tgz"); // For tarballs the hash is against the tarball file itself
SGPath p(child.path);
if (child.type == ChildInfo::DirectoryType) {
p.append(".dirindex");
}
return _repository->hashForPath(p);
}
HTTPRepoPrivate* _repository;
std::string _relativePath; // in URL and file-system space
};
HTTPRepository::HTTPRepository(const SGPath& base, HTTP::Client *cl) :

View File

@@ -18,9 +18,6 @@
#include <simgear_config.h>
#include "HTTPRequest.hxx"
#include <cstring>
#include <algorithm> // for std::min
#include <simgear/compiler.h>
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/strutils.hxx>
@@ -331,16 +328,6 @@ unsigned int Request::responseLength() const
return _responseLength;
}
//------------------------------------------------------------------------------
void Request::setSuccess(int code)
{
_responseStatus = code;
_responseReason.clear();
if( !isComplete() ) {
setReadyState(DONE);
}
}
//------------------------------------------------------------------------------
void Request::setFailure(int code, const std::string& reason)
{

View File

@@ -28,6 +28,8 @@
#include <simgear/structure/SGSharedPtr.hxx>
#include <simgear/math/sg_types.hxx>
#include <boost/bind.hpp>
class SGPropertyNode;
namespace simgear
@@ -44,7 +46,7 @@ class Request:
public SGReferenced
{
public:
typedef std::function<void(Request*)> Callback;
typedef boost::function<void(Request*)> Callback;
enum ReadyState
{
@@ -80,7 +82,7 @@ public:
template<class C>
Request* done(C* instance, void (C::*mem_func)(Request*))
{
return done(std::bind(mem_func, instance, std::placeholders::_1));
return done(boost::bind(mem_func, instance, _1));
}
/**
@@ -95,7 +97,7 @@ public:
template<class C>
Request* fail(C* instance, void (C::*mem_func)(Request*))
{
return fail(std::bind(mem_func, instance, std::placeholders::_1));
return fail(boost::bind(mem_func, instance, _1));
}
/**
@@ -110,7 +112,7 @@ public:
template<class C>
Request* always(C* instance, void (C::*mem_func)(Request*))
{
return always(std::bind(mem_func, instance, std::placeholders::_1));
return always(boost::bind(mem_func, instance, _1));
}
/**
@@ -222,7 +224,7 @@ protected:
virtual void onAlways();
void setFailure(int code, const std::string& reason);
void setSuccess(int code);
private:
friend class Client;
friend class Connection;

View File

@@ -5,6 +5,8 @@
#include <signal.h>
#include <iostream>
#include <boost/foreach.hpp>
#include <simgear/io/sg_file.hxx>
#include <simgear/io/HTTPClient.hxx>
@@ -27,17 +29,17 @@ public:
_complete(false),
_file(NULL)
{
}
void setFile(SGFile* f)
{
_file = f;
}
bool complete() const
{ return _complete; }
void addHeader(const string& h)
{
int colonPos = h.find(':');
@@ -45,22 +47,22 @@ public:
cerr << "malformed header: " << h << endl;
return;
}
string key = h.substr(0, colonPos);
requestHeader(key) = h.substr(colonPos + 1);
}
protected:
virtual void onDone()
{
_complete = true;
}
}
virtual void gotBodyData(const char* s, int n)
{
_file->write(s, n);
}
private:
private:
bool _complete;
SGFile* _file;
};
@@ -72,7 +74,7 @@ int main(int argc, char* argv[])
string proxy, proxyAuth;
string_list headers;
string url;
for (int a=0; a<argc;++a) {
if (argv[a][0] == '-') {
if (!strcmp(argv[a], "--user-agent")) {
@@ -103,7 +105,7 @@ int main(int argc, char* argv[])
proxyHost = proxy.substr(0, colonPos);
proxyPort = strutils::to_int(proxy.substr(colonPos + 1));
}
cl.setProxy(proxyHost, proxyPort, proxyAuth);
}
@@ -121,23 +123,23 @@ int main(int argc, char* argv[])
}
ARequest* req = new ARequest(url);
for (const auto& h : headers) {
BOOST_FOREACH(string h, headers) {
req->addHeader(h);
}
req->setFile(outFile);
cl.makeRequest(req);
while (!req->complete()) {
cl.update();
SGTimeStamp::sleepForMSec(100);
}
if (req->responseCode() != 200) {
cerr << "got response:" << req->responseCode() << endl;
cerr << "\treason:" << req->responseReason() << endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@@ -71,10 +71,10 @@ static const uint32_t EndianMagic = 0x11223344;
* gzContainerWriter
**************************************************************************/
gzContainerWriter::gzContainerWriter(const SGPath& name,
gzContainerWriter::gzContainerWriter(const std::string& name,
const std::string& fileMagic) :
sg_gzofstream(name, ios_out | ios_binary),
filename(name.utf8Str())
filename(name)
{
/* write byte-order marker **************************************/
write((char*)&EndianMagic, sizeof(EndianMagic));
@@ -138,10 +138,10 @@ gzContainerWriter::writeContainer(ContainerType Type, SGPropertyNode* root)
* gzContainerReader
**************************************************************************/
gzContainerReader::gzContainerReader(const SGPath& name,
gzContainerReader::gzContainerReader(const std::string& name,
const std::string& fileMagic) :
sg_gzifstream(SGPath(name), ios_in | ios_binary),
filename(name.utf8Str())
filename(name)
{
bool ok = (good() && !eof());

View File

@@ -35,7 +35,7 @@ typedef int ContainerType;
class gzContainerReader : public sg_gzifstream
{
public:
gzContainerReader( const SGPath& name,
gzContainerReader( const std::string& name,
const std::string& fileMagic);
bool readContainerHeader(ContainerType* pType, size_t* pSize);
@@ -48,7 +48,7 @@ private:
class gzContainerWriter : public sg_gzofstream
{
public:
gzContainerWriter( const SGPath& name,
gzContainerWriter( const std::string& name,
const std::string& fileMagic);
bool writeContainerHeader(ContainerType Type, size_t Size);

22
simgear/io/iostreams/sgstream.cxx Executable file → Normal file
View File

@@ -212,7 +212,7 @@ sg_ifstream::sg_ifstream(const SGPath& path, ios_openmode io_mode)
#if defined(SG_WINDOWS)
std::wstring ps = path.wstr();
#else
std::string ps = path.utf8Str();
std::string ps = path.local8BitStr();
#endif
std::ifstream::open(ps.c_str(), io_mode);
}
@@ -222,31 +222,17 @@ void sg_ifstream::open( const SGPath& name, ios_openmode io_mode )
#if defined(SG_WINDOWS)
std::wstring ps = name.wstr();
#else
std::string ps = name.utf8Str();
std::string ps = name.local8BitStr();
#endif
std::ifstream::open(ps.c_str(), io_mode);
}
std::string sg_ifstream::read_all()
{
this->seekg(0, std::ios::end); // seek to end
const auto pos = this->tellg();
std::string result;
result.resize(pos);
this->seekg(0, std::ios::beg);
this->read(const_cast<char*>(result.data()), pos);
return result;
}
sg_ofstream::sg_ofstream(const SGPath& path, ios_openmode io_mode)
{
#if defined(SG_WINDOWS)
std::wstring ps = path.wstr();
#else
std::string ps = path.utf8Str();
std::string ps = path.local8BitStr();
#endif
std::ofstream::open(ps.c_str(), io_mode);
}
@@ -256,7 +242,7 @@ void sg_ofstream::open( const SGPath& name, ios_openmode io_mode )
#if defined(SG_WINDOWS)
std::wstring ps = name.wstr();
#else
std::string ps = name.utf8Str();
std::string ps = name.local8BitStr();
#endif
std::ofstream::open(ps.c_str(), io_mode);
}

View File

@@ -196,10 +196,6 @@ public:
void open( const SGPath& name,
ios_openmode io_mode = ios_in|ios_binary );
/// read the entire stream into a buffer. Use on files, etc - not recommended on streams
/// which never EOF, will bvlock forever.
std::string read_all();
};
class sg_ofstream : public std::ofstream

View File

@@ -431,7 +431,7 @@ void test_ZlibDecompressorIStream_readPutbackEtc()
try {
// 'Z' is not the last character read from the stream
decompressor.putback('Z');
} catch (const std::ios_base::failure&) {
} catch (std::ios_base::failure) {
gotException = true;
} catch (const std::exception& e) {
// gcc fails to catch std::ios_base::failure due to an inconsistent C++11

View File

@@ -36,7 +36,6 @@
#include <cstring>
#include <cassert>
#include <cstdio> // for snprintf
#include <mutex>
#include <errno.h>
#if defined(WINSOCK)
@@ -214,7 +213,7 @@ private:
return ok;
}
std::mutex _lock;
SGMutex _lock;
SGWaitCondition _wait;
typedef std::map<string, simgear::IPAddress*> AddressCache;

View File

@@ -160,7 +160,7 @@ public:
}
}
int32_t readInt()
float readInt()
{
unsigned int* p = reinterpret_cast<unsigned int*>(ptr + offset);
if ( sgIsBigEndian() ) {

View File

@@ -34,15 +34,18 @@
#include <simgear/math/sg_types.hxx>
#include <simgear/math/SGMath.hxx>
#include <array>
#include <string>
#include <vector>
#include <string>
#include <boost/array.hpp>
#define MAX_TC_SETS (4)
#define MAX_VAS (8)
typedef std::array<int_list, MAX_TC_SETS> tci_list;
typedef std::array<int_list, MAX_VAS> vai_list;
// I really want to pass around fixed length arrays, as the size
// has to be hardcoded
// but it's a C++0x feature use boost in its absence
typedef boost::array<int_list, MAX_TC_SETS> tci_list;
typedef boost::array<int_list, MAX_VAS> vai_list;
/** STL Structure used to store (integer index) object information */
typedef std::vector < int_list > group_list;

View File

@@ -64,31 +64,6 @@ SGFile::SGFile( int existingFd ) :
SGFile::~SGFile() {
}
#include <simgear/misc/sg_hash.hxx>
#include <simgear/structure/exception.hxx>
#include "simgear/misc/strutils.hxx"
std::string SGFile::computeHash()
{
if (!file_name.exists())
return std::string();
simgear::sha1nfo info;
sha1_init(&info);
char* buf = static_cast<char*>(malloc(1024 * 1024));
size_t readLen;
SGBinaryFile f(file_name);
if (!f.open(SG_IO_IN)) {
throw sg_io_exception("Couldn't open file for compute hash", file_name);
}
while ((readLen = f.read(buf, 1024 * 1024)) > 0) {
sha1_write(&info, buf, readLen);
}
f.close();
free(buf);
std::string hashBytes((char*)sha1_result(&info), HASH_LENGTH);
return simgear::strutils::encodeHex(hashBytes);
}
// open the file based on specified direction
bool SGFile::open( const SGProtocolDir d ) {

View File

@@ -87,9 +87,6 @@ public:
/** @return true of eof conditions exists */
virtual bool eof() const { return eof_flag; };
std::string computeHash();
};
class SGBinaryFile : public SGFile {

View File

@@ -7,6 +7,8 @@
#include <thread>
#include <atomic>
#include <boost/algorithm/string/case_conv.hpp>
#include <simgear/simgear_config.h>
#include "DNSClient.hxx"

View File

@@ -1,10 +1,12 @@
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <map>
#include <sstream>
#include <cerrno>
#include <boost/algorithm/string/case_conv.hpp>
#include <simgear/simgear_config.h>
#include "HTTPClient.hxx"
@@ -59,23 +61,23 @@ public:
std::map<string, string> headers;
protected:
void onDone() override
virtual void onDone()
{
complete = true;
}
void onFail() override
virtual void onFail()
{
failed = true;
}
void gotBodyData(const char* s, int n) override
virtual void gotBodyData(const char* s, int n)
{
// std::cout << "got body data:'" << string(s, n) << "'" <<std::endl;
//std::cout << "got body data:'" << string(s, n) << "'" <<std::endl;
bodyData += string(s, n);
}
void responseHeader(const string& header, const string& value) override
virtual void responseHeader(const string& header, const string& value)
{
Request::responseHeader(header, value);
headers[header] = value;
@@ -271,23 +273,7 @@ public:
d << "\r\n"; // final CRLF to terminate the headers
d << contentStr;
push(d.str().c_str());
} else if (path == "/test_redirect") {
string contentStr("<html>See <a href=\"wibble\">Here</a></html>");
stringstream d;
d << "HTTP/1.1 " << 302 << " " << "Found" << "\r\n";
d << "Location:" << " http://localhost:2000/was_redirected" << "\r\n";
d << "Content-Length:" << contentStr.size() << "\r\n";
d << "\r\n"; // final CRLF to terminate the headers
d << contentStr;
push(d.str().c_str());
} else if (path == "/was_redirected") {
string contentStr(BODY1);
stringstream d;
d << "HTTP/1.1 " << 200 << " " << reasonForCode(200) << "\r\n";
d << "Content-Length:" << contentStr.size() << "\r\n";
d << "\r\n"; // final CRLF to terminate the headers
d << contentStr;
push(d.str().c_str());
} else {
TestServerChannel::processRequestHeaders();
}
@@ -379,26 +365,6 @@ void waitForFailed(HTTP::Client* cl, TestRequest* tr)
cerr << "timed out waiting for failure" << endl;
}
using CompletionCheck = std::function<bool()>;
bool waitFor(HTTP::Client* cl, CompletionCheck ccheck)
{
SGTimeStamp start(SGTimeStamp::now());
while (start.elapsedMSec() < 10000) {
cl->update();
testServer.poll();
if (ccheck()) {
return true;
}
SGTimeStamp::sleepForMSec(15);
}
cerr << "timed out" << endl;
return false;
}
int main(int argc, char* argv[])
{
sglog().setLogLevels( SG_ALL, SG_INFO );
@@ -474,8 +440,6 @@ int main(int argc, char* argv[])
// larger get request
for (unsigned int i=0; i<body2Size; ++i) {
// this contains embeded 0s on purpose, i.e it's
// not text data but binary
body2[i] = (i << 4) | (i >> 2);
}
@@ -620,10 +584,9 @@ cout << "testing proxy close" << endl;
HTTP::Request_ptr own3(tr3);
cl.makeRequest(tr3);
SG_VERIFY(waitFor(&cl, [tr, tr2, tr3]() {
return tr->complete && tr2->complete &&tr3->complete;
}));
waitForComplete(&cl, tr3);
SG_VERIFY(tr->complete);
SG_VERIFY(tr2->complete);
SG_CHECK_EQUAL(tr->bodyData, string(BODY1));
SG_CHECK_EQUAL(tr2->responseLength(), strlen(BODY3));
@@ -652,9 +615,9 @@ cout << "testing proxy close" << endl;
HTTP::Request_ptr own3(tr3);
cl.makeRequest(tr3);
SG_VERIFY(waitFor(&cl, [tr, tr2, tr3]() {
return tr->complete && tr2->complete &&tr3->complete;
}));
waitForComplete(&cl, tr3);
SG_VERIFY(tr->complete);
SG_VERIFY(tr2->complete);
SG_CHECK_EQUAL(tr->responseLength(), strlen(BODY1));
SG_CHECK_EQUAL(tr->responseBytesReceived(), strlen(BODY1));
@@ -781,15 +744,8 @@ cout << "testing proxy close" << endl;
SG_CHECK_EQUAL(tr3->bodyData, string(BODY1));
}
// disabling this test for now, since it seems to have changed depending
// on the libCurl version. (Or some other configuration which is currently
// not apparent).
// old behaviour: Curl sends the second request soon after makeRequest
// new behaviour: Curl waits for the first request to complete, before
// sending the second request (i.e acts as if HTTP pipelining is disabled)
#if 0
{
cout << "get-during-response-send\n\n" << endl;
cout << "get-during-response-send" << endl;
cl.clearAllConnections();
//test_get_during_send
@@ -809,10 +765,7 @@ cout << "testing proxy close" << endl;
HTTP::Request_ptr own2(tr2);
cl.makeRequest(tr2);
SG_VERIFY(waitFor(&cl, [tr, tr2]() {
return tr->isComplete() && tr2->isComplete();
}));
waitForComplete(&cl, tr2);
SG_CHECK_EQUAL(tr->responseCode(), 200);
SG_CHECK_EQUAL(tr->bodyData, string(BODY3));
SG_CHECK_EQUAL(tr->responseBytesReceived(), strlen(BODY3));
@@ -820,25 +773,6 @@ cout << "testing proxy close" << endl;
SG_CHECK_EQUAL(tr2->bodyData, string(BODY1));
SG_CHECK_EQUAL(tr2->responseBytesReceived(), strlen(BODY1));
}
#endif
{
cout << "redirect test" << endl;
// redirect test
testServer.disconnectAll();
cl.clearAllConnections();
TestRequest* tr = new TestRequest("http://localhost:2000/test_redirect");
HTTP::Request_ptr own(tr);
cl.makeRequest(tr);
waitForComplete(&cl, tr);
SG_CHECK_EQUAL(tr->responseCode(), 200);
SG_CHECK_EQUAL(tr->responseReason(), string("OK"));
SG_CHECK_EQUAL(tr->responseLength(), strlen(BODY1));
SG_CHECK_EQUAL(tr->responseBytesReceived(), strlen(BODY1));
SG_CHECK_EQUAL(tr->bodyData, string(BODY1));
}
cout << "all tests passed ok" << endl;
return EXIT_SUCCESS;

View File

@@ -1,7 +1,6 @@
#ifndef SIMGEAR_IO_TEST_HTTP_HXX
#define SIMGEAR_IO_TEST_HTTP_HXX
#include <algorithm>
#include <sstream>
#include <vector>
@@ -31,6 +30,7 @@ public:
virtual ~TestServerChannel()
{
std::cerr << "dtor test server channel" << std::endl;
}
virtual void collectIncomingData(const char* s, int n)
@@ -139,8 +139,8 @@ public:
void sendErrorResponse(int code, bool close, std::string content)
{
// std::cerr << "sending error " << code << " for " << path << std::endl;
// std::cerr << "\tcontent:" << content << std::endl;
std::cerr << "sending error " << code << " for " << path << std::endl;
std::cerr << "\tcontent:" << content << std::endl;
std::stringstream headerData;
headerData << "HTTP/1.1 " << code << " " << reasonForCode(code) << "\r\n";
@@ -168,6 +168,7 @@ public:
virtual void handleClose (void)
{
std::cerr << "channel close" << std::endl;
NetBufferChannel::handleClose();
}

View File

@@ -1,4 +1,3 @@
#include <cassert>
#include <cstdlib>
#include <iostream>
#include <map>
@@ -6,6 +5,8 @@
#include <errno.h>
#include <fcntl.h>
#include <boost/algorithm/string/case_conv.hpp>
#include <simgear/simgear_config.h>
#include "test_HTTP.hxx"

View File

@@ -5,6 +5,8 @@
#include <sstream>
#include <errno.h>
#include <boost/algorithm/string/case_conv.hpp>
#include <simgear/simgear_config.h>
#include "HTTPClient.hxx"

View File

@@ -48,8 +48,6 @@ namespace simgear
assert(outer);
}
virtual ~ArchiveExtractorPrivate() = default;
typedef enum {
INVALID = 0,
READING_HEADER,
@@ -340,7 +338,7 @@ public:
}
if (!isSafePath(tarPath)) {
SG_LOG(SG_IO, SG_WARN, "unsafe tar path, skipping::" << tarPath);
SG_LOG(SG_IO, SG_WARN, "bad tar path:" << tarPath);
skipCurrentEntry = true;
}
@@ -506,7 +504,7 @@ public:
#endif
unzFile zip = unzOpen2(bufferName, &memoryAccessFuncs);
const size_t BUFFER_SIZE = 1024 * 1024;
const size_t BUFFER_SIZE = 32 * 1024;
void* buf = malloc(BUFFER_SIZE);
try {
@@ -532,28 +530,24 @@ public:
state = END_OF_ARCHIVE;
}
catch (sg_exception&) {
state = BAD_ARCHIVE;
}
free(buf);
unzClose(zip);
}
void extractCurrentFile(unzFile zip, char* buffer, size_t bufferSize)
{
unz_file_info fileInfo;
int result = unzGetCurrentFileInfo(zip, &fileInfo,
buffer, bufferSize,
NULL, 0, /* extra field */
NULL, 0 /* comment field */);
if (result != Z_OK) {
throw sg_io_exception("Failed to get zip current file info");
}
state = BAD_ARCHIVE;
}
free(buf);
unzClose(zip);
}
void extractCurrentFile(unzFile zip, char* buffer, size_t bufferSize)
{
unz_file_info fileInfo;
unzGetCurrentFileInfo(zip, &fileInfo,
buffer, bufferSize,
NULL, 0, /* extra field */
NULL, 0 /* comment field */);
std::string name(buffer);
if (!isSafePath(name)) {
SG_LOG(SG_IO, SG_WARN, "unsafe zip path, skipping::" << name);
return;
throw sg_format_exception("Bad zip path", name);
}
auto filterResult = filterPath(name);
@@ -572,7 +566,7 @@ public:
return;
}
result = unzOpenCurrentFile(zip);
int result = unzOpenCurrentFile(zip);
if (result != UNZ_OK) {
throw sg_io_exception("opening current zip file failed", sg_location(name));
}
@@ -620,7 +614,10 @@ ArchiveExtractor::ArchiveExtractor(const SGPath& rootPath) :
{
}
ArchiveExtractor::~ArchiveExtractor() = default;
ArchiveExtractor::~ArchiveExtractor()
{
}
void ArchiveExtractor::extractBytes(const uint8_t* bytes, size_t count)
{
@@ -638,7 +635,7 @@ void ArchiveExtractor::extractBytes(const uint8_t* bytes, size_t count)
d.reset(new ZipExtractorPrivate(this));
}
else {
SG_LOG(SG_IO, SG_WARN, "Invalid archive type");
SG_LOG(SG_IO, SG_ALERT, "Invcalid archive type");
_invalidDataType = true;
return;
}
@@ -728,10 +725,8 @@ ArchiveExtractor::DetermineResult ArchiveExtractor::isTarData(const uint8_t* byt
}
int result = inflate(&z, Z_SYNC_FLUSH);
if ((result == Z_OK) || (result == Z_STREAM_END)) {
// all good
} else {
SG_LOG(SG_IO, SG_WARN, "isTarData: Zlib inflate failed:" << result);
if (result != Z_OK) {
SG_LOG(SG_IO, SG_WARN, "inflate failed:" << result);
inflateEnd(&z);
return Invalid; // not tar data
}

View File

@@ -34,7 +34,7 @@ class ArchiveExtractor
{
public:
ArchiveExtractor(const SGPath& rootPath);
virtual ~ArchiveExtractor();
~ArchiveExtractor();
enum DetermineResult
{

View File

@@ -193,8 +193,8 @@ min(S s, SGVec2<T> v)
template<typename T>
inline
SGVec2<T>
max(SGVec2<T> v1, const SGVec2<T>& v2)
{ v1.simd2() = simd4::max(v1.simd2(), v2.simd2()); return v1; }
max(const SGVec2<T>& v1, const SGVec2<T>& v2)
{ v1 = simd4::max(v1.simd2(), v2.simd2()); return v1; }
template<typename S, typename T>
inline
SGVec2<T>
@@ -375,29 +375,6 @@ interpolate(T tau, const SGVec2<T>& v1, const SGVec2<T>& v2)
return r;
}
// Helper function for point_in_triangle
template <typename T>
inline
T
pt_determine(const SGVec2<T>& pt1, const SGVec2<T>& pt2, const SGVec2<T>& pt3)
{
return (pt1.x()-pt3.x()) * (pt2.y()-pt3.y()) - (pt2.x() - pt3.x()) * (pt1.y() - pt3.y());
}
// Is testpt inside the triangle formed by the other three points?
template <typename T>
inline
bool
point_in_triangle(const SGVec2<T>& testpt, const SGVec2<T>& pt1, const SGVec2<T>& pt2, const SGVec2<T>& pt3)
{
T d1 = pt_determine(testpt,pt1,pt2);
T d2 = pt_determine(testpt,pt2,pt3);
T d3 = pt_determine(testpt,pt3,pt1);
bool has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0);
bool has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0);
return !(has_neg && has_pos);
}
#ifndef NDEBUG
template<typename T>
inline

View File

@@ -56,6 +56,8 @@ SGInterpTable::SGInterpTable(const SGPropertyNode* interpolation)
// file
SGInterpTable::SGInterpTable( const std::string& file )
{
SG_LOG( SG_MATH, SG_INFO, "Initializing Interpolator for " << file );
sg_gzifstream in( SGPath::fromUtf8(file) );
if ( !in.is_open() ) {
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file );
@@ -76,6 +78,8 @@ SGInterpTable::SGInterpTable( const std::string& file )
// file
SGInterpTable::SGInterpTable( const SGPath& file )
{
SG_LOG( SG_MATH, SG_INFO, "Initializing Interpolator for " << file );
sg_gzifstream in( file );
if ( !in.is_open() ) {
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file );

View File

@@ -19,8 +19,6 @@ set(HEADERS
tabbed_values.hxx
texcoord.hxx
test_macros.hxx
lru_cache.hxx
simgear_optional.hxx
)
set(SOURCES

View File

@@ -18,6 +18,8 @@
#include "CSSBorder.hxx"
#include <boost/lexical_cast.hpp>
#include <boost/range.hpp>
#include <boost/tokenizer.hpp>
namespace simgear
@@ -112,9 +114,9 @@ namespace simgear
std::max
(
0.f,
std::stof
boost::lexical_cast<float>
(
rel ? std::string(tok->begin(), tok->end() - 1)
rel ? boost::make_iterator_range(tok->begin(), tok->end() - 1)
: *tok
)
/

View File

@@ -21,6 +21,7 @@
#define SG_LISTDIFF_HXX_
#include <vector>
#include <boost/function.hpp>
namespace simgear
{
@@ -29,7 +30,7 @@ namespace simgear
struct ListDiff
{
typedef std::vector<T> List;
typedef std::function<void (T)> Callback;
typedef boost::function<void (T)> Callback;
/**
* Perform list diff in-place (modifies both lists) and call cb_add for

View File

@@ -30,16 +30,11 @@
// code can register another one immediately without worrying about
// timer aliasing.
class SGInterpolator : public SGSubsystem
{
class SGInterpolator : public SGSubsystem {
public:
SGInterpolator() { _list = 0; }
// Subsystem API.
void update(double delta_time_sec) override;
// Subsystem identification.
static const char* staticSubsystemClassId() { return "interpolator"; }
virtual void init() {}
virtual void update(double delta_time_sec);
// Simple method that interpolates a double property value from
// its current value (default of zero) to the specified target

View File

@@ -1,173 +0,0 @@
///@file
/// Compare lists and get differences
//---------------------------------------------------------------------------//
// Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
//
// Distributed under the Boost Software License, Version 1.0
// See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
// See http://boostorg.github.com/compute for more information.
//---------------------------------------------------------------------------//
///
// Changes Copyright (C) 2019 Richard Harrison (rjh@zaretto.com)
//
// As the boost licence is lax and permissive see
// (https://www.gnu.org/licenses/license-list.en.html#boost)
// any changes to this module are covered under the GPL
//
// 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 LRU_CACHE_HXX_
#define LRU_CACHE_HXX_
#include <map>
#include <list>
#include <utility>
#include <mutex>
#include <boost/optional.hpp>
#include <simgear/threads/SGThread.hxx>
namespace simgear
{
// a cache which evicts the least recently used item when it is full
template<class Key, class Value>
class lru_cache
{
public:
std::mutex _mutex;
typedef Key key_type;
typedef Value value_type;
typedef std::list<key_type> list_type;
typedef std::map<
key_type,
std::pair<value_type, typename list_type::iterator>
> map_type;
lru_cache(size_t capacity)
: m_capacity(capacity)
{
}
~lru_cache()
{
}
size_t size() const
{
return m_map.size();
}
size_t capacity() const
{
return m_capacity;
}
bool empty() const
{
return m_map.empty();
}
bool contains(const key_type &key)
{
std::lock_guard<std::mutex> scopeLock(_mutex);
return m_map.find(key) != m_map.end();
}
void insert(const key_type &key, const value_type &value)
{
std::lock_guard<std::mutex> scopeLock(_mutex);
typename map_type::iterator i = m_map.find(key);
if (i == m_map.end()) {
// insert item into the cache, but first check if it is full
if (size() >= m_capacity) {
// cache is full, evict the least recently used item
evict();
}
// insert the new item
m_list.push_front(key);
m_map[key] = std::make_pair(value, m_list.begin());
}
}
boost::optional<key_type> findValue(const std::string &requiredValue)
{
std::lock_guard<std::mutex> scopeLock(_mutex);
for (typename map_type::iterator it = m_map.begin(); it != m_map.end(); ++it)
if (it->second.first == requiredValue)
return it->first;
return boost::none;
}
boost::optional<value_type> get(const key_type &key)
{
std::lock_guard<std::mutex> scopeLock(_mutex);
// lookup value in the cache
typename map_type::iterator i = m_map.find(key);
if (i == m_map.end()) {
// value not in cache
return boost::none;
}
// return the value, but first update its place in the most
// recently used list
typename list_type::iterator j = i->second.second;
if (j != m_list.begin()) {
// move item to the front of the most recently used list
m_list.erase(j);
m_list.push_front(key);
// update iterator in map
j = m_list.begin();
const value_type &value = i->second.first;
m_map[key] = std::make_pair(value, j);
// return the value
return value;
}
else {
// the item is already at the front of the most recently
// used list so just return it
return i->second.first;
}
}
void clear()
{
std::lock_guard<std::mutex> scopeLock(_mutex);
m_map.clear();
m_list.clear();
}
private:
void evict()
{
std::lock_guard<std::mutex> scopeLock(_mutex);
// evict item from the end of most recently used list
typename list_type::iterator i = --m_list.end();
m_map.erase(*i);
m_list.erase(i);
}
private:
map_type m_map;
list_type m_list;
size_t m_capacity;
};
} // namespace simgear
#endif /* SG_LISTDIFF_HXX_ */

7
simgear/misc/path_test.cxx Executable file → Normal file
View File

@@ -333,12 +333,6 @@ void test_hash_function()
SG_CHECK_NE(std::hash<SGPath>{}(p), std::hash<SGPath>{}(p / "foobar"));
}
void test_null_path()
{
const SGPath nullPath;
SG_VERIFY(!nullPath.exists());
}
int main(int argc, char* argv[])
{
SGPath pa;
@@ -447,7 +441,6 @@ int main(int argc, char* argv[])
test_update_dir();
test_comparisons();
test_hash_function();
test_null_path();
cout << "all tests passed OK" << endl;
return 0; // passed

View File

@@ -41,6 +41,7 @@
#include <simgear/misc/strutils.hxx>
#include <simgear/debug/logstream.hxx>
#include <boost/foreach.hpp>
#include <cstring>
#include <cstdlib>
@@ -114,14 +115,14 @@ Dir Dir::tempDir(const std::string& templ)
// Mac OS-X / BSD manual says any number of 'X's, but GLibc manual
// says exactly six, so that's what I'm going with
p.concat("-XXXXXX");
std::string s = p.utf8Str();
std::string s = p.local8BitStr();
::snprintf(buf, 1024, "%s", s.c_str());
if (!mkdtemp(buf)) {
SG_LOG(SG_IO, SG_WARN,
"mkdtemp failed: " << simgear::strutils::error_string(errno));
return Dir();
}
return Dir(SGPath(buf));
#else
#if defined(SG_WINDOWS)
@@ -137,7 +138,7 @@ Dir Dir::tempDir(const std::string& templ)
SG_LOG(SG_IO, SG_WARN, "failed to create temporary directory at " << p);
return Dir();
}
return t;
#endif
}
@@ -153,7 +154,7 @@ PathList Dir::children(int types, const std::string& nameFilter) const
if (types == 0) {
types = TYPE_FILE | TYPE_DIR | NO_DOT_OR_DOTDOT;
}
#if defined(SG_WINDOWS)
std::wstring search(_path.wstr());
if (nameFilter.empty()) {
@@ -161,18 +162,18 @@ PathList Dir::children(int types, const std::string& nameFilter) const
} else {
search += simgear::strutils::convertUtf8ToWString("\\*" + nameFilter);
}
WIN32_FIND_DATAW fData;
HANDLE find = FindFirstFileW(search.c_str(), &fData);
if (find == INVALID_HANDLE_VALUE) {
int err = GetLastError();
if (err != ERROR_FILE_NOT_FOUND) {
SG_LOG(SG_GENERAL, SG_WARN, "Dir::children: FindFirstFile failed:" <<
SG_LOG(SG_GENERAL, SG_WARN, "Dir::children: FindFirstFile failed:" <<
_path << " with error:" << err);
}
return result;
}
bool done = false;
for (bool done = false; !done; done = (FindNextFileW(find, &fData) == 0)) {
if (fData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
@@ -180,7 +181,7 @@ PathList Dir::children(int types, const std::string& nameFilter) const
continue;
}
}
std::string utf8File = simgear::strutils::convertWStringToUtf8(fData.cFileName);
if (fData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
if (types & NO_DOT_OR_DOTDOT) {
@@ -205,38 +206,38 @@ PathList Dir::children(int types, const std::string& nameFilter) const
FindClose(find);
#else
std::string ps = _path.utf8Str();
std::string ps = _path.local8BitStr();
DIR* dp = opendir(ps.c_str());
if (!dp) {
SG_LOG(SG_GENERAL, SG_WARN, "Dir::children: opendir failed:" << _path);
return result;
}
int filterLen = nameFilter.size();
while (true) {
struct dirent* entry = readdir(dp);
if (!entry) {
break; // done iteration
}
// skip hidden files (names beginning with '.') unless requested
if (!(types & INCLUDE_HIDDEN) && (entry->d_name[0] == '.') &&
strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) {
continue;
}
SGPath f = file(entry->d_name);
if (!f.exists()) {
continue; // stat() failed
}
if (f.isDir()) {
// directory handling
if (!(types & TYPE_DIR)) {
continue;
}
if (types & NO_DOT_OR_DOTDOT) {
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
continue;
@@ -257,17 +258,17 @@ PathList Dir::children(int types, const std::string& nameFilter) const
if (nameLen < filterLen) {
continue; // name is shorter than the filter
}
char* nameSuffix = entry->d_name + (nameLen - filterLen);
if (strcmp(nameSuffix, nameFilter.c_str())) {
continue;
}
}
// passed all criteria, add to our result vector
result.push_back(file(entry->d_name));
}
closedir(dp);
#endif
@@ -289,7 +290,7 @@ bool Dir::isEmpty() const
std::wstring ps = _path.wstr();
return PathIsDirectoryEmptyW( ps.c_str() );
#else
std::string ps = _path.utf8Str();
std::string ps = _path.local8BitStr();
DIR* dp = opendir( ps.c_str() );
if (!dp) return true;
@@ -315,7 +316,7 @@ SGPath Dir::file(const std::string& name) const
SGPath childPath = _path;
childPath.set_cached(true);
childPath.append(name);
return childPath;
return childPath;
}
bool Dir::create(mode_t mode)
@@ -323,7 +324,7 @@ bool Dir::create(mode_t mode)
if (exists()) {
return false; // already exists
}
// recursively create parent directories
Dir pr(parent());
if (!pr.path().isNull() && !pr.exists()) {
@@ -332,13 +333,13 @@ bool Dir::create(mode_t mode)
return false;
}
}
// finally, create ourselves
#if defined(SG_WINDOWS)
std::wstring ps = _path.wstr();
int err = _wmkdir(ps.c_str());
#else
std::string ps = _path.utf8Str();
std::string ps = _path.local8BitStr();
int err = mkdir(ps.c_str(), mode);
#endif
if (err) {
@@ -346,7 +347,7 @@ bool Dir::create(mode_t mode)
"directory creation failed for '" << _path.utf8Str() << "': " <<
simgear::strutils::error_string(errno));
}
return (err == 0);
}
@@ -358,20 +359,20 @@ bool Dir::removeChildren() const
bool ok;
PathList cs = children(NO_DOT_OR_DOTDOT | INCLUDE_HIDDEN | TYPE_FILE | TYPE_DIR);
for (auto path : cs) {
BOOST_FOREACH(SGPath path, cs) {
if (path.isDir()) {
Dir childDir(path);
ok = childDir.remove(true);
} else {
ok = path.remove();
}
if (!ok) {
SG_LOG(SG_IO, SG_WARN, "failed to remove:" << path);
return false;
}
} // of child iteration
return true;
}
@@ -381,7 +382,7 @@ bool Dir::remove(bool recursive)
SG_LOG(SG_IO, SG_WARN, "attempt to remove non-existant dir:" << _path);
return false;
}
if (recursive) {
if (!removeChildren()) {
SG_LOG(SG_IO, SG_WARN, "Dir at:" << _path << " failed to remove children");
@@ -393,7 +394,7 @@ bool Dir::remove(bool recursive)
std::wstring ps = _path.wstr();
int err = _wrmdir(ps.c_str());
#else
std::string ps = _path.utf8Str();
std::string ps = _path.local8BitStr();
int err = rmdir(ps.c_str());
#endif
if (err) {

View File

@@ -29,7 +29,6 @@
#include <simgear/misc/strutils.hxx>
#include <simgear/io/iostreams/sgstream.hxx>
#include <cstring>
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
@@ -48,6 +47,8 @@
#include "sg_path.hxx"
#include <boost/algorithm/string/case_conv.hpp>
using std::string;
using simgear::strutils::starts_with;
@@ -397,7 +398,7 @@ string SGPath::extension() const {
}
string SGPath::lower_extension() const {
return simgear::strutils::lowercase (extension());
return boost::to_lower_copy(extension());
}
string SGPath::complete_lower_extension() const
@@ -411,7 +412,7 @@ string SGPath::complete_lower_extension() const
string::size_type firstDot = path.find(".", index);
if ((firstDot != string::npos) && (path.find(sgDirPathSep, firstDot) == string::npos)) {
return simgear::strutils::lowercase (path.substr(firstDot + 1));
return boost::to_lower_copy(path.substr(firstDot + 1));
} else {
return "";
}
@@ -785,8 +786,8 @@ bool SGPath::rename(const SGPath& newName)
std::wstring np = newName.wstr();
if (_wrename(p.c_str(), np.c_str()) != 0)
#else
std::string p = utf8Str();
std::string np = newName.utf8Str();
std::string p = local8BitStr();
std::string np = newName.local8BitStr();
if( ::rename(p.c_str(), np.c_str()) != 0 )
#endif

View File

@@ -1,95 +0,0 @@
// -*- coding: utf-8 -*-
//
// simgear_optional.hxx --- Mimic std::optional until we can use C++14
// Copyright (C) 2020 James Turner <james@flightgear.org>
//
// 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 Street, Fifth Floor, Boston,
// MA 02110-1301 USA.
#pragma once
#include <simgear/structure/exception.hxx>
namespace simgear
{
/**
* Inefficient version of std::optional. It requires a default-constructable,
* copyable T type, unlike the real version.
*/
template <class T>
class optional
{
public:
using value_type = T;
optional() = default;
optional(const T& v) :
_value(v),
_haveValue(true)
{}
optional(const optional<T>& other) :
_value(other._value),
_haveValue(other._haveValue)
{}
optional<T>& operator=(const optional<T>& other)
{
_haveValue = other._haveValue;
_value = other._value;
return *this;
}
explicit operator bool() const
{
return _haveValue;
}
bool has_value() const
{
return _haveValue;
}
const T& value() const
{
if (!_haveValue) {
throw sg_exception("No value in optional");
}
return _value;
}
T& value()
{
if (!_haveValue) {
throw sg_exception("No value in optional");
}
return _value;
}
void reset()
{
_haveValue = false;
_value = {};
}
private:
T _value = {};
bool _haveValue = false;
};
} // of namespace simgear

View File

@@ -587,40 +587,6 @@ namespace simgear {
// reached end - longer wins
return v1parts.size() - v2parts.size();
}
bool compareVersionToWildcard(const std::string& aVersion, const std::string& aCandidate)
{
if (aCandidate == aVersion) {
return true;
}
// examine each dot-seperated component in turn, supporting a wildcard
// in the versions from the catalog.
string_list parts = split(aVersion, ".");
string_list candidateParts = split(aCandidate, ".");
const size_t partCount = parts.size();
const size_t candidatePartCount = candidateParts.size();
bool previousCandidatePartWasWildcard = false;
for (unsigned int p=0; p < partCount; ++p) {
// candidate string is too short, can match if it ended with wildcard
// part. This allows candidate '2016.*' to match '2016.1.2' and so on
if (candidatePartCount <= p) {
return previousCandidatePartWasWildcard;
}
if (candidateParts.at(p) == "*") {
// always passes
previousCandidatePartWasWildcard = true;
} else if (parts.at(p) != candidateParts.at(p)) {
return false;
}
}
return true;
}
string join(const string_list& l, const string& joinWith)
{
@@ -657,22 +623,6 @@ namespace simgear {
*p = tolower(*p);
}
}
bool iequals(const std::string& a, const std::string& b)
{
const auto lenA = a.length();
const auto lenB = b.length();
if (lenA != lenB) return false;
const char* aPtr = a.data();
const char* bPtr = b.data();
for (size_t i = 0; i < lenA; ++i) {
if (tolower(*aPtr++) != tolower(*bPtr++)) return false;
}
return true;
}
#if defined(SG_WINDOWS)
static std::wstring convertMultiByteToWString(DWORD encoding, const std::string& a)
@@ -706,7 +656,8 @@ static std::string convertWStringToMultiByte(DWORD encoding, const std::wstring&
std::wstring convertUtf8ToWString(const std::string& a)
{
#if defined(SG_WINDOWS)
return convertMultiByteToWString(CP_UTF8, a);
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> ucs2conv;
return ucs2conv.from_bytes(a);
#else
assert(sizeof(wchar_t) == 4);
std::wstring result;
@@ -756,7 +707,8 @@ std::wstring convertUtf8ToWString(const std::string& a)
std::string convertWStringToUtf8(const std::wstring& w)
{
#if defined(SG_WINDOWS)
return convertWStringToMultiByte(CP_UTF8, w);
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> ucs2conv;
return ucs2conv.to_bytes(w);
#else
assert(sizeof(wchar_t) == 4);
std::string result;
@@ -931,69 +883,6 @@ std::string encodeHex(const unsigned char* rawBytes, unsigned int length)
return hex;
}
std::vector<uint8_t> decodeHex(const std::string& input)
{
std::vector<uint8_t> result;
char* ptr = const_cast<char*>(input.data());
const char* end = ptr + input.length();
bool highNibble = true;
uint8_t b = 0;
while (ptr != end) {
const char c = *ptr;
char val = 0;
if (c == '0') {
val = 0;
if ((ptr + 1) < end) {
const auto peek = *(ptr + 1);
if (peek == 'x') {
// tolerate 0x prefixing
highNibble = true;
ptr += 2; // skip both bytes
continue;
}
}
} else if (isdigit(c)) {
val = c - '0';
} else if ((c >= 'A') && (c <= 'F')) {
val = c - 'A' + 10;
} else if ((c >= 'a') && (c <= 'f')) {
val = c - 'a' + 10;
} else {
// any other input: newline, space, tab, comma...
if (!highNibble) {
// allow a single digit to work, if we have spacing
highNibble = true;
result.push_back(b >> 4);
}
++ptr;
continue;
}
if (highNibble) {
highNibble = false;
b = val << 4;
} else {
highNibble = true;
b |= val;
result.push_back(b);
}
++ptr;
}
// watch for trailing single digit
// this is reqquired so a stirng ending in 0x3 is decoded.
if (!highNibble) {
result.push_back(b >> 4);
}
return result;
}
// Write an octal backslash-escaped respresentation of 'val' to 'buf'.
//
// At least 4 write positions must be available at 'buf'. The result is *not*
@@ -1102,16 +991,6 @@ std::string unescape(const char* s)
}
return r;
}
std::string replace(std::string source, const std::string search, const std::string replacement, std::size_t start_pos)
{
if (start_pos < source.length()) {
while ((start_pos = source.find(search, start_pos)) != std::string::npos) {
source.replace(start_pos, search.length(), replacement);
start_pos += replacement.length();
}
}
return source;
}
string sanitizePrintfFormat(const string& input)
{
@@ -1138,7 +1017,7 @@ std::string error_string(int errnum)
retcode = strerror_s(buf, sizeof(buf), errnum);
#elif defined(_GNU_SOURCE)
return std::string(strerror_r(errnum, buf, sizeof(buf)));
#elif (_POSIX_C_SOURCE >= 200112L) || defined(SG_MAC) || defined(__FreeBSD__) || defined(__OpenBSD__)
#elif (_POSIX_C_SOURCE >= 200112L) || defined(SG_MAC) || defined(__FreeBSD__)
int retcode;
// POSIX.1-2001 and POSIX.1-2008
retcode = strerror_r(errnum, buf, sizeof(buf));

View File

@@ -33,7 +33,6 @@
#include <vector>
#include <type_traits>
#include <cstdlib>
#include <cstdint>
typedef std::vector < std::string > string_list;
@@ -248,13 +247,6 @@ namespace simgear {
const std::string& v2,
int maxComponents = 0 );
/**
@brief COmpare a version string to a template version string (which can contain wildcards)
@param aVersion : a regular version such as 2017.6 or 2020.1.2
@param aCandidate : a version specifier, eg 2020.* or 21.5.*
*/
bool compareVersionToWildcard(const std::string& aVersion, const std::string& aCandidate);
/**
* Convert a string to upper case.
* @return upper case string
@@ -272,11 +264,6 @@ namespace simgear {
*/
void lowercase(std::string &s);
/**
* case-insensitive string comparisom
*/
bool iequals(const std::string& a, const std::string& b);
/**
* convert a string in the local Windows 8-bit encoding to UTF-8
* (no-op on other platforms)
@@ -312,9 +299,6 @@ namespace simgear {
std::string encodeHex(const unsigned char* rawBytes, unsigned int length);
std::vector<uint8_t> decodeHex(const std::string& input);
/**
* Backslash-escape a string for C/C++ string literal syntax.
*
@@ -344,18 +328,7 @@ namespace simgear {
inline std::string unescape(const std::string& str)
{ return unescape(str.c_str()); }
/**
* Replace matching elements of string.
*
* @param source source string
* @param search search string
* @param replace replacement string
* @param start_pos starting position for replacement in source. Checked to ensure less than length of source.
* @return string with all occurrences of search changed to replace
*/
std::string replace(std::string source, const std::string search, const std::string replacement, std::size_t start_pos = 0);
/**
/**
* Check a printf-style format string for dangerous (buffer-overflowing,
* memory re-writing) format tokens. If a problematic token is
* found, logs an error (SG_WARN) and returns an empty format string.

View File

@@ -99,16 +99,6 @@ void test_to_int()
SG_CHECK_EQUAL(strutils::to_int("-10000"), -10000);
}
void test_iequals()
{
SG_VERIFY(strutils::iequals("abcdef", "AbCDeF"));
SG_VERIFY(strutils::iequals("", ""));
SG_VERIFY(!strutils::iequals("abcdE", "ABCD"));
SG_VERIFY(strutils::iequals("%$abcdef12", "%$AbCDeF12"));
SG_VERIFY(strutils::iequals("VOR-DME", "vor-dme"));
SG_VERIFY(!strutils::iequals("VOR-DME", "vor_dme"));
}
// Auxiliary function for test_readNonNegativeInt()
void aux_readNonNegativeInt_setUpOStringStream(std::ostringstream& oss, int base)
{
@@ -458,7 +448,7 @@ void test_escape()
" ab\\nc \\\\def\\t\\r \\\\ ghi\\\\");
// U+0152 is LATIN CAPITAL LIGATURE OE. The last word is Egg translated in
// French and encoded in UTF-8 ('Œuf' if you can read UTF-8).
SG_CHECK_EQUAL(strutils::escape(u8"Un \"Bel\" '\u0152uf'"),
SG_CHECK_EQUAL(strutils::escape("Un \"Bel\" '\u0152uf'"),
"Un \\\"Bel\\\" '\\305\\222uf'");
SG_CHECK_EQUAL(strutils::escape("\a\b\f\n\r\t\v"),
"\\a\\b\\f\\n\\r\\t\\v");
@@ -628,11 +618,6 @@ void test_utf8Convert()
std::wstring aRoundTrip = strutils::convertUtf8ToWString(utf8A);
SG_VERIFY(a == aRoundTrip);
const auto wide2(L"\U0001f6eb\u2708\ufe0f\u2764\ufe0f");
std::string utf8_2 = strutils::convertWStringToUtf8(wide2);
SG_VERIFY(utf8_2 == std::string("\xf0\x9f\x9b\xab\xe2\x9c\x88\xef\xb8\x8f\xe2\x9d\xa4\xef\xb8\x8f"));
}
void test_parseGeod()
@@ -730,13 +715,6 @@ void test_formatGeod()
}
void testDecodeHex()
{
const auto decoded = simgear::strutils::decodeHex("01 0xff,0xcd \n\t99 0xcD abcdef\n\r0x1 0x2 0x3");
vector<uint8_t> data1 = {0x1, 0xff, 0xcd, 0x99, 0xcd, 0xAB, 0xCD,0xEF, 1, 2, 3};
SG_VERIFY(decoded == data1);
}
int main(int argc, char* argv[])
{
test_strip();
@@ -759,8 +737,6 @@ int main(int argc, char* argv[])
test_utf8Convert();
test_parseGeod();
test_formatGeod();
test_iequals();
testDecodeHex();
return EXIT_SUCCESS;
}

View File

@@ -157,7 +157,7 @@ static void initContext(naContext c)
c->error[0] = 0;
c->userData = 0;
}
#define BASE_SIZE 256000
static void initGlobals()
{
int i;
@@ -168,10 +168,10 @@ static void initGlobals()
globals->sem = naNewSem();
globals->lock = naNewLock();
globals->allocCount = BASE_SIZE; // reasonable starting value
globals->allocCount = 256; // reasonable starting value
for(i=0; i<NUM_NASAL_TYPES; i++)
naGC_init(&(globals->pools[i]), i);
globals->deadsz = BASE_SIZE;
globals->deadsz = 256;
globals->ndead = 0;
globals->deadBlocks = naAlloc(sizeof(void*) * globals->deadsz);
@@ -235,21 +235,6 @@ void naFreeContext(naContext c)
if(c->callChild) naFreeContext(c->callChild);
if(c->callParent) c->callParent->callChild = 0;
LOCK();
// 2019-09-21
// James adding this to ensure stray stuff in freed contexts gets GCed
// this shows up when doing a reset / shutdown of all Nasal - we drop
// all our contexts and saved refs, and run a GC pass. We expect *everything*
// to be freed but actually the freed contexts often have a ref in their
// opStack.
//
// The underlying cause is likely some operation which leaves a value on
// the opstack accidently, but tracing that down requires more Nasal-fu
// than I have right now. So instead I'm clearing the stack tops here, so
// a freed context looks the same as a new one returned by initContext.
c->fTop = c->opTop = c->markTop = 0;
c->nextFree = globals->freeContexts;
globals->freeContexts = c;
UNLOCK();
@@ -503,7 +488,7 @@ static void setMember(naContext ctx, naRef obj, naRef fld, naRef value)
return;
}
if(!IS_HASH(obj)) naRuntimeError(ctx, "non-object does not have member: %s", naStr_data(fld));
if(!IS_HASH(obj)) ERR(ctx, "non-objects have no members");
naHash_set(obj, fld, value);
ctx->opTop -= 2;
}
@@ -848,13 +833,9 @@ naRef naGetSourceFile(naContext ctx, int frame)
{
naRef f;
frame = findFrame(ctx, &ctx, frame);
if (frame >= 0) {
f = ctx->fStack[frame].func;
f = PTR(f).func->code;
if (!IS_NIL(f) && PTR(f).code)
return PTR(f).code->srcFile;
}
return naNil();
f = ctx->fStack[frame].func;
f = PTR(f).func->code;
return PTR(f).code->srcFile;
}
char* naGetError(naContext ctx)

View File

@@ -5,7 +5,6 @@ set(HEADERS
Ghost.hxx
NasalCallContext.hxx
NasalContext.hxx
NasalEmesaryInterface.hxx
NasalHash.hxx
NasalMe.hxx
NasalMethodHolder.hxx

View File

@@ -29,24 +29,20 @@
#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/mpl/has_xxx.hpp>
#include <boost/shared_ptr.hpp>
#include <map>
#include <memory>
template<class T>
inline T* get_pointer(std::weak_ptr<T> const& p)
inline T* get_pointer(boost::weak_ptr<T> const& p)
{
return p.lock().get();
}
template<class T>
inline T* get_pointer(std::shared_ptr<T> const& p)
{
return p.get();
}
template<class T>
inline T* get_pointer(SGWeakPtr<T> const& p)
{
@@ -81,7 +77,7 @@ get_pointer(T ptr)
// With old g++ on Jenkins (21.07.2014), ADL for static_pointer_cast does not
// work.
using std::static_pointer_cast;
using boost::static_pointer_cast;
using osg::static_pointer_cast;
#else
// VS (2008, 2010, ... ?) only allow this version.
@@ -197,7 +193,7 @@ namespace nasal
* int myMember();
* void doSomethingElse(const nasal::CallContext& ctx);
* }
* using MyClassPtr = std::shared_ptr<MyClass>;
* using MyClassPtr = boost::shared_ptr<MyClass>;
*
* std::string myOtherFreeMember(int num);
*
@@ -205,7 +201,7 @@ namespace nasal
* {
* // Register a nasal ghost type for MyClass. This needs to be done only
* // once before creating the first ghost instance. The exposed class needs
* // to be wrapped inside a shared pointer, eg. std::shared_ptr.
* // to be wrapped inside a shared pointer, eg. boost::shared_ptr.
* Ghost<MyClassPtr>::init("MyClass")
* // Members can be exposed by getters and setters
* .member("x", &MyClass::getX, &MyClass::setX)
@@ -215,7 +211,7 @@ namespace nasal
* .member("x_writeonly", &MyClass::setX)
* // Methods can be nearly anything callable and accepting a reference
* // to an instance of the class type. (member functions, free functions
* // and anything else bindable using std::function and std::bind)
* // and anything else bindable using boost::function and boost::bind)
* .method("myMember", &MyClass::myMember)
* .method("doSomething", &MyClass::doSomethingElse)
* .method("other", &myOtherFreeMember);
@@ -232,16 +228,16 @@ namespace nasal
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 = std::function<naRef(raw_type&, naContext)>;
using setter_t = std::function<void( raw_type&, naContext, naRef)>;
using method_t = std::function<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 =
std::function<bool(raw_type&, naContext, const std::string&, naRef&)>;
boost::function<bool(raw_type&, naContext, const std::string&, naRef&)>;
using fallback_setter_t =
std::function<bool(raw_type&, naContext, const std::string&, naRef)>;
boost::function<bool(raw_type&, naContext, const std::string&, naRef)>;
template<class Ret, class... Args>
using method_variadic_t = std::function<Ret (raw_type&, Args...)>;
using method_variadic_t = boost::function<Ret (raw_type&, Args...)>;
class MethodHolder:
public internal::MethodHolder
@@ -563,7 +559,7 @@ namespace nasal
const getter_t& getter,
const setter_t& setter = setter_t() )
{
if( getter || setter )
if( !getter.empty() || !setter.empty() )
_members[field] = member_t(getter, setter);
else
SG_LOG
@@ -590,16 +586,13 @@ namespace nasal
* of this ghost, and convert it to the given @a Param type.
*/
template<class Param>
Ghost& _get( const std::function<bool ( raw_type&,
const std::string&,
Param& )>& getter )
Ghost& _get( const boost::function<bool ( raw_type&,
const std::string&,
Param& )>& getter )
{
return _get(std::bind(convert_param_invoker<Param>,
getter,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3,
std::placeholders::_4));
return _get(boost::bind(
convert_param_invoker<Param>, getter, _1, _2, _3, _4
));
}
/**
@@ -622,7 +615,7 @@ namespace nasal
Ghost& _get(bool (raw_type::*getter)(const std::string&, Param&) const)
{
return _get(
std::function<bool (raw_type&, const std::string&, Param&)>(getter)
boost::function<bool (raw_type&, const std::string&, Param&)>(getter)
);
}
@@ -665,20 +658,20 @@ namespace nasal
* this ghost, and convert it to the given @a Param type.
*/
template<class Param>
Ghost& _set(const std::function<bool ( raw_type&,
const std::string&,
Param )>& setter)
Ghost& _set(const boost::function<bool ( raw_type&,
const std::string&,
Param )>& setter)
{
// Setter signature: bool( raw_type&,
// naContext,
// const std::string&,
// naRef )
return _set(std::bind(setter,
std::placeholders::_1,
std::placeholders::_3,
std::bind(from_nasal_ptr<Param>::get(),
std::placeholders::_2,
std::placeholders::_4)));
return _set(boost::bind(
setter,
_1,
_3,
boost::bind(from_nasal_ptr<Param>::get(), _2, _4)
));
}
/**
@@ -701,7 +694,7 @@ namespace nasal
Ghost& _set(bool (raw_type::*setter)(const std::string&, Param))
{
return _set(
std::function<bool (raw_type&, const std::string&, Param)>(setter)
boost::function<bool (raw_type&, const std::string&, Param)>(setter)
);
}
@@ -767,13 +760,10 @@ namespace nasal
Ghost& method
(
const std::string& name,
const std::function<Ret (raw_type&, const CallContext&)>& func
const boost::function<Ret (raw_type&, const CallContext&)>& func
)
{
return method(name, std::bind(method_invoker<Ret>,
func,
std::placeholders::_1,
std::placeholders::_2));
return method(name, boost::bind(method_invoker<Ret>, func, _1, _2));
}
/**
@@ -787,13 +777,16 @@ namespace nasal
const method_variadic_t<Ret, Args...>& func,
std::index_sequence<Indices...> )
{
return method<Ret>(name,
typename std::function<Ret (raw_type&, const CallContext&)>
(std::bind(func,
std::placeholders::_1,
std::bind(&Ghost::arg_from_nasal<Args>,
std::placeholders::_2,
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)...
))
);
}
template<class Ret, class... Args>
@@ -1125,20 +1118,24 @@ namespace nasal
naRef(*to_nasal_)(naContext, param_type) = &to_nasal;
// Getter signature: naRef(raw_type&, naContext)
return std::bind(to_nasal_,
std::placeholders::_2,
std::bind(getter, std::placeholders::_1));
return boost::bind
(
to_nasal_,
_2,
boost::bind(getter, _1)
);
}
template<class Param>
setter_t to_setter(void (raw_type::*setter)(Param))
{
// Setter signature: void(raw_type&, naContext, naRef)
return std::bind(setter,
std::placeholders::_1,
std::bind(from_nasal_ptr<Param>::get(),
std::placeholders::_2,
std::placeholders::_3));
return boost::bind
(
setter,
_1,
boost::bind(from_nasal_ptr<Param>::get(), _2, _3)
);
}
/**
@@ -1148,9 +1145,9 @@ namespace nasal
static
bool convert_param_invoker
(
const std::function<bool ( raw_type&,
const std::string&,
Param& )>& func,
const boost::function<bool ( raw_type&,
const std::string&,
Param& )>& func,
raw_type& obj,
naContext c,
const std::string& key,
@@ -1173,7 +1170,7 @@ namespace nasal
std::enable_if_t<!std::is_void<Ret>::value, naRef>
method_invoker
(
const std::function<Ret (raw_type&, const CallContext&)>& func,
const boost::function<Ret (raw_type&, const CallContext&)>& func,
raw_type& obj,
const CallContext& ctx
)
@@ -1189,7 +1186,7 @@ namespace nasal
std::enable_if_t<std::is_void<Ret>::value, naRef>
method_invoker
(
const std::function<Ret (raw_type&, const CallContext&)>& func,
const boost::function<Ret (raw_type&, const CallContext&)>& func,
raw_type& obj,
const CallContext& ctx
)
@@ -1227,7 +1224,7 @@ namespace nasal
// Either const CallContext& or CallContext, non-const reference
// does not make sense.
static_assert(
!std::is_same<Arg, CallContext&>::value,
!boost::is_same<Arg, CallContext&>::value,
"Only const reference and value make sense!");
return ctx;
};
@@ -1361,7 +1358,7 @@ namespace nasal
}
else if( member->second.func )
*out = member->second.func->get_naRef(c);
else if( member->second.getter )
else if( !member->second.getter.empty() )
*out = member->second.getter(obj, c);
else
return "Read-protected member";
@@ -1410,7 +1407,7 @@ namespace nasal
else if( !fallback_set(obj, c, key, val) )
naRuntimeError(c, "ghost: Failed to write (_set: %s)", key.c_str());
}
else if( !member->second.setter )
else if( member->second.setter.empty() )
naRuntimeError(c, "ghost: Write protected member: %s", key.c_str());
else if( member->second.func )
naRuntimeError(c, "ghost: Write to function: %s", key.c_str());

View File

@@ -1,120 +0,0 @@
#ifndef NASALEMESARYINTERFACE_INCLUDED
#define NASALEMESARYINTERFACE_INCLUDED 1
// Nasal Emesary receipient interface.
//
// Copyright (C) 2019 Richard Harrison rjh@zaretto.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
#include <simgear/nasal/cppbind/NasalHash.hxx>
#include <simgear/nasal/cppbind/Ghost.hxx>
#include <simgear/math/SGMath.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/emesary/Emesary.hxx>
#include <simgear/emesary/notifications.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/threads/SGThread.hxx>
#include <mutex>
#include <condition_variable>
#include <atomic>
namespace nasal
{
extern"C" {
extern int GCglobalAlloc();
extern int naGarbageCollect();
// these are used by the detailed debug in the Nasal GC.
SGTimeStamp global_timestamp;
void global_stamp() {
global_timestamp.stamp();
}
extern int global_elapsedUSec()
{
return global_timestamp.elapsedUSec();
}
}
class ThreadedGarbageCollector : public SGExclusiveThread {
public:
ThreadedGarbageCollector() : SGExclusiveThread() {}
virtual ~ThreadedGarbageCollector() {}
virtual int process(){
return naGarbageCollect();
}
};
class NasalMainLoopRecipient : public simgear::Emesary::IReceiver {
public:
NasalMainLoopRecipient() : receiveCount(0) {
simgear::Emesary::GlobalTransmitter::instance()->Register(*this);
}
virtual ~NasalMainLoopRecipient() {
simgear::Emesary::GlobalTransmitter::instance()->DeRegister(*this);
}
std::atomic<int> receiveCount;
virtual simgear::Emesary::ReceiptStatus Receive(simgear::Emesary::INotification &n)
{
simgear::Notifications::MainLoopNotification *mln = dynamic_cast<simgear::Notifications::MainLoopNotification *>(&n);
if (mln) {
switch (mln->GetValue()) {
case simgear::Notifications::MainLoopNotification::Type::Begin:
if (gct.is_running()) {
if (Active && CanWait)
gct.awaitCompletion();
else
gct.clearAwaitCompletionTime();
}
break;
case simgear::Notifications::MainLoopNotification::Type::End:
if (Active) {
if (gct.is_running())
gct.release();
}
break;
case simgear::Notifications::MainLoopNotification::Type::Started:
gct.ensure_running();
break;
case simgear::Notifications::MainLoopNotification::Type::Stopped:
gct.terminate();
break;
}
return simgear::Emesary::ReceiptStatusOK;
}
auto *gccn = dynamic_cast<simgear::Notifications::NasalGarbageCollectionConfigurationNotification *>(&n);
if (gccn) {
CanWait = gccn->GetCanWait();
Active = gccn->GetActive();
return simgear::Emesary::ReceiptStatusOK;
}
return simgear::Emesary::ReceiptStatusNotProcessed;
}
protected:
bool CanWait;
bool Active;
ThreadedGarbageCollector gct;
};
} // namespace nasal
#endif

View File

@@ -120,9 +120,9 @@ namespace nasal
* @param name Member name
*/
template<class Sig, class Key>
typename std::enable_if< std::is_function<Sig>::value,
std::function<Sig>
>::type
typename boost::enable_if< boost::is_function<Sig>,
boost::function<Sig>
>::type
get(const Key& name) const
{
BOOST_STATIC_ASSERT(( boost::is_convertible<Key, naRef>::value
@@ -237,9 +237,9 @@ namespace nasal
*/
template<bool is_other_const>
Iterator( Iterator<is_other_const> const& other,
typename std::enable_if< is_const || !is_other_const,
void*
>::type = NULL ):
typename boost::enable_if_c< is_const || !is_other_const,
void*
>::type = NULL ):
_hash(other._hash),
_index(other._index)
{}

View File

@@ -52,7 +52,7 @@ namespace nasal
return Ret();
Context ctx;
auto func = get_member<std::function<Ret (Me, Args...)>>(
auto func = get_member<boost::function<Ret (Me, Args...)>>(
ctx, _nasal_impl.get_naRef(), name
);
if( func )

View File

@@ -32,8 +32,9 @@
#include <simgear/structure/exception.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
#include <boost/function.hpp>
#include <array>
#include <functional>
#include <string>
#include <vector>
@@ -109,14 +110,14 @@ namespace nasal
bool from_nasal_helper(naContext c, naRef ref, const bool*);
/**
* Convert a Nasal function to a std::function with the given signature.
* Convert a Nasal function to a boost::function with the given signature.
*
* @tparam Sig Signature of returned function (arguments and return value
* are automatically converted using from_nasal/to_nasal)
*/
template<class Ret, class... Args>
std::function<Ret (Args...)>
from_nasal_helper(naContext c, naRef ref, const std::function<Ret (Args...)>*)
boost::function<Ret (Args...)>
from_nasal_helper(naContext c, naRef ref, const boost::function<Ret (Args...)>*)
{
if( naIsNil(ref) )
return {};
@@ -130,11 +131,11 @@ namespace nasal
}
template<class Ret, class... Args>
std::function<Ret (Args...)>
boost::function<Ret (Args...)>
from_nasal_helper(naContext c, naRef ref, Ret (*const)(Args...))
{
return
from_nasal_helper(c, ref, static_cast<std::function<Ret (Args...)>*>(0));
from_nasal_helper(c, ref, static_cast<boost::function<Ret (Args...)>*>(0));
}
/**
@@ -206,15 +207,6 @@ namespace nasal
return Vec2(vec[0], vec[1]);
}
template<class Vec4>
std::enable_if_t<is_vec4<Vec4>::value, Vec4>
from_nasal_helper(naContext c, naRef ref, const Vec4*)
{
auto vec = from_nasal_helper(c, ref, static_cast<std::array<double, 4>*>(0));
return Vec4(vec[0], vec[1], vec[2], vec[3]);
}
/**
* Convert a Nasal vector with 4 elements ([x, y, w, h]) to an SGRect
*/

View File

@@ -20,7 +20,6 @@
#ifndef SG_NASAL_TRAITS_HXX_
#define SG_NASAL_TRAITS_HXX_
#include <memory>
#include <simgear/std/type_traits.hxx>
// Forward declarations
@@ -29,8 +28,12 @@ class SGWeakReferenced;
template<class T> class SGSharedPtr;
template<class T> class SGWeakPtr;
template<class T> class SGVec2;
template<class T> class SGVec4;
namespace boost
{
template<class T> class shared_ptr;
template<class T> class weak_ptr;
}
namespace osg
{
class Referenced;
@@ -44,9 +47,6 @@ namespace osg
class Vec2d;
class Vec2f;
class Vec2s;
class Vec4f;
class Vec4d;
}
// The actual traits...
@@ -55,10 +55,6 @@ namespace nasal
template<class T>
struct is_vec2: public std::false_type {};
template<class T>
struct is_vec4: public std::false_type {};
#define SG_MAKE_TRAIT(templ,type,attr)\
template templ\
struct attr< type >: public std::true_type {};
@@ -69,10 +65,6 @@ SG_MAKE_TRAIT(<>, osg::Vec2d, is_vec2)
SG_MAKE_TRAIT(<>, osg::Vec2f, is_vec2)
SG_MAKE_TRAIT(<>, osg::Vec2s, is_vec2)
SG_MAKE_TRAIT(<class T>, SGVec4<T>, is_vec4)
SG_MAKE_TRAIT(<>, osg::Vec4d, is_vec4)
SG_MAKE_TRAIT(<>, osg::Vec4f, is_vec4)
#undef SG_MAKE_TRAIT
template<class T>
@@ -110,7 +102,7 @@ SG_MAKE_TRAIT(<>, osg::Vec4f, is_vec4)
SG_MAKE_SHARED_PTR_TRAIT(SGSharedPtr, SGWeakPtr, true)
SG_MAKE_SHARED_PTR_TRAIT(osg::ref_ptr, osg::observer_ptr, true)
SG_MAKE_SHARED_PTR_TRAIT(std::shared_ptr, std::weak_ptr, false)
SG_MAKE_SHARED_PTR_TRAIT(boost::shared_ptr, boost::weak_ptr, false)
#undef SG_MAKE_SHARED_PTR_TRAIT

View File

@@ -19,26 +19,14 @@
#include "to_nasal_helper.hxx"
#include <simgear/nasal/cppbind/NasalHash.hxx>
#include <simgear/nasal/cppbind/Ghost.hxx>
#include <simgear/nasal/cppbind/NasalEmesaryInterface.hxx>
#include <simgear/math/SGMath.hxx>
#include <simgear/misc/sg_path.hxx>
#include <boost/function.hpp>
namespace nasal
{
// create single instance of the main loop recipient for Nasal - this will self register at the
// global transmitter - and that's all that is needed to link up the background GC to the main
// loop in FG that will send out the MainLoop notifications.
//class NasalMainLoopRecipientSingleton : public simgear::Singleton<NasalMainLoopRecipient>
//{
//public:
// NasalMainLoopRecipientSingleton()
// {
// }
// virtual ~NasalMainLoopRecipientSingleton() {}
//};
NasalMainLoopRecipient mrl;
//----------------------------------------------------------------------------
naRef to_nasal_helper(naContext c, const std::string& str)
{

View File

@@ -27,10 +27,10 @@
#include <simgear/nasal/cppbind/cppbind_fwd.hxx>
#include <simgear/std/type_traits.hxx>
#include <boost/function/function_fwd.hpp>
#include <boost/call_traits.hpp>
#include <array>
#include <functional>
#include <initializer_list>
#include <map>
#include <string>
@@ -42,7 +42,7 @@ class SGPath;
namespace nasal
{
typedef std::function<naRef (CallContext)> free_function_t;
typedef boost::function<naRef (CallContext)> free_function_t;
/**
* Convert std::string to Nasal string

View File

@@ -9,6 +9,9 @@
#include <simgear/math/SGMath.hxx>
#include <simgear/structure/map.hxx>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <cstring>
enum MyEnum
@@ -76,7 +79,7 @@ struct DoubleDerived:
};
typedef std::shared_ptr<Base> BasePtr;
typedef boost::shared_ptr<Base> BasePtr;
typedef std::vector<BasePtr> BaseVec;
struct DoubleDerived2:
@@ -99,13 +102,13 @@ class SGWeakReferenceBasedClass:
};
typedef std::shared_ptr<Derived> DerivedPtr;
typedef std::shared_ptr<DoubleDerived> DoubleDerivedPtr;
typedef std::shared_ptr<DoubleDerived2> DoubleDerived2Ptr;
typedef boost::shared_ptr<Derived> DerivedPtr;
typedef boost::shared_ptr<DoubleDerived> DoubleDerivedPtr;
typedef boost::shared_ptr<DoubleDerived2> DoubleDerived2Ptr;
typedef SGSharedPtr<SGReferenceBasedClass> SGRefBasedPtr;
typedef SGSharedPtr<SGWeakReferenceBasedClass> SGWeakRefBasedPtr;
typedef std::weak_ptr<Derived> DerivedWeakPtr;
typedef boost::weak_ptr<Derived> DerivedWeakPtr;
naRef derivedFreeMember(Derived&, const nasal::CallContext&) { return naNil(); }
naRef f_derivedGetX(const Derived& d, naContext c)
@@ -231,25 +234,25 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
// 'func' is a C++ function registered to Nasal and now converted back to C++
std::function<int (int)> f = hash.get<int (int)>("func");
boost::function<int (int)> f = hash.get<int (int)>("func");
BOOST_REQUIRE( f );
BOOST_CHECK_EQUAL(f(3), 3);
std::function<std::string (int)> fs = hash.get<std::string (int)>("func");
boost::function<std::string (int)> fs = hash.get<std::string (int)>("func");
BOOST_REQUIRE( fs );
BOOST_CHECK_EQUAL(fs(14), "14");
typedef std::function<void (int)> FuncVoidInt;
typedef boost::function<void (int)> FuncVoidInt;
FuncVoidInt fvi = hash.get<FuncVoidInt>("func");
BOOST_REQUIRE( fvi );
fvi(123);
typedef std::function<std::string (const std::string&, int, float)> FuncMultiArg;
typedef boost::function<std::string (const std::string&, int, float)> FuncMultiArg;
FuncMultiArg fma = hash.get<FuncMultiArg>("func");
BOOST_REQUIRE( fma );
BOOST_CHECK_EQUAL(fma("test", 3, .5), "test");
typedef std::function<naRef (naRef)> naRefMemFunc;
typedef boost::function<naRef (naRef)> naRefMemFunc;
naRefMemFunc fmem = hash.get<naRefMemFunc>("func");
BOOST_REQUIRE( fmem );
naRef ret = fmem(hash.get_naRef()),
@@ -258,7 +261,7 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
// Check if nasal::Me gets passed as self/me and remaining arguments are
// passed on to function
typedef std::function<int (Me, int)> MeIntFunc;
typedef boost::function<int (Me, int)> MeIntFunc;
MeIntFunc fmeint = hash.get<MeIntFunc>("func");
BOOST_CHECK_EQUAL(fmeint(Me{}, 5), 5);
@@ -331,7 +334,7 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
BOOST_CHECK( naIsFunc(thisGetter) );
// ...and check if it really gets passed the correct instance
typedef std::function<unsigned long (Me)> MemFunc;
typedef boost::function<unsigned long (Me)> MemFunc;
MemFunc fGetThis = c.from_nasal<MemFunc>(thisGetter);
BOOST_REQUIRE( fGetThis );
BOOST_CHECK_EQUAL( fGetThis(Me{derived}), (unsigned long)d.get() );
@@ -358,9 +361,9 @@ BOOST_AUTO_TEST_CASE( cppbind_misc_testing )
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),
std::dynamic_pointer_cast<Derived>(d3) );
boost::dynamic_pointer_cast<Derived>(d3) );
BOOST_CHECK_EQUAL( c.from_nasal<DoubleDerived2Ptr>(derived),
std::dynamic_pointer_cast<DoubleDerived2>(d3) );
boost::dynamic_pointer_cast<DoubleDerived2>(d3) );
BOOST_CHECK_THROW( c.from_nasal<DoubleDerivedPtr>(derived), bad_nasal_cast );
std::map<std::string, BasePtr> instances;

View File

@@ -6,6 +6,10 @@
#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>
class Base1:
public virtual SGVirtualWeakReferenced
{};
@@ -39,7 +43,7 @@ typedef SGSharedPtr<SGReferenced> SGReferencedPtr;
CHECK_PTR_TRAIT_TYPE(weak, weak_ref, weak)\
CHECK_PTR_TRAIT(DerivedPtr, DerivedWeakPtr)
CHECK_PTR_TRAIT(std::shared_ptr<Base1>, std::weak_ptr<Base1>)
CHECK_PTR_TRAIT(boost::shared_ptr<Base1>, boost::weak_ptr<Base1>)
#undef CHECK_PTR_TRAIT
#undef CHECK_PTR_TRAIT_TYPE
@@ -146,11 +150,11 @@ BOOST_AUTO_TEST_CASE( ghost_casting_storage )
CHECK_PTR_STORAGE_TRAIT_TYPE(DerivedPtr, Derived)
CHECK_PTR_STORAGE_TRAIT_TYPE(DerivedWeakPtr, DerivedWeakPtr)
typedef std::shared_ptr<Derived> StdDerivedPtr;
CHECK_PTR_STORAGE_TRAIT_TYPE(StdDerivedPtr, StdDerivedPtr)
typedef boost::shared_ptr<Derived> BoostDerivedPtr;
CHECK_PTR_STORAGE_TRAIT_TYPE(BoostDerivedPtr, BoostDerivedPtr)
typedef std::weak_ptr<Derived> StdDerivedWeakPtr;
CHECK_PTR_STORAGE_TRAIT_TYPE(StdDerivedWeakPtr, StdDerivedWeakPtr)
typedef boost::weak_ptr<Derived> BoostDerivedWeakPtr;
CHECK_PTR_STORAGE_TRAIT_TYPE(BoostDerivedWeakPtr, BoostDerivedWeakPtr)
#undef CHECK_PTR_STORAGE_TRAIT_TYPE
@@ -160,8 +164,8 @@ BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<DerivedPtr>::is_intrusive::value)
BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<DerivedWeakPtr>::is_intrusive::value));
BOOST_STATIC_ASSERT(( nasal::shared_ptr_traits<SGReferencedPtr>::is_intrusive::value));
BOOST_STATIC_ASSERT((!nasal::shared_ptr_traits<std::shared_ptr<Derived> >::is_intrusive::value));
BOOST_STATIC_ASSERT((!nasal::shared_ptr_traits<std::weak_ptr<Derived> >::is_intrusive::value));
BOOST_STATIC_ASSERT((!nasal::shared_ptr_traits<boost::shared_ptr<Derived> >::is_intrusive::value));
BOOST_STATIC_ASSERT((!nasal::shared_ptr_traits<boost::weak_ptr<Derived> >::is_intrusive::value));
BOOST_AUTO_TEST_CASE( storage_traits )
{
@@ -203,8 +207,8 @@ BOOST_AUTO_TEST_CASE( bind_methods )
arg4 = a4;
}
};
using TestClassPtr = std::shared_ptr<TestClass>;
auto set_func = std::function<
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")
@@ -212,7 +216,7 @@ BOOST_AUTO_TEST_CASE( bind_methods )
.method("setReverse", set_func, std::index_sequence<3,2,1,0>{});
TestContext ctx;
auto test = std::make_shared<TestClass>();
auto test = boost::make_shared<TestClass>();
ctx.exec("me.set(1, \"s2\", \"s3\", 4);", ctx.to_me(test));
BOOST_CHECK_EQUAL(test->arg1, 1);

Some files were not shown because too many files have changed in this diff Show More