Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArsentiy Milchakov <milcars@mapswithme.com>2017-07-28 13:35:46 +0300
committerYuri Gorshenin <mipt.vi002@gmail.com>2017-07-31 17:09:17 +0300
commit84183a61840c34e10faf673638151fe8b3c6a2bc (patch)
tree59b920aadd3d10fe995f7a5a8a6dcd4c1f8f7ee9
parent1c252b73166a2974637463f19b37d9bee3c72754 (diff)
MAPSME-5094 localads serialization
-rw-r--r--local_ads/campaign.hpp33
-rw-r--r--local_ads/campaign_serialization.cpp124
-rw-r--r--local_ads/campaign_serialization.hpp14
-rw-r--r--local_ads/local_ads_tests/campaign_serialization_test.cpp57
-rw-r--r--local_ads/pylocal_ads/bindings.cpp5
-rw-r--r--local_ads/pylocal_ads/bindings_test.py27
6 files changed, 206 insertions, 54 deletions
diff --git a/local_ads/campaign.hpp b/local_ads/campaign.hpp
index 172e4f114f..5eb795ef7f 100644
--- a/local_ads/campaign.hpp
+++ b/local_ads/campaign.hpp
@@ -9,30 +9,35 @@ namespace local_ads
{
struct Campaign
{
- Campaign(uint32_t featureId,
- uint16_t iconId,
- uint8_t daysBeforeExpired,
- bool priorityBit)
+ // Constructor for data Version::v1
+ Campaign(uint32_t featureId, uint16_t iconId, uint8_t daysBeforeExpired)
+ : m_featureId(featureId), m_iconId(iconId), m_daysBeforeExpired(daysBeforeExpired)
+ {
+ }
+
+ // Constructor for data Version::v2
+ Campaign(uint32_t featureId, uint16_t iconId, uint8_t daysBeforeExpired, uint8_t zoomLevel,
+ uint8_t priority)
: m_featureId(featureId)
, m_iconId(iconId)
, m_daysBeforeExpired(daysBeforeExpired)
- , m_priorityBit(priorityBit)
+ , m_minZoomLevel(zoomLevel)
+ , m_priority(priority)
{
}
std::string GetIconName() const { return IconsInfo::Instance().GetIcon(m_iconId); }
- uint32_t m_featureId;
- uint16_t m_iconId;
- uint8_t m_daysBeforeExpired;
- bool m_priorityBit;
+ uint32_t m_featureId = 0;
+ uint16_t m_iconId = 0;
+ uint8_t m_daysBeforeExpired = 0;
+ uint8_t m_minZoomLevel = 16; // supported values range: 10-17
+ uint8_t m_priority = 0; // supported values range: 0-7
};
inline bool operator==(Campaign const & a, Campaign const & b)
{
- return
- a.m_featureId == b.m_featureId &&
- a.m_iconId == b.m_iconId &&
- a.m_daysBeforeExpired == b.m_daysBeforeExpired &&
- a.m_priorityBit == b.m_priorityBit;
+ return a.m_featureId == b.m_featureId && a.m_iconId == b.m_iconId &&
+ a.m_daysBeforeExpired == b.m_daysBeforeExpired && a.m_minZoomLevel == b.m_minZoomLevel &&
+ a.m_priority == b.m_priority;
}
} // namespace local_ads
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
diff --git a/local_ads/campaign_serialization.hpp b/local_ads/campaign_serialization.hpp
index a73b78b6ed..167c0259a0 100644
--- a/local_ads/campaign_serialization.hpp
+++ b/local_ads/campaign_serialization.hpp
@@ -10,11 +10,17 @@ namespace local_ads
enum class Version
{
unknown = -1,
- v1 = 0, // March 2017 (Store feature ids and icon ids as varints,
- // use one byte for days before expiration.)
- latest = v1
-};
+ // March 2017 (store feature ids and icon ids as varints, use one byte for days before
+ // expiration).
+ v1 = 0,
+ // August 2017 (store zoom level and priority as 0-7 values in one byte).
+ v2 = 1,
+ latest = v2
+};
+std::vector<uint8_t> Serialize(std::vector<Campaign> const & campaigns, Version const version);
std::vector<uint8_t> Serialize(std::vector<Campaign> const & campaigns);
std::vector<Campaign> Deserialize(std::vector<uint8_t> const & bytes);
+
+std::string DebugPrint(local_ads::Version version);
} // namespace local_ads
diff --git a/local_ads/local_ads_tests/campaign_serialization_test.cpp b/local_ads/local_ads_tests/campaign_serialization_test.cpp
index 5479fa5021..40a69017bd 100644
--- a/local_ads/local_ads_tests/campaign_serialization_test.cpp
+++ b/local_ads/local_ads_tests/campaign_serialization_test.cpp
@@ -9,13 +9,13 @@ using namespace local_ads;
namespace
{
-bool TestSerialization(std::vector<Campaign> const & cs)
+bool TestSerialization(std::vector<Campaign> const & cs, Version const v)
{
- auto const bytes = Serialize(cs);
+ auto const bytes = Serialize(cs, v);
return cs == Deserialize(bytes);
}
-std::vector<Campaign> GenerateRandomCampaigns(size_t number)
+std::vector<Campaign> GenerateCampaignsV1(size_t number)
{
std::random_device rd;
std::mt19937 gen(rd());
@@ -29,7 +29,30 @@ std::vector<Campaign> GenerateRandomCampaigns(size_t number)
auto const fid = featureIds(gen);
auto const iconid = icons(gen);
auto const days = expirationDays(gen);
- cs.emplace_back(fid, iconid, days, true /* priorityBit */);
+ cs.emplace_back(fid, iconid, days);
+ }
+ return cs;
+}
+
+std::vector<Campaign> GenerateCampaignsV2(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<> zoomLevels(10, 17);
+ std::uniform_int_distribution<> priorities(0, 7);
+
+ std::vector<Campaign> cs;
+ while (number--)
+ {
+ auto const fid = featureIds(gen);
+ auto const iconid = icons(gen);
+ auto const days = expirationDays(gen);
+ auto const zoom = zoomLevels(gen);
+ auto const priority = priorities(gen);
+ cs.emplace_back(fid, iconid, days, zoom, priority);
}
return cs;
}
@@ -38,12 +61,22 @@ std::vector<Campaign> GenerateRandomCampaigns(size_t number)
UNIT_TEST(Serialization_Smoke)
{
TEST(TestSerialization({
- {10, 10, 10, true},
- {1000, 100, 20, true},
- {120003, 456, 15, true}
- }), ());
-
- TEST(TestSerialization(GenerateRandomCampaigns(100)), ());
- TEST(TestSerialization(GenerateRandomCampaigns(1000)), ());
- TEST(TestSerialization(GenerateRandomCampaigns(10000)), ());
+ {10, 10, 10},
+ {1000, 100, 20},
+ {120003, 456, 15}
+ }, Version::v1), ());
+
+ TEST(TestSerialization({
+ {10, 10, 10, 10, 0},
+ {1000, 100, 20, 17, 7},
+ {120003, 456, 15, 13, 6}
+ }, Version::v2), ());
+
+ TEST(TestSerialization(GenerateCampaignsV1(100), Version::v1), ());
+ TEST(TestSerialization(GenerateCampaignsV1(1000), Version::v1), ());
+ TEST(TestSerialization(GenerateCampaignsV1(10000), Version::v1), ());
+
+ TEST(TestSerialization(GenerateCampaignsV2(100), Version::v2), ());
+ TEST(TestSerialization(GenerateCampaignsV2(1000), Version::v2), ());
+ TEST(TestSerialization(GenerateCampaignsV2(10000), Version::v2), ());
}
diff --git a/local_ads/pylocal_ads/bindings.cpp b/local_ads/pylocal_ads/bindings.cpp
index a3639f64c6..c31ea91f01 100644
--- a/local_ads/pylocal_ads/bindings.cpp
+++ b/local_ads/pylocal_ads/bindings.cpp
@@ -38,11 +38,12 @@ BOOST_PYTHON_MODULE(pylocal_ads)
to_python_converter<std::vector<uint8_t>, vector_uint8t_to_str>();
vector_uint8t_from_python_str();
- class_<Campaign>("Campaign", init<uint32_t, uint16_t, uint8_t, bool>())
+ class_<Campaign>("Campaign", init<uint32_t, uint16_t, uint8_t, uint8_t, uint8_t>())
.def_readonly("m_featureId", &Campaign::m_featureId)
.def_readonly("m_iconId", &Campaign::m_iconId)
.def_readonly("m_daysBeforeExpired", &Campaign::m_daysBeforeExpired)
- .def_readonly("m_priorityBit", &Campaign::m_priorityBit);
+ .def_readonly("m_minZoomLevel", &Campaign::m_minZoomLevel)
+ .def_readonly("m_priority", &Campaign::m_priority);
class_<std::vector<Campaign>>("CampaignList")
.def(vector_indexing_suite<std::vector<Campaign>>());
diff --git a/local_ads/pylocal_ads/bindings_test.py b/local_ads/pylocal_ads/bindings_test.py
new file mode 100644
index 0000000000..4decdc314a
--- /dev/null
+++ b/local_ads/pylocal_ads/bindings_test.py
@@ -0,0 +1,27 @@
+from pylocal_ads import (Campaign, serialize, deserialize)
+
+
+def smoke():
+ campaigns = [
+ Campaign(10, 10, 10, 10, 0),
+ Campaign(1000, 100, 20, 17, 7),
+ Campaign(120003, 456, 15, 13, 6)
+ ]
+
+ serialized = serialize(campaigns)
+ result = deserialize(serialized)
+
+ if campaigns.sort() == result.sort():
+ return True
+
+ return False
+
+
+def main():
+ if smoke():
+ print "Smoke OK"
+ else:
+ print "Smoke FAIL"
+
+if __name__ == "__main__":
+ main()