Export of internal Abseil changes

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

Support int128 in SimpleAtoi.

PiperOrigin-RevId: 337946262

--
0be53049ccf8309650e4e22f23b290e5f75ee828 by Gennadiy Rozental <rogeeff@google.com>:

Update build scripts to use --mount instead of --volume to mount the host data into a container.

This is somewhat more verbose, but more readable and flexible. More importantly this is what docker documentation is recomending to use now.

PiperOrigin-RevId: 337898761

--
3bc877f1679fdf61ecbf4365287a0403cfc9b53e by Samuel Benzaquen <sbenza@google.com>:

Add Cord constructor for constinit instances.

PiperOrigin-RevId: 337871148

--
8b87701892b9c325e78ad4e8e4f16b785a744622 by Chris Kennelly <ckennelly@google.com>:

Use the address of kSeed, rather than its value.

We initialize kSeed with &kSeed, so these are equivalent, but kSeed requires a
load from memory while &kSeed can be formed as a RIP-relative lea.

PiperOrigin-RevId: 337868415
GitOrigin-RevId: 77c85460dc3c46593b231c5161ac55273bb0c7ef
Change-Id: I3d06c18a123f1be29dad5801e8625952dc41cd95
pull/827/head
Abseil Team 4 years ago committed by Gennadiy Rozental
parent 8f1c34a77a
commit 4b915e7092
  1. 1
      CMake/AbseilDll.cmake
  2. 7
      absl/hash/internal/hash.h
  3. 14
      absl/strings/BUILD.bazel
  4. 14
      absl/strings/CMakeLists.txt
  5. 2
      absl/strings/cord.cc
  6. 26
      absl/strings/cord.h
  7. 82
      absl/strings/cord_test.cc
  8. 82
      absl/strings/internal/cord_internal.h
  9. 70
      absl/strings/internal/string_constant.h
  10. 60
      absl/strings/internal/string_constant_test.cc
  11. 120
      absl/strings/numbers.cc
  12. 7
      absl/strings/numbers.h
  13. 76
      absl/strings/numbers_test.cc
  14. 2
      ci/cmake_install_test.sh
  15. 6
      ci/linux_clang-latest_libcxx_asan_bazel.sh
  16. 6
      ci/linux_clang-latest_libcxx_bazel.sh
  17. 6
      ci/linux_clang-latest_libcxx_tsan_bazel.sh
  18. 6
      ci/linux_clang-latest_libstdcxx_bazel.sh
  19. 6
      ci/linux_gcc-4.9_libstdcxx_bazel.sh
  20. 6
      ci/linux_gcc-latest_libstdcxx_bazel.sh
  21. 2
      ci/linux_gcc-latest_libstdcxx_cmake.sh
  22. 2
      ci/linux_gcc_alpine_cmake.sh

@ -196,6 +196,7 @@ set(ABSL_INTERNAL_DLL_FILES
"strings/internal/charconv_parse.cc"
"strings/internal/charconv_parse.h"
"strings/internal/stl_type_traits.h"
"strings/internal/string_constant.h"
"strings/match.cc"
"strings/match.h"
"strings/numbers.cc"

@ -855,7 +855,14 @@ class ABSL_DLL CityHashState
// On other platforms this is still going to be non-deterministic but most
// probably per-build and not per-process.
ABSL_ATTRIBUTE_ALWAYS_INLINE static uint64_t Seed() {
#if (!defined(__clang__) || __clang_major__ > 11) && \
!defined(__apple_build_version__)
return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(&kSeed));
#else
// Workaround the absence of
// https://github.com/llvm/llvm-project/commit/bc15bf66dcca76cc06fe71fca35b74dc4d521021.
return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(kSeed));
#endif
}
static const void* const kSeed;

@ -54,6 +54,7 @@ cc_library(
"ascii.h",
"charconv.h",
"escaping.h",
"internal/string_constant.h",
"match.h",
"numbers.h",
"str_cat.h",
@ -222,6 +223,19 @@ cc_test(
],
)
cc_test(
name = "string_constant_test",
size = "small",
srcs = ["internal/string_constant_test.cc"],
copts = ABSL_TEST_COPTS,
visibility = ["//visibility:private"],
deps = [
":strings",
"//absl/meta:type_traits",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "string_view_benchmark",
srcs = ["string_view_benchmark.cc"],

@ -21,6 +21,7 @@ absl_cc_library(
"ascii.h"
"charconv.h"
"escaping.h"
"internal/string_constant.h"
"match.h"
"numbers.h"
"str_cat.h"
@ -158,6 +159,19 @@ absl_cc_test(
gmock_main
)
absl_cc_test(
NAME
string_constant_test
SRCS
"internal/string_constant_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
absl::strings
absl::type_traits
gmock_main
)
absl_cc_test(
NAME
string_view_test

@ -241,6 +241,7 @@ static void UnrefInternal(CordRep* rep) {
absl::InlinedVector<CordRep*, kInlinedVectorSize> pending;
while (true) {
assert(!rep->refcount.IsImmortal());
if (rep->tag == CONCAT) {
CordRepConcat* rep_concat = rep->concat();
CordRep* right = rep_concat->right;
@ -256,6 +257,7 @@ static void UnrefInternal(CordRep* rep) {
}
} else if (rep->tag == EXTERNAL) {
CordRepExternal* rep_external = rep->external();
assert(rep_external->releaser_invoker != nullptr);
rep_external->releaser_invoker(rep_external);
rep = nullptr;
} else if (rep->tag == SUBSTRING) {

@ -79,6 +79,7 @@
#include "absl/meta/type_traits.h"
#include "absl/strings/internal/cord_internal.h"
#include "absl/strings/internal/resize_uninitialized.h"
#include "absl/strings/internal/string_constant.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
@ -624,6 +625,14 @@ class Cord {
return c.HashFragmented(std::move(hash_state));
}
// Create a Cord with the contents of StringConstant<T>::value.
// No allocations will be done and no data will be copied.
// This is an INTERNAL API and subject to change or removal. This API can only
// be used by spelling absl::strings_internal::MakeStringConstant, which is
// also an internal API.
template <typename T>
explicit constexpr Cord(strings_internal::StringConstant<T>);
private:
friend class CordTestPeer;
friend bool operator==(const Cord& lhs, const Cord& rhs);
@ -655,6 +664,8 @@ class Cord {
InlineRep& operator=(const InlineRep& src);
InlineRep& operator=(InlineRep&& src) noexcept;
explicit constexpr InlineRep(cord_internal::InlineData data);
void Swap(InlineRep* rhs);
bool empty() const;
size_t size() const;
@ -884,6 +895,9 @@ Cord MakeCordFromExternal(absl::string_view data, Releaser&& releaser) {
return cord;
}
constexpr Cord::InlineRep::InlineRep(cord_internal::InlineData data)
: data_(data) {}
inline Cord::InlineRep::InlineRep(const Cord::InlineRep& src) {
data_ = src.data_;
}
@ -981,6 +995,18 @@ inline void Cord::InlineRep::CopyToArray(char* dst) const {
constexpr inline Cord::Cord() noexcept {}
template <typename T>
constexpr Cord::Cord(strings_internal::StringConstant<T>)
: contents_(strings_internal::StringConstant<T>::value.size() <=
cord_internal::kMaxInline
? cord_internal::InlineData(
strings_internal::StringConstant<T>::value)
: cord_internal::InlineData(cord_internal::AsTree{
&cord_internal::ConstInitExternalStorage<
strings_internal::StringConstant<T>>::value,
{},
cord_internal::kTreeFlag})) {}
inline Cord& Cord::operator=(const Cord& x) {
contents_ = x.contents_;
return *this;

@ -181,6 +181,8 @@ class CordTestPeer {
const Cord& c, absl::FunctionRef<void(absl::string_view)> callback) {
c.ForEachChunk(callback);
}
static bool IsTree(const Cord& c) { return c.contents_.is_tree(); }
};
ABSL_NAMESPACE_END
@ -1627,3 +1629,83 @@ TEST(CordDeathTest, Hardening) {
EXPECT_DEATH_IF_SUPPORTED(static_cast<void>(cord.chunk_end()->empty()), "");
EXPECT_DEATH_IF_SUPPORTED(++cord.chunk_end(), "");
}
class AfterExitCordTester {
public:
bool Set(absl::Cord* cord, absl::string_view expected) {
cord_ = cord;
expected_ = expected;
return true;
}
~AfterExitCordTester() {
EXPECT_EQ(*cord_, expected_);
}
private:
absl::Cord* cord_;
absl::string_view expected_;
};
template <typename Str>
void TestConstinitConstructor(Str) {
const auto expected = Str::value;
// Defined before `cord` to be destroyed after it.
static AfterExitCordTester exit_tester; // NOLINT
ABSL_CONST_INIT static absl::Cord cord(Str{}); // NOLINT
static bool init_exit_tester = exit_tester.Set(&cord, expected);
(void)init_exit_tester;
EXPECT_EQ(cord, expected);
// Copy the object and test the copy, and the original.
{
absl::Cord copy = cord;
EXPECT_EQ(copy, expected);
}
// The original still works
EXPECT_EQ(cord, expected);
// Try making adding more structure to the tree.
{
absl::Cord copy = cord;
std::string expected_copy(expected);
for (int i = 0; i < 10; ++i) {
copy.Append(cord);
absl::StrAppend(&expected_copy, expected);
EXPECT_EQ(copy, expected_copy);
}
}
// Make sure we are using the right branch during constant evaluation.
EXPECT_EQ(absl::CordTestPeer::IsTree(cord), cord.size() >= 16);
for (int i = 0; i < 10; ++i) {
// Make a few more Cords from the same global rep.
// This tests what happens when the refcount for it gets below 1.
EXPECT_EQ(expected, absl::Cord(Str{}));
}
}
constexpr int SimpleStrlen(const char* p) {
return *p ? 1 + SimpleStrlen(p + 1) : 0;
}
struct ShortView {
constexpr absl::string_view operator()() const {
return absl::string_view("SSO string", SimpleStrlen("SSO string"));
}
};
struct LongView {
constexpr absl::string_view operator()() const {
return absl::string_view("String that does not fit SSO.",
SimpleStrlen("String that does not fit SSO."));
}
};
TEST(Cord, ConstinitConstructor) {
TestConstinitConstructor(
absl::strings_internal::MakeStringConstant(ShortView{}));
TestConstinitConstructor(
absl::strings_internal::MakeStringConstant(LongView{}));
}

@ -33,14 +33,17 @@ namespace cord_internal {
// Wraps std::atomic for reference counting.
class Refcount {
public:
Refcount() : count_{1} {}
~Refcount() {}
constexpr Refcount() : count_{kRefIncrement} {}
struct Immortal {};
explicit constexpr Refcount(Immortal) : count_(kImmortalTag) {}
// Increments the reference count by 1. Imposes no memory ordering.
inline void Increment() { count_.fetch_add(1, std::memory_order_relaxed); }
// Increments the reference count. Imposes no memory ordering.
inline void Increment() {
count_.fetch_add(kRefIncrement, std::memory_order_relaxed);
}
// Asserts that the current refcount is greater than 0. If the refcount is
// greater than 1, decrements the reference count by 1.
// greater than 1, decrements the reference count.
//
// Returns false if there are no references outstanding; true otherwise.
// Inserts barriers to ensure that state written before this method returns
@ -48,19 +51,24 @@ class Refcount {
// false.
inline bool Decrement() {
int32_t refcount = count_.load(std::memory_order_acquire);
assert(refcount > 0);
return refcount != 1 && count_.fetch_sub(1, std::memory_order_acq_rel) != 1;
assert(refcount > 0 || refcount & kImmortalTag);
return refcount != kRefIncrement &&
count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel) !=
kRefIncrement;
}
// Same as Decrement but expect that refcount is greater than 1.
inline bool DecrementExpectHighRefcount() {
int32_t refcount = count_.fetch_sub(1, std::memory_order_acq_rel);
assert(refcount > 0);
return refcount != 1;
int32_t refcount =
count_.fetch_sub(kRefIncrement, std::memory_order_acq_rel);
assert(refcount > 0 || refcount & kImmortalTag);
return refcount != kRefIncrement;
}
// Returns the current reference count using acquire semantics.
inline int32_t Get() const { return count_.load(std::memory_order_acquire); }
inline int32_t Get() const {
return count_.load(std::memory_order_acquire) >> kImmortalShift;
}
// Returns whether the atomic integer is 1.
// If the reference count is used in the conventional way, a
@ -70,9 +78,27 @@ class Refcount {
// performs the memory barrier needed for the owning thread
// to act on the object, knowing that it has exclusive access to the
// object.
inline bool IsOne() { return count_.load(std::memory_order_acquire) == 1; }
inline bool IsOne() {
return count_.load(std::memory_order_acquire) == kRefIncrement;
}
bool IsImmortal() const {
return (count_.load(std::memory_order_relaxed) & kImmortalTag) != 0;
}
private:
// We reserve the bottom bit to tag a reference count as immortal.
// By making it `1` we ensure that we never reach `0` when adding/subtracting
// `2`, thus it never looks as if it should be destroyed.
// These are used for the StringConstant constructor where we do not increase
// the refcount at construction time (due to constinit requirements) but we
// will still decrease it at destruction time to avoid branching on Unref.
enum {
kImmortalShift = 1,
kRefIncrement = 1 << kImmortalShift,
kImmortalTag = kRefIncrement - 1
};
std::atomic<int32_t> count_;
};
@ -97,6 +123,10 @@ enum CordRepKind {
};
struct CordRep {
CordRep() = default;
constexpr CordRep(Refcount::Immortal immortal, size_t l)
: length(l), refcount(immortal), tag(EXTERNAL), data{} {}
// The following three fields have to be less than 32 bytes since
// that is the smallest supported flat node size.
size_t length;
@ -135,6 +165,12 @@ using ExternalReleaserInvoker = void (*)(CordRepExternal*);
// External CordReps are allocated together with a type erased releaser. The
// releaser is stored in the memory directly following the CordRepExternal.
struct CordRepExternal : public CordRep {
CordRepExternal() = default;
explicit constexpr CordRepExternal(absl::string_view str)
: CordRep(Refcount::Immortal{}, str.size()),
base(str.data()),
releaser_invoker(nullptr) {}
const char* base;
// Pointer to function that knows how to call and destroy the releaser.
ExternalReleaserInvoker releaser_invoker;
@ -178,6 +214,14 @@ struct CordRepExternalImpl
}
};
template <typename Str>
struct ConstInitExternalStorage {
ABSL_CONST_INIT static CordRepExternal value;
};
template <typename Str>
CordRepExternal ConstInitExternalStorage<Str>::value(Str::value);
enum {
kMaxInline = 15,
// Tag byte & kMaxInline means we are storing a pointer.
@ -195,9 +239,23 @@ struct AsTree {
char padding[kMaxInline + 1 - sizeof(absl::cord_internal::CordRep*) - 1];
char tagged_size;
};
constexpr char GetOrNull(absl::string_view data, size_t pos) {
return pos < data.size() ? data[pos] : '\0';
}
union InlineData {
constexpr InlineData() : as_chars{} {}
explicit constexpr InlineData(AsTree tree) : as_tree(tree) {}
explicit constexpr InlineData(absl::string_view chars)
: as_chars{GetOrNull(chars, 0), GetOrNull(chars, 1),
GetOrNull(chars, 2), GetOrNull(chars, 3),
GetOrNull(chars, 4), GetOrNull(chars, 5),
GetOrNull(chars, 6), GetOrNull(chars, 7),
GetOrNull(chars, 8), GetOrNull(chars, 9),
GetOrNull(chars, 10), GetOrNull(chars, 11),
GetOrNull(chars, 12), GetOrNull(chars, 13),
GetOrNull(chars, 14), static_cast<char>(chars.size())} {}
AsTree as_tree;
char as_chars[kMaxInline + 1];

@ -0,0 +1,70 @@
// Copyright 2020 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.
#ifndef ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_
#define ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_
#include "absl/meta/type_traits.h"
#include "absl/strings/string_view.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace strings_internal {
// StringConstant<T> represents a compile time string constant.
// It can be accessed via its `absl::string_view value` static member.
// It is guaranteed that the `string_view` returned has constant `.data()`,
// constant `.size()` and constant `value[i]` for all `0 <= i < .size()`
//
// The `T` is an opaque type. It is guaranteed that different string constants
// will have different values of `T`. This allows users to associate the string
// constant with other static state at compile time.
//
// Instances should be made using the `MakeStringConstant()` factory function
// below.
template <typename T>
struct StringConstant {
private:
// Returns true if `view` points to constant data.
// Otherwise, it can't be constant evaluated.
static constexpr bool ValidateConstant(absl::string_view view) {
return view.empty() || 2 * view[0] != 1;
}
public:
static constexpr absl::string_view value = T{}();
constexpr absl::string_view operator()() const { return value; }
static_assert(ValidateConstant(value),
"The input string_view must point to constant data.");
};
template <typename T>
constexpr absl::string_view StringConstant<T>::value; // NOLINT
// Factory function for `StringConstant` instances.
// It supports callables that have a constexpr default constructor and a
// constexpr operator().
// It must return an `absl::string_view` or `const char*` pointing to constant
// data. This is validated at compile time.
template <typename T>
constexpr StringConstant<T> MakeStringConstant(T) {
return {};
}
} // namespace strings_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_STRING_CONSTANT_H_

@ -0,0 +1,60 @@
// Copyright 2020 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/strings/internal/string_constant.h"
#include "absl/meta/type_traits.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace {
using absl::strings_internal::MakeStringConstant;
struct Callable {
constexpr absl::string_view operator()() const {
return absl::string_view("Callable", 8);
}
};
TEST(StringConstant, Traits) {
constexpr auto str = MakeStringConstant(Callable{});
using T = decltype(str);
EXPECT_TRUE(std::is_empty<T>::value);
EXPECT_TRUE(std::is_trivial<T>::value);
EXPECT_TRUE(absl::is_trivially_default_constructible<T>::value);
EXPECT_TRUE(absl::is_trivially_copy_constructible<T>::value);
EXPECT_TRUE(absl::is_trivially_move_constructible<T>::value);
EXPECT_TRUE(absl::is_trivially_destructible<T>::value);
}
TEST(StringConstant, MakeFromCallable) {
constexpr auto str = MakeStringConstant(Callable{});
using T = decltype(str);
EXPECT_EQ(Callable{}(), T::value);
EXPECT_EQ(Callable{}(), str());
}
TEST(StringConstant, MakeFromStringConstant) {
// We want to make sure the StringConstant itself is a valid input to the
// factory function.
constexpr auto str = MakeStringConstant(Callable{});
constexpr auto str2 = MakeStringConstant(str);
using T = decltype(str2);
EXPECT_EQ(Callable{}(), T::value);
EXPECT_EQ(Callable{}(), str2());
}
} // namespace

@ -736,9 +736,18 @@ struct LookupTables {
X / 35, X / 36, \
}
// This kVmaxOverBase is generated with
// for (int base = 2; base < 37; ++base) {
// absl::uint128 max = std::numeric_limits<absl::uint128>::max();
// auto result = max / base;
// std::cout << " MakeUint128(" << absl::Uint128High64(result) << "u, "
// << absl::Uint128Low64(result) << "u),\n";
// }
// See https://godbolt.org/z/aneYsb
//
// uint128& operator/=(uint128) is not constexpr, so hardcode the resulting
// array to avoid a static initializer.
template <>
template<>
const uint128 LookupTables<uint128>::kVmaxOverBase[] = {
0,
0,
@ -779,6 +788,111 @@ const uint128 LookupTables<uint128>::kVmaxOverBase[] = {
MakeUint128(512409557603043100u, 8198552921648689607u),
};
// This kVmaxOverBase generated with
// for (int base = 2; base < 37; ++base) {
// absl::int128 max = std::numeric_limits<absl::int128>::max();
// auto result = max / base;
// std::cout << "\tMakeInt128(" << absl::Int128High64(result) << ", "
// << absl::Int128Low64(result) << "u),\n";
// }
// See https://godbolt.org/z/7djYWz
//
// int128& operator/=(int128) is not constexpr, so hardcode the resulting array
// to avoid a static initializer.
template<>
const int128 LookupTables<int128>::kVmaxOverBase[] = {
0,
0,
MakeInt128(4611686018427387903, 18446744073709551615u),
MakeInt128(3074457345618258602, 12297829382473034410u),
MakeInt128(2305843009213693951, 18446744073709551615u),
MakeInt128(1844674407370955161, 11068046444225730969u),
MakeInt128(1537228672809129301, 6148914691236517205u),
MakeInt128(1317624576693539401, 2635249153387078802u),
MakeInt128(1152921504606846975, 18446744073709551615u),
MakeInt128(1024819115206086200, 16397105843297379214u),
MakeInt128(922337203685477580, 14757395258967641292u),
MakeInt128(838488366986797800, 13415813871788764811u),
MakeInt128(768614336404564650, 12297829382473034410u),
MakeInt128(709490156681136600, 11351842506898185609u),
MakeInt128(658812288346769700, 10540996613548315209u),
MakeInt128(614891469123651720, 9838263505978427528u),
MakeInt128(576460752303423487, 18446744073709551615u),
MakeInt128(542551296285575047, 9765923333140350855u),
MakeInt128(512409557603043100, 8198552921648689607u),
MakeInt128(485440633518672410, 17475862806672206794u),
MakeInt128(461168601842738790, 7378697629483820646u),
MakeInt128(439208192231179800, 7027331075698876806u),
MakeInt128(419244183493398900, 6707906935894382405u),
MakeInt128(401016175515425035, 2406097053092550210u),
MakeInt128(384307168202282325, 6148914691236517205u),
MakeInt128(368934881474191032, 5902958103587056517u),
MakeInt128(354745078340568300, 5675921253449092804u),
MakeInt128(341606371735362066, 17763531330238827482u),
MakeInt128(329406144173384850, 5270498306774157604u),
MakeInt128(318047311615681924, 7633135478776366185u),
MakeInt128(307445734561825860, 4919131752989213764u),
MakeInt128(297528130221121800, 4760450083537948804u),
MakeInt128(288230376151711743, 18446744073709551615u),
MakeInt128(279496122328932600, 4471937957262921603u),
MakeInt128(271275648142787523, 14106333703424951235u),
MakeInt128(263524915338707880, 4216398645419326083u),
MakeInt128(256204778801521550, 4099276460824344803u),
};
// This kVminOverBase generated with
// for (int base = 2; base < 37; ++base) {
// absl::int128 min = std::numeric_limits<absl::int128>::min();
// auto result = min / base;
// std::cout << "\tMakeInt128(" << absl::Int128High64(result) << ", "
// << absl::Int128Low64(result) << "u),\n";
// }
//
// See https://godbolt.org/z/7djYWz
//
// int128& operator/=(int128) is not constexpr, so hardcode the resulting array
// to avoid a static initializer.
template<>
const int128 LookupTables<int128>::kVminOverBase[] = {
0,
0,
MakeInt128(-4611686018427387904, 0u),
MakeInt128(-3074457345618258603, 6148914691236517206u),
MakeInt128(-2305843009213693952, 0u),
MakeInt128(-1844674407370955162, 7378697629483820647u),
MakeInt128(-1537228672809129302, 12297829382473034411u),
MakeInt128(-1317624576693539402, 15811494920322472814u),
MakeInt128(-1152921504606846976, 0u),
MakeInt128(-1024819115206086201, 2049638230412172402u),
MakeInt128(-922337203685477581, 3689348814741910324u),
MakeInt128(-838488366986797801, 5030930201920786805u),
MakeInt128(-768614336404564651, 6148914691236517206u),
MakeInt128(-709490156681136601, 7094901566811366007u),
MakeInt128(-658812288346769701, 7905747460161236407u),
MakeInt128(-614891469123651721, 8608480567731124088u),
MakeInt128(-576460752303423488, 0u),
MakeInt128(-542551296285575048, 8680820740569200761u),
MakeInt128(-512409557603043101, 10248191152060862009u),
MakeInt128(-485440633518672411, 970881267037344822u),
MakeInt128(-461168601842738791, 11068046444225730970u),
MakeInt128(-439208192231179801, 11419412998010674810u),
MakeInt128(-419244183493398901, 11738837137815169211u),
MakeInt128(-401016175515425036, 16040647020617001406u),
MakeInt128(-384307168202282326, 12297829382473034411u),
MakeInt128(-368934881474191033, 12543785970122495099u),
MakeInt128(-354745078340568301, 12770822820260458812u),
MakeInt128(-341606371735362067, 683212743470724134u),
MakeInt128(-329406144173384851, 13176245766935394012u),
MakeInt128(-318047311615681925, 10813608594933185431u),
MakeInt128(-307445734561825861, 13527612320720337852u),
MakeInt128(-297528130221121801, 13686293990171602812u),
MakeInt128(-288230376151711744, 0u),
MakeInt128(-279496122328932601, 13974806116446630013u),
MakeInt128(-271275648142787524, 4340410370284600381u),
MakeInt128(-263524915338707881, 14230345428290225533u),
MakeInt128(-256204778801521551, 14347467612885206813u),
};
template <typename IntType>
const IntType LookupTables<IntType>::kVmaxOverBase[] =
X_OVER_BASE_INITIALIZER(std::numeric_limits<IntType>::max());
@ -948,6 +1062,10 @@ bool safe_strto64_base(absl::string_view text, int64_t* value, int base) {
return safe_int_internal<int64_t>(text, value, base);
}
bool safe_strto128_base(absl::string_view text, int128* value, int base) {
return safe_int_internal<absl::int128>(text, value, base);
}
bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base) {
return safe_uint_internal<uint32_t>(text, value, base);
}

@ -127,6 +127,8 @@ inline void PutTwoDigits(size_t i, char* buf) {
// safe_strto?() functions for implementing SimpleAtoi()
bool safe_strto32_base(absl::string_view text, int32_t* value, int base);
bool safe_strto64_base(absl::string_view text, int64_t* value, int base);
bool safe_strto128_base(absl::string_view text, absl::int128* value,
int base);
bool safe_strtou32_base(absl::string_view text, uint32_t* value, int base);
bool safe_strtou64_base(absl::string_view text, uint64_t* value, int base);
bool safe_strtou128_base(absl::string_view text, absl::uint128* value,
@ -255,6 +257,11 @@ ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type* out) {
return numbers_internal::safe_strtoi_base(str, out, 10);
}
ABSL_MUST_USE_RESULT inline bool SimpleAtoi(absl::string_view str,
absl::int128* out) {
return numbers_internal::safe_strto128_base(str, out, 10);
}
ABSL_MUST_USE_RESULT inline bool SimpleAtoi(absl::string_view str,
absl::uint128* out) {
return numbers_internal::safe_strtou128_base(str, out, 10);

@ -251,7 +251,7 @@ TEST(Numbers, TestFastPrints) {
template <typename int_type, typename in_val_type>
void VerifySimpleAtoiGood(in_val_type in_value, int_type exp_value) {
std::string s;
// uint128 can be streamed but not StrCat'd
// (u)int128 can be streamed but not StrCat'd.
absl::strings_internal::OStringStream(&s) << in_value;
int_type x = static_cast<int_type>(~exp_value);
EXPECT_TRUE(SimpleAtoi(s, &x))
@ -264,7 +264,9 @@ void VerifySimpleAtoiGood(in_val_type in_value, int_type exp_value) {
template <typename int_type, typename in_val_type>
void VerifySimpleAtoiBad(in_val_type in_value) {
std::string s = absl::StrCat(in_value);
std::string s;
// (u)int128 can be streamed but not StrCat'd.
absl::strings_internal::OStringStream(&s) << in_value;
int_type x;
EXPECT_FALSE(SimpleAtoi(s, &x));
EXPECT_FALSE(SimpleAtoi(s.c_str(), &x));
@ -347,6 +349,31 @@ TEST(NumbersTest, Atoi) {
std::numeric_limits<absl::uint128>::max(),
std::numeric_limits<absl::uint128>::max());
// SimpleAtoi(absl::string_view, absl::int128)
VerifySimpleAtoiGood<absl::int128>(0, 0);
VerifySimpleAtoiGood<absl::int128>(42, 42);
VerifySimpleAtoiGood<absl::int128>(-42, -42);
VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<int32_t>::min(),
std::numeric_limits<int32_t>::min());
VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<int32_t>::max(),
std::numeric_limits<int32_t>::max());
VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<uint32_t>::max(),
std::numeric_limits<uint32_t>::max());
VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<int64_t>::min(),
std::numeric_limits<int64_t>::min());
VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<int64_t>::max(),
std::numeric_limits<int64_t>::max());
VerifySimpleAtoiGood<absl::int128>(std::numeric_limits<uint64_t>::max(),
std::numeric_limits<uint64_t>::max());
VerifySimpleAtoiGood<absl::int128>(
std::numeric_limits<absl::int128>::min(),
std::numeric_limits<absl::int128>::min());
VerifySimpleAtoiGood<absl::int128>(
std::numeric_limits<absl::int128>::max(),
std::numeric_limits<absl::int128>::max());
VerifySimpleAtoiBad<absl::int128>(std::numeric_limits<absl::uint128>::max());
// Some other types
VerifySimpleAtoiGood<int>(-42, -42);
VerifySimpleAtoiGood<int32_t>(-42, -42);
@ -725,6 +752,51 @@ TEST(stringtest, safe_strtou128_random) {
EXPECT_FALSE(parse_func(s, &parsed_value, base));
}
}
TEST(stringtest, safe_strto128_random) {
// random number generators don't work for int128, and
// int128 can be streamed but not StrCat'd, so this code must be custom
// implemented for int128, but is generally the same as what's above.
// test_random_integer_parse_base<absl::int128>(
// &absl::numbers_internal::safe_strto128_base);
using RandomEngine = std::minstd_rand0;
using IntType = absl::int128;
constexpr auto parse_func = &absl::numbers_internal::safe_strto128_base;
std::random_device rd;
RandomEngine rng(rd());
std::uniform_int_distribution<int64_t> random_int64(
std::numeric_limits<int64_t>::min());
std::uniform_int_distribution<uint64_t> random_uint64(
std::numeric_limits<uint64_t>::min());
std::uniform_int_distribution<int> random_base(2, 35);
for (size_t i = 0; i < kNumRandomTests; ++i) {
int64_t high = random_int64(rng);
uint64_t low = random_uint64(rng);
IntType value = absl::MakeInt128(high, low);
int base = random_base(rng);
std::string str_value;
EXPECT_TRUE(Itoa<IntType>(value, base, &str_value));
IntType parsed_value;
// Test successful parse
EXPECT_TRUE(parse_func(str_value, &parsed_value, base));
EXPECT_EQ(parsed_value, value);
// Test overflow
std::string s;
absl::strings_internal::OStringStream(&s)
<< std::numeric_limits<IntType>::max() << value;
EXPECT_FALSE(parse_func(s, &parsed_value, base));
// Test underflow
s.clear();
absl::strings_internal::OStringStream(&s)
<< std::numeric_limits<IntType>::min() << value;
EXPECT_FALSE(parse_func(s, &parsed_value, base));
}
}
TEST(stringtest, safe_strtou32_base) {
for (int i = 0; strtouint32_test_cases()[i].str != nullptr; ++i) {

@ -24,7 +24,7 @@ source "${ABSEIL_ROOT}/ci/linux_docker_containers.sh"
readonly DOCKER_CONTAINER=${LINUX_GCC_LATEST_CONTAINER}
time docker run \
--volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
--mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
--workdir=/abseil-cpp \
--tmpfs=/buildfs:exec \
--cap-add=SYS_PTRACE \

@ -42,7 +42,7 @@ readonly DOCKER_CONTAINER=${LINUX_CLANG_LATEST_CONTAINER}
# USE_BAZEL_CACHE=1 only works on Kokoro.
# Without access to the credentials this won't work.
if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
# Bazel doesn't track changes to tools outside of the workspace
# (e.g. /usr/bin/gcc), so by appending the docker container to the
# remote_http_cache url, we make changes to the container part of
@ -55,7 +55,7 @@ fi
# external dependencies first.
# https://docs.bazel.build/versions/master/guide.html#distdir
if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}"
DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
fi
@ -64,7 +64,7 @@ for std in ${STD}; do
for exceptions_mode in ${EXCEPTIONS_MODE}; do
echo "--------------------------------------------------------------------"
time docker run \
--volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
--mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
--workdir=/abseil-cpp \
--cap-add=SYS_PTRACE \
--rm \

@ -42,7 +42,7 @@ readonly DOCKER_CONTAINER=${LINUX_CLANG_LATEST_CONTAINER}
# USE_BAZEL_CACHE=1 only works on Kokoro.
# Without access to the credentials this won't work.
if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
# Bazel doesn't track changes to tools outside of the workspace
# (e.g. /usr/bin/gcc), so by appending the docker container to the
# remote_http_cache url, we make changes to the container part of
@ -55,7 +55,7 @@ fi
# external dependencies first.
# https://docs.bazel.build/versions/master/guide.html#distdir
if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}"
DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
fi
@ -64,7 +64,7 @@ for std in ${STD}; do
for exceptions_mode in ${EXCEPTIONS_MODE}; do
echo "--------------------------------------------------------------------"
time docker run \
--volume="${ABSEIL_ROOT}:/abseil-cpp-ro:ro" \
--mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp-ro,readonly \
--tmpfs=/abseil-cpp \
--workdir=/abseil-cpp \
--cap-add=SYS_PTRACE \

@ -42,7 +42,7 @@ readonly DOCKER_CONTAINER=${LINUX_CLANG_LATEST_CONTAINER}
# USE_BAZEL_CACHE=1 only works on Kokoro.
# Without access to the credentials this won't work.
if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
# Bazel doesn't track changes to tools outside of the workspace
# (e.g. /usr/bin/gcc), so by appending the docker container to the
# remote_http_cache url, we make changes to the container part of
@ -55,7 +55,7 @@ fi
# external dependencies first.
# https://docs.bazel.build/versions/master/guide.html#distdir
if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}"
DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
fi
@ -64,7 +64,7 @@ for std in ${STD}; do
for exceptions_mode in ${EXCEPTIONS_MODE}; do
echo "--------------------------------------------------------------------"
time docker run \
--volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
--mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
--workdir=/abseil-cpp \
--cap-add=SYS_PTRACE \
--rm \

@ -42,7 +42,7 @@ readonly DOCKER_CONTAINER=${LINUX_CLANG_LATEST_CONTAINER}
# USE_BAZEL_CACHE=1 only works on Kokoro.
# Without access to the credentials this won't work.
if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
# Bazel doesn't track changes to tools outside of the workspace
# (e.g. /usr/bin/gcc), so by appending the docker container to the
# remote_http_cache url, we make changes to the container part of
@ -55,7 +55,7 @@ fi
# external dependencies first.
# https://docs.bazel.build/versions/master/guide.html#distdir
if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}"
DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
fi
@ -64,7 +64,7 @@ for std in ${STD}; do
for exceptions_mode in ${EXCEPTIONS_MODE}; do
echo "--------------------------------------------------------------------"
time docker run \
--volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
--mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
--workdir=/abseil-cpp \
--cap-add=SYS_PTRACE \
--rm \

@ -42,7 +42,7 @@ readonly DOCKER_CONTAINER=${LINUX_GCC_49_CONTAINER}
# USE_BAZEL_CACHE=1 only works on Kokoro.
# Without access to the credentials this won't work.
if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
# Bazel doesn't track changes to tools outside of the workspace
# (e.g. /usr/bin/gcc), so by appending the docker container to the
# remote_http_cache url, we make changes to the container part of
@ -55,7 +55,7 @@ fi
# external dependencies first.
# https://docs.bazel.build/versions/master/guide.html#distdir
if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}"
DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
fi
@ -64,7 +64,7 @@ for std in ${STD}; do
for exceptions_mode in ${EXCEPTIONS_MODE}; do
echo "--------------------------------------------------------------------"
time docker run \
--volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
--mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
--workdir=/abseil-cpp \
--cap-add=SYS_PTRACE \
--rm \

@ -42,7 +42,7 @@ readonly DOCKER_CONTAINER=${LINUX_GCC_LATEST_CONTAINER}
# USE_BAZEL_CACHE=1 only works on Kokoro.
# Without access to the credentials this won't work.
if [[ ${USE_BAZEL_CACHE:-0} -ne 0 ]]; then
DOCKER_EXTRA_ARGS="--volume=${KOKORO_KEYSTORE_DIR}:/keystore:ro ${DOCKER_EXTRA_ARGS:-}"
DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_KEYSTORE_DIR},target=/keystore,readonly ${DOCKER_EXTRA_ARGS:-}"
# Bazel doesn't track changes to tools outside of the workspace
# (e.g. /usr/bin/gcc), so by appending the docker container to the
# remote_http_cache url, we make changes to the container part of
@ -55,7 +55,7 @@ fi
# external dependencies first.
# https://docs.bazel.build/versions/master/guide.html#distdir
if [[ ${KOKORO_GFILE_DIR:-} ]] && [[ -d "${KOKORO_GFILE_DIR}/distdir" ]]; then
DOCKER_EXTRA_ARGS="--volume=${KOKORO_GFILE_DIR}/distdir:/distdir:ro ${DOCKER_EXTRA_ARGS:-}"
DOCKER_EXTRA_ARGS="--mount type=bind,source=${KOKORO_GFILE_DIR}/distdir,target=/distdir,readonly ${DOCKER_EXTRA_ARGS:-}"
BAZEL_EXTRA_ARGS="--distdir=/distdir ${BAZEL_EXTRA_ARGS:-}"
fi
@ -64,7 +64,7 @@ for std in ${STD}; do
for exceptions_mode in ${EXCEPTIONS_MODE}; do
echo "--------------------------------------------------------------------"
time docker run \
--volume="${ABSEIL_ROOT}:/abseil-cpp-ro:ro" \
--mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp-ro,readonly \
--tmpfs=/abseil-cpp \
--workdir=/abseil-cpp \
--cap-add=SYS_PTRACE \

@ -45,7 +45,7 @@ for std in ${ABSL_CMAKE_CXX_STANDARDS}; do
for compilation_mode in ${ABSL_CMAKE_BUILD_TYPES}; do
for build_shared in ${ABSL_CMAKE_BUILD_SHARED}; do
time docker run \
--volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
--mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
--workdir=/abseil-cpp \
--tmpfs=/buildfs:exec \
--cap-add=SYS_PTRACE \

@ -45,7 +45,7 @@ for std in ${ABSL_CMAKE_CXX_STANDARDS}; do
for compilation_mode in ${ABSL_CMAKE_BUILD_TYPES}; do
for build_shared in ${ABSL_CMAKE_BUILD_SHARED}; do
time docker run \
--volume="${ABSEIL_ROOT}:/abseil-cpp:ro" \
--mount type=bind,source="${ABSEIL_ROOT}",target=/abseil-cpp,readonly \
--workdir=/abseil-cpp \
--tmpfs=/buildfs:exec \
--cap-add=SYS_PTRACE \

Loading…
Cancel
Save