diff --git a/src/google/protobuf/BUILD.bazel b/src/google/protobuf/BUILD.bazel index 1275c73c7d..8e8f71b2a1 100644 --- a/src/google/protobuf/BUILD.bazel +++ b/src/google/protobuf/BUILD.bazel @@ -343,6 +343,7 @@ cc_library( "map.cc", "message_lite.cc", "parse_context.cc", + "raw_ptr.cc", "repeated_field.cc", "repeated_ptr_field.cc", "wire_format_lite.cc", @@ -371,6 +372,7 @@ cc_library( "metadata_lite.h", "parse_context.h", "port.h", + "raw_ptr.h", "repeated_field.h", "repeated_ptr_field.h", "serial_arena.h", diff --git a/src/google/protobuf/raw_ptr.cc b/src/google/protobuf/raw_ptr.cc new file mode 100644 index 0000000000..bdba8d5851 --- /dev/null +++ b/src/google/protobuf/raw_ptr.cc @@ -0,0 +1,48 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/raw_ptr.h" + +#include "absl/base/attributes.h" +#include "absl/base/optimization.h" + +// Must be included last. +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace internal { + +ABSL_CONST_INIT PROTOBUF_EXPORT + ABSL_CACHELINE_ALIGNED const char kZeroBuffer[ABSL_CACHELINE_SIZE] = {}; + +} // namespace internal +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/raw_ptr.h b/src/google/protobuf/raw_ptr.h new file mode 100644 index 0000000000..516a026623 --- /dev/null +++ b/src/google/protobuf/raw_ptr.h @@ -0,0 +1,81 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_RAW_PTR_H__ +#define GOOGLE_PROTOBUF_RAW_PTR_H__ + +#include + +#include "absl/base/optimization.h" + +// Must be included last. +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace internal { + +PROTOBUF_EXPORT ABSL_CACHELINE_ALIGNED extern const char + kZeroBuffer[std::max(ABSL_CACHELINE_SIZE, 64)]; + +// This class is trivially copyable/trivially destructible and constexpr +// constructible. The class allows for storing a raw pointer to a non-trivial +// object in a constexpr context. +template +class RawPtr { + public: + constexpr RawPtr() : RawPtr(kZeroBuffer) { + static_assert(sizeof(T) <= sizeof(kZeroBuffer), ""); + static_assert(alignof(T) <= ABSL_CACHELINE_SIZE, ""); + } + explicit constexpr RawPtr(const void* p) : p_(const_cast(p)) {} + + bool IsDefault() const { return p_ == kZeroBuffer; } + + void Set(const void* p) { p_ = const_cast(p); } + T* Get() const { return reinterpret_cast(p_); } + T* operator->() const { return Get(); } + T& operator*() const { return *Get(); } + + private: + void* p_; +}; + +constexpr void* DefaultRawPtr() { + return const_cast(static_cast(kZeroBuffer)); +} + +} // namespace internal +} // namespace protobuf +} // namespace google + +#include "google/protobuf/port_undef.inc" + +#endif // GOOGLE_PROTOBUF_RAW_PTR_H__ diff --git a/src/google/protobuf/raw_ptr_test.cc b/src/google/protobuf/raw_ptr_test.cc new file mode 100644 index 0000000000..1a6d569d38 --- /dev/null +++ b/src/google/protobuf/raw_ptr_test.cc @@ -0,0 +1,88 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/raw_ptr.h" + +#include + +#include +#include "absl/base/optimization.h" + +namespace google { +namespace protobuf { +namespace internal { +namespace { + +TEST(ZeroCacheline, Basic) { + for (int i = 0; i < ABSL_CACHELINE_SIZE; ++i) { + EXPECT_EQ(kZeroBuffer[i], 0) << i; + } + EXPECT_EQ(reinterpret_cast(kZeroBuffer) % ABSL_CACHELINE_SIZE, 0); +} + +struct Obj { + int i; +}; + +TEST(RawPtr, Basic) { + RawPtr raw; + EXPECT_EQ(raw->i, 0); + EXPECT_EQ((*raw).i, 0); + EXPECT_EQ(static_cast(&raw->i), kZeroBuffer); + EXPECT_EQ(static_cast(raw.Get()), kZeroBuffer); + EXPECT_TRUE(raw.IsDefault()); + + Obj obj = {1}; + raw.Set(&obj); + EXPECT_EQ(raw->i, 1); + EXPECT_EQ(static_cast(raw.Get()), &obj); + EXPECT_FALSE(raw.IsDefault()); +} + +TEST(RawPtr, Constexpr) { + constexpr RawPtr raw; + EXPECT_EQ(raw->i, 0); + EXPECT_EQ((*raw).i, 0); + EXPECT_EQ(static_cast(&raw->i), kZeroBuffer); + EXPECT_EQ(static_cast(raw.Get()), kZeroBuffer); + EXPECT_TRUE(raw.IsDefault()); + + static constexpr Obj obj = {1}; + constexpr RawPtr raw2(&obj); + EXPECT_EQ(raw2->i, 1); + EXPECT_EQ((*raw2).i, 1); + EXPECT_EQ(static_cast(raw2.Get()), &obj); + EXPECT_FALSE(raw2.IsDefault()); +} + +} // namespace +} // namespace internal +} // namespace protobuf +} // namespace google