Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Humanoid Path Planner
hpp-util
Commits
449e4a0a
Commit
449e4a0a
authored
Dec 13, 2020
by
Joseph Mirabel
Browse files
[Serialization] Add pointer holder in archive.
parent
26ca869c
Pipeline
#12671
passed with stage
in 4 minutes and 38 seconds
Changes
6
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
CMakeLists.txt
View file @
449e4a0a
...
...
@@ -29,7 +29,7 @@ COMPUTE_PROJECT_ARGS(PROJECT_ARGS LANGUAGES CXX C)
PROJECT
(
${
PROJECT_NAME
}
${
PROJECT_ARGS
}
)
# Search for Boost.
ADD_PROJECT_DEPENDENCY
(
Boost REQUIRED COMPONENTS filesystem
serialization
)
ADD_PROJECT_DEPENDENCY
(
Boost REQUIRED COMPONENTS filesystem serialization
)
SET
(
CMAKE_MODULE_PATH
${
PROJECT_SOURCE_DIR
}
/cmake/find-external/TinyXML
)
FIND_PACKAGE
(
TinyXML REQUIRED
)
...
...
@@ -65,7 +65,7 @@ SET(${PROJECT_NAME}_SOURCES
ADD_LIBRARY
(
${
PROJECT_NAME
}
SHARED
${${
PROJECT_NAME
}
_SOURCES
}
${${
PROJECT_NAME
}
_HEADERS
}
)
TARGET_INCLUDE_DIRECTORIES
(
${
PROJECT_NAME
}
PRIVATE
${
TinyXML_INCLUDE_DIR
}
)
TARGET_INCLUDE_DIRECTORIES
(
${
PROJECT_NAME
}
PUBLIC $<INSTALL_INTERFACE:include>
)
TARGET_LINK_LIBRARIES
(
${
PROJECT_NAME
}
${
TinyXML_LIBRARY
}
Boost::filesystem Boost::serialization
)
TARGET_LINK_LIBRARIES
(
${
PROJECT_NAME
}
PUBLIC
${
TinyXML_LIBRARY
}
Boost::filesystem Boost::serialization
)
# Check for unistd.h presence.
INCLUDE
(
CheckIncludeFiles
)
...
...
include/hpp/util/serialization.hh
View file @
449e4a0a
...
...
@@ -30,6 +30,10 @@
#include
<boost/serialization/export.hpp>
#include
<boost/serialization/shared_ptr.hpp>
#include
<boost/serialization/nvp.hpp>
#include
<boost/serialization/utility.hpp>
#include
<hpp/util/config.hh>
#include
<hpp/util/serialization-fwd.hh>
#define _HPP_SERIALIZATION_SPLIT_IMPLEMENT(type,archive,arg) \
template void type load<archive##_iarchive>(archive##_iarchive& ar, \
...
...
@@ -47,7 +51,6 @@
arg BOOST_PP_COMMA_IF(BOOST_PP_NOT(BOOST_PP_IS_EMPTY(arg))) \
const unsigned int ver)
#if BOOST_VERSION >= 106500
#define HPP_SERIALIZATION_SPLIT_IMPLEMENT(type) \
_HPP_SERIALIZATION_SPLIT_IMPLEMENT(type::,boost::archive::xml,); \
_HPP_SERIALIZATION_SPLIT_IMPLEMENT(type::,boost::archive::binary,)
...
...
@@ -72,37 +75,143 @@
_HPP_SERIALIZATION_IMPLEMENT(,archive::binary,type& t); \
}}
#else // BOOST_VERSION >= 106500
#define HPP_SERIALIZATION_SPLIT_IMPLEMENT(type) \
_HPP_SERIALIZATION_SPLIT_IMPLEMENT(type::,boost::archive::xml,); \
_HPP_SERIALIZATION_SPLIT_IMPLEMENT(type::,boost::archive::binary,)
#define HPP_SERIALIZATION_IMPLEMENT(type) \
_HPP_SERIALIZATION_IMPLEMENT(type::,boost::archive::xml,); \
_HPP_SERIALIZATION_IMPLEMENT(type::,boost::archive::binary,)
#define HPP_SERIALIZATION_FREE_IMPLEMENT(type) \
namespace boost { namespace serialization { \
_HPP_SERIALIZATION_IMPLEMENT(,archive::xml,type& t); \
_HPP_SERIALIZATION_IMPLEMENT(,archive::binary,type& t); \
}}
#define HPP_SERIALIZATION_SPLIT_FREE_IMPLEMENT(type) \
namespace boost { namespace serialization { \
template<class Archive> \
void serialize(Archive & ar, type& t, const unsigned int version) { \
split_free(ar, t, version); \
} \
_HPP_SERIALIZATION_IMPLEMENT(,archive::xml,type& t); \
_HPP_SERIALIZATION_IMPLEMENT(,archive::binary,type& t); \
}}
#endif // BOOST_VERSION >= 106500
namespace
hpp
{
namespace
serialization
{
using
boost
::
serialization
::
make_nvp
;
using
boost
::
serialization
::
guid
;
using
boost
::
serialization
::
guid_defined
;
class
holder_base
{
public:
const
char
*
classid
;
virtual
~
holder_base
()
=
default
;
protected:
holder_base
(
const
char
*
classid
)
:
classid
(
classid
)
{}
};
template
<
typename
T
>
class
holder
:
public
holder_base
{
public:
T
*
t
;
holder
(
T
*
t
,
const
char
*
classid
)
:
holder_base
(
classid
),
t
(
t
)
{}
holder
(
T
*
t
)
:
holder
(
t
,
guid
<
T
>
())
{
static_assert
(
guid_defined
<
T
>::
value
,
"You must use BOOST_CLASS_EXPORT_KEY on this class first."
);
}
template
<
typename
U
>
explicit
operator
holder
<
U
>
()
{
return
holder
<
U
>
(
dynamic_cast
<
U
*>
(
t
),
classid
);
}
};
class
archive_ptr_holder
{
std
::
map
<
std
::
string
,
holder_base
*>
ptrs_
;
public:
bool
contains
(
const
std
::
string
&
k
)
const
{
return
ptrs_
.
count
(
k
);
}
template
<
typename
T
>
bool
containsOfType
(
const
std
::
string
&
k
)
const
{
return
(
get
<
T
>
(
k
,
false
))
!=
NULL
;
}
void
insert
(
const
std
::
string
&
k
,
holder_base
*
ptr
)
{
ptrs_
[
k
]
=
ptr
;
}
template
<
typename
T
>
void
insert
(
const
std
::
string
&
k
,
T
*
ptr
)
{
insert
(
k
,
(
holder_base
*
)
new
holder
<
T
>
(
ptr
));
}
holder_base
*
get
(
const
std
::
string
&
k
,
bool
throwIfNotFound
=
false
)
const
{
auto
_ptr
=
ptrs_
.
find
(
k
);
if
(
_ptr
==
ptrs_
.
end
())
{
if
(
!
throwIfNotFound
)
return
NULL
;
throw
std
::
invalid_argument
(
"Pointer with name "
+
k
+
" not found."
);
}
else
return
_ptr
->
second
;
}
template
<
typename
T
>
T
*
get
(
const
std
::
string
&
k
,
bool
throwIfNotFound
=
false
)
const
{
holder_base
*
hb
(
get
(
k
,
throwIfNotFound
));
if
(
hb
==
NULL
)
return
NULL
;
holder
<
T
>*
h
;
if
((
h
=
dynamic_cast
<
holder
<
T
>*>
(
hb
))
==
NULL
)
{
if
(
!
throwIfNotFound
)
return
NULL
;
throw
std
::
invalid_argument
(
"Pointer with name "
+
k
+
" found of type "
+
hb
->
classid
+
" but not of requested type "
+
guid
<
T
>
()
+
"."
);
}
return
h
->
t
;
}
template
<
typename
Base
,
typename
Child
>
void
insertChildClass
(
const
std
::
string
&
k
,
Child
*
ptr
)
{
static_assert
(
guid_defined
<
Child
>::
value
,
"You must use BOOST_CLASS_EXPORT_KEY on this class first."
);
insert
(
k
,
(
holder_base
*
)
new
holder
<
Base
>
(
ptr
,
guid
<
Child
>
()));
}
template
<
typename
Base
,
typename
Child
>
Child
*
getChildClass
(
const
std
::
string
&
k
,
bool
throwIfNotFound
=
false
)
const
{
holder_base
*
hb
(
get
(
k
,
throwIfNotFound
));
if
(
hb
==
NULL
)
return
NULL
;
holder
<
Base
>*
b
;
if
((
b
=
dynamic_cast
<
holder
<
Base
>*>
(
hb
))
==
NULL
)
{
if
(
!
throwIfNotFound
)
return
NULL
;
throw
std
::
invalid_argument
(
"Pointer with name "
+
k
+
" found of type "
+
hb
->
classid
+
" but not of requested type "
+
guid
<
Child
>
()
+
"."
);
}
holder
<
Child
>
c
(
*
b
);
if
(
c
.
t
==
NULL
)
{
if
(
!
throwIfNotFound
)
return
NULL
;
throw
std
::
invalid_argument
(
"Pointer with name "
+
k
+
" found of type "
+
hb
->
classid
+
" but not of requested type "
+
guid
<
Child
>
()
+
"."
);
}
return
c
.
t
;
}
virtual
~
archive_ptr_holder
()
{
for
(
auto
it
:
ptrs_
)
delete
it
.
second
;
}
protected:
template
<
typename
Archive
,
std
::
enable_if_t
<
Archive
::
is_saving
::
value
,
int
>
=
42
>
void
initialize_tpl
(
Archive
&
ar
)
// save
{
auto
size
(
ptrs_
.
size
());
ar
<<
make_nvp
(
"nrequires"
,
size
);
typedef
std
::
pair
<
std
::
string
,
std
::
string
>
string_pair
;
for
(
auto
it
:
ptrs_
)
{
string_pair
requires
(
it
.
first
,
it
.
second
->
classid
);
ar
<<
make_nvp
(
"requires"
,
requires
);
}
}
template
<
typename
Archive
,
std
::
enable_if_t
<!
Archive
::
is_saving
::
value
,
int
>
=
42
>
void
initialize_tpl
(
Archive
&
ar
)
// read
{
decltype
(
ptrs_
.
size
())
size
;
ar
>>
make_nvp
(
"nrequires"
,
size
);
typedef
std
::
pair
<
std
::
string
,
std
::
string
>
string_pair
;
string_pair
pair
;
for
(
decltype
(
size
)
i
=
0
;
i
<
size
;
++
i
)
{
ar
>>
make_nvp
(
"requires"
,
pair
);
holder_base
*
hb
=
get
(
pair
.
first
,
true
);
if
(
pair
.
second
!=
hb
->
classid
)
throw
std
::
invalid_argument
(
"Required pointer with name "
+
pair
.
first
+
" found of type "
+
hb
->
classid
+
" but not of required type "
+
pair
.
second
+
"."
);
}
}
};
template
<
typename
archive_base
>
class
archive_tpl
:
public
archive_base
,
public
archive_ptr_holder
{
public:
inline
void
initialize
()
{
initialize_tpl
<
archive_base
>
(
*
this
);
}
using
archive_base
::
archive_base
;
};
template
<
typename
Archive
>
archive_tpl
<
Archive
>&
cast
(
Archive
&
ar
)
{
return
dynamic_cast
<
archive_tpl
<
Archive
>&>
(
ar
);
}
template
<
typename
Archive
>
archive_tpl
<
Archive
>*
cast
(
Archive
*
ar
)
{
return
dynamic_cast
<
archive_tpl
<
Archive
>*>
(
ar
);
}
typedef
archive_tpl
<
boost
::
archive
::
binary_iarchive
>
binary_iarchive
;
typedef
archive_tpl
<
boost
::
archive
::
binary_oarchive
>
binary_oarchive
;
typedef
archive_tpl
<
boost
::
archive
::
xml_iarchive
>
xml_iarchive
;
typedef
archive_tpl
<
boost
::
archive
::
xml_oarchive
>
xml_oarchive
;
}
// namespace util
}
// namespace hpp
...
...
tests/common.hh
View file @
449e4a0a
...
...
@@ -22,8 +22,8 @@
# include <iostream>
# include "config.h"
static
const
int
TEST_FAILED
=
10
;
static
const
int
TEST_SUCCEED
=
0
;
static
const
expr
int
TEST_FAILED
=
10
;
static
const
expr
int
TEST_SUCCEED
=
0
;
# define GENERATE_TEST() \
int \
...
...
tests/serialization-test.cc
View file @
449e4a0a
...
...
@@ -20,34 +20,113 @@
#include
"common.hh"
#include
"serialization.hh"
#include
<boost/archive/xml_iarchive.hpp>
#include
<boost/archive/xml_oarchive.hpp>
#include
<hpp/util/serialization.hh>
template
<
typename
T
>
int
run_test_tpl
()
{
std
::
stringstream
ss
;
T
t
(
10
);
T
*
t
(
new
T
(
10
)
)
;
{
boost
::
archive
::
xml_oarchive
oa
(
ss
);
hpp
::
serialization
::
xml_oarchive
oa
(
ss
);
oa
<<
boost
::
serialization
::
make_nvp
(
"t"
,
t
);
}
Foo
*
t_r
=
NULL
;
std
::
cout
<<
ss
.
str
()
<<
std
::
endl
;
T
*
t_r
=
NULL
;
{
boost
::
archive
::
xml_iarchive
ia
(
ss
);
hpp
::
serialization
::
xml_iarchive
ia
(
ss
);
ia
>>
boost
::
serialization
::
make_nvp
(
"t"
,
t_r
);
}
if
(
t_r
==
NULL
||
t_r
->
i_
!=
t
.
i_
)
return
TEST_FAILED
;
if
(
t_r
==
NULL
||
t_r
->
i_
!=
t
->
i_
)
{
std
::
cerr
<<
"Failed to deserialize "
<<
hpp
::
serialization
::
guid
<
T
>
()
<<
" class"
<<
std
::
endl
;
return
TEST_FAILED
;
}
delete
t
;
return
TEST_SUCCEED
;
}
int
run_test_bar
(
bool
check_throw
)
{
std
::
unique_ptr
<
Foo
>
foo
(
new
Foo
(
1
));
std
::
stringstream
ss
;
Bar
*
t
(
new
Bar
(
10
));
{
hpp
::
serialization
::
xml_oarchive
oa
(
ss
);
oa
.
insert
(
"foo"
,
foo
.
get
());
oa
.
initialize
();
oa
<<
boost
::
serialization
::
make_nvp
(
"t"
,
t
);
}
std
::
cout
<<
ss
.
str
()
<<
std
::
endl
;
Bar
*
t_r
=
NULL
;
bool
caught_error
;
{
hpp
::
serialization
::
xml_iarchive
ia
(
ss
);
if
(
!
check_throw
)
ia
.
insert
(
"foo"
,
foo
.
get
());
else
ia
.
insert
(
"foo"
,
new
Bar
(
0
));
try
{
caught_error
=
true
;
ia
.
initialize
();
caught_error
=
false
;
ia
>>
boost
::
serialization
::
make_nvp
(
"t"
,
t_r
);
}
catch
(
const
std
::
invalid_argument
&
e
)
{
std
::
cerr
<<
e
.
what
()
<<
std
::
endl
;
}
}
if
(
check_throw
!=
caught_error
)
return
TEST_FAILED
;
if
(
check_throw
&&
t_r
!=
NULL
)
{
std
::
cerr
<<
"Deserialize Bar class while it shouldn't"
<<
std
::
endl
;
return
TEST_FAILED
;
}
if
(
!
check_throw
)
{
if
(
t_r
->
f_
!=
foo
.
get
())
{
std
::
cerr
<<
"Failed to deserialize Bar::f_ Foo pointer"
<<
std
::
endl
;
return
TEST_FAILED
;
}
if
(
t_r
==
NULL
||
t_r
->
i_
!=
t
->
i_
)
{
std
::
cerr
<<
"Failed to deserialize Bar class"
<<
std
::
endl
;
return
TEST_FAILED
;
}
}
delete
t
;
return
TEST_SUCCEED
;
}
struct
S1
{
virtual
~
S1
()
=
default
;
};
struct
S2
:
S1
{};
BOOST_CLASS_EXPORT_KEY
(
S1
)
BOOST_CLASS_EXPORT_KEY
(
S2
)
int
run_test_holder_inheritance
()
{
using
namespace
hpp
::
serialization
;
archive_ptr_holder
aph
;
S2
s2
;
aph
.
insert
<
S1
>
(
"s1"
,
&
s2
);
aph
.
insertChildClass
<
S1
>
(
"s2"
,
&
s2
);
aph
.
template
get
<
S1
>(
"s1"
,
true
);
aph
.
getChildClass
<
S1
,
S2
>
(
"s2"
,
true
);
S1
*
s1
=
aph
.
template
get
<
S1
>(
"s2"
,
false
);
if
(
s1
==
NULL
)
{
std
::
cerr
<<
"Failed to cast S2 into S1"
<<
std
::
endl
;
return
TEST_FAILED
;
}
return
TEST_SUCCEED
;
}
int
run_test
()
{
if
(
run_test_tpl
<
Foo
>
()
==
TEST_FAILED
)
return
TEST_FAILED
;
if
(
run_test_tpl
<
Bar
>
()
==
TEST_FAILED
)
return
TEST_FAILED
;
if
(
run_test_tpl
<
FooFree
>
()
==
TEST_FAILED
)
return
TEST_FAILED
;
if
(
run_test_tpl
<
BarFree
>
()
==
TEST_FAILED
)
return
TEST_FAILED
;
if
(
run_test_tpl
<
Foo
>
()
==
TEST_FAILED
)
return
TEST_FAILED
;
if
(
run_test_bar
(
true
)
==
TEST_FAILED
)
return
TEST_FAILED
;
if
(
run_test_bar
(
false
)
==
TEST_FAILED
)
return
TEST_FAILED
;
if
(
run_test_tpl
<
FooFree
>
()
==
TEST_FAILED
)
return
TEST_FAILED
;
if
(
run_test_tpl
<
BarFree
>
()
==
TEST_FAILED
)
return
TEST_FAILED
;
if
(
run_test_holder_inheritance
()
==
TEST_FAILED
)
return
TEST_FAILED
;
return
TEST_SUCCEED
;
}
...
...
tests/serialization.cc
View file @
449e4a0a
...
...
@@ -18,7 +18,7 @@
#include
"serialization.hh"
BOOST_CLASS_EXPORT
(
Foo
)
BOOST_CLASS_EXPORT
_IMPLEMENT
(
Foo
)
template
<
class
Archive
>
void
Foo
::
serialize
(
Archive
&
ar
,
const
unsigned
int
version
)
...
...
@@ -29,13 +29,14 @@ void Foo::serialize(Archive & ar, const unsigned int version)
HPP_SERIALIZATION_IMPLEMENT
(
Foo
);
BOOST_CLASS_EXPORT
(
Bar
)
BOOST_CLASS_EXPORT
_IMPLEMENT
(
Bar
)
template
<
class
Archive
>
void
Bar
::
load
(
Archive
&
ar
,
const
unsigned
int
version
)
{
(
void
)
version
;
ar
&
hpp
::
serialization
::
make_nvp
(
"i"
,
i_
);
f_
=
hpp
::
serialization
::
cast
(
ar
).
template
get
<
Foo
>(
"foo"
,
true
);
}
template
<
class
Archive
>
...
...
tests/serialization.hh
View file @
449e4a0a
...
...
@@ -26,22 +26,26 @@ class Foo {
HPP_SERIALIZABLE
();
};
BOOST_CLASS_EXPORT_KEY
(
Foo
)
class
Bar
{
public:
Bar
(
int
i
)
:
i_
(
i
)
{};
int
i_
;
Foo
*
f_
;
private:
Bar
()
{}
HPP_SERIALIZABLE_SPLIT
();
};
BOOST_CLASS_EXPORT_KEY
(
Bar
)
class
FooFree
{
public:
FooFree
(
int
i
)
:
i_
(
i
)
{};
int
i_
;
private:
FooFree
()
{}
};
...
...
@@ -52,7 +56,6 @@ class BarFree {
BarFree
(
int
i
)
:
i_
(
i
)
{};
int
i_
;
private:
BarFree
()
{}
};
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment