// bsls_assertimputil.h                                               -*-C++-*-
#ifndef INCLUDED_BSLS_ASSERTIMPUTIL
#define INCLUDED_BSLS_ASSERTIMPUTIL

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide utilities to implement `bsls_assert` and `bsls_review`.
//
//@CLASSES:
//  bsls::AssertImpUtil: namespace for shared assert and review functions
//
//@DESCRIPTION: This component defines a `struct`, `bsls::AssertImpUtil`, that
// serves as a namespace for shared functions used by the various handlers
// provided by `bsls_assert` and `bsls_review`.
//
///`BSLS_ASSERTIMPUTIL_AVOID_STRING_CONSTANTS`
///-------------------------------------------
// On some platforms the string constants used to pass filenames to the assert
// macro invocations are not coalesced, so each inline function use containing
// such a macro puts an extra copy of the filename string into the resulting
// executable.  For these platforms, it is possible to locally alter the
// filename that assert macros will use by altering the definition of
// `BSLS_ASSERTIMPUTIL_FILE`.
//
// At the start of your component header, after all other include directives,
// place the following block of code to detect if this is a platform where the
// workaround is needed and apply it:
// ```
// // my_component.h
// // ...
// // 'BSLS_ASSERT' filename fix -- See {bsls_assertimputil}
// #ifdef BSLS_ASSERTIMPUTIL_AVOID_STRING_CONSTANTS
// extern const char s_my_component_h[];
// #undef BSLS_ASSERTIMPUTIL_FILE
// #define BSLS_ASSERTIMPUTIL_FILE BloombergLP::s_my_component_h
// #endif
// ```
// Then, at the end of your header revert the definition of the filename macro
// to its default:
// ```
// // Undo 'BSLS_ASSERT' filename fix -- See {bsls_assertimputil}
// #ifdef BSLS_ASSERTIMPUTIL_AVOID_STRING_CONSTANTS
// #undef BSLS_ASSERTIMPUTIL_FILE
// #define BSLS_ASSERTIMPUTIL_FILE BSLS_ASSERTIMPUTIL_DEFAULTFILE
// #endif
// ```
// Finally, in the `.cpp` file add the following:
// ```
// // 'BSLS_ASSERT' filename fix -- See {bsls_assertimputil}
// #ifdef BSLS_ASSERTIMPUTIL_AVOID_STRING_CONSTANTS
// extern const char s_my_component_h[] = "my_component.h";
// #endif
// ```
// Note that these constants should all be in an appropriate namespace and
// should have names and contents that match your actual component name.
//
///Usage
///-----
// This section illustrates the intended use of this component.
//
///Example 1: Aborting the Current Process
///- - - - - - - - - - - - - - - - - - - -
// Suppose you are implementing an assertion handler that should cause a
// process to terminate when invoked.  In order to stop the process
// immediately, you would call `failByAbort` like this:
// ```
// void myAbort()
// {
//     bsls::AssertImpUtil::failByAbort();
//     // This code should never be reached.
// }
// ```
// This function would then abort the current process.
//
///Example 2: Sleeping Forever
///- - - - - - - - - - - - - -
// Suppose you want a process to no longer continue doing anything, but you
// want to leave it running in order to attach a debugger to it and diagnose
// the full state of your system.  In order to have your process sleep forever,
// you might call `failBySleep` like this:
// ```
// void mySleep()
// {
//     bsls::AssertImpUtil::failBySleep();
//     // This code should never be reached.
// }
// ```
// This function would then sleep forever and never return.

#include <bsls_annotation.h>
#include <bsls_compilerfeatures.h>
#include <bsls_linkcoercion.h>
#include <bsls_platform.h>

                 // =========================================
                 // BSLS_ASSERTIMPUTIL_AVOID_STRING_CONSTANTS
                 // =========================================

#ifdef BSLS_PLATFORM_CMP_SUN
// On sun, string constants are not coalesced, so uses of 'BSLS_ASSERT' and
// 'BSLS_REVIEW' macros in inlined functions lead to massive executable size
// bloat.  This flag indicates that a workaround should be enabled to minimize
// references to strings literals in these macros.  That workaround should
// involve redefining 'BSLS_ASSERTIMPUTIL_FILE' to reference a static constant
// that is initialized in the component's implementation file.

#define BSLS_ASSERTIMPUTIL_AVOID_STRING_CONSTANTS

#endif

namespace BloombergLP {
namespace bsls {
                        // ===========================
                        // Assert Macro Support Macros
                        // ===========================

// Assertion Filename
#define BSLS_ASSERTIMPUTIL_DEFAULTFILE __FILE__
#define BSLS_ASSERTIMPUTIL_FILE BSLS_ASSERTIMPUTIL_DEFAULTFILE

#define BSLS_ASSERTIMPUTIL_LINE __LINE__

#ifdef BSLS_PLATFORM_CMP_SUN
// On sun, if possible headers that use 'bsls_review' or 'bsls_assert' macros
// in inline functions should attempt to specify their filenames as an extern
// string defined in just the '.cpp' file of the component instead of just
// using '__FILE__'.

#define BSLS_ASSERTIMPUTIL_AVOID_STRING_CONSTANTS

#endif

                         // =========================
                         // BSLS_ASSERT_USE_CONTRACTS
                         // =========================
// Language-level contracts can be turned on with the external control macro
// 'BSLS_ASSERT_USE_CONTRACTS' when running on a compiler that supports this.
// Note that mixing builds where language contracts are supported and those
// where they are not is not ABI-compatible, so we enforce that this does not
// happen with a link coercion.  Note also that this is likely not to be
// ABI-compatible between distinct flavours of language level contracts in the
// future, so we will coerce the use of distinct names to protect against mixed
// builds.

#ifdef BSLS_ASSERT_USE_CONTRACTS

// The Lock3 branch of GCC supports a contract implementation sufficient to
// build 'bsls_assert' and 'bsls_review' on.  Full documentation for the
// extensions it makes available can be found at
// 'https://github.com/lock3/gcc/wiki/contracts'.

#if !defined(__cpp_contracts_literal_semantics)
#error BSLS_ASSERT_USE_CONTRACTS requires compiler contract support           \
    (__cpp_contracts_literal_semantics)
#endif

#ifndef BSLS_ASSERT_NORETURN_INVOKE_HANDLER
// 'bsls_assert' with language-level contracts will use a non-continuing
// contract mode, so we can no longer support a returning violation handler.
#define BSLS_ASSERT_NORETURN_INVOKE_HANDLER
#endif

struct AssertImpUtil_UseContractsCpp20 {
    static const int s_isAssertUseContracts;
};
typedef AssertImpUtil_UseContractsCpp20 AssertImpUtil_UseContracts;

#else

struct AssertImpUtil_UseContractsNo {
    static const int s_isAssertUseContracts;
};
typedef AssertImpUtil_UseContractsNo AssertImpUtil_UseContracts;

#endif

BSLS_LINKCOERCION_FORCE_SYMBOL_DEPENDENCY(
                      const int,
                      bsls_assertimputil_coerce_use_contracts,
                      bsls::AssertImpUtil_UseContracts::s_isAssertUseContracts)

                            // ====================
                            // struct AssertImpUtil
                            // ====================

/// This "implementation utility" `struct` provides static functions with
/// shared functionality that is made use of by both `bsls_assert` and
/// `bsls_review`.
struct AssertImpUtil {

  public:
    // CLASS METHODS

    /// Unconditionally abort the current application.  It is up to the
    /// caller to first output a useful message describing the location of
    /// the failure.
    BSLS_ANNOTATION_NORETURN
    static void failByAbort();

    /// Spin in an infinite loop.  It is up to the caller to first output a
    /// useful message describing the location of the failure.
    BSLS_ANNOTATION_NORETURN
    static void failBySleep();
};

}  // close package namespace
}  // close enterprise namespace

          // ========================================================
          // UNDEFINE THE LOCALLY-SCOPED IMPLEMENTATION DETAIL MACROS
          // ========================================================

#endif

// ----------------------------------------------------------------------------
// Copyright 2018 Bloomberg Finance L.P.
//
// 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.
// ----------------------------- END-OF-FILE ----------------------------------
