Commit 22771d47 by Abseil Team Committed by vslashg

Export of internal Abseil changes

--
642ab296a2c9629c44f3f2ce6911cd2488bcf416 by Derek Mauro <dmauro@google.com>:

Remove an obsolete check in CMakeLists.txt

PiperOrigin-RevId: 352852564

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

Clarify that the calling *thread* must have locked the mutex in order to unlock
it.

PiperOrigin-RevId: 352801804

--
24e1f5f72756046f5265abf618e951c341f09b8d by Derek Mauro <dmauro@google.com>:

Fixes failing CMake string comparisons
https://cmake.org/cmake/help/latest/policy/CMP0054.html

Fixes #791

PiperOrigin-RevId: 352791054

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

Introduce CordRepRing class

This change introduces the CordRepRing class that implements all the lower level / internal implementation for upcoming CordRepRing ring buffer support in cord.

PiperOrigin-RevId: 352771994

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

Optimize InlineData representation for cord sampling (cordz)

This CL changes InlineData to allow us to store a (future) Cordz Info pointer directly into the inline representation:

- make InlineData a class that provides a public API to set the active union members (tree or chars) and safely access that data.
- change 'tree' and 'profiled' bits to be the 2 least significant bits, allowing us 62 continquous bits for storing a Cordz Info pointer.

PiperOrigin-RevId: 352642411

--
dc55ba71bbce0e6a83e05a453990c51ac3d68426 by Mark Barolak <mbar@google.com>:

Add unit test coverage for the mutating overload of absl::AsciiStrToLower.

PiperOrigin-RevId: 352626006
GitOrigin-RevId: 642ab296a2c9629c44f3f2ce6911cd2488bcf416
Change-Id: I6c5929dd830d3c630e14e7fd5387fc3e25a69100
parent b2dcbba1
...@@ -196,6 +196,8 @@ set(ABSL_INTERNAL_DLL_FILES ...@@ -196,6 +196,8 @@ set(ABSL_INTERNAL_DLL_FILES
"strings/internal/cord_internal.cc" "strings/internal/cord_internal.cc"
"strings/internal/cord_internal.h" "strings/internal/cord_internal.h"
"strings/internal/cord_rep_flat.h" "strings/internal/cord_rep_flat.h"
"strings/internal/cord_rep_ring.cc"
"strings/internal/cord_rep_ring.h"
"strings/internal/charconv_bigint.cc" "strings/internal/charconv_bigint.cc"
"strings/internal/charconv_bigint.h" "strings/internal/charconv_bigint.h"
"strings/internal/charconv_parse.cc" "strings/internal/charconv_parse.cc"
......
...@@ -104,7 +104,7 @@ function(absl_cc_library) ...@@ -104,7 +104,7 @@ function(absl_cc_library)
endif() endif()
endforeach() endforeach()
if("${ABSL_CC_SRCS}" STREQUAL "") if(ABSL_CC_SRCS STREQUAL "")
set(ABSL_CC_LIB_IS_INTERFACE 1) set(ABSL_CC_LIB_IS_INTERFACE 1)
else() else()
set(ABSL_CC_LIB_IS_INTERFACE 0) set(ABSL_CC_LIB_IS_INTERFACE 0)
...@@ -142,7 +142,7 @@ function(absl_cc_library) ...@@ -142,7 +142,7 @@ function(absl_cc_library)
endif() endif()
# Generate a pkg-config file for every library: # Generate a pkg-config file for every library:
if(${_build_type} STREQUAL "static" OR ${_build_type} STREQUAL "shared") if(_build_type STREQUAL "static" OR _build_type STREQUAL "shared")
if(NOT ABSL_CC_LIB_TESTONLY) if(NOT ABSL_CC_LIB_TESTONLY)
if(absl_VERSION) if(absl_VERSION)
set(PC_VERSION "${absl_VERSION}") set(PC_VERSION "${absl_VERSION}")
...@@ -183,7 +183,7 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n") ...@@ -183,7 +183,7 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n")
endif() endif()
if(NOT ABSL_CC_LIB_IS_INTERFACE) if(NOT ABSL_CC_LIB_IS_INTERFACE)
if(${_build_type} STREQUAL "dll_dep") if(_build_type STREQUAL "dll_dep")
# This target depends on the DLL. When adding dependencies to this target, # This target depends on the DLL. When adding dependencies to this target,
# any depended-on-target which is contained inside the DLL is replaced # any depended-on-target which is contained inside the DLL is replaced
# with a dependency on the DLL. # with a dependency on the DLL.
...@@ -212,7 +212,7 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n") ...@@ -212,7 +212,7 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n")
"${_gtest_link_define}" "${_gtest_link_define}"
) )
elseif(${_build_type} STREQUAL "static" OR ${_build_type} STREQUAL "shared") elseif(_build_type STREQUAL "static" OR _build_type STREQUAL "shared")
add_library(${_NAME} "") add_library(${_NAME} "")
target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS}) target_sources(${_NAME} PRIVATE ${ABSL_CC_LIB_SRCS} ${ABSL_CC_LIB_HDRS})
target_link_libraries(${_NAME} target_link_libraries(${_NAME}
...@@ -273,7 +273,7 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n") ...@@ -273,7 +273,7 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n")
$<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}> $<INSTALL_INTERFACE:${ABSL_INSTALL_INCLUDEDIR}>
) )
if (${_build_type} STREQUAL "dll") if (_build_type STREQUAL "dll")
set(ABSL_CC_LIB_DEPS abseil_dll) set(ABSL_CC_LIB_DEPS abseil_dll)
endif() endif()
......
...@@ -51,7 +51,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) ...@@ -51,7 +51,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# when absl is included as subproject (i.e. using add_subdirectory(abseil-cpp)) # when absl is included as subproject (i.e. using add_subdirectory(abseil-cpp))
# in the source tree of a project that uses it, install rules are disabled. # in the source tree of a project that uses it, install rules are disabled.
if(NOT "^${CMAKE_SOURCE_DIR}$" STREQUAL "^${PROJECT_SOURCE_DIR}$") if(NOT CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
option(ABSL_ENABLE_INSTALL "Enable install rule" OFF) option(ABSL_ENABLE_INSTALL "Enable install rule" OFF)
else() else()
option(ABSL_ENABLE_INSTALL "Enable install rule" ON) option(ABSL_ENABLE_INSTALL "Enable install rule" ON)
......
...@@ -12,16 +12,16 @@ else() ...@@ -12,16 +12,16 @@ else()
set(ABSL_BUILD_DLL FALSE) set(ABSL_BUILD_DLL FALSE)
endif() endif()
if("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "x86_64|amd64|AMD64") if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64")
if (MSVC) if (MSVC)
set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_MSVC_X64_FLAGS}") set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_MSVC_X64_FLAGS}")
else() else()
set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_X64_FLAGS}") set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_X64_FLAGS}")
endif() endif()
elseif("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "arm.*|aarch64") elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm.*|aarch64")
if ("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") if (CMAKE_SIZEOF_VOID_P STREQUAL "8")
set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_ARM64_FLAGS}") set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_ARM64_FLAGS}")
elseif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "4") elseif(CMAKE_SIZEOF_VOID_P STREQUAL "4")
set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_ARM32_FLAGS}") set(ABSL_RANDOM_RANDEN_COPTS "${ABSL_RANDOM_HWAES_ARM32_FLAGS}")
else() else()
message(WARNING "Value of CMAKE_SIZEOF_VOID_P (${CMAKE_SIZEOF_VOID_P}) is not supported.") message(WARNING "Value of CMAKE_SIZEOF_VOID_P (${CMAKE_SIZEOF_VOID_P}) is not supported.")
...@@ -32,10 +32,10 @@ else() ...@@ -32,10 +32,10 @@ else()
endif() endif()
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(ABSL_DEFAULT_COPTS "${ABSL_GCC_FLAGS}") set(ABSL_DEFAULT_COPTS "${ABSL_GCC_FLAGS}")
set(ABSL_TEST_COPTS "${ABSL_GCC_FLAGS};${ABSL_GCC_TEST_FLAGS}") set(ABSL_TEST_COPTS "${ABSL_GCC_FLAGS};${ABSL_GCC_TEST_FLAGS}")
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# MATCHES so we get both Clang and AppleClang # MATCHES so we get both Clang and AppleClang
if(MSVC) if(MSVC)
# clang-cl is half MSVC, half LLVM # clang-cl is half MSVC, half LLVM
...@@ -45,7 +45,7 @@ elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") ...@@ -45,7 +45,7 @@ elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
else() else()
set(ABSL_DEFAULT_COPTS "${ABSL_LLVM_FLAGS}") set(ABSL_DEFAULT_COPTS "${ABSL_LLVM_FLAGS}")
set(ABSL_TEST_COPTS "${ABSL_LLVM_FLAGS};${ABSL_LLVM_TEST_FLAGS}") set(ABSL_TEST_COPTS "${ABSL_LLVM_FLAGS};${ABSL_LLVM_TEST_FLAGS}")
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# AppleClang doesn't have lsan # AppleClang doesn't have lsan
# https://developer.apple.com/documentation/code_diagnostics # https://developer.apple.com/documentation/code_diagnostics
if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5) if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5)
...@@ -54,7 +54,7 @@ elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") ...@@ -54,7 +54,7 @@ elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
endif() endif()
endif() endif()
endif() endif()
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
set(ABSL_DEFAULT_COPTS "${ABSL_MSVC_FLAGS}") set(ABSL_DEFAULT_COPTS "${ABSL_MSVC_FLAGS}")
set(ABSL_TEST_COPTS "${ABSL_MSVC_FLAGS};${ABSL_MSVC_TEST_FLAGS}") set(ABSL_TEST_COPTS "${ABSL_MSVC_FLAGS};${ABSL_MSVC_TEST_FLAGS}")
set(ABSL_DEFAULT_LINKOPTS "${ABSL_MSVC_LINKOPTS}") set(ABSL_DEFAULT_LINKOPTS "${ABSL_MSVC_LINKOPTS}")
......
...@@ -269,10 +269,12 @@ cc_library( ...@@ -269,10 +269,12 @@ cc_library(
name = "cord_internal", name = "cord_internal",
srcs = [ srcs = [
"internal/cord_internal.cc", "internal/cord_internal.cc",
"internal/cord_rep_ring.cc",
], ],
hdrs = [ hdrs = [
"internal/cord_internal.h", "internal/cord_internal.h",
"internal/cord_rep_flat.h", "internal/cord_rep_flat.h",
"internal/cord_rep_ring.h",
], ],
copts = ABSL_DEFAULT_COPTS, copts = ABSL_DEFAULT_COPTS,
visibility = [ visibility = [
...@@ -281,9 +283,13 @@ cc_library( ...@@ -281,9 +283,13 @@ cc_library(
deps = [ deps = [
":strings", ":strings",
"//absl/base:base_internal", "//absl/base:base_internal",
"//absl/base:config",
"//absl/base:core_headers", "//absl/base:core_headers",
"//absl/base:raw_logging_internal",
"//absl/base:throw_delegate",
"//absl/container:compressed_tuple", "//absl/container:compressed_tuple",
"//absl/container:inlined_vector", "//absl/container:inlined_vector",
"//absl/container:layout",
"//absl/meta:type_traits", "//absl/meta:type_traits",
], ],
) )
...@@ -348,6 +354,23 @@ cc_test( ...@@ -348,6 +354,23 @@ cc_test(
) )
cc_test( cc_test(
name = "cord_ring_test",
size = "medium",
srcs = ["cord_ring_test.cc"],
copts = ABSL_TEST_COPTS,
visibility = ["//visibility:private"],
deps = [
":cord_internal",
":strings",
"//absl/base:config",
"//absl/base:core_headers",
"//absl/base:raw_logging_internal",
"//absl/debugging:leak_check",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "substitute_test", name = "substitute_test",
size = "small", size = "small",
srcs = ["substitute_test.cc"], srcs = ["substitute_test.cc"],
......
...@@ -558,6 +558,8 @@ absl_cc_library( ...@@ -558,6 +558,8 @@ absl_cc_library(
"cord.cc" "cord.cc"
"internal/cord_internal.cc" "internal/cord_internal.cc"
"internal/cord_internal.h" "internal/cord_internal.h"
"internal/cord_rep_ring.h"
"internal/cord_rep_ring.cc"
"internal/cord_rep_flat.h" "internal/cord_rep_flat.h"
COPTS COPTS
${ABSL_DEFAULT_COPTS} ${ABSL_DEFAULT_COPTS}
...@@ -565,6 +567,7 @@ absl_cc_library( ...@@ -565,6 +567,7 @@ absl_cc_library(
absl::base absl::base
absl::base_internal absl::base_internal
absl::compressed_tuple absl::compressed_tuple
absl::config
absl::core_headers absl::core_headers
absl::endian absl::endian
absl::fixed_array absl::fixed_array
...@@ -574,6 +577,7 @@ absl_cc_library( ...@@ -574,6 +577,7 @@ absl_cc_library(
absl::raw_logging_internal absl::raw_logging_internal
absl::strings absl::strings
absl::strings_internal absl::strings_internal
absl::throw_delegate
absl::type_traits absl::type_traits
PUBLIC PUBLIC
) )
...@@ -609,3 +613,20 @@ absl_cc_test( ...@@ -609,3 +613,20 @@ absl_cc_test(
absl::fixed_array absl::fixed_array
gmock_main gmock_main
) )
absl_cc_test(
NAME
cord_ring_test
SRCS
"cord_ring_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
absl::config
absl::cord
absl::strings
absl::base
absl::core_headers
absl::raw_logging_internal
gmock_main
)
...@@ -197,11 +197,15 @@ TEST(AsciiStrTo, Lower) { ...@@ -197,11 +197,15 @@ TEST(AsciiStrTo, Lower) {
const std::string str("GHIJKL"); const std::string str("GHIJKL");
const std::string str2("MNOPQR"); const std::string str2("MNOPQR");
const absl::string_view sp(str2); const absl::string_view sp(str2);
std::string mutable_str("STUVWX");
EXPECT_EQ("abcdef", absl::AsciiStrToLower(buf)); EXPECT_EQ("abcdef", absl::AsciiStrToLower(buf));
EXPECT_EQ("ghijkl", absl::AsciiStrToLower(str)); EXPECT_EQ("ghijkl", absl::AsciiStrToLower(str));
EXPECT_EQ("mnopqr", absl::AsciiStrToLower(sp)); EXPECT_EQ("mnopqr", absl::AsciiStrToLower(sp));
absl::AsciiStrToLower(&mutable_str);
EXPECT_EQ("stuvwx", mutable_str);
char mutable_buf[] = "Mutable"; char mutable_buf[] = "Mutable";
std::transform(mutable_buf, mutable_buf + strlen(mutable_buf), std::transform(mutable_buf, mutable_buf + strlen(mutable_buf),
mutable_buf, absl::ascii_tolower); mutable_buf, absl::ascii_tolower);
......
...@@ -255,50 +255,49 @@ inline void Cord::InlineRep::set_data(const char* data, size_t n, ...@@ -255,50 +255,49 @@ inline void Cord::InlineRep::set_data(const char* data, size_t n,
bool nullify_tail) { bool nullify_tail) {
static_assert(kMaxInline == 15, "set_data is hard-coded for a length of 15"); static_assert(kMaxInline == 15, "set_data is hard-coded for a length of 15");
cord_internal::SmallMemmove(data_.as_chars, data, n, nullify_tail); cord_internal::SmallMemmove(data_.as_chars(), data, n, nullify_tail);
set_tagged_size(static_cast<char>(n)); set_inline_size(n);
} }
inline char* Cord::InlineRep::set_data(size_t n) { inline char* Cord::InlineRep::set_data(size_t n) {
assert(n <= kMaxInline); assert(n <= kMaxInline);
ResetToEmpty(); ResetToEmpty();
set_tagged_size(static_cast<char>(n)); set_inline_size(n);
return data_.as_chars; return data_.as_chars();
} }
inline CordRep* Cord::InlineRep::force_tree(size_t extra_hint) { inline CordRep* Cord::InlineRep::force_tree(size_t extra_hint) {
size_t len = tagged_size(); if (data_.is_tree()) {
if (len > kMaxInline) { return data_.as_tree();
return data_.as_tree.rep;
} }
size_t len = inline_size();
CordRepFlat* result = CordRepFlat::New(len + extra_hint); CordRepFlat* result = CordRepFlat::New(len + extra_hint);
result->length = len; result->length = len;
static_assert(kMinFlatLength >= sizeof(data_.as_chars), ""); static_assert(kMinFlatLength >= sizeof(data_), "");
memcpy(result->Data(), data_.as_chars, sizeof(data_.as_chars)); memcpy(result->Data(), data_.as_chars(), sizeof(data_));
set_tree(result); set_tree(result);
return result; return result;
} }
inline void Cord::InlineRep::reduce_size(size_t n) { inline void Cord::InlineRep::reduce_size(size_t n) {
size_t tag = tagged_size(); size_t tag = inline_size();
assert(tag <= kMaxInline); assert(tag <= kMaxInline);
assert(tag >= n); assert(tag >= n);
tag -= n; tag -= n;
memset(data_.as_chars + tag, 0, n); memset(data_.as_chars() + tag, 0, n);
set_tagged_size(static_cast<char>(tag)); set_inline_size(static_cast<char>(tag));
} }
inline void Cord::InlineRep::remove_prefix(size_t n) { inline void Cord::InlineRep::remove_prefix(size_t n) {
cord_internal::SmallMemmove(data_.as_chars, data_.as_chars + n, cord_internal::SmallMemmove(data_.as_chars(), data_.as_chars() + n,
tagged_size() - n); inline_size() - n);
reduce_size(n); reduce_size(n);
} }
void Cord::InlineRep::AppendTree(CordRep* tree) { void Cord::InlineRep::AppendTree(CordRep* tree) {
if (tree == nullptr) return; if (tree == nullptr) return;
size_t len = tagged_size(); if (data_.is_empty()) {
if (len == 0) {
set_tree(tree); set_tree(tree);
} else { } else {
set_tree(Concat(force_tree(0), tree)); set_tree(Concat(force_tree(0), tree));
...@@ -307,8 +306,7 @@ void Cord::InlineRep::AppendTree(CordRep* tree) { ...@@ -307,8 +306,7 @@ void Cord::InlineRep::AppendTree(CordRep* tree) {
void Cord::InlineRep::PrependTree(CordRep* tree) { void Cord::InlineRep::PrependTree(CordRep* tree) {
assert(tree != nullptr); assert(tree != nullptr);
size_t len = tagged_size(); if (data_.is_empty()) {
if (len == 0) {
set_tree(tree); set_tree(tree);
} else { } else {
set_tree(Concat(tree, force_tree(0))); set_tree(Concat(tree, force_tree(0)));
...@@ -363,12 +361,14 @@ void Cord::InlineRep::GetAppendRegion(char** region, size_t* size, ...@@ -363,12 +361,14 @@ void Cord::InlineRep::GetAppendRegion(char** region, size_t* size,
} }
// Try to fit in the inline buffer if possible. // Try to fit in the inline buffer if possible.
size_t inline_length = tagged_size(); if (!is_tree()) {
if (inline_length < kMaxInline && max_length <= kMaxInline - inline_length) { size_t inline_length = inline_size();
*region = data_.as_chars + inline_length; if (max_length <= kMaxInline - inline_length) {
*size = max_length; *region = data_.as_chars() + inline_length;
set_tagged_size(static_cast<char>(inline_length + max_length)); *size = max_length;
return; set_inline_size(inline_length + max_length);
return;
}
} }
CordRep* root = force_tree(max_length); CordRep* root = force_tree(max_length);
...@@ -390,12 +390,14 @@ void Cord::InlineRep::GetAppendRegion(char** region, size_t* size) { ...@@ -390,12 +390,14 @@ void Cord::InlineRep::GetAppendRegion(char** region, size_t* size) {
const size_t max_length = std::numeric_limits<size_t>::max(); const size_t max_length = std::numeric_limits<size_t>::max();
// Try to fit in the inline buffer if possible. // Try to fit in the inline buffer if possible.
size_t inline_length = tagged_size(); if (!data_.is_tree()) {
if (inline_length < kMaxInline) { size_t inline_length = inline_size();
*region = data_.as_chars + inline_length; if (inline_length < kMaxInline) {
*size = kMaxInline - inline_length; *region = data_.as_chars() + inline_length;
set_tagged_size(kMaxInline); *size = kMaxInline - inline_length;
return; set_inline_size(kMaxInline);
return;
}
} }
CordRep* root = force_tree(max_length); CordRep* root = force_tree(max_length);
...@@ -549,24 +551,25 @@ template Cord& Cord::operator=(std::string&& src); ...@@ -549,24 +551,25 @@ template Cord& Cord::operator=(std::string&& src);
// we keep it here to make diffs easier. // we keep it here to make diffs easier.
void Cord::InlineRep::AppendArray(const char* src_data, size_t src_size) { void Cord::InlineRep::AppendArray(const char* src_data, size_t src_size) {
if (src_size == 0) return; // memcpy(_, nullptr, 0) is undefined. if (src_size == 0) return; // memcpy(_, nullptr, 0) is undefined.
// Try to fit in the inline buffer if possible.
size_t inline_length = tagged_size();
if (inline_length < kMaxInline && src_size <= kMaxInline - inline_length) {
// Append new data to embedded array
set_tagged_size(static_cast<char>(inline_length + src_size));
memcpy(data_.as_chars + inline_length, src_data, src_size);
return;
}
CordRep* root = tree();
size_t appended = 0; size_t appended = 0;
if (root) { CordRep* root = nullptr;
if (is_tree()) {
root = data_.as_tree();
char* region; char* region;
if (PrepareAppendRegion(root, &region, &appended, src_size)) { if (PrepareAppendRegion(root, &region, &appended, src_size)) {
memcpy(region, src_data, appended); memcpy(region, src_data, appended);
} }
} else { } else {
// Try to fit in the inline buffer if possible.
size_t inline_length = inline_size();
if (src_size <= kMaxInline - inline_length) {
// Append new data to embedded array
memcpy(data_.as_chars() + inline_length, src_data, src_size);
set_inline_size(inline_length + src_size);
return;
}
// It is possible that src_data == data_, but when we transition from an // It is possible that src_data == data_, but when we transition from an
// InlineRep to a tree we need to assign data_ = root via set_tree. To // InlineRep to a tree we need to assign data_ = root via set_tree. To
// avoid corrupting the source data before we copy it, delay calling // avoid corrupting the source data before we copy it, delay calling
...@@ -578,7 +581,7 @@ void Cord::InlineRep::AppendArray(const char* src_data, size_t src_size) { ...@@ -578,7 +581,7 @@ void Cord::InlineRep::AppendArray(const char* src_data, size_t src_size) {
root = CordRepFlat::New(std::max<size_t>(size1, size2)); root = CordRepFlat::New(std::max<size_t>(size1, size2));
appended = std::min( appended = std::min(
src_size, root->flat()->Capacity() - inline_length); src_size, root->flat()->Capacity() - inline_length);
memcpy(root->flat()->Data(), data_.as_chars, inline_length); memcpy(root->flat()->Data(), data_.as_chars(), inline_length);
memcpy(root->flat()->Data() + inline_length, src_data, appended); memcpy(root->flat()->Data() + inline_length, src_data, appended);
root->length = inline_length + appended; root->length = inline_length + appended;
set_tree(root); set_tree(root);
...@@ -684,18 +687,19 @@ void Cord::Prepend(const Cord& src) { ...@@ -684,18 +687,19 @@ void Cord::Prepend(const Cord& src) {
void Cord::Prepend(absl::string_view src) { void Cord::Prepend(absl::string_view src) {
if (src.empty()) return; // memcpy(_, nullptr, 0) is undefined. if (src.empty()) return; // memcpy(_, nullptr, 0) is undefined.
size_t cur_size = contents_.size(); if (!contents_.is_tree()) {
if (!contents_.is_tree() && cur_size + src.size() <= InlineRep::kMaxInline) { size_t cur_size = contents_.inline_size();
// Use embedded storage. if (cur_size + src.size() <= InlineRep::kMaxInline) {
char data[InlineRep::kMaxInline + 1] = {0}; // Use embedded storage.
data[InlineRep::kMaxInline] = cur_size + src.size(); // set size char data[InlineRep::kMaxInline + 1] = {0};
memcpy(data, src.data(), src.size()); memcpy(data, src.data(), src.size());
memcpy(data + src.size(), contents_.data(), cur_size); memcpy(data + src.size(), contents_.data(), cur_size);
memcpy(reinterpret_cast<void*>(&contents_), data, memcpy(contents_.data_.as_chars(), data, InlineRep::kMaxInline + 1);
InlineRep::kMaxInline + 1); contents_.set_inline_size(cur_size + src.size());
} else { return;
contents_.PrependTree(NewTree(src.data(), src.size(), 0)); }
} }
contents_.PrependTree(NewTree(src.data(), src.size(), 0));
} }
template <typename T, Cord::EnableIfString<T>> template <typename T, Cord::EnableIfString<T>>
...@@ -888,7 +892,7 @@ Cord Cord::Subcord(size_t pos, size_t new_size) const { ...@@ -888,7 +892,7 @@ Cord Cord::Subcord(size_t pos, size_t new_size) const {
} else if (new_size <= InlineRep::kMaxInline) { } else if (new_size <= InlineRep::kMaxInline) {
Cord::ChunkIterator it = chunk_begin(); Cord::ChunkIterator it = chunk_begin();
it.AdvanceBytes(pos); it.AdvanceBytes(pos);
char* dest = sub_cord.contents_.data_.as_chars; char* dest = sub_cord.contents_.data_.as_chars();
size_t remaining_size = new_size; size_t remaining_size = new_size;
while (remaining_size > it->size()) { while (remaining_size > it->size()) {
cord_internal::SmallMemmove(dest, it->data(), it->size()); cord_internal::SmallMemmove(dest, it->data(), it->size());
...@@ -897,7 +901,7 @@ Cord Cord::Subcord(size_t pos, size_t new_size) const { ...@@ -897,7 +901,7 @@ Cord Cord::Subcord(size_t pos, size_t new_size) const {
++it; ++it;
} }
cord_internal::SmallMemmove(dest, it->data(), remaining_size); cord_internal::SmallMemmove(dest, it->data(), remaining_size);
sub_cord.contents_.set_tagged_size(new_size); sub_cord.contents_.set_inline_size(new_size);
} else { } else {
sub_cord.contents_.set_tree(NewSubRange(tree, pos, new_size)); sub_cord.contents_.set_tree(NewSubRange(tree, pos, new_size));
} }
...@@ -1086,9 +1090,8 @@ bool ComputeCompareResult<bool>(int memcmp_res) { ...@@ -1086,9 +1090,8 @@ bool ComputeCompareResult<bool>(int memcmp_res) {
// Helper routine. Locates the first flat chunk of the Cord without // Helper routine. Locates the first flat chunk of the Cord without
// initializing the iterator. // initializing the iterator.
inline absl::string_view Cord::InlineRep::FindFlatStartPiece() const { inline absl::string_view Cord::InlineRep::FindFlatStartPiece() const {
size_t n = tagged_size(); if (!is_tree()) {
if (n <= kMaxInline) { return absl::string_view(data_.as_chars(), data_.inline_size());
return absl::string_view(data_.as_chars, n);
} }
CordRep* node = tree(); CordRep* node = tree();
......
...@@ -665,8 +665,6 @@ class Cord { ...@@ -665,8 +665,6 @@ class Cord {
public: public:
static constexpr unsigned char kMaxInline = cord_internal::kMaxInline; static constexpr unsigned char kMaxInline = cord_internal::kMaxInline;
static_assert(kMaxInline >= sizeof(absl::cord_internal::CordRep*), ""); static_assert(kMaxInline >= sizeof(absl::cord_internal::CordRep*), "");
static constexpr unsigned char kTreeFlag = cord_internal::kTreeFlag;
static constexpr unsigned char kProfiledFlag = cord_internal::kProfiledFlag;
constexpr InlineRep() : data_() {} constexpr InlineRep() : data_() {}
InlineRep(const InlineRep& src); InlineRep(const InlineRep& src);
...@@ -685,6 +683,7 @@ class Cord { ...@@ -685,6 +683,7 @@ class Cord {
char* set_data(size_t n); // Write data to the result char* set_data(size_t n); // Write data to the result
// Returns nullptr if holding bytes // Returns nullptr if holding bytes
absl::cord_internal::CordRep* tree() const; absl::cord_internal::CordRep* tree() const;
absl::cord_internal::CordRep* as_tree() const;
// Discards old pointer, if any // Discards old pointer, if any
void set_tree(absl::cord_internal::CordRep* rep); void set_tree(absl::cord_internal::CordRep* rep);
// Replaces a tree with a new root. This is faster than set_tree, but it // Replaces a tree with a new root. This is faster than set_tree, but it
...@@ -728,13 +727,13 @@ class Cord { ...@@ -728,13 +727,13 @@ class Cord {
memcpy(&(*dst)[0], &data_, sizeof(data_) - 1); memcpy(&(*dst)[0], &data_, sizeof(data_) - 1);
// erase is faster than resize because the logic for memory allocation is // erase is faster than resize because the logic for memory allocation is
// not needed. // not needed.
dst->erase(tagged_size()); dst->erase(inline_size());
} }
// Copies the inline contents into `dst`. Assumes the cord is not empty. // Copies the inline contents into `dst`. Assumes the cord is not empty.
void CopyToArray(char* dst) const; void CopyToArray(char* dst) const;
bool is_tree() const { return tagged_size() > kMaxInline; } bool is_tree() const { return data_.is_tree(); }
private: private:
friend class Cord; friend class Cord;
...@@ -745,14 +744,8 @@ class Cord { ...@@ -745,14 +744,8 @@ class Cord {
void ResetToEmpty() { data_ = {}; } void ResetToEmpty() { data_ = {}; }
// This uses reinterpret_cast instead of the union to avoid accessing the void set_inline_size(size_t size) { data_.set_inline_size(size); }
// inactive union element. The tagged size is not a common prefix. size_t inline_size() const { return data_.inline_size(); }
void set_tagged_size(char new_tag) {
reinterpret_cast<char*>(&data_)[kMaxInline] = new_tag;
}
char tagged_size() const {
return reinterpret_cast<const char*>(&data_)[kMaxInline];
}
cord_internal::InlineData data_; cord_internal::InlineData data_;
}; };
...@@ -948,35 +941,39 @@ inline void Cord::InlineRep::Swap(Cord::InlineRep* rhs) { ...@@ -948,35 +941,39 @@ inline void Cord::InlineRep::Swap(Cord::InlineRep* rhs) {
} }
inline const char* Cord::InlineRep::data() const { inline const char* Cord::InlineRep::data() const {
return is_tree() ? nullptr : data_.as_chars; return is_tree() ? nullptr : data_.as_chars();
}
inline absl::cord_internal::CordRep* Cord::InlineRep::as_tree() const {
assert(data_.is_tree());
return data_.as_tree();
} }
inline absl::cord_internal::CordRep* Cord::InlineRep::tree() const { inline absl::cord_internal::CordRep* Cord::InlineRep::tree() const {
if (is_tree()) { if (is_tree()) {
return data_.as_tree.rep; return as_tree();
} else { } else {
return nullptr; return nullptr;
} }
} }
inline bool Cord::InlineRep::empty() const { return tagged_size() == 0; } inline bool Cord::InlineRep::empty() const { return data_.is_empty(); }
inline size_t Cord::InlineRep::size() const { inline size_t Cord::InlineRep::size() const {
const char tag = tagged_size(); return is_tree() ? as_tree()->length : inline_size();
if (tag <= kMaxInline) return tag;
return static_cast<size_t>(tree()->length);
} }
inline void Cord::InlineRep::set_tree(absl::cord_internal::CordRep* rep) { inline void Cord::InlineRep::set_tree(absl::cord_internal::CordRep* rep) {
if (rep == nullptr) { if (rep == nullptr) {
ResetToEmpty(); ResetToEmpty();
} else { } else {
bool was_tree = is_tree(); if (data_.is_tree()) {
data_.as_tree = {rep, {}, tagged_size()}; // `data_` already holds a 'tree' value and an optional cordz_info value.
if (!was_tree) { // Replace the tree value only, leaving the cordz_info value unchanged.
// If we were not a tree already, set the tag. data_.set_tree(rep);
// Otherwise, leave it alone because it might have the profile bit on. } else {
set_tagged_size(kTreeFlag); // `data_` contains inlined data: initialize data_ to tree value `rep`.
data_.make_tree(rep);
} }
} }
} }
...@@ -987,7 +984,7 @@ inline void Cord::InlineRep::replace_tree(absl::cord_internal::CordRep* rep) { ...@@ -987,7 +984,7 @@ inline void Cord::InlineRep::replace_tree(absl::cord_internal::CordRep* rep) {
set_tree(rep); set_tree(rep);
return; return;
} }
data_.as_tree = {rep, {}, tagged_size()}; data_.set_tree(rep);
} }
inline absl::cord_internal::CordRep* Cord::InlineRep::clear() { inline absl::cord_internal::CordRep* Cord::InlineRep::clear() {
...@@ -998,9 +995,9 @@ inline absl::cord_internal::CordRep* Cord::InlineRep::clear() { ...@@ -998,9 +995,9 @@ inline absl::cord_internal::CordRep* Cord::InlineRep::clear() {
inline void Cord::InlineRep::CopyToArray(char* dst) const { inline void Cord::InlineRep::CopyToArray(char* dst) const {
assert(!is_tree()); assert(!is_tree());
size_t n = tagged_size(); size_t n = inline_size();
assert(n != 0); assert(n != 0);
cord_internal::SmallMemmove(dst, data_.as_chars, n); cord_internal::SmallMemmove(dst, data_.as_chars(), n);
} }
constexpr inline Cord::Cord() noexcept {} constexpr inline Cord::Cord() noexcept {}
...@@ -1011,11 +1008,9 @@ constexpr Cord::Cord(strings_internal::StringConstant<T>) ...@@ -1011,11 +1008,9 @@ constexpr Cord::Cord(strings_internal::StringConstant<T>)
cord_internal::kMaxInline cord_internal::kMaxInline
? cord_internal::InlineData( ? cord_internal::InlineData(
strings_internal::StringConstant<T>::value) strings_internal::StringConstant<T>::value)
: cord_internal::InlineData(cord_internal::AsTree{ : cord_internal::InlineData(
&cord_internal::ConstInitExternalStorage< &cord_internal::ConstInitExternalStorage<
strings_internal::StringConstant<T>>::value, strings_internal::StringConstant<T>>::value)) {}
{},
cord_internal::kTreeFlag})) {}
inline Cord& Cord::operator=(const Cord& x) { inline Cord& Cord::operator=(const Cord& x) {
contents_ = x.contents_; contents_ = x.contents_;
...@@ -1107,12 +1102,12 @@ inline bool Cord::StartsWith(absl::string_view rhs) const { ...@@ -1107,12 +1102,12 @@ inline bool Cord::StartsWith(absl::string_view rhs) const {
inline Cord::ChunkIterator::ChunkIterator(const Cord* cord) inline Cord::ChunkIterator::ChunkIterator(const Cord* cord)
: bytes_remaining_(cord->size()) { : bytes_remaining_(cord->size()) {
if (cord->empty()) return;
if (cord->contents_.is_tree()) { if (cord->contents_.is_tree()) {
stack_of_right_children_.push_back(cord->contents_.tree()); stack_of_right_children_.push_back(cord->contents_.as_tree());
operator++(); operator++();
} else { } else {
current_chunk_ = absl::string_view(cord->contents_.data(), cord->size()); current_chunk_ =
absl::string_view(cord->contents_.data(), bytes_remaining_);
} }
} }
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "absl/container/inlined_vector.h" #include "absl/container/inlined_vector.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"
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
...@@ -48,6 +49,9 @@ void CordRep::Destroy(CordRep* rep) { ...@@ -48,6 +49,9 @@ void CordRep::Destroy(CordRep* rep) {
rep = left; rep = left;
continue; continue;
} }
} else if (rep->tag == RING) {
CordRepRing::Destroy(rep->ring());
rep = nullptr;
} else if (rep->tag == EXTERNAL) { } else if (rep->tag == EXTERNAL) {
CordRepExternal::Delete(rep); CordRepExternal::Delete(rep);
rep = nullptr; rep = nullptr;
......
// Copyright 2020 The Abseil Authors. // Copyright 2021 The Abseil Authors.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <cstdint> #include <cstdint>
#include <type_traits> #include <type_traits>
#include "absl/base/config.h"
#include "absl/base/internal/invoke.h" #include "absl/base/internal/invoke.h"
#include "absl/base/optimization.h" #include "absl/base/optimization.h"
#include "absl/container/internal/compressed_tuple.h" #include "absl/container/internal/compressed_tuple.h"
...@@ -145,13 +146,14 @@ struct CordRepConcat; ...@@ -145,13 +146,14 @@ struct CordRepConcat;
struct CordRepExternal; struct CordRepExternal;
struct CordRepFlat; struct CordRepFlat;
struct CordRepSubstring; struct CordRepSubstring;
class CordRepRing;
// Various representations that we allow // Various representations that we allow
enum CordRepKind { enum CordRepKind {
CONCAT = 0, CONCAT = 0,
EXTERNAL = 1, EXTERNAL = 1,
SUBSTRING = 2, SUBSTRING = 2,
RING = 3, RING = 3,
// 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 224 value is based on // starting with FLAT, and limited to MAX_FLAT_TAG. The 224 value is based on
...@@ -160,7 +162,7 @@ enum CordRepKind { ...@@ -160,7 +162,7 @@ enum CordRepKind {
// 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 = 4, FLAT = 4,
MAX_FLAT_TAG = 224, MAX_FLAT_TAG = 224
}; };
struct CordRep { struct CordRep {
...@@ -177,6 +179,8 @@ struct CordRep { ...@@ -177,6 +179,8 @@ struct CordRep {
uint8_t tag; uint8_t tag;
char storage[1]; // Starting point for flat array: MUST BE LAST FIELD char storage[1]; // Starting point for flat array: MUST BE LAST FIELD
inline CordRepRing* ring();
inline const CordRepRing* ring() const;
inline CordRepConcat* concat(); inline CordRepConcat* concat();
inline const CordRepConcat* concat() const; inline const CordRepConcat* concat() const;
inline CordRepSubstring* substring(); inline CordRepSubstring* substring();
...@@ -306,45 +310,165 @@ CordRepExternal ConstInitExternalStorage<Str>::value(Str::value); ...@@ -306,45 +310,165 @@ CordRepExternal ConstInitExternalStorage<Str>::value(Str::value);
enum { enum {
kMaxInline = 15, kMaxInline = 15,
// Tag byte & kMaxInline means we are storing a pointer.
kTreeFlag = 1 << 4,
// Tag byte & kProfiledFlag means we are profiling the Cord.
kProfiledFlag = 1 << 5
};
// If the data has length <= kMaxInline, we store it in `as_chars`, and
// store the size in `tagged_size`.
// Else we store it in a tree and store a pointer to that tree in
// `as_tree.rep` and store a tag in `tagged_size`.
struct AsTree {
absl::cord_internal::CordRep* rep;
char padding[kMaxInline + 1 - sizeof(absl::cord_internal::CordRep*) - 1];
char tagged_size;
}; };
constexpr char GetOrNull(absl::string_view data, size_t pos) { constexpr char GetOrNull(absl::string_view data, size_t pos) {
return pos < data.size() ? data[pos] : '\0'; return pos < data.size() ? data[pos] : '\0';
} }
union InlineData { // We store cordz_info as 64 bit pointer value in big endian format. This
constexpr InlineData() : as_chars{} {} // guarantees that the least significant byte of cordz_info matches the last
explicit constexpr InlineData(AsTree tree) : as_tree(tree) {} // byte of the inline data representation in as_chars_, which holds the inlined
// size or the 'is_tree' bit.
using cordz_info_t = int64_t;
// Assert that the `cordz_info` pointer value perfectly overlaps the last half
// of `as_chars_` and can hold a pointer value.
static_assert(sizeof(cordz_info_t) * 2 == kMaxInline + 1, "");
static_assert(sizeof(cordz_info_t) >= sizeof(intptr_t), "");
// BigEndianByte() creates a big endian representation of 'value', i.e.: a big
// endian value where the last byte in the host's representation holds 'value`,
// with all other bytes being 0.
static constexpr cordz_info_t BigEndianByte(unsigned char value) {
#if defined(ABSL_IS_BIG_ENDIAN)
return value;
#else
return static_cast<cordz_info_t>(value) << ((sizeof(cordz_info_t) - 1) * 8);
#endif
}
class InlineData {
public:
// kNullCordzInfo holds the big endian representation of intptr_t(1)
// This is the 'null' / initial value of 'cordz_info'. The null value
// is specifically big endian 1 as with 64-bit pointers, the last
// byte of cordz_info overlaps with the last byte holding the tag.
static constexpr cordz_info_t kNullCordzInfo = BigEndianByte(1);
// kFakeCordzInfo holds a 'fake', non-null cordz-info value we use to
// emulate the previous 'kProfiled' tag logic in 'set_profiled' until
// cord code is changed to store cordz_info values in InlineData.
static constexpr cordz_info_t kFakeCordzInfo = BigEndianByte(9);
constexpr InlineData() : as_chars_{0} {}
explicit constexpr InlineData(CordRep* rep) : as_tree_(rep) {}
explicit constexpr InlineData(absl::string_view chars) explicit constexpr InlineData(absl::string_view chars)
: as_chars{GetOrNull(chars, 0), GetOrNull(chars, 1), : as_chars_{
GetOrNull(chars, 2), GetOrNull(chars, 3), GetOrNull(chars, 0), GetOrNull(chars, 1),
GetOrNull(chars, 4), GetOrNull(chars, 5), GetOrNull(chars, 2), GetOrNull(chars, 3),
GetOrNull(chars, 6), GetOrNull(chars, 7), GetOrNull(chars, 4), GetOrNull(chars, 5),
GetOrNull(chars, 8), GetOrNull(chars, 9), GetOrNull(chars, 6), GetOrNull(chars, 7),
GetOrNull(chars, 10), GetOrNull(chars, 11), GetOrNull(chars, 8), GetOrNull(chars, 9),
GetOrNull(chars, 12), GetOrNull(chars, 13), GetOrNull(chars, 10), GetOrNull(chars, 11),
GetOrNull(chars, 14), static_cast<char>(chars.size())} {} GetOrNull(chars, 12), GetOrNull(chars, 13),
GetOrNull(chars, 14), static_cast<char>((chars.size() << 1))} {}
AsTree as_tree;
char as_chars[kMaxInline + 1]; // Returns true if the current instance is empty.
// The 'empty value' is an inlined data value of zero length.
bool is_empty() const { return tag() == 0; }
// Returns true if the current instance holds a tree value.
bool is_tree() const { return (tag() & 1) != 0; }
// Returns true if the current instance holds a cordz_info value.
// Requires the current instance to hold a tree value.
bool is_profiled() const {
assert(is_tree());
return as_tree_.cordz_info != kNullCordzInfo;
}
// Returns a read only pointer to the character data inside this instance.
// Requires the current instance to hold inline data.
const char* as_chars() const {
assert(!is_tree());
return as_chars_;
}
// Returns a mutable pointer to the character data inside this instance.
// Should be used for 'write only' operations setting an inlined value.
// Applications can set the value of inlined data either before or after
// setting the inlined size, i.e., both of the below are valid:
//
// // Set inlined data and inline size
// memcpy(data_.as_chars(), data, size);
// data_.set_inline_size(size);
//
// // Set inlined size and inline data
// data_.set_inline_size(size);
// memcpy(data_.as_chars(), data, size);
//
// It's an error to read from the returned pointer without a preceding write
// if the current instance does not hold inline data, i.e.: is_tree() == true.
char* as_chars() { return as_chars_; }
// Returns the tree value of this value.
// Requires the current instance to hold a tree value.
CordRep* as_tree() const {
assert(is_tree());
return as_tree_.rep;
}
// Initialize this instance to holding the tree value `rep`,
// initializing the cordz_info to null, i.e.: 'not profiled'.
void make_tree(CordRep* rep) {
as_tree_.rep = rep;
as_tree_.cordz_info = kNullCordzInfo;
}
// Set the tree value of this instance to 'rep`.
// Requires the current instance to already hold a tree value.
// Does not affect the value of cordz_info.
void set_tree(CordRep* rep) {
assert(is_tree());
as_tree_.rep = rep;
}
// Returns the size of the inlined character data inside this instance.
// Requires the current instance to hold inline data.
size_t inline_size() const {
assert(!is_tree());
return tag() >> 1;
}
// Sets the size of the inlined character data inside this instance.
// Requires `size` to be <= kMaxInline.
// See the documentation on 'as_chars()' for more information and examples.
void set_inline_size(size_t size) {
ABSL_ASSERT(size <= kMaxInline);
tag() = static_cast<char>(size << 1);
}
// Sets or unsets the 'is_profiled' state of this instance.
// Requires the current instance to hold a tree value.
void set_profiled(bool profiled) {
assert(is_tree());
as_tree_.cordz_info = profiled ? kFakeCordzInfo : kNullCordzInfo;
}
private:
// See cordz_info_t for forced alignment and size of `cordz_info` details.
struct AsTree {
explicit constexpr AsTree(absl::cord_internal::CordRep* tree)
: rep(tree), cordz_info(kNullCordzInfo) {}
absl::cord_internal::CordRep* rep;
alignas(sizeof(cordz_info_t)) cordz_info_t cordz_info;
};
char& tag() { return reinterpret_cast<char*>(this)[kMaxInline]; }
char tag() const { return reinterpret_cast<const char*>(this)[kMaxInline]; }
// If the data has length <= kMaxInline, we store it in `as_chars_`, and
// store the size in the last char of `as_chars_` shifted left + 1.
// Else we store it in a tree and store a pointer to that tree in
// `as_tree_.rep` and store a tag in `tagged_size`.
union {
char as_chars_[kMaxInline + 1];
AsTree as_tree_;
};
}; };
static_assert(sizeof(InlineData) == kMaxInline + 1, ""); static_assert(sizeof(InlineData) == kMaxInline + 1, "");
static_assert(sizeof(AsTree) == sizeof(InlineData), "");
static_assert(offsetof(AsTree, tagged_size) == kMaxInline, "");
inline CordRepConcat* CordRep::concat() { inline CordRepConcat* CordRep::concat() {
assert(tag == CONCAT); assert(tag == CONCAT);
...@@ -386,6 +510,16 @@ inline const CordRepFlat* CordRep::flat() const { ...@@ -386,6 +510,16 @@ inline const CordRepFlat* CordRep::flat() const {
return reinterpret_cast<const CordRepFlat*>(this); return reinterpret_cast<const CordRepFlat*>(this);
} }
inline CordRepRing* CordRep::ring() {
assert(tag == RING);
return reinterpret_cast<CordRepRing*>(this);
}
inline const CordRepRing* CordRep::ring() const {
assert(tag == RING);
return reinterpret_cast<const CordRepRing*>(this);
}
inline CordRep* CordRep::Ref(CordRep* rep) { inline CordRep* CordRep::Ref(CordRep* rep) {
assert(rep != nullptr); assert(rep != nullptr);
rep->refcount.Increment(); rep->refcount.Increment();
......
...@@ -104,7 +104,8 @@ struct CordRepFlat : public CordRep { ...@@ -104,7 +104,8 @@ struct CordRepFlat : public CordRep {
// Flat CordReps are allocated and constructed with raw ::operator new and // Flat CordReps are allocated and constructed with raw ::operator new and
// placement new, and must be destructed and deallocated accordingly. // placement new, and must be destructed and deallocated accordingly.
static void Delete(CordRep*rep) { static void Delete(CordRep*rep) {
assert(rep->tag >= FLAT); assert(rep->tag >= FLAT && rep->tag <= MAX_FLAT_TAG);
#if defined(__cpp_sized_deallocation) #if defined(__cpp_sized_deallocation)
size_t size = TagToAllocatedSize(rep->tag); size_t size = TagToAllocatedSize(rep->tag);
rep->~CordRep(); rep->~CordRep();
...@@ -115,6 +116,7 @@ struct CordRepFlat : public CordRep { ...@@ -115,6 +116,7 @@ struct CordRepFlat : public CordRep {
#endif #endif
} }
// Returns a pointer to the data inside this flat rep.
char* Data() { return storage; } char* Data() { return storage; }
const char* Data() const { return storage; } const char* Data() const { return storage; }
......
...@@ -162,7 +162,7 @@ class ABSL_LOCKABLE Mutex { ...@@ -162,7 +162,7 @@ class ABSL_LOCKABLE Mutex {
// Mutex::Unlock() // Mutex::Unlock()
// //
// Releases this `Mutex` and returns it from the exclusive/write state to the // Releases this `Mutex` and returns it from the exclusive/write state to the
// free state. Caller must hold the `Mutex` exclusively. // free state. Calling thread must hold the `Mutex` exclusively.
void Unlock() ABSL_UNLOCK_FUNCTION(); void Unlock() ABSL_UNLOCK_FUNCTION();
// Mutex::TryLock() // Mutex::TryLock()
......
...@@ -353,9 +353,6 @@ absl_cc_test( ...@@ -353,9 +353,6 @@ absl_cc_test(
gmock_main gmock_main
) )
# TODO(cohenjon,zhangxy) Figure out why this test is failing on gcc 4.8
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)
else()
absl_cc_test( absl_cc_test(
NAME NAME
variant_exception_safety_test variant_exception_safety_test
...@@ -370,4 +367,3 @@ absl_cc_test( ...@@ -370,4 +367,3 @@ absl_cc_test(
absl::memory absl::memory
gmock_main gmock_main
) )
endif()
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