Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
A
Actor Framework
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
cpp-libs
Actor Framework
Commits
0913c491
Commit
0913c491
authored
Aug 17, 2020
by
Dominik Charousset
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add support for STL types to the new inspector API
parent
ee5ce710
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
520 additions
and
13 deletions
+520
-13
libcaf_core/caf/fwd.hpp
libcaf_core/caf/fwd.hpp
+1
-0
libcaf_core/caf/inspector_access.hpp
libcaf_core/caf/inspector_access.hpp
+185
-13
libcaf_core/caf/inspector_access_type.hpp
libcaf_core/caf/inspector_access_type.hpp
+68
-0
libcaf_core/caf/sec.hpp
libcaf_core/caf/sec.hpp
+2
-0
libcaf_core/test/load_inspector.cpp
libcaf_core/test/load_inspector.cpp
+101
-0
libcaf_core/test/save_inspector.cpp
libcaf_core/test/save_inspector.cpp
+163
-0
No files found.
libcaf_core/caf/fwd.hpp
View file @
0913c491
...
...
@@ -46,6 +46,7 @@ template <class> class stream_source;
template
<
class
>
class
weak_intrusive_ptr
;
template
<
class
>
struct
inspector_access
;
template
<
class
>
struct
inspector_access_traits
;
template
<
class
>
struct
timeout_definition
;
template
<
class
>
struct
type_id
;
...
...
libcaf_core/caf/inspector_access.hpp
View file @
0913c491
...
...
@@ -19,11 +19,14 @@
#pragma once
#include <tuple>
#include <utility>
#include "caf/allowed_unsafe_message_type.hpp"
#include "caf/detail/inspect.hpp"
#include "caf/detail/type_list.hpp"
#include "caf/error.hpp"
#include "caf/fwd.hpp"
#include "caf/inspector_access_type.hpp"
#include "caf/optional.hpp"
#include "caf/sec.hpp"
#include "caf/span.hpp"
...
...
@@ -32,10 +35,10 @@
namespace
caf
{
// -- utility function objects and functions for load and save inspectors ------
namespace
detail
{
// -- predicates ---------------------------------------------------------------
/// Utility class for predicates that always return `true`.
struct
always_true_t
{
template
<
class
...
Ts
>
...
...
@@ -47,6 +50,8 @@ struct always_true_t {
/// Predicate that always returns `true`.
constexpr
auto
always_true
=
always_true_t
{};
// -- const conversions --------------------------------------------------------
/// Returns a mutable reference to `x`.
template
<
class
T
>
T
&
as_mutable_ref
(
T
&
x
)
{
...
...
@@ -59,6 +64,8 @@ T& as_mutable_ref(const T& x) {
return
const_cast
<
T
&>
(
x
);
}
// -- traits -------------------------------------------------------------------
/// Checks whether the inspector has a `value` overload for `T`.
template
<
class
Inspector
,
class
T
>
class
is_trivially_inspectable
{
...
...
@@ -76,8 +83,168 @@ public:
static
constexpr
bool
value
=
sfinae_result
::
value
;
};
// -- loading ------------------------------------------------------------------
template
<
class
Inspector
,
class
T
>
bool
load_value
(
Inspector
&
f
,
T
&
x
,
inspector_access_type
::
empty
)
{
return
f
.
object
(
x
).
fields
();
}
template
<
class
Inspector
,
class
T
>
bool
load_value
(
Inspector
&
f
,
T
&
,
inspector_access_type
::
unsafe
)
{
f
.
set_error
(
sec
::
unsafe_type
);
return
false
;
}
template
<
class
Inspector
,
class
T
>
bool
load_value
(
Inspector
&
f
,
T
&
x
,
inspector_access_type
::
integral
)
{
auto
tmp
=
detail
::
squashed_int_t
<
T
>
{
0
};
if
(
f
.
value
(
tmp
))
{
x
=
static_cast
<
T
>
(
tmp
);
return
true
;
}
return
false
;
}
template
<
class
Inspector
,
class
T
,
size_t
N
>
bool
load_value
(
Inspector
&
f
,
T
(
&
xs
)[
N
],
inspector_access_type
::
array
)
{
if
(
!
f
.
begin_tuple
(
N
))
return
false
;
for
(
size_t
index
=
0
;
index
<
N
;
++
index
)
if
(
!
inspect_value
(
f
,
xs
[
index
]))
return
false
;
return
f
.
end_tuple
();
}
template
<
class
Inspector
,
class
T
,
size_t
...
Ns
>
bool
load_tuple
(
Inspector
&
f
,
T
&
xs
,
std
::
index_sequence
<
Ns
...
>
)
{
return
f
.
begin_tuple
(
sizeof
...(
Ns
))
//
&&
(
inspect_value
(
f
,
get
<
Ns
>
(
xs
))
&&
...)
//
&&
f
.
end_tuple
();
}
template
<
class
Inspector
,
class
T
>
bool
load_value
(
Inspector
&
f
,
T
&
x
,
inspector_access_type
::
tuple
)
{
return
load_tuple
(
f
,
x
,
std
::
make_index_sequence
<
std
::
tuple_size
<
T
>::
value
>
{});
}
template
<
class
Inspector
,
class
T
>
bool
load_value
(
Inspector
&
f
,
T
&
x
,
inspector_access_type
::
map
)
{
x
.
clear
();
size_t
size
=
0
;
if
(
!
f
.
begin_sequence
(
size
))
return
false
;
for
(
size_t
i
=
0
;
i
<
size
;
++
i
)
{
auto
key
=
typename
T
::
key_type
{};
auto
val
=
typename
T
::
mapped_type
{};
if
(
!
(
f
.
begin_tuple
(
2
)
&&
inspect_value
(
f
,
key
)
&&
inspect_value
(
f
,
val
)
&&
f
.
end_tuple
()))
return
false
;
auto
added
=
x
.
emplace
(
std
::
move
(
key
),
std
::
move
(
val
)).
second
;
if
(
!
added
)
{
f
.
set_error
(
make_error
(
sec
::
runtime_error
,
"multiple key definitions"
));
return
false
;
}
}
return
f
.
end_sequence
();
}
template
<
class
Inspector
,
class
T
>
bool
load_value
(
Inspector
&
f
,
T
&
x
,
inspector_access_type
::
list
)
{
x
.
clear
();
size_t
size
=
0
;
if
(
!
f
.
begin_sequence
(
size
))
return
false
;
for
(
size_t
i
=
0
;
i
<
size
;
++
i
)
{
auto
val
=
typename
T
::
value_type
{};
if
(
!
inspect_value
(
f
,
val
))
return
false
;
x
.
insert
(
x
.
end
(),
std
::
move
(
val
));
}
return
f
.
end_sequence
();
}
// -- saving -------------------------------------------------------------------
template
<
class
Inspector
,
class
T
>
bool
save_value
(
Inspector
&
f
,
T
&
x
,
inspector_access_type
::
empty
)
{
return
f
.
object
(
x
).
fields
();
}
template
<
class
Inspector
,
class
T
>
bool
save_value
(
Inspector
&
f
,
T
&
,
inspector_access_type
::
unsafe
)
{
f
.
set_error
(
sec
::
unsafe_type
);
return
false
;
}
template
<
class
Inspector
,
class
T
>
bool
save_value
(
Inspector
&
f
,
T
&
x
,
inspector_access_type
::
integral
)
{
auto
tmp
=
static_cast
<
detail
::
squashed_int_t
<
T
>>
(
x
);
return
f
.
value
(
tmp
);
}
template
<
class
Inspector
,
class
T
,
size_t
N
>
bool
save_value
(
Inspector
&
f
,
T
(
&
xs
)[
N
],
inspector_access_type
::
array
)
{
if
(
!
f
.
begin_tuple
(
N
))
return
false
;
for
(
size_t
index
=
0
;
index
<
N
;
++
index
)
if
(
!
inspect_value
(
f
,
xs
[
index
]))
return
false
;
return
f
.
end_tuple
();
}
template
<
class
Inspector
,
class
T
,
size_t
...
Ns
>
bool
save_tuple
(
Inspector
&
f
,
T
&
xs
,
std
::
index_sequence
<
Ns
...
>
)
{
return
f
.
begin_tuple
(
sizeof
...(
Ns
))
//
&&
(
inspect_value
(
f
,
get
<
Ns
>
(
xs
))
&&
...)
//
&&
f
.
end_tuple
();
}
template
<
class
Inspector
,
class
T
>
bool
save_value
(
Inspector
&
f
,
T
&
x
,
inspector_access_type
::
tuple
)
{
return
save_tuple
(
f
,
x
,
std
::
make_index_sequence
<
std
::
tuple_size
<
T
>::
value
>
{});
}
template
<
class
Inspector
,
class
T
>
bool
save_value
(
Inspector
&
f
,
T
&
x
,
inspector_access_type
::
map
)
{
auto
size
=
x
.
size
();
if
(
!
f
.
begin_sequence
(
size
))
return
false
;
for
(
auto
&
kvp
:
x
)
{
if
(
!
(
f
.
begin_tuple
(
2
)
&&
inspect_value
(
f
,
as_mutable_ref
(
kvp
.
first
))
&&
inspect_value
(
f
,
kvp
.
second
)
&&
f
.
end_tuple
()))
return
false
;
}
return
f
.
end_sequence
();
}
template
<
class
Inspector
,
class
T
>
bool
save_value
(
Inspector
&
f
,
T
&
x
,
inspector_access_type
::
list
)
{
auto
size
=
x
.
size
();
if
(
!
f
.
begin_sequence
(
size
))
return
false
;
for
(
auto
&
val
:
x
)
if
(
!
inspect_value
(
f
,
val
))
return
false
;
return
f
.
end_sequence
();
}
}
// namespace detail
/// Customization point for selecting a default inspector behavior for `T`.
/// @note User-provided `inspect` overloads always override this default.
template
<
class
T
>
struct
inspector_access_traits
{
using
tag
=
decltype
(
guess_inspector_access_type
<
T
>
());
};
/// Expands to `inspector_access_traits::tag{}`.
template
<
class
T
>
constexpr
auto
inspector_access_tag_v
=
typename
inspector_access_traits
<
T
>::
tag
{};
/// Calls `f.value(x)` if this is a valid expression,
/// `inspector_access<T>::apply_value(f, x)` otherwise.
template
<
class
Inspector
,
class
T
>
...
...
@@ -180,36 +347,39 @@ struct inspector_access_base {
/// Default implementation for @ref inspector_access.
template
<
class
T
>
struct
default_inspector_access
:
inspector_access_base
<
T
>
{
// -- interface functions ----------------------------------------------------
/// Applies `x` as an object to `f`.
template
<
class
Inspector
>
[[
nodiscard
]]
static
bool
apply_object
(
Inspector
&
f
,
T
&
x
)
{
using
detail
::
inspect
;
//
User-provided `inspect` overloads come first
.
//
Dispatch to user-provided `inspect` overload or assume a trivial type
.
if
constexpr
(
detail
::
is_inspectable
<
Inspector
,
T
>::
value
)
{
using
result_type
=
decltype
(
inspect
(
f
,
x
));
if
constexpr
(
std
::
is_same
<
result_type
,
bool
>::
value
)
return
inspect
(
f
,
x
);
else
return
apply_deprecated
(
f
,
x
);
}
else
if
constexpr
(
Inspector
::
is_loading
)
{
return
load_object
(
f
,
x
);
}
else
if
constexpr
(
std
::
is_empty
<
T
>::
value
)
{
return
f
.
object
(
x
).
fields
(
);
}
else
{
return
save_object
(
f
,
x
);
return
f
.
object
(
x
).
fields
(
f
.
field
(
"value"
,
x
)
);
}
}
/// Applies `x` as a single value to `f`.
template
<
class
Inspector
>
[[
nodiscard
]]
static
bool
apply_value
(
Inspector
&
f
,
T
&
x
)
{
return
apply_object
(
f
,
x
);
if
constexpr
(
detail
::
is_inspectable
<
Inspector
,
T
>::
value
)
return
apply_object
(
f
,
x
);
else
if
constexpr
(
Inspector
::
is_loading
)
return
detail
::
load_value
(
f
,
x
,
inspector_access_tag_v
<
T
>
);
else
return
detail
::
save_value
(
f
,
x
,
inspector_access_tag_v
<
T
>
);
}
template
<
class
Inspector
>
[[
nodiscard
]]
static
bool
load_object
(
Inspector
&
f
,
T
&
x
)
{
if
constexpr
(
std
::
is_arithmetic
<
T
>::
value
)
{
return
f
.
object
(
x
).
fields
(
f
.
field
(
"value"
,
x
));
}
}
// -- deprecated API ---------------------------------------------------------
template
<
class
Inspector
>
[[
deprecated
(
"inspect() overloads should return bool"
)]]
//
...
...
@@ -229,6 +399,7 @@ struct default_inspector_access : inspector_access_base<T> {
template
<
class
T
>
struct
inspector_access
:
default_inspector_access
<
T
>
{};
/*
template <class... Ts>
struct inspector_access<std::tuple<Ts...>> {
// -- boilerplate ------------------------------------------------------------
...
...
@@ -346,6 +517,7 @@ struct inspector_access<std::tuple<Ts...>> {
tuple_indexes{});
}
};
*/
template
<
class
T
>
struct
inspector_access
<
optional
<
T
>>
{
...
...
libcaf_core/caf/inspector_access_type.hpp
0 → 100644
View file @
0913c491
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2020 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include <type_traits>
#include "caf/detail/type_traits.hpp"
namespace
caf
{
/// Wraps tag types for static dispatching.
struct
inspector_access_type
{
/// Flags stateless message types.
struct
empty
{};
/// Flags allowed unsafe message types.
struct
unsafe
{};
/// Flags builtin integral types.
struct
integral
{};
/// Flags type with user-defined `inspect` overloads.
struct
inspect
{};
/// Flags native C array types.
struct
array
{};
/// Flags types with `std::tuple`-like API.
struct
tuple
{};
/// Flags types with `std::map`-like API.
struct
map
{};
/// Flags types with `std::vector`-like API.
struct
list
{};
};
/// @relates inspector_access_type
template
<
class
T
>
constexpr
auto
guess_inspector_access_type
()
{
if
constexpr
(
std
::
is_empty
<
T
>::
value
)
{
return
inspector_access_type
::
empty
{};
}
else
if
constexpr
(
is_allowed_unsafe_message_type_v
<
T
>
)
{
return
inspector_access_type
::
unsafe
{};
}
else
if
constexpr
(
std
::
is_integral
<
T
>::
value
)
{
return
inspector_access_type
::
integral
{};
}
else
if
constexpr
(
std
::
is_array
<
T
>::
value
)
{
return
inspector_access_type
::
array
{};
}
else
if
constexpr
(
detail
::
is_stl_tuple_type_v
<
T
>
)
{
return
inspector_access_type
::
tuple
{};
}
else
if
constexpr
(
detail
::
is_map_like_v
<
T
>
)
{
return
inspector_access_type
::
map
{};
}
else
{
static_assert
(
detail
::
is_list_like_v
<
T
>
);
return
inspector_access_type
::
list
{};
}
}
}
// namespace caf
libcaf_core/caf/sec.hpp
View file @
0913c491
...
...
@@ -152,6 +152,8 @@ enum class sec : uint8_t {
field_value_synchronization_failed
,
/// Deserialization failed, because the source announced an invalid type.
invalid_field_type
,
/// Serialization failed because a type was flagged as unsafe message type.
unsafe_type
,
};
/// @relates sec
...
...
libcaf_core/test/load_inspector.cpp
View file @
0913c491
...
...
@@ -22,6 +22,7 @@
#include "caf/test/dsl.hpp"
#include <array>
#include <cstdint>
#include <string>
#include <vector>
...
...
@@ -153,6 +154,29 @@ bool inspect(Inspector& f, fallback_dummy_message& x) {
return
f
.
object
(
x
).
fields
(
f
.
field
(
"content"
,
x
.
content
).
fallback
(
42.0
));
}
struct
basics
{
static
inline
string_view
tname
=
"basics"
;
struct
tag
{
static
inline
string_view
tname
=
"tag"
;
};
tag
v1
;
int32_t
v2
;
int32_t
v3
[
4
];
dummy_message
v4
[
2
];
std
::
array
<
int32_t
,
2
>
v5
;
std
::
tuple
<
int32_t
,
dummy_message
>
v6
;
std
::
map
<
std
::
string
,
int32_t
>
v7
;
std
::
vector
<
std
::
list
<
std
::
pair
<
std
::
string
,
std
::
array
<
int32_t
,
3
>>>>
v8
;
};
template
<
class
Inspector
>
bool
inspect
(
Inspector
&
f
,
basics
&
x
)
{
return
f
.
object
(
x
).
fields
(
f
.
field
(
"v1"
,
x
.
v1
),
f
.
field
(
"v2"
,
x
.
v2
),
f
.
field
(
"v3"
,
x
.
v3
),
f
.
field
(
"v4"
,
x
.
v4
),
f
.
field
(
"v5"
,
x
.
v5
),
f
.
field
(
"v6"
,
x
.
v6
),
f
.
field
(
"v7"
,
x
.
v7
),
f
.
field
(
"v8"
,
x
.
v8
));
}
struct
testee
:
load_inspector
{
std
::
string
log
;
...
...
@@ -253,6 +277,22 @@ struct testee : load_inspector {
return
ok
;
}
bool
begin_sequence
(
size_t
&
size
)
{
size
=
0
;
new_line
();
indent
+=
2
;
log
+=
"begin sequence of size "
;
log
+=
std
::
to_string
(
size
);
return
ok
;
}
bool
end_sequence
()
{
indent
-=
2
;
new_line
();
log
+=
"end sequence"
;
return
ok
;
}
template
<
class
T
>
std
::
enable_if_t
<
std
::
is_arithmetic
<
T
>::
value
,
bool
>
value
(
T
&
x
)
{
new_line
();
...
...
@@ -516,4 +556,65 @@ begin object nasty
end object)_"
);
}
CAF_TEST
(
load
inspectors
support
all
basic
STL
types
)
{
basics
x
;
CAF_CHECK
(
inspect
(
f
,
x
));
CAF_CHECK_EQUAL
(
f
.
log
,
R"_(
begin object basics
begin field v1
begin object tag
end object
end field
begin field v2
int32_t value
end field
begin field v3
begin tuple of size 4
int32_t value
int32_t value
int32_t value
int32_t value
end tuple
end field
begin field v4
begin tuple of size 2
begin object dummy_message
begin variant field content
std::string value
end field
end object
begin object dummy_message
begin variant field content
std::string value
end field
end object
end tuple
end field
begin field v5
begin tuple of size 2
int32_t value
int32_t value
end tuple
end field
begin field v6
begin tuple of size 2
int32_t value
begin object dummy_message
begin variant field content
std::string value
end field
end object
end tuple
end field
begin field v7
begin sequence of size 0
end sequence
end field
begin field v8
begin sequence of size 0
end sequence
end field
end object)_"
);
}
CAF_TEST_FIXTURE_SCOPE_END
()
libcaf_core/test/save_inspector.cpp
View file @
0913c491
...
...
@@ -127,6 +127,40 @@ bool inspect(Inspector& f, foobar& x) {
f
.
field
(
"bar"
,
get_bar
,
set_bar
));
}
struct
dummy_message
{
static
inline
string_view
tname
=
"dummy_message"
;
variant
<
std
::
string
,
double
>
content
;
};
template
<
class
Inspector
>
bool
inspect
(
Inspector
&
f
,
dummy_message
&
x
)
{
return
f
.
object
(
x
).
fields
(
f
.
field
(
"content"
,
x
.
content
));
}
struct
basics
{
static
inline
string_view
tname
=
"basics"
;
struct
tag
{
static
inline
string_view
tname
=
"tag"
;
};
tag
v1
;
int32_t
v2
;
int32_t
v3
[
4
];
dummy_message
v4
[
2
];
std
::
array
<
int32_t
,
2
>
v5
;
std
::
tuple
<
int32_t
,
dummy_message
>
v6
;
std
::
map
<
std
::
string
,
int32_t
>
v7
;
std
::
vector
<
std
::
list
<
std
::
pair
<
std
::
string
,
std
::
array
<
int32_t
,
3
>>>>
v8
;
};
template
<
class
Inspector
>
bool
inspect
(
Inspector
&
f
,
basics
&
x
)
{
return
f
.
object
(
x
).
fields
(
f
.
field
(
"v1"
,
x
.
v1
),
f
.
field
(
"v2"
,
x
.
v2
),
f
.
field
(
"v3"
,
x
.
v3
),
f
.
field
(
"v4"
,
x
.
v4
),
f
.
field
(
"v5"
,
x
.
v5
),
f
.
field
(
"v6"
,
x
.
v6
),
f
.
field
(
"v7"
,
x
.
v7
),
f
.
field
(
"v8"
,
x
.
v8
));
}
struct
testee
:
save_inspector
{
std
::
string
log
;
...
...
@@ -227,6 +261,21 @@ struct testee : save_inspector {
return
ok
;
}
bool
begin_sequence
(
size_t
size
)
{
new_line
();
indent
+=
2
;
log
+=
"begin sequence of size "
;
log
+=
std
::
to_string
(
size
);
return
ok
;
}
bool
end_sequence
()
{
indent
-=
2
;
new_line
();
log
+=
"end sequence"
;
return
ok
;
}
template
<
class
T
>
std
::
enable_if_t
<
std
::
is_arithmetic
<
T
>::
value
,
bool
>
value
(
const
T
&
)
{
new_line
();
...
...
@@ -496,4 +545,118 @@ begin object nasty
end object)_"
);
}
CAF_TEST
(
save
inspectors
support
all
basic
STL
types
)
{
basics
x
;
x
.
v7
.
emplace
(
"one"
,
1
);
x
.
v7
.
emplace
(
"two"
,
2
);
x
.
v7
.
emplace
(
"three"
,
3
);
using
v8_list
=
decltype
(
x
.
v8
);
using
v8_nested_list
=
v8_list
::
value_type
;
using
array_3i
=
std
::
array
<
int32_t
,
3
>
;
v8_nested_list
v8_1
;
v8_1
.
emplace_back
(
"hello"
,
array_3i
{{
1
,
2
,
3
}});
v8_1
.
emplace_back
(
"world"
,
array_3i
{{
2
,
3
,
4
}});
v8_nested_list
v8_2
;
v8_2
.
emplace_back
(
"foo"
,
array_3i
{{
0
,
0
,
0
}});
x
.
v8
.
emplace_back
(
std
::
move
(
v8_1
));
x
.
v8
.
emplace_back
(
std
::
move
(
v8_2
));
CAF_CHECK
(
inspect
(
f
,
x
));
CAF_CHECK_EQUAL
(
f
.
log
,
R"_(
begin object basics
begin field v1
begin object tag
end object
end field
begin field v2
int32_t value
end field
begin field v3
begin tuple of size 4
int32_t value
int32_t value
int32_t value
int32_t value
end tuple
end field
begin field v4
begin tuple of size 2
begin object dummy_message
begin variant field content
std::string value
end field
end object
begin object dummy_message
begin variant field content
std::string value
end field
end object
end tuple
end field
begin field v5
begin tuple of size 2
int32_t value
int32_t value
end tuple
end field
begin field v6
begin tuple of size 2
int32_t value
begin object dummy_message
begin variant field content
std::string value
end field
end object
end tuple
end field
begin field v7
begin sequence of size 3
begin tuple of size 2
std::string value
int32_t value
end tuple
begin tuple of size 2
std::string value
int32_t value
end tuple
begin tuple of size 2
std::string value
int32_t value
end tuple
end sequence
end field
begin field v8
begin sequence of size 2
begin sequence of size 2
begin tuple of size 2
std::string value
begin tuple of size 3
int32_t value
int32_t value
int32_t value
end tuple
end tuple
begin tuple of size 2
std::string value
begin tuple of size 3
int32_t value
int32_t value
int32_t value
end tuple
end tuple
end sequence
begin sequence of size 1
begin tuple of size 2
std::string value
begin tuple of size 3
int32_t value
int32_t value
int32_t value
end tuple
end tuple
end sequence
end sequence
end field
end object)_"
);
}
CAF_TEST_FIXTURE_SCOPE_END
()
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a 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