Export of internal Abseil changes
-- 20b3acaff75d05315f272747956b01405adccafb by Greg Falcon <gfalcon@google.com>: Re-import of CCTZ from GitHub, with new ABSL_NAMESPACE_ transform applied. PiperOrigin-RevId: 285564474 -- 4d9e3fcabcea33c8b0b69f094ad2eddc0fa19557 by Derek Mauro <dmauro@google.com>: Moves the disabling of a warning to before the function begins. MSVC apparently requires this for warnings in the range 4700-4999. https://docs.microsoft.com/en-us/cpp/preprocessor/warning?redirectedfrom=MSDN&view=vs-2019 PiperOrigin-RevId: 285516232 -- 4a060cbeda76e89693c50276ae5b62cbf0fff39a by Derek Mauro <dmauro@google.com>: MSVC: Fixes uniform_real_distribution_test in opt mode Disables a constant arithmetic overflow warning in a test that tests the behavior on overflow. This should be tested because a user might have this warning disabled. PiperOrigin-RevId: 285452242 -- 548ab2f4cbe59bd6f6bf493af4f9ea765c4fa949 by Andy Soffer <asoffer@google.com>: Release absl::bind_front, a C++11-compliant work-alike type for the C++20 std::bind_front. PiperOrigin-RevId: 285247872 GitOrigin-RevId: 20b3acaff75d05315f272747956b01405adccafb Change-Id: I00fe45939246cba9bfc7be375d67787d2eb57cd3
This commit is contained in:
parent
12bc53e031
commit
bf86cfe165
31 changed files with 1972 additions and 1421 deletions
|
@ -26,6 +26,32 @@ package(default_visibility = ["//visibility:public"])
|
|||
|
||||
licenses(["notice"]) # Apache 2.0
|
||||
|
||||
cc_library(
|
||||
name = "bind_front",
|
||||
srcs = ["internal/front_binder.h"],
|
||||
hdrs = ["bind_front.h"],
|
||||
copts = ABSL_DEFAULT_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
"//absl/base:base_internal",
|
||||
"//absl/container:compressed_tuple",
|
||||
"//absl/meta:type_traits",
|
||||
"//absl/utility",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "bind_front_test",
|
||||
srcs = ["bind_front_test.cc"],
|
||||
copts = ABSL_TEST_COPTS,
|
||||
linkopts = ABSL_DEFAULT_LINKOPTS,
|
||||
deps = [
|
||||
":bind_front",
|
||||
"//absl/memory",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "function_ref",
|
||||
srcs = ["internal/function_ref.h"],
|
||||
|
|
152
absl/functional/bind_front.h
Normal file
152
absl/functional/bind_front.h
Normal file
|
@ -0,0 +1,152 @@
|
|||
// Copyright 2018 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
// `absl::bind_front()` returns a functor by binding a number of arguments to
|
||||
// the front of a provided functor, allowing you to avoid known problems with
|
||||
// `std::bind()`. It is a form of partial function application
|
||||
// https://en.wikipedia.org/wiki/Partial_application.
|
||||
//
|
||||
// Like `std::bind()` it is implicitly convertible to `std::function`. In
|
||||
// particular, it may be used as a simpler replacement for `std::bind()` in most
|
||||
// cases, as it does not require placeholders to be specified. More
|
||||
// importantly, it provides more reliable correctness guarantees than
|
||||
// `std::bind()`.
|
||||
//
|
||||
// absl::bind_front(a...) can be seen as storing the results of
|
||||
// std::make_tuple(a...).
|
||||
//
|
||||
// Example: Binding a free function.
|
||||
//
|
||||
// int Minus(int a, int b) { return a - b; }
|
||||
//
|
||||
// assert(absl::bind_front(Minus)(3, 2) == 3 - 2);
|
||||
// assert(absl::bind_front(Minus, 3)(2) == 3 - 2);
|
||||
// assert(absl::bind_front(Minus, 3, 2)() == 3 - 2);
|
||||
//
|
||||
// Example: Binding a member function.
|
||||
//
|
||||
// struct Math {
|
||||
// int Double(int a) const { return 2 * a; }
|
||||
// };
|
||||
//
|
||||
// Math math;
|
||||
//
|
||||
// assert(absl::bind_front(&Math::Double)(&math, 3) == 2 * 3);
|
||||
// // Stores a pointer to math inside the functor.
|
||||
// assert(absl::bind_front(&Math::Double, &math)(3) == 2 * 3);
|
||||
// // Stores a copy of math inside the functor.
|
||||
// assert(absl::bind_front(&Math::Double, math)(3) == 2 * 3);
|
||||
// // Stores std::unique_ptr<Math> inside the functor.
|
||||
// assert(absl::bind_front(&Math::Double,
|
||||
// std::unique_ptr<Math>(new Math))(3) == 2 * 3);
|
||||
//
|
||||
// Example: Using `absl::bind_front()`, instead of `std::bind()`, with
|
||||
// `std::function`.
|
||||
//
|
||||
// class FileReader {
|
||||
// public:
|
||||
// void ReadFileAsync(const std::string& filename, std::string* content,
|
||||
// const std::function<void()>& done) {
|
||||
// // Calls Executor::Schedule(std::function<void()>).
|
||||
// Executor::DefaultExecutor()->Schedule(
|
||||
// absl::bind_front(&FileReader::BlockingRead, this,
|
||||
// filename, content, done));
|
||||
// }
|
||||
//
|
||||
// private:
|
||||
// void BlockingRead(const std::string& filename, std::string* content,
|
||||
// const std::function<void()>& done) {
|
||||
// CHECK_OK(file::GetContents(filename, content, {}));
|
||||
// done();
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// `absl::bind_front()` stores bound arguments explicitly using the type passed
|
||||
// rather than implicitly based on the type accepted by its functor.
|
||||
//
|
||||
// Example: Binding arguments explicitly.
|
||||
//
|
||||
// void LogStringView(absl::string_view sv) {
|
||||
// LOG(INFO) << sv;
|
||||
// }
|
||||
//
|
||||
// Executor* e = Executor::DefaultExecutor();
|
||||
// std::string s = "hello";
|
||||
// absl::string_view sv = s;
|
||||
//
|
||||
// // absl::bind_front(LogStringView, arg) makes a copy of arg and stores it.
|
||||
// e->Schedule(absl::bind_front(LogStringView, sv)); // ERROR: dangling
|
||||
// // string_view.
|
||||
//
|
||||
// e->Schedule(absl::bind_front(LogStringView, s)); // OK: stores a copy of
|
||||
// // s.
|
||||
//
|
||||
// To store some of the arguments passed to `absl::bind_front()` by reference,
|
||||
// use std::ref()` and `std::cref()`.
|
||||
//
|
||||
// Example: Storing some of the bound arguments by reference.
|
||||
//
|
||||
// class Service {
|
||||
// public:
|
||||
// void Serve(const Request& req, std::function<void()>* done) {
|
||||
// // The request protocol buffer won't be deleted until done is called.
|
||||
// // It's safe to store a reference to it inside the functor.
|
||||
// Executor::DefaultExecutor()->Schedule(
|
||||
// absl::bind_front(&Service::BlockingServe, this, std::cref(req),
|
||||
// done));
|
||||
// }
|
||||
//
|
||||
// private:
|
||||
// void BlockingServe(const Request& req, std::function<void()>* done);
|
||||
// };
|
||||
//
|
||||
// Example: Storing bound arguments by reference.
|
||||
//
|
||||
// void Print(const string& a, const string& b) { LOG(INFO) << a << b; }
|
||||
//
|
||||
// std::string hi = "Hello, ";
|
||||
// std::vector<std::string> names = {"Chuk", "Gek"};
|
||||
// // Doesn't copy hi.
|
||||
// for_each(names.begin(), names.end(),
|
||||
// absl::bind_front(Print, std::ref(hi)));
|
||||
//
|
||||
// // DO NOT DO THIS: the functor may outlive "hi", resulting in
|
||||
// // dangling references.
|
||||
// foo->DoInFuture(absl::bind_front(Print, std::ref(hi), "Guest")); // BAD!
|
||||
// auto f = absl::bind_front(Print, std::ref(hi), "Guest"); // BAD!
|
||||
|
||||
#ifndef ABSL_FUNCTIONAL_BIND_FRONT_H_
|
||||
#define ABSL_FUNCTIONAL_BIND_FRONT_H_
|
||||
|
||||
#include "absl/functional/internal/front_binder.h"
|
||||
#include "absl/utility/utility.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
// Binds the first N arguments of an invocable object and stores them by value,
|
||||
// except types of std::reference_wrapper which are 'unwound' and stored by
|
||||
// reference.
|
||||
template <class F, class... BoundArgs>
|
||||
constexpr functional_internal::bind_front_t<F, BoundArgs...> bind_front(
|
||||
F&& func, BoundArgs&&... args) {
|
||||
return functional_internal::bind_front_t<F, BoundArgs...>(
|
||||
absl::in_place, absl::forward<F>(func),
|
||||
absl::forward<BoundArgs>(args)...);
|
||||
}
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_FUNCTIONAL_BIND_FRONT_H_
|
231
absl/functional/bind_front_test.cc
Normal file
231
absl/functional/bind_front_test.cc
Normal file
|
@ -0,0 +1,231 @@
|
|||
// Copyright 2018 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 "absl/functional/bind_front.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/memory/memory.h"
|
||||
|
||||
namespace {
|
||||
|
||||
char CharAt(const char* s, size_t index) { return s[index]; }
|
||||
|
||||
TEST(BindTest, Basics) {
|
||||
EXPECT_EQ('C', absl::bind_front(CharAt)("ABC", 2));
|
||||
EXPECT_EQ('C', absl::bind_front(CharAt, "ABC")(2));
|
||||
EXPECT_EQ('C', absl::bind_front(CharAt, "ABC", 2)());
|
||||
}
|
||||
|
||||
TEST(BindTest, Lambda) {
|
||||
auto lambda = [](int x, int y, int z) { return x + y + z; };
|
||||
EXPECT_EQ(6, absl::bind_front(lambda)(1, 2, 3));
|
||||
EXPECT_EQ(6, absl::bind_front(lambda, 1)(2, 3));
|
||||
EXPECT_EQ(6, absl::bind_front(lambda, 1, 2)(3));
|
||||
EXPECT_EQ(6, absl::bind_front(lambda, 1, 2, 3)());
|
||||
}
|
||||
|
||||
struct Functor {
|
||||
std::string operator()() & { return "&"; }
|
||||
std::string operator()() const& { return "const&"; }
|
||||
std::string operator()() && { return "&&"; }
|
||||
std::string operator()() const&& { return "const&&"; }
|
||||
};
|
||||
|
||||
TEST(BindTest, PerfectForwardingOfBoundArgs) {
|
||||
auto f = absl::bind_front(Functor());
|
||||
const auto& cf = f;
|
||||
EXPECT_EQ("&", f());
|
||||
EXPECT_EQ("const&", cf());
|
||||
EXPECT_EQ("&&", std::move(f)());
|
||||
EXPECT_EQ("const&&", std::move(cf)());
|
||||
}
|
||||
|
||||
struct ArgDescribe {
|
||||
std::string operator()(int&) const { return "&"; } // NOLINT
|
||||
std::string operator()(const int&) const { return "const&"; } // NOLINT
|
||||
std::string operator()(int&&) const { return "&&"; }
|
||||
std::string operator()(const int&&) const { return "const&&"; }
|
||||
};
|
||||
|
||||
TEST(BindTest, PerfectForwardingOfFreeArgs) {
|
||||
ArgDescribe f;
|
||||
int i;
|
||||
EXPECT_EQ("&", absl::bind_front(f)(static_cast<int&>(i)));
|
||||
EXPECT_EQ("const&", absl::bind_front(f)(static_cast<const int&>(i)));
|
||||
EXPECT_EQ("&&", absl::bind_front(f)(static_cast<int&&>(i)));
|
||||
EXPECT_EQ("const&&", absl::bind_front(f)(static_cast<const int&&>(i)));
|
||||
}
|
||||
|
||||
struct NonCopyableFunctor {
|
||||
NonCopyableFunctor() = default;
|
||||
NonCopyableFunctor(const NonCopyableFunctor&) = delete;
|
||||
NonCopyableFunctor& operator=(const NonCopyableFunctor&) = delete;
|
||||
const NonCopyableFunctor* operator()() const { return this; }
|
||||
};
|
||||
|
||||
TEST(BindTest, RefToFunctor) {
|
||||
// It won't copy/move the functor and use the original object.
|
||||
NonCopyableFunctor ncf;
|
||||
auto bound_ncf = absl::bind_front(std::ref(ncf));
|
||||
auto bound_ncf_copy = bound_ncf;
|
||||
EXPECT_EQ(&ncf, bound_ncf_copy());
|
||||
}
|
||||
|
||||
struct Struct {
|
||||
std::string value;
|
||||
};
|
||||
|
||||
TEST(BindTest, StoreByCopy) {
|
||||
Struct s = {"hello"};
|
||||
auto f = absl::bind_front(&Struct::value, s);
|
||||
auto g = f;
|
||||
EXPECT_EQ("hello", f());
|
||||
EXPECT_EQ("hello", g());
|
||||
EXPECT_NE(&s.value, &f());
|
||||
EXPECT_NE(&s.value, &g());
|
||||
EXPECT_NE(&g(), &f());
|
||||
}
|
||||
|
||||
struct NonCopyable {
|
||||
explicit NonCopyable(const std::string& s) : value(s) {}
|
||||
NonCopyable(const NonCopyable&) = delete;
|
||||
NonCopyable& operator=(const NonCopyable&) = delete;
|
||||
|
||||
std::string value;
|
||||
};
|
||||
|
||||
const std::string& GetNonCopyableValue(const NonCopyable& n) { return n.value; }
|
||||
|
||||
TEST(BindTest, StoreByRef) {
|
||||
NonCopyable s("hello");
|
||||
auto f = absl::bind_front(&GetNonCopyableValue, std::ref(s));
|
||||
EXPECT_EQ("hello", f());
|
||||
EXPECT_EQ(&s.value, &f());
|
||||
auto g = std::move(f); // NOLINT
|
||||
EXPECT_EQ("hello", g());
|
||||
EXPECT_EQ(&s.value, &g());
|
||||
s.value = "goodbye";
|
||||
EXPECT_EQ("goodbye", g());
|
||||
}
|
||||
|
||||
TEST(BindTest, StoreByCRef) {
|
||||
NonCopyable s("hello");
|
||||
auto f = absl::bind_front(&GetNonCopyableValue, std::cref(s));
|
||||
EXPECT_EQ("hello", f());
|
||||
EXPECT_EQ(&s.value, &f());
|
||||
auto g = std::move(f); // NOLINT
|
||||
EXPECT_EQ("hello", g());
|
||||
EXPECT_EQ(&s.value, &g());
|
||||
s.value = "goodbye";
|
||||
EXPECT_EQ("goodbye", g());
|
||||
}
|
||||
|
||||
const std::string& GetNonCopyableValueByWrapper(
|
||||
std::reference_wrapper<NonCopyable> n) {
|
||||
return n.get().value;
|
||||
}
|
||||
|
||||
TEST(BindTest, StoreByRefInvokeByWrapper) {
|
||||
NonCopyable s("hello");
|
||||
auto f = absl::bind_front(GetNonCopyableValueByWrapper, std::ref(s));
|
||||
EXPECT_EQ("hello", f());
|
||||
EXPECT_EQ(&s.value, &f());
|
||||
auto g = std::move(f);
|
||||
EXPECT_EQ("hello", g());
|
||||
EXPECT_EQ(&s.value, &g());
|
||||
s.value = "goodbye";
|
||||
EXPECT_EQ("goodbye", g());
|
||||
}
|
||||
|
||||
TEST(BindTest, StoreByPointer) {
|
||||
NonCopyable s("hello");
|
||||
auto f = absl::bind_front(&NonCopyable::value, &s);
|
||||
EXPECT_EQ("hello", f());
|
||||
EXPECT_EQ(&s.value, &f());
|
||||
auto g = std::move(f);
|
||||
EXPECT_EQ("hello", g());
|
||||
EXPECT_EQ(&s.value, &g());
|
||||
}
|
||||
|
||||
int Sink(std::unique_ptr<int> p) {
|
||||
return *p;
|
||||
}
|
||||
|
||||
std::unique_ptr<int> Factory(int n) { return absl::make_unique<int>(n); }
|
||||
|
||||
TEST(BindTest, NonCopyableArg) {
|
||||
EXPECT_EQ(42, absl::bind_front(Sink)(absl::make_unique<int>(42)));
|
||||
EXPECT_EQ(42, absl::bind_front(Sink, absl::make_unique<int>(42))());
|
||||
}
|
||||
|
||||
TEST(BindTest, NonCopyableResult) {
|
||||
EXPECT_THAT(absl::bind_front(Factory)(42), ::testing::Pointee(42));
|
||||
EXPECT_THAT(absl::bind_front(Factory, 42)(), ::testing::Pointee(42));
|
||||
}
|
||||
|
||||
// is_copy_constructible<FalseCopyable<unique_ptr<T>> is true but an attempt to
|
||||
// instantiate the copy constructor leads to a compile error. This is similar
|
||||
// to how standard containers behave.
|
||||
template <class T>
|
||||
struct FalseCopyable {
|
||||
FalseCopyable() {}
|
||||
FalseCopyable(const FalseCopyable& other) : m(other.m) {}
|
||||
FalseCopyable(FalseCopyable&& other) : m(std::move(other.m)) {}
|
||||
T m;
|
||||
};
|
||||
|
||||
int GetMember(FalseCopyable<std::unique_ptr<int>> x) { return *x.m; }
|
||||
|
||||
TEST(BindTest, WrappedMoveOnly) {
|
||||
FalseCopyable<std::unique_ptr<int>> x;
|
||||
x.m = absl::make_unique<int>(42);
|
||||
auto f = absl::bind_front(&GetMember, std::move(x));
|
||||
EXPECT_EQ(42, std::move(f)());
|
||||
}
|
||||
|
||||
int Plus(int a, int b) { return a + b; }
|
||||
|
||||
TEST(BindTest, ConstExpr) {
|
||||
constexpr auto f = absl::bind_front(CharAt);
|
||||
EXPECT_EQ(f("ABC", 1), 'B');
|
||||
static constexpr int five = 5;
|
||||
constexpr auto plus5 = absl::bind_front(Plus, five);
|
||||
EXPECT_EQ(plus5(1), 6);
|
||||
|
||||
// There seems to be a bug in MSVC dealing constexpr construction of
|
||||
// char[]. Notice 'plus5' above; 'int' works just fine.
|
||||
#if !(defined(_MSC_VER) && _MSC_VER < 1910)
|
||||
static constexpr char data[] = "DEF";
|
||||
constexpr auto g = absl::bind_front(CharAt, data);
|
||||
EXPECT_EQ(g(1), 'E');
|
||||
#endif
|
||||
}
|
||||
|
||||
struct ManglingCall {
|
||||
int operator()(int, double, std::string) const { return 0; }
|
||||
};
|
||||
|
||||
TEST(BindTest, Mangling) {
|
||||
// We just want to generate a particular instantiation to see its mangling.
|
||||
absl::bind_front(ManglingCall{}, 1, 3.3)("A");
|
||||
}
|
||||
|
||||
} // namespace
|
95
absl/functional/internal/front_binder.h
Normal file
95
absl/functional/internal/front_binder.h
Normal file
|
@ -0,0 +1,95 @@
|
|||
// Copyright 2018 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
// Implementation details for `absl::bind_front()`.
|
||||
|
||||
#ifndef ABSL_FUNCTIONAL_INTERNAL_FRONT_BINDER_H_
|
||||
#define ABSL_FUNCTIONAL_INTERNAL_FRONT_BINDER_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/internal/invoke.h"
|
||||
#include "absl/container/internal/compressed_tuple.h"
|
||||
#include "absl/meta/type_traits.h"
|
||||
#include "absl/utility/utility.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace functional_internal {
|
||||
|
||||
// Invoke the method, expanding the tuple of bound arguments.
|
||||
template <class R, class Tuple, size_t... Idx, class... Args>
|
||||
R Apply(Tuple&& bound, absl::index_sequence<Idx...>, Args&&... free) {
|
||||
return base_internal::Invoke(
|
||||
absl::forward<Tuple>(bound).template get<Idx>()...,
|
||||
absl::forward<Args>(free)...);
|
||||
}
|
||||
|
||||
template <class F, class... BoundArgs>
|
||||
class FrontBinder {
|
||||
using BoundArgsT = absl::container_internal::CompressedTuple<F, BoundArgs...>;
|
||||
using Idx = absl::make_index_sequence<sizeof...(BoundArgs) + 1>;
|
||||
|
||||
BoundArgsT bound_args_;
|
||||
|
||||
public:
|
||||
template <class... Ts>
|
||||
constexpr explicit FrontBinder(absl::in_place_t, Ts&&... ts)
|
||||
: bound_args_(absl::forward<Ts>(ts)...) {}
|
||||
|
||||
template <class... FreeArgs,
|
||||
class R = base_internal::InvokeT<F&, BoundArgs&..., FreeArgs&&...>>
|
||||
R operator()(FreeArgs&&... free_args) & {
|
||||
return functional_internal::Apply<R>(bound_args_, Idx(),
|
||||
absl::forward<FreeArgs>(free_args)...);
|
||||
}
|
||||
|
||||
template <class... FreeArgs,
|
||||
class R = base_internal::InvokeT<const F&, const BoundArgs&...,
|
||||
FreeArgs&&...>>
|
||||
R operator()(FreeArgs&&... free_args) const& {
|
||||
return functional_internal::Apply<R>(bound_args_, Idx(),
|
||||
absl::forward<FreeArgs>(free_args)...);
|
||||
}
|
||||
|
||||
template <class... FreeArgs, class R = base_internal::InvokeT<
|
||||
F&&, BoundArgs&&..., FreeArgs&&...>>
|
||||
R operator()(FreeArgs&&... free_args) && {
|
||||
// This overload is called when *this is an rvalue. If some of the bound
|
||||
// arguments are stored by value or rvalue reference, we move them.
|
||||
return functional_internal::Apply<R>(absl::move(bound_args_), Idx(),
|
||||
absl::forward<FreeArgs>(free_args)...);
|
||||
}
|
||||
|
||||
template <class... FreeArgs,
|
||||
class R = base_internal::InvokeT<const F&&, const BoundArgs&&...,
|
||||
FreeArgs&&...>>
|
||||
R operator()(FreeArgs&&... free_args) const&& {
|
||||
// This overload is called when *this is an rvalue. If some of the bound
|
||||
// arguments are stored by value or rvalue reference, we move them.
|
||||
return functional_internal::Apply<R>(absl::move(bound_args_), Idx(),
|
||||
absl::forward<FreeArgs>(free_args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <class F, class... BoundArgs>
|
||||
using bind_front_t = FrontBinder<decay_t<F>, absl::decay_t<BoundArgs>...>;
|
||||
|
||||
} // namespace functional_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_FUNCTIONAL_INTERNAL_FRONT_BINDER_H_
|
|
@ -161,6 +161,10 @@ TYPED_TEST(UniformRealDistributionTest, ParamSerializeTest) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4756) // Constant arithmetic overflow.
|
||||
#endif
|
||||
TYPED_TEST(UniformRealDistributionTest, ViolatesPreconditionsDeathTest) {
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
// Hi < Lo
|
||||
|
@ -195,6 +199,9 @@ TYPED_TEST(UniformRealDistributionTest, ViolatesPreconditionsDeathTest) {
|
|||
}
|
||||
#endif // NDEBUG
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop) // warning(disable:4756)
|
||||
#endif
|
||||
|
||||
TYPED_TEST(UniformRealDistributionTest, TestMoments) {
|
||||
constexpr int kSize = 1000000;
|
||||
|
|
|
@ -42,6 +42,7 @@ cc_library(
|
|||
],
|
||||
textual_hdrs = ["include/cctz/civil_time_detail.h"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//absl/base:config"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
|
@ -78,7 +79,10 @@ cc_library(
|
|||
"//conditions:default": [],
|
||||
}),
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [":civil_time"],
|
||||
deps = [
|
||||
":civil_time",
|
||||
"//absl/base:config",
|
||||
],
|
||||
)
|
||||
|
||||
### tests
|
||||
|
@ -89,6 +93,7 @@ cc_test(
|
|||
srcs = ["src/civil_time_test.cc"],
|
||||
deps = [
|
||||
":civil_time",
|
||||
"//absl/base:config",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
@ -106,6 +111,7 @@ cc_test(
|
|||
deps = [
|
||||
":civil_time",
|
||||
":time_zone",
|
||||
"//absl/base:config",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
@ -124,6 +130,7 @@ cc_test(
|
|||
deps = [
|
||||
":civil_time",
|
||||
":time_zone",
|
||||
"//absl/base:config",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
@ -144,6 +151,7 @@ cc_test(
|
|||
deps = [
|
||||
":civil_time",
|
||||
":time_zone",
|
||||
"//absl/base:config",
|
||||
"@com_github_google_benchmark//:benchmark_main",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -15,9 +15,11 @@
|
|||
#ifndef ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_
|
||||
#define ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/civil_time_detail.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
|
@ -324,6 +326,7 @@ using detail::get_yearday;
|
|||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include <ostream>
|
||||
#include <type_traits>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
// Disable constexpr support unless we are in C++14 mode.
|
||||
#if __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910)
|
||||
#define CONSTEXPR_D constexpr // data
|
||||
|
@ -32,6 +34,7 @@
|
|||
#endif
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
|
@ -53,8 +56,8 @@ using second_t = std::int_fast8_t; // [0:59]
|
|||
|
||||
// Normalized civil-time fields: Y-M-D HH:MM:SS.
|
||||
struct fields {
|
||||
CONSTEXPR_M fields(year_t year, month_t month, day_t day,
|
||||
hour_t hour, minute_t minute, second_t second)
|
||||
CONSTEXPR_M fields(year_t year, month_t month, day_t day, hour_t hour,
|
||||
minute_t minute, second_t second)
|
||||
: y(year), m(month), d(day), hh(hour), mm(minute), ss(second) {}
|
||||
std::int_least64_t y;
|
||||
std::int_least8_t m;
|
||||
|
@ -101,8 +104,8 @@ CONSTEXPR_F int days_per_month(year_t y, month_t m) noexcept {
|
|||
return k_days_per_month[m] + (m == 2 && is_leap_year(y));
|
||||
}
|
||||
|
||||
CONSTEXPR_F fields n_day(year_t y, month_t m, diff_t d, diff_t cd,
|
||||
hour_t hh, minute_t mm, second_t ss) noexcept {
|
||||
CONSTEXPR_F fields n_day(year_t y, month_t m, diff_t d, diff_t cd, hour_t hh,
|
||||
minute_t mm, second_t ss) noexcept {
|
||||
y += (cd / 146097) * 400;
|
||||
cd %= 146097;
|
||||
if (cd < 0) {
|
||||
|
@ -152,8 +155,8 @@ CONSTEXPR_F fields n_day(year_t y, month_t m, diff_t d, diff_t cd,
|
|||
}
|
||||
return fields(y, m, static_cast<day_t>(d), hh, mm, ss);
|
||||
}
|
||||
CONSTEXPR_F fields n_mon(year_t y, diff_t m, diff_t d, diff_t cd,
|
||||
hour_t hh, minute_t mm, second_t ss) noexcept {
|
||||
CONSTEXPR_F fields n_mon(year_t y, diff_t m, diff_t d, diff_t cd, hour_t hh,
|
||||
minute_t mm, second_t ss) noexcept {
|
||||
if (m != 12) {
|
||||
y += m / 12;
|
||||
m %= 12;
|
||||
|
@ -164,8 +167,8 @@ CONSTEXPR_F fields n_mon(year_t y, diff_t m, diff_t d, diff_t cd,
|
|||
}
|
||||
return n_day(y, static_cast<month_t>(m), d, cd, hh, mm, ss);
|
||||
}
|
||||
CONSTEXPR_F fields n_hour(year_t y, diff_t m, diff_t d, diff_t cd,
|
||||
diff_t hh, minute_t mm, second_t ss) noexcept {
|
||||
CONSTEXPR_F fields n_hour(year_t y, diff_t m, diff_t d, diff_t cd, diff_t hh,
|
||||
minute_t mm, second_t ss) noexcept {
|
||||
cd += hh / 24;
|
||||
hh %= 24;
|
||||
if (hh < 0) {
|
||||
|
@ -264,8 +267,8 @@ CONSTEXPR_F diff_t ymd_ord(year_t y, month_t m, day_t d) noexcept {
|
|||
// yet the difference between two such extreme values may actually be
|
||||
// small, so we take a little care to avoid overflow when possible by
|
||||
// exploiting the 146097-day cycle.
|
||||
CONSTEXPR_F diff_t day_difference(year_t y1, month_t m1, day_t d1,
|
||||
year_t y2, month_t m2, day_t d2) noexcept {
|
||||
CONSTEXPR_F diff_t day_difference(year_t y1, month_t m1, day_t d1, year_t y2,
|
||||
month_t m2, day_t d2) noexcept {
|
||||
const diff_t a_c4_off = y1 % 400;
|
||||
const diff_t b_c4_off = y2 % 400;
|
||||
diff_t c4_diff = (y1 - a_c4_off) - (y2 - b_c4_off);
|
||||
|
@ -305,9 +308,7 @@ CONSTEXPR_F diff_t difference(second_tag, fields f1, fields f2) noexcept {
|
|||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Aligns the (normalized) fields struct to the indicated field.
|
||||
CONSTEXPR_F fields align(second_tag, fields f) noexcept {
|
||||
return f;
|
||||
}
|
||||
CONSTEXPR_F fields align(second_tag, fields f) noexcept { return f; }
|
||||
CONSTEXPR_F fields align(minute_tag, fields f) noexcept {
|
||||
return fields{f.y, f.m, f.d, f.hh, f.mm, 0};
|
||||
}
|
||||
|
@ -416,17 +417,13 @@ class civil_time {
|
|||
}
|
||||
return *this;
|
||||
}
|
||||
CONSTEXPR_M civil_time& operator++() noexcept {
|
||||
return *this += 1;
|
||||
}
|
||||
CONSTEXPR_M civil_time& operator++() noexcept { return *this += 1; }
|
||||
CONSTEXPR_M civil_time operator++(int) noexcept {
|
||||
const civil_time a = *this;
|
||||
++*this;
|
||||
return a;
|
||||
}
|
||||
CONSTEXPR_M civil_time& operator--() noexcept {
|
||||
return *this -= 1;
|
||||
}
|
||||
CONSTEXPR_M civil_time& operator--() noexcept { return *this -= 1; }
|
||||
CONSTEXPR_M civil_time operator--(int) noexcept {
|
||||
const civil_time a = *this;
|
||||
--*this;
|
||||
|
@ -483,12 +480,12 @@ using civil_second = civil_time<second_tag>;
|
|||
template <typename T1, typename T2>
|
||||
CONSTEXPR_F bool operator<(const civil_time<T1>& lhs,
|
||||
const civil_time<T2>& rhs) noexcept {
|
||||
return (lhs.year() < rhs.year() ||
|
||||
return (
|
||||
lhs.year() < rhs.year() ||
|
||||
(lhs.year() == rhs.year() &&
|
||||
(lhs.month() < rhs.month() ||
|
||||
(lhs.month() == rhs.month() &&
|
||||
(lhs.day() < rhs.day() ||
|
||||
(lhs.day() == rhs.day() &&
|
||||
(lhs.day() < rhs.day() || (lhs.day() == rhs.day() &&
|
||||
(lhs.hour() < rhs.hour() ||
|
||||
(lhs.hour() == rhs.hour() &&
|
||||
(lhs.minute() < rhs.minute() ||
|
||||
|
@ -615,6 +612,7 @@ std::ostream& operator<<(std::ostream& os, weekday wd);
|
|||
} // namespace detail
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#undef CONSTEXPR_M
|
||||
|
|
|
@ -25,9 +25,11 @@
|
|||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
|
@ -39,8 +41,8 @@ using sys_seconds = seconds; // Deprecated. Use cctz::seconds instead.
|
|||
|
||||
namespace detail {
|
||||
template <typename D>
|
||||
inline std::pair<time_point<seconds>, D>
|
||||
split_seconds(const time_point<D>& tp) {
|
||||
inline std::pair<time_point<seconds>, D> split_seconds(
|
||||
const time_point<D>& tp) {
|
||||
auto sec = std::chrono::time_point_cast<seconds>(tp);
|
||||
auto sub = tp - sec;
|
||||
if (sub.count() < 0) {
|
||||
|
@ -49,8 +51,8 @@ split_seconds(const time_point<D>& tp) {
|
|||
}
|
||||
return {sec, std::chrono::duration_cast<D>(sub)};
|
||||
}
|
||||
inline std::pair<time_point<seconds>, seconds>
|
||||
split_seconds(const time_point<seconds>& tp) {
|
||||
inline std::pair<time_point<seconds>, seconds> split_seconds(
|
||||
const time_point<seconds>& tp) {
|
||||
return {tp, seconds::zero()};
|
||||
}
|
||||
} // namespace detail
|
||||
|
@ -194,15 +196,13 @@ class time_zone {
|
|||
bool next_transition(const time_point<seconds>& tp,
|
||||
civil_transition* trans) const;
|
||||
template <typename D>
|
||||
bool next_transition(const time_point<D>& tp,
|
||||
civil_transition* trans) const {
|
||||
bool next_transition(const time_point<D>& tp, civil_transition* trans) const {
|
||||
return next_transition(detail::split_seconds(tp).first, trans);
|
||||
}
|
||||
bool prev_transition(const time_point<seconds>& tp,
|
||||
civil_transition* trans) const;
|
||||
template <typename D>
|
||||
bool prev_transition(const time_point<D>& tp,
|
||||
civil_transition* trans) const {
|
||||
bool prev_transition(const time_point<D>& tp, civil_transition* trans) const {
|
||||
return prev_transition(detail::split_seconds(tp).first, trans);
|
||||
}
|
||||
|
||||
|
@ -220,9 +220,7 @@ class time_zone {
|
|||
friend bool operator==(time_zone lhs, time_zone rhs) {
|
||||
return &lhs.effective_impl() == &rhs.effective_impl();
|
||||
}
|
||||
friend bool operator!=(time_zone lhs, time_zone rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
friend bool operator!=(time_zone lhs, time_zone rhs) { return !(lhs == rhs); }
|
||||
|
||||
template <typename H>
|
||||
friend H AbslHashValue(H h, time_zone tz) {
|
||||
|
@ -380,6 +378,7 @@ inline bool parse(const std::string& fmt, const std::string& input,
|
|||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_
|
||||
|
|
|
@ -20,7 +20,10 @@
|
|||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
|
@ -40,9 +43,11 @@ class ZoneInfoSource {
|
|||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz_extension {
|
||||
|
||||
|
@ -52,8 +57,8 @@ namespace cctz_extension {
|
|||
using ZoneInfoSourceFactory =
|
||||
std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource> (*)(
|
||||
const std::string&,
|
||||
const std::function<std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource>(
|
||||
const std::string&)>&);
|
||||
const std::function<std::unique_ptr<
|
||||
absl::time_internal::cctz::ZoneInfoSource>(const std::string&)>&);
|
||||
|
||||
// The user can control the mapping of zone names to zoneinfo data by
|
||||
// providing a definition for cctz_extension::zone_info_source_factory.
|
||||
|
@ -91,6 +96,7 @@ extern ZoneInfoSourceFactory zone_info_source_factory;
|
|||
|
||||
} // namespace cctz_extension
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_
|
||||
|
|
|
@ -105,8 +105,7 @@ const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z";
|
|||
|
||||
// A list of known time-zone names.
|
||||
// TODO: Refactor with src/time_zone_lookup_test.cc.
|
||||
const char* const kTimeZoneNames[] = {
|
||||
"Africa/Abidjan",
|
||||
const char* const kTimeZoneNames[] = {"Africa/Abidjan",
|
||||
"Africa/Accra",
|
||||
"Africa/Addis_Ababa",
|
||||
"Africa/Algiers",
|
||||
|
@ -698,8 +697,7 @@ const char* const kTimeZoneNames[] = {
|
|||
"W-SU",
|
||||
"WET",
|
||||
"Zulu",
|
||||
nullptr
|
||||
};
|
||||
nullptr};
|
||||
|
||||
std::vector<std::string> AllTimeZoneNames() {
|
||||
std::vector<std::string> names;
|
||||
|
|
|
@ -18,7 +18,10 @@
|
|||
#include <ostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
namespace detail {
|
||||
|
@ -87,4 +90,5 @@ std::ostream& operator<<(std::ostream& os, weekday wd) {
|
|||
} // namespace detail
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
|
|
@ -21,8 +21,10 @@
|
|||
#include <type_traits>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
|
@ -1014,19 +1016,13 @@ TEST(CivilTime, LeapYears) {
|
|||
int day;
|
||||
} leap_day; // The date of the day after Feb 28.
|
||||
} kLeapYearTable[]{
|
||||
{1900, 365, {3, 1}},
|
||||
{1999, 365, {3, 1}},
|
||||
{1900, 365, {3, 1}}, {1999, 365, {3, 1}},
|
||||
{2000, 366, {2, 29}}, // leap year
|
||||
{2001, 365, {3, 1}},
|
||||
{2002, 365, {3, 1}},
|
||||
{2003, 365, {3, 1}},
|
||||
{2004, 366, {2, 29}}, // leap year
|
||||
{2005, 365, {3, 1}},
|
||||
{2006, 365, {3, 1}},
|
||||
{2007, 365, {3, 1}},
|
||||
{2008, 366, {2, 29}}, // leap year
|
||||
{2009, 365, {3, 1}},
|
||||
{2100, 365, {3, 1}},
|
||||
{2001, 365, {3, 1}}, {2002, 365, {3, 1}},
|
||||
{2003, 365, {3, 1}}, {2004, 366, {2, 29}}, // leap year
|
||||
{2005, 365, {3, 1}}, {2006, 365, {3, 1}},
|
||||
{2007, 365, {3, 1}}, {2008, 366, {2, 29}}, // leap year
|
||||
{2009, 365, {3, 1}}, {2100, 365, {3, 1}},
|
||||
};
|
||||
|
||||
for (const auto& e : kLeapYearTable) {
|
||||
|
@ -1056,4 +1052,5 @@ TEST(CivilTime, FirstThursdayInMonth) {
|
|||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
|
|
@ -20,7 +20,10 @@
|
|||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
|
@ -59,11 +62,9 @@ bool FixedOffsetFromName(const std::string& name, seconds* offset) {
|
|||
const char* const ep = kFixedZonePrefix + prefix_len;
|
||||
if (name.size() != prefix_len + 9) // <prefix>+99:99:99
|
||||
return false;
|
||||
if (!std::equal(kFixedZonePrefix, ep, name.begin()))
|
||||
return false;
|
||||
if (!std::equal(kFixedZonePrefix, ep, name.begin())) return false;
|
||||
const char* np = name.data() + prefix_len;
|
||||
if (np[0] != '+' && np[0] != '-')
|
||||
return false;
|
||||
if (np[0] != '+' && np[0] != '-') return false;
|
||||
if (np[3] != ':' || np[6] != ':') // see note below about large offsets
|
||||
return false;
|
||||
|
||||
|
@ -135,4 +136,5 @@ std::string FixedOffsetToAbbr(const seconds& offset) {
|
|||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
|
|
@ -17,9 +17,11 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
|
@ -44,6 +46,7 @@ std::string FixedOffsetToAbbr(const seconds& offset);
|
|||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
|
||||
// Include time.h directly since, by C++ standards, ctime doesn't have to
|
||||
|
@ -48,6 +49,7 @@
|
|||
#include "time_zone_if.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
namespace detail {
|
||||
|
@ -502,7 +504,8 @@ std::string format(const std::string& format, const time_point<seconds>& tp,
|
|||
bp = ep;
|
||||
if (n > 0) {
|
||||
if (n > kDigits10_64) n = kDigits10_64;
|
||||
bp = Format64(bp, n, (n > 15) ? fs.count() * kExp10[n - 15]
|
||||
bp = Format64(bp, n,
|
||||
(n > 15) ? fs.count() * kExp10[n - 15]
|
||||
: fs.count() / kExp10[15 - n]);
|
||||
if (*np == 'S') *--bp = '.';
|
||||
}
|
||||
|
@ -720,10 +723,9 @@ bool parse(const std::string& format, const std::string& input,
|
|||
data = ParseZone(data, &zone);
|
||||
continue;
|
||||
case 's':
|
||||
data = ParseInt(data, 0,
|
||||
std::numeric_limits<std::int_fast64_t>::min(),
|
||||
std::numeric_limits<std::int_fast64_t>::max(),
|
||||
&percent_s);
|
||||
data =
|
||||
ParseInt(data, 0, std::numeric_limits<std::int_fast64_t>::min(),
|
||||
std::numeric_limits<std::int_fast64_t>::max(), &percent_s);
|
||||
if (data != nullptr) saw_percent_s = true;
|
||||
continue;
|
||||
case ':':
|
||||
|
@ -916,4 +918,5 @@ bool parse(const std::string& format, const std::string& input,
|
|||
} // namespace detail
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
|
|
@ -12,20 +12,21 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
|
||||
namespace chrono = std::chrono;
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
|
@ -88,8 +89,11 @@ TEST(Format, TimePointResolution) {
|
|||
format(kFmt, chrono::time_point_cast<chrono::milliseconds>(t0), utc));
|
||||
EXPECT_EQ("03:04:05",
|
||||
format(kFmt, chrono::time_point_cast<chrono::seconds>(t0), utc));
|
||||
EXPECT_EQ("03:04:05",
|
||||
format(kFmt, chrono::time_point_cast<absl::time_internal::cctz::seconds>(t0), utc));
|
||||
EXPECT_EQ(
|
||||
"03:04:05",
|
||||
format(kFmt,
|
||||
chrono::time_point_cast<absl::time_internal::cctz::seconds>(t0),
|
||||
utc));
|
||||
EXPECT_EQ("03:04:00",
|
||||
format(kFmt, chrono::time_point_cast<chrono::minutes>(t0), utc));
|
||||
EXPECT_EQ("03:00:00",
|
||||
|
@ -110,11 +114,9 @@ TEST(Format, TimePointExtendedResolution) {
|
|||
EXPECT_EQ(
|
||||
"12:34:56.012345678901234",
|
||||
detail::format(kFmt, tp, detail::femtoseconds(12345678901234), utc));
|
||||
EXPECT_EQ(
|
||||
"12:34:56.001234567890123",
|
||||
EXPECT_EQ("12:34:56.001234567890123",
|
||||
detail::format(kFmt, tp, detail::femtoseconds(1234567890123), utc));
|
||||
EXPECT_EQ(
|
||||
"12:34:56.000123456789012",
|
||||
EXPECT_EQ("12:34:56.000123456789012",
|
||||
detail::format(kFmt, tp, detail::femtoseconds(123456789012), utc));
|
||||
|
||||
EXPECT_EQ("12:34:56.000000000000123",
|
||||
|
@ -1416,8 +1418,8 @@ TEST(Parse, MaxRange) {
|
|||
parse(RFC3339_sec, "-292277022657-01-27T08:29:51+01:00", utc, &tp));
|
||||
|
||||
// tests max/min civil-second overflow
|
||||
EXPECT_FALSE(parse(RFC3339_sec, "9223372036854775807-12-31T23:59:59-00:01",
|
||||
utc, &tp));
|
||||
EXPECT_FALSE(
|
||||
parse(RFC3339_sec, "9223372036854775807-12-31T23:59:59-00:01", utc, &tp));
|
||||
EXPECT_FALSE(parse(RFC3339_sec, "-9223372036854775808-01-01T00:00:00+00:01",
|
||||
utc, &tp));
|
||||
|
||||
|
@ -1474,7 +1476,8 @@ TEST(FormatParse, RoundTrip) {
|
|||
|
||||
TEST(FormatParse, RoundTripDistantFuture) {
|
||||
const time_zone utc = utc_time_zone();
|
||||
const time_point<absl::time_internal::cctz::seconds> in = time_point<absl::time_internal::cctz::seconds>::max();
|
||||
const time_point<absl::time_internal::cctz::seconds> in =
|
||||
time_point<absl::time_internal::cctz::seconds>::max();
|
||||
const std::string s = format(RFC3339_full, in, utc);
|
||||
time_point<absl::time_internal::cctz::seconds> out;
|
||||
EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s;
|
||||
|
@ -1483,7 +1486,8 @@ TEST(FormatParse, RoundTripDistantFuture) {
|
|||
|
||||
TEST(FormatParse, RoundTripDistantPast) {
|
||||
const time_zone utc = utc_time_zone();
|
||||
const time_point<absl::time_internal::cctz::seconds> in = time_point<absl::time_internal::cctz::seconds>::min();
|
||||
const time_point<absl::time_internal::cctz::seconds> in =
|
||||
time_point<absl::time_internal::cctz::seconds>::min();
|
||||
const std::string s = format(RFC3339_full, in, utc);
|
||||
time_point<absl::time_internal::cctz::seconds> out;
|
||||
EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s;
|
||||
|
@ -1492,4 +1496,5 @@ TEST(FormatParse, RoundTripDistantPast) {
|
|||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
|
|
@ -13,10 +13,13 @@
|
|||
// limitations under the License.
|
||||
|
||||
#include "time_zone_if.h"
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "time_zone_info.h"
|
||||
#include "time_zone_libc.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
|
@ -38,4 +41,5 @@ TimeZoneIf::~TimeZoneIf() {}
|
|||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
|
|
@ -20,10 +20,12 @@
|
|||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
|
@ -38,8 +40,7 @@ class TimeZoneIf {
|
|||
|
||||
virtual time_zone::absolute_lookup BreakTime(
|
||||
const time_point<seconds>& tp) const = 0;
|
||||
virtual time_zone::civil_lookup MakeTime(
|
||||
const civil_second& cs) const = 0;
|
||||
virtual time_zone::civil_lookup MakeTime(const civil_second& cs) const = 0;
|
||||
|
||||
virtual bool NextTransition(const time_point<seconds>& tp,
|
||||
time_zone::civil_transition* trans) const = 0;
|
||||
|
@ -58,15 +59,18 @@ class TimeZoneIf {
|
|||
// Unix clock are second aligned, but not that they share an epoch.
|
||||
inline std::int_fast64_t ToUnixSeconds(const time_point<seconds>& tp) {
|
||||
return (tp - std::chrono::time_point_cast<seconds>(
|
||||
std::chrono::system_clock::from_time_t(0))).count();
|
||||
std::chrono::system_clock::from_time_t(0)))
|
||||
.count();
|
||||
}
|
||||
inline time_point<seconds> FromUnixSeconds(std::int_fast64_t t) {
|
||||
return std::chrono::time_point_cast<seconds>(
|
||||
std::chrono::system_clock::from_time_t(0)) + seconds(t);
|
||||
std::chrono::system_clock::from_time_t(0)) +
|
||||
seconds(t);
|
||||
}
|
||||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_
|
||||
|
|
|
@ -20,9 +20,11 @@
|
|||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "time_zone_fixed.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
|
@ -43,9 +45,7 @@ std::mutex& TimeZoneMutex() {
|
|||
|
||||
} // namespace
|
||||
|
||||
time_zone time_zone::Impl::UTC() {
|
||||
return time_zone(UTCImpl());
|
||||
}
|
||||
time_zone time_zone::Impl::UTC() { return time_zone(UTCImpl()); }
|
||||
|
||||
bool time_zone::Impl::LoadTimeZone(const std::string& name, time_zone* tz) {
|
||||
const time_zone::Impl* const utc_impl = UTCImpl();
|
||||
|
@ -117,4 +117,5 @@ const time_zone::Impl* time_zone::Impl::UTCImpl() {
|
|||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
|
|
@ -18,12 +18,14 @@
|
|||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
#include "time_zone_if.h"
|
||||
#include "time_zone_info.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
|
@ -85,6 +87,7 @@ class time_zone::Impl {
|
|||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_
|
||||
|
|
|
@ -45,11 +45,13 @@
|
|||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
|
||||
#include "time_zone_fixed.h"
|
||||
#include "time_zone_posix.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
|
@ -172,8 +174,8 @@ inline time_zone::civil_lookup MakeRepeated(const Transition& tr,
|
|||
}
|
||||
|
||||
inline civil_second YearShift(const civil_second& cs, year_t shift) {
|
||||
return civil_second(cs.year() + shift, cs.month(), cs.day(),
|
||||
cs.hour(), cs.minute(), cs.second());
|
||||
return civil_second(cs.year() + shift, cs.month(), cs.day(), cs.hour(),
|
||||
cs.minute(), cs.second());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -393,31 +395,24 @@ void TimeZoneInfo::ExtendTransitions(const std::string& name,
|
|||
bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
|
||||
// Read and validate the header.
|
||||
tzhead tzh;
|
||||
if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh))
|
||||
return false;
|
||||
if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false;
|
||||
if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0)
|
||||
return false;
|
||||
Header hdr;
|
||||
if (!hdr.Build(tzh))
|
||||
return false;
|
||||
if (!hdr.Build(tzh)) return false;
|
||||
std::size_t time_len = 4;
|
||||
if (tzh.tzh_version[0] != '\0') {
|
||||
// Skip the 4-byte data.
|
||||
if (zip->Skip(hdr.DataLength(time_len)) != 0)
|
||||
return false;
|
||||
if (zip->Skip(hdr.DataLength(time_len)) != 0) return false;
|
||||
// Read and validate the header for the 8-byte data.
|
||||
if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh))
|
||||
return false;
|
||||
if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh)) return false;
|
||||
if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0)
|
||||
return false;
|
||||
if (tzh.tzh_version[0] == '\0')
|
||||
return false;
|
||||
if (!hdr.Build(tzh))
|
||||
return false;
|
||||
if (tzh.tzh_version[0] == '\0') return false;
|
||||
if (!hdr.Build(tzh)) return false;
|
||||
time_len = 8;
|
||||
}
|
||||
if (hdr.typecnt == 0)
|
||||
return false;
|
||||
if (hdr.typecnt == 0) return false;
|
||||
if (hdr.leapcnt != 0) {
|
||||
// This code assumes 60-second minutes so we do not want
|
||||
// the leap-second encoded zoneinfo. We could reverse the
|
||||
|
@ -425,16 +420,13 @@ bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
|
|||
// so currently we simply reject such data.
|
||||
return false;
|
||||
}
|
||||
if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt)
|
||||
return false;
|
||||
if (hdr.ttisutcnt != 0 && hdr.ttisutcnt != hdr.typecnt)
|
||||
return false;
|
||||
if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt) return false;
|
||||
if (hdr.ttisutcnt != 0 && hdr.ttisutcnt != hdr.typecnt) return false;
|
||||
|
||||
// Read the data into a local buffer.
|
||||
std::size_t len = hdr.DataLength(time_len);
|
||||
std::vector<char> tbuf(len);
|
||||
if (zip->Read(tbuf.data(), len) != len)
|
||||
return false;
|
||||
if (zip->Read(tbuf.data(), len) != len) return false;
|
||||
const char* bp = tbuf.data();
|
||||
|
||||
// Decode and validate the transitions.
|
||||
|
@ -452,10 +444,8 @@ bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
|
|||
bool seen_type_0 = false;
|
||||
for (std::size_t i = 0; i != hdr.timecnt; ++i) {
|
||||
transitions_[i].type_index = Decode8(bp++);
|
||||
if (transitions_[i].type_index >= hdr.typecnt)
|
||||
return false;
|
||||
if (transitions_[i].type_index == 0)
|
||||
seen_type_0 = true;
|
||||
if (transitions_[i].type_index >= hdr.typecnt) return false;
|
||||
if (transitions_[i].type_index == 0) seen_type_0 = true;
|
||||
}
|
||||
|
||||
// Decode and validate the transition types.
|
||||
|
@ -469,8 +459,7 @@ bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
|
|||
bp += 4;
|
||||
transition_types_[i].is_dst = (Decode8(bp++) != 0);
|
||||
transition_types_[i].abbr_index = Decode8(bp++);
|
||||
if (transition_types_[i].abbr_index >= hdr.charcnt)
|
||||
return false;
|
||||
if (transition_types_[i].abbr_index >= hdr.charcnt) return false;
|
||||
}
|
||||
|
||||
// Determine the before-first-transition type.
|
||||
|
@ -479,13 +468,10 @@ bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
|
|||
std::uint_fast8_t index = 0;
|
||||
if (transition_types_[0].is_dst) {
|
||||
index = transitions_[0].type_index;
|
||||
while (index != 0 && transition_types_[index].is_dst)
|
||||
--index;
|
||||
while (index != 0 && transition_types_[index].is_dst) --index;
|
||||
}
|
||||
while (index != hdr.typecnt && transition_types_[index].is_dst)
|
||||
++index;
|
||||
if (index != hdr.typecnt)
|
||||
default_transition_type_ = index;
|
||||
while (index != hdr.typecnt && transition_types_[index].is_dst) ++index;
|
||||
if (index != hdr.typecnt) default_transition_type_ = index;
|
||||
}
|
||||
|
||||
// Copy all the abbreviations.
|
||||
|
@ -509,11 +495,9 @@ bool TimeZoneInfo::Load(const std::string& name, ZoneInfoSource* zip) {
|
|||
unsigned char ch; // all non-EOF results are positive
|
||||
return (azip->Read(&ch, 1) == 1) ? ch : EOF;
|
||||
};
|
||||
if (get_char(zip) != '\n')
|
||||
return false;
|
||||
if (get_char(zip) != '\n') return false;
|
||||
for (int c = get_char(zip); c != '\n'; c = get_char(zip)) {
|
||||
if (c == EOF)
|
||||
return false;
|
||||
if (c == EOF) return false;
|
||||
future_spec_.push_back(static_cast<char>(c));
|
||||
}
|
||||
}
|
||||
|
@ -748,13 +732,13 @@ time_zone::absolute_lookup TimeZoneInfo::LocalTime(
|
|||
// A civil time in "+offset" looks like (time+offset) in UTC.
|
||||
// Note: We perform two additions in the civil_second domain to
|
||||
// sidestep the chance of overflow in (unix_time + tt.utc_offset).
|
||||
return {(civil_second() + unix_time) + tt.utc_offset,
|
||||
tt.utc_offset, tt.is_dst, &abbreviations_[tt.abbr_index]};
|
||||
return {(civil_second() + unix_time) + tt.utc_offset, tt.utc_offset,
|
||||
tt.is_dst, &abbreviations_[tt.abbr_index]};
|
||||
}
|
||||
|
||||
// BreakTime() translation for a particular transition.
|
||||
time_zone::absolute_lookup TimeZoneInfo::LocalTime(
|
||||
std::int_fast64_t unix_time, const Transition& tr) const {
|
||||
time_zone::absolute_lookup TimeZoneInfo::LocalTime(std::int_fast64_t unix_time,
|
||||
const Transition& tr) const {
|
||||
const TransitionType& tt = transition_types_[tr.type_index];
|
||||
// Note: (unix_time - tr.unix_time) will never overflow as we
|
||||
// have ensured that there is always a "nearby" transition.
|
||||
|
@ -897,9 +881,7 @@ time_zone::civil_lookup TimeZoneInfo::MakeTime(const civil_second& cs) const {
|
|||
return MakeUnique(tr->unix_time + (cs - tr->civil_sec));
|
||||
}
|
||||
|
||||
std::string TimeZoneInfo::Version() const {
|
||||
return version_;
|
||||
}
|
||||
std::string TimeZoneInfo::Version() const { return version_; }
|
||||
|
||||
std::string TimeZoneInfo::Description() const {
|
||||
std::ostringstream oss;
|
||||
|
@ -921,8 +903,8 @@ bool TimeZoneInfo::NextTransition(const time_point<seconds>& tp,
|
|||
}
|
||||
std::int_fast64_t unix_time = ToUnixSeconds(tp);
|
||||
const Transition target = {unix_time, 0, civil_second(), civil_second()};
|
||||
const Transition* tr = std::upper_bound(begin, end, target,
|
||||
Transition::ByUnixTime());
|
||||
const Transition* tr =
|
||||
std::upper_bound(begin, end, target, Transition::ByUnixTime());
|
||||
for (; tr != end; ++tr) { // skip no-op transitions
|
||||
std::uint_fast8_t prev_type_index =
|
||||
(tr == begin) ? default_transition_type_ : tr[-1].type_index;
|
||||
|
@ -956,8 +938,8 @@ bool TimeZoneInfo::PrevTransition(const time_point<seconds>& tp,
|
|||
unix_time += 1; // ceils
|
||||
}
|
||||
const Transition target = {unix_time, 0, civil_second(), civil_second()};
|
||||
const Transition* tr = std::lower_bound(begin, end, target,
|
||||
Transition::ByUnixTime());
|
||||
const Transition* tr =
|
||||
std::lower_bound(begin, end, target, Transition::ByUnixTime());
|
||||
for (; tr != begin; --tr) { // skip no-op transitions
|
||||
std::uint_fast8_t prev_type_index =
|
||||
(tr - 1 == begin) ? default_transition_type_ : tr[-2].type_index;
|
||||
|
@ -972,4 +954,5 @@ bool TimeZoneInfo::PrevTransition(const time_point<seconds>& tp,
|
|||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/zone_info_source.h"
|
||||
|
@ -28,6 +29,7 @@
|
|||
#include "tzfile.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
|
@ -72,8 +74,7 @@ class TimeZoneInfo : public TimeZoneIf {
|
|||
// TimeZoneIf implementations.
|
||||
time_zone::absolute_lookup BreakTime(
|
||||
const time_point<seconds>& tp) const override;
|
||||
time_zone::civil_lookup MakeTime(
|
||||
const civil_second& cs) const override;
|
||||
time_zone::civil_lookup MakeTime(const civil_second& cs) const override;
|
||||
bool NextTransition(const time_point<seconds>& tp,
|
||||
time_zone::civil_transition* trans) const override;
|
||||
bool PrevTransition(const time_point<seconds>& tp,
|
||||
|
@ -131,6 +132,7 @@ class TimeZoneInfo : public TimeZoneIf {
|
|||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_
|
||||
|
|
|
@ -23,10 +23,12 @@
|
|||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
|
@ -84,9 +86,7 @@ auto tm_gmtoff(const T& tm) -> decltype(tm.__tm_gmtoff) {
|
|||
}
|
||||
#endif // tm_gmtoff
|
||||
#if defined(tm_zone)
|
||||
auto tm_zone(const std::tm& tm) -> decltype(tm.tm_zone) {
|
||||
return tm.tm_zone;
|
||||
}
|
||||
auto tm_zone(const std::tm& tm) -> decltype(tm.tm_zone) { return tm.tm_zone; }
|
||||
#elif defined(__tm_zone)
|
||||
auto tm_zone(const std::tm& tm) -> decltype(tm.__tm_zone) {
|
||||
return tm.__tm_zone;
|
||||
|
@ -208,8 +208,8 @@ time_zone::absolute_lookup TimeZoneLibC::BreakTime(
|
|||
}
|
||||
|
||||
const year_t year = tmp->tm_year + year_t{1900};
|
||||
al.cs = civil_second(year, tmp->tm_mon + 1, tmp->tm_mday,
|
||||
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
||||
al.cs = civil_second(year, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour,
|
||||
tmp->tm_min, tmp->tm_sec);
|
||||
al.offset = static_cast<int>(tm_gmtoff(*tmp));
|
||||
al.abbr = local_ ? tm_zone(*tmp) : "UTC"; // as expected by cctz
|
||||
al.is_dst = tmp->tm_isdst > 0;
|
||||
|
@ -304,4 +304,5 @@ std::string TimeZoneLibC::Description() const {
|
|||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
|
|
@ -17,9 +17,11 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "time_zone_if.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
|
@ -33,8 +35,7 @@ class TimeZoneLibC : public TimeZoneIf {
|
|||
// TimeZoneIf implementations.
|
||||
time_zone::absolute_lookup BreakTime(
|
||||
const time_point<seconds>& tp) const override;
|
||||
time_zone::civil_lookup MakeTime(
|
||||
const civil_second& cs) const override;
|
||||
time_zone::civil_lookup MakeTime(const civil_second& cs) const override;
|
||||
bool NextTransition(const time_point<seconds>& tp,
|
||||
time_zone::civil_transition* trans) const override;
|
||||
bool PrevTransition(const time_point<seconds>& tp,
|
||||
|
@ -48,6 +49,7 @@ class TimeZoneLibC : public TimeZoneIf {
|
|||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
|
@ -23,6 +24,7 @@
|
|||
|
||||
#if defined(__APPLE__)
|
||||
#include <CoreFoundation/CFTimeZone.h>
|
||||
|
||||
#include <vector>
|
||||
#endif
|
||||
|
||||
|
@ -34,6 +36,7 @@
|
|||
#include "time_zone_impl.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
|
@ -66,9 +69,7 @@ int __system_property_get(const char* name, char* value) {
|
|||
} // namespace
|
||||
#endif
|
||||
|
||||
std::string time_zone::name() const {
|
||||
return effective_impl().Name();
|
||||
}
|
||||
std::string time_zone::name() const { return effective_impl().Name(); }
|
||||
|
||||
time_zone::absolute_lookup time_zone::lookup(
|
||||
const time_point<seconds>& tp) const {
|
||||
|
@ -89,9 +90,7 @@ bool time_zone::prev_transition(const time_point<seconds>& tp,
|
|||
return effective_impl().PrevTransition(tp, trans);
|
||||
}
|
||||
|
||||
std::string time_zone::version() const {
|
||||
return effective_impl().Version();
|
||||
}
|
||||
std::string time_zone::version() const { return effective_impl().Version(); }
|
||||
|
||||
std::string time_zone::description() const {
|
||||
return effective_impl().Description();
|
||||
|
@ -184,4 +183,5 @@ time_zone local_time_zone() {
|
|||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
|
@ -23,20 +21,22 @@
|
|||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
|
||||
namespace chrono = std::chrono;
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
namespace {
|
||||
|
||||
// A list of known time-zone names.
|
||||
const char* const kTimeZoneNames[] = {
|
||||
"Africa/Abidjan",
|
||||
const char* const kTimeZoneNames[] = {"Africa/Abidjan",
|
||||
"Africa/Accra",
|
||||
"Africa/Addis_Ababa",
|
||||
"Africa/Algiers",
|
||||
|
@ -628,8 +628,7 @@ const char* const kTimeZoneNames[] = {
|
|||
"W-SU",
|
||||
"WET",
|
||||
"Zulu",
|
||||
nullptr
|
||||
};
|
||||
nullptr};
|
||||
|
||||
// Helper to return a loaded time zone by value (UTC on error).
|
||||
time_zone LoadZone(const std::string& name) {
|
||||
|
@ -724,7 +723,8 @@ TEST(TimeZone, NamedTimeZones) {
|
|||
EXPECT_EQ("America/New_York", nyc.name());
|
||||
const time_zone syd = LoadZone("Australia/Sydney");
|
||||
EXPECT_EQ("Australia/Sydney", syd.name());
|
||||
const time_zone fixed0 = fixed_time_zone(absl::time_internal::cctz::seconds::zero());
|
||||
const time_zone fixed0 =
|
||||
fixed_time_zone(absl::time_internal::cctz::seconds::zero());
|
||||
EXPECT_EQ("UTC", fixed0.name());
|
||||
const time_zone fixed_pos = fixed_time_zone(
|
||||
chrono::hours(3) + chrono::minutes(25) + chrono::seconds(45));
|
||||
|
@ -767,7 +767,8 @@ TEST(TimeZone, Equality) {
|
|||
EXPECT_EQ(implicit_utc, explicit_utc);
|
||||
EXPECT_EQ(implicit_utc.name(), explicit_utc.name());
|
||||
|
||||
const time_zone fixed_zero = fixed_time_zone(absl::time_internal::cctz::seconds::zero());
|
||||
const time_zone fixed_zero =
|
||||
fixed_time_zone(absl::time_internal::cctz::seconds::zero());
|
||||
EXPECT_EQ(fixed_zero, LoadZone(fixed_zero.name()));
|
||||
EXPECT_EQ(fixed_zero, explicit_utc);
|
||||
|
||||
|
@ -806,8 +807,8 @@ TEST(TimeZone, Equality) {
|
|||
TEST(StdChronoTimePoint, TimeTAlignment) {
|
||||
// Ensures that the Unix epoch and the system clock epoch are an integral
|
||||
// number of seconds apart. This simplifies conversions to/from time_t.
|
||||
auto diff = chrono::system_clock::time_point() -
|
||||
chrono::system_clock::from_time_t(0);
|
||||
auto diff =
|
||||
chrono::system_clock::time_point() - chrono::system_clock::from_time_t(0);
|
||||
EXPECT_EQ(chrono::system_clock::time_point::duration::zero(),
|
||||
diff % chrono::seconds(1));
|
||||
}
|
||||
|
@ -816,20 +817,20 @@ TEST(BreakTime, TimePointResolution) {
|
|||
const time_zone utc = utc_time_zone();
|
||||
const auto t0 = chrono::system_clock::from_time_t(0);
|
||||
|
||||
ExpectTime(chrono::time_point_cast<chrono::nanoseconds>(t0), utc,
|
||||
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
|
||||
ExpectTime(chrono::time_point_cast<chrono::microseconds>(t0), utc,
|
||||
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
|
||||
ExpectTime(chrono::time_point_cast<chrono::milliseconds>(t0), utc,
|
||||
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
|
||||
ExpectTime(chrono::time_point_cast<chrono::seconds>(t0), utc,
|
||||
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
|
||||
ExpectTime(chrono::time_point_cast<absl::time_internal::cctz::seconds>(t0), utc,
|
||||
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
|
||||
ExpectTime(chrono::time_point_cast<chrono::minutes>(t0), utc,
|
||||
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
|
||||
ExpectTime(chrono::time_point_cast<chrono::hours>(t0), utc,
|
||||
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
|
||||
ExpectTime(chrono::time_point_cast<chrono::nanoseconds>(t0), utc, 1970, 1, 1,
|
||||
0, 0, 0, 0, false, "UTC");
|
||||
ExpectTime(chrono::time_point_cast<chrono::microseconds>(t0), utc, 1970, 1, 1,
|
||||
0, 0, 0, 0, false, "UTC");
|
||||
ExpectTime(chrono::time_point_cast<chrono::milliseconds>(t0), utc, 1970, 1, 1,
|
||||
0, 0, 0, 0, false, "UTC");
|
||||
ExpectTime(chrono::time_point_cast<chrono::seconds>(t0), utc, 1970, 1, 1, 0,
|
||||
0, 0, 0, false, "UTC");
|
||||
ExpectTime(chrono::time_point_cast<absl::time_internal::cctz::seconds>(t0),
|
||||
utc, 1970, 1, 1, 0, 0, 0, 0, false, "UTC");
|
||||
ExpectTime(chrono::time_point_cast<chrono::minutes>(t0), utc, 1970, 1, 1, 0,
|
||||
0, 0, 0, false, "UTC");
|
||||
ExpectTime(chrono::time_point_cast<chrono::hours>(t0), utc, 1970, 1, 1, 0, 0,
|
||||
0, 0, false, "UTC");
|
||||
}
|
||||
|
||||
TEST(BreakTime, LocalTimeInUTC) {
|
||||
|
@ -911,8 +912,7 @@ TEST(MakeTime, TimePointResolution) {
|
|||
chrono::time_point_cast<chrono::minutes>(
|
||||
convert(civil_second(2015, 1, 2, 3, 4, 5), utc));
|
||||
EXPECT_EQ("04:00", format("%M:%E*S", tp_m, utc));
|
||||
const time_point<chrono::hours> tp_h =
|
||||
chrono::time_point_cast<chrono::hours>(
|
||||
const time_point<chrono::hours> tp_h = chrono::time_point_cast<chrono::hours>(
|
||||
convert(civil_second(2015, 1, 2, 3, 4, 5), utc));
|
||||
EXPECT_EQ("00:00", format("%M:%E*S", tp_h, utc));
|
||||
}
|
||||
|
@ -1030,8 +1030,7 @@ TEST(MakeTime, LocalTimeLibC) {
|
|||
const auto lc = LoadZone("libc:localtime");
|
||||
time_zone::civil_transition trans;
|
||||
for (auto tp = zi.lookup(civil_second()).trans;
|
||||
zi.next_transition(tp, &trans);
|
||||
tp = zi.lookup(trans.to).trans) {
|
||||
zi.next_transition(tp, &trans); tp = zi.lookup(trans.to).trans) {
|
||||
const auto fcl = zi.lookup(trans.from);
|
||||
const auto tcl = zi.lookup(trans.to);
|
||||
civil_second cs; // compare cs in zi and lc
|
||||
|
@ -1433,4 +1432,5 @@ TEST(TimeZoneEdgeCase, UTC5DigitYear) {
|
|||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
|
@ -152,4 +155,5 @@ bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res) {
|
|||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
|
|
@ -55,7 +55,10 @@
|
|||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
|
@ -123,6 +126,7 @@ bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res);
|
|||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
#define TZDEFRULES "posixrules"
|
||||
#endif /* !defined TZDEFRULES */
|
||||
|
||||
|
||||
/* See Internet RFC 8536 for more details about the following format. */
|
||||
|
||||
/*
|
||||
|
|
|
@ -14,7 +14,10 @@
|
|||
|
||||
#include "absl/time/internal/cctz/include/cctz/zone_info_source.h"
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
|
@ -24,9 +27,11 @@ std::string ZoneInfoSource::Version() const { return std::string(); }
|
|||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz_extension {
|
||||
|
||||
|
@ -36,7 +41,8 @@ namespace {
|
|||
// defers to the fallback factory.
|
||||
std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource> DefaultFactory(
|
||||
const std::string& name,
|
||||
const std::function<std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource>(
|
||||
const std::function<
|
||||
std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource>(
|
||||
const std::string& name)>& fallback_factory) {
|
||||
return fallback_factory(name);
|
||||
}
|
||||
|
@ -53,8 +59,8 @@ std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource> DefaultFactory(
|
|||
// Windows linker cannot handle that. Nor does the MinGW compiler know how to
|
||||
// pass "#pragma comment(linker, ...)" to the Windows linker.
|
||||
#if (__has_attribute(weak) || defined(__GNUC__)) && !defined(__MINGW32__)
|
||||
ZoneInfoSourceFactory zone_info_source_factory
|
||||
__attribute__((weak)) = DefaultFactory;
|
||||
ZoneInfoSourceFactory zone_info_source_factory __attribute__((weak)) =
|
||||
DefaultFactory;
|
||||
#elif defined(_MSC_VER) && !defined(__MINGW32__) && !defined(_LIBCPP_VERSION)
|
||||
extern ZoneInfoSourceFactory zone_info_source_factory;
|
||||
extern ZoneInfoSourceFactory default_factory;
|
||||
|
@ -77,4 +83,5 @@ ZoneInfoSourceFactory zone_info_source_factory = DefaultFactory;
|
|||
|
||||
} // namespace cctz_extension
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
|
Loading…
Reference in a new issue