From 22c226af3f5570514d3d13d82a399577ecd7d280 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 27 Mar 2018 11:50:03 -0400 Subject: C++ migration: make Timestamp class a part of public API (#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. --- .../core/src/firebase/firestore/CMakeLists.txt | 8 ++ .../src/firebase/firestore/model/CMakeLists.txt | 2 - .../src/firebase/firestore/model/field_value.h | 2 +- .../firebase/firestore/model/snapshot_version.h | 2 +- .../core/src/firebase/firestore/model/timestamp.cc | 54 ---------- .../core/src/firebase/firestore/model/timestamp.h | 94 ----------------- Firestore/core/src/firebase/firestore/timestamp.cc | 117 +++++++++++++++++++++ 7 files changed, 127 insertions(+), 152 deletions(-) delete mode 100644 Firestore/core/src/firebase/firestore/model/timestamp.cc delete mode 100644 Firestore/core/src/firebase/firestore/model/timestamp.h create mode 100644 Firestore/core/src/firebase/firestore/timestamp.cc (limited to 'Firestore/core/src/firebase') diff --git a/Firestore/core/src/firebase/firestore/CMakeLists.txt b/Firestore/core/src/firebase/firestore/CMakeLists.txt index 3f5522c..aad2ebb 100644 --- a/Firestore/core/src/firebase/firestore/CMakeLists.txt +++ b/Firestore/core/src/firebase/firestore/CMakeLists.txt @@ -17,6 +17,14 @@ cc_library( firebase_firestore_types SOURCES geo_point.cc + timestamp.cc DEPENDS firebase_firestore_util ) + +# Include the folder with public headers. +target_include_directories( + firebase_firestore_types + PUBLIC + ${PROJECT_SOURCE_DIR}/core/include +) diff --git a/Firestore/core/src/firebase/firestore/model/CMakeLists.txt b/Firestore/core/src/firebase/firestore/model/CMakeLists.txt index e7824e3..78f5cd6 100644 --- a/Firestore/core/src/firebase/firestore/model/CMakeLists.txt +++ b/Firestore/core/src/firebase/firestore/model/CMakeLists.txt @@ -34,8 +34,6 @@ cc_library( resource_path.h snapshot_version.cc snapshot_version.h - timestamp.cc - timestamp.h types.h DEPENDS absl_strings diff --git a/Firestore/core/src/firebase/firestore/model/field_value.h b/Firestore/core/src/firebase/firestore/model/field_value.h index fc8619d..9111ffb 100644 --- a/Firestore/core/src/firebase/firestore/model/field_value.h +++ b/Firestore/core/src/firebase/firestore/model/field_value.h @@ -25,9 +25,9 @@ #include #include "Firestore/core/include/firebase/firestore/geo_point.h" +#include "Firestore/core/include/firebase/firestore/timestamp.h" #include "Firestore/core/src/firebase/firestore/model/database_id.h" #include "Firestore/core/src/firebase/firestore/model/document_key.h" -#include "Firestore/core/src/firebase/firestore/model/timestamp.h" #include "Firestore/core/src/firebase/firestore/util/firebase_assert.h" namespace firebase { diff --git a/Firestore/core/src/firebase/firestore/model/snapshot_version.h b/Firestore/core/src/firebase/firestore/model/snapshot_version.h index 70f6f4a..56e8c50 100644 --- a/Firestore/core/src/firebase/firestore/model/snapshot_version.h +++ b/Firestore/core/src/firebase/firestore/model/snapshot_version.h @@ -17,7 +17,7 @@ #ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_SNAPSHOT_VERSION_H_ #define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_MODEL_SNAPSHOT_VERSION_H_ -#include "Firestore/core/src/firebase/firestore/model/timestamp.h" +#include "Firestore/core/include/firebase/firestore/timestamp.h" namespace firebase { namespace firestore { diff --git a/Firestore/core/src/firebase/firestore/model/timestamp.cc b/Firestore/core/src/firebase/firestore/model/timestamp.cc deleted file mode 100644 index b3d1597..0000000 --- a/Firestore/core/src/firebase/firestore/model/timestamp.cc +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 - -#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h" - -namespace firebase { -namespace firestore { -namespace model { - -Timestamp::Timestamp(int64_t seconds, int32_t 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 deleted file mode 100644 index dd0349c..0000000 --- a/Firestore/core/src/firebase/firestore/model/timestamp.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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 - -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(int64_t seconds, int32_t nanos); - - /** Returns a timestamp with the current date / time. */ - static Timestamp Now(); - - int64_t seconds() const { - return seconds_; - } - - int32_t nanos() const { - return nanos_; - } - - private: - int64_t seconds_; - int32_t 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_TIMESTAMP_H_ diff --git a/Firestore/core/src/firebase/firestore/timestamp.cc b/Firestore/core/src/firebase/firestore/timestamp.cc new file mode 100644 index 0000000..7d947c5 --- /dev/null +++ b/Firestore/core/src/firebase/firestore/timestamp.cc @@ -0,0 +1,117 @@ +/* + * 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/timestamp.h" + +#include "Firestore/core/src/firebase/firestore/util/firebase_assert.h" + +namespace firebase { + +Timestamp::Timestamp() { +} + +Timestamp::Timestamp(const int64_t seconds, const int32_t nanoseconds) + : seconds_(seconds), nanoseconds_(nanoseconds) { + ValidateBounds(); +} + +Timestamp Timestamp::Now() { +#if !defined(_STLPORT_VERSION) + // Use the standard library from C++11 if possible. + return FromTimePoint(std::chrono::system_clock::now()); +#else + // If is unavailable, use clock_gettime from POSIX, which supports up + // to nanosecond resolution. Note that it's a non-standard function contained + // in . + // + // Note: it's possible to check for availability of POSIX clock_gettime using + // macros (see "Availability" at https://linux.die.net/man/3/clock_gettime). + // However, the only platform where isn't available is Android with + // STLPort standard library, where clock_gettime is known to be available. + timespec now; + clock_gettime(CLOCK_REALTIME, &now); + return Timestamp(now.tv_sec, now.tv_nsec); +#endif // !defined(_STLPORT_VERSION) +} + +Timestamp Timestamp::FromTimeT(const time_t seconds_since_unix_epoch) { + return Timestamp(seconds_since_unix_epoch, 0); +} + +#if !defined(_STLPORT_VERSION) +Timestamp Timestamp::FromTimePoint( + const std::chrono::time_point time_point) { + namespace chr = std::chrono; + const auto epoch_time = time_point.time_since_epoch(); + auto seconds = chr::duration_cast>(epoch_time); + auto nanoseconds = chr::duration_cast(epoch_time - seconds); + FIREBASE_DEV_ASSERT(nanoseconds.count() < 1 * 1000 * 1000 * 1000); + + if (nanoseconds.count() < 0) { + // Timestamp format always has a positive number of nanoseconds that is + // counting forward. For negative time, we need to transform chrono + // representation of (negative seconds s1 + negative nanoseconds ns1) to + // (negative seconds s2 + positive nanoseconds ns2). Since nanosecond part + // is always less than 1 second in our representation, instead of starting + // at s1 and going back ns1 nanoseconds, start at (s1 minus one second) and + // go *forward* ns2 = (1 second + ns1, ns1 < 0) nanoseconds. + // + // Note: if nanoseconds are negative, it must mean that seconds are + // non-positive, but the formula would still be valid, so no need to check. + seconds = seconds - chr::seconds(1); + nanoseconds = chr::seconds(1) + nanoseconds; + } + + const Timestamp result{seconds.count(), + static_cast(nanoseconds.count())}; + result.ValidateBounds(); + return result; +} + +#endif // !defined(_STLPORT_VERSION) + +std::string Timestamp::ToString() const { + return std::string("Timestamp(seconds=") + std::to_string(seconds_) + + ", nanoseconds=" + std::to_string(nanoseconds_) + ")"; +} + +void Timestamp::ValidateBounds() const { + FIREBASE_ASSERT_MESSAGE(nanoseconds_ >= 0, + "Timestamp nanoseconds out of range: %d", + nanoseconds_); + FIREBASE_ASSERT_MESSAGE(nanoseconds_ < 1e9, + "Timestamp nanoseconds out of range: %d", + nanoseconds_); + // Midnight at the beginning of 1/1/1 is the earliest timestamp Firestore + // supports. + FIREBASE_ASSERT_MESSAGE(seconds_ >= -62135596800L, + "Timestamp seconds out of range: %lld", seconds_); + // This will break in the year 10,000. + FIREBASE_ASSERT_MESSAGE(seconds_ < 253402300800L, + "Timestamp seconds out of range: %lld", seconds_); +} + +} // namespace firebase + +namespace std { +size_t hash::operator()( + const firebase::Timestamp& timestamp) const { + // Note: if sizeof(size_t) == 4, this discards high-order bits of seconds. + return 37 * static_cast(timestamp.seconds()) + + static_cast(timestamp.nanoseconds()); +} + +} // namespace std -- cgit v1.2.3