Commit f340f773 by Abseil Team Committed by CJ Johnson

Export of internal Abseil changes.

--
906c47420646d510edd2479d5542c56f5fa31b65 by CJ Johnson <johnsoncj@google.com>:

Import of CCTZ from GitHub.

PiperOrigin-RevId: 216573923

--
74560d4afd2b605909e677c6fc3076049fb3010a by Eric Fiselier <ericwf@google.com>:

Avoid -Wformat-pedantic in benchmark.

PiperOrigin-RevId: 216523769

--
9bcc9da8b03e6d1ea43ee78931256c5541cb9686 by Eric Fiselier <ericwf@google.com>:

Delete unused CityHash functions.

PiperOrigin-RevId: 216464492

--
a42563b394c89fbb4c55cb5a6a5edbf96d271eea by Abseil Team <absl-team@google.com>:

Introduce new Abseil interfaces for converting between civil
times and absolute times.s

Deprecates absl::ConvertDateTime() and absl::FromDateTime().

PiperOrigin-RevId: 216424948

--
088e11235124267517d7f137854fa5554679c24f by Eric Fiselier <ericwf@google.com>:

Remove unneeded break statements in test.

PiperOrigin-RevId: 216403321
GitOrigin-RevId: 906c47420646d510edd2479d5542c56f5fa31b65
Change-Id: Idb44420be623e369c66f5a9c92bdc9ab46d3ec92
parent 445998d7
......@@ -1029,7 +1029,6 @@ ExpectedStats XorSeedExpectedStats() {
{{0.95, 0.1}},
{{0.95, 0}, {0.99, 2}, {0.999, 4}, {0.9999, 10}}};
}
break;
case 16:
if (kRandomizesInserts) {
return {0.1,
......@@ -1042,10 +1041,8 @@ ExpectedStats XorSeedExpectedStats() {
{{0.95, 0.05}},
{{0.95, 0}, {0.99, 1}, {0.999, 4}, {0.9999, 10}}};
}
break;
default:
ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width");
}
ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width");
return {};
}
TEST(Table, DISABLED_EnsureNonQuadraticTopNXorSeedByProbeSeqLength) {
......@@ -1125,7 +1122,6 @@ ExpectedStats LinearTransformExpectedStats() {
{{0.95, 0.3}},
{{0.95, 0}, {0.99, 3}, {0.999, 15}, {0.9999, 25}}};
}
break;
case 16:
if (kRandomizesInserts) {
return {0.1,
......@@ -1138,10 +1134,8 @@ ExpectedStats LinearTransformExpectedStats() {
{{0.95, 0.1}},
{{0.95, 0}, {0.99, 1}, {0.999, 6}, {0.9999, 10}}};
}
break;
default:
ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width");
}
ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width");
return {};
}
TEST(Table, DISABLED_EnsureNonQuadraticTopNLinearTransformByProbeSeqLength) {
......@@ -1834,18 +1828,15 @@ std::vector<std::pair<double, double>> StringTablePefectRatios() {
} else {
return {{0.995, 0.01}, {0.97, 0.01}, {0.89, 0.02}};
}
break;
case 16:
if (kRandomizesInserts) {
return {{0.973, 0.01}, {0.965, 0.01}, {0.92, 0.02}};
} else {
return {{0.995, 0.005}, {0.99, 0.005}, {0.94, 0.01}};
}
break;
default:
// Ignore anything else.
return {};
}
ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width");
return {};
}
// This is almost a change detector, but it allows us to know how we are
......@@ -1884,18 +1875,15 @@ std::vector<std::pair<double, double>> IntTablePefectRatios() {
} else {
return {{0.99, 0.01}, {0.99, 0.01}, {0.95, 0.02}};
}
break;
case 16:
if (kRandomizesInserts) {
return {{0.98, 0.02}, {0.978, 0.02}, {0.96, 0.02}};
} else {
return {{0.998, 0.003}, {0.995, 0.01}, {0.975, 0.02}};
}
break;
default:
// Ignore anything else.
return {};
}
ABSL_RAW_LOG(FATAL, "%s", "Unknown Group width");
return {};
}
// This is almost a change detector, but it allows us to know how we are
......
......@@ -93,7 +93,6 @@ cc_library(
srcs = ["internal/city.cc"],
hdrs = [
"internal/city.h",
"internal/city_crc.h",
],
copts = ABSL_DEFAULT_COPTS,
deps = [
......
......@@ -20,7 +20,6 @@ list(APPEND HASH_PUBLIC_HEADERS
list(APPEND HASH_INTERNAL_HEADERS
"internal/city.h"
"internal/city_crc.h"
"internal/hash.h"
)
......
......@@ -340,251 +340,5 @@ uint64_t CityHash64WithSeeds(const char *s, size_t len, uint64_t seed0,
return HashLen16(CityHash64(s, len) - seed0, seed1);
}
// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings
// of any length representable in signed long. Based on City and Murmur.
static uint128 CityMurmur(const char *s, size_t len, uint128 seed) {
uint64_t a = Uint128Low64(seed);
uint64_t b = Uint128High64(seed);
uint64_t c = 0;
uint64_t d = 0;
int64_t l = len - 16;
if (l <= 0) { // len <= 16
a = ShiftMix(a * k1) * k1;
c = b * k1 + HashLen0to16(s, len);
d = ShiftMix(a + (len >= 8 ? Fetch64(s) : c));
} else { // len > 16
c = HashLen16(Fetch64(s + len - 8) + k1, a);
d = HashLen16(b + len, c + Fetch64(s + len - 16));
a += d;
do {
a ^= ShiftMix(Fetch64(s) * k1) * k1;
a *= k1;
b ^= a;
c ^= ShiftMix(Fetch64(s + 8) * k1) * k1;
c *= k1;
d ^= c;
s += 16;
l -= 16;
} while (l > 0);
}
a = HashLen16(a, c);
b = HashLen16(d, b);
return uint128(a ^ b, HashLen16(b, a));
}
uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) {
if (len < 128) {
return CityMurmur(s, len, seed);
}
// We expect len >= 128 to be the common case. Keep 56 bytes of state:
// v, w, x, y, and z.
std::pair<uint64_t, uint64_t> v, w;
uint64_t x = Uint128Low64(seed);
uint64_t y = Uint128High64(seed);
uint64_t z = len * k1;
v.first = Rotate(y ^ k1, 49) * k1 + Fetch64(s);
v.second = Rotate(v.first, 42) * k1 + Fetch64(s + 8);
w.first = Rotate(y + z, 35) * k1 + x;
w.second = Rotate(x + Fetch64(s + 88), 53) * k1;
// This is the same inner loop as CityHash64(), manually unrolled.
do {
x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
x ^= w.second;
y += v.first + Fetch64(s + 40);
z = Rotate(z + w.first, 33) * k1;
v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
std::swap(z, x);
s += 64;
x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
x ^= w.second;
y += v.first + Fetch64(s + 40);
z = Rotate(z + w.first, 33) * k1;
v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
std::swap(z, x);
s += 64;
len -= 128;
} while (ABSL_PREDICT_TRUE(len >= 128));
x += Rotate(v.first + z, 49) * k0;
y = y * k0 + Rotate(w.second, 37);
z = z * k0 + Rotate(w.first, 27);
w.first *= 9;
v.first *= k0;
// If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
for (size_t tail_done = 0; tail_done < len;) {
tail_done += 32;
y = Rotate(x + y, 42) * k0 + v.second;
w.first += Fetch64(s + len - tail_done + 16);
x = x * k0 + w.first;
z += w.second + Fetch64(s + len - tail_done);
w.second += v.first;
v = WeakHashLen32WithSeeds(s + len - tail_done, v.first + z, v.second);
v.first *= k0;
}
// At this point our 56 bytes of state should contain more than
// enough information for a strong 128-bit hash. We use two
// different 56-byte-to-8-byte hashes to get a 16-byte final result.
x = HashLen16(x, v.first);
y = HashLen16(y + z, w.first);
return uint128(HashLen16(x + v.second, w.second) + y,
HashLen16(x + w.second, y + v.second));
}
uint128 CityHash128(const char *s, size_t len) {
return len >= 16
? CityHash128WithSeed(s + 16, len - 16,
uint128(Fetch64(s), Fetch64(s + 8) + k0))
: CityHash128WithSeed(s, len, uint128(k0, k1));
}
} // namespace hash_internal
} // namespace absl
#ifdef __SSE4_2__
#include <nmmintrin.h>
#include "absl/hash/internal/city_crc.h"
namespace absl {
namespace hash_internal {
// Requires len >= 240.
static void CityHashCrc256Long(const char *s, size_t len, uint32_t seed,
uint64_t *result) {
uint64_t a = Fetch64(s + 56) + k0;
uint64_t b = Fetch64(s + 96) + k0;
uint64_t c = result[0] = HashLen16(b, len);
uint64_t d = result[1] = Fetch64(s + 120) * k0 + len;
uint64_t e = Fetch64(s + 184) + seed;
uint64_t f = 0;
uint64_t g = 0;
uint64_t h = c + d;
uint64_t x = seed;
uint64_t y = 0;
uint64_t z = 0;
// 240 bytes of input per iter.
size_t iters = len / 240;
len -= iters * 240;
do {
#undef CHUNK
#define CHUNK(r) \
PERMUTE3(x, z, y); \
b += Fetch64(s); \
c += Fetch64(s + 8); \
d += Fetch64(s + 16); \
e += Fetch64(s + 24); \
f += Fetch64(s + 32); \
a += b; \
h += f; \
b += c; \
f += d; \
g += e; \
e += z; \
g += x; \
z = _mm_crc32_u64(z, b + g); \
y = _mm_crc32_u64(y, e + h); \
x = _mm_crc32_u64(x, f + a); \
e = Rotate(e, r); \
c += e; \
s += 40
CHUNK(0);
PERMUTE3(a, h, c);
CHUNK(33);
PERMUTE3(a, h, f);
CHUNK(0);
PERMUTE3(b, h, f);
CHUNK(42);
PERMUTE3(b, h, d);
CHUNK(0);
PERMUTE3(b, h, e);
CHUNK(33);
PERMUTE3(a, h, e);
} while (--iters > 0);
while (len >= 40) {
CHUNK(29);
e ^= Rotate(a, 20);
h += Rotate(b, 30);
g ^= Rotate(c, 40);
f += Rotate(d, 34);
PERMUTE3(c, h, g);
len -= 40;
}
if (len > 0) {
s = s + len - 40;
CHUNK(33);
e ^= Rotate(a, 43);
h += Rotate(b, 42);
g ^= Rotate(c, 41);
f += Rotate(d, 40);
}
result[0] ^= h;
result[1] ^= g;
g += h;
a = HashLen16(a, g + z);
x += y << 32;
b += x;
c = HashLen16(c, z) + h;
d = HashLen16(d, e + result[0]);
g += e;
h += HashLen16(x, f);
e = HashLen16(a, d) + g;
z = HashLen16(b, c) + a;
y = HashLen16(g, h) + c;
result[0] = e + z + y + x;
a = ShiftMix((a + y) * k0) * k0 + b;
result[1] += a + result[0];
a = ShiftMix(a * k0) * k0 + c;
result[2] = a + result[1];
a = ShiftMix((a + e) * k0) * k0;
result[3] = a + result[2];
}
// Requires len < 240.
static void CityHashCrc256Short(const char *s, size_t len, uint64_t *result) {
char buf[240];
memcpy(buf, s, len);
memset(buf + len, 0, 240 - len);
CityHashCrc256Long(buf, 240, ~static_cast<uint32_t>(len), result);
}
void CityHashCrc256(const char *s, size_t len, uint64_t *result) {
if (ABSL_PREDICT_TRUE(len >= 240)) {
CityHashCrc256Long(s, len, 0, result);
} else {
CityHashCrc256Short(s, len, result);
}
}
uint128 CityHashCrc128WithSeed(const char *s, size_t len, uint128 seed) {
if (len <= 900) {
return CityHash128WithSeed(s, len, seed);
} else {
uint64_t result[4];
CityHashCrc256(s, len, result);
uint64_t u = Uint128High64(seed) + result[0];
uint64_t v = Uint128Low64(seed) + result[1];
return uint128(HashLen16(u, v + result[2]),
HashLen16(Rotate(v, 32), u * k0 + result[3]));
}
}
uint128 CityHashCrc128(const char *s, size_t len) {
if (len <= 900) {
return CityHash128(s, len);
} else {
uint64_t result[4];
CityHashCrc256(s, len, result);
return uint128(result[2], result[3]);
}
}
} // namespace hash_internal
} // namespace absl
#endif
......@@ -23,15 +23,6 @@
// is Murmur3. For 64-bit x86 code, CityHash64 is an excellent choice for hash
// tables and most other hashing (excluding cryptography).
//
// For 64-bit x86 code, on long strings, the picture is more complicated.
// On many recent Intel CPUs, such as Nehalem, Westmere, Sandy Bridge, etc.,
// CityHashCrc128 appears to be faster than all competitors of comparable
// quality. CityHash128 is also good but not quite as fast. We believe our
// nearest competitor is Bob Jenkins' Spooky. We don't have great data for
// other 64-bit CPUs, but for long strings we know that Spooky is slightly
// faster than CityHash on some relatively recent AMD x86-64 CPUs, for example.
// Note that CityHashCrc128 is declared in citycrc.h.
//
// For 32-bit x86 code, we don't know of anything faster than CityHash32 that
// is of comparable quality. We believe our nearest competitor is Murmur3A.
// (On 64-bit CPUs, it is typically faster to use the other CityHash variants.)
......@@ -79,13 +70,6 @@ uint64_t CityHash64WithSeed(const char *s, size_t len, uint64_t seed);
uint64_t CityHash64WithSeeds(const char *s, size_t len, uint64_t seed0,
uint64_t seed1);
// Hash function for a byte array.
uint128 CityHash128(const char *s, size_t len);
// Hash function for a byte array. For convenience, a 128-bit seed is also
// hashed into the result.
uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed);
// Hash function for a byte array. Most useful in 32-bit binaries.
uint32_t CityHash32(const char *s, size_t len);
......
// 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
//
// 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.
//
// This file declares the subset of the CityHash functions that require
// _mm_crc32_u64(). See the CityHash README for details.
//
// Functions in the CityHash family are not suitable for cryptography.
#ifndef ABSL_HASH_INTERNAL_CITY_CRC_H_
#define ABSL_HASH_INTERNAL_CITY_CRC_H_
#include "absl/hash/internal/city.h"
namespace absl {
namespace hash_internal {
// Hash function for a byte array.
uint128 CityHashCrc128(const char *s, size_t len);
// Hash function for a byte array. For convenience, a 128-bit seed is also
// hashed into the result.
uint128 CityHashCrc128WithSeed(const char *s, size_t len, uint128 seed);
// Hash function for a byte array. Sets result[0] ... result[3].
void CityHashCrc256(const char *s, size_t len, uint64_t *result);
} // namespace hash_internal
} // namespace absl
#endif // ABSL_HASH_INTERNAL_CITY_CRC_H_
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -605,35 +605,21 @@ TEST_F(ParsedFormatTest, RegressionMixPositional) {
// Some codegen thunks that we can use to easily dump the generated assembly for
// different StrFormat calls.
inline std::string CodegenAbslStrFormatInt(int i) {
std::string CodegenAbslStrFormatInt(int i) { // NOLINT
return absl::StrFormat("%d", i);
}
inline std::string CodegenAbslStrFormatIntStringInt64(int i, const std::string& s,
int64_t i64) {
std::string CodegenAbslStrFormatIntStringInt64(int i, const std::string& s,
int64_t i64) { // NOLINT
return absl::StrFormat("%d %s %d", i, s, i64);
}
inline void CodegenAbslStrAppendFormatInt(std::string* out, int i) {
void CodegenAbslStrAppendFormatInt(std::string* out, int i) { // NOLINT
absl::StrAppendFormat(out, "%d", i);
}
inline void CodegenAbslStrAppendFormatIntStringInt64(std::string* out, int i,
void CodegenAbslStrAppendFormatIntStringInt64(std::string* out, int i,
const std::string& s,
int64_t i64) {
int64_t i64) { // NOLINT
absl::StrAppendFormat(out, "%d %s %d", i, s, i64);
}
auto absl_internal_str_format_force_codegen_funcs = std::make_tuple(
CodegenAbslStrFormatInt, CodegenAbslStrFormatIntStringInt64,
CodegenAbslStrAppendFormatInt, CodegenAbslStrAppendFormatIntStringInt64);
bool absl_internal_str_format_force_codegen_always_false;
// Force the compiler to generate the functions by making it look like we
// escape the function pointers.
// It can't statically know that
// absl_internal_str_format_force_codegen_always_false is not changed by someone
// else.
bool absl_internal_str_format_force_codegen =
absl_internal_str_format_force_codegen_always_false &&
printf("%p", &absl_internal_str_format_force_codegen_funcs) == 0;
......@@ -27,6 +27,7 @@ licenses(["notice"]) # Apache 2.0
cc_library(
name = "time",
srcs = [
"civil_time.cc",
"clock.cc",
"duration.cc",
"format.cc",
......@@ -35,6 +36,7 @@ cc_library(
"time.cc",
],
hdrs = [
"civil_time.h",
"clock.h",
"time.h",
],
......@@ -72,10 +74,10 @@ cc_library(
cc_test(
name = "time_test",
srcs = [
"civil_time_test.cc",
"clock_test.cc",
"duration_test.cc",
"format_test.cc",
"time_norm_test.cc",
"time_test.cc",
"time_zone_test.cc",
],
......@@ -94,6 +96,7 @@ cc_test(
cc_test(
name = "time_benchmark",
srcs = [
"civil_time_benchmark.cc",
"clock_benchmark.cc",
"duration_benchmark.cc",
"format_benchmark.cc",
......
......@@ -15,6 +15,7 @@
#
list(APPEND TIME_PUBLIC_HEADERS
"civil_time.h"
"clock.h"
"time.h"
)
......@@ -29,6 +30,7 @@ list(APPEND TIME_INTERNAL_HEADERS
)
list(APPEND TIME_SRC
"civil_time.cc"
"time.cc"
"clock.cc"
"duration.cc"
......@@ -74,11 +76,11 @@ absl_library(
# test time_test
list(APPEND TIME_TEST_SRC
"civil_time_test.cc"
"time_test.cc"
"clock_test.cc"
"duration_test.cc"
"format_test.cc"
"time_norm_test.cc"
"time_test.cc"
"time_zone_test.cc"
"internal/test_util.cc"
......
// 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
//
// 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 "absl/time/civil_time.h"
#include <cstdlib>
#include <string>
#include "absl/strings/str_cat.h"
#include "absl/time/time.h"
namespace absl {
namespace {
// Since a civil time has a larger year range than absl::Time (64-bit years vs
// 64-bit seconds, respectively) we normalize years to roughly +/- 400 years
// around the year 2400, which will produce an equivalent year in a range that
// absl::Time can handle.
inline civil_year_t NormalizeYear(civil_year_t year) {
return 2400 + year % 400;
}
// Formats the given CivilSecond according to the given format.
std::string FormatYearAnd(string_view fmt, CivilSecond cs) {
const CivilSecond ncs(NormalizeYear(cs.year()), cs.month(), cs.day(),
cs.hour(), cs.minute(), cs.second());
const TimeZone utc = UTCTimeZone();
// TODO(absl-team): Avoid conversion of fmt std::string.
return StrCat(cs.year(), FormatTime(std::string(fmt), FromCivil(ncs, utc), utc));
}
} // namespace
std::string FormatCivilTime(CivilSecond c) {
return FormatYearAnd("-%m-%dT%H:%M:%S", c);
}
std::string FormatCivilTime(CivilMinute c) {
return FormatYearAnd("-%m-%dT%H:%M", c);
}
std::string FormatCivilTime(CivilHour c) {
return FormatYearAnd("-%m-%dT%H", c);
}
std::string FormatCivilTime(CivilDay c) {
return FormatYearAnd("-%m-%d", c);
}
std::string FormatCivilTime(CivilMonth c) {
return FormatYearAnd("-%m", c);
}
std::string FormatCivilTime(CivilYear c) {
return FormatYearAnd("", c);
}
namespace time_internal {
std::ostream& operator<<(std::ostream& os, CivilYear y) {
return os << FormatCivilTime(y);
}
std::ostream& operator<<(std::ostream& os, CivilMonth m) {
return os << FormatCivilTime(m);
}
std::ostream& operator<<(std::ostream& os, CivilDay d) {
return os << FormatCivilTime(d);
}
std::ostream& operator<<(std::ostream& os, CivilHour h) {
return os << FormatCivilTime(h);
}
std::ostream& operator<<(std::ostream& os, CivilMinute m) {
return os << FormatCivilTime(m);
}
std::ostream& operator<<(std::ostream& os, CivilSecond s) {
return os << FormatCivilTime(s);
}
} // namespace time_internal
} // namespace absl
// 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
//
// 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 "absl/time/civil_time.h"
#include "benchmark/benchmark.h"
namespace {
// Benchmark Time(ns) CPU(ns) Iterations
// -------------------------------------------------------------------------
// BM_Difference_Days 20 20 34542508
// BM_Step_Days 15 15 48098146
// BM_Format 688 687 1019803
// BM_Parse 921 920 762788
// BM_RoundTripFormatParse 1766 1764 396092
void BM_Difference_Days(benchmark::State& state) {
const absl::CivilDay c(2014, 8, 22);
const absl::CivilDay epoch(1970, 1, 1);
while (state.KeepRunning()) {
const absl::civil_diff_t n = c - epoch;
benchmark::DoNotOptimize(n);
}
}
BENCHMARK(BM_Difference_Days);
void BM_Step_Days(benchmark::State& state) {
const absl::CivilDay kStart(2014, 8, 22);
absl::CivilDay c = kStart;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(++c);
}
}
BENCHMARK(BM_Step_Days);
void BM_Format(benchmark::State& state) {
const absl::CivilSecond c(2014, 1, 2, 3, 4, 5);
while (state.KeepRunning()) {
const std::string s = absl::FormatCivilTime(c);
benchmark::DoNotOptimize(s);
}
}
BENCHMARK(BM_Format);
} // namespace
......@@ -38,7 +38,8 @@ void BM_Format_FormatTime(benchmark::State& state) {
const absl::TimeZone lax =
absl::time_internal::LoadTimeZone("America/Los_Angeles");
const absl::Time t =
absl::FromDateTime(1977, 6, 28, 9, 8, 7, lax) + absl::Nanoseconds(1);
absl::FromCivil(absl::CivilSecond(1977, 6, 28, 9, 8, 7), lax) +
absl::Nanoseconds(1);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::FormatTime(fmt, t, lax).length());
}
......@@ -50,8 +51,8 @@ void BM_Format_ParseTime(benchmark::State& state) {
state.SetLabel(fmt);
const absl::TimeZone lax =
absl::time_internal::LoadTimeZone("America/Los_Angeles");
absl::Time t =
absl::FromDateTime(1977, 6, 28, 9, 8, 7, lax) + absl::Nanoseconds(1);
absl::Time t = absl::FromCivil(absl::CivilSecond(1977, 6, 28, 9, 8, 7), lax) +
absl::Nanoseconds(1);
const std::string when = absl::FormatTime(fmt, t, lax);
std::string err;
while (state.KeepRunning()) {
......
......@@ -118,7 +118,7 @@ TEST(FormatTime, RFC1123FormatPadsYear) { // locale specific
absl::TimeZone tz = absl::UTCTimeZone();
// A year of 77 should be padded to 0077.
absl::Time t = absl::FromDateTime(77, 6, 28, 9, 8, 7, tz);
absl::Time t = absl::FromCivil(absl::CivilSecond(77, 6, 28, 9, 8, 7), tz);
EXPECT_EQ("Mon, 28 Jun 0077 09:08:07 +0000",
absl::FormatTime(absl::RFC1123_full, t, tz));
EXPECT_EQ("28 Jun 0077 09:08:07 +0000",
......@@ -154,9 +154,9 @@ TEST(ParseTime, Basics) {
EXPECT_TRUE(absl::ParseTime("%Y-%m-%d %H:%M:%S %z",
"2013-06-28 19:08:09 -0800", &t, &err))
<< err;
absl::Time::Breakdown bd = t.In(absl::FixedTimeZone(-8 * 60 * 60));
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -8 * 60 * 60, false);
EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
const auto ci = absl::FixedTimeZone(-8 * 60 * 60).At(t);
EXPECT_EQ(absl::CivilSecond(2013, 6, 28, 19, 8, 9), ci.cs);
EXPECT_EQ(absl::ZeroDuration(), ci.subsecond);
}
TEST(ParseTime, NullErrorString) {
......@@ -177,17 +177,17 @@ TEST(ParseTime, WithTimeZone) {
EXPECT_TRUE(
absl::ParseTime("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &t, &e))
<< e;
absl::Time::Breakdown bd = t.In(tz);
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true);
EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
auto ci = tz.At(t);
EXPECT_EQ(absl::CivilSecond(2013, 6, 28, 19, 8, 9), ci.cs);
EXPECT_EQ(absl::ZeroDuration(), ci.subsecond);
// But the timezone is ignored when a UTC offset is present.
EXPECT_TRUE(absl::ParseTime("%Y-%m-%d %H:%M:%S %z",
"2013-06-28 19:08:09 +0800", tz, &t, &e))
<< e;
bd = t.In(absl::FixedTimeZone(8 * 60 * 60));
ABSL_INTERNAL_EXPECT_TIME(bd, 2013, 6, 28, 19, 8, 9, 8 * 60 * 60, false);
EXPECT_EQ(absl::ZeroDuration(), bd.subsecond);
ci = absl::FixedTimeZone(8 * 60 * 60).At(t);
EXPECT_EQ(absl::CivilSecond(2013, 6, 28, 19, 8, 9), ci.cs);
EXPECT_EQ(absl::ZeroDuration(), ci.subsecond);
}
TEST(ParseTime, ErrorCases) {
......@@ -332,15 +332,15 @@ TEST(ParseTime, InfiniteTime) {
EXPECT_TRUE(absl::ParseTime("infinite-future %H:%M", "infinite-future 03:04",
&t, &err));
EXPECT_NE(absl::InfiniteFuture(), t);
EXPECT_EQ(3, t.In(tz).hour);
EXPECT_EQ(4, t.In(tz).minute);
EXPECT_EQ(3, tz.At(t).cs.hour());
EXPECT_EQ(4, tz.At(t).cs.minute());
// "infinite-past" as literal std::string
EXPECT_TRUE(
absl::ParseTime("infinite-past %H:%M", "infinite-past 03:04", &t, &err));
EXPECT_NE(absl::InfinitePast(), t);
EXPECT_EQ(3, t.In(tz).hour);
EXPECT_EQ(4, t.In(tz).minute);
EXPECT_EQ(3, tz.At(t).cs.hour());
EXPECT_EQ(4, tz.At(t).cs.minute());
// The input doesn't match the format.
EXPECT_FALSE(absl::ParseTime("infinite-future %H:%M", "03:04", &t, &err));
......@@ -365,16 +365,17 @@ TEST(ParseTime, FailsOnUnrepresentableTime) {
//
TEST(FormatParse, RoundTrip) {
const absl::TimeZone gst =
const absl::TimeZone lax =
absl::time_internal::LoadTimeZone("America/Los_Angeles");
const absl::Time in = absl::FromDateTime(1977, 6, 28, 9, 8, 7, gst);
const absl::Time in =
absl::FromCivil(absl::CivilSecond(1977, 6, 28, 9, 8, 7), lax);
const absl::Duration subseconds = absl::Nanoseconds(654321);
std::string err;
// RFC3339, which renders subseconds.
{
absl::Time out;
const std::string s = absl::FormatTime(absl::RFC3339_full, in + subseconds, gst);
const std::string s = absl::FormatTime(absl::RFC3339_full, in + subseconds, lax);
EXPECT_TRUE(absl::ParseTime(absl::RFC3339_full, s, &out, &err))
<< s << ": " << err;
EXPECT_EQ(in + subseconds, out); // RFC3339_full includes %Ez
......@@ -383,7 +384,7 @@ TEST(FormatParse, RoundTrip) {
// RFC1123, which only does whole seconds.
{
absl::Time out;
const std::string s = absl::FormatTime(absl::RFC1123_full, in, gst);
const std::string s = absl::FormatTime(absl::RFC1123_full, in, lax);
EXPECT_TRUE(absl::ParseTime(absl::RFC1123_full, s, &out, &err))
<< s << ": " << err;
EXPECT_EQ(in, out); // RFC1123_full includes %z
......
......@@ -68,25 +68,35 @@ namespace cctz {
// it would take us to another day, and perhaps week, or even month.
struct PosixTransition {
enum DateFormat { J, N, M };
struct {
DateFormat fmt;
union {
struct {
struct Date {
struct NonLeapDay {
std::int_fast16_t day; // day of non-leap year [1:365]
} j;
struct {
};
struct Day {
std::int_fast16_t day; // day of year [0:365]
} n;
struct {
};
struct MonthWeekWeekday {
std::int_fast8_t month; // month of year [1:12]
std::int_fast8_t week; // week of month [1:5] (5==last)
std::int_fast8_t weekday; // 0==Sun, ..., 6=Sat
} m;
};
} date;
struct {
DateFormat fmt;
union {
NonLeapDay j;
Day n;
MonthWeekWeekday m;
};
};
struct Time {
std::int_fast32_t offset; // seconds before/after 00:00:00
} time;
};
Date date;
Time time;
};
// The entirety of a POSIX-string specified time-zone rule. The standard
......
......@@ -26,12 +26,6 @@ namespace cctz = absl::time_internal::cctz;
namespace absl {
namespace time_internal {
#if GTEST_USES_SIMPLE_RE
extern const char kZoneAbbrRE[] = ".*"; // just punt
#else
extern const char kZoneAbbrRE[] = "[A-Za-z]{3,4}|[-+][0-9]{2}([0-9]{2})?";
#endif
TimeZone LoadTimeZone(const std::string& name) {
TimeZone tz;
ABSL_RAW_CHECK(LoadTimeZone(name, &tz), name.c_str());
......
......@@ -17,35 +17,11 @@
#include <string>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/time/time.h"
// This helper is a macro so that failed expectations show up with the
// correct line numbers.
//
// This is for internal testing of the Base Time library itself. This is not
// part of a public API.
#define ABSL_INTERNAL_EXPECT_TIME(bd, y, m, d, h, min, s, off, isdst) \
do { \
EXPECT_EQ(y, bd.year); \
EXPECT_EQ(m, bd.month); \
EXPECT_EQ(d, bd.day); \
EXPECT_EQ(h, bd.hour); \
EXPECT_EQ(min, bd.minute); \
EXPECT_EQ(s, bd.second); \
EXPECT_EQ(off, bd.offset); \
EXPECT_EQ(isdst, bd.is_dst); \
EXPECT_THAT(bd.zone_abbr, \
testing::MatchesRegex(absl::time_internal::kZoneAbbrRE)); \
} while (0)
namespace absl {
namespace time_internal {
// A regular expression that matches all zone abbreviations (%Z).
extern const char kZoneAbbrRE[];
// Loads the named timezone, but dies on any failure.
absl::TimeZone LoadTimeZone(const std::string& name);
......
......@@ -169,32 +169,32 @@ void BM_Time_ToUnixSeconds(benchmark::State& state) {
BENCHMARK(BM_Time_ToUnixSeconds);
//
// FromDateTime
// FromCivil
//
// In each "FromDateTime" benchmark we switch between two YMDhms
// values separated by at least one transition in order to defeat any
// internal caching of previous results (e.g., see time_local_hint_).
// In each "FromCivil" benchmark we switch between two YMDhms values
// separated by at least one transition in order to defeat any internal
// caching of previous results (e.g., see time_local_hint_).
//
// The "UTC" variants use UTC instead of the Google/local time zone.
// The "Day0" variants require normalization of the day of month.
//
void BM_Time_FromDateTime_Absl(benchmark::State& state) {
void BM_Time_FromCivil_Absl(benchmark::State& state) {
const absl::TimeZone tz =
absl::time_internal::LoadTimeZone("America/Los_Angeles");
int i = 0;
while (state.KeepRunning()) {
if ((i & 1) == 0) {
absl::FromDateTime(2014, 12, 18, 20, 16, 18, tz);
absl::FromCivil(absl::CivilSecond(2014, 12, 18, 20, 16, 18), tz);
} else {
absl::FromDateTime(2013, 11, 15, 18, 30, 27, tz);
absl::FromCivil(absl::CivilSecond(2013, 11, 15, 18, 30, 27), tz);
}
++i;
}
}
BENCHMARK(BM_Time_FromDateTime_Absl);
BENCHMARK(BM_Time_FromCivil_Absl);
void BM_Time_FromDateTime_Libc(benchmark::State& state) {
void BM_Time_FromCivil_Libc(benchmark::State& state) {
// No timezone support, so just use localtime.
int i = 0;
while (state.KeepRunning()) {
......@@ -219,32 +219,32 @@ void BM_Time_FromDateTime_Libc(benchmark::State& state) {
++i;
}
}
BENCHMARK(BM_Time_FromDateTime_Libc);
BENCHMARK(BM_Time_FromCivil_Libc);
void BM_Time_FromDateTimeUTC_Absl(benchmark::State& state) {
void BM_Time_FromCivilUTC_Absl(benchmark::State& state) {
const absl::TimeZone tz = absl::UTCTimeZone();
while (state.KeepRunning()) {
FromDateTime(2014, 12, 18, 20, 16, 18, tz);
absl::FromCivil(absl::CivilSecond(2014, 12, 18, 20, 16, 18), tz);
}
}
BENCHMARK(BM_Time_FromDateTimeUTC_Absl);
BENCHMARK(BM_Time_FromCivilUTC_Absl);
void BM_Time_FromDateTimeDay0_Absl(benchmark::State& state) {
void BM_Time_FromCivilDay0_Absl(benchmark::State& state) {
const absl::TimeZone tz =
absl::time_internal::LoadTimeZone("America/Los_Angeles");
int i = 0;
while (state.KeepRunning()) {
if ((i & 1) == 0) {
absl::FromDateTime(2014, 12, 0, 20, 16, 18, tz);
absl::FromCivil(absl::CivilSecond(2014, 12, 0, 20, 16, 18), tz);
} else {
absl::FromDateTime(2013, 11, 0, 18, 30, 27, tz);
absl::FromCivil(absl::CivilSecond(2013, 11, 0, 18, 30, 27), tz);
}
++i;
}
}
BENCHMARK(BM_Time_FromDateTimeDay0_Absl);
BENCHMARK(BM_Time_FromCivilDay0_Absl);
void BM_Time_FromDateTimeDay0_Libc(benchmark::State& state) {
void BM_Time_FromCivilDay0_Libc(benchmark::State& state) {
// No timezone support, so just use localtime.
int i = 0;
while (state.KeepRunning()) {
......@@ -269,7 +269,7 @@ void BM_Time_FromDateTimeDay0_Libc(benchmark::State& state) {
++i;
}
}
BENCHMARK(BM_Time_FromDateTimeDay0_Libc);
BENCHMARK(BM_Time_FromCivilDay0_Libc);
//
// To/FromTimespec
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment