2024-05-11 17:43:38 +08:00

168 lines
6.1 KiB
C++

// Protocol Buffers - Google's data interchange format
// Copyright 2023 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.
//
// This header provides support for a per thread 'reflection mode'.
//
// Some protocol buffer optimizations use interceptors to determine which
// fields are effectively used in the application. These optimizations are
// disabled if certain reflection calls are intercepted as the assumption is
// then that any field data can be accessed.
//
// The 'reflection mode' defined in this header is intended to be used by
// logic such as ad-hoc profilers to indicate that any scoped reflection usage
// is not originating from, or affecting application code. This reflection mode
// can then be used by such interceptors to ignore any reflection calls not
// affecting the application behavior.
#ifndef GOOGLE_PROTOBUF_REFLECTION_MODE_H__
#define GOOGLE_PROTOBUF_REFLECTION_MODE_H__
#include <cstddef>
// Must be included last.
#include "google/protobuf/port_def.inc"
namespace google {
namespace protobuf {
namespace internal {
// The ReflectionModes are ordered in observability levels:
// kDefault: Lowest level. All reflection calls are observable.
// kDebugString: Middle level. Only reflection calls in Message::DebugString are
// observable.
// kDiagnostics: Highest level. No reflection calls are observable.
enum class ReflectionMode {
kDefault,
kDebugString,
kDiagnostics,
};
// Returns the current ReflectionMode of protobuf for the current thread. This
// reflection mode can be used by interceptors to ignore any reflection calls
// not affecting the application behavior.
// Always returns `kDefault' if the current platform does not support thread
// local data.
ReflectionMode GetReflectionMode();
// Scoping class to set the specific ReflectionMode for a given scope.
class PROTOBUF_EXPORT ScopedReflectionMode final {
public:
// Sets the current reflection mode, which will be restored at destruction.
// The reflection mode can only be 'elevated' in observability levels.
// For instance, if the current mode is `kDiagnostics` then scope will remain
// unchanged regardless of `mode`.
explicit ScopedReflectionMode(ReflectionMode mode);
// Restores the previous reflection mode.
~ScopedReflectionMode();
// Returns the scoped ReflectionMode for the current thread.
// See `GetReflectionMode()` for more information on purpose and usage.
static ReflectionMode current_reflection_mode();
// ScopedReflectionMode is only intended to be used as a locally scoped
// instance to set a reflection mode for the code scoped by this instance.
ScopedReflectionMode(const ScopedReflectionMode&) = delete;
ScopedReflectionMode& operator=(const ScopedReflectionMode&) = delete;
private:
#if !defined(PROTOBUF_NO_THREADLOCAL)
const ReflectionMode previous_mode_;
#if defined(PROTOBUF_USE_DLLS) && defined(_WIN32)
// Thread local variables cannot be exposed through MSVC DLL interface but we
// can wrap them in static functions.
static ReflectionMode& reflection_mode();
#else
PROTOBUF_CONSTINIT static PROTOBUF_THREAD_LOCAL ReflectionMode
reflection_mode_;
#endif // PROTOBUF_USE_DLLS && _MSC_VER
#endif // !PROTOBUF_NO_THREADLOCAL
};
#if !defined(PROTOBUF_NO_THREADLOCAL)
#if defined(PROTOBUF_USE_DLLS) && defined(_WIN32)
inline ScopedReflectionMode::ScopedReflectionMode(ReflectionMode mode)
: previous_mode_(reflection_mode()) {
if (mode > reflection_mode()) {
reflection_mode() = mode;
}
}
inline ScopedReflectionMode::~ScopedReflectionMode() {
reflection_mode() = previous_mode_;
}
inline ReflectionMode ScopedReflectionMode::current_reflection_mode() {
return reflection_mode();
}
#else
inline ScopedReflectionMode::ScopedReflectionMode(ReflectionMode mode)
: previous_mode_(reflection_mode_) {
if (mode > reflection_mode_) {
reflection_mode_ = mode;
}
}
inline ScopedReflectionMode::~ScopedReflectionMode() {
reflection_mode_ = previous_mode_;
}
inline ReflectionMode ScopedReflectionMode::current_reflection_mode() {
return reflection_mode_;
}
#endif // PROTOBUF_USE_DLLS && _MSC_VER
#else
inline ScopedReflectionMode::ScopedReflectionMode(ReflectionMode mode) {}
inline ScopedReflectionMode::~ScopedReflectionMode() {}
inline ReflectionMode ScopedReflectionMode::current_reflection_mode() {
return ReflectionMode::kDefault;
}
#endif // !PROTOBUF_NO_THREADLOCAL
inline ReflectionMode GetReflectionMode() {
return ScopedReflectionMode::current_reflection_mode();
}
} // namespace internal
} // namespace protobuf
} // namespace google
#include "google/protobuf/port_undef.inc"
#endif // GOOGLE_PROTOBUF_REFLECTION_MODE_H__