diff options
author | Yuri Gorshenin <y@maps.me> | 2017-06-21 01:07:36 +0300 |
---|---|---|
committer | Yuri Gorshenin <mipt.vi002@gmail.com> | 2017-07-05 16:41:38 +0300 |
commit | 41800988f08780d79efe5db10ddd8e15a060929f (patch) | |
tree | ff2687c229b9eeb6de695e272383788be96302d7 | |
parent | 56347174828c1982b397a4671b1e9991d209a912 (diff) |
[ugc] Template and macro magic for visitors.
-rw-r--r-- | ugc/serdes.hpp | 170 | ||||
-rw-r--r-- | ugc/types.hpp | 70 | ||||
-rw-r--r-- | ugc/ugc_tests/serdes_tests.cpp | 17 |
3 files changed, 111 insertions, 146 deletions
diff --git a/ugc/serdes.hpp b/ugc/serdes.hpp index f799403dcf..a6be07e468 100644 --- a/ugc/serdes.hpp +++ b/ugc/serdes.hpp @@ -28,63 +28,33 @@ class Serializer public: Serializer(Sink & sink, HeaderV0 const & header) : m_sink(sink), m_header(header) {} - void operator()(uint8_t const d) { WriteToSink(m_sink, d); } - void operator()(uint32_t const d) { WriteToSink(m_sink, d); } - void operator()(uint64_t const d) { WriteToSink(m_sink, d); } - void operator()(std::string const & s) { utils::WriteString(m_sink, s); } + void operator()(uint8_t const d, char const * /* name */ = nullptr) { WriteToSink(m_sink, d); } + void operator()(uint32_t const d, char const * /* name */ = nullptr) { WriteToSink(m_sink, d); } + void operator()(uint64_t const d, char const * /* name */ = nullptr) { WriteToSink(m_sink, d); } + void operator()(std::string const & s, char const * /* name */ = nullptr) + { + utils::WriteString(m_sink, s); + } - void SerRating(float const f) + void VisitRating(float const f, char const * /* name */ = nullptr) { CHECK_GREATER_OR_EQUAL(f, 0.0, ()); auto const d = static_cast<uint32_t>(round(f * 10)); - SerVarUint(d); + VisitVarUint(d); } template <typename T> - void SerVarUint(T const & t) + void VisitVarUint(T const & t, char const * /* name */ = nullptr) { WriteVarUint(m_sink, t); } - template <typename T> - void operator()(vector<T> const & vs) - { - SerVarUint(static_cast<uint32_t>(vs.size())); - for (auto const & v : vs) - (*this)(v); - } - - void operator()(RatingRecord const & ratingRecord) + void operator()(Time const & t, char const * /* name */ = nullptr) { - (*this)(ratingRecord.m_key); - SerRating(ratingRecord.m_value); + VisitVarUint(ToDaysSinceEpoch(t)); } - void operator()(Rating const & rating) - { - (*this)(rating.m_ratings); - SerRating(rating.m_aggValue); - } - - void operator()(UID const & uid) - { - (*this)(uid.m_hi); - (*this)(uid.m_lo); - } - - void operator()(Author const & author) - { - (*this)(author.m_uid); - (*this)(author.m_name); - } - - void operator()(Text const & text) - { - (*this)(text.m_lang); - (*this)(text.m_text); - } - - void operator()(Sentiment sentiment) + void operator()(Sentiment sentiment, char const * /* name */ = nullptr) { switch (sentiment) { @@ -93,27 +63,18 @@ public: } } - void operator()(Review const & review) - { - (*this)(review.m_id); - (*this)(review.m_text); - (*this)(review.m_author); - SerRating(review.m_rating); - (*this)(review.m_sentiment); - SerVarUint(review.DaysSinceEpoch()); - } - - void operator()(Attribute const & attribute) + template <typename T> + void operator()(vector<T> const & vs, char const * /* name */ = nullptr) { - (*this)(attribute.m_key); - (*this)(attribute.m_value); + VisitVarUint(static_cast<uint32_t>(vs.size())); + for (auto const & v : vs) + (*this)(v); } - void operator()(UGC const & ugc) + template <typename R> + void operator()(R const & r, char const * /* name */ = nullptr) { - (*this)(ugc.m_rating); - (*this)(ugc.m_reviews); - (*this)(ugc.m_attributes); + r.Visit(*this); } private: @@ -127,70 +88,47 @@ class DeserializerV0 public: DeserializerV0(Source & source, HeaderV0 const & header) : m_source(source), m_header(header) {} - void operator()(uint8_t & d) { ReadPrimitiveFromSource(m_source, d); } - void operator()(uint32_t & d) { ReadPrimitiveFromSource(m_source, d); } - void operator()(uint64_t & d) { ReadPrimitiveFromSource(m_source, d); } - void operator()(std::string & s) { utils::ReadString(m_source, s); } - - void DesRating(float & f) - { - uint32_t d = 0; - DesVarUint(d); - f = static_cast<float>(d) / 10; - } - - template <typename T> - void DesVarUint(T & t) + void operator()(uint8_t & d, char const * /* name */ = nullptr) { - t = ReadVarUint<T, Source>(m_source); + ReadPrimitiveFromSource(m_source, d); } - - template <typename T> - T DesVarUint() + void operator()(uint32_t & d, char const * /* name */ = nullptr) { - return ReadVarUint<T, Source>(m_source); + ReadPrimitiveFromSource(m_source, d); } - - void operator()(RatingRecord & ratingRecord) + void operator()(uint64_t & d, char const * /* name */ = nullptr) { - (*this)(ratingRecord.m_key); - DesRating(ratingRecord.m_value); + ReadPrimitiveFromSource(m_source, d); } - - template <typename T> - void operator()(vector<T> & vs) + void operator()(std::string & s, char const * /* name */ = nullptr) { - auto const size = DesVarUint<uint32_t>(); - vs.resize(size); - for (auto & v : vs) - (*this)(v); + utils::ReadString(m_source, s); } - void operator()(Rating & rating) + void VisitRating(float & f, char const * /* name */ = nullptr) { - (*this)(rating.m_ratings); - DesRating(rating.m_aggValue); + auto const d = DesVarUint<uint32_t>(); + f = static_cast<float>(d) / 10; } - void operator()(UID & uid) + template <typename T> + void VisitVarUint(T & t, char const * /* name */ = nullptr) { - (*this)(uid.m_hi); - (*this)(uid.m_lo); + t = ReadVarUint<T, Source>(m_source); } - void operator()(Author & author) + template <typename T> + T DesVarUint() { - (*this)(author.m_uid); - (*this)(author.m_name); + return ReadVarUint<T, Source>(m_source); } - void operator()(Text & text) + void operator()(Time & t, char const * /* name */ = nullptr) { - (*this)(text.m_lang); - (*this)(text.m_text); + t = FromDaysSinceEpoch(DesVarUint<uint32_t>()); } - void operator()(Sentiment & sentiment) + void operator()(Sentiment & sentiment, char const * /* name */ = nullptr) { uint8_t s = 0; (*this)(s); @@ -202,27 +140,19 @@ public: } } - void operator()(Review & review) - { - (*this)(review.m_id); - (*this)(review.m_text); - (*this)(review.m_author); - DesRating(review.m_rating); - (*this)(review.m_sentiment); - review.SetDaysSinceEpoch(DesVarUint<uint32_t>()); - } - - void operator()(Attribute & attribute) + template <typename T> + void operator()(vector<T> & vs, char const * /* name */ = nullptr) { - (*this)(attribute.m_key); - (*this)(attribute.m_value); + auto const size = DesVarUint<uint32_t>(); + vs.resize(size); + for (auto & v : vs) + (*this)(v); } - void operator()(UGC & ugc) + template <typename R> + void operator()(R & r, char const * /* name */ = nullptr) { - (*this)(ugc.m_rating); - (*this)(ugc.m_reviews); - (*this)(ugc.m_attributes); + r.Visit(*this); } private: diff --git a/ugc/types.hpp b/ugc/types.hpp index 1fffe74d07..32e4e2cd64 100644 --- a/ugc/types.hpp +++ b/ugc/types.hpp @@ -4,7 +4,6 @@ #include "coding/hex.hpp" - #include <chrono> #include <cstdint> #include <memory> @@ -13,6 +12,18 @@ #include <string> #include <vector> +#define DECLARE_VISITOR(...) \ + template <typename Visitor> \ + void Visit(Visitor & visitor) \ + { \ + __VA_ARGS__; \ + } \ + template <typename Visitor> \ + void Visit(Visitor & visitor) const \ + { \ + __VA_ARGS__; \ + } + namespace ugc { using TranslationKey = std::string; @@ -33,11 +44,25 @@ inline std::string DebugPrint(Sentiment const & sentiment) } } +inline uint32_t ToDaysSinceEpoch(Time const & time) +{ + auto const hours = std::chrono::duration_cast<std::chrono::hours>(time.time_since_epoch()); + return static_cast<uint32_t>(hours.count()) / 24; +} + +inline Time FromDaysSinceEpoch(uint32_t days) +{ + auto const hours = std::chrono::hours(days * 24); + return Time(hours); +} + struct RatingRecord { RatingRecord() = default; RatingRecord(TranslationKey const & key, float const value) : m_key(key), m_value(value) {} + DECLARE_VISITOR(visitor(m_key, "key"), visitor.VisitRating(m_value, "value")) + bool operator==(RatingRecord const & rhs) const { return m_key == rhs.m_key && m_value == rhs.m_value; @@ -62,6 +87,8 @@ struct Rating { } + DECLARE_VISITOR(visitor(m_ratings, "ratings"), visitor.VisitRating(m_aggValue, "aggValue")) + bool operator==(Rating const & rhs) const { return m_ratings == rhs.m_ratings && m_aggValue == rhs.m_aggValue; @@ -70,8 +97,8 @@ struct Rating friend std::string DebugPrint(Rating const & rating) { std::ostringstream os; - os << "Rating [ ratings:" << ::DebugPrint(rating.m_ratings) << ", aggValue:" << rating.m_aggValue - << " ]"; + os << "Rating [ ratings:" << ::DebugPrint(rating.m_ratings) + << ", aggValue:" << rating.m_aggValue << " ]"; return os.str(); } @@ -86,8 +113,9 @@ struct UID std::string ToString() const { return NumToHex(m_hi) + NumToHex(m_lo); } - bool operator==(UID const & rhs) const { return m_hi == rhs.m_hi && m_lo == rhs.m_lo; } + DECLARE_VISITOR(visitor(m_hi, "hi"), visitor(m_lo, "lo")); + bool operator==(UID const & rhs) const { return m_hi == rhs.m_hi && m_lo == rhs.m_lo; } friend std::string DebugPrint(UID const & uid) { std::ostringstream os; @@ -104,8 +132,9 @@ struct Author Author() = default; Author(UID const & uid, std::string const & name) : m_uid(uid), m_name(name) {} - bool operator==(Author const & rhs) const { return m_uid == rhs.m_uid && m_name == rhs.m_name; } + DECLARE_VISITOR(visitor(m_uid, "uid"), visitor(m_name, "name")); + bool operator==(Author const & rhs) const { return m_uid == rhs.m_uid && m_name == rhs.m_name; } friend std::string DebugPrint(Author const & author) { std::ostringstream os; @@ -122,8 +151,9 @@ struct Text Text() = default; Text(std::string const & text, uint8_t const lang) : m_text(text), m_lang(lang) {} - bool operator==(Text const & rhs) const { return m_lang == rhs.m_lang && m_text == rhs.m_text; } + DECLARE_VISITOR(visitor(m_lang, "lang"), visitor(m_text, "text")); + bool operator==(Text const & rhs) const { return m_lang == rhs.m_lang && m_text == rhs.m_text; } friend std::string DebugPrint(Text const & text) { std::ostringstream os; @@ -147,24 +177,16 @@ struct Review { } + DECLARE_VISITOR(visitor(m_id, "id"), visitor(m_text, "text"), visitor(m_author, "author"), + visitor.VisitRating(m_rating, "rating"), visitor(m_sentiment, "sentiment"), + visitor(m_time, "time")) + bool operator==(Review const & rhs) const { return m_id == rhs.m_id && m_text == rhs.m_text && m_author == rhs.m_author && m_rating == rhs.m_rating && m_sentiment == rhs.m_sentiment && m_time == rhs.m_time; } - uint32_t DaysSinceEpoch() const - { - auto const hours = std::chrono::duration_cast<std::chrono::hours>(m_time.time_since_epoch()); - return static_cast<uint32_t>(hours.count()) / 24; - } - - void SetDaysSinceEpoch(uint32_t days) - { - auto const hours = std::chrono::hours(days * 24); - m_time = Time(hours); - } - friend std::string DebugPrint(Review const & review) { std::ostringstream os; @@ -174,7 +196,7 @@ struct Review os << "author:" << DebugPrint(review.m_author) << ", "; os << "rating:" << review.m_rating << ", "; os << "sentiment:" << DebugPrint(review.m_sentiment) << ", "; - os << "days since epoch:" << review.DaysSinceEpoch() << " ]"; + os << "days since epoch:" << ToDaysSinceEpoch(review.m_time) << " ]"; return os.str(); } @@ -196,6 +218,8 @@ struct Attribute { } + DECLARE_VISITOR(visitor(m_key, "key"), visitor(m_value, "value")) + bool operator==(Attribute const & rhs) const { return m_key == rhs.m_key && m_value == rhs.m_value; @@ -221,7 +245,11 @@ struct UGC { } - bool operator==(UGC const & rhs) const { + DECLARE_VISITOR(visitor(m_rating, "rating"), visitor(m_reviews, "review"), + visitor(m_attributes, "attributes")) + + bool operator==(UGC const & rhs) const + { return m_rating == rhs.m_rating && m_reviews == rhs.m_reviews && m_attributes == rhs.m_attributes; } @@ -274,3 +302,5 @@ struct UGCUpdate ReviewFeedback m_feedbacks; }; } // namespace ugc + +#undef DECLARE_VISITOR diff --git a/ugc/ugc_tests/serdes_tests.cpp b/ugc/ugc_tests/serdes_tests.cpp index 66638655a3..5687570f32 100644 --- a/ugc/ugc_tests/serdes_tests.cpp +++ b/ugc/ugc_tests/serdes_tests.cpp @@ -29,6 +29,7 @@ Rating GetTestRating() } MemWriter<Buffer> MakeSink(Buffer & buffer) { return MemWriter<Buffer>(buffer); } + ReaderSource<MemReader> MakeSource(Buffer const & buffer) { MemReader reader(buffer.data(), buffer.size()); @@ -37,7 +38,7 @@ ReaderSource<MemReader> MakeSource(Buffer const & buffer) UNIT_TEST(SerDes_Rating) { - auto const expectedRating = GetTestRating(); + auto expectedRating = GetTestRating(); TEST_EQUAL(expectedRating, expectedRating, ()); HeaderV0 header; @@ -46,14 +47,16 @@ UNIT_TEST(SerDes_Rating) { auto sink = MakeSink(buffer); - Ser(sink, header)(expectedRating); + Ser ser(sink, header); + ser(expectedRating); } Rating actualRating({} /* ratings */, {} /* aggValue */); { auto source = MakeSource(buffer); - Des(source, header)(actualRating); + Des des(source, header); + des(actualRating); } TEST_EQUAL(expectedRating, actualRating, ()); @@ -61,7 +64,7 @@ UNIT_TEST(SerDes_Rating) UNIT_TEST(SerDes_UGC) { - auto const expectedUGC = Api::MakeTestUGC1(); + auto expectedUGC = Api::MakeTestUGC1(); TEST_EQUAL(expectedUGC, expectedUGC, ()); HeaderV0 header; @@ -70,13 +73,15 @@ UNIT_TEST(SerDes_UGC) { auto sink = MakeSink(buffer); - Ser(sink, header)(expectedUGC); + Ser ser(sink, header); + ser(expectedUGC); } UGC actualUGC({} /* rating */, {} /* reviews */, {} /* attributes */); { auto source = MakeSource(buffer); - Des(source, header)(actualUGC); + Des des(source, header); + des(actualUGC); } TEST_EQUAL(expectedUGC, actualUGC, ()); |