Export of internal Abseil changes

--
5e45aadfb89e366dedd1fcad5034a76c5c10ad76 by James Y Knight <jyknight@google.com>:

Correct the conditions for std::{optional,variant,any} availability on Apple platforms.

Before XCode 12.5, the availability declarations incorrectly excluded one release on which the features were in fact available. This was corrected in 7fb40e1569

Unfortunately, we cannot simply switch abseil to the corrected versions, as that will cause build failures when using the older XCode toolchain. So, we check the version, and choose the correct set of versions for the toolchain in use.

PiperOrigin-RevId: 407667302

--
376fa06cde048e536e9447336b27bebf598ed4ea by Greg Falcon <gfalcon@google.com>:

Cord implementation change: Add a new CordRepCrc node type.

This is an implementation detail that will allow storing expected CRCs alongside cord data.  This node is intended only to live at the top of Cord trees.

PiperOrigin-RevId: 407587140
GitOrigin-RevId: 5e45aadfb89e366dedd1fcad5034a76c5c10ad76
Change-Id: Iea3ca001c0cbb4deec8286b5581b30dc172a9918
pull/1057/head
Abseil Team 3 years ago committed by vslashg
parent d6c75d9dd8
commit c86347d4ce
  1. 6
      CMake/AbseilDll.cmake
  2. 43
      absl/base/config.h
  3. 16
      absl/strings/BUILD.bazel
  4. 16
      absl/strings/CMakeLists.txt
  5. 20
      absl/strings/cord.cc
  6. 4
      absl/strings/internal/cord_internal.cc
  7. 17
      absl/strings/internal/cord_internal.h
  8. 54
      absl/strings/internal/cord_rep_crc.cc
  9. 93
      absl/strings/internal/cord_rep_crc.h
  10. 115
      absl/strings/internal/cord_rep_crc_test.cc
  11. 10
      absl/strings/internal/cord_rep_flat.h

@ -204,14 +204,16 @@ set(ABSL_INTERNAL_DLL_FILES
"strings/internal/charconv_parse.h" "strings/internal/charconv_parse.h"
"strings/internal/cord_internal.cc" "strings/internal/cord_internal.cc"
"strings/internal/cord_internal.h" "strings/internal/cord_internal.h"
"strings/internal/cord_rep_consume.h"
"strings/internal/cord_rep_consume.cc"
"strings/internal/cord_rep_btree.cc" "strings/internal/cord_rep_btree.cc"
"strings/internal/cord_rep_btree.h" "strings/internal/cord_rep_btree.h"
"strings/internal/cord_rep_btree_navigator.cc" "strings/internal/cord_rep_btree_navigator.cc"
"strings/internal/cord_rep_btree_navigator.h" "strings/internal/cord_rep_btree_navigator.h"
"strings/internal/cord_rep_btree_reader.cc" "strings/internal/cord_rep_btree_reader.cc"
"strings/internal/cord_rep_btree_reader.h" "strings/internal/cord_rep_btree_reader.h"
"strings/internal/cord_rep_crc.cc"
"strings/internal/cord_rep_crc.h"
"strings/internal/cord_rep_consume.h"
"strings/internal/cord_rep_consume.cc"
"strings/internal/cord_rep_flat.h" "strings/internal/cord_rep_flat.h"
"strings/internal/cord_rep_ring.cc" "strings/internal/cord_rep_ring.cc"
"strings/internal/cord_rep_ring.h" "strings/internal/cord_rep_ring.h"

@ -520,22 +520,41 @@ static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
#error "absl endian detection needs to be set up for your compiler" #error "absl endian detection needs to be set up for your compiler"
#endif #endif
// macOS 10.13 and iOS 10.11 don't let you use <any>, <optional>, or <variant> // macOS < 10.13 and iOS < 11 don't let you use <any>, <optional>, or <variant>
// even though the headers exist and are publicly noted to work. See // even though the headers exist and are publicly noted to work, because the
// https://github.com/abseil/abseil-cpp/issues/207 and // libc++ shared library shipped on the system doesn't have the requisite
// exported symbols. See https://github.com/abseil/abseil-cpp/issues/207 and
// https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes // https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes
//
// libc++ spells out the availability requirements in the file // libc++ spells out the availability requirements in the file
// llvm-project/libcxx/include/__config via the #define // llvm-project/libcxx/include/__config via the #define
// _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS. // _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS.
#if defined(__APPLE__) && defined(_LIBCPP_VERSION) && \ //
((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ // Unfortunately, Apple initially mis-stated the requirements as macOS < 10.14
__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101400) || \ // and iOS < 12 in the libc++ headers. This was corrected by
(defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \ // https://github.com/llvm/llvm-project/commit/7fb40e1569dd66292b647f4501b85517e9247953
__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \ // which subsequently made it into the XCode 12.5 release. We need to match the
(defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \ // old (incorrect) conditions when built with old XCode, but can use the
__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000) || \ // corrected earlier versions with new XCode.
(defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \ #if defined(__APPLE__) && defined(_LIBCPP_VERSION) && \
__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 120000)) ((_LIBCPP_VERSION >= 11000 && /* XCode 12.5 or later: */ \
((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101300) || \
(defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 110000) || \
(defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 40000) || \
(defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 110000))) || \
(_LIBCPP_VERSION < 11000 && /* Pre-XCode 12.5: */ \
((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101400) || \
(defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \
(defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000) || \
(defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 120000))))
#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 1 #define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 1
#else #else
#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0 #define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0

@ -272,6 +272,7 @@ cc_library(
"internal/cord_rep_btree_navigator.cc", "internal/cord_rep_btree_navigator.cc",
"internal/cord_rep_btree_reader.cc", "internal/cord_rep_btree_reader.cc",
"internal/cord_rep_consume.cc", "internal/cord_rep_consume.cc",
"internal/cord_rep_crc.cc",
"internal/cord_rep_ring.cc", "internal/cord_rep_ring.cc",
], ],
hdrs = [ hdrs = [
@ -280,6 +281,7 @@ cc_library(
"internal/cord_rep_btree_navigator.h", "internal/cord_rep_btree_navigator.h",
"internal/cord_rep_btree_reader.h", "internal/cord_rep_btree_reader.h",
"internal/cord_rep_consume.h", "internal/cord_rep_consume.h",
"internal/cord_rep_crc.h",
"internal/cord_rep_flat.h", "internal/cord_rep_flat.h",
"internal/cord_rep_ring.h", "internal/cord_rep_ring.h",
"internal/cord_rep_ring_reader.h", "internal/cord_rep_ring_reader.h",
@ -366,6 +368,20 @@ cc_test(
], ],
) )
cc_test(
name = "cord_rep_crc_test",
size = "small",
srcs = ["internal/cord_rep_crc_test.cc"],
copts = ABSL_TEST_COPTS,
visibility = ["//visibility:private"],
deps = [
":cord_internal",
":cord_rep_test_util",
"//absl/base:config",
"@com_google_googletest//:gtest_main",
],
)
cc_library( cc_library(
name = "cordz_update_tracker", name = "cordz_update_tracker",
hdrs = ["internal/cordz_update_tracker.h"], hdrs = ["internal/cordz_update_tracker.h"],

@ -558,6 +558,7 @@ absl_cc_library(
"internal/cord_rep_btree.h" "internal/cord_rep_btree.h"
"internal/cord_rep_btree_navigator.h" "internal/cord_rep_btree_navigator.h"
"internal/cord_rep_btree_reader.h" "internal/cord_rep_btree_reader.h"
"internal/cord_rep_crc.h"
"internal/cord_rep_consume.h" "internal/cord_rep_consume.h"
"internal/cord_rep_flat.h" "internal/cord_rep_flat.h"
"internal/cord_rep_ring.h" "internal/cord_rep_ring.h"
@ -567,6 +568,7 @@ absl_cc_library(
"internal/cord_rep_btree.cc" "internal/cord_rep_btree.cc"
"internal/cord_rep_btree_navigator.cc" "internal/cord_rep_btree_navigator.cc"
"internal/cord_rep_btree_reader.cc" "internal/cord_rep_btree_reader.cc"
"internal/cord_rep_crc.cc"
"internal/cord_rep_consume.cc" "internal/cord_rep_consume.cc"
"internal/cord_rep_ring.cc" "internal/cord_rep_ring.cc"
COPTS COPTS
@ -1011,6 +1013,20 @@ absl_cc_test(
GTest::gmock_main GTest::gmock_main
) )
absl_cc_test(
NAME
cord_rep_crc_test
SRCS
"internal/cord_rep_crc_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
absl::config
absl::cord_internal
absl::cord_rep_test_util
GTest::gmock_main
)
absl_cc_test( absl_cc_test(
NAME NAME
cord_ring_test cord_ring_test

@ -37,6 +37,7 @@
#include "absl/strings/escaping.h" #include "absl/strings/escaping.h"
#include "absl/strings/internal/cord_internal.h" #include "absl/strings/internal/cord_internal.h"
#include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_btree.h"
#include "absl/strings/internal/cord_rep_crc.h"
#include "absl/strings/internal/cord_rep_flat.h" #include "absl/strings/internal/cord_rep_flat.h"
#include "absl/strings/internal/cordz_statistics.h" #include "absl/strings/internal/cordz_statistics.h"
#include "absl/strings/internal/cordz_update_scope.h" #include "absl/strings/internal/cordz_update_scope.h"
@ -53,6 +54,7 @@ ABSL_NAMESPACE_BEGIN
using ::absl::cord_internal::CordRep; using ::absl::cord_internal::CordRep;
using ::absl::cord_internal::CordRepBtree; using ::absl::cord_internal::CordRepBtree;
using ::absl::cord_internal::CordRepConcat; using ::absl::cord_internal::CordRepConcat;
using ::absl::cord_internal::CordRepCrc;
using ::absl::cord_internal::CordRepExternal; using ::absl::cord_internal::CordRepExternal;
using ::absl::cord_internal::CordRepFlat; using ::absl::cord_internal::CordRepFlat;
using ::absl::cord_internal::CordRepSubstring; using ::absl::cord_internal::CordRepSubstring;
@ -1870,7 +1872,11 @@ static void DumpNode(CordRep* rep, bool include_data, std::ostream* os,
*os << "]"; *os << "]";
*os << " " << (IsRootBalanced(rep) ? 'b' : 'u'); *os << " " << (IsRootBalanced(rep) ? 'b' : 'u');
*os << " " << std::setw(indent) << ""; *os << " " << std::setw(indent) << "";
if (rep->IsConcat()) { if (rep->IsCrc()) {
*os << "CRC crc=" << rep->crc()->crc << "\n";
indent += kIndentStep;
rep = rep->crc()->child;
} else if (rep->IsConcat()) {
*os << "CONCAT depth=" << Depth(rep) << "\n"; *os << "CONCAT depth=" << Depth(rep) << "\n";
indent += kIndentStep; indent += kIndentStep;
indents.push_back(indent); indents.push_back(indent);
@ -1922,6 +1928,7 @@ static bool VerifyNode(CordRep* root, CordRep* start_node,
ABSL_INTERNAL_CHECK(node != nullptr, ReportError(root, node)); ABSL_INTERNAL_CHECK(node != nullptr, ReportError(root, node));
if (node != root) { if (node != root) {
ABSL_INTERNAL_CHECK(node->length != 0, ReportError(root, node)); ABSL_INTERNAL_CHECK(node->length != 0, ReportError(root, node));
ABSL_INTERNAL_CHECK(!node->IsCrc(), ReportError(root, node));
} }
if (node->IsConcat()) { if (node->IsConcat()) {
@ -1949,6 +1956,12 @@ static bool VerifyNode(CordRep* root, CordRep* start_node,
ABSL_INTERNAL_CHECK(node->substring()->start + node->length <= ABSL_INTERNAL_CHECK(node->substring()->start + node->length <=
node->substring()->child->length, node->substring()->child->length,
ReportError(root, node)); ReportError(root, node));
} else if (node->IsCrc()) {
ABSL_INTERNAL_CHECK(node->crc()->child != nullptr,
ReportError(root, node));
ABSL_INTERNAL_CHECK(node->crc()->length == node->crc()->child->length,
ReportError(root, node));
worklist.push_back(node->crc()->child);
} }
} while (!worklist.empty()); } while (!worklist.empty());
return true; return true;
@ -1958,6 +1971,11 @@ static bool VerifyNode(CordRep* root, CordRep* start_node,
/* static */ size_t Cord::MemoryUsageAux(const CordRep* rep) { /* static */ size_t Cord::MemoryUsageAux(const CordRep* rep) {
size_t total_mem_usage = 0; size_t total_mem_usage = 0;
if (rep->IsCrc()) {
total_mem_usage += sizeof(CordRepCrc);
rep = rep->crc()->child;
}
// Allow a quick exit for the common case that the root is a leaf. // Allow a quick exit for the common case that the root is a leaf.
if (RepMemoryUsageLeaf(rep, &total_mem_usage)) { if (RepMemoryUsageLeaf(rep, &total_mem_usage)) {
return total_mem_usage; return total_mem_usage;

@ -19,6 +19,7 @@
#include "absl/container/inlined_vector.h" #include "absl/container/inlined_vector.h"
#include "absl/strings/internal/cord_rep_btree.h" #include "absl/strings/internal/cord_rep_btree.h"
#include "absl/strings/internal/cord_rep_crc.h"
#include "absl/strings/internal/cord_rep_flat.h" #include "absl/strings/internal/cord_rep_flat.h"
#include "absl/strings/internal/cord_rep_ring.h" #include "absl/strings/internal/cord_rep_ring.h"
@ -70,6 +71,9 @@ void CordRep::Destroy(CordRep* rep) {
rep = child; rep = child;
continue; continue;
} }
} else if (rep->tag == CRC) {
CordRepCrc::Destroy(rep->crc());
rep = nullptr;
} else { } else {
CordRepFlat::Delete(rep); CordRepFlat::Delete(rep);
rep = nullptr; rep = nullptr;

@ -192,6 +192,7 @@ struct CordRepConcat;
struct CordRepExternal; struct CordRepExternal;
struct CordRepFlat; struct CordRepFlat;
struct CordRepSubstring; struct CordRepSubstring;
struct CordRepCrc;
class CordRepRing; class CordRepRing;
class CordRepBtree; class CordRepBtree;
@ -199,18 +200,19 @@ class CordRepBtree;
enum CordRepKind { enum CordRepKind {
CONCAT = 0, CONCAT = 0,
SUBSTRING = 1, SUBSTRING = 1,
BTREE = 2, CRC = 2,
RING = 3, BTREE = 3,
EXTERNAL = 4, RING = 4,
EXTERNAL = 5,
// We have different tags for different sized flat arrays, // We have different tags for different sized flat arrays,
// starting with FLAT, and limited to MAX_FLAT_TAG. The 225 value is based on // starting with FLAT, and limited to MAX_FLAT_TAG. The 226 value is based on
// the current 'size to tag' encoding of 8 / 32 bytes. If a new tag is needed // the current 'size to tag' encoding of 8 / 32 bytes. If a new tag is needed
// in the future, then 'FLAT' and 'MAX_FLAT_TAG' should be adjusted as well // in the future, then 'FLAT' and 'MAX_FLAT_TAG' should be adjusted as well
// as the Tag <---> Size logic so that FLAT stil represents the minimum flat // as the Tag <---> Size logic so that FLAT stil represents the minimum flat
// allocation size. (32 bytes as of now). // allocation size. (32 bytes as of now).
FLAT = 5, FLAT = 6,
MAX_FLAT_TAG = 225 MAX_FLAT_TAG = 226
}; };
// There are various locations where we want to check if some rep is a 'plain' // There are various locations where we want to check if some rep is a 'plain'
@ -251,6 +253,7 @@ struct CordRep {
constexpr bool IsRing() const { return tag == RING; } constexpr bool IsRing() const { return tag == RING; }
constexpr bool IsConcat() const { return tag == CONCAT; } constexpr bool IsConcat() const { return tag == CONCAT; }
constexpr bool IsSubstring() const { return tag == SUBSTRING; } constexpr bool IsSubstring() const { return tag == SUBSTRING; }
constexpr bool IsCrc() const { return tag == CRC; }
constexpr bool IsExternal() const { return tag == EXTERNAL; } constexpr bool IsExternal() const { return tag == EXTERNAL; }
constexpr bool IsFlat() const { return tag >= FLAT; } constexpr bool IsFlat() const { return tag >= FLAT; }
constexpr bool IsBtree() const { return tag == BTREE; } constexpr bool IsBtree() const { return tag == BTREE; }
@ -261,6 +264,8 @@ struct CordRep {
inline const CordRepConcat* concat() const; inline const CordRepConcat* concat() const;
inline CordRepSubstring* substring(); inline CordRepSubstring* substring();
inline const CordRepSubstring* substring() const; inline const CordRepSubstring* substring() const;
inline CordRepCrc* crc();
inline const CordRepCrc* crc() const;
inline CordRepExternal* external(); inline CordRepExternal* external();
inline const CordRepExternal* external() const; inline const CordRepExternal* external() const;
inline CordRepFlat* flat(); inline CordRepFlat* flat();

@ -0,0 +1,54 @@
// Copyright 2021 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/cord_rep_crc.h"
#include <cassert>
#include <cstdint>
#include "absl/base/config.h"
#include "absl/strings/internal/cord_internal.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace cord_internal {
CordRepCrc* CordRepCrc::New(CordRep* child, uint32_t crc) {
assert(child != nullptr);
if (child->IsCrc()) {
if (child->refcount.IsOne()) {
child->crc()->crc = crc;
return child->crc();
}
CordRep* old = child;
child = old->crc()->child;
CordRep::Ref(child);
CordRep::Unref(old);
}
auto* new_cordrep = new CordRepCrc;
new_cordrep->length = child->length;
new_cordrep->tag = cord_internal::CRC;
new_cordrep->child = child;
new_cordrep->crc = crc;
return new_cordrep;
}
void CordRepCrc::Destroy(CordRepCrc* node) {
CordRep::Unref(node->child);
delete node;
}
} // namespace cord_internal
ABSL_NAMESPACE_END
} // namespace absl

@ -0,0 +1,93 @@
// Copyright 2021 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_CORD_REP_CRC_H_
#define ABSL_STRINGS_INTERNAL_CORD_REP_CRC_H_
#include <cassert>
#include <cstdint>
#include "absl/base/config.h"
#include "absl/base/optimization.h"
#include "absl/strings/internal/cord_internal.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace cord_internal {
// CordRepCrc is a CordRep node intended only to appear at the top level of a
// cord tree. It associates an "expected CRC" with the contained data, to allow
// for easy passage of checksum data in Cord data flows.
//
// From Cord's perspective, the crc value has no semantics; any validation of
// the contained checksum is the user's responsibility.
struct CordRepCrc : public CordRep {
CordRep* child;
uint32_t crc;
// Consumes `child` and returns a CordRepCrc prefixed tree containing `child`.
// If the specified `child` is itself a CordRepCrc node, then this method
// either replaces the existing node, or directly updates the crc value in it
// depending on the node being shared or not, i.e.: refcount.IsOne().
// `child` must not be null. Never returns null.
static CordRepCrc* New(CordRep* child, uint32_t crc);
// Destroys (deletes) the provided node. `node` must not be null.
static void Destroy(CordRepCrc* node);
};
// Consumes `rep` and returns a CordRep* with any outer CordRepCrc wrapper
// removed. This is usually a no-op (returning `rep`), but this will remove and
// unref an outer CordRepCrc node.
inline CordRep* RemoveCrcNode(CordRep* rep) {
assert(rep != nullptr);
if (ABSL_PREDICT_FALSE(rep->IsCrc())) {
CordRep* child = rep->crc()->child;
if (rep->refcount.IsOne()) {
delete rep->crc();
} else {
CordRep::Ref(child);
CordRep::Unref(rep);
}
return child;
}
return rep;
}
// Returns `rep` if it is not a CordRepCrc node, or its child if it is.
// Does not consume or create a reference on `rep` or the returned value.
inline CordRep* SkipCrcNode(CordRep* rep) {
assert(rep != nullptr);
if (ABSL_PREDICT_FALSE(rep->IsCrc())) {
return rep->crc()->child;
} else {
return rep;
}
}
inline CordRepCrc* CordRep::crc() {
assert(IsCrc());
return static_cast<CordRepCrc*>(this);
}
inline const CordRepCrc* CordRep::crc() const {
assert(IsCrc());
return static_cast<const CordRepCrc*>(this);
}
} // namespace cord_internal
ABSL_NAMESPACE_END
} // namespace absl
#endif // ABSL_STRINGS_INTERNAL_CORD_REP_CRC_H_

@ -0,0 +1,115 @@
// Copyright 2021 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/cord_rep_crc.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/base/config.h"
#include "absl/strings/internal/cord_internal.h"
#include "absl/strings/internal/cord_rep_test_util.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace cord_internal {
namespace {
using ::absl::cordrep_testing::MakeFlat;
using ::testing::Eq;
using ::testing::Ne;
#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
TEST(CordRepCrc, NewWithNullPtr) {
EXPECT_DEATH(CordRepCrc::New(nullptr, 0), "");
}
TEST(CordRepCrc, RemoveCrcWithNullptr) {
EXPECT_DEATH(RemoveCrcNode(nullptr), "");
}
#endif // !NDEBUG && GTEST_HAS_DEATH_TEST
TEST(CordRepCrc, NewDestroy) {
CordRep* rep = cordrep_testing::MakeFlat("Hello world");
CordRepCrc* crc = CordRepCrc::New(rep, 12345);
EXPECT_TRUE(crc->refcount.IsOne());
EXPECT_THAT(crc->child, Eq(rep));
EXPECT_THAT(crc->crc, Eq(12345));
EXPECT_TRUE(rep->refcount.IsOne());
CordRepCrc::Destroy(crc);
}
TEST(CordRepCrc, NewExistingCrcNotShared) {
CordRep* rep = cordrep_testing::MakeFlat("Hello world");
CordRepCrc* crc = CordRepCrc::New(rep, 12345);
CordRepCrc* new_crc = CordRepCrc::New(crc, 54321);
EXPECT_THAT(new_crc, Eq(crc));
EXPECT_TRUE(new_crc->refcount.IsOne());
EXPECT_THAT(new_crc->child, Eq(rep));
EXPECT_THAT(new_crc->crc, Eq(54321));
EXPECT_TRUE(rep->refcount.IsOne());
CordRepCrc::Destroy(new_crc);
}
TEST(CordRepCrc, NewExistingCrcShared) {
CordRep* rep = cordrep_testing::MakeFlat("Hello world");
CordRepCrc* crc = CordRepCrc::New(rep, 12345);
CordRep::Ref(crc);
CordRepCrc* new_crc = CordRepCrc::New(crc, 54321);
EXPECT_THAT(new_crc, Ne(crc));
EXPECT_TRUE(new_crc->refcount.IsOne());
EXPECT_TRUE(crc->refcount.IsOne());
EXPECT_FALSE(rep->refcount.IsOne());
EXPECT_THAT(crc->child, Eq(rep));
EXPECT_THAT(new_crc->child, Eq(rep));
EXPECT_THAT(crc->crc, Eq(12345));
EXPECT_THAT(new_crc->crc, Eq(54321));
CordRep::Unref(crc);
CordRep::Unref(new_crc);
}
TEST(CordRepCrc, RemoveCrcNotCrc) {
CordRep* rep = cordrep_testing::MakeFlat("Hello world");
CordRep* nocrc = RemoveCrcNode(rep);
EXPECT_THAT(nocrc, Eq(rep));
CordRep::Unref(nocrc);
}
TEST(CordRepCrc, RemoveCrcNotShared) {
CordRep* rep = cordrep_testing::MakeFlat("Hello world");
CordRepCrc* crc = CordRepCrc::New(rep, 12345);
CordRep* nocrc = RemoveCrcNode(crc);
EXPECT_THAT(nocrc, Eq(rep));
EXPECT_TRUE(rep->refcount.IsOne());
CordRep::Unref(nocrc);
}
TEST(CordRepCrc, RemoveCrcShared) {
CordRep* rep = cordrep_testing::MakeFlat("Hello world");
CordRepCrc* crc = CordRepCrc::New(rep, 12345);
CordRep::Ref(crc);
CordRep* nocrc = RemoveCrcNode(crc);
EXPECT_THAT(nocrc, Eq(rep));
EXPECT_FALSE(rep->refcount.IsOne());
CordRep::Unref(nocrc);
CordRep::Unref(crc);
}
} // namespace
} // namespace cord_internal
ABSL_NAMESPACE_END
} // namespace absl

@ -44,11 +44,11 @@ static constexpr size_t kMaxFlatLength = kMaxFlatSize - kFlatOverhead;
static constexpr size_t kMinFlatLength = kMinFlatSize - kFlatOverhead; static constexpr size_t kMinFlatLength = kMinFlatSize - kFlatOverhead;
constexpr uint8_t AllocatedSizeToTagUnchecked(size_t size) { constexpr uint8_t AllocatedSizeToTagUnchecked(size_t size) {
return static_cast<uint8_t>((size <= 1024) ? size / 8 + 1 return static_cast<uint8_t>((size <= 1024) ? size / 8 + 2
: 129 + size / 32 - 1024 / 32); : 130 + size / 32 - 1024 / 32);
} }
static_assert(kMinFlatSize / 8 + 1 >= FLAT, ""); static_assert(kMinFlatSize / 8 + 2 >= FLAT, "");
static_assert(AllocatedSizeToTagUnchecked(kMaxFlatSize) <= MAX_FLAT_TAG, ""); static_assert(AllocatedSizeToTagUnchecked(kMaxFlatSize) <= MAX_FLAT_TAG, "");
// Helper functions for rounded div, and rounding to exact sizes. // Helper functions for rounded div, and rounding to exact sizes.
@ -73,7 +73,7 @@ inline uint8_t AllocatedSizeToTag(size_t size) {
// Converts the provided tag to the corresponding allocated size // Converts the provided tag to the corresponding allocated size
constexpr size_t TagToAllocatedSize(uint8_t tag) { constexpr size_t TagToAllocatedSize(uint8_t tag) {
return (tag <= 129) ? ((tag - 1) * 8) : (1024 + (tag - 129) * 32); return (tag <= 130) ? ((tag - 2) * 8) : (1024 + (tag - 130) * 32);
} }
// Converts the provided tag to the corresponding available data length // Converts the provided tag to the corresponding available data length
@ -82,7 +82,7 @@ constexpr size_t TagToLength(uint8_t tag) {
} }
// Enforce that kMaxFlatSize maps to a well-known exact tag value. // Enforce that kMaxFlatSize maps to a well-known exact tag value.
static_assert(TagToAllocatedSize(225) == kMaxFlatSize, "Bad tag logic"); static_assert(TagToAllocatedSize(226) == kMaxFlatSize, "Bad tag logic");
struct CordRepFlat : public CordRep { struct CordRepFlat : public CordRep {
// Creates a new flat node. // Creates a new flat node.

Loading…
Cancel
Save