1 Commits

Author SHA1 Message Date
Mindaugas
a6dad0885f visual studio variadic templates issues 2019-01-16 11:27:56 +02:00
28 changed files with 121 additions and 104 deletions

2
.gitignore vendored
View File

@@ -1,5 +1,5 @@
.idea/
.vs/
build/
cmake-build-debug/
cmake-build-*
CTestConfig.cmake

View File

@@ -1,3 +1,11 @@
# [4.5.1](https://github.com/fraillt/bitsery/compare/v4.5.0...v4.5.1) (2019-01-16)
### Improvements
* template specializations, where possible, was changed to avoid using variadics, some Visual Studio compilers has [issues](https://developercommunity.visualstudio.com/content/problem/3437/error-with-c11-variadics.html) with variadic templates.
* reduced compile warnings for VisualStudio:
* added explicit casts
* renamed `struct` to `class` where class is used as friend. e.g. `friend class bitsery::Access`, because it is more conventional usage.
# [4.5.0](https://github.com/fraillt/bitsery/compare/v4.4.0...v4.5.0) (2019-01-10)
### Features

View File

@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.1)
project(bitsery
LANGUAGES CXX
VERSION 4.5.0)
VERSION 4.5.1)
#======== build options ===================================
option(BITSERY_BUILD_EXAMPLES "Build examples" OFF)

View File

@@ -26,6 +26,16 @@ you contribute:
6. Open a pull request against Bitsery *master* branch. Currently ongoing development is on *master*. At some point an integration branch will be set-up, and pull-requests should target that, but for now its all against master. You may see feature branches come and go, too.
If you're working with visual studio, there is how to build and run all tests from command line
```shell
mkdir build
cd build
cmake -DBITSERY_BUILD_TESTS=ON -DGTEST_ROOT="<PATH to GTEST>" -DCMAKE_CXX_FLAGS_RELEASE=/MT ..
cmake --build . --config Release
(cd tests && ctest -C Release && cd ..)
```
/MT option might be optional, depending on how gtest was built.
## Style guide
Just use your own judgment and stick to the style of the surrounding code.
Just use your own judgment and stick to the style of the surrounding code.

View File

@@ -26,7 +26,7 @@
#define BITSERY_MAJOR_VERSION 4
#define BITSERY_MINOR_VERSION 5
#define BITSERY_PATCH_VERSION 0
#define BITSERY_PATCH_VERSION 1
#define BITSERY_QUOTE_MACRO(name) #name
#define BITSERY_BUILD_VERSION_STR(major,minor, patch) \

View File

@@ -34,7 +34,8 @@ namespace bitsery {
//this allows to call private serialize method, and construct instance (if no default constructor is provided) for your type
//just make friend it in your class
struct Access {
class Access {
public:
template<typename S, typename T>
static auto serialize(S &s, T &obj) -> decltype(obj.serialize(s)) {
obj.serialize(s);

View File

@@ -96,7 +96,7 @@ namespace bitsery {
template<typename TResult, typename TUnsigned>
TResult zigZagDecode(TUnsigned v, std::true_type) const {
return (v >> 1) ^ -(v & 1);
return (v >> 1) ^ (~(v & 1) + 1); // same as -(v & 1), but no warning on VisualStudio
}
// write/read bytes one by one

View File

@@ -68,12 +68,12 @@ namespace bitsery {
}
}
private:
template <typename ... TArgs>
void reserve(std::unordered_map<TArgs...>& obj, size_t size) const {
template <typename Key, typename T, typename Hash, typename KeyEqual, typename Allocator>
void reserve(std::unordered_map<Key, T, Hash, KeyEqual, Allocator>& obj, size_t size) const {
obj.reserve(size);
}
template <typename ... TArgs>
void reserve(std::unordered_multimap<TArgs...>& obj, size_t size) const {
template <typename Key, typename T, typename Hash, typename KeyEqual, typename Allocator>
void reserve(std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator>& obj, size_t size) const {
obj.reserve(size);
}
template <typename T>

View File

@@ -65,14 +65,17 @@ namespace bitsery {
}
private:
template <typename ... TArgs>
void reserve(std::unordered_set<TArgs...>& obj, size_t size) const {
template <typename Key, typename Hash, typename KeyEqual, typename Allocator>
void reserve(std::unordered_set<Key, Hash, KeyEqual, Allocator>& obj, size_t size) const {
obj.reserve(size);
}
template <typename ... TArgs>
void reserve(std::unordered_multiset<TArgs...>& obj, size_t size) const {
template <typename Key, typename Hash, typename KeyEqual, typename Allocator>
void reserve(std::unordered_multiset<Key, Hash, KeyEqual, Allocator>& obj, size_t size) const {
obj.reserve(size);
}
template <typename T>
void reserve(T& , size_t ) const {
//for ordered container do nothing

View File

@@ -96,7 +96,8 @@ namespace bitsery {
constexpr RangeSpec(T minValue, T maxValue, T precision) :
min{minValue},
max{maxValue},
bitsRequired{calcRequiredBits<details::SameSizeUnsigned<T>>({}, ((max - min) / precision))} {
bitsRequired{calcRequiredBits<details::SameSizeUnsigned<T>>(
{}, static_cast<details::SameSizeUnsigned<T>>((max - min) / precision))} {
}
@@ -163,7 +164,8 @@ namespace bitsery {
public:
template<typename ... Args>
explicit constexpr ValueRange(Args &&... args):_range{std::forward<Args>(args)...} {}
constexpr ValueRange(const TValue& min, const TValue& max, Args &&... args)
:_range{min, max, std::forward<Args>(args)...} {}
template<typename Ser, typename Writer, typename T, typename Fnc>
void serialize(Ser &, Writer &writer, const T &v, Fnc &&) const {

View File

@@ -28,8 +28,8 @@
#include "../details/flexible_common.h"
namespace bitsery {
template<typename S, typename ... TArgs>
void serialize(S &s, std::deque<TArgs... > &obj) {
template<typename S, typename T, typename Allocator>
void serialize(S &s, std::deque<T, Allocator> &obj) {
flexible::processContainer(s, obj);
}
}

View File

@@ -28,8 +28,8 @@
#include "../details/flexible_common.h"
namespace bitsery {
template<typename S, typename ... TArgs>
void serialize(S &s, std::forward_list<TArgs... > &obj) {
template<typename S, typename T, typename Allocator>
void serialize(S &s, std::forward_list<T, Allocator> &obj) {
flexible::processContainer(s, obj);
}
}

View File

@@ -28,8 +28,8 @@
#include "../details/flexible_common.h"
namespace bitsery {
template<typename S, typename ... TArgs>
void serialize(S &s, std::list<TArgs... > &obj) {
template<typename S, typename T, typename Allocator>
void serialize(S &s, std::list<T, Allocator> &obj) {
flexible::processContainer(s, obj);
}
}

View File

@@ -28,23 +28,19 @@
#include "../ext/std_map.h"
namespace bitsery {
template<typename S, typename ... TArgs>
void serialize(S &s, std::map<TArgs ... > &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
using TKey = typename std::map<TArgs...>::key_type;
using TValue = typename std::map<TArgs...>::mapped_type;
template<typename S, typename Key, typename T, typename Compare, typename Allocator>
void serialize(S &s, std::map<Key, T, Compare, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdMap{maxSize},
[&s](TKey& key, TValue& value) {
[&s](Key& key, T& value) {
s.object(key);
s.object(value);
});
}
template<typename S, typename ... TArgs>
void serialize(S &s, std::multimap<TArgs ... > &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
using TKey = typename std::multimap<TArgs...>::key_type;
using TValue = typename std::multimap<TArgs...>::mapped_type;
template<typename S, typename Key, typename T, typename Compare, typename Allocator>
void serialize(S &s, std::multimap<Key, T, Compare, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdMap{maxSize},
[&s](TKey& key, TValue& value) {
[&s](Key& key, T& value) {
s.object(key);
s.object(value);
});

View File

@@ -28,13 +28,13 @@
#include "../ext/std_set.h"
namespace bitsery {
template<typename S, typename ... TArgs>
void serialize(S &s, std::set<TArgs...> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
template<typename S, typename Key, typename Compare, typename Allocator>
void serialize(S &s, std::set<Key, Compare, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdSet{maxSize});
}
template<typename S, typename ... TArgs>
void serialize(S &s, std::multiset<TArgs...> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
template<typename S, typename Key, typename Compare, typename Allocator>
void serialize(S &s, std::multiset<Key, Compare, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdSet{maxSize});
}

View File

@@ -28,8 +28,8 @@
#include "../details/flexible_common.h"
namespace bitsery {
template<typename S, typename T, typename ... TArgs>
void serialize(S &s, std::basic_string<T, TArgs...> &str) {
template<typename S, typename CharT, typename Traits, typename Allocator>
void serialize(S &s, std::basic_string<CharT, Traits, Allocator> &str) {
flexible::processContainer(s, str);
}
}

View File

@@ -28,23 +28,19 @@
#include "../ext/std_map.h"
namespace bitsery {
template<typename S, typename ... TArgs>
void serialize(S &s, std::unordered_map<TArgs ... > &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
using TKey = typename std::unordered_map<TArgs...>::key_type;
using TValue = typename std::unordered_map<TArgs...>::mapped_type;
template<typename S, typename Key, typename T, typename Hash, typename KeyEqual, typename Allocator>
void serialize(S &s, std::unordered_map<Key, T, Hash, KeyEqual, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdMap{maxSize},
[&s](TKey& key, TValue& value) {
[&s](Key& key, T& value) {
s.object(key);
s.object(value);
});
}
template<typename S, typename ... TArgs>
void serialize(S &s, std::unordered_multimap<TArgs ... > &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
using TKey = typename std::unordered_multimap<TArgs...>::key_type;
using TValue = typename std::unordered_multimap<TArgs...>::mapped_type;
template<typename S, typename Key, typename T, typename Hash, typename KeyEqual, typename Allocator>
void serialize(S &s, std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdMap{maxSize},
[&s](TKey& key, TValue& value) {
[&s](Key& key, T& value) {
s.object(key);
s.object(value);
});

View File

@@ -28,13 +28,13 @@
#include "../ext/std_set.h"
namespace bitsery {
template<typename S, typename ... TArgs>
void serialize(S &s, std::unordered_set<TArgs...> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
template<typename S, typename Key, typename Hash, typename KeyEqual, typename Allocator>
void serialize(S &s, std::unordered_set<Key, Hash, KeyEqual, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdSet{maxSize});
}
template<typename S, typename ... TArgs>
void serialize(S &s, std::unordered_multiset<TArgs...> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
template<typename S, typename Key, typename Hash, typename KeyEqual, typename Allocator>
void serialize(S &s, std::unordered_multiset<Key, Hash, KeyEqual, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdSet{maxSize});
}

View File

@@ -28,8 +28,8 @@
#include "../details/flexible_common.h"
namespace bitsery {
template<typename S, typename ... TArgs>
void serialize(S &s, std::vector<TArgs... > &obj) {
template<typename S, typename T, typename Allocator>
void serialize(S &s, std::vector<T, Allocator> &obj) {
flexible::processContainer(s, obj);
}
}

View File

@@ -31,9 +31,9 @@ namespace bitsery {
namespace traits {
template<typename ... TArgs>
struct ContainerTraits<std::deque<TArgs...>>
: public StdContainer<std::deque<TArgs...>, true, false> {};
template<typename T, typename Allocator>
struct ContainerTraits<std::deque<T, Allocator>>
: public StdContainer<std::deque<T, Allocator>, true, false> {};
}

View File

@@ -32,22 +32,22 @@ namespace bitsery {
namespace traits {
template<typename ... TArgs>
struct ContainerTraits<std::forward_list<TArgs...>> {
using TValue = typename std::forward_list<TArgs...>::value_type;
template<typename T, typename Allocator>
struct ContainerTraits<std::forward_list<T, Allocator>> {
using TValue = T;
static constexpr bool isResizable = true;
static constexpr bool isContiguous = false;
static size_t size(const std::forward_list<TArgs...>& container) {
static size_t size(const std::forward_list<T, Allocator>& container) {
return static_cast<size_t>(std::distance(container.begin(), container.end()));
}
static void resize(std::forward_list<TArgs...>& container, size_t size) {
static void resize(std::forward_list<T, Allocator>& container, size_t size) {
resizeImpl(container, size, std::is_default_constructible<TValue>{});
}
private:
static void resizeImpl(std::forward_list<TArgs...>& container, size_t size, std::true_type) {
static void resizeImpl(std::forward_list<T, Allocator>& container, size_t size, std::true_type) {
container.resize(size);
}
static void resizeImpl(std::forward_list<TArgs...>& container, size_t newSize, std::false_type) {
static void resizeImpl(std::forward_list<T, Allocator>& container, size_t newSize, std::false_type) {
const auto oldSize = size(container);
for (auto it = oldSize; it < newSize; ++it) {
container.push_front(::bitsery::Access::create<TValue>());

View File

@@ -31,9 +31,9 @@ namespace bitsery {
namespace traits {
template<typename ... TArgs>
struct ContainerTraits<std::list<TArgs...>>
: public StdContainer<std::list<TArgs...>, true, false> {};
template<typename T, typename Allocator>
struct ContainerTraits<std::list<T, Allocator>>
: public StdContainer<std::list<T, Allocator>, true, false> {};
}

View File

@@ -33,18 +33,18 @@ namespace bitsery {
// specialization for string, because string is already included for std::char_traits
template<typename ... TArgs>
struct ContainerTraits<std::basic_string<TArgs...>>
:public StdContainer<std::basic_string<TArgs...>, true, true> {};
template<typename CharT, typename Traits, typename Allocator>
struct ContainerTraits<std::basic_string<CharT, Traits, Allocator>>
:public StdContainer<std::basic_string<CharT, Traits, Allocator>, true, true> {};
template <typename ... TArgs>
struct TextTraits<std::basic_string<TArgs...>> {
using TValue = typename ContainerTraits<std::basic_string<TArgs...>>::TValue;
template <typename CharT, typename Traits, typename Allocator>
struct TextTraits<std::basic_string<CharT, Traits, Allocator>> {
using TValue = typename ContainerTraits<std::basic_string<CharT, Traits, Allocator>>::TValue;
//string is automatically null-terminated
static constexpr bool addNUL = false;
//is is not 100% accurate, but for performance reasons assume that string stores text, not binary data
static size_t length(const std::basic_string<TArgs...>& str) {
static size_t length(const std::basic_string<CharT, Traits, Allocator>& str) {
return str.size();
}
};
@@ -60,9 +60,9 @@ namespace bitsery {
}
};
template<typename ... TArgs>
struct BufferAdapterTraits<std::basic_string<TArgs...>>
:public StdContainerForBufferAdapter<std::basic_string<TArgs...>> {};
template<typename CharT, typename Traits, typename Allocator>
struct BufferAdapterTraits<std::basic_string<CharT, Traits, Allocator>>
:public StdContainerForBufferAdapter<std::basic_string<CharT, Traits, Allocator>> {};
}

View File

@@ -30,18 +30,18 @@
namespace bitsery {
namespace traits {
template<typename ... TArgs>
struct ContainerTraits<std::vector<TArgs...>>
:public StdContainer<std::vector<TArgs...>, true, true> {};
template<typename T, typename Allocator>
struct ContainerTraits<std::vector<T, Allocator>>
:public StdContainer<std::vector<T, Allocator>, true, true> {};
//bool vector is not contiguous, do not copy it directly to buffer
template<typename Allocator>
struct ContainerTraits<std::vector<bool, Allocator>>
:public StdContainer<std::vector<bool, Allocator>, true, false> {};
template<typename ... TArgs>
struct BufferAdapterTraits<std::vector<TArgs...>>
:public StdContainerForBufferAdapter<std::vector<TArgs...>> {};
template<typename T, typename Allocator>
struct BufferAdapterTraits<std::vector<T, Allocator>>
:public StdContainerForBufferAdapter<std::vector<T, Allocator>> {};
}

View File

@@ -56,19 +56,19 @@ using InverseReader = bitsery::AdapterReader<InputAdapter, InverseEndiannessConf
TEST(DataEndianness, WhenWriteBytesThenBytesAreSwapped) {
//fill initial values
IntegralTypes src{};
src.a = static_cast<int64_t>(0x1122334455667788);
src.b = 0xBBCCDDEE;
src.c = static_cast<int16_t>(0xCCDD);
src.d = static_cast<uint8_t>(0xDD);
src.e = static_cast<int8_t>(0xEE);
src.a = static_cast<int64_t>(0x1122334455667788u);
src.b = 0xBBCCDDEEu;
src.c = static_cast<int16_t>(0xCCDDu);
src.d = static_cast<uint8_t>(0xDDu);
src.e = static_cast<int8_t>(0xEEu);
//fill expected result after swap
IntegralTypes resInv{};
resInv.a = static_cast<int64_t>(0x8877665544332211);
resInv.b = 0xEEDDCCBB;
resInv.c = static_cast<int16_t>(0xDDCC);
resInv.d = static_cast<uint8_t>(0xDD);
resInv.e = static_cast<int8_t>(0xEE);
resInv.a = static_cast<int64_t>(0x8877665544332211u);
resInv.b = 0xEEDDCCBBu;
resInv.c = static_cast<int16_t>(0xDDCCu);
resInv.d = static_cast<uint8_t>(0xDDu);
resInv.e = static_cast<int8_t>(0xEEu);
//create and write to buffer
Buffer buf{};

View File

@@ -35,7 +35,7 @@ using testing::ContainerEq;
using testing::Eq;
//forward declare, for testing with std::unordered_map
struct HasherForNonDefaultConstructible;
class HasherForNonDefaultConstructible;
class NonDefaultConstructible {
int32_t i{0};
@@ -65,7 +65,8 @@ public:
}
};
struct HasherForNonDefaultConstructible {
class HasherForNonDefaultConstructible {
public:
size_t operator()(const NonDefaultConstructible& o) const {
return std::hash<int32_t>()(o.i);
}

View File

@@ -52,9 +52,9 @@ TEST(SerializeExtensionGrowable, WriteSessionsDataAtBufferEndAfterFlush) {
ser.value1b(v);
});
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
EXPECT_THAT(ctx.getBufferSize(), Eq(1u));
ctx.bw->flush();
EXPECT_THAT(ctx.getBufferSize(), Gt(1));
EXPECT_THAT(ctx.getBufferSize(), Gt(1u));
}

View File

@@ -37,26 +37,26 @@ bool SerializeDeserializeContainerSize(SerializationContext& ctx, const size_t s
TEST(SerializeSize, WhenLengthLessThan128Then1Byte) {
SerializationContext ctx1{};
EXPECT_TRUE(SerializeDeserializeContainerSize(ctx1, 127));
EXPECT_THAT(ctx1.getBufferSize(), Eq(1));
EXPECT_THAT(ctx1.getBufferSize(), Eq(1u));
SerializationContext ctx2;
EXPECT_TRUE(SerializeDeserializeContainerSize(ctx2, 128));
EXPECT_THAT(ctx2.getBufferSize(), testing::Gt(1));
EXPECT_THAT(ctx2.getBufferSize(), testing::Gt(1u));
}
TEST(SerializeSize, WhenLengthLessThan16384Then2Bytes) {
SerializationContext ctx1;
EXPECT_TRUE(SerializeDeserializeContainerSize(ctx1, 16383));
EXPECT_THAT(ctx1.getBufferSize(), Eq(2));
EXPECT_THAT(ctx1.getBufferSize(), Eq(2u));
SerializationContext ctx2;
EXPECT_TRUE(SerializeDeserializeContainerSize(ctx2, 16384));
EXPECT_THAT(ctx2.getBufferSize(), testing::Gt(2));
EXPECT_THAT(ctx2.getBufferSize(), testing::Gt(2u));
}
TEST(SerializeSize, WhenGreaterThan16383Then4Bytes) {
SerializationContext ctx1;
EXPECT_TRUE(SerializeDeserializeContainerSize(ctx1, 16384));
EXPECT_THAT(ctx1.getBufferSize(), Eq(4));
EXPECT_THAT(ctx1.getBufferSize(), Eq(4u));
SerializationContext ctx2;
EXPECT_TRUE(SerializeDeserializeContainerSize(ctx2, 66384));
EXPECT_THAT(ctx2.getBufferSize(), Eq(4));
}
EXPECT_THAT(ctx2.getBufferSize(), Eq(4u));
}