From b3ab518fd70f72420f4278d7053ecaf880001817 Mon Sep 17 00:00:00 2001 From: Arsentiy Milchakov Date: Wed, 16 Aug 2017 16:10:37 +0300 Subject: [PATCH] [local_ads] campaign ser/des fixes + tests --- coding/write_to_sink.hpp | 3 +- local_ads/campaign_serialization.cpp | 148 +++++++++--------- .../campaign_serialization_test.cpp | 25 +-- std/type_traits.hpp | 1 + 4 files changed, 92 insertions(+), 85 deletions(-) diff --git a/coding/write_to_sink.hpp b/coding/write_to_sink.hpp index c26b6fa8a2..9ae0ab0750 100644 --- a/coding/write_to_sink.hpp +++ b/coding/write_to_sink.hpp @@ -6,7 +6,8 @@ template -typename enable_if::value, void>::type WriteToSink(TSink & sink, T const & v) +typename enable_if::value || is_enum::value, void>::type +WriteToSink(TSink & sink, T const & v) { T const t = SwapIfBigEndian(v); sink.Write(&t, sizeof(T)); diff --git a/local_ads/campaign_serialization.cpp b/local_ads/campaign_serialization.cpp index 8dcce2e803..1d583f3657 100644 --- a/local_ads/campaign_serialization.cpp +++ b/local_ads/campaign_serialization.cpp @@ -1,8 +1,12 @@ #include "local_ads/campaign_serialization.hpp" -#include "coding/varint.hpp" #include "coding/byte_stream.hpp" +#include "coding/reader.hpp" +#include "coding/varint.hpp" +#include "coding/write_to_sink.hpp" +#include "base/exception.hpp" +#include "base/logging.hpp" #include "base/stl_add.hpp" #include @@ -14,6 +18,8 @@ namespace { using namespace local_ads; +DECLARE_EXCEPTION(UnknownVersion, RootException); + auto const kHalfByteShift = CHAR_BIT / 2; auto const kHalfByteMaxValue = 15; auto const kLowerMask = 0x0F; @@ -22,44 +28,25 @@ auto const kMinZoomLevel = 10; auto const kMaxZoomLevel = 17; auto const kMaxPriority = 7; -template -constexpr bool IsEnumOrIntegral() -{ - return std::is_integral::value || std::is_enum::value; -} - -template(), void>::type * = nullptr> -void Write(ByteStream & s, T t) -{ - s.Write(&t, sizeof(T)); -} - -template(), void>::type * = nullptr> -T Read(ByteStream & s) -{ - T t; - s.Read(static_cast(&t), sizeof(t)); - return t; -} - -template::value, void*>::type = nullptr> -std::vector ReadData(ByteStream & s, size_t chunksNumber) +template ::value, void *>::type = nullptr> +std::vector ReadVarUintArray(Source & s, size_t chunksNumber) { std::vector result; - result.reserve(chunksNumber); - auto const streamBegin = s.PtrUC(); - auto const afterLastReadByte = ReadVarUint64Array( - streamBegin, - chunksNumber, - MakeBackInsertFunctor(result) - ); + for (size_t i = 0; i < chunksNumber; ++i) + result.emplace_back(static_cast(ReadVarUint(s))); - ASSERT_EQUAL(result.size(), chunksNumber, ()); - s.Advance(static_cast(afterLastReadByte) - streamBegin); + return result; +} + +template +std::vector ReadArray(Source & s, size_t chunksNumber) +{ + std::vector result; + for (size_t i = 0; i < chunksNumber; ++i) + { + result.emplace_back(ReadPrimitiveFromSource(s)); + } return result; } @@ -68,31 +55,28 @@ std::vector SerializeV1(std::vector const & campaigns) { std::vector buff; PushBackByteSink dst(buff); - Write(dst, Version::V1); - Write(dst, campaigns.size()); + WriteToSink(dst, Version::V1); + WriteToSink(dst, campaigns.size()); for (auto const & c : campaigns) WriteVarUint(dst, c.m_featureId); for (auto const & c : campaigns) WriteVarUint(dst, c.m_iconId); for (auto const & c : campaigns) - Write(dst, c.m_daysBeforeExpired); + WriteVarUint(dst, c.m_daysBeforeExpired); return buff; } std::vector DeserializeV1(std::vector const & bytes) { - ArrayByteSource src(bytes.data()); - CHECK_EQUAL(Read(src), Version::V1, ()); - auto const chunksNumber = Read(src); + ReaderSource src({bytes.data(), bytes.size()}); - auto const featureIds = ReadData(src, chunksNumber); - auto const icons = ReadData(src, chunksNumber); - auto const expirations = ReadData(src, chunksNumber); + CHECK_EQUAL(ReadPrimitiveFromSource(src), Version::V1, ()); + auto const chunksNumber = ReadPrimitiveFromSource(src); - CHECK_EQUAL(featureIds.size(), chunksNumber, ()); - CHECK_EQUAL(icons.size(), chunksNumber, ()); - CHECK_EQUAL(expirations.size(), chunksNumber, ()); + auto const featureIds = ReadVarUintArray(src, chunksNumber); + auto const icons = ReadVarUintArray(src, chunksNumber); + auto const expirations = ReadVarUintArray(src, chunksNumber); std::vector campaigns; campaigns.reserve(chunksNumber); @@ -135,35 +119,32 @@ std::vector SerializeV2(std::vector const & campaigns) { std::vector buff; PushBackByteSink dst(buff); - Write(dst, Version::V2); - Write(dst, campaigns.size()); + WriteToSink(dst, Version::V2); + WriteToSink(dst, campaigns.size()); for (auto const & c : campaigns) WriteVarUint(dst, c.m_featureId); for (auto const & c : campaigns) WriteVarUint(dst, c.m_iconId); for (auto const & c : campaigns) - Write(dst, c.m_daysBeforeExpired); + WriteVarUint(dst, c.m_daysBeforeExpired); for (auto const & c : campaigns) - Write(dst, PackZoomAndPriority(c.m_minZoomLevel, c.m_priority)); + WriteToSink(dst, PackZoomAndPriority(c.m_minZoomLevel, c.m_priority)); return buff; } std::vector DeserializeV2(std::vector const & bytes) { - ArrayByteSource src(bytes.data()); - CHECK_EQUAL(Read(src), Version::V2, ()); - auto const chunksNumber = Read(src); + ReaderSource src({bytes.data(), bytes.size()}); - auto const featureIds = ReadData(src, chunksNumber); - auto const icons = ReadData(src, chunksNumber); - auto const expirations = ReadData(src, chunksNumber); - auto const zoomAndPriority = ReadData(src, chunksNumber); + CHECK_EQUAL(ReadPrimitiveFromSource(src), Version::V2, ()); + auto const chunksNumber = ReadPrimitiveFromSource(src); - CHECK_EQUAL(featureIds.size(), chunksNumber, ()); - CHECK_EQUAL(icons.size(), chunksNumber, ()); - CHECK_EQUAL(expirations.size(), chunksNumber, ()); - CHECK_EQUAL(zoomAndPriority.size(), chunksNumber, ()); + auto const featureIds = ReadVarUintArray(src, chunksNumber); + auto const icons = ReadVarUintArray(src, chunksNumber); + auto const expirations = ReadVarUintArray(src, chunksNumber); + + auto const zoomAndPriority = ReadArray(src, chunksNumber); std::vector campaigns; campaigns.reserve(chunksNumber); @@ -187,11 +168,18 @@ namespace local_ads { std::vector Serialize(std::vector const & campaigns, Version const version) { - switch (version) + try { - case Version::V1: return SerializeV1(campaigns); - case Version::V2: return SerializeV2(campaigns); - default: ASSERT(false, ("Unknown version")); + switch (version) + { + case Version::V1: return SerializeV1(campaigns); + case Version::V2: return SerializeV2(campaigns); + default: MYTHROW(UnknownVersion, (version)); + } + } + catch (RootException const & e) + { + LOG(LERROR, ("Cannot to serialize campaigns", e.what(), e.Msg())); } return {}; @@ -204,14 +192,26 @@ std::vector Serialize(std::vector const & campaigns) std::vector Deserialize(std::vector const & bytes) { - ArrayByteSource src(bytes.data()); - auto const version = Read(src); - - switch (version) + try { - case Version::V1: return DeserializeV1(bytes); - case Version::V2: return DeserializeV2(bytes); - default: ASSERT(false, ("Unknown version")); + ReaderSource src({bytes.data(), bytes.size()}); + + auto const version = ReadPrimitiveFromSource(src); + + switch (version) + { + case Version::V1: return DeserializeV1(bytes); + case Version::V2: return DeserializeV2(bytes); + default: MYTHROW(UnknownVersion, (version)); + } + } + catch (RootException const & e) + { + LOG(LERROR, ("Cannot to deserialize received data", e.what(), e.Msg())); + } + catch (std::bad_alloc const & e) + { + LOG(LERROR, ("Cannot to allocate memory for local ads campaigns", e.what())); } return {}; diff --git a/local_ads/local_ads_tests/campaign_serialization_test.cpp b/local_ads/local_ads_tests/campaign_serialization_test.cpp index 4cec8f9ab0..a111539555 100644 --- a/local_ads/local_ads_tests/campaign_serialization_test.cpp +++ b/local_ads/local_ads_tests/campaign_serialization_test.cpp @@ -2,6 +2,7 @@ #include "local_ads/campaign_serialization.hpp" +#include #include #include @@ -9,6 +10,9 @@ using namespace local_ads; namespace { +template +using Limits = typename std::numeric_limits; + bool TestSerialization(std::vector const & cs, Version const v) { auto const bytes = Serialize(cs, v); @@ -19,9 +23,9 @@ std::vector GenerateCampaignsV1(size_t number) { std::random_device rd; std::mt19937 gen(rd()); - std::uniform_int_distribution<> featureIds(1, 600000); - std::uniform_int_distribution<> icons(1, 4096); - std::uniform_int_distribution<> expirationDays(1, 30); + std::uniform_int_distribution<> featureIds(1, Limits::max()); + std::uniform_int_distribution<> icons(1, Limits::max()); + std::uniform_int_distribution<> expirationDays(1, Limits::max()); std::vector cs; while (number--) @@ -38,9 +42,9 @@ std::vector GenerateCampaignsV2(size_t number) { int kSeed = 42; std::mt19937 gen(kSeed); - std::uniform_int_distribution<> featureIds(1, 600000); - std::uniform_int_distribution<> icons(1, 4096); - std::uniform_int_distribution<> expirationDays(1, 30); + std::uniform_int_distribution<> featureIds(1, Limits::max()); + std::uniform_int_distribution<> icons(1, Limits::max()); + std::uniform_int_distribution<> expirationDays(1, Limits::max()); std::uniform_int_distribution<> zoomLevels(10, 17); std::uniform_int_distribution<> priorities(0, 7); @@ -61,14 +65,15 @@ std::vector GenerateCampaignsV2(size_t number) UNIT_TEST(Serialization_Smoke) { TEST(TestSerialization({ - {10, 10, 10}, - {1000, 100, 20}, + {0, 0, 0}, + {Limits::max(), Limits::max(), Limits::max()}, {120003, 456, 15} }, Version::V1), ()); TEST(TestSerialization({ - {10, 10, 10, 10, 0}, - {1000, 100, 20, 17, 7}, + {0, 0, 0, 10, 0}, + {Limits::max(), Limits::max(), Limits::max()}, + {1000, 100, 255, 17, 7}, {120003, 456, 15, 13, 6} }, Version::V2), ()); diff --git a/std/type_traits.hpp b/std/type_traits.hpp index df4d4565d2..85a1bf9390 100644 --- a/std/type_traits.hpp +++ b/std/type_traits.hpp @@ -12,6 +12,7 @@ using std::is_arithmetic; using std::is_base_of; using std::is_constructible; using std::is_convertible; +using std::is_enum; using std::is_floating_point; using std::is_integral; using std::is_pod;