aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore/core/src
diff options
context:
space:
mode:
authorGravatar zxu <zxu@google.com>2018-01-25 09:14:19 -0500
committerGravatar GitHub <noreply@github.com>2018-01-25 09:14:19 -0500
commitbfa0e40795ba676fd02d616794cce1c9b2d6a95f (patch)
tree875e86ca1282c275a7f4ad68d03dbc0a2fb22b45 /Firestore/core/src
parent1f772120365641eb66f0cc9db9975721c8285d6e (diff)
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`
Diffstat (limited to 'Firestore/core/src')
-rw-r--r--Firestore/core/src/firebase/firestore/CMakeLists.txt22
-rw-r--r--Firestore/core/src/firebase/firestore/geo_point.cc50
-rw-r--r--Firestore/core/src/firebase/firestore/model/CMakeLists.txt2
-rw-r--r--Firestore/core/src/firebase/firestore/model/field_value.cc209
-rw-r--r--Firestore/core/src/firebase/firestore/model/field_value.h39
-rw-r--r--Firestore/core/src/firebase/firestore/model/timestamp.cc54
-rw-r--r--Firestore/core/src/firebase/firestore/model/timestamp.h94
7 files changed, 470 insertions, 0 deletions
diff --git a/Firestore/core/src/firebase/firestore/CMakeLists.txt b/Firestore/core/src/firebase/firestore/CMakeLists.txt
new file mode 100644
index 0000000..3f5522c
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/CMakeLists.txt
@@ -0,0 +1,22 @@
+# Copyright 2018 Google
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Public types to be used both internally and externally.
+cc_library(
+ firebase_firestore_types
+ SOURCES
+ geo_point.cc
+ DEPENDS
+ firebase_firestore_util
+)
diff --git a/Firestore/core/src/firebase/firestore/geo_point.cc b/Firestore/core/src/firebase/firestore/geo_point.cc
new file mode 100644
index 0000000..fb01023
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/geo_point.cc
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Firestore/core/include/firebase/firestore/geo_point.h"
+
+#include <math.h>
+
+#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+
+namespace firebase {
+namespace firestore {
+
+GeoPoint::GeoPoint() : GeoPoint(0, 0) {
+}
+
+GeoPoint::GeoPoint(double latitude, double longitude)
+ : latitude_(latitude), longitude_(longitude) {
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(
+ !isnan(latitude) && -90 <= latitude && latitude <= 90,
+ -90 <= latitude && latitude <= 90,
+ "Latitude must be in the range of [-90, 90]");
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(
+ !isnan(longitude) && -180 <= longitude && longitude <= 180,
+ -180 <= longitude && longitude <= 180,
+ "Latitude must be in the range of [-180, 180]");
+}
+
+bool operator<(const GeoPoint& lhs, const GeoPoint& rhs) {
+ if (lhs.latitude() == rhs.latitude()) {
+ return lhs.longitude() < rhs.longitude();
+ } else {
+ return lhs.latitude() < rhs.latitude();
+ }
+}
+
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/model/CMakeLists.txt b/Firestore/core/src/firebase/firestore/model/CMakeLists.txt
index ae80de3..3af56ec 100644
--- a/Firestore/core/src/firebase/firestore/model/CMakeLists.txt
+++ b/Firestore/core/src/firebase/firestore/model/CMakeLists.txt
@@ -16,6 +16,8 @@ cc_library(
firebase_firestore_model
SOURCES
field_value.cc
+ timestamp.cc
DEPENDS
firebase_firestore_util
+ firebase_firestore_types
)
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 <math.h>
+
#include <algorithm>
#include <memory>
#include <utility>
@@ -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<const uint8_t> 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<const FieldValue> tmp = value.array_value_;
std::swap(array_value_, tmp);
break;
}
+ case Type::Object: {
+ // copy-and-swap
+ std::map<const std::string, const FieldValue> 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<const uint8_t> 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<const FieldValue>& value) {
std::vector<const FieldValue> copy(value);
return ArrayValue(std::move(copy));
@@ -131,6 +252,20 @@ FieldValue FieldValue::ArrayValue(std::vector<const FieldValue>&& value) {
return result;
}
+FieldValue FieldValue::ObjectValue(
+ const std::map<const std::string, const FieldValue>& value) {
+ std::map<const std::string, const FieldValue> copy(value);
+ return ObjectValue(std::move(copy));
+}
+
+FieldValue FieldValue::ObjectValue(
+ std::map<const std::string, const FieldValue>&& 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<bool>()(lhs.boolean_value_, rhs.boolean_value_);
+ case Type::Long:
+ if (rhs.type() == Type::Long) {
+ return Comparator<int64_t>()(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<double>()(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 (&timestamp_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<const uint8_t>();
+ break;
+ case Type::GeoPoint:
+ new (&geo_point_value_) GeoPoint();
+ break;
case Type::Array:
new (&array_value_) std::vector<const FieldValue>();
break;
+ case Type::Object:
+ new (&object_value_) std::map<const std::string, const FieldValue>();
+ break;
default: {} // The other types where there is nothing to worry about.
}
}
diff --git a/Firestore/core/src/firebase/firestore/model/field_value.h b/Firestore/core/src/firebase/firestore/model/field_value.h
index 781e34f..bb6594f 100644
--- a/Firestore/core/src/firebase/firestore/model/field_value.h
+++ b/Firestore/core/src/firebase/firestore/model/field_value.h
@@ -17,13 +17,27 @@
#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_VALUE_H_
#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_VALUE_H_
+#include <stdint.h>
+
+#include <map>
#include <memory>
+#include <string>
#include <vector>
+#include "Firestore/core/include/firebase/firestore/geo_point.h"
+#include "Firestore/core/src/firebase/firestore/model/timestamp.h"
+
namespace firebase {
namespace firestore {
namespace model {
+struct ServerTimestamp {
+ Timestamp local_write_time;
+ Timestamp previous_value;
+ // TODO(zxu123): adopt absl::optional once abseil is ported.
+ bool has_previous_value_;
+};
+
/**
* tagged-union class representing an immutable data value as stored in
* Firestore. FieldValue represents all the different kinds of values
@@ -78,8 +92,25 @@ class FieldValue {
static const FieldValue& TrueValue();
static const FieldValue& FalseValue();
static const FieldValue& BooleanValue(bool value);
+ static const FieldValue& NanValue();
+ static FieldValue IntegerValue(int64_t value);
+ static FieldValue DoubleValue(double value);
+ static FieldValue TimestampValue(const Timestamp& value);
+ static FieldValue ServerTimestampValue(const Timestamp& local_write_time,
+ const Timestamp& previous_value);
+ static FieldValue ServerTimestampValue(const Timestamp& local_write_time);
+ static FieldValue StringValue(const char* value);
+ static FieldValue StringValue(const std::string& value);
+ static FieldValue StringValue(std::string&& value);
+ static FieldValue BlobValue(const uint8_t* source, size_t size);
+ // static FieldValue ReferenceValue();
+ static FieldValue GeoPointValue(const GeoPoint& value);
static FieldValue ArrayValue(const std::vector<const FieldValue>& value);
static FieldValue ArrayValue(std::vector<const FieldValue>&& value);
+ static FieldValue ObjectValue(
+ const std::map<const std::string, const FieldValue>& value);
+ static FieldValue ObjectValue(
+ std::map<const std::string, const FieldValue>&& value);
friend bool operator<(const FieldValue& lhs, const FieldValue& rhs);
@@ -96,7 +127,15 @@ class FieldValue {
union {
// There is no null type as tag_ alone is enough for Null FieldValue.
bool boolean_value_;
+ int64_t integer_value_;
+ double double_value_;
+ Timestamp timestamp_value_;
+ ServerTimestamp server_timestamp_value_;
+ std::string string_value_;
+ std::vector<const uint8_t> blob_value_;
+ GeoPoint geo_point_value_;
std::vector<const FieldValue> array_value_;
+ std::map<const std::string, const FieldValue> object_value_;
};
};
diff --git a/Firestore/core/src/firebase/firestore/model/timestamp.cc b/Firestore/core/src/firebase/firestore/model/timestamp.cc
new file mode 100644
index 0000000..c2bb008
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/model/timestamp.cc
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Firestore/core/src/firebase/firestore/model/timestamp.h"
+
+#include <time.h>
+
+#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
+
+namespace firebase {
+namespace firestore {
+namespace model {
+
+Timestamp::Timestamp(long seconds, int nanos)
+ : seconds_(seconds), nanos_(nanos) {
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(
+ nanos >= 0, nanos >= 0, "timestamp nanoseconds out of range: %d", nanos);
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(
+ nanos < 1e9, nanos < 1e9, "timestamp nanoseconds out of range: %d",
+ nanos);
+ // Midnight at the beginning of 1/1/1 is the earliest timestamp Firestore
+ // supports.
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(
+ seconds >= -62135596800L, seconds >= -62135596800L,
+ "timestamp seconds out of range: %lld", seconds);
+ // This will break in the year 10,000.
+ FIREBASE_ASSERT_MESSAGE_WITH_EXPRESSION(
+ seconds < 253402300800L, seconds < 253402300800L,
+ "timestamp seconds out of range: %lld", seconds);
+}
+
+Timestamp::Timestamp() : seconds_(0), nanos_(0) {
+}
+
+Timestamp Timestamp::Now() {
+ return Timestamp(time(nullptr), 0);
+}
+
+} // namespace model
+} // namespace firestore
+} // namespace firebase
diff --git a/Firestore/core/src/firebase/firestore/model/timestamp.h b/Firestore/core/src/firebase/firestore/model/timestamp.h
new file mode 100644
index 0000000..3ffee48
--- /dev/null
+++ b/Firestore/core/src/firebase/firestore/model/timestamp.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_TIMESTAMP_H_
+#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_TIMESTAMP_H_
+
+#include <stdint.h>
+
+namespace firebase {
+namespace firestore {
+namespace model {
+
+/**
+ * A Timestamp represents an absolute time from the backend at up to nanosecond
+ * precision. A Timestamp is always UTC.
+ */
+class Timestamp {
+ public:
+ /**
+ * Creates a new timestamp with seconds and nanos set to 0.
+ *
+ * PORTING NOTE: This does NOT set to current timestamp by default. To get the
+ * current timestamp, call Timestamp::Now().
+ */
+ Timestamp();
+
+ /**
+ * Creates a new timestamp.
+ *
+ * @param seconds the number of seconds since epoch.
+ * @param nanos the number of nanoseconds after the seconds.
+ */
+ Timestamp(long seconds, int nanos);
+
+ /** Returns a timestamp with the current date / time. */
+ static Timestamp Now();
+
+ long seconds() const {
+ return seconds_;
+ }
+
+ int nanos() const {
+ return nanos_;
+ }
+
+ private:
+ long seconds_;
+ int nanos_;
+};
+
+/** Compares against another Timestamp. */
+inline bool operator<(const Timestamp& lhs, const Timestamp& rhs) {
+ return lhs.seconds() < rhs.seconds() ||
+ (lhs.seconds() == rhs.seconds() && lhs.nanos() < rhs.nanos());
+}
+
+inline bool operator>(const Timestamp& lhs, const Timestamp& rhs) {
+ return rhs < lhs;
+}
+
+inline bool operator>=(const Timestamp& lhs, const Timestamp& rhs) {
+ return !(lhs < rhs);
+}
+
+inline bool operator<=(const Timestamp& lhs, const Timestamp& rhs) {
+ return !(lhs > rhs);
+}
+
+inline bool operator!=(const Timestamp& lhs, const Timestamp& rhs) {
+ return lhs < rhs || lhs > rhs;
+}
+
+inline bool operator==(const Timestamp& lhs, const Timestamp& rhs) {
+ return !(lhs != rhs);
+}
+
+} // namespace model
+} // namespace firestore
+} // namespace firebase
+
+#endif // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_VALUE_H_