crashpad/util/misc/initialization_state_dcheck.h
Mark Mentovai 6278690abe Update copyright boilerplate, 2022 edition (Crashpad)
sed -i '' -E -e 's/Copyright (.+) The Crashpad Authors\. All rights reserved\.$/Copyright \1 The Crashpad Authors/' $(git grep -El 'Copyright (.+) The Crashpad Authors\. All rights reserved\.$')

Bug: chromium:1098010
Change-Id: I8d6138469ddbe3d281a5d83f64cf918ec2491611
Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3878262
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
Commit-Queue: Mark Mentovai <mark@chromium.org>
2022-09-06 23:54:07 +00:00

196 lines
7.9 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright 2014 The Crashpad 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
//
// http://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 CRASHPAD_UTIL_MISC_INITIALIZATION_INITIALIZATION_STATE_DCHECK_H_
#define CRASHPAD_UTIL_MISC_INITIALIZATION_INITIALIZATION_STATE_DCHECK_H_
//! \file
#include <tuple>
#include "base/check_op.h"
#include "build/build_config.h"
#include "util/misc/initialization_state.h"
namespace crashpad {
#if DCHECK_IS_ON() || DOXYGEN
//! \brief Tracks whether data are initialized, triggering a DCHECK assertion
//! on an invalid data access.
//!
//! Put an InitializationStateDcheck member into a class to help DCHECK that
//! its in the right states at the right times. This is useful for classes with
//! Initialize() methods. The chief advantage of InitializationStateDcheck over
//! having a member variable to track state is that when the only use of the
//! variable is to DCHECK, it wastes space (in memory and executable code) in
//! non-DCHECK builds unless the code is also peppered with ugly `#%ifdef`s.
//!
//! This implementation concentrates the ugly `#%ifdef`s in one location.
//!
//! Usage:
//!
//! \code
//! class Class {
//! public:
//! Class() : initialized_() {}
//!
//! void Initialize() {
//! INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
//! // Perform initialization.
//! INITIALIZATION_STATE_SET_VALID(initialized_);
//! }
//!
//! void DoSomething() {
//! INITIALIZATION_STATE_DCHECK_VALID(initialized_);
//! // Do something.
//! }
//!
//! private:
//! InitializationStateDcheck initialized_;
//! };
//! \endcode
class InitializationStateDcheck : public InitializationState {
public:
InitializationStateDcheck() : InitializationState() {}
InitializationStateDcheck(const InitializationStateDcheck&) = delete;
InitializationStateDcheck& operator=(const InitializationStateDcheck&) =
delete;
//! \brief Returns the objects state.
//!
//! Consumers of this class should not call this method. Use the
//! INITIALIZATION_STATE_SET_INITIALIZING(), INITIALIZATION_STATE_SET_VALID(),
//! and INITIALIZATION_STATE_DCHECK_VALID() macros instead.
//
// The superclass state() accessor is protected, but it needs to be exposed
// to consumers of this class for the macros below to work properly. The
// macros prefer access to the unerlying state value over a simple boolean
// because with access to the state value, DCHECK_EQ can be used, which, when
// tripped, prints both the expected and observed values. This can aid
// troubleshooting.
State state() const { return InitializationState::state(); }
//! \brief Marks an uninitialized object as initializing.
//!
//! If the object is in the #kStateUninitialized state, changes its state to
//! #kStateInvalid (initializing) and returns the previous
//! (#kStateUninitialized) state. Otherwise, returns the objects current
//! state.
//!
//! Consumers of this class should not call this method. Use the
//! INITIALIZATION_STATE_SET_INITIALIZING() macro instead.
State SetInitializing();
//! \brief Marks an initializing object as valid.
//!
//! If the object is in the #kStateInvalid (initializing) state, changes its
//! state to #kStateValid and returns the previous (#kStateInvalid) state.
//! Otherwise, returns the objects current state.
//!
//! Consumers of this class should not call this method. Use the
//! INITIALIZATION_STATE_SET_VALID() macro instead.
State SetValid();
};
// Using macros enables the non-DCHECK no-op implementation below to be more
// compact and less intrusive. These are macros instead of methods that call
// DCHECK to enable the DCHECK failure message to point to the correct file and
// line number, and to allow additional messages to be streamed on failure with
// the << operator.
//! \brief Checks that a crashpad::InitializationStateDcheck object is in the
//! crashpad::InitializationState::kStateUninitialized state, and changes
//! its state to initializing
//! (crashpad::InitializationState::kStateInvalid).
//!
//! If the object is not in the correct state, a DCHECK assertion is triggered
//! and the objects state remains unchanged.
//!
//! \param[in] initialization_state_dcheck A crashpad::InitializationStateDcheck
//! object.
//!
//! \sa crashpad::InitializationStateDcheck
#define INITIALIZATION_STATE_SET_INITIALIZING(initialization_state_dcheck) \
DCHECK_EQ((initialization_state_dcheck).SetInitializing(), \
(initialization_state_dcheck).kStateUninitialized)
//! \brief Checks that a crashpad::InitializationStateDcheck object is in the
//! initializing (crashpad::InitializationState::kStateInvalid) state, and
//! changes its state to crashpad::InitializationState::kStateValid.
//!
//! If the object is not in the correct state, a DCHECK assertion is triggered
//! and the objects state remains unchanged.
//!
//! \param[in] initialization_state_dcheck A crashpad::InitializationStateDcheck
//! object.
//!
//! \sa crashpad::InitializationStateDcheck
#define INITIALIZATION_STATE_SET_VALID(initialization_state_dcheck) \
DCHECK_EQ((initialization_state_dcheck).SetValid(), \
(initialization_state_dcheck).kStateInvalid)
//! \brief Checks that a crashpad::InitializationStateDcheck object is in the
//! crashpad::InitializationState::kStateValid state.
//!
//! If the object is not in the correct state, a DCHECK assertion is triggered.
//!
//! \param[in] initialization_state_dcheck A crashpad::InitializationStateDcheck
//! object.
//!
//! \sa crashpad::InitializationStateDcheck
#define INITIALIZATION_STATE_DCHECK_VALID(initialization_state_dcheck) \
DCHECK_EQ((initialization_state_dcheck).state(), \
(initialization_state_dcheck).kStateValid)
#else
#if defined(COMPILER_MSVC)
// bool[0] (below) is not accepted by MSVC.
struct InitializationStateDcheck {
};
#else
// Since this is to be used as a DCHECK (for debugging), it should be
// non-intrusive in non-DCHECK (non-debug, release) builds. An empty struct
// would still have a nonzero size (rationale:
// http://www.stroustrup.com/bs_faq2.html#sizeof-empty). Zero-length arrays are
// technically invalid according to the standard, but clang and g++ accept them
// without complaint even with warnings turned up. They take up no space at all,
// and they can be “initialized” with the same () syntax used to initialize
// objects of the DCHECK_IS_ON() InitializationStateDcheck class above.
using InitializationStateDcheck = bool[0];
#endif // COMPILER_MSVC
// Avoid triggering warnings by repurposing these macros when DCHECKs are
// disabled.
#define INITIALIZATION_STATE_SET_INITIALIZING(initialization_state_dcheck) \
do { \
std::ignore = initialization_state_dcheck; \
} while (false)
#define INITIALIZATION_STATE_SET_VALID(initialization_state_dcheck) \
do { \
std::ignore = initialization_state_dcheck; \
} while (false)
#define INITIALIZATION_STATE_DCHECK_VALID(initialization_state_dcheck) \
do { \
std::ignore = initialization_state_dcheck; \
} while (false)
#endif
} // namespace crashpad
#endif // CRASHPAD_UTIL_MISC_INITIALIZATION_INITIALIZATION_STATE_DCHECK_H_