Skip to content

Commit 03c2e72

Browse files
authored
Flesh out C++ FieldValue (#2990)
* Add GeoPoint::ToString * Add FieldValue::ToString * Fix description of FIRTimestamp * ServerTimestamp's previous_value is a FieldValue * Implement FieldValue::Hash
1 parent 2b403a6 commit 03c2e72

File tree

6 files changed

+243
-35
lines changed

6 files changed

+243
-35
lines changed

Firestore/Source/API/FIRTimestamp.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ - (NSUInteger)hash {
110110
}
111111

112112
- (NSString *)description {
113-
return [NSString stringWithFormat:@"FIRTimestamp: seconds=%lld nanoseconds=%d>", self.seconds,
113+
return [NSString stringWithFormat:@"<FIRTimestamp: seconds=%lld nanoseconds=%d>", self.seconds,
114114
self.nanoseconds];
115115
}
116116

Firestore/core/include/firebase/firestore/geo_point.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
#ifndef FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_GEO_POINT_H_
1818
#define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_GEO_POINT_H_
1919

20+
#include <iosfwd>
21+
#include <string>
22+
2023
namespace firebase {
2124
namespace firestore {
2225

@@ -55,6 +58,16 @@ class GeoPoint {
5558
return longitude_;
5659
}
5760

61+
/**
62+
* Returns a string representation of this `GeoPoint` for logging/debugging
63+
* purposes.
64+
*
65+
* Note: the exact string representation is unspecified and subject to change;
66+
* don't rely on the format of the string.
67+
*/
68+
std::string ToString() const;
69+
friend std::ostream& operator<<(std::ostream& out, const GeoPoint& geo_point);
70+
5871
private:
5972
double latitude_;
6073
double longitude_;

Firestore/core/src/firebase/firestore/geo_point.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
#include "Firestore/core/include/firebase/firestore/geo_point.h"
1818

1919
#include <cmath>
20+
#include <iostream>
2021

2122
#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
23+
#include "absl/strings/str_cat.h"
2224

2325
namespace firebase {
2426
namespace firestore {
@@ -34,6 +36,15 @@ GeoPoint::GeoPoint(double latitude, double longitude)
3436
"Latitude must be in the range of [-180, 180]");
3537
}
3638

39+
std::string GeoPoint::ToString() const {
40+
return absl::StrCat("GeoPoint(latitude=", latitude_,
41+
", longitude=", longitude_, ")");
42+
}
43+
44+
std::ostream& operator<<(std::ostream& out, const GeoPoint& geo_point) {
45+
return out << geo_point.ToString();
46+
}
47+
3748
bool operator<(const GeoPoint& lhs, const GeoPoint& rhs) {
3849
if (lhs.latitude() == rhs.latitude()) {
3950
return lhs.longitude() < rhs.longitude();

Firestore/core/src/firebase/firestore/model/field_value.cc

Lines changed: 116 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include <algorithm>
2020
#include <cmath>
21+
#include <iostream>
2122
#include <memory>
2223
#include <new>
2324
#include <utility>
@@ -27,7 +28,9 @@
2728
#include "Firestore/core/src/firebase/firestore/util/comparison.h"
2829
#include "Firestore/core/src/firebase/firestore/util/hard_assert.h"
2930
#include "Firestore/core/src/firebase/firestore/util/hashing.h"
31+
#include "Firestore/core/src/firebase/firestore/util/to_string.h"
3032
#include "absl/memory/memory.h"
33+
#include "absl/strings/escaping.h"
3134

3235
namespace firebase {
3336
namespace firestore {
@@ -38,6 +41,37 @@ using Type = FieldValue::Type;
3841
using util::Compare;
3942
using util::ComparisonResult;
4043

44+
std::string ServerTimestamp::ToString() const {
45+
std::string time = local_write_time.ToString();
46+
return absl::StrCat("ServerTimestamp(local_write_time=", time, ")");
47+
}
48+
49+
std::ostream& operator<<(std::ostream& os, const ServerTimestamp& value) {
50+
return os << value.ToString();
51+
}
52+
53+
size_t ServerTimestamp::Hash() const {
54+
size_t result =
55+
util::Hash(local_write_time.seconds(), local_write_time.nanoseconds());
56+
57+
if (previous_value) {
58+
result = util::Hash(result, *previous_value);
59+
}
60+
return result;
61+
}
62+
63+
std::string ReferenceValue::ToString() const {
64+
return absl::StrCat("Reference(key=", reference.ToString(), ")");
65+
}
66+
67+
std::ostream& operator<<(std::ostream& os, const ReferenceValue& value) {
68+
return os << value.ToString();
69+
}
70+
71+
size_t ReferenceValue::Hash() const {
72+
return util::Hash(reference, *database_id);
73+
}
74+
4175
FieldValue::FieldValue(const FieldValue& value) {
4276
*this = value;
4377
}
@@ -97,8 +131,6 @@ FieldValue& FieldValue::operator=(const FieldValue& value) {
97131
std::swap(*object_value_, tmp);
98132
break;
99133
}
100-
default:
101-
HARD_FAIL("Unsupported type %s", value.type());
102134
}
103135
return *this;
104136
}
@@ -210,6 +242,14 @@ ObjectValue ObjectValue::SetChild(const std::string& child_name,
210242
return ObjectValue::FromMap(fv_.object_value_->insert(child_name, value));
211243
}
212244

245+
absl::string_view FieldValue::blob_value_as_string_view() const {
246+
const std::vector<uint8_t>& blob = blob_value();
247+
248+
// string_view accepts const char*, but treats it internally as unsigned.
249+
auto data = reinterpret_cast<const char*>(blob.data());
250+
return absl::string_view(data, blob.size());
251+
}
252+
213253
FieldValue FieldValue::Null() {
214254
return FieldValue();
215255
}
@@ -256,7 +296,7 @@ FieldValue FieldValue::FromTimestamp(const Timestamp& value) {
256296
}
257297

258298
FieldValue FieldValue::FromServerTimestamp(const Timestamp& local_write_time,
259-
const Timestamp& previous_value) {
299+
const FieldValue& previous_value) {
260300
FieldValue result;
261301
result.SwitchTo(Type::ServerTimestamp);
262302
result.server_timestamp_value_->local_write_time = local_write_time;
@@ -348,29 +388,43 @@ FieldValue FieldValue::FromMap(FieldValue::Map&& value) {
348388
return result;
349389
}
350390

391+
static size_t HashObject(const FieldValue::Map& object) {
392+
size_t result = 0;
393+
for (auto&& entry : object) {
394+
result = util::Hash(result, entry.first, entry.second);
395+
}
396+
return result;
397+
}
398+
351399
size_t FieldValue::Hash() const {
352400
switch (type()) {
353401
case FieldValue::Type::Null:
354-
HARD_FAIL("TODO(rsgowman): Implement");
355-
402+
// std::hash is not defined for nullptr_t.
403+
return util::Hash(static_cast<void*>(nullptr));
356404
case FieldValue::Type::Boolean:
357-
return util::Hash(boolean_value());
358-
405+
return util::Hash(boolean_value_);
359406
case FieldValue::Type::Integer:
407+
return util::Hash(integer_value_);
360408
case FieldValue::Type::Double:
409+
return util::DoubleBitwiseHash(double_value_);
361410
case FieldValue::Type::Timestamp:
411+
return util::Hash(timestamp_value_->seconds(),
412+
timestamp_value_->nanoseconds());
362413
case FieldValue::Type::ServerTimestamp:
363-
HARD_FAIL("TODO(rsgowman): Implement");
364-
414+
return util::Hash(*server_timestamp_value_);
365415
case FieldValue::Type::String:
366-
return util::Hash(string_value());
367-
416+
return util::Hash(*string_value_);
368417
case FieldValue::Type::Blob:
418+
return util::Hash(*blob_value_);
369419
case FieldValue::Type::Reference:
420+
return util::Hash(*reference_value_);
370421
case FieldValue::Type::GeoPoint:
422+
return util::Hash(geo_point_value_->latitude(),
423+
geo_point_value_->longitude());
371424
case FieldValue::Type::Array:
425+
return util::Hash(*array_value_);
372426
case FieldValue::Type::Object:
373-
HARD_FAIL("TODO(rsgowman): Implement");
427+
return HashObject(*object_value_);
374428
}
375429

376430
UNREACHABLE();
@@ -430,12 +484,45 @@ ComparisonResult FieldValue::CompareTo(const FieldValue& rhs) const {
430484
return CompareContainer(*array_value_, *rhs.array_value_);
431485
case Type::Object:
432486
return CompareContainer(*object_value_, *rhs.object_value_);
433-
default:
434-
HARD_FAIL("Unsupported type %s", type());
435-
// return false if assertion does not abort the program. We will say
436-
// each unsupported type takes only one value thus everything is equal.
437-
return ComparisonResult::Same;
438487
}
488+
489+
UNREACHABLE();
490+
}
491+
492+
std::string FieldValue::ToString() const {
493+
switch (tag_) {
494+
case Type::Null:
495+
return util::ToString(nullptr);
496+
case Type::Boolean:
497+
return util::ToString(boolean_value_);
498+
case Type::Integer:
499+
return util::ToString(integer_value_);
500+
case Type::Double:
501+
return util::ToString(double_value_);
502+
case Type::Timestamp:
503+
return util::ToString(*timestamp_value_);
504+
case Type::ServerTimestamp:
505+
return util::ToString(*server_timestamp_value_);
506+
case Type::String:
507+
return util::ToString(*string_value_);
508+
case Type::Blob:
509+
return absl::StrCat(
510+
"<", absl::BytesToHexString(blob_value_as_string_view()), ">");
511+
case Type::Reference:
512+
return util::ToString(*reference_value_);
513+
case Type::GeoPoint:
514+
return util::ToString(*geo_point_value_);
515+
case Type::Array:
516+
return util::ToString(*array_value_);
517+
case Type::Object:
518+
return util::ToString(*object_value_);
519+
}
520+
521+
UNREACHABLE();
522+
}
523+
524+
std::ostream& operator<<(std::ostream& os, const FieldValue& value) {
525+
return os << value.ToString();
439526
}
440527

441528
void FieldValue::SwitchTo(const Type type) {
@@ -522,6 +609,18 @@ ComparisonResult ObjectValue::CompareTo(const ObjectValue& rhs) const {
522609
return fv_.CompareTo(rhs.fv_);
523610
}
524611

612+
std::string ObjectValue::ToString() const {
613+
return fv_.ToString();
614+
}
615+
616+
std::ostream& operator<<(std::ostream& os, const ObjectValue& value) {
617+
return os << value.ToString();
618+
}
619+
620+
size_t ObjectValue::Hash() const {
621+
return fv_.Hash();
622+
}
623+
525624
} // namespace model
526625
} // namespace firestore
527626
} // namespace firebase

Firestore/core/src/firebase/firestore/model/field_value.h

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_FIELD_VALUE_H_
1919

2020
#include <cstdint>
21+
#include <iosfwd>
2122
#include <memory>
2223
#include <string>
2324
#include <utility>
@@ -40,16 +41,8 @@ namespace firebase {
4041
namespace firestore {
4142
namespace model {
4243

43-
struct ServerTimestamp {
44-
Timestamp local_write_time;
45-
absl::optional<Timestamp> previous_value;
46-
};
47-
48-
struct ReferenceValue {
49-
DocumentKey reference;
50-
// Does not own the DatabaseId instance.
51-
const DatabaseId* database_id;
52-
};
44+
struct ReferenceValue;
45+
struct ServerTimestamp;
5346

5447
/**
5548
* tagged-union class representing an immutable data value as stored in
@@ -153,6 +146,12 @@ class FieldValue : public util::Comparable<FieldValue> {
153146
return *blob_value_;
154147
}
155148

149+
/**
150+
* Returns a string_view of the blob_value(). This can be useful when using
151+
* abseil bytewise APIs that accept this type.
152+
*/
153+
absl::string_view blob_value_as_string_view() const;
154+
156155
const GeoPoint& geo_point_value() const {
157156
HARD_ASSERT(tag_ == Type::GeoPoint);
158157
return *geo_point_value_;
@@ -174,7 +173,7 @@ class FieldValue : public util::Comparable<FieldValue> {
174173
static FieldValue FromDouble(double value);
175174
static FieldValue FromTimestamp(const Timestamp& value);
176175
static FieldValue FromServerTimestamp(const Timestamp& local_write_time,
177-
const Timestamp& previous_value);
176+
const FieldValue& previous_value);
178177
static FieldValue FromServerTimestamp(const Timestamp& local_write_time);
179178
static FieldValue FromString(const char* value);
180179
static FieldValue FromString(const std::string& value);
@@ -194,6 +193,9 @@ class FieldValue : public util::Comparable<FieldValue> {
194193

195194
util::ComparisonResult CompareTo(const FieldValue& rhs) const;
196195

196+
std::string ToString() const;
197+
friend std::ostream& operator<<(std::ostream& os, const FieldValue& value);
198+
197199
private:
198200
friend class ObjectValue;
199201

@@ -277,13 +279,41 @@ class ObjectValue : public util::Comparable<ObjectValue> {
277279

278280
util::ComparisonResult CompareTo(const ObjectValue& rhs) const;
279281

282+
std::string ToString() const;
283+
friend std::ostream& operator<<(std::ostream& os, const ObjectValue& value);
284+
285+
size_t Hash() const;
286+
280287
private:
281288
ObjectValue SetChild(const std::string& child_name,
282289
const FieldValue& value) const;
283290

284291
FieldValue fv_;
285292
};
286293

294+
struct ServerTimestamp {
295+
Timestamp local_write_time;
296+
absl::optional<FieldValue> previous_value;
297+
298+
std::string ToString() const;
299+
friend std::ostream& operator<<(std::ostream& os,
300+
const ServerTimestamp& value);
301+
302+
size_t Hash() const;
303+
};
304+
305+
struct ReferenceValue {
306+
DocumentKey reference;
307+
// Does not own the DatabaseId instance.
308+
const DatabaseId* database_id = nullptr;
309+
310+
std::string ToString() const;
311+
friend std::ostream& operator<<(std::ostream& os,
312+
const ReferenceValue& value);
313+
314+
size_t Hash() const;
315+
};
316+
287317
} // namespace model
288318
} // namespace firestore
289319
} // namespace firebase

0 commit comments

Comments
 (0)