Skip to content

Commit 22c226a

Browse files
authored
C++ migration: make Timestamp class a part of public API (firebase#944)
* move Timestamp from model/ to the root directory; * move Timestamp to top-level firebase namespace and update all references; * add conversions to and from native date types; * add a specialization of std::hash; * add comments to public member functions; * rename nanos -> nanoseconds; * add public headers, including Timestamp, to CMake; * increase test coverage.
1 parent 13aa616 commit 22c226a

File tree

15 files changed

+650
-206
lines changed

15 files changed

+650
-206
lines changed

Firestore/Example/Firestore.xcodeproj/project.pbxproj

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@
384384
ABA495B9202B7E79008A7851 /* snapshot_version_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = snapshot_version_test.cc; sourceTree = "<group>"; };
385385
ABC1D7DF2023A3EF00BA84F0 /* token_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = token_test.cc; sourceTree = "<group>"; };
386386
ABC1D7E22023CDC500BA84F0 /* firebase_credentials_provider_test.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = firebase_credentials_provider_test.mm; sourceTree = "<group>"; };
387-
ABF6506B201131F8005F2C74 /* timestamp_test.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = timestamp_test.cc; sourceTree = "<group>"; };
387+
ABF6506B201131F8005F2C74 /* timestamp_test.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = timestamp_test.cc; path = ../../core/test/firebase/firestore/timestamp_test.cc; sourceTree = "<group>"; };
388388
B2FA635DF5D116A67A7441CD /* Pods_Firestore_IntegrationTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Firestore_IntegrationTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
389389
B6152AD5202A5385000E5744 /* document_key_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = document_key_test.cc; sourceTree = "<group>"; };
390390
B65D34A7203C99090076A5E1 /* FIRTimestampTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FIRTimestampTest.m; sourceTree = "<group>"; };
@@ -504,6 +504,7 @@
504504
54740A561FC913EB00713A1A /* util */,
505505
54764FAE1FAA21B90085E60A /* FSTGoogleTestTests.mm */,
506506
AB7BAB332012B519001E0872 /* geo_point_test.cc */,
507+
ABF6506B201131F8005F2C74 /* timestamp_test.cc */,
507508
);
508509
name = GoogleTests;
509510
sourceTree = "<group>";
@@ -554,8 +555,6 @@
554555
6003F58C195388D20070C39A /* Frameworks */,
555556
6003F58B195388D20070C39A /* Products */,
556557
A47A1BF74A48BCAEAFBCBF1E /* Pods */,
557-
132E3B6B902D5CBD779D901A,
558-
132E37F450D23EF90B2352D9,
559558
);
560559
sourceTree = "<group>";
561560
};
@@ -679,7 +678,6 @@
679678
AB6B908520322E6D00CC290A /* maybe_document_test.cc */,
680679
AB6B908720322E8800CC290A /* no_document_test.cc */,
681680
ABA495B9202B7E79008A7851 /* snapshot_version_test.cc */,
682-
ABF6506B201131F8005F2C74 /* timestamp_test.cc */,
683681
);
684682
name = model;
685683
path = ../../core/test/firebase/firestore/model;

Firestore/core/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
add_subdirectory(include/firebase/firestore)
16+
1517
add_subdirectory(src/firebase/firestore)
1618
add_subdirectory(src/firebase/firestore/auth)
1719
add_subdirectory(src/firebase/firestore/core)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Copyright 2018 Google
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# Hack to make the headers show up in IDEs
16+
# (see https://stackoverflow.com/questions/27039019/ and open issue on CMake
17+
# issue tracker: https://gitlab.kitware.com/cmake/cmake/issues/15234)
18+
add_custom_target(firebase_firestore_types_ide SOURCES
19+
document_reference.h
20+
event_listener.h
21+
firestore.h
22+
firestore_errors.h
23+
geo_point.h
24+
timestamp.h
25+
)
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
/*
2+
* Copyright 2018 Google
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_TIMESTAMP_H_
18+
#define FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_TIMESTAMP_H_
19+
20+
#include <stdint.h>
21+
#include <time.h>
22+
#if !defined(_STLPORT_VERSION)
23+
#include <chrono> // NOLINT(build/c++11)
24+
#endif // !defined(_STLPORT_VERSION)
25+
#include <limits>
26+
#include <string>
27+
28+
namespace firebase {
29+
30+
/**
31+
* A Timestamp represents a point in time independent of any time zone or
32+
* calendar, represented as seconds and fractions of seconds at nanosecond
33+
* resolution in UTC Epoch time. It is encoded using the Proleptic Gregorian
34+
* Calendar which extends the Gregorian calendar backwards to year one. It is
35+
* encoded assuming all minutes are 60 seconds long, i.e. leap seconds are
36+
* "smeared" so that no leap second table is needed for interpretation. Range is
37+
* from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z.
38+
*
39+
* @see
40+
* https://github.com/google/protobuf/blob/master/src/google/protobuf/timestamp.proto
41+
*/
42+
class Timestamp {
43+
public:
44+
/**
45+
* Creates a new timestamp representing the epoch (with seconds and
46+
* nanoseconds set to 0).
47+
*/
48+
Timestamp();
49+
50+
/**
51+
* Creates a new timestamp.
52+
*
53+
* @param seconds The number of seconds of UTC time since Unix epoch
54+
* 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
55+
* 9999-12-31T23:59:59Z inclusive; otherwise, assertion failure will be
56+
* triggered.
57+
* @param nanoseconds The non-negative fractions of a second at nanosecond
58+
* resolution. Negative second values with fractions must still have
59+
* non-negative nanoseconds values that count forward in time. Must be
60+
* from 0 to 999,999,999 inclusive; otherwise, assertion failure will be
61+
* triggered.
62+
*/
63+
Timestamp(int64_t seconds, int32_t nanoseconds);
64+
65+
/**
66+
* Creates a new timestamp with the current date.
67+
*
68+
* The precision is up to nanoseconds, depending on the system clock.
69+
*
70+
* @return a new timestamp representing the current date.
71+
*/
72+
static Timestamp Now();
73+
74+
/**
75+
* The number of seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z.
76+
*/
77+
int64_t seconds() const {
78+
return seconds_;
79+
}
80+
81+
/**
82+
* The non-negative fractions of a second at nanosecond resolution. Negative
83+
* second values with fractions still have non-negative nanoseconds values
84+
* that count forward in time.
85+
*/
86+
int32_t nanoseconds() const {
87+
return nanoseconds_;
88+
}
89+
90+
/**
91+
* Converts `time_t` to a `Timestamp`.
92+
*
93+
* @param seconds_since_unix_epoch
94+
* @parblock
95+
* The number of seconds of UTC time since Unix epoch
96+
* 1970-01-01T00:00:00Z. Can be negative to represent dates before the
97+
* epoch. Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z
98+
* inclusive; otherwise, assertion failure will be triggered.
99+
*
100+
* Note that while the epoch of `time_t` is unspecified, it's usually Unix
101+
* epoch. If this assumption is broken, this function will produce
102+
* incorrect results.
103+
* @endparblock
104+
*
105+
* @return a new timestamp with the given number of seconds and zero
106+
* nanoseconds.
107+
*/
108+
static Timestamp FromTimeT(time_t seconds_since_unix_epoch);
109+
110+
#if !defined(_STLPORT_VERSION)
111+
/**
112+
* Converts `std::chrono::time_point` to a `Timestamp`.
113+
*
114+
* @param time_point
115+
* @parblock
116+
* The time point with system clock's epoch, which is
117+
* presumed to be Unix epoch 1970-01-01T00:00:00Z. Can be negative to
118+
* represent dates before the epoch. Must be from 0001-01-01T00:00:00Z to
119+
* 9999-12-31T23:59:59Z inclusive; otherwise, assertion failure will be
120+
* triggered.
121+
*
122+
* Note that while the epoch of `std::chrono::system_clock` is
123+
* unspecified, it's usually Unix epoch. If this assumption is broken,
124+
* this constructor will produce incorrect results.
125+
* @endparblock
126+
*/
127+
static Timestamp FromTimePoint(
128+
std::chrono::time_point<std::chrono::system_clock> time_point);
129+
130+
/**
131+
* Converts this `Timestamp` to a `time_point`.
132+
*
133+
* Important: if overflow would occur, the returned value will be the maximum
134+
* or minimum value that `Duration` can hold. Note in particular that `long
135+
* long` is insufficient to hold the full range of `Timestamp` values with
136+
* nanosecond precision (which is why `Duration` defaults to `microseconds`).
137+
*/
138+
template <typename Clock = std::chrono::system_clock,
139+
typename Duration = std::chrono::microseconds>
140+
std::chrono::time_point<Clock, Duration> ToTimePoint() const;
141+
#endif // !defined(_STLPORT_VERSION)
142+
143+
/**
144+
* Returns a string representation of this `Timestamp` for logging/debugging
145+
* purposes.
146+
*
147+
* Note: the exact string representation is unspecified and subject to change;
148+
* don't rely on the format of the string.
149+
*/
150+
std::string ToString() const;
151+
152+
private:
153+
// Checks that the number of seconds is within the supported date range, and
154+
// that nanoseconds satisfy 0 <= ns <= 1second.
155+
void ValidateBounds() const;
156+
157+
int64_t seconds_ = 0;
158+
int32_t nanoseconds_ = 0;
159+
};
160+
161+
inline bool operator<(const Timestamp& lhs, const Timestamp& rhs) {
162+
return lhs.seconds() < rhs.seconds() ||
163+
(lhs.seconds() == rhs.seconds() &&
164+
lhs.nanoseconds() < rhs.nanoseconds());
165+
}
166+
167+
inline bool operator>(const Timestamp& lhs, const Timestamp& rhs) {
168+
return rhs < lhs;
169+
}
170+
171+
inline bool operator>=(const Timestamp& lhs, const Timestamp& rhs) {
172+
return !(lhs < rhs);
173+
}
174+
175+
inline bool operator<=(const Timestamp& lhs, const Timestamp& rhs) {
176+
return !(lhs > rhs);
177+
}
178+
179+
inline bool operator!=(const Timestamp& lhs, const Timestamp& rhs) {
180+
return lhs < rhs || lhs > rhs;
181+
}
182+
183+
inline bool operator==(const Timestamp& lhs, const Timestamp& rhs) {
184+
return !(lhs != rhs);
185+
}
186+
187+
#if !defined(_STLPORT_VERSION)
188+
template <typename Clock, typename Duration>
189+
std::chrono::time_point<Clock, Duration> Timestamp::ToTimePoint() const {
190+
namespace chr = std::chrono;
191+
using TimePoint = chr::time_point<Clock, Duration>;
192+
193+
// Saturate on overflow
194+
const auto max_value = std::numeric_limits<typename Duration::rep>::max();
195+
if (seconds_ > 0 && max_value / Duration::period::den <= seconds_) {
196+
return TimePoint{Duration(max_value)};
197+
}
198+
const auto min_value = std::numeric_limits<typename Duration::rep>::min();
199+
if (seconds_ < 0 && min_value / Duration::period::den >= seconds_) {
200+
return TimePoint{Duration(min_value)};
201+
}
202+
203+
const auto seconds = chr::duration_cast<Duration>(chr::seconds(seconds_));
204+
const auto nanoseconds =
205+
chr::duration_cast<Duration>(chr::nanoseconds(nanoseconds_));
206+
return TimePoint{seconds + nanoseconds};
207+
}
208+
#endif // !defined(_STLPORT_VERSION)
209+
210+
} // namespace firebase
211+
212+
namespace std {
213+
template <>
214+
struct hash<firebase::Timestamp> {
215+
// Note: specialization of `std::hash` is provided for convenience only. The
216+
// implementation is subject to change.
217+
size_t operator()(const firebase::Timestamp& timestamp) const;
218+
};
219+
} // namespace std
220+
221+
#endif // FIRESTORE_CORE_INCLUDE_FIREBASE_FIRESTORE_TIMESTAMP_H_

Firestore/core/src/firebase/firestore/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ cc_library(
1717
firebase_firestore_types
1818
SOURCES
1919
geo_point.cc
20+
timestamp.cc
2021
DEPENDS
2122
firebase_firestore_util
2223
)
24+
25+
# Include the folder with public headers.
26+
target_include_directories(
27+
firebase_firestore_types
28+
PUBLIC
29+
${PROJECT_SOURCE_DIR}/core/include
30+
)

Firestore/core/src/firebase/firestore/model/CMakeLists.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ cc_library(
3434
resource_path.h
3535
snapshot_version.cc
3636
snapshot_version.h
37-
timestamp.cc
38-
timestamp.h
3937
types.h
4038
DEPENDS
4139
absl_strings

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@
2525
#include <vector>
2626

2727
#include "Firestore/core/include/firebase/firestore/geo_point.h"
28+
#include "Firestore/core/include/firebase/firestore/timestamp.h"
2829
#include "Firestore/core/src/firebase/firestore/model/database_id.h"
2930
#include "Firestore/core/src/firebase/firestore/model/document_key.h"
30-
#include "Firestore/core/src/firebase/firestore/model/timestamp.h"
3131
#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h"
3232

3333
namespace firebase {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_SNAPSHOT_VERSION_H_
1818
#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_SNAPSHOT_VERSION_H_
1919

20-
#include "Firestore/core/src/firebase/firestore/model/timestamp.h"
20+
#include "Firestore/core/include/firebase/firestore/timestamp.h"
2121

2222
namespace firebase {
2323
namespace firestore {

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

Lines changed: 0 additions & 54 deletions
This file was deleted.

0 commit comments

Comments
 (0)