From bfa0e40795ba676fd02d616794cce1c9b2d6a95f Mon Sep 17 00:00:00 2001 From: zxu Date: Thu, 25 Jan 2018 09:14:19 -0500 Subject: Implement the rest of FieldValue types for C++ (#687) * implement FieldValue for null and boolean. * Implement number and string FieldValue. * Implement object FieldValue. * implement timestamp FieldValue. * Implement number and string FieldValue. * implement public type `Blob` and `GeoPoint` * implement Blob FieldValue * Implement GeoPoint FieldValue * refactoring `Blob` --- .../src/firebase/firestore/model/field_value.cc | 209 +++++++++++++++++++++ 1 file changed, 209 insertions(+) (limited to 'Firestore/core/src/firebase/firestore/model/field_value.cc') diff --git a/Firestore/core/src/firebase/firestore/model/field_value.cc b/Firestore/core/src/firebase/firestore/model/field_value.cc index 5583afc..b063543 100644 --- a/Firestore/core/src/firebase/firestore/model/field_value.cc +++ b/Firestore/core/src/firebase/firestore/model/field_value.cc @@ -16,6 +16,8 @@ #include "Firestore/core/src/firebase/firestore/model/field_value.h" +#include + #include #include #include @@ -31,6 +33,7 @@ namespace firestore { namespace model { using Type = FieldValue::Type; +using firebase::firestore::util::ComparisonResult; namespace { /** @@ -75,12 +78,42 @@ FieldValue& FieldValue::operator=(const FieldValue& value) { case Type::Boolean: boolean_value_ = value.boolean_value_; break; + case Type::Long: + integer_value_ = value.integer_value_; + break; + case Type::Double: + double_value_ = value.double_value_; + break; + case Type::Timestamp: + timestamp_value_ = value.timestamp_value_; + break; + case Type::ServerTimestamp: + server_timestamp_value_ = value.server_timestamp_value_; + break; + case Type::String: + string_value_ = value.string_value_; + break; + case Type::Blob: { + // copy-and-swap + std::vector tmp = value.blob_value_; + std::swap(blob_value_, tmp); + break; + } + case Type::GeoPoint: + geo_point_value_ = value.geo_point_value_; + break; case Type::Array: { // copy-and-swap std::vector tmp = value.array_value_; std::swap(array_value_, tmp); break; } + case Type::Object: { + // copy-and-swap + std::map tmp = value.object_value_; + std::swap(object_value_, tmp); + break; + } default: FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION( false, lhs.type(), "Unsupported type %d", value.type()); @@ -90,10 +123,22 @@ FieldValue& FieldValue::operator=(const FieldValue& value) { FieldValue& FieldValue::operator=(FieldValue&& value) { switch (value.tag_) { + case Type::String: + SwitchTo(Type::String); + string_value_.swap(value.string_value_); + return *this; + case Type::Blob: + SwitchTo(Type::Blob); + std::swap(blob_value_, value.blob_value_); + return *this; case Type::Array: SwitchTo(Type::Array); std::swap(array_value_, value.array_value_); return *this; + case Type::Object: + SwitchTo(Type::Object); + std::swap(object_value_, value.object_value_); + return *this; default: // We just copy over POD union types. return *this = value; @@ -119,6 +164,82 @@ const FieldValue& FieldValue::BooleanValue(bool value) { return value ? TrueValue() : FalseValue(); } +const FieldValue& FieldValue::NanValue() { + static const FieldValue kNanInstance = FieldValue::DoubleValue(NAN); + return kNanInstance; +} + +FieldValue FieldValue::IntegerValue(int64_t value) { + FieldValue result; + result.SwitchTo(Type::Long); + result.integer_value_ = value; + return result; +} + +FieldValue FieldValue::DoubleValue(double value) { + FieldValue result; + result.SwitchTo(Type::Double); + result.double_value_ = value; + return result; +} + +FieldValue FieldValue::TimestampValue(const Timestamp& value) { + FieldValue result; + result.SwitchTo(Type::Timestamp); + result.timestamp_value_ = value; + return result; +} + +FieldValue FieldValue::ServerTimestampValue(const Timestamp& local_write_time, + const Timestamp& previous_value) { + FieldValue result; + result.SwitchTo(Type::ServerTimestamp); + result.server_timestamp_value_.local_write_time = local_write_time; + result.server_timestamp_value_.previous_value = previous_value; + result.server_timestamp_value_.has_previous_value_ = true; + return result; +} + +FieldValue FieldValue::ServerTimestampValue(const Timestamp& local_write_time) { + FieldValue result; + result.SwitchTo(Type::ServerTimestamp); + result.server_timestamp_value_.local_write_time = local_write_time; + result.server_timestamp_value_.has_previous_value_ = false; + return result; +} + +FieldValue FieldValue::StringValue(const char* value) { + std::string copy(value); + return StringValue(std::move(copy)); +} + +FieldValue FieldValue::StringValue(const std::string& value) { + std::string copy(value); + return StringValue(std::move(copy)); +} + +FieldValue FieldValue::StringValue(std::string&& value) { + FieldValue result; + result.SwitchTo(Type::String); + result.string_value_.swap(value); + return result; +} + +FieldValue FieldValue::BlobValue(const uint8_t* source, size_t size) { + FieldValue result; + result.SwitchTo(Type::Blob); + std::vector copy(source, source + size); + std::swap(result.blob_value_, copy); + return result; +} + +FieldValue FieldValue::GeoPointValue(const GeoPoint& value) { + FieldValue result; + result.SwitchTo(Type::GeoPoint); + result.geo_point_value_ = value; + return result; +} + FieldValue FieldValue::ArrayValue(const std::vector& value) { std::vector copy(value); return ArrayValue(std::move(copy)); @@ -131,6 +252,20 @@ FieldValue FieldValue::ArrayValue(std::vector&& value) { return result; } +FieldValue FieldValue::ObjectValue( + const std::map& value) { + std::map copy(value); + return ObjectValue(std::move(copy)); +} + +FieldValue FieldValue::ObjectValue( + std::map&& value) { + FieldValue result; + result.SwitchTo(Type::Object); + std::swap(result.object_value_, value); + return result; +} + bool operator<(const FieldValue& lhs, const FieldValue& rhs) { if (!Comparable(lhs.type(), rhs.type())) { return lhs.type() < rhs.type(); @@ -141,8 +276,45 @@ bool operator<(const FieldValue& lhs, const FieldValue& rhs) { return false; case Type::Boolean: return Comparator()(lhs.boolean_value_, rhs.boolean_value_); + case Type::Long: + if (rhs.type() == Type::Long) { + return Comparator()(lhs.integer_value_, rhs.integer_value_); + } else { + return util::CompareMixedNumber(rhs.double_value_, + lhs.integer_value_) == + ComparisonResult::Descending; + } + case Type::Double: + if (rhs.type() == Type::Double) { + return Comparator()(lhs.double_value_, rhs.double_value_); + } else { + return util::CompareMixedNumber(lhs.double_value_, + rhs.integer_value_) == + ComparisonResult::Ascending; + } + case Type::Timestamp: + if (rhs.type() == Type::Timestamp) { + return lhs.timestamp_value_ < rhs.timestamp_value_; + } else { + return true; + } + case Type::ServerTimestamp: + if (rhs.type() == Type::ServerTimestamp) { + return lhs.server_timestamp_value_.local_write_time < + rhs.server_timestamp_value_.local_write_time; + } else { + return false; + } + case Type::String: + return lhs.string_value_.compare(rhs.string_value_) < 0; + case Type::Blob: + return lhs.blob_value_ < rhs.blob_value_; + case Type::GeoPoint: + return lhs.geo_point_value_ < rhs.geo_point_value_; case Type::Array: return lhs.array_value_ < rhs.array_value_; + case Type::Object: + return lhs.object_value_ < rhs.object_value_; default: FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION( false, lhs.type(), "Unsupported type %d", lhs.type()); @@ -159,17 +331,54 @@ void FieldValue::SwitchTo(const Type type) { // Not same type. Destruct old type first and then initialize new type. // Must call destructor explicitly for any non-POD type. switch (tag_) { + case Type::Timestamp: + timestamp_value_.~Timestamp(); + break; + case Type::ServerTimestamp: + server_timestamp_value_.~ServerTimestamp(); + break; + case Type::String: + string_value_.~basic_string(); + break; + case Type::Blob: + blob_value_.~vector(); + break; + case Type::GeoPoint: + geo_point_value_.~GeoPoint(); + break; case Type::Array: array_value_.~vector(); break; + case Type::Object: + object_value_.~map(); + break; default: {} // The other types where there is nothing to worry about. } tag_ = type; // Must call constructor explicitly for any non-POD type to initialize. switch (tag_) { + case Type::Timestamp: + new (×tamp_value_) Timestamp(0, 0); + break; + case Type::ServerTimestamp: + new (&server_timestamp_value_) ServerTimestamp(); + break; + case Type::String: + new (&string_value_) std::string(); + break; + case Type::Blob: + // Do not even bother to allocate a new array of size 0. + new (&blob_value_) std::vector(); + break; + case Type::GeoPoint: + new (&geo_point_value_) GeoPoint(); + break; case Type::Array: new (&array_value_) std::vector(); break; + case Type::Object: + new (&object_value_) std::map(); + break; default: {} // The other types where there is nothing to worry about. } } -- cgit v1.2.3