Merge branch 'next' of ssh://git.code.sf.net/p/flightgear/simgear into next
This commit is contained in:
commit
12bed8e8ad
@ -343,7 +343,7 @@ SET(CMAKE_MINSIZEREL_POSTFIX "" CACHE STRING "add a postfix, usually empty on wi
|
|||||||
|
|
||||||
# isnan might not be real symbol, so can't check using function_exists
|
# isnan might not be real symbol, so can't check using function_exists
|
||||||
check_cxx_source_compiles(
|
check_cxx_source_compiles(
|
||||||
"#include <cstdlib>
|
"#include <cmath>
|
||||||
int main() { return std::isnan(0.0);} "
|
int main() { return std::isnan(0.0);} "
|
||||||
HAVE_STD_ISNAN)
|
HAVE_STD_ISNAN)
|
||||||
|
|
||||||
|
@ -10,12 +10,13 @@
|
|||||||
#
|
#
|
||||||
# Created by Erik Hofman.
|
# Created by Erik Hofman.
|
||||||
|
|
||||||
FIND_PATH(AAX_INCLUDE_DIR aax/aeonwave.hpp
|
FIND_PATH(AAX_INCLUDE_DIR aax/aax.h
|
||||||
HINTS
|
HINTS
|
||||||
$ENV{AAXDIR}
|
$ENV{AAXDIR}
|
||||||
$ENV{ProgramFiles}/aax
|
$ENV{ProgramFiles}/aax
|
||||||
$ENV{ProgramFiles}/AeonWave
|
$ENV{ProgramFiles}/AeonWave
|
||||||
$ENV{ProgramFiles}/Adalin/AeonWave
|
$ENV{ProgramFiles}/Adalin/AeonWave
|
||||||
|
${CMAKE_SOURCE_DIR}/aax
|
||||||
PATH_SUFFIXES include
|
PATH_SUFFIXES include
|
||||||
PATHS
|
PATHS
|
||||||
~/Library/Frameworks
|
~/Library/Frameworks
|
||||||
@ -26,23 +27,35 @@ FIND_PATH(AAX_INCLUDE_DIR aax/aeonwave.hpp
|
|||||||
)
|
)
|
||||||
|
|
||||||
FIND_LIBRARY(AAX_LIBRARY
|
FIND_LIBRARY(AAX_LIBRARY
|
||||||
NAMES AAX aax AAX32 libAAX32
|
NAMES AAX aax AAX32
|
||||||
HINTS
|
HINTS
|
||||||
$ENV{AAXDIR}
|
$ENV{AAXDIR}
|
||||||
$ENV{ProgramFiles}/AAX
|
$ENV{ProgramFiles}/AAX
|
||||||
$ENV{ProgramFiles}/AeonWave
|
$ENV{ProgramFiles}/AeonWave
|
||||||
$ENV{ProgramFiles}/Adalin/AeonWave
|
$ENV{ProgramFiles}/Adalin/AeonWave
|
||||||
|
${CMAKE_BUILD_DIR}/aax
|
||||||
PATH_SUFFIXES bin lib lib/${CMAKE_LIBRARY_ARCHITECTURE} lib64 libs64 libs libs/Win32 libs/Win64
|
PATH_SUFFIXES bin lib lib/${CMAKE_LIBRARY_ARCHITECTURE} lib64 libs64 libs libs/Win32 libs/Win64
|
||||||
PATHS
|
PATHS
|
||||||
~/Library/Frameworks
|
~/Library/Frameworks
|
||||||
/Library/Frameworks
|
/Library/Frameworks
|
||||||
|
/usr/local
|
||||||
/usr
|
/usr
|
||||||
/opt
|
/opt
|
||||||
/usr/local
|
|
||||||
)
|
)
|
||||||
|
|
||||||
SET(AAX_FOUND "NO")
|
|
||||||
IF(AAX_LIBRARY AND AAX_INCLUDE_DIR)
|
IF(AAX_LIBRARY AND AAX_INCLUDE_DIR)
|
||||||
SET(AAX_FOUND "YES")
|
SET(AAX_FOUND "YES")
|
||||||
|
ELSE(AAX_LIBRARY AND AAX_INCLUDE_DIR)
|
||||||
|
IF(NOT AAX_INCLUDE_DIR)
|
||||||
|
MESSAGE(FATAL_ERROR "Unable to find the AAX library development files.")
|
||||||
|
SET(AAX_FOUND "NO")
|
||||||
|
ENDIF(NOT AAX_INCLUDE_DIR)
|
||||||
|
IF(NOT AAX_LIBRARY)
|
||||||
|
IF(SINGLE_PACKAGE)
|
||||||
|
SET(AAX_LIBRARY "${aax_BUILD_DIR}/aax/AAX32.dll")
|
||||||
|
SET(AAX_FOUND "YES")
|
||||||
|
ELSE(SINGLE_PACKAGE)
|
||||||
|
ENDIF(SINGLE_PACKAGE)
|
||||||
|
ENDIF(NOT AAX_LIBRARY)
|
||||||
ENDIF(AAX_LIBRARY AND AAX_INCLUDE_DIR)
|
ENDIF(AAX_LIBRARY AND AAX_INCLUDE_DIR)
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ find_dependency(Threads)
|
|||||||
|
|
||||||
set(SIMGEAR_HEADLESS @SIMGEAR_HEADLESS@)
|
set(SIMGEAR_HEADLESS @SIMGEAR_HEADLESS@)
|
||||||
set(SIMGEAR_SOUND @ENABLE_SOUND@)
|
set(SIMGEAR_SOUND @ENABLE_SOUND@)
|
||||||
|
set(USE_AEONWAVE @USE_AEONWAVE@)
|
||||||
|
|
||||||
# OpenAL isn't a public dependency, so maybe not needed
|
# OpenAL isn't a public dependency, so maybe not needed
|
||||||
#if (SIMGEAR_SOUND)
|
#if (SIMGEAR_SOUND)
|
||||||
|
@ -433,6 +433,7 @@ namespace canvas
|
|||||||
osg::Vec2f Element::posToLocal(const osg::Vec2f& pos) const
|
osg::Vec2f Element::posToLocal(const osg::Vec2f& pos) const
|
||||||
{
|
{
|
||||||
getMatrix();
|
getMatrix();
|
||||||
|
if (! _transform) return osg::Vec2f(pos[0], pos[1]);
|
||||||
const osg::Matrix& m = _transform->getInverseMatrix();
|
const osg::Matrix& m = _transform->getInverseMatrix();
|
||||||
return osg::Vec2f
|
return osg::Vec2f
|
||||||
(
|
(
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
# include <simgear_config.h>
|
# include <simgear_config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
#include "HLAArrayDataType.hxx"
|
#include "HLAArrayDataType.hxx"
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
# include <simgear_config.h>
|
# include <simgear_config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
#include "HLADataType.hxx"
|
#include "HLADataType.hxx"
|
||||||
|
@ -21,11 +21,11 @@
|
|||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
#include "HLAEnumeratedDataType.hxx"
|
#include <algorithm>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "HLAEnumeratedDataType.hxx"
|
#include "HLAEnumeratedDataType.hxx"
|
||||||
#include "HLADataTypeVisitor.hxx"
|
#include "HLADataTypeVisitor.hxx"
|
||||||
|
|
||||||
|
@ -19,10 +19,11 @@
|
|||||||
# include <simgear_config.h>
|
# include <simgear_config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
#include "HLAFixedRecordDataType.hxx"
|
#include "HLAFixedRecordDataType.hxx"
|
||||||
|
|
||||||
#include "HLADataTypeVisitor.hxx"
|
#include "HLADataTypeVisitor.hxx"
|
||||||
#include "HLAFixedRecordDataElement.hxx"
|
#include "HLAFixedRecordDataElement.hxx"
|
||||||
|
|
||||||
|
@ -19,12 +19,12 @@
|
|||||||
# include <simgear_config.h>
|
# include <simgear_config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
#include "HLAInteractionClass.hxx"
|
|
||||||
|
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
|
||||||
|
#include "HLAInteractionClass.hxx"
|
||||||
#include "HLADataElement.hxx"
|
#include "HLADataElement.hxx"
|
||||||
#include "HLAFederate.hxx"
|
#include "HLAFederate.hxx"
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
# include <simgear_config.h>
|
# include <simgear_config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
#include "HLAObjectClass.hxx"
|
#include "HLAObjectClass.hxx"
|
||||||
|
@ -19,10 +19,11 @@
|
|||||||
# include <simgear_config.h>
|
# include <simgear_config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
#include "HLAVariantRecordDataType.hxx"
|
#include "HLAVariantRecordDataType.hxx"
|
||||||
|
|
||||||
#include "HLADataTypeVisitor.hxx"
|
#include "HLADataTypeVisitor.hxx"
|
||||||
#include "HLAVariantRecordDataElement.hxx"
|
#include "HLAVariantRecordDataElement.hxx"
|
||||||
|
|
||||||
|
@ -22,9 +22,13 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#include <simgear_config.h>
|
#include <simgear_config.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "DNSClient.hxx"
|
#include "DNSClient.hxx"
|
||||||
#include <udns.h>
|
#include <udns.h>
|
||||||
#include <time.h>
|
#include <ctime>
|
||||||
|
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
|
|
||||||
namespace simgear {
|
namespace simgear {
|
||||||
|
@ -296,7 +296,10 @@ bool Dir::isEmpty() const
|
|||||||
|
|
||||||
int n = 0;
|
int n = 0;
|
||||||
dirent* d;
|
dirent* d;
|
||||||
while( (d = readdir(dp)) !=NULL && (n < 4) ) n++;
|
while (n < 3 && (d = readdir(dp)) != nullptr) {
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
closedir(dp);
|
closedir(dp);
|
||||||
|
|
||||||
return (n == 2); // '.' and '..' always exist
|
return (n == 2); // '.' and '..' always exist
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include <simgear/io/iostreams/sgstream.hxx>
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
#include <simgear/misc/test_macros.hxx>
|
#include <simgear/misc/test_macros.hxx>
|
||||||
#include "sg_dir.hxx"
|
#include "sg_dir.hxx"
|
||||||
@ -34,11 +35,35 @@ void test_tempDir()
|
|||||||
d.remove();
|
d.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_isEmpty()
|
||||||
|
{
|
||||||
|
simgear::Dir d = simgear::Dir::tempDir("FlightGear");
|
||||||
|
SG_VERIFY(!d.isNull() && d.exists() && d.isEmpty());
|
||||||
|
SGPath f = d.file("some file");
|
||||||
|
|
||||||
|
{ sg_ofstream file(f); } // create and close the file
|
||||||
|
SG_VERIFY(!d.isEmpty());
|
||||||
|
|
||||||
|
f.remove();
|
||||||
|
SG_VERIFY(d.isEmpty());
|
||||||
|
|
||||||
|
simgear::Dir subDir{d.file("some subdir")};
|
||||||
|
subDir.create(0777);
|
||||||
|
SG_VERIFY(!d.isEmpty());
|
||||||
|
|
||||||
|
subDir.remove();
|
||||||
|
SG_VERIFY(d.isEmpty());
|
||||||
|
|
||||||
|
d.remove();
|
||||||
|
SG_VERIFY(d.isEmpty()); // eek, but that's how it is
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
test_isNull();
|
test_isNull();
|
||||||
test_setRemoveOnDestroy();
|
test_setRemoveOnDestroy();
|
||||||
test_tempDir();
|
test_tempDir();
|
||||||
|
test_isEmpty();
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -29,10 +29,7 @@
|
|||||||
#include <cstring> // strerror_r() and strerror_s()
|
#include <cstring> // strerror_r() and strerror_s()
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
|
#include <cassert>
|
||||||
#if defined(HAVE_CPP11_CODECVT)
|
|
||||||
#include <codecvt> // new in C++11
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "strutils.hxx"
|
#include "strutils.hxx"
|
||||||
|
|
||||||
@ -44,6 +41,8 @@
|
|||||||
|
|
||||||
#if defined(SG_WINDOWS)
|
#if defined(SG_WINDOWS)
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <codecvt>
|
||||||
|
#include <locale>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
@ -656,25 +655,85 @@ static std::string convertWStringToMultiByte(DWORD encoding, const std::wstring&
|
|||||||
|
|
||||||
std::wstring convertUtf8ToWString(const std::string& a)
|
std::wstring convertUtf8ToWString(const std::string& a)
|
||||||
{
|
{
|
||||||
#ifdef SG_WINDOWS
|
#if defined(SG_WINDOWS)
|
||||||
return convertMultiByteToWString(CP_UTF8, a);
|
|
||||||
#elif defined(HAVE_CPP11_CODECVT)
|
|
||||||
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> ucs2conv;
|
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> ucs2conv;
|
||||||
return ucs2conv.from_bytes(a);
|
return ucs2conv.from_bytes(a);
|
||||||
#else
|
#else
|
||||||
return std::wstring();
|
assert(sizeof(wchar_t) == 4);
|
||||||
|
std::wstring result;
|
||||||
|
int expectedContinuationCount = 0;
|
||||||
|
wchar_t wc = 0;
|
||||||
|
|
||||||
|
for (uint8_t utf8CodePoint : a) {
|
||||||
|
// ASCII 7-bit range
|
||||||
|
if (utf8CodePoint <= 0x7f) {
|
||||||
|
if (expectedContinuationCount != 0) {
|
||||||
|
throw sg_format_exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push_back(static_cast<wchar_t>(utf8CodePoint));
|
||||||
|
} else if (expectedContinuationCount > 0) {
|
||||||
|
if ((utf8CodePoint & 0xC0) != 0x80) {
|
||||||
|
throw sg_format_exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
wc = (wc << 6) | (utf8CodePoint & 0x3F);
|
||||||
|
if (--expectedContinuationCount == 0) {
|
||||||
|
result.push_back(wc);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((utf8CodePoint & 0xE0) == 0xC0) {
|
||||||
|
expectedContinuationCount = 1;
|
||||||
|
wc = utf8CodePoint & 0x1f;
|
||||||
|
} else if ((utf8CodePoint & 0xF0) == 0xE0) {
|
||||||
|
expectedContinuationCount = 2;
|
||||||
|
wc = utf8CodePoint & 0x0f;
|
||||||
|
} else if ((utf8CodePoint & 0xF8) == 0xF0) {
|
||||||
|
expectedContinuationCount = 3;
|
||||||
|
wc =utf8CodePoint & 0x07;
|
||||||
|
} else {
|
||||||
|
// illegal UTF-8 encoding
|
||||||
|
throw sg_format_exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // of UTF-8 code point iteration
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string convertWStringToUtf8(const std::wstring& w)
|
std::string convertWStringToUtf8(const std::wstring& w)
|
||||||
{
|
{
|
||||||
#ifdef SG_WINDOWS
|
#if defined(SG_WINDOWS)
|
||||||
return convertWStringToMultiByte(CP_UTF8, w);
|
|
||||||
#elif defined(HAVE_CPP11_CODECVT)
|
|
||||||
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> ucs2conv;
|
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> ucs2conv;
|
||||||
return ucs2conv.to_bytes(w);
|
return ucs2conv.to_bytes(w);
|
||||||
#else
|
#else
|
||||||
return std::string();
|
assert(sizeof(wchar_t) == 4);
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
for (wchar_t cp : w) {
|
||||||
|
if (cp <= 0x7f) {
|
||||||
|
result.push_back(static_cast<uint8_t>(cp));
|
||||||
|
} else if (cp <= 0x07ff) {
|
||||||
|
result.push_back(0xC0 | ((cp >> 6) & 0x1f));
|
||||||
|
result.push_back(0x80 | (cp & 0x3f));
|
||||||
|
} else if (cp <= 0xffff) {
|
||||||
|
result.push_back(0xE0 | ((cp >> 12) & 0x0f));
|
||||||
|
result.push_back(0x80 | ((cp >> 6) & 0x3f));
|
||||||
|
result.push_back(0x80 | (cp & 0x3f));
|
||||||
|
} else if (cp < 0x10ffff) {
|
||||||
|
result.push_back(0xF0 | ((cp >> 18) & 0x07));
|
||||||
|
result.push_back(0x80 | ((cp >> 12) & 0x3f));
|
||||||
|
result.push_back(0x80 | ((cp >> 6) & 0x3f));
|
||||||
|
result.push_back(0x80 | (cp & 0x3f));
|
||||||
|
} else {
|
||||||
|
throw sg_format_exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -605,6 +605,20 @@ void test_readTime()
|
|||||||
SG_CHECK_EQUAL_EP(strutils::readTime("-0:0:28"), -28 * seconds);
|
SG_CHECK_EQUAL_EP(strutils::readTime("-0:0:28"), -28 * seconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_utf8Convert()
|
||||||
|
{
|
||||||
|
// F, smiley emoticon, Maths summation symbol, section sign
|
||||||
|
std::wstring a(L"\u0046\U0001F600\u2211\u00A7");
|
||||||
|
|
||||||
|
|
||||||
|
std::string utf8A = strutils::convertWStringToUtf8(a);
|
||||||
|
SG_VERIFY(utf8A == std::string("F\xF0\x9F\x98\x80\xE2\x88\x91\xC2\xA7"));
|
||||||
|
|
||||||
|
|
||||||
|
std::wstring aRoundTrip = strutils::convertUtf8ToWString(utf8A);
|
||||||
|
SG_VERIFY(a == aRoundTrip);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
test_strip();
|
test_strip();
|
||||||
@ -624,6 +638,7 @@ int main(int argc, char* argv[])
|
|||||||
test_error_string();
|
test_error_string();
|
||||||
test_propPathMatch();
|
test_propPathMatch();
|
||||||
test_readTime();
|
test_readTime();
|
||||||
|
test_utf8Convert();
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -787,6 +787,11 @@ void naGCRelease(int key)
|
|||||||
naHash_delete(globals->save_hash, naNum(key));
|
naHash_delete(globals->save_hash, naNum(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int naNumSaved()
|
||||||
|
{
|
||||||
|
return naHash_size(globals->save_hash) + naVec_size(globals->save);
|
||||||
|
}
|
||||||
|
|
||||||
void naClearSaved()
|
void naClearSaved()
|
||||||
{
|
{
|
||||||
naContext c;
|
naContext c;
|
||||||
|
@ -139,10 +139,9 @@ namespace nasal
|
|||||||
template<class Base>
|
template<class Base>
|
||||||
ObjectHolder<Base>::ObjectHolder(naRef obj):
|
ObjectHolder<Base>::ObjectHolder(naRef obj):
|
||||||
_ref(obj),
|
_ref(obj),
|
||||||
_gc_key(0)
|
_gc_key(naIsNil(obj) ? 0 : naGCSave(obj))
|
||||||
{
|
{
|
||||||
if( !naIsNil(obj) )
|
|
||||||
naGCSave(obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@ -159,7 +158,7 @@ namespace nasal
|
|||||||
SGSharedPtr<ObjectHolder<Base> >
|
SGSharedPtr<ObjectHolder<Base> >
|
||||||
ObjectHolder<Base>::makeShared(naRef obj)
|
ObjectHolder<Base>::makeShared(naRef obj)
|
||||||
{
|
{
|
||||||
return SGSharedPtr<ObjectHolder<Base> >( new ObjectHolder<SGReferenced>(obj) );
|
return SGSharedPtr<ObjectHolder<Base> >( new ObjectHolder<Base>(obj) );
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace nasal
|
} // namespace nasal
|
||||||
|
@ -39,7 +39,7 @@ namespace nasal
|
|||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
bad_nasal_cast::~bad_nasal_cast() throw()
|
bad_nasal_cast::~bad_nasal_cast()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ namespace nasal
|
|||||||
*/
|
*/
|
||||||
explicit bad_nasal_cast(const std::string& msg);
|
explicit bad_nasal_cast(const std::string& msg);
|
||||||
|
|
||||||
virtual ~bad_nasal_cast() throw();
|
virtual ~bad_nasal_cast();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string _msg;
|
std::string _msg;
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
#include <BoostTestTargetConfig.h>
|
#include <BoostTestTargetConfig.h>
|
||||||
|
|
||||||
#include "TestContext.hxx"
|
#include "TestContext.hxx"
|
||||||
|
|
||||||
|
#include <simgear/nasal/cppbind/NasalObjectHolder.hxx>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
@ -91,3 +94,47 @@ BOOST_AUTO_TEST_CASE( ghost_gc )
|
|||||||
|
|
||||||
BOOST_REQUIRE(active_instances.empty());
|
BOOST_REQUIRE(active_instances.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
BOOST_AUTO_TEST_CASE( object_holder_gc )
|
||||||
|
{
|
||||||
|
TestContext c;
|
||||||
|
BOOST_REQUIRE_EQUAL(naNumSaved(), 0);
|
||||||
|
BOOST_REQUIRE(active_instances.empty());
|
||||||
|
|
||||||
|
//-----------------------------------------------
|
||||||
|
// Put some ghosts in ObjectHolder and check if
|
||||||
|
// they are saved from gc
|
||||||
|
|
||||||
|
naRef g1 = createTestGhost(c, 1),
|
||||||
|
g2 = createTestGhost(c, 2);
|
||||||
|
|
||||||
|
nasal::ObjectHolder<> h1(g1);
|
||||||
|
BOOST_CHECK_EQUAL(naNumSaved(), 1);
|
||||||
|
BOOST_CHECK(naIsGhost(h1.get_naRef()));
|
||||||
|
|
||||||
|
nasal::ObjectHolder<> h2(g2);
|
||||||
|
BOOST_CHECK_EQUAL(naNumSaved(), 2);
|
||||||
|
BOOST_CHECK(naIsGhost(h2.get_naRef()));
|
||||||
|
|
||||||
|
c.runGC();
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(active_instances.size(), 2);
|
||||||
|
BOOST_CHECK_EQUAL(naNumSaved(), 2);
|
||||||
|
|
||||||
|
h1.reset(naNum(1));
|
||||||
|
h2.reset(naNum(2));
|
||||||
|
BOOST_CHECK_EQUAL(naNumSaved(), 2);
|
||||||
|
|
||||||
|
//-----------------------------------------------
|
||||||
|
// Check that the saved objects are released
|
||||||
|
|
||||||
|
h1.reset();
|
||||||
|
BOOST_CHECK_EQUAL(naNumSaved(), 1);
|
||||||
|
|
||||||
|
h2.reset();
|
||||||
|
BOOST_CHECK_EQUAL(naNumSaved(), 0);
|
||||||
|
|
||||||
|
c.runGC();
|
||||||
|
BOOST_CHECK_EQUAL(active_instances.size(), 0);
|
||||||
|
}
|
||||||
|
@ -58,6 +58,10 @@ int naGCSave(naRef obj);
|
|||||||
// by the garbage collector.
|
// by the garbage collector.
|
||||||
void naGCRelease(int key);
|
void naGCRelease(int key);
|
||||||
|
|
||||||
|
// Get the number of currently saved and not yet again released objects
|
||||||
|
// (saved by naSave or naGCSave)
|
||||||
|
int naNumSaved();
|
||||||
|
|
||||||
// Drop all saved references
|
// Drop all saved references
|
||||||
void naClearSaved();
|
void naClearSaved();
|
||||||
|
|
||||||
|
@ -2443,6 +2443,7 @@ SGPropertyNode::fireValueChanged (SGPropertyNode * node)
|
|||||||
{
|
{
|
||||||
if (_listeners != 0) {
|
if (_listeners != 0) {
|
||||||
for (unsigned int i = 0; i < _listeners->size(); i++) {
|
for (unsigned int i = 0; i < _listeners->size(); i++) {
|
||||||
|
if ((*_listeners)[i])
|
||||||
(*_listeners)[i]->valueChanged(node);
|
(*_listeners)[i]->valueChanged(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2581,20 +2582,20 @@ std::ostream& SGRawBase<SGVec4d>::printOn(std::ostream& stream) const
|
|||||||
namespace simgear
|
namespace simgear
|
||||||
{
|
{
|
||||||
#if !PROPS_STANDALONE
|
#if !PROPS_STANDALONE
|
||||||
template<>
|
template<>
|
||||||
std::istream& readFrom<SGVec4d>(std::istream& stream, SGVec4d& result)
|
std::istream& readFrom<SGVec4d>(std::istream& stream, SGVec4d& result)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 4; ++i) {
|
for (int i = 0; i < 4; ++i) {
|
||||||
stream >> result[i];
|
stream >> result[i];
|
||||||
}
|
}
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
bool compareNodeValue(const SGPropertyNode& lhs, const SGPropertyNode& rhs)
|
bool compareNodeValue(const SGPropertyNode& lhs, const SGPropertyNode& rhs)
|
||||||
{
|
{
|
||||||
props::Type ltype = lhs.getType();
|
props::Type ltype = lhs.getType();
|
||||||
props::Type rtype = rhs.getType();
|
props::Type rtype = rhs.getType();
|
||||||
if (ltype != rtype)
|
if (ltype != rtype)
|
||||||
@ -2626,8 +2627,32 @@ bool compareNodeValue(const SGPropertyNode& lhs, const SGPropertyNode& rhs)
|
|||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
void SGPropertyNode::copy(SGPropertyNode *to)
|
||||||
|
{
|
||||||
|
if (nChildren())
|
||||||
|
{
|
||||||
|
for (int i = 0; i < nChildren(); i++) {
|
||||||
|
SGPropertyNode *child = getChild(i);
|
||||||
|
SGPropertyNode *to_child = to->getChild(child->getName());
|
||||||
|
if (!to_child)
|
||||||
|
to_child = to->addChild(child->getName());
|
||||||
|
if (child->nChildren())
|
||||||
|
{
|
||||||
|
child->copy(to_child);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
to_child->setValue(child->getStringValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
to->setValue(getStringValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SGPropertyNode::compare(const SGPropertyNode& lhs,
|
bool SGPropertyNode::compare(const SGPropertyNode& lhs,
|
||||||
|
@ -1105,6 +1105,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
SGPropertyNode * getNode (const char * relative_path, bool create = false);
|
SGPropertyNode * getNode (const char * relative_path, bool create = false);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* deep copy one node to another.
|
||||||
|
*/
|
||||||
|
void copy(SGPropertyNode *to);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a pointer to another node by relative path.
|
* Get a pointer to another node by relative path.
|
||||||
*/
|
*/
|
||||||
|
@ -161,8 +161,7 @@ setFlag( int& mode,
|
|||||||
string message = "Unrecognized flag value '";
|
string message = "Unrecognized flag value '";
|
||||||
message += flag;
|
message += flag;
|
||||||
message += '\'';
|
message += '\'';
|
||||||
// FIXME: add location info
|
throw sg_io_exception(message, location, SG_ORIGIN);
|
||||||
throw sg_io_exception(message, location, "SimGear Property Reader");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +176,7 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
|
|||||||
string message = "Root element name is ";
|
string message = "Root element name is ";
|
||||||
message += name;
|
message += name;
|
||||||
message += "; expected PropertyList";
|
message += "; expected PropertyList";
|
||||||
throw sg_io_exception(message, location, "SimGear Property Reader");
|
throw sg_io_exception(message, location, SG_ORIGIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for an include.
|
// Check for an include.
|
||||||
@ -189,8 +188,7 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
|
|||||||
{
|
{
|
||||||
string message ="Cannot open file ";
|
string message ="Cannot open file ";
|
||||||
message += attval;
|
message += attval;
|
||||||
throw sg_io_exception(message, location,
|
throw sg_io_exception(message, location, SG_ORIGIN);
|
||||||
"SimGear Property Reader");
|
|
||||||
}
|
}
|
||||||
readProperties(path, _root, 0, _extended);
|
readProperties(path, _root, 0, _extended);
|
||||||
} catch (sg_io_exception &e) {
|
} catch (sg_io_exception &e) {
|
||||||
@ -277,7 +275,7 @@ PropsVisitor::startElement (const char * name, const XMLAttributes &atts)
|
|||||||
{
|
{
|
||||||
string message ="Cannot open file ";
|
string message ="Cannot open file ";
|
||||||
message += val;
|
message += val;
|
||||||
throw sg_io_exception(message, location, "SimGear Property Reader");
|
throw sg_io_exception(message, location, SG_ORIGIN);
|
||||||
}
|
}
|
||||||
readProperties(path, node, 0, _extended);
|
readProperties(path, node, 0, _extended);
|
||||||
}
|
}
|
||||||
@ -352,8 +350,7 @@ PropsVisitor::endElement (const char * name)
|
|||||||
string message = "Unrecognized data type '";
|
string message = "Unrecognized data type '";
|
||||||
message += st.type;
|
message += st.type;
|
||||||
message += '\'';
|
message += '\'';
|
||||||
// FIXME: add location information
|
throw sg_io_exception(message, location, SG_ORIGIN);
|
||||||
throw sg_io_exception(message, location, "SimGear Property Reader");
|
|
||||||
}
|
}
|
||||||
if( !ret )
|
if( !ret )
|
||||||
SG_LOG
|
SG_LOG
|
||||||
@ -770,7 +767,7 @@ copyPropertyValue(const SGPropertyNode *in, SGPropertyNode *out)
|
|||||||
break;
|
break;
|
||||||
string message = "Unknown internal SGPropertyNode type";
|
string message = "Unknown internal SGPropertyNode type";
|
||||||
message += in->getType();
|
message += in->getType();
|
||||||
throw sg_error(message, "SimGear Property Reader");
|
throw sg_error(message, SG_ORIGIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <simgear/compiler.h>
|
#include <simgear/compiler.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <memory> // std::unique_ptr
|
#include <memory> // std::unique_ptr
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -85,7 +85,7 @@ BuilderException::BuilderException(const std::string& message,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
BuilderException::~BuilderException() throw()
|
BuilderException::~BuilderException()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -184,7 +184,7 @@ public:
|
|||||||
BuilderException();
|
BuilderException();
|
||||||
BuilderException(const char* message, const char* origin = 0);
|
BuilderException(const char* message, const char* origin = 0);
|
||||||
BuilderException(const std::string& message, const std::string& = "");
|
BuilderException(const std::string& message, const std::string& = "");
|
||||||
virtual ~BuilderException() throw();
|
virtual ~BuilderException();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -832,3 +832,157 @@ SGSliderAnimation::setupCallbacks(SGSceneUserData* ud, osg::Group*)
|
|||||||
{
|
{
|
||||||
ud->setPickCallback(new KnobSliderPickCallback(getConfig(), getModelRoot()));
|
ud->setPickCallback(new KnobSliderPickCallback(getConfig(), getModelRoot()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* touch screen is a 2d surface that will pass parameters to the callbacks indicating the
|
||||||
|
* normalized coordinates of hover or touch. Touch is defined as a button click.
|
||||||
|
* For compatibility with touchscreen operations this class does not differentiate between
|
||||||
|
* which buttons are touched, simply because this isn't how touchscreens work.
|
||||||
|
* Some touchscreens (e.g. SAW) can have a Z-axis indicating the pressure. This is not
|
||||||
|
* simulated.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle picking events on object with a canvas placed onto
|
||||||
|
*/
|
||||||
|
class TouchPickCallback : public SGPickCallback {
|
||||||
|
public:
|
||||||
|
TouchPickCallback(const SGPropertyNode* configNode,
|
||||||
|
SGPropertyNode* modelRoot) :
|
||||||
|
_repeatable(configNode->getBoolValue("repeatable", false)),
|
||||||
|
_repeatInterval(configNode->getDoubleValue("interval-sec", 0.1)),
|
||||||
|
SGPickCallback(PriorityPanel)
|
||||||
|
{
|
||||||
|
std::vector<SGPropertyNode_ptr> bindings;
|
||||||
|
|
||||||
|
bindings = configNode->getChildren("touch");
|
||||||
|
for (unsigned int i = 0; i < bindings.size(); ++i) {
|
||||||
|
_touches.insert(bindings[i]->getIntValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
_bindingsTouched = readBindingList(configNode->getChildren("binding"), modelRoot);
|
||||||
|
readOptionalBindingList(configNode, modelRoot, "mod-up", _bindingsReleased);
|
||||||
|
|
||||||
|
if (configNode->hasChild("cursor")) {
|
||||||
|
_cursorName = configNode->getStringValue("cursor");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void addHoverBindings(const SGPropertyNode* hoverNode,
|
||||||
|
SGPropertyNode* modelRoot)
|
||||||
|
{
|
||||||
|
_hover = readBindingList(hoverNode->getChildren("binding"), modelRoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool buttonPressed(int touchIdx,
|
||||||
|
const osgGA::GUIEventAdapter& event,
|
||||||
|
const Info& info)
|
||||||
|
{
|
||||||
|
if (_touches.find(touchIdx) == _touches.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!anyBindingEnabled(_bindingsTouched)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
SGPropertyNode_ptr params(new SGPropertyNode);
|
||||||
|
params->setDoubleValue("x", info.uv[0]);
|
||||||
|
params->setDoubleValue("y", info.uv[1]);
|
||||||
|
|
||||||
|
_repeatTime = -_repeatInterval; // anti-bobble: delay start of repeat
|
||||||
|
fireBindingList(_bindingsTouched, params.ptr());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual void buttonReleased(int keyModState,
|
||||||
|
const osgGA::GUIEventAdapter&,
|
||||||
|
const Info* info)
|
||||||
|
{
|
||||||
|
SG_UNUSED(keyModState);
|
||||||
|
SGPropertyNode_ptr params(new SGPropertyNode);
|
||||||
|
params->setDoubleValue("x", info->uv[0]);
|
||||||
|
params->setDoubleValue("y", info->uv[1]);
|
||||||
|
fireBindingList(_bindingsReleased, params.ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void update(double dt, int keyModState)
|
||||||
|
{
|
||||||
|
SG_UNUSED(keyModState);
|
||||||
|
if (!_repeatable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_repeatTime += dt;
|
||||||
|
while (_repeatInterval < _repeatTime) {
|
||||||
|
_repeatTime -= _repeatInterval;
|
||||||
|
fireBindingList(_bindingsTouched);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool hover(const osg::Vec2d& windowPos,
|
||||||
|
const Info& info)
|
||||||
|
{
|
||||||
|
if (!anyBindingEnabled(_hover)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SGPropertyNode_ptr params(new SGPropertyNode);
|
||||||
|
params->setDoubleValue("x", info.uv[0]);
|
||||||
|
params->setDoubleValue("y", info.uv[1]);
|
||||||
|
fireBindingList(_hover, params.ptr());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getCursor() const
|
||||||
|
{
|
||||||
|
return _cursorName;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool needsUV() const { return true; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
SGBindingList _bindingsTouched;
|
||||||
|
SGBindingList _bindingsReleased;
|
||||||
|
SGBindingList _hover;
|
||||||
|
std::set<int> _touches;
|
||||||
|
std::string _cursorName;
|
||||||
|
bool _repeatable;
|
||||||
|
double _repeatInterval;
|
||||||
|
double _repeatTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
SGTouchAnimation::SGTouchAnimation(simgear::SGTransientModelData &modelData) :
|
||||||
|
SGPickAnimation(modelData)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Group* SGTouchAnimation::createMainGroup(osg::Group* pr)
|
||||||
|
{
|
||||||
|
SGRotateTransform* transform = new SGRotateTransform();
|
||||||
|
pr->addChild(transform);
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SGTouchAnimation::setupCallbacks(SGSceneUserData* ud, osg::Group*)
|
||||||
|
{
|
||||||
|
TouchPickCallback* touchCb = NULL;
|
||||||
|
|
||||||
|
// add actions that become macro and command invocations
|
||||||
|
std::vector<SGPropertyNode_ptr> actions;
|
||||||
|
actions = getConfig()->getChildren("action");
|
||||||
|
for (unsigned int i = 0; i < actions.size(); ++i) {
|
||||||
|
touchCb = new TouchPickCallback(actions[i], getModelRoot());
|
||||||
|
ud->addPickCallback(touchCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getConfig()->hasChild("hovered")) {
|
||||||
|
if (!touchCb) {
|
||||||
|
// make a trivial PickCallback to hang the hovered off of
|
||||||
|
SGPropertyNode_ptr dummyNode(new SGPropertyNode);
|
||||||
|
touchCb = new TouchPickCallback(dummyNode.ptr(), getModelRoot());
|
||||||
|
ud->addPickCallback(touchCb);
|
||||||
|
}
|
||||||
|
|
||||||
|
touchCb->addHoverBindings(getConfig()->getNode("hovered"), getModelRoot());
|
||||||
|
}
|
||||||
|
// ud->setPickCallback(new TouchPickCallback(getConfig(), getModelRoot()));
|
||||||
|
}
|
||||||
|
@ -114,5 +114,19 @@ private:
|
|||||||
SGSharedPtr<SGExpressiond const> _animationValue;
|
SGSharedPtr<SGExpressiond const> _animationValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SGTouchAnimation : public SGPickAnimation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SGTouchAnimation(simgear::SGTransientModelData &modelData);
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual osg::Group* createMainGroup(osg::Group* pr);
|
||||||
|
|
||||||
|
virtual void setupCallbacks(SGSceneUserData* ud, osg::Group* parent);
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
#endif // of SG_SCENE_PICK_ANIMATION_HXX
|
#endif // of SG_SCENE_PICK_ANIMATION_HXX
|
||||||
|
|
||||||
|
@ -226,7 +226,7 @@ namespace {
|
|||||||
{
|
{
|
||||||
string typeString(aNode->getStringValue("type"));
|
string typeString(aNode->getStringValue("type"));
|
||||||
// exclude these so we don't show yellow outlines in preview mode
|
// exclude these so we don't show yellow outlines in preview mode
|
||||||
return (typeString == "pick") || (typeString == "knob") || (typeString == "slider");
|
return (typeString == "pick") || (typeString == "knob") || (typeString == "slider") || (typeString == "touch");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -497,6 +497,9 @@ SGAnimation::animate(simgear::SGTransientModelData &modelData)
|
|||||||
} else if (type == "slider") {
|
} else if (type == "slider") {
|
||||||
SGSliderAnimation anim(modelData);
|
SGSliderAnimation anim(modelData);
|
||||||
anim.apply(modelData.getNode());
|
anim.apply(modelData.getNode());
|
||||||
|
} else if (type == "touch") {
|
||||||
|
SGTouchAnimation anim(modelData);
|
||||||
|
anim.apply(modelData.getNode());
|
||||||
} else if (type == "range") {
|
} else if (type == "range") {
|
||||||
SGRangeAnimation anim(modelData);
|
SGRangeAnimation anim(modelData);
|
||||||
anim.apply(modelData);
|
anim.apply(modelData);
|
||||||
@ -769,7 +772,7 @@ bool SGAnimation::setCenterAndAxisFromObject(osg::Node *rootNode, SGVec3d& cente
|
|||||||
object_group->setNodeMask(0);
|
object_group->setNodeMask(0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
SG_LOG(SG_INPUT, SG_ALERT, "Could find a valid line segment for animation: " << axis_object_name);
|
SG_LOG(SG_INPUT, SG_ALERT, "Could not find a valid line segment for animation: " << axis_object_name);
|
||||||
}
|
}
|
||||||
else if (can_warn)
|
else if (can_warn)
|
||||||
SG_LOG(SG_INPUT, SG_ALERT, "Could not find at least one of the following objects for axis animation: " << axis_object_name);
|
SG_LOG(SG_INPUT, SG_ALERT, "Could not find at least one of the following objects for axis animation: " << axis_object_name);
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
//
|
//
|
||||||
// $Id$
|
// $Id$
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#ifndef _SG_INLINES_H
|
#ifndef _SG_INLINES_H
|
||||||
#define _SG_INLINES_H
|
#define _SG_INLINES_H
|
||||||
@ -109,4 +110,19 @@ inline void SG_NORMALIZE_RANGE( T &val, const T min, const T max ) {
|
|||||||
Class(const Class &); \
|
Class(const Class &); \
|
||||||
Class &operator=(const Class &);
|
Class &operator=(const Class &);
|
||||||
|
|
||||||
|
namespace simgear {
|
||||||
|
|
||||||
|
// A swap() that is guaranteed to be 'noexcept' as long as compilation
|
||||||
|
// succeeds. Idea and implementation from
|
||||||
|
// <https://akrzemi1.wordpress.com/2011/06/10/using-noexcept/>.
|
||||||
|
template<typename T>
|
||||||
|
void noexceptSwap(T& a, T& b) noexcept
|
||||||
|
{
|
||||||
|
using std::swap;
|
||||||
|
static_assert(noexcept(swap(a, b)), "this swap() is not 'noexcept'" );
|
||||||
|
swap(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // of namespace simgear
|
||||||
|
|
||||||
#endif // _SG_INLINES_H
|
#endif // _SG_INLINES_H
|
||||||
|
@ -4,16 +4,15 @@ set(HEADERS
|
|||||||
sample.hxx
|
sample.hxx
|
||||||
sample_group.hxx
|
sample_group.hxx
|
||||||
xmlsound.hxx
|
xmlsound.hxx
|
||||||
readwav.hxx
|
|
||||||
soundmgr.hxx
|
soundmgr.hxx
|
||||||
|
filters.hxx
|
||||||
)
|
)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
sample.cxx
|
sample.cxx
|
||||||
sample_group.cxx
|
sample_group.cxx
|
||||||
xmlsound.cxx
|
xmlsound.cxx
|
||||||
readwav.cxx
|
filters.cxx
|
||||||
soundmgr_openal_private.hxx
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (USE_AEONWAVE)
|
if (USE_AEONWAVE)
|
||||||
@ -21,8 +20,13 @@ if (USE_AEONWAVE)
|
|||||||
soundmgr_aeonwave.cxx
|
soundmgr_aeonwave.cxx
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
|
set(HEADERS ${HEADERS}
|
||||||
|
readwav.hxx
|
||||||
|
)
|
||||||
set(SOURCES ${SOURCES}
|
set(SOURCES ${SOURCES}
|
||||||
soundmgr_openal.cxx
|
soundmgr_openal.cxx
|
||||||
|
soundmgr_openal_private.hxx
|
||||||
|
readwav.cxx
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
@ -66,15 +66,15 @@ int main( int argc, char *argv[] )
|
|||||||
std::cout << "Vendor: " << _vendor << std::endl;
|
std::cout << "Vendor: " << _vendor << std::endl;
|
||||||
std::cout << "Renderer: " << _renderer << std::endl;
|
std::cout << "Renderer: " << _renderer << std::endl;
|
||||||
|
|
||||||
aax::Matrix64 mtx64;
|
aax::Matrix mtx;
|
||||||
mtx64.translate(-5000.0, 12500.0, 1000.0);
|
mtx.translate(-5000.0, 12500.0, 1000.0);
|
||||||
|
|
||||||
aax::Matrix mtx = mtx64.toMatrix();
|
aax::Matrix64 mtx64 = mtx.toMatrix64();
|
||||||
emitter.matrix(mtx);
|
emitter.matrix(mtx64);
|
||||||
|
|
||||||
mtx.translate(-5.0, 2.0, 1.0);
|
mtx.translate(-5.0, 2.0, 1.0);
|
||||||
mtx.inverse();
|
mtx64.inverse();
|
||||||
aax.sensor_matrix(mtx);
|
aax.sensor_matrix(mtx64);
|
||||||
|
|
||||||
aax.set(AAX_PLAYING);
|
aax.set(AAX_PLAYING);
|
||||||
emitter.set(AAX_PLAYING);
|
emitter.set(AAX_PLAYING);
|
||||||
|
169
simgear/sound/filters.cxx
Normal file
169
simgear/sound/filters.cxx
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007-2017 by Erik Hofman.
|
||||||
|
* Copyright 2009-2017 by Adalin B.V.
|
||||||
|
*
|
||||||
|
* This file is part of SimGear
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the Lesser GNU General Public License as published
|
||||||
|
* by the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the Lesser GNU General Public License
|
||||||
|
* along with this program;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <simgear/constants.h>
|
||||||
|
#include "filters.hxx"
|
||||||
|
|
||||||
|
namespace simgear {
|
||||||
|
|
||||||
|
FreqFilter::FreqFilter(int order, float sample_freq, float cutoff_freq, float Qfactor) {
|
||||||
|
|
||||||
|
Q = Qfactor;
|
||||||
|
fs = sample_freq;
|
||||||
|
no_stages = order / 2;
|
||||||
|
gain = order;
|
||||||
|
|
||||||
|
butterworth_compute(cutoff_freq);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < 2*SG_FREQFILTER_MAX_STAGES; ++i) {
|
||||||
|
hist[i] = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FreqFilter::~FreqFilter() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreqFilter::update( int16_t *data, unsigned int num) {
|
||||||
|
|
||||||
|
if (num) {
|
||||||
|
float k = gain;
|
||||||
|
for (unsigned int stage = 0; stage < no_stages; ++stage) {
|
||||||
|
|
||||||
|
float h0 = hist[2*stage + 0];
|
||||||
|
float h1 = hist[2*stage + 1];
|
||||||
|
unsigned int i = num;
|
||||||
|
do {
|
||||||
|
float nsmp, smp = data[i] * k;
|
||||||
|
smp = smp + h0 * coeff[4*stage + 0];
|
||||||
|
nsmp = smp + h1 * coeff[4*stage + 1];
|
||||||
|
smp = nsmp + h0 * coeff[4*stage + 2];
|
||||||
|
smp = smp + h1 * coeff[4*stage + 3];
|
||||||
|
|
||||||
|
h1 = h0;
|
||||||
|
h0 = nsmp;
|
||||||
|
data[i] = smp;
|
||||||
|
}
|
||||||
|
while (--i);
|
||||||
|
|
||||||
|
hist[2*stage + 0] = h0;
|
||||||
|
hist[2*stage + 1] = h1;
|
||||||
|
k = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void FreqFilter::bilinear(float a0, float a1, float a2,
|
||||||
|
float b0, float b1, float b2,
|
||||||
|
float *k, int stage) {
|
||||||
|
a2 *= 4.0f;
|
||||||
|
b2 *= 4.0f;
|
||||||
|
a1 *= 2.0f;
|
||||||
|
b1 *= 2.0f;
|
||||||
|
|
||||||
|
float ad = a2 + a1 + a0;
|
||||||
|
float bd = b2 + b1 + b0;
|
||||||
|
|
||||||
|
*k *= ad/bd;
|
||||||
|
|
||||||
|
coeff[4*stage + 0] = 2.0f*(-b2 + b0) / bd;
|
||||||
|
coeff[4*stage + 1] = (b2 - b1 + b0) / bd;
|
||||||
|
coeff[4*stage + 2] = 2.0f*(-a2 + a0) / ad;
|
||||||
|
coeff[4*stage + 3] = (a2 - a1 + a0) / ad;
|
||||||
|
|
||||||
|
// negate to prevent this is required every time the filter is applied.
|
||||||
|
coeff[4*stage + 0] = -coeff[4*stage + 0];
|
||||||
|
coeff[4*stage + 1] = -coeff[4*stage + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert from S-domain to Z-domain
|
||||||
|
inline void FreqFilter::bilinear_s2z(float *a0, float *a1, float *a2,
|
||||||
|
float *b0, float *b1, float *b2,
|
||||||
|
float fc, float fs, float *k, int stage) {
|
||||||
|
// prewarp
|
||||||
|
float wp = 2.0f*tanf(SG_PI * fc/fs);
|
||||||
|
|
||||||
|
*a2 /= wp*wp;
|
||||||
|
*b2 /= wp*wp;
|
||||||
|
*a1 /= wp;
|
||||||
|
*b1 /= wp;
|
||||||
|
|
||||||
|
bilinear(*a0, *a1, *a2, *b0, *b1, *b2, k, stage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreqFilter::butterworth_compute(float fc) {
|
||||||
|
|
||||||
|
// http://www.ti.com/lit/an/sloa049b/sloa049b.pdf
|
||||||
|
static const float _Q[SG_FREQFILTER_MAX_STAGES][SG_FREQFILTER_MAX_STAGES]= {
|
||||||
|
{ 0.7071f, 1.0f, 1.0f, 1.0f }, // 2nd order
|
||||||
|
{ 0.5412f, 1.3605f, 1.0f, 1.0f }, // 4th order
|
||||||
|
{ 0.5177f, 0.7071f, 1.9320f, 1.0f }, // 6th roder
|
||||||
|
{ 0.5098f, 0.6013f, 0.8999f, 2.5628f } // 8th order
|
||||||
|
};
|
||||||
|
|
||||||
|
gain = 1.0f;
|
||||||
|
|
||||||
|
int pos = no_stages-1;
|
||||||
|
for (unsigned i = 0; i < no_stages; ++i)
|
||||||
|
{
|
||||||
|
float a2 = 0.0f;
|
||||||
|
float a1 = 0.0f;
|
||||||
|
float a0 = 1.0f;
|
||||||
|
|
||||||
|
float b2 = 1.0f;
|
||||||
|
float b1 = 1.0f/(_Q[pos][i] * Q);
|
||||||
|
float b0 = 1.0f;
|
||||||
|
|
||||||
|
// fill the filter coefficients
|
||||||
|
bilinear_s2z(&a0, &a1, &a2, &b0, &b1, &b2, fc, fs, &gain, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
BitCrusher::BitCrusher(float level) {
|
||||||
|
|
||||||
|
float bits = level * 15.0f;
|
||||||
|
factor = powf(2.0f, bits);
|
||||||
|
devider = 1.0f/factor;
|
||||||
|
}
|
||||||
|
|
||||||
|
BitCrusher::~BitCrusher() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void BitCrusher::update( int16_t *data, unsigned int num ) {
|
||||||
|
|
||||||
|
if (num && factor < 1.0f) {
|
||||||
|
unsigned int i = num;
|
||||||
|
do {
|
||||||
|
float integral;
|
||||||
|
|
||||||
|
modff(data[i]*devider, &integral);
|
||||||
|
data[i] = integral*factor;
|
||||||
|
} while (--i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace simgear
|
||||||
|
|
77
simgear/sound/filters.hxx
Normal file
77
simgear/sound/filters.hxx
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007-2017 by Erik Hofman.
|
||||||
|
* Copyright 2009-2017 by Adalin B.V.
|
||||||
|
*
|
||||||
|
* This file is part of SimGear
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the Lesser GNU General Public License as published
|
||||||
|
* by the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the Lesser GNU General Public License
|
||||||
|
* along with this program;
|
||||||
|
* if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _SIMGEAR_FREQUENCY_FILTER_HXX
|
||||||
|
#define _SIMGEAR_FREQUENCY_FILTER_HXX
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace simgear {
|
||||||
|
|
||||||
|
// Every stage is a 2nd order filter
|
||||||
|
// Four stages therefore equals to an 8th order filter with a 48dB/oct slope.
|
||||||
|
#define SG_FREQFILTER_MAX_STAGES 4
|
||||||
|
|
||||||
|
class FreqFilter {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
float fs, Q, gain;
|
||||||
|
float coeff[4*SG_FREQFILTER_MAX_STAGES];
|
||||||
|
float hist[2*SG_FREQFILTER_MAX_STAGES];
|
||||||
|
unsigned char no_stages;
|
||||||
|
|
||||||
|
void butterworth_compute(float fc);
|
||||||
|
void bilinear(float a0, float a1, float a2,
|
||||||
|
float b0, float b1, float b2,
|
||||||
|
float *k, int stage);
|
||||||
|
void bilinear_s2z(float *a0, float *a1, float *a2,
|
||||||
|
float *b0, float *b1, float *b2,
|
||||||
|
float fc, float fs, float *k, int stage);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
FreqFilter(int order, float fs, float cutoff, float Qfactor = 1.0f);
|
||||||
|
~FreqFilter();
|
||||||
|
|
||||||
|
void update( int16_t *data, unsigned int num );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class BitCrusher {
|
||||||
|
|
||||||
|
private:
|
||||||
|
float factor, devider;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// level ranges from 0.0f (all muted) to 1.0f (no change)
|
||||||
|
BitCrusher(float level);
|
||||||
|
~BitCrusher();
|
||||||
|
|
||||||
|
void update( int16_t *data, unsigned int num );
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace simgear
|
||||||
|
|
||||||
|
#endif // _SIMGEAR_FREQUENCY_FILTER_HXX
|
@ -92,14 +92,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void init() {
|
void init() {
|
||||||
_mtx = aax::Matrix();
|
_mtx = aax::Matrix64();
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_pos_and_orientation()
|
void update_pos_and_orientation()
|
||||||
{
|
{
|
||||||
SGVec3d sgv_at = _orientation.backTransform(-SGVec3d::e3());
|
SGVec3d sgv_at = _orientation.backTransform(-SGVec3d::e3());
|
||||||
SGVec3d sgv_up = _orientation.backTransform(SGVec3d::e2());
|
SGVec3d sgv_up = _orientation.backTransform(SGVec3d::e2());
|
||||||
SGVec3f pos = SGVec3f::zeros();
|
SGVec3d pos = SGVec3d::zeros();
|
||||||
|
|
||||||
_mtx.set(pos.data(), toVec3f(sgv_at).data(), toVec3f(sgv_up).data());
|
_mtx.set(pos.data(), toVec3f(sgv_at).data(), toVec3f(sgv_up).data());
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
aax::AeonWave _aax;
|
aax::AeonWave _aax;
|
||||||
aax::Matrix _mtx;
|
aax::Matrix64 _mtx;
|
||||||
|
|
||||||
SGVec3d _absolute_pos;
|
SGVec3d _absolute_pos;
|
||||||
SGVec3d _base_pos;
|
SGVec3d _base_pos;
|
||||||
@ -338,7 +338,7 @@ void SGSoundMgr::update( double dt )
|
|||||||
TRY( dsp.set(AAX_SOUND_VELOCITY, 340.3f) );
|
TRY( dsp.set(AAX_SOUND_VELOCITY, 340.3f) );
|
||||||
TRY( d->_aax.set(dsp) );
|
TRY( d->_aax.set(dsp) );
|
||||||
#endif
|
#endif
|
||||||
aax::Matrix mtx = d->_mtx;
|
aax::Matrix64 mtx = d->_mtx;
|
||||||
mtx.inverse();
|
mtx.inverse();
|
||||||
TRY( d->_aax.sensor_matrix(mtx) );
|
TRY( d->_aax.sensor_matrix(mtx) );
|
||||||
|
|
||||||
@ -465,7 +465,7 @@ unsigned int SGSoundMgr::request_buffer(SGSoundSample *sample)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bufid = d->_buffer_id++;
|
bufid = d->_buffer_id++;
|
||||||
d->_buffers.insert( std::make_pair<unsigned int,aax::Buffer&>(bufid,buf) );
|
d->_buffers.insert( {bufid, buf} );
|
||||||
|
|
||||||
if ( !sample->is_file() ) {
|
if ( !sample->is_file() ) {
|
||||||
enum aaxFormat format = AAX_FORMAT_NONE;
|
enum aaxFormat format = AAX_FORMAT_NONE;
|
||||||
@ -493,7 +493,7 @@ unsigned int SGSoundMgr::request_buffer(SGSoundSample *sample)
|
|||||||
unsigned int no_samples = sample->get_no_samples();
|
unsigned int no_samples = sample->get_no_samples();
|
||||||
unsigned int no_tracks = sample->get_no_tracks();
|
unsigned int no_tracks = sample->get_no_tracks();
|
||||||
unsigned int frequency = sample->get_frequency();
|
unsigned int frequency = sample->get_frequency();
|
||||||
TRY( buf.set(d->_aax, no_samples, no_tracks, format) );
|
buf.set(d->_aax, no_samples, no_tracks, format);
|
||||||
TRY( buf.set(AAX_FREQUENCY, frequency) );
|
TRY( buf.set(AAX_FREQUENCY, frequency) );
|
||||||
TRY( buf.fill(sample->get_data()) );
|
TRY( buf.fill(sample->get_data()) );
|
||||||
|
|
||||||
@ -659,11 +659,11 @@ void SGSoundMgr::update_sample_config( SGSoundSample *sample, SGVec3d& position,
|
|||||||
aax::Emitter& emitter = d->get_emitter(sample->get_source());
|
aax::Emitter& emitter = d->get_emitter(sample->get_source());
|
||||||
aax::dsp dsp;
|
aax::dsp dsp;
|
||||||
|
|
||||||
aax::Vector pos = toVec3f(position).data();
|
aax::Vector64 pos = position.data();
|
||||||
aax::Vector ori = orientation.data();
|
aax::Vector ori = orientation.data();
|
||||||
aax::Vector vel = velocity.data();
|
aax::Vector vel = velocity.data();
|
||||||
|
|
||||||
aax::Matrix mtx(pos, ori);
|
aax::Matrix64 mtx(pos, ori);
|
||||||
TRY( emitter.matrix(mtx) );
|
TRY( emitter.matrix(mtx) );
|
||||||
TRY( emitter.velocity(vel) );
|
TRY( emitter.velocity(vel) );
|
||||||
|
|
||||||
@ -763,7 +763,8 @@ void SGSoundMgr::set_position( const SGVec3d& pos, const SGGeod& pos_geod )
|
|||||||
|
|
||||||
SGVec3f SGSoundMgr::get_direction() const
|
SGVec3f SGSoundMgr::get_direction() const
|
||||||
{
|
{
|
||||||
aaxVec3f pos, at, up;
|
aaxVec3f at, up;
|
||||||
|
aaxVec3d pos;
|
||||||
d->_mtx.get(pos, at, up);
|
d->_mtx.get(pos, at, up);
|
||||||
return SGVec3f( at );
|
return SGVec3f( at );
|
||||||
}
|
}
|
||||||
|
@ -60,14 +60,13 @@ add_executable(test_expressions expression_test.cxx)
|
|||||||
target_link_libraries(test_expressions ${TEST_LIBS})
|
target_link_libraries(test_expressions ${TEST_LIBS})
|
||||||
add_test(expressions ${EXECUTABLE_OUTPUT_PATH}/test_expressions)
|
add_test(expressions ${EXECUTABLE_OUTPUT_PATH}/test_expressions)
|
||||||
|
|
||||||
|
add_executable(test_shared_ptr shared_ptr_test.cpp)
|
||||||
|
target_link_libraries(test_shared_ptr ${TEST_LIBS})
|
||||||
|
add_test(shared_ptr ${EXECUTABLE_OUTPUT_PATH}/test_shared_ptr)
|
||||||
|
|
||||||
endif(ENABLE_TESTS)
|
endif(ENABLE_TESTS)
|
||||||
|
|
||||||
add_boost_test(function_list
|
add_boost_test(function_list
|
||||||
SOURCES function_list_test.cxx
|
SOURCES function_list_test.cxx
|
||||||
LIBRARIES ${TEST_LIBS}
|
LIBRARIES ${TEST_LIBS}
|
||||||
)
|
)
|
||||||
|
|
||||||
add_boost_test(shared_ptr
|
|
||||||
SOURCES shared_ptr_test.cpp
|
|
||||||
LIBRARIES ${TEST_LIBS}
|
|
||||||
)
|
|
||||||
|
@ -43,7 +43,7 @@ public:
|
|||||||
|
|
||||||
static unsigned get(const SGReferenced* ref)
|
static unsigned get(const SGReferenced* ref)
|
||||||
{ if (ref) return ++(ref->_refcount); else return 0; }
|
{ if (ref) return ++(ref->_refcount); else return 0; }
|
||||||
static unsigned put(const SGReferenced* ref)
|
static unsigned put(const SGReferenced* ref) noexcept
|
||||||
{ if (ref) return --(ref->_refcount); else return 0; }
|
{ if (ref) return --(ref->_refcount); else return 0; }
|
||||||
static unsigned count(const SGReferenced* ref)
|
static unsigned count(const SGReferenced* ref)
|
||||||
{ if (ref) return ref->_refcount; else return 0; }
|
{ if (ref) return ref->_refcount; else return 0; }
|
||||||
|
@ -20,8 +20,9 @@
|
|||||||
#ifndef SGSharedPtr_HXX
|
#ifndef SGSharedPtr_HXX
|
||||||
#define SGSharedPtr_HXX
|
#define SGSharedPtr_HXX
|
||||||
|
|
||||||
|
#include <simgear/sg_inlines.h>
|
||||||
|
|
||||||
#include "SGReferenced.hxx"
|
#include "SGReferenced.hxx"
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class SGWeakPtr;
|
class SGWeakPtr;
|
||||||
@ -50,12 +51,16 @@ class SGSharedPtr {
|
|||||||
public:
|
public:
|
||||||
typedef T element_type;
|
typedef T element_type;
|
||||||
|
|
||||||
SGSharedPtr(void) : _ptr(0)
|
SGSharedPtr(void) noexcept
|
||||||
|
: _ptr(0)
|
||||||
{}
|
{}
|
||||||
SGSharedPtr(T* ptr) : _ptr(ptr)
|
SGSharedPtr(T* ptr) : _ptr(ptr)
|
||||||
{ get(_ptr); }
|
{ get(_ptr); }
|
||||||
SGSharedPtr(const SGSharedPtr& p) : _ptr(p.get())
|
SGSharedPtr(const SGSharedPtr& p) : _ptr(p.get())
|
||||||
{ get(_ptr); }
|
{ get(_ptr); }
|
||||||
|
SGSharedPtr(SGSharedPtr&& other) noexcept
|
||||||
|
: SGSharedPtr()
|
||||||
|
{ swap(other); }
|
||||||
template<typename U>
|
template<typename U>
|
||||||
SGSharedPtr(const SGSharedPtr<U>& p) : _ptr(p.get())
|
SGSharedPtr(const SGSharedPtr<U>& p) : _ptr(p.get())
|
||||||
{ get(_ptr); }
|
{ get(_ptr); }
|
||||||
@ -67,6 +72,17 @@ public:
|
|||||||
|
|
||||||
SGSharedPtr& operator=(const SGSharedPtr& p)
|
SGSharedPtr& operator=(const SGSharedPtr& p)
|
||||||
{ reset(p.get()); return *this; }
|
{ reset(p.get()); return *this; }
|
||||||
|
|
||||||
|
SGSharedPtr& operator=(SGSharedPtr&& p) noexcept
|
||||||
|
{ // Whether self-move is to be supported at all is controversial, let's
|
||||||
|
// take the conservative approach for now
|
||||||
|
if (this != &p) {
|
||||||
|
swap(p);
|
||||||
|
p.reset();
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
SGSharedPtr& operator=(const SGSharedPtr<U>& p)
|
SGSharedPtr& operator=(const SGSharedPtr<U>& p)
|
||||||
{ reset(p.get()); return *this; }
|
{ reset(p.get()); return *this; }
|
||||||
@ -86,7 +102,7 @@ public:
|
|||||||
{ return _ptr; }
|
{ return _ptr; }
|
||||||
T* release()
|
T* release()
|
||||||
{ T* tmp = _ptr; _ptr = 0; T::put(tmp); return tmp; }
|
{ T* tmp = _ptr; _ptr = 0; T::put(tmp); return tmp; }
|
||||||
void reset()
|
void reset() noexcept
|
||||||
{ if (!T::put(_ptr)) delete _ptr; _ptr = 0; }
|
{ if (!T::put(_ptr)) delete _ptr; _ptr = 0; }
|
||||||
void reset(T* p)
|
void reset(T* p)
|
||||||
{ SGSharedPtr(p).swap(*this); }
|
{ SGSharedPtr(p).swap(*this); }
|
||||||
@ -101,8 +117,8 @@ public:
|
|||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{ reset(); }
|
{ reset(); }
|
||||||
void swap(SGSharedPtr& other)
|
void swap(SGSharedPtr& other) noexcept
|
||||||
{ std::swap(_ptr, other._ptr); }
|
{ simgear::noexceptSwap(_ptr, other._ptr); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void assignNonRef(T* p)
|
void assignNonRef(T* p)
|
||||||
@ -118,6 +134,12 @@ private:
|
|||||||
friend class SGWeakPtr;
|
friend class SGWeakPtr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
void swap(SGSharedPtr<T>& a, SGSharedPtr<T>& b) noexcept
|
||||||
|
{
|
||||||
|
a.swap(b);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Support for boost::mem_fn
|
* Support for boost::mem_fn
|
||||||
*/
|
*/
|
||||||
|
@ -49,7 +49,7 @@ sg_location::sg_location (const char* path, int line, int column)
|
|||||||
setPath(path);
|
setPath(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
sg_location::~sg_location () throw ()
|
sg_location::~sg_location ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +144,7 @@ sg_throwable::sg_throwable (const char* message, const char* origin)
|
|||||||
setOrigin(origin);
|
setOrigin(origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
sg_throwable::~sg_throwable () throw ()
|
sg_throwable::~sg_throwable ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +185,7 @@ sg_throwable::setOrigin (const char* origin)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* sg_throwable::what() const throw()
|
const char* sg_throwable::what() const noexcept
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return getMessage();
|
return getMessage();
|
||||||
@ -215,7 +215,7 @@ sg_error::sg_error(const std::string& message, const std::string& origin)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
sg_error::~sg_error () throw ()
|
sg_error::~sg_error ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,7 +239,7 @@ sg_exception::sg_exception( const std::string& message,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
sg_exception::~sg_exception () throw ()
|
sg_exception::~sg_exception ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,7 +279,7 @@ sg_io_exception::sg_io_exception( const std::string& message,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
sg_io_exception::~sg_io_exception () throw ()
|
sg_io_exception::~sg_io_exception ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,7 +335,7 @@ sg_format_exception::sg_format_exception( const std::string& message,
|
|||||||
setText(text.c_str());
|
setText(text.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
sg_format_exception::~sg_format_exception () throw ()
|
sg_format_exception::~sg_format_exception ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,7 +379,7 @@ sg_range_exception::sg_range_exception(const std::string& message,
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
sg_range_exception::~sg_range_exception () throw ()
|
sg_range_exception::~sg_range_exception ()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
// end of exception.cxx
|
// end of exception.cxx
|
||||||
|
@ -31,7 +31,7 @@ public:
|
|||||||
sg_location(const std::string& path, int line = -1, int column = -1);
|
sg_location(const std::string& path, int line = -1, int column = -1);
|
||||||
sg_location(const SGPath& path, int line = -1, int column = -1);
|
sg_location(const SGPath& path, int line = -1, int column = -1);
|
||||||
explicit sg_location(const char* path, int line = -1, int column = -1);
|
explicit sg_location(const char* path, int line = -1, int column = -1);
|
||||||
virtual ~sg_location() throw ();
|
virtual ~sg_location();
|
||||||
virtual const char* getPath() const;
|
virtual const char* getPath() const;
|
||||||
virtual void setPath (const char* path);
|
virtual void setPath (const char* path);
|
||||||
virtual int getLine () const;
|
virtual int getLine () const;
|
||||||
@ -58,13 +58,13 @@ public:
|
|||||||
enum {MAX_TEXT_LEN = 1024};
|
enum {MAX_TEXT_LEN = 1024};
|
||||||
sg_throwable ();
|
sg_throwable ();
|
||||||
sg_throwable (const char* message, const char* origin = 0);
|
sg_throwable (const char* message, const char* origin = 0);
|
||||||
virtual ~sg_throwable () throw ();
|
virtual ~sg_throwable ();
|
||||||
virtual const char* getMessage () const;
|
virtual const char* getMessage () const;
|
||||||
virtual const std::string getFormattedMessage () const;
|
virtual const std::string getFormattedMessage () const;
|
||||||
virtual void setMessage (const char* message);
|
virtual void setMessage (const char* message);
|
||||||
virtual const char* getOrigin () const;
|
virtual const char* getOrigin () const;
|
||||||
virtual void setOrigin (const char *origin);
|
virtual void setOrigin (const char *origin);
|
||||||
virtual const char* what() const throw();
|
virtual const char* what() const noexcept;
|
||||||
private:
|
private:
|
||||||
char _message[MAX_TEXT_LEN];
|
char _message[MAX_TEXT_LEN];
|
||||||
char _origin[MAX_TEXT_LEN];
|
char _origin[MAX_TEXT_LEN];
|
||||||
@ -87,7 +87,7 @@ public:
|
|||||||
sg_error ();
|
sg_error ();
|
||||||
sg_error (const char* message, const char* origin = 0);
|
sg_error (const char* message, const char* origin = 0);
|
||||||
sg_error (const std::string& message, const std::string& origin = "");
|
sg_error (const std::string& message, const std::string& origin = "");
|
||||||
virtual ~sg_error () throw ();
|
virtual ~sg_error ();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ public:
|
|||||||
sg_exception ();
|
sg_exception ();
|
||||||
sg_exception (const char* message, const char* origin = 0);
|
sg_exception (const char* message, const char* origin = 0);
|
||||||
sg_exception (const std::string& message, const std::string& = "");
|
sg_exception (const std::string& message, const std::string& = "");
|
||||||
virtual ~sg_exception () throw ();
|
virtual ~sg_exception ();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ public:
|
|||||||
sg_io_exception (const std::string &message, const sg_location &location,
|
sg_io_exception (const std::string &message, const sg_location &location,
|
||||||
const std::string &origin = "");
|
const std::string &origin = "");
|
||||||
|
|
||||||
virtual ~sg_io_exception () throw ();
|
virtual ~sg_io_exception ();
|
||||||
virtual const std::string getFormattedMessage () const;
|
virtual const std::string getFormattedMessage () const;
|
||||||
virtual const sg_location &getLocation () const;
|
virtual const sg_location &getLocation () const;
|
||||||
virtual void setLocation (const sg_location &location);
|
virtual void setLocation (const sg_location &location);
|
||||||
@ -165,7 +165,7 @@ public:
|
|||||||
const char* origin = 0);
|
const char* origin = 0);
|
||||||
sg_format_exception (const std::string& message, const std::string& text,
|
sg_format_exception (const std::string& message, const std::string& text,
|
||||||
const std::string& origin = "");
|
const std::string& origin = "");
|
||||||
virtual ~sg_format_exception () throw ();
|
virtual ~sg_format_exception ();
|
||||||
virtual const char* getText () const;
|
virtual const char* getText () const;
|
||||||
virtual void setText (const char* text);
|
virtual void setText (const char* text);
|
||||||
private:
|
private:
|
||||||
@ -190,7 +190,7 @@ public:
|
|||||||
const char* origin = 0);
|
const char* origin = 0);
|
||||||
sg_range_exception (const std::string& message,
|
sg_range_exception (const std::string& message,
|
||||||
const std::string& origin = "");
|
const std::string& origin = "");
|
||||||
virtual ~sg_range_exception () throw ();
|
virtual ~sg_range_exception ();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
/// Unit tests for reference counting and smart pointer classes
|
// -*- coding: utf-8 -*-
|
||||||
#define BOOST_TEST_MODULE structure
|
//
|
||||||
#include <BoostTestTargetConfig.h>
|
// Unit tests for reference counting and smart pointer classes
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <cstdlib> // EXIT_SUCCESS
|
||||||
|
|
||||||
|
#include <simgear/misc/test_macros.hxx>
|
||||||
|
|
||||||
#include "SGSharedPtr.hxx"
|
#include "SGSharedPtr.hxx"
|
||||||
#include "SGWeakPtr.hxx"
|
#include "SGWeakPtr.hxx"
|
||||||
@ -21,33 +28,152 @@ struct ReferenceCounted:
|
|||||||
};
|
};
|
||||||
typedef SGSharedPtr<ReferenceCounted> RefPtr;
|
typedef SGSharedPtr<ReferenceCounted> RefPtr;
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( shared_ptr )
|
void test_SGSharedPtr()
|
||||||
{
|
{
|
||||||
BOOST_REQUIRE_EQUAL( ReferenceCounted::count(0), 0 );
|
std::cout << "Testing SGSharedPtr and SGReferenced" << std::endl;
|
||||||
|
|
||||||
|
SG_CHECK_EQUAL( ReferenceCounted::count(0), 0 );
|
||||||
|
|
||||||
RefPtr ptr( new ReferenceCounted() );
|
RefPtr ptr( new ReferenceCounted() );
|
||||||
BOOST_REQUIRE_EQUAL( instance_count, 1 );
|
SG_CHECK_EQUAL( instance_count, 1 );
|
||||||
BOOST_REQUIRE_EQUAL( ReferenceCounted::count(ptr.get()), 1 );
|
SG_CHECK_EQUAL( ReferenceCounted::count(ptr.get()), 1 );
|
||||||
BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 1 );
|
SG_CHECK_EQUAL( ptr.getNumRefs(), 1 );
|
||||||
|
|
||||||
|
// Test SGSharedPtr's copy assignment operator
|
||||||
RefPtr ptr2 = ptr;
|
RefPtr ptr2 = ptr;
|
||||||
BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 2 );
|
SG_CHECK_EQUAL( ptr.getNumRefs(), 2 );
|
||||||
BOOST_REQUIRE_EQUAL( ptr2.getNumRefs(), 2 );
|
SG_CHECK_EQUAL( ptr2.getNumRefs(), 2 );
|
||||||
|
|
||||||
BOOST_REQUIRE_EQUAL( ptr, ptr2 );
|
SG_CHECK_EQUAL( ptr, ptr2 );
|
||||||
BOOST_REQUIRE_EQUAL( ptr.get(), ptr2.get() );
|
SG_CHECK_EQUAL( ptr.get(), ptr2.get() );
|
||||||
|
|
||||||
|
// Test SGSharedPtr::reset() with no argument
|
||||||
ptr.reset();
|
ptr.reset();
|
||||||
BOOST_REQUIRE( !ptr.get() );
|
SG_CHECK_IS_NULL( ptr.get() );
|
||||||
BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 0 );
|
SG_CHECK_EQUAL( ptr.getNumRefs(), 0 );
|
||||||
BOOST_REQUIRE_EQUAL( ReferenceCounted::count(ptr2.get()), 1 );
|
SG_CHECK_EQUAL( ReferenceCounted::count(ptr2.get()), 1 );
|
||||||
BOOST_REQUIRE_EQUAL( ptr2.getNumRefs(), 1 );
|
SG_CHECK_EQUAL( ptr2.getNumRefs(), 1 );
|
||||||
|
|
||||||
ptr2.reset();
|
ptr2.reset();
|
||||||
BOOST_REQUIRE( !ptr2.get() );
|
SG_CHECK_IS_NULL( ptr2.get() );
|
||||||
BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 0 );
|
SG_CHECK_EQUAL( ptr.getNumRefs(), 0 );
|
||||||
BOOST_REQUIRE_EQUAL( ptr2.getNumRefs(), 0 );
|
SG_CHECK_EQUAL( ptr2.getNumRefs(), 0 );
|
||||||
BOOST_REQUIRE_EQUAL( instance_count, 0) ;
|
SG_CHECK_EQUAL( instance_count, 0) ;
|
||||||
|
|
||||||
|
// Test operator==() and operator!=() for SGSharedPtr
|
||||||
|
{
|
||||||
|
RefPtr ptrA(new ReferenceCounted());
|
||||||
|
RefPtr ptrB(ptrA);
|
||||||
|
RefPtr ptrC(new ReferenceCounted());
|
||||||
|
RefPtr emptyPtr{};
|
||||||
|
SG_CHECK_EQUAL( ptrA, ptrB );
|
||||||
|
SG_CHECK_EQUAL( ptrA.get(), ptrB.get() ); // same thing by definition
|
||||||
|
SG_CHECK_NE( ptrA, ptrC );
|
||||||
|
SG_CHECK_NE( ptrA.get(), ptrC.get() );
|
||||||
|
SG_CHECK_NE( ptrB, ptrC );
|
||||||
|
SG_CHECK_NE( ptrA, emptyPtr );
|
||||||
|
SG_CHECK_EQUAL( emptyPtr, emptyPtr );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test SGSharedPtr::reset(T* p) and SGSharedPtr::operator T*()
|
||||||
|
{
|
||||||
|
RefPtr ptrA(new ReferenceCounted());
|
||||||
|
SG_CHECK_EQUAL( ptrA.getNumRefs(), 1 );
|
||||||
|
|
||||||
|
RefPtr ptrB(new ReferenceCounted());
|
||||||
|
SG_CHECK_NE( ptrA, ptrB );
|
||||||
|
ptrB.reset(ptrA);
|
||||||
|
SG_CHECK_EQUAL( ptrA, ptrB );
|
||||||
|
SG_CHECK_EQUAL( ptrA.getNumRefs(), 2 );
|
||||||
|
SG_CHECK_EQUAL( ptrB.getNumRefs(), 2 );
|
||||||
|
|
||||||
|
RefPtr ptrC(new ReferenceCounted());
|
||||||
|
SG_CHECK_NE( ptrA, ptrC );
|
||||||
|
SG_CHECK_EQUAL( ptrC.getNumRefs(), 1 );
|
||||||
|
// ptrA is implicit converted to ReferenceCounted*
|
||||||
|
ptrC.reset(ptrA);
|
||||||
|
SG_CHECK_EQUAL( ptrA.getNumRefs(), 3 );
|
||||||
|
SG_CHECK_EQUAL( ptrB.getNumRefs(), 3 );
|
||||||
|
SG_CHECK_EQUAL( ptrC.getNumRefs(), 3 );
|
||||||
|
SG_CHECK_EQUAL( ptrA, ptrB );
|
||||||
|
SG_CHECK_EQUAL( ptrB, ptrC );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test SGSharedPtr's copy constructor
|
||||||
|
{
|
||||||
|
RefPtr ptrA(new ReferenceCounted());
|
||||||
|
SG_CHECK_EQUAL( ptrA.getNumRefs(), 1 );
|
||||||
|
|
||||||
|
RefPtr ptrB(ptrA);
|
||||||
|
SG_CHECK_EQUAL( ptrA.getNumRefs(), 2 );
|
||||||
|
SG_CHECK_EQUAL( ptrB.getNumRefs(), 2 );
|
||||||
|
SG_CHECK_EQUAL( ptrA, ptrB );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test SGSharedPtr's move constructor
|
||||||
|
{
|
||||||
|
RefPtr ptrA(new ReferenceCounted());
|
||||||
|
RefPtr ptrB(ptrA);
|
||||||
|
RefPtr ptrC(std::move(ptrA));
|
||||||
|
|
||||||
|
SG_CHECK_EQUAL( ptrB.getNumRefs(), 2 );
|
||||||
|
SG_CHECK_EQUAL( ptrC.getNumRefs(), 2 );
|
||||||
|
SG_CHECK_EQUAL( ptrB, ptrC );
|
||||||
|
// Although our implementation has these two properties, they are
|
||||||
|
// absolutely *not* guaranteed by the C++ move semantics:
|
||||||
|
SG_CHECK_EQUAL( ptrA.getNumRefs(), 0 );
|
||||||
|
SG_CHECK_IS_NULL( ptrA.get() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test SGSharedPtr's move assignment operator: self-move, supposedly
|
||||||
|
// undefined behavior but certainly safer as a no-op---which the
|
||||||
|
// copy-and-swap idiom offers for free.
|
||||||
|
{
|
||||||
|
RefPtr ptrA(new ReferenceCounted());
|
||||||
|
RefPtr ptrB(ptrA);
|
||||||
|
|
||||||
|
ptrA = std::move(ptrA);
|
||||||
|
SG_CHECK_EQUAL( ptrA.getNumRefs(), 2 );
|
||||||
|
SG_CHECK_EQUAL( ptrB.getNumRefs(), 2 );
|
||||||
|
SG_CHECK_IS_NOT_NULL( ptrA.get() );
|
||||||
|
SG_CHECK_EQUAL( ptrA, ptrB );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test SGSharedPtr's move assignment operator: move to an empty SGSharedPtr
|
||||||
|
{
|
||||||
|
RefPtr ptrA;
|
||||||
|
RefPtr ptrB(new ReferenceCounted());
|
||||||
|
|
||||||
|
ptrA = std::move(ptrB);
|
||||||
|
SG_CHECK_EQUAL( ptrA.getNumRefs(), 1 );
|
||||||
|
SG_CHECK_IS_NOT_NULL( ptrA.get() );
|
||||||
|
// Implementation detail that is *not* guaranteed by the C++ move
|
||||||
|
// semantics:
|
||||||
|
SG_CHECK_EQUAL( ptrB.getNumRefs(), 0 );
|
||||||
|
SG_CHECK_IS_NULL( ptrB.get() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test SGSharedPtr's move assignment operator: move to a non-empty
|
||||||
|
// SGSharedPtr
|
||||||
|
{
|
||||||
|
RefPtr ptrA(new ReferenceCounted());
|
||||||
|
RefPtr ptrB(ptrA);
|
||||||
|
RefPtr ptrC(new ReferenceCounted());
|
||||||
|
|
||||||
|
SG_CHECK_EQUAL( ptrA.getNumRefs(), 2 );
|
||||||
|
SG_CHECK_EQUAL( ptrB.getNumRefs(), 2 );
|
||||||
|
SG_CHECK_EQUAL( ptrC.getNumRefs(), 1 );
|
||||||
|
SG_CHECK_EQUAL( ptrA, ptrB );
|
||||||
|
SG_CHECK_NE( ptrA, ptrC );
|
||||||
|
|
||||||
|
ptrA = std::move(ptrC);
|
||||||
|
SG_CHECK_EQUAL( ptrA.getNumRefs(), 1 );
|
||||||
|
SG_CHECK_EQUAL( ptrB.getNumRefs(), 1 );
|
||||||
|
SG_CHECK_NE( ptrA, ptrB );
|
||||||
|
// Implementation detail that is *not* guaranteed by the C++ move
|
||||||
|
// semantics:
|
||||||
|
SG_CHECK_IS_NULL( ptrC.get() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Base1:
|
class Base1:
|
||||||
@ -63,31 +189,41 @@ class VirtualDerived:
|
|||||||
public Base2
|
public Base2
|
||||||
{};
|
{};
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE( virtual_weak_ptr )
|
void test_SGWeakPtr()
|
||||||
{
|
{
|
||||||
|
std::cout << "Testing SGWeakPtr and SGVirtualWeakReferenced" << std::endl;
|
||||||
|
|
||||||
SGSharedPtr<VirtualDerived> ptr( new VirtualDerived() );
|
SGSharedPtr<VirtualDerived> ptr( new VirtualDerived() );
|
||||||
SGWeakPtr<VirtualDerived> weak_ptr( ptr );
|
SGWeakPtr<VirtualDerived> weak_ptr( ptr );
|
||||||
BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 1 );
|
SG_CHECK_EQUAL( ptr.getNumRefs(), 1 );
|
||||||
|
|
||||||
SGSharedPtr<Base1> ptr1( weak_ptr.lock() );
|
SGSharedPtr<Base1> ptr1( weak_ptr.lock() );
|
||||||
BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 2 );
|
SG_CHECK_EQUAL( ptr.getNumRefs(), 2 );
|
||||||
|
|
||||||
// converting constructor
|
// converting constructor
|
||||||
BOOST_REQUIRE_EQUAL( SGSharedPtr<Base1>(weak_ptr), ptr1 );
|
SG_CHECK_EQUAL( SGSharedPtr<Base1>(weak_ptr), ptr1 );
|
||||||
|
|
||||||
SGSharedPtr<Base2> ptr2( weak_ptr.lock() );
|
SGSharedPtr<Base2> ptr2( weak_ptr.lock() );
|
||||||
BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 3 );
|
SG_CHECK_EQUAL( ptr.getNumRefs(), 3 );
|
||||||
|
|
||||||
BOOST_REQUIRE( ptr != NULL );
|
SG_CHECK_IS_NOT_NULL( ptr );
|
||||||
BOOST_REQUIRE_EQUAL( ptr.get(), ptr1.get() );
|
SG_CHECK_EQUAL( ptr.get(), ptr1.get() );
|
||||||
BOOST_REQUIRE_EQUAL( ptr.get(), ptr2.get() );
|
SG_CHECK_EQUAL( ptr.get(), ptr2.get() );
|
||||||
|
|
||||||
SGWeakPtr<Base1> weak_base1( ptr );
|
SGWeakPtr<Base1> weak_base1( ptr );
|
||||||
SGWeakPtr<Base2> weak_base2( ptr );
|
SGWeakPtr<Base2> weak_base2( ptr );
|
||||||
ptr1 = dynamic_cast<VirtualDerived*>(weak_base1.lock().get());
|
ptr1 = dynamic_cast<VirtualDerived*>(weak_base1.lock().get());
|
||||||
ptr2 = dynamic_cast<VirtualDerived*>(weak_base2.lock().get());
|
ptr2 = dynamic_cast<VirtualDerived*>(weak_base2.lock().get());
|
||||||
|
|
||||||
BOOST_REQUIRE_EQUAL( ptr.get(), ptr1.get() );
|
SG_CHECK_EQUAL( ptr.get(), ptr1.get() );
|
||||||
BOOST_REQUIRE_EQUAL( ptr.get(), ptr2.get() );
|
SG_CHECK_EQUAL( ptr.get(), ptr2.get() );
|
||||||
BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 3 );
|
SG_CHECK_EQUAL( ptr.getNumRefs(), 3 );
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
test_SGSharedPtr();
|
||||||
|
test_SGWeakPtr();
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
# include <simgear_config.h>
|
# include <simgear_config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <simgear/debug/logstream.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
#include <simgear/timing/timestamp.hxx>
|
#include <simgear/timing/timestamp.hxx>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user