diff options
Diffstat (limited to 'local_ads/campaign_serialization.cpp')
-rw-r--r-- | local_ads/campaign_serialization.cpp | 124 |
1 files changed, 102 insertions, 22 deletions
diff --git a/local_ads/campaign_serialization.cpp b/local_ads/campaign_serialization.cpp index 2b43c093eb..4b64e1a87d 100644 --- a/local_ads/campaign_serialization.cpp +++ b/local_ads/campaign_serialization.cpp @@ -11,6 +11,15 @@ namespace { +using namespace local_ads; + +auto const kHalfByteShift = 0x4; +auto const kLowerMask = 0xF; +auto const kUpperMask = 0xF0; +auto const kMinZoomLevel = 10; +auto const kMaxZoomLevel = 17; +auto const kMaxPriority = 7; + template<typename T> constexpr bool IsEnumOrIntegral() { @@ -52,52 +61,123 @@ std::vector<Integral> ReadData(ByteStream & s, size_t chunksNumber) return result; } +std::vector<Campaign> DeserializeV1(std::vector<uint8_t> const & bytes) +{ + ArrayByteSource src(bytes.data()); + CHECK_EQUAL(Read<Version>(src), Version::v1, ()); + auto const chunksNumber = Read<uint64_t>(src); + + auto const featureIds = ReadData<uint32_t>(src, chunksNumber); + auto const icons = ReadData<uint16_t>(src, chunksNumber); + auto const expirations = ReadData<uint8_t>(src, chunksNumber); + + CHECK_EQUAL(featureIds.size(), chunksNumber, ()); + CHECK_EQUAL(icons.size(), chunksNumber, ()); + CHECK_EQUAL(expirations.size(), chunksNumber, ()); + + std::vector<Campaign> campaigns; + campaigns.reserve(chunksNumber); + for (size_t i = 0; i < chunksNumber; ++i) + { + campaigns.emplace_back(featureIds[i], icons[i], expirations[i]); + } + return campaigns; +} + +uint8_t ZoomIndex(uint8_t zoomValue) { return zoomValue - kMinZoomLevel; } + +uint8_t ZoomValue(uint8_t zoomIndex) { return zoomIndex + kMinZoomLevel; } + +std::vector<Campaign> DeserializeV2(std::vector<uint8_t> const & bytes) +{ + ArrayByteSource src(bytes.data()); + CHECK_EQUAL(Read<Version>(src), Version::v2, ()); + auto const chunksNumber = Read<uint64_t>(src); + + auto const featureIds = ReadData<uint32_t>(src, chunksNumber); + auto const icons = ReadData<uint16_t>(src, chunksNumber); + auto const expirations = ReadData<uint8_t>(src, chunksNumber); + auto const zoomAndPriority = ReadData<uint8_t>(src, chunksNumber); + + CHECK_EQUAL(featureIds.size(), chunksNumber, ()); + CHECK_EQUAL(icons.size(), chunksNumber, ()); + CHECK_EQUAL(expirations.size(), chunksNumber, ()); + CHECK_EQUAL(zoomAndPriority.size(), chunksNumber, ()); + + std::vector<Campaign> campaigns; + campaigns.reserve(chunksNumber); + for (size_t i = 0; i < chunksNumber; ++i) + { + campaigns.emplace_back(featureIds[i], icons[i], expirations[i], + ZoomValue(zoomAndPriority[i] & kLowerMask), + (zoomAndPriority[i] >> kHalfByteShift) & kLowerMask); + + ASSERT_GREATER_OR_EQUAL(campaigns.back().m_minZoomLevel, kMinZoomLevel, + ("Unsupported zoom level")); + ASSERT_LESS_OR_EQUAL(campaigns.back().m_minZoomLevel, kMaxZoomLevel, + ("Unsupported zoom level")); + ASSERT_LESS_OR_EQUAL(campaigns.back().m_priority, kMaxPriority, ("Unsupported priority value")); + } + return campaigns; +} } // namespace namespace local_ads { -std::vector<uint8_t> Serialize(std::vector<Campaign> const & campaigns) +std::vector<uint8_t> Serialize(std::vector<Campaign> const & campaigns, Version const version) { std::vector<uint8_t> buff; PushBackByteSink<decltype(buff)> dst(buff); - Write(dst, Version::latest); + Write(dst, version); Write(dst, campaigns.size()); for (auto const & c : campaigns) - WriteVarUint(dst, c.m_featureId); + 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); + for (auto const & c : campaigns) + { + ASSERT_GREATER_OR_EQUAL(c.m_minZoomLevel, kMinZoomLevel, ("Unsupported zoom level")); + ASSERT_LESS_OR_EQUAL(c.m_minZoomLevel, kMaxZoomLevel, ("Unsupported zoom level")); + ASSERT_LESS_OR_EQUAL(c.m_priority, kMaxPriority, ("Unsupported priority value")); + + Write(dst, static_cast<uint8_t>((ZoomIndex(c.m_minZoomLevel) & kLowerMask) | + ((c.m_priority << kHalfByteShift) & kUpperMask))); + } + return buff; } +std::vector<uint8_t> Serialize(std::vector<Campaign> const & campaigns) +{ + return Serialize(campaigns, Version::latest); +} + std::vector<Campaign> Deserialize(std::vector<uint8_t> const & bytes) { ArrayByteSource src(bytes.data()); auto const version = Read<Version>(src); - static_cast<void>(version); // No version dispatching for now. - auto const chunksNumber = Read<uint64_t>(src); - auto const featureIds = ReadData<uint32_t>(src, chunksNumber); - auto const icons = ReadData<uint16_t>(src, chunksNumber); - auto const expirations = ReadData<uint8_t>(src, chunksNumber); + switch (version) + { + case Version::v1: return DeserializeV1(bytes); + case Version::v2: return DeserializeV2(bytes); + default: ASSERT(false, ("Unknown version type")); + } - CHECK_EQUAL(featureIds.size(), chunksNumber, ()); - CHECK_EQUAL(icons.size(), chunksNumber, ()); - CHECK_EQUAL(expirations.size(), chunksNumber, ()); + return {}; +} - std::vector<Campaign> campaigns; - campaigns.reserve(chunksNumber); - for (size_t i = 0; i < chunksNumber; ++i) +std::string DebugPrint(local_ads::Version version) +{ + using local_ads::Version; + + switch (version) { - campaigns.emplace_back( - featureIds[i], - icons[i], - expirations[i], - true /* priorityBit */ - ); + case Version::unknown: return "Unknown"; + case Version::v1: return "Version 1"; + case Version::v2: return "Version 2"; } - return campaigns; } } // namespace local_ads |