// bdlb_nullablevalueref_cpp03.h                                      -*-C++-*-

// Automatically generated file.  **DO NOT EDIT**

#ifndef INCLUDED_BDLB_NULLABLEVALUEREF_CPP03
#define INCLUDED_BDLB_NULLABLEVALUEREF_CPP03

//@PURPOSE: Provide C++03 implementation for bdlb_nullablevalueref.h
//
//@CLASSES: See bdlb_nullablevalueref.h for list of classes
//
//@SEE_ALSO: bdlb_nullablevalueref
//
//@DESCRIPTION:  This component is the C++03 translation of a C++11 component,
// generated by the 'sim_cpp11_features.pl' program.  If the original header
// contains any specially delimited regions of C++11 code, then this generated
// file contains the C++03 equivalent, i.e., with variadic templates expanded
// and rvalue-references replaced by 'bslmf::MovableRef' objects.  The header
// code in this file is designed to be '#include'd into the original header
// when compiling with a C++03 compiler.  If there are no specially delimited
// regions of C++11 code, then this header contains no code and is not
// '#include'd in the original header.
//
// Generated on Wed Nov  6 15:09:19 2024
// Command line: sim_cpp11_features.pl bdlb_nullablevalueref.h

#ifdef COMPILING_BDLB_NULLABLEVALUEREF_H

namespace BloombergLP {
namespace bdlb {

template <class TYPE>
class ConstNullableValueRef;

                        // ============================
                        // class NullableValueRef<TYPE>
                        // ============================

/// This class is a wrapper for either a `bsl::optional` or
/// `NullableAllocatedValue`, and provides modifiable access to the wrapped
/// object.
template <class TYPE>
class NullableValueRef {

    // PRIVATE TYPES
#ifndef BSLS_COMPILERFEATURES_SUPPORT_OPERATOR_EXPLICIT
    // UNSPECIFIED BOOL

    /// This type is needed only in C++03 mode, where `explicit` conversion
    /// operators are not supported.  A `NullableAllocatedValue` is implicitly
    /// converted to `UnspecifiedBool` when used in `if` statements, but is not
    /// implicitly convertible to `bool`.
    typedef BloombergLP::bsls::UnspecifiedBool<NullableValueRef>
                                                           UnspecifiedBoolUtil;
    typedef typename UnspecifiedBoolUtil::BoolType         UnspecifiedBool;
#endif

    // DATA

    // the address of the target
    void *d_target_p;

    // `true` if the target is a specialization of `bsl::optional`, and
    // `false` it's a specialization of `NullableAllocatedValue`
    bool  d_isTargetOptional;

    // PRIVATE ACCESSORS

    /// Return a reference providing non-const access to the held
    /// `NullableAllocatedValue` object.  The behavior is undefined if the
    /// target is not a `NullableAllocatedValue`.
    NullableAllocatedValue<TYPE>& getNAV() const;

    /// Return a reference providing non-const access to the held
    /// `bsl::optional` object.  The behavior is undefined if the target is
    /// not a `bdlb::bsl::optional`.
    bsl::optional<TYPE>& getOpt() const;

    /// Return `true` if the target of this object is a `bsl::optional`, and
    /// `false` otherwise.
    bool hasOpt() const;

    // FRIENDS
    friend class ConstNullableValueRef<TYPE>;

    // TRAITS

    // This class requires that `TYPE` is not `const`- or `volatile`-
    // qualified, nor a reference.
    BSLMF_ASSERT((
                 bsl::is_same<TYPE,
                              typename bsl::remove_cvref<TYPE>::type>::value));

  public:
    // TYPES

    /// `value_type` is an alias for the template parameter `TYPE`, and
    /// represents the type of the object managed by the wrapped nullable
    /// object.
    typedef TYPE value_type;

    // CREATORS

    /// Create a nullable object wrapper that refers to the specified `opt`
    /// object.  Note that the created wrapper does not own a copy of the
    /// underlying nullable value, but instead refers to it, and so the
    /// lifetime of `opt` must exceed the lifetime of the created wrapper.
    NullableValueRef(bsl::optional<TYPE>& opt);                     // IMPLICIT

    /// Create a nullable object wrapper that refers to the specified `opt`
    /// object.  Note that the created wrapper does not own a copy of the
    /// underlying nullable value, but instead refers to it, and so the
    /// lifetime of `opt` must exceed the lifetime of the created wrapper.
    NullableValueRef(NullableAllocatedValue<TYPE>& opt);            // IMPLICIT

    /// Create a nullable object wrapper that refers to the target object of
    /// the specified `original` wrapper.  Note that the created wrapper
    /// does not own a copy of the underlying nullable value, but instead
    /// refers to it, and so the lifetime of the target must exceed the
    /// lifetime of the created wrapper.
    NullableValueRef(const NullableValueRef& original);

    /// Destroy this object.  Note that this destructor is generated by the
    /// compiler, and does not destroy the target.
    //! ~NullableValueRef();

    // ACCESSORS

    /// Return `true` if the target contains a value, and `false` otherwise.
    bool has_value() const BSLS_KEYWORD_NOEXCEPT;

    /// Return `false` if the target contains a value, and `true` otherwise.
    /// Note that this accessor is provided purely for compatibility with
    /// `NullableValue` and `NullableAllocatedValue`, and its use is
    /// discouraged in favor of `has_value`.
    bool isNull() const BSLS_KEYWORD_NOEXCEPT;

    /// Return a reference providing non-modifiable access to the underlying
    /// object of a (template parameter) `TYPE`.  The behavior is undefined
    /// if the target has no value.
    const value_type& value() const;

    /// Return a pointer providing non-modifiable access to the underlying
    /// `TYPE` object.  The behavior is undefined if the target has no
    /// value.
    const value_type *operator->() const;

    /// Return a reference providing non-modifiable access to the underlying
    /// `TYPE` object.  The behavior is undefined if the target has no
    /// value.
    const value_type& operator*() const;

#ifdef BSLS_COMPILERFEATURES_SUPPORT_OPERATOR_EXPLICIT
    /// Return `true` if the target holds a value, and `false` otherwise.
    BSLS_KEYWORD_EXPLICIT operator bool() const BSLS_KEYWORD_NOEXCEPT;
#else
    /// Simulation of explicit conversion to bool.  Inlined to work around xlC
    /// but when out-of-line.
    operator UnspecifiedBool() const BSLS_NOTHROW_SPEC
    {
        return UnspecifiedBoolUtil::makeValue(has_value());
    }
#endif

    /// Return the value of the underlying object of a (template parameter)
    /// `TYPE` if the target is non-null, and the specified `default_value`
    /// otherwise.  Note that this method returns *by* *value*, so may be
    /// inefficient in some contexts.
    template <class ANY_TYPE>
    TYPE value_or(const ANY_TYPE& default_value) const;

    // MANIPULATORS
#if BSLS_COMPILERFEATURES_SIMULATE_VARIADIC_TEMPLATES
// {{{ BEGIN GENERATED CODE
// Command line: sim_cpp11_features.pl bdlb_nullablevalueref.h
#ifndef BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT
#define BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT 5
#endif
#ifndef BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_A
#define BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_A BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT
#endif
#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_A >= 0
    TYPE& emplace();
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_A >= 0

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_A >= 1
    template <class ARGS_1>
    TYPE& emplace(BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_1));
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_A >= 1

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_A >= 2
    template <class ARGS_1,
              class ARGS_2>
    TYPE& emplace(BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_1),
                  BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_2));
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_A >= 2

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_A >= 3
    template <class ARGS_1,
              class ARGS_2,
              class ARGS_3>
    TYPE& emplace(BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_1),
                  BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_2),
                  BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_3));
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_A >= 3

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_A >= 4
    template <class ARGS_1,
              class ARGS_2,
              class ARGS_3,
              class ARGS_4>
    TYPE& emplace(BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_1),
                  BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_2),
                  BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_3),
                  BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_4));
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_A >= 4

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_A >= 5
    template <class ARGS_1,
              class ARGS_2,
              class ARGS_3,
              class ARGS_4,
              class ARGS_5>
    TYPE& emplace(BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_1),
                  BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_2),
                  BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_3),
                  BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_4),
                  BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_5));
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_A >= 5

#else
// The generated code below is a workaround for the absence of perfect
// forwarding in some compilers.
    template <class... ARGS>
    TYPE& emplace(BSLS_COMPILERFEATURES_FORWARD_REF(ARGS)...);
// }}} END GENERATED CODE
#endif

    /// Return a pointer providing modifiable access to the underlying
    /// `TYPE` object.  The behavior is undefined if the target has no
    /// value.
    value_type *operator->();

    /// Return a reference providing modifiable access to the underlying
    /// `TYPE` object.  The behavior is undefined if the target has no
    /// value.
    value_type& operator*();

    /// Reset the target to the default constructed state (i.e., to have the
    /// null value).
    NullableValueRef<TYPE>& operator=(const bsl::nullopt_t&);

    /// Assign to the target the value of the specified `rhs`, and return a
    /// reference providing modifiable access to this object.
    NullableValueRef<TYPE>& operator=(const TYPE& rhs);

    /// Assign to the target the value of the specified `rhs`, and return a
    /// reference providing modifiable access to this object.
    NullableValueRef<TYPE>& operator=(const bsl::optional<TYPE>& rhs);

    /// Assign to the target the value of the specified `rhs`, and return a
    /// reference providing modifiable access to this object.
    NullableValueRef<TYPE>& operator=(
                                      const NullableAllocatedValue<TYPE>& rhs);

    /// Assign to the target the value of the specified `rhs`, and return a
    /// reference providing modifiable access to this object.
    NullableValueRef<TYPE>& operator=(const NullableValueRef& rhs);

    /// Reset the target to the default constructed state (i.e., to have the
    /// null value).
    void reset();

    /// Return a reference providing modifiable access to the underlying
    /// `TYPE` object.  The behavior is undefined unless this object is
    /// non-null.
    value_type& value();

    // DEPRECATED FUNCTIONS
    //  provided for compatibility with NullableValue

    /// Return an address providing non-modifiable access to the underlying
    /// object of a (template parameter) `TYPE` if this object is non-null,
    /// and the specified `address` otherwise.
    BSLS_DEPRECATE_FEATURE("bdl", "NullableValueRef::addressOr",
                              "Use 'has_value() ? &value() : address' instead")
    const TYPE *addressOr(const TYPE *address) const;

#if BSLS_COMPILERFEATURES_SIMULATE_VARIADIC_TEMPLATES
// {{{ BEGIN GENERATED CODE
// Command line: sim_cpp11_features.pl bdlb_nullablevalueref.h
#ifndef BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT
#define BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT 5
#endif
#ifndef BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_B
#define BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_B BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT
#endif

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_B >= 0
    BSLS_DEPRECATE_FEATURE("bdl", "NullableValueRef::makeValueInplace",
                                                       "Use 'emplace' instead")
    TYPE& makeValueInplace();
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_B >= 0

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_B >= 1
    template <class ARGS_1>
    BSLS_DEPRECATE_FEATURE("bdl", "NullableValueRef::makeValueInplace",
                                                       "Use 'emplace' instead")
    TYPE& makeValueInplace(BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_1) args_1);
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_B >= 1

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_B >= 2
    template <class ARGS_1,
              class ARGS_2>
    BSLS_DEPRECATE_FEATURE("bdl", "NullableValueRef::makeValueInplace",
                                                       "Use 'emplace' instead")
    TYPE& makeValueInplace(BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_1) args_1,
                           BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_2) args_2);
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_B >= 2

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_B >= 3
    template <class ARGS_1,
              class ARGS_2,
              class ARGS_3>
    BSLS_DEPRECATE_FEATURE("bdl", "NullableValueRef::makeValueInplace",
                                                       "Use 'emplace' instead")
    TYPE& makeValueInplace(BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_1) args_1,
                           BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_2) args_2,
                           BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_3) args_3);
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_B >= 3

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_B >= 4
    template <class ARGS_1,
              class ARGS_2,
              class ARGS_3,
              class ARGS_4>
    BSLS_DEPRECATE_FEATURE("bdl", "NullableValueRef::makeValueInplace",
                                                       "Use 'emplace' instead")
    TYPE& makeValueInplace(BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_1) args_1,
                           BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_2) args_2,
                           BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_3) args_3,
                           BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_4) args_4);
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_B >= 4

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_B >= 5
    template <class ARGS_1,
              class ARGS_2,
              class ARGS_3,
              class ARGS_4,
              class ARGS_5>
    BSLS_DEPRECATE_FEATURE("bdl", "NullableValueRef::makeValueInplace",
                                                       "Use 'emplace' instead")
    TYPE& makeValueInplace(BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_1) args_1,
                           BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_2) args_2,
                           BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_3) args_3,
                           BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_4) args_4,
                           BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_5) args_5);
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_B >= 5

#else
// The generated code below is a workaround for the absence of perfect
// forwarding in some compilers.

    template <class... ARGS>
    BSLS_DEPRECATE_FEATURE("bdl", "NullableValueRef::makeValueInplace",
                                                       "Use 'emplace' instead")
    TYPE& makeValueInplace(BSLS_COMPILERFEATURES_FORWARD_REF(ARGS)... args);
// }}} END GENERATED CODE
#endif

    /// Return the value of the underlying object of a (template parameter)
    /// `TYPE` if this object is non-null, and the specified `otherValue`
    /// otherwise.  Note that this method returns *by* *value*, so may be
    /// inefficient in some contexts.
    BSLS_DEPRECATE_FEATURE("bdl", "NullableValueRef::valueOr",
                                                      "Use 'value_or' instead")
    TYPE valueOr(const TYPE& otherValue) const;

    /// Return an address providing non-modifiable access to the underlying
    /// object of a (template parameter) `TYPE` if this object is non-null,
    /// and 0 otherwise.
    BSLS_DEPRECATE_FEATURE("bdl", "NullableValueRef::valueOrNull",
                                 "Use 'has_value() ? &value() : NULL' instead")
    const TYPE *valueOrNull() const;
};

// FREE FUNCTIONS

/// Pass the boolean value of whether the specified `input` references a
/// non-empty nullable value to the specified `hashAlg` hashing algorithm of
/// (template parameter) type `HASHALG`.  If `input.has_value` is true,
/// additionally pass the value to `hashAlg`.
template <class HASHALG, class TYPE>
void hashAppend(HASHALG& hashAlg, const NullableValueRef<TYPE>& input);

// FREE OPERATORS

/// Return `true` if the specified `lhs` and `rhs` nullable wrappers have
/// the same value, and `false` otherwise.  Two nullable wrappers have the
/// same value if both targets are null, or if both are non-null and the
/// values of their underlying objects compare equal.  Note that this
/// function will fail to compile if `LHS_TYPE` and `RHS_TYPE` are not
/// compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator==(const NullableValueRef<LHS_TYPE>& lhs,
                const NullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` and `rhs` objects have the same
/// value, and `false` otherwise.  A nullable wrapper and a value of some
/// type have the same value if the nullable wrapper is non-null and the
/// underlying value of it's target compares equal to the other value.  Note
/// that this function will fail to compile if `LHS_TYPE` and `RHS_TYPE` are
/// not compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator==(const NullableValueRef<LHS_TYPE>& lhs,
                const RHS_TYPE&                   rhs);
template <class LHS_TYPE, class RHS_TYPE>
bool operator==(const LHS_TYPE&                   lhs,
                const NullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` and `rhs` nullable objects do not
/// have the same value, and `false` otherwise.  Two nullable wrappers do
/// not have the same value if one is null and the other is non-null, or if
/// both are non-null and the values of their underlying objects do not
/// compare equal.  Note that this function will fail to compile if
/// `LHS_TYPE` and `RHS_TYPE` are not compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator!=(const NullableValueRef<LHS_TYPE>& lhs,
                const NullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` and `rhs` objects do not have the
/// same value, and `false` otherwise.  A nullable wrappers and a value of
/// some type do not have the same value if either the nullable wrappers is
/// null, or its underlying value does not compare equal to the other value.
/// Note that this function will fail to compile if `LHS_TYPE` and
/// `RHS_TYPE` are not compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator!=(const NullableValueRef<LHS_TYPE>& lhs,
                const RHS_TYPE&                   rhs);
template <class LHS_TYPE, class RHS_TYPE>
bool operator!=(const LHS_TYPE&                   lhs,
                const NullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` nullable wrapper is ordered before
/// the specified `rhs` nullable object, and `false` otherwise.  `lhs` is
/// ordered before `rhs` if `lhs` is null and `rhs` is non-null or if both
/// are non-null and `lhs.value()` is ordered before `rhs.value()`.  Note
/// that this function will fail to compile if `LHS_TYPE` and `RHS_TYPE` are
/// not compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator<(const NullableValueRef<LHS_TYPE>& lhs,
               const NullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` nullable wrapper is ordered before
/// the specified `rhs`, and `false` otherwise.  `lhs` is ordered before
/// `rhs` if `lhs` is null or `lhs.value()` is ordered before `rhs`.
template <class LHS_TYPE, class RHS_TYPE>
bool operator<(const NullableValueRef<LHS_TYPE>& lhs,
               const RHS_TYPE&                   rhs);

/// Return `true` if the specified `lhs` is ordered before the specified
/// `rhs` nullable wrappers, and `false` otherwise.  `lhs` is ordered before
/// `rhs` if `rhs` is not null and `lhs` is ordered before `rhs.value()`.
template <class LHS_TYPE, class RHS_TYPE>
bool operator<(const LHS_TYPE&                   lhs,
               const NullableValueRef<RHS_TYPE>& rhs);


/// Return `true` if the specified `lhs` nullable wrapper is ordered before
/// the specified `rhs` nullable object or `lhs` and `rhs` have the same
/// value, and `false` otherwise.  (See `operator<` and `operator==`.)  Note
/// that this function will fail to compile if `LHS_TYPE` and `RHS_TYPE`
/// are not compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator<=(const NullableValueRef<LHS_TYPE>& lhs,
                const NullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` nullable wrapper is ordered before
/// the specified `rhs` or `lhs` and `rhs` have the same value, and `false`
/// otherwise.  (See `operator<` and `operator==`.)  Note that this operator
/// returns `!(rhs < lhs)`.
template <class LHS_TYPE, class RHS_TYPE>
bool operator<=(const NullableValueRef<LHS_TYPE>& lhs,
                const RHS_TYPE&                   rhs);

/// Return `true` if the specified `lhs` is ordered before the specified
/// `rhs` nullable wrapper or `lhs` and `rhs` have the same value, and
/// `false` otherwise.  (See `operator<` and `operator==`.)  Note that this
/// operator returns `!(rhs < lhs)`.
template <class LHS_TYPE, class RHS_TYPE>
bool operator<=(const LHS_TYPE&                   lhs,
                const NullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` nullable wrapper is ordered after
/// the specified `rhs` nullable object, and `false` otherwise.  `lhs` is
/// ordered after `rhs` if `lhs` is non-null and `rhs` is null or if both
/// are non-null and `lhs.value()` is ordered after `rhs.value()`.  Note
/// that this operator returns `rhs < lhs` when both operands are of
/// `bsl::optional` type.  Also note that this function will fail to compile
/// if `LHS_TYPE` and `RHS_TYPE` are not compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator>(const NullableValueRef<LHS_TYPE>& lhs,
               const NullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` nullable wrapper is ordered after
/// the specified `rhs`, and `false` otherwise.  `lhs` is ordered after
/// `rhs` if `lhs` is not null and `lhs.value()` is ordered after `rhs`.
/// Note that this operator returns `rhs < lhs`.
template <class LHS_TYPE, class RHS_TYPE>
bool operator>(const NullableValueRef<LHS_TYPE>& lhs,
               const RHS_TYPE&                   rhs);

/// Return `true` if the specified `lhs` is ordered after the specified
/// `rhs` nullable wrapper, and `false` otherwise.  `lhs` is ordered after
/// `rhs` if `rhs` is null or `lhs` is ordered after `rhs.value()`.  Note
/// that this operator returns `rhs < lhs`.
template <class LHS_TYPE, class RHS_TYPE>
bool operator>(const LHS_TYPE&                   lhs,
               const NullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` nullable object is ordered after
/// the specified `rhs` nullable wrapper or `lhs` and `rhs` have the same
/// value, and `false` otherwise.  (See `operator>` and `operator==`.)  Note
/// that this operator returns `!(lhs < rhs)` when both operands are of
/// `bsl::optional` type.  Also note that this function will fail to compile
/// if `LHS_TYPE` and `RHS_TYPE` are not compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator>=(const NullableValueRef<LHS_TYPE>& lhs,
                const NullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` nullable wrapper is ordered after
/// the specified `rhs` or `lhs` and `rhs` have the same value, and `false`
/// otherwise.  (See `operator>` and `operator==`.)  Note that this operator
/// returns `!(lhs < rhs)`.
template <class LHS_TYPE, class RHS_TYPE>
bool operator>=(const NullableValueRef<LHS_TYPE>& lhs,
                const RHS_TYPE&                   rhs);

/// Return `true` if the specified `lhs` is wrapper after the specified
/// `rhs` nullable object or `lhs` and `rhs` have the same value, and
/// `false` otherwise.  (See `operator>` and `operator==`.)  Note that this
/// operator returns `!(lhs < rhs)`.
template <class LHS_TYPE, class RHS_TYPE>
bool operator>=(const LHS_TYPE&                   lhs,
                const NullableValueRef<RHS_TYPE>& rhs);


                  //================================
                  // Comparisons with bsl::nullopt_t
                  //================================

/// Return `true` if the specified `lhs` is null, and `false` otherwise.
template <class TYPE>
bool operator==(const NullableValueRef<TYPE>& lhs, const bsl::nullopt_t&)
                                                         BSLS_KEYWORD_NOEXCEPT;

/// Return `true` if the specified `rhs` is null, and `false` otherwise.
template <class TYPE>
bool operator==(const bsl::nullopt_t&, const NullableValueRef<TYPE>& rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;

/// Return `true` if the specified `lhs` is not null, and `false` otherwise.
template <class TYPE>
bool operator!=(const NullableValueRef<TYPE>& lhs, const bsl::nullopt_t&)
                                                         BSLS_KEYWORD_NOEXCEPT;

/// Return `true` if the specified `rhs` is not null, and `false`
/// otherwise.
template <class TYPE>
bool operator!=(const bsl::nullopt_t&, const NullableValueRef<TYPE>& rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;

/// Return `false`.  `bsl::nullopt` never orders after a
/// `NullableValueRef`.
template <class TYPE>
bool operator<(const NullableValueRef<TYPE>&, const bsl::nullopt_t&)
                                                         BSLS_KEYWORD_NOEXCEPT;

/// Return `true` if the specified `rhs` is not null, and `false` otherwise.
/// Note that `bsl::nullopt` is ordered before any `NullableValueRef` that
/// is not null.
template <class TYPE>
bool operator<(const bsl::nullopt_t&, const NullableValueRef<TYPE>& rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;

/// Return `true` if the specified `lhs` is not null, and `false`
/// otherwise.
template <class TYPE>
bool operator>(const NullableValueRef<TYPE>& lhs, const bsl::nullopt_t&)
                                                         BSLS_KEYWORD_NOEXCEPT;

/// Return `false`.  `bsl::nullopt` never orders after a
/// `NullableValueRef`.
template <class TYPE>
bool operator>(const bsl::nullopt_t&, const NullableValueRef<TYPE>&)
                                                         BSLS_KEYWORD_NOEXCEPT;

/// Return `true` if the specified `lhs` is null, and `false` otherwise.
template <class TYPE>
bool operator<=(const NullableValueRef<TYPE>& lhs, const bsl::nullopt_t&)
                                                         BSLS_KEYWORD_NOEXCEPT;

/// Return `true`.
template <class TYPE>
bool operator<=(const bsl::nullopt_t&, const NullableValueRef<TYPE>&)
                                                         BSLS_KEYWORD_NOEXCEPT;

/// Return `true`.
template <class TYPE>
bool operator>=(const NullableValueRef<TYPE>&, const bsl::nullopt_t&)
                                                         BSLS_KEYWORD_NOEXCEPT;

/// Return `true` if the specified `rhs` is null, and `false` otherwise.
template <class TYPE>
bool operator>=(const bsl::nullopt_t&, const NullableValueRef<TYPE>& rhs)
                                                         BSLS_KEYWORD_NOEXCEPT;

                      // =================================
                      // class ConstNullableValueRef<TYPE>
                      // =================================

/// This class is a wrapper for either a `bsl::optional` or
/// `NullableAllocatedValue`, and provides non-modifiable access to the
/// wrapped object.
template <class TYPE>
class ConstNullableValueRef {

    // PRIVATE TYPES
#ifndef BSLS_COMPILERFEATURES_SUPPORT_OPERATOR_EXPLICIT
    // UNSPECIFIED BOOL

    /// This type is needed only in C++03 mode, where `explicit` conversion
    /// operators are not supported.  A `NullableAllocatedValue` is implicitly
    /// converted to `UnspecifiedBool` when used in `if` statements, but is not
    /// implicitly convertible to `bool`.
    typedef BloombergLP::bsls::UnspecifiedBool<ConstNullableValueRef>
                                                           UnspecifiedBoolUtil;
    typedef typename UnspecifiedBoolUtil::BoolType         UnspecifiedBool;
#endif

    // DATA

    // the address of the target
    const void *d_target_p;

    // `true` if the referent is a specialization of `bsl::optional`, and
    // `false` if it's a specialization of `NullableAllocatedValue`.
    bool        d_isTargetOptional;

    // PRIVATE ACCESSORS

    /// Return a pointer to the held `bdlb::NullableAllocatedValue`.  The
    /// behavior is undefined if the target is not a
    /// `bdlb::NullableAllocatedValue`.
    const NullableAllocatedValue<TYPE>& getNAV() const;

    /// Return a pointer to the held `bdlb::bsl::optional`. The behavior is
    /// undefined if the target is not a `bdlb::bsl::optional`.
    const bsl::optional<TYPE>& getOpt() const;

    /// Return `true` if this object currently holds a pointer to a
    /// bdlb::bsl::optional, and `false` otherwise.
    bool hasOpt() const;

    // TRAITS

    /// This class requires that `TYPE` is not `const`- or `volatile`-
    /// qualified, nor a reference.
    BSLMF_ASSERT((
                 bsl::is_same<TYPE,
                              typename bsl::remove_cvref<TYPE>::type>::value));

  public:
    // TYPES

    /// `value_type` is an alias for the template parameter `TYPE`, and
    /// represents the type of the object managed by the wrapped nullable
    /// object.
    typedef TYPE value_type;

    // CREATORS

    /// Create a nullable object wrapper that refers to the specified `opt`
    /// object.  Note that the created wrapper does not own a copy of the
    /// underlying nullable value, but instead refers to it, and so the
    /// lifetime of `opt` must exceed the lifetime of the created wrapper.
    ConstNullableValueRef(const bsl::optional<TYPE>& opt);          // IMPLICIT

    /// Create a nullable object wrapper that refers to the specified `opt`
    /// object.  Note that the created wrapper does not own a copy of the
    /// underlying nullable value, but instead refers to it, and so the
    /// lifetime of `opt` must exceed the lifetime of the created wrapper.
    ConstNullableValueRef(const NullableAllocatedValue<TYPE>& opt);
                                                                    // IMPLICIT

    /// Create a nullable object wrapper that refers to the target object of
    /// the specified `ref` wrapper.  Note that the created wrapper does not
    /// own a copy of the underlying nullable value, but instead refers to
    /// to it, and so the lifetime of the target must exceed the lifetime of
    /// the created wrapper.
    ConstNullableValueRef(const NullableValueRef<TYPE>& ref);       // IMPLICIT

    /// Create a nullable object wrapper that refers to the target object of
    /// the specified `original` wrapper.  Note that the created wrapper
    /// does not own a copy of the underlying nullable value, but instead
    /// refers to it, and so the lifetime of the target must exceed the
    /// lifetime of the created wrapper.
    ConstNullableValueRef(const ConstNullableValueRef& original);

    /// Destroy this object.  Note that this destructor is generated by the
    /// compiler, and does not destruct the target.
    //! ~ConstNullableValueRef();

    // ACCESSORS

    /// Return `true` if the target contains a value, and `false` otherwise.
    bool has_value() const BSLS_KEYWORD_NOEXCEPT;

    /// Return `false` if the target contains a value, and `true` otherwise.
    /// Note that this accessor is provided purely for compatibility with
    /// `NullableValue` and `NullableAllocatedValue`, and its use is
    /// discouraged in favor of `has_value`.
    bool isNull() const BSLS_KEYWORD_NOEXCEPT;

    /// Return a reference providing non-modifiable access to the underlying
    /// object of a (template parameter) `TYPE`.  The behavior is undefined
    /// if the target has no value.
    const value_type& value() const;

    /// Return a pointer providing non-modifiable access to the underlying
    /// `TYPE` object.  The behavior is undefined if the target has no
    /// value.
    const value_type *operator->() const;

    /// Return a reference providing non-modifiable access to the underlying
    /// `TYPE` object.  The behavior is undefined if the target has no
    /// value.
    const value_type& operator*() const;

#ifdef BSLS_COMPILERFEATURES_SUPPORT_OPERATOR_EXPLICIT
    /// Return `true` if the target holds a value, and `false` otherwise.
    BSLS_KEYWORD_EXPLICIT operator bool() const BSLS_KEYWORD_NOEXCEPT;
#else
    /// Simulation of explicit conversion to bool.  Inlined to work around xlC
    /// but when out-of-line.
    operator UnspecifiedBool() const BSLS_NOTHROW_SPEC
    {
        return UnspecifiedBoolUtil::makeValue(has_value());
    }
#endif

    /// Return the value of the underlying object of a (template parameter)
    /// `TYPE` if the target is non-null, and the specified `default_value`
    /// otherwise.  Note that this method returns *by* *value*, so may be
    /// inefficient in some contexts.
    template <class ANY_TYPE>
    TYPE value_or(const ANY_TYPE& default_value) const;

    // DEPRECATED FUNCTIONS
    //  provided for compatibility with NullableValue

    /// Return an address providing non-modifiable access to the underlying
    /// object of a (template parameter) `TYPE` if this object is non-null,
    /// and the specified `address` otherwise.
    BSLS_DEPRECATE_FEATURE("bdl", "ConstNullableValueRef::addressOr",
                              "Use 'has_value() ? &value() : address' instead")
    const TYPE *addressOr(const TYPE *address) const;

    /// Return the value of the underlying object of a (template parameter)
    /// `TYPE` if this object is non-null, and the specified `otherValue`
    /// otherwise.  Note that this method returns *by* *value*, so may be
    /// inefficient in some contexts.
    BSLS_DEPRECATE_FEATURE("bdl", "ConstNullableValueRef::valueOr",
                                                      "Use 'value_or' instead")
    TYPE valueOr(const TYPE& otherValue) const;

    /// Return an address providing non-modifiable access to the underlying
    /// object of a (template parameter) `TYPE` if this object is non-null,
    /// and 0 otherwise.
    BSLS_DEPRECATE_FEATURE("bdl", "ConstNullableValueRef::valueOrNull",
                                 "Use 'has_value() ? &value() : NULL' instead")
    const TYPE *valueOrNull() const;

};

// FREE FUNCTIONS

/// Pass the boolean value of whether the specified `input` references a
/// non-empty nullable value to the specified `hashAlg` hashing algorithm of
/// (template parameter) type `HASHALG`.  If `input.has_value` is true,
/// additionally pass the value to `hashAlg`.
template <class HASHALG, class TYPE>
void hashAppend(HASHALG& hashAlg, const ConstNullableValueRef<TYPE>& input);

// FREE OPERATORS

/// Return `true` if the specified `lhs` and `rhs` nullable wrappers have
/// the same value, and `false` otherwise.  Two nullable wrappers have the
/// same value if both targets are null, or if both are non-null and the
/// values of their underlying objects compare equal.  Note that this
/// function will fail to compile if `LHS_TYPE` and `RHS_TYPE` are not
/// compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator==(const ConstNullableValueRef<LHS_TYPE>& lhs,
                const ConstNullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` and `rhs` objects have the same
/// value, and `false` otherwise.  A nullable wrapper and a value of some
/// type have the same value if the nullable wrapper is non-null and the
/// underlying value of it's target compares equal to the other value.  Note
/// that this function will fail to compile if `LHS_TYPE` and `RHS_TYPE` are
/// not compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator==(const ConstNullableValueRef<LHS_TYPE>& lhs,
                const RHS_TYPE&                        rhs);
template <class LHS_TYPE, class RHS_TYPE>
bool operator==(const LHS_TYPE&                        lhs,
                const ConstNullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` and `rhs` nullable objects do not
/// have the same value, and `false` otherwise.  Two nullable wrappers do
/// not have the same value if one is null and the other is non-null, or if
/// bost are non-null and the values of their underlying objects do not
/// compare equal.  Note that this function will fail to compile if
/// `LHS_TYPE` and `RHS_TYPE` are not compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator!=(const ConstNullableValueRef<LHS_TYPE>& lhs,
                const ConstNullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` and `rhs` objects do not have the
/// same value, and `false` otherwise.  A nullable wrappers and a value of
/// some type do not have the same value if either the nullable wrappers is
/// null, or its underlying value does not compare equal to the other value.
/// Note that this function will fail to compile if `LHS_TYPE` and
/// `RHS_TYPE` are not compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator!=(const ConstNullableValueRef<LHS_TYPE>& lhs,
                const RHS_TYPE&                        rhs);
template <class LHS_TYPE, class RHS_TYPE>
bool operator!=(const LHS_TYPE&                        lhs,
                const ConstNullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` nullable wrapper is ordered before
/// the specified `rhs` nullable object, and `false` otherwise.  `lhs` is
/// ordered before `rhs` if `lhs` is null and `rhs` is non-null or if both
/// are non-null and `lhs.value()` is ordered before `rhs.value()`.  Note
/// that this function will fail to compile if `LHS_TYPE` and `RHS_TYPE` are
/// not compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator<(const ConstNullableValueRef<LHS_TYPE>& lhs,
               const ConstNullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` nullable wrapper is ordered before
/// the specified `rhs`, and `false` otherwise.  `lhs` is ordered before
/// `rhs` if `lhs` is null or `lhs.value()` is ordered before `rhs`.
template <class LHS_TYPE, class RHS_TYPE>
bool operator<(const ConstNullableValueRef<LHS_TYPE>& lhs,
               const RHS_TYPE&                        rhs);

/// Return `true` if the specified `lhs` is ordered before the specified
/// `rhs` nullable wrappers, and `false` otherwise.  `lhs` is ordered before
/// `rhs` if `rhs` is not null and `lhs` is ordered before `rhs.value()`.
template <class LHS_TYPE, class RHS_TYPE>
bool operator<(const LHS_TYPE&                        lhs,
               const ConstNullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` nullable wrapper is ordered before
/// the specified `rhs` nullable object or `lhs` and `rhs` have the same
/// value, and `false` otherwise.  (See `operator<` and `operator==`.)  Note
/// that this function will fail to compile if `LHS_TYPE` and `RHS_TYPE`
/// are not compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator<=(const ConstNullableValueRef<LHS_TYPE>& lhs,
                const ConstNullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` nullable wrapper is ordered before
/// the specified `rhs` or `lhs` and `rhs` have the same value, and `false`
/// otherwise.  (See `operator<` and `operator==`.)  Note that this operator
/// returns `!(rhs < lhs)`.
template <class LHS_TYPE, class RHS_TYPE>
bool operator<=(const ConstNullableValueRef<LHS_TYPE>& lhs,
                const RHS_TYPE&                        rhs);

/// Return `true` if the specified `lhs` is ordered before the specified
/// `rhs` nullable wrapper or `lhs` and `rhs` have the same value, and
/// `false` otherwise.  (See `operator<` and `operator==`.)  Note that this
/// operator returns `!(rhs < lhs)`.
template <class LHS_TYPE, class RHS_TYPE>
bool operator<=(const LHS_TYPE&                        lhs,
                const ConstNullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` nullable wrapper is ordered after
/// the specified `rhs` nullable object, and `false` otherwise.  `lhs` is
/// ordered after `rhs` if `lhs` is non-null and `rhs` is null or if both
/// are non-null and `lhs.value()` is ordered after `rhs.value()`.  Note
/// that this operator returns `rhs < lhs` when both operands are of
/// `NullableValue` type.  Also note that this function will fail to compile
/// if `LHS_TYPE` and `RHS_TYPE` are not compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator>(const ConstNullableValueRef<LHS_TYPE>& lhs,
               const ConstNullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` nullable wrapper is ordered after
/// the specified `rhs`, and `false` otherwise.  `lhs` is ordered after
/// `rhs` if `lhs` is not null and `lhs.value()` is ordered after `rhs`.
/// Note that this operator returns `rhs < lhs`.
template <class LHS_TYPE, class RHS_TYPE>
bool operator>(const ConstNullableValueRef<LHS_TYPE>& lhs,
               const RHS_TYPE&                        rhs);

/// Return `true` if the specified `lhs` is ordered after the specified
/// `rhs` nullable wrapper, and `false` otherwise.  `lhs` is ordered after
/// `rhs` if `rhs` is null or `lhs` is ordered after `rhs.value()`.  Note
/// that this operator returns `rhs < lhs`.
template <class LHS_TYPE, class RHS_TYPE>
bool operator>(const LHS_TYPE&                        lhs,
               const ConstNullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` nullable object is ordered after
/// the specified `rhs` nullable wrapper or `lhs` and `rhs` have the same
/// value, and `false` otherwise.  (See `operator>` and `operator==`.)  Note
/// that this operator returns `!(lhs < rhs)` when both operands are of
/// `NullableValue` type.  Also note that this function will fail to compile
/// if `LHS_TYPE` and `RHS_TYPE` are not compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator>=(const ConstNullableValueRef<LHS_TYPE>& lhs,
                const ConstNullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` nullable wrapper is ordered after
/// the specified `rhs` or `lhs` and `rhs` have the same value, and `false`
/// otherwise.  (See `operator>` and `operator==`.)  Note that this operator
/// returns `!(lhs < rhs)`.
template <class LHS_TYPE, class RHS_TYPE>
bool operator>=(const ConstNullableValueRef<LHS_TYPE>& lhs,
                const RHS_TYPE&                        rhs);

/// Return `true` if the specified `lhs` is wrapper after the specified
/// `rhs` nullable object or `lhs` and `rhs` have the same value, and
/// `false` otherwise.  (See `operator>` and `operator==`.)  Note that this
/// operator returns `!(lhs < rhs)`.
template <class LHS_TYPE, class RHS_TYPE>
bool operator>=(const LHS_TYPE&                        lhs,
                const ConstNullableValueRef<RHS_TYPE>& rhs);

                       //================================
                       // Comparisons with bsl::nullopt_t
                       //================================

/// Return `true` if the specified `lhs` is null, and `false` otherwise.
template <class TYPE>
bool operator==(const ConstNullableValueRef<TYPE>& lhs,
                const bsl::nullopt_t&) BSLS_KEYWORD_NOEXCEPT;

/// Return `true` if the specified `rhs` is null, and `false` otherwise.
template <class TYPE>
bool operator==(const bsl::nullopt_t&,
                const ConstNullableValueRef<TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT;

/// Return `true` if the specified `lhs` is not null, and `false` otherwise.
template <class TYPE>
bool operator!=(const ConstNullableValueRef<TYPE>& lhs,
                const bsl::nullopt_t&) BSLS_KEYWORD_NOEXCEPT;

/// Return `true` if the specified `rhs` is not null, and `false`
/// otherwise.
template <class TYPE>
bool operator!=(const bsl::nullopt_t&,
                const ConstNullableValueRef<TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT;

/// Return `false`.  `bsl::nullopt` never orders after a
/// `ConstNullableValueRef`.
template <class TYPE>
bool operator<(const ConstNullableValueRef<TYPE>&, const bsl::nullopt_t&)
                                                         BSLS_KEYWORD_NOEXCEPT;

/// Return `true` if the specified `rhs` is not null, and `false` otherwise.
/// Note that `bsl::nullopt` is ordered before any `ConstNullableValueRef`
/// that is not null.
template <class TYPE>
bool operator<(const bsl::nullopt_t&,
               const ConstNullableValueRef<TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT;

/// Return `true` if the specified `lhs` is not null, and `false`
/// otherwise.
template <class TYPE>
bool operator>(const ConstNullableValueRef<TYPE>& lhs,
               const bsl::nullopt_t&) BSLS_KEYWORD_NOEXCEPT;

/// Return `false`.  `bsl::nullopt` never orders after a
/// `NullableValueRef`.
template <class TYPE>
bool operator>(const bsl::nullopt_t&, const ConstNullableValueRef<TYPE>&)
                                                         BSLS_KEYWORD_NOEXCEPT;

/// Return `true` if the specified `lhs` is null, and `false` otherwise.
template <class TYPE>
bool operator<=(const ConstNullableValueRef<TYPE>& lhs,
                const bsl::nullopt_t&) BSLS_KEYWORD_NOEXCEPT;

/// Return `true`.
template <class TYPE>
bool operator<=(const bsl::nullopt_t&, const ConstNullableValueRef<TYPE>&)
                                                         BSLS_KEYWORD_NOEXCEPT;

/// Return `true`.
template <class TYPE>
bool operator>=(const ConstNullableValueRef<TYPE>&, const bsl::nullopt_t&)
                                                         BSLS_KEYWORD_NOEXCEPT;

/// Return `true` if the specified `rhs` is null, and `false` otherwise.
template <class TYPE>
bool operator>=(const bsl::nullopt_t&,
                const ConstNullableValueRef<TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT;

     //===================================================================
     // Comparisons between 'ConstNullableValueRef' and 'NullableValueRef'
     //===================================================================

/// Return `true` if the specified `lhs` and `rhs` nullable wrappers have
/// the same value, and `false` otherwise.  Two nullable wrappers have the
/// same value if both targets are null, or if both are non-null and the
/// values of their underlying objects compare equal.  Note that this
/// function will fail to compile if `LHS_TYPE` and `RHS_TYPE` are not
/// compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator==(const ConstNullableValueRef<LHS_TYPE>& lhs,
                const NullableValueRef<RHS_TYPE>&      rhs);
template <class LHS_TYPE, class RHS_TYPE>
bool operator==(const NullableValueRef<LHS_TYPE>&      lhs,
                const ConstNullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` and `rhs` nullable objects do not
/// have the same value, and `false` otherwise.  Two nullable wrappers do
/// not have the same value if one is null and the other is non-null, or if
/// both are non-null and the values of their underlying objects do not
/// compare equal.  Note that this function will fail to compile if
/// `LHS_TYPE` and `RHS_TYPE` are not compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator!=(const ConstNullableValueRef<LHS_TYPE>& lhs,
                const NullableValueRef<RHS_TYPE>&      rhs);
template <class LHS_TYPE, class RHS_TYPE>
bool operator!=(const NullableValueRef<LHS_TYPE>&      lhs,
                const ConstNullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` nullable wrapper is ordered before
/// the specified `rhs` nullable object, and `false` otherwise.  `lhs` is
/// ordered before `rhs` if `lhs` is null and `rhs` is non-null or if both
/// are non-null and `lhs.value()` is ordered before `rhs.value()`.  Note
/// that this function will fail to compile if `LHS_TYPE` and `RHS_TYPE` are
/// not compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator<(const ConstNullableValueRef<LHS_TYPE>& lhs,
               const NullableValueRef<RHS_TYPE>&      rhs);
template <class LHS_TYPE, class RHS_TYPE>
bool operator<(const NullableValueRef<LHS_TYPE>&      lhs,
               const ConstNullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` nullable wrapper is ordered before
/// the specified `rhs` nullable object or `lhs` and `rhs` have the same
/// value, and `false` otherwise.  (See `operator<` and `operator==`.)  Note
/// that this function will fail to compile if `LHS_TYPE` and `RHS_TYPE`
/// are not compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator<=(const ConstNullableValueRef<LHS_TYPE>& lhs,
                const NullableValueRef<RHS_TYPE>&      rhs);
template <class LHS_TYPE, class RHS_TYPE>
bool operator<=(const NullableValueRef<LHS_TYPE>&      lhs,
                const ConstNullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` nullable wrapper is ordered after
/// the specified `rhs` nullable object, and `false` otherwise.  `lhs` is
/// ordered after `rhs` if `lhs` is non-null and `rhs` is null or if both
/// are non-null and `lhs.value()` is ordered after `rhs.value()`.  Note
/// that this operator returns `rhs < lhs` when both operands are of
/// `NullableValue` type.  Also note that this function will fail to compile
/// if `LHS_TYPE` and `RHS_TYPE` are not compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator>(const ConstNullableValueRef<LHS_TYPE>& lhs,
               const NullableValueRef<RHS_TYPE>&      rhs);
template <class LHS_TYPE, class RHS_TYPE>
bool operator>(const NullableValueRef<LHS_TYPE>&      lhs,
               const ConstNullableValueRef<RHS_TYPE>& rhs);

/// Return `true` if the specified `lhs` nullable object is ordered after
/// the specified `rhs` nullable wrapper or `lhs` and `rhs` have the same
/// value, and `false` otherwise.  (See `operator>` and `operator==`.)  Note
/// that this operator returns `!(lhs < rhs)` when both operands are of
/// `NullableValue` type.  Also note that this function will fail to compile
/// if `LHS_TYPE` and `RHS_TYPE` are not compatible.
template <class LHS_TYPE, class RHS_TYPE>
bool operator>=(const ConstNullableValueRef<LHS_TYPE>& lhs,
                const NullableValueRef<RHS_TYPE>&      rhs);
template <class LHS_TYPE, class RHS_TYPE>
bool operator>=(const NullableValueRef<LHS_TYPE>&      lhs,
                const ConstNullableValueRef<RHS_TYPE>& rhs);

}  // close package namespace

                        // ----------------------------
                        // class NullableValueRef<TYPE>
                        // ----------------------------

// PRIVATE ACCESSORS
template <class TYPE>
inline
bdlb::NullableAllocatedValue<TYPE>&
bdlb::NullableValueRef<TYPE>::getNAV() const
{
    BSLS_ASSERT(!hasOpt());
    return *static_cast<bdlb::NullableAllocatedValue<TYPE> *>(d_target_p);
}

template <class TYPE>
inline
bsl::optional<TYPE>&
bdlb::NullableValueRef<TYPE>::getOpt() const
{
    BSLS_ASSERT(hasOpt());
    return *static_cast<bsl::optional<TYPE> *>(d_target_p);
}

template <class TYPE>
inline
bool bdlb::NullableValueRef<TYPE>::hasOpt() const
{
    return d_isTargetOptional;
}

// CREATORS
template <class TYPE>
inline
bdlb::NullableValueRef<TYPE>::NullableValueRef(bsl::optional<TYPE>& opt)
: d_target_p(&opt)
, d_isTargetOptional(true)
{
}

template <class TYPE>
inline
bdlb::NullableValueRef<TYPE>::NullableValueRef(
                                             NullableAllocatedValue<TYPE>& opt)
: d_target_p(&opt)
, d_isTargetOptional(false)
{
}

template <class TYPE>
inline
bdlb::NullableValueRef<TYPE>::NullableValueRef(
                                              const NullableValueRef& original)
: d_target_p(original.d_target_p)
, d_isTargetOptional(original.d_isTargetOptional)
{
}

// ACCESSORS
template <class TYPE>
inline
bool bdlb::NullableValueRef<TYPE>::has_value() const BSLS_KEYWORD_NOEXCEPT
{
    return hasOpt()
              ? getOpt().has_value()
              : getNAV().has_value();
}

template <class TYPE>
inline
bool bdlb::NullableValueRef<TYPE>::isNull() const BSLS_KEYWORD_NOEXCEPT
{
    return !has_value();
}

template <class TYPE>
inline
const typename bdlb::NullableValueRef<TYPE>::value_type&
bdlb::NullableValueRef<TYPE>::value() const
{
    return hasOpt()
              ? getOpt().value()
              : getNAV().value();
}


template <class TYPE>
inline
const typename bdlb::NullableValueRef<TYPE>::value_type *
bdlb::NullableValueRef<TYPE>::operator->() const
{
    return hasOpt()
              ? getOpt().operator->()
              : getNAV().operator->();
}

template <class TYPE>
inline
const typename bdlb::NullableValueRef<TYPE>::value_type&
bdlb::NullableValueRef<TYPE>::operator*() const
{
    return hasOpt()
              ? getOpt().operator*()
              : getNAV().operator*();
}

#ifdef BSLS_COMPILERFEATURES_SUPPORT_OPERATOR_EXPLICIT
template <class TYPE>
bdlb::NullableValueRef<TYPE>::operator bool() const BSLS_KEYWORD_NOEXCEPT
{
    return has_value();
}
#endif

template <class TYPE>
template <class ANY_TYPE>
inline
TYPE bdlb::NullableValueRef<TYPE>::value_or(
                                           const ANY_TYPE& default_value) const
{
    if (has_value()) {
        return hasOpt()
                  ? getOpt().value()
                  : getNAV().value();                                 // RETURN
    }
    return default_value;
}


// MANIPULATORS
#if BSLS_COMPILERFEATURES_SIMULATE_VARIADIC_TEMPLATES
// {{{ BEGIN GENERATED CODE
// Command line: sim_cpp11_features.pl bdlb_nullablevalueref.h
#ifndef BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT
#define BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT 5
#endif
#ifndef BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_C
#define BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_C BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT
#endif
#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_C >= 0
template <class TYPE>
inline
TYPE& bdlb::NullableValueRef<TYPE>::emplace(
                               )
{
    return hasOpt()
              ? getOpt().emplace()
              : getNAV().emplace();
}
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_C >= 0

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_C >= 1
template <class TYPE>
template <class ARGS_1>
inline
TYPE& bdlb::NullableValueRef<TYPE>::emplace(
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_1) args_1)
{
    return hasOpt()
              ? getOpt().emplace(BSLS_COMPILERFEATURES_FORWARD(ARGS_1, args_1))
              : getNAV().emplace(
                                BSLS_COMPILERFEATURES_FORWARD(ARGS_1, args_1));
}
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_C >= 1

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_C >= 2
template <class TYPE>
template <class ARGS_1,
          class ARGS_2>
inline
TYPE& bdlb::NullableValueRef<TYPE>::emplace(
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_1) args_1,
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_2) args_2)
{
    return hasOpt()
              ? getOpt().emplace(BSLS_COMPILERFEATURES_FORWARD(ARGS_1, args_1),
                                 BSLS_COMPILERFEATURES_FORWARD(ARGS_2, args_2))
              : getNAV().emplace(
                                BSLS_COMPILERFEATURES_FORWARD(ARGS_1, args_1),
                                BSLS_COMPILERFEATURES_FORWARD(ARGS_2, args_2));
}
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_C >= 2

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_C >= 3
template <class TYPE>
template <class ARGS_1,
          class ARGS_2,
          class ARGS_3>
inline
TYPE& bdlb::NullableValueRef<TYPE>::emplace(
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_1) args_1,
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_2) args_2,
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_3) args_3)
{
    return hasOpt()
              ? getOpt().emplace(BSLS_COMPILERFEATURES_FORWARD(ARGS_1, args_1),
                                 BSLS_COMPILERFEATURES_FORWARD(ARGS_2, args_2),
                                 BSLS_COMPILERFEATURES_FORWARD(ARGS_3, args_3))
              : getNAV().emplace(
                                BSLS_COMPILERFEATURES_FORWARD(ARGS_1, args_1),
                                BSLS_COMPILERFEATURES_FORWARD(ARGS_2, args_2),
                                BSLS_COMPILERFEATURES_FORWARD(ARGS_3, args_3));
}
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_C >= 3

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_C >= 4
template <class TYPE>
template <class ARGS_1,
          class ARGS_2,
          class ARGS_3,
          class ARGS_4>
inline
TYPE& bdlb::NullableValueRef<TYPE>::emplace(
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_1) args_1,
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_2) args_2,
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_3) args_3,
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_4) args_4)
{
    return hasOpt()
              ? getOpt().emplace(BSLS_COMPILERFEATURES_FORWARD(ARGS_1, args_1),
                                 BSLS_COMPILERFEATURES_FORWARD(ARGS_2, args_2),
                                 BSLS_COMPILERFEATURES_FORWARD(ARGS_3, args_3),
                                 BSLS_COMPILERFEATURES_FORWARD(ARGS_4, args_4))
              : getNAV().emplace(
                                BSLS_COMPILERFEATURES_FORWARD(ARGS_1, args_1),
                                BSLS_COMPILERFEATURES_FORWARD(ARGS_2, args_2),
                                BSLS_COMPILERFEATURES_FORWARD(ARGS_3, args_3),
                                BSLS_COMPILERFEATURES_FORWARD(ARGS_4, args_4));
}
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_C >= 4

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_C >= 5
template <class TYPE>
template <class ARGS_1,
          class ARGS_2,
          class ARGS_3,
          class ARGS_4,
          class ARGS_5>
inline
TYPE& bdlb::NullableValueRef<TYPE>::emplace(
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_1) args_1,
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_2) args_2,
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_3) args_3,
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_4) args_4,
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_5) args_5)
{
    return hasOpt()
              ? getOpt().emplace(BSLS_COMPILERFEATURES_FORWARD(ARGS_1, args_1),
                                 BSLS_COMPILERFEATURES_FORWARD(ARGS_2, args_2),
                                 BSLS_COMPILERFEATURES_FORWARD(ARGS_3, args_3),
                                 BSLS_COMPILERFEATURES_FORWARD(ARGS_4, args_4),
                                 BSLS_COMPILERFEATURES_FORWARD(ARGS_5, args_5))
              : getNAV().emplace(
                                BSLS_COMPILERFEATURES_FORWARD(ARGS_1, args_1),
                                BSLS_COMPILERFEATURES_FORWARD(ARGS_2, args_2),
                                BSLS_COMPILERFEATURES_FORWARD(ARGS_3, args_3),
                                BSLS_COMPILERFEATURES_FORWARD(ARGS_4, args_4),
                                BSLS_COMPILERFEATURES_FORWARD(ARGS_5, args_5));
}
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_C >= 5

#else
// The generated code below is a workaround for the absence of perfect
// forwarding in some compilers.
template <class TYPE>
template <class... ARGS>
inline
TYPE& bdlb::NullableValueRef<TYPE>::emplace(
                               BSLS_COMPILERFEATURES_FORWARD_REF(ARGS)... args)
{
    return hasOpt()
              ? getOpt().emplace(BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...)
              : getNAV().emplace(BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...);
}
// }}} END GENERATED CODE
#endif

template <class TYPE>
inline
typename bdlb::NullableValueRef<TYPE>::value_type *
bdlb::NullableValueRef<TYPE>::operator->()
{
    return hasOpt()
              ? getOpt().operator->()
              : getNAV().operator->();
}

template <class TYPE>
inline
typename bdlb::NullableValueRef<TYPE>::value_type&
bdlb::NullableValueRef<TYPE>::operator*()
{
    return hasOpt()
              ? getOpt().operator*()
              : getNAV().operator*();
}

template <class TYPE>
inline
bdlb::NullableValueRef<TYPE>&
bdlb::NullableValueRef<TYPE>::operator=(const bsl::nullopt_t&)
{
    reset();
    return *this;
}

template <class TYPE>
inline
bdlb::NullableValueRef<TYPE>&
bdlb::NullableValueRef<TYPE>::operator=(const TYPE& rhs)
{
    if (hasOpt()) {
        getOpt() = rhs;
    }
    else {
        getNAV() = rhs;
    }

    return *this;
}

template <class TYPE>
inline
bdlb::NullableValueRef<TYPE>&
bdlb::NullableValueRef<TYPE>::operator=(const bsl::optional<TYPE>& rhs)
{
    if (rhs.has_value()) {
        *this = rhs.value();
    }
    else {
        reset();
    }
    return *this;
}

template <class TYPE>
inline
bdlb::NullableValueRef<TYPE>&
bdlb::NullableValueRef<TYPE>::operator=(
                                       const NullableAllocatedValue<TYPE>& rhs)
{
    if (rhs.has_value()) {
        *this = rhs.value();
    }
    else {
        reset();
    }

    return *this;
}

template <class TYPE>
inline
bdlb::NullableValueRef<TYPE>&
bdlb::NullableValueRef<TYPE>::operator=(const NullableValueRef& rhs)
{
    if (rhs.has_value()) {
        *this = rhs.value();
    }
    else {
        reset();
    }

    return *this;
}

template <class TYPE>
inline
void bdlb::NullableValueRef<TYPE>::reset()
{
    if (hasOpt()) {
        getOpt().reset();
    }
    else {
        getNAV().reset();
    }
}

template <class TYPE>
inline
typename bdlb::NullableValueRef<TYPE>::value_type&
bdlb::NullableValueRef<TYPE>::value()
{
    return hasOpt()
              ? getOpt().value()
              : getNAV().value();
}

// DEPRECATED FUNCTIONS
template <class TYPE>
inline
const TYPE *
bdlb::NullableValueRef<TYPE>::addressOr(const TYPE *address) const
{
    return has_value() ? &value() : address;
}

#if BSLS_COMPILERFEATURES_SIMULATE_VARIADIC_TEMPLATES
// {{{ BEGIN GENERATED CODE
// Command line: sim_cpp11_features.pl bdlb_nullablevalueref.h
#ifndef BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT
#define BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT 5
#endif
#ifndef BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_D
#define BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_D BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT
#endif
#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_D >= 0
template <class TYPE>
inline
TYPE& bdlb::NullableValueRef<TYPE>::makeValueInplace(
                               )
{
    return emplace();
}
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_D >= 0

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_D >= 1
template <class TYPE>
template <class ARGS_1>
inline
TYPE& bdlb::NullableValueRef<TYPE>::makeValueInplace(
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_1) args_1)
{
    return emplace(BSLS_COMPILERFEATURES_FORWARD(ARGS_1, args_1));
}
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_D >= 1

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_D >= 2
template <class TYPE>
template <class ARGS_1,
          class ARGS_2>
inline
TYPE& bdlb::NullableValueRef<TYPE>::makeValueInplace(
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_1) args_1,
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_2) args_2)
{
    return emplace(BSLS_COMPILERFEATURES_FORWARD(ARGS_1, args_1),
                   BSLS_COMPILERFEATURES_FORWARD(ARGS_2, args_2));
}
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_D >= 2

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_D >= 3
template <class TYPE>
template <class ARGS_1,
          class ARGS_2,
          class ARGS_3>
inline
TYPE& bdlb::NullableValueRef<TYPE>::makeValueInplace(
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_1) args_1,
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_2) args_2,
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_3) args_3)
{
    return emplace(BSLS_COMPILERFEATURES_FORWARD(ARGS_1, args_1),
                   BSLS_COMPILERFEATURES_FORWARD(ARGS_2, args_2),
                   BSLS_COMPILERFEATURES_FORWARD(ARGS_3, args_3));
}
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_D >= 3

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_D >= 4
template <class TYPE>
template <class ARGS_1,
          class ARGS_2,
          class ARGS_3,
          class ARGS_4>
inline
TYPE& bdlb::NullableValueRef<TYPE>::makeValueInplace(
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_1) args_1,
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_2) args_2,
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_3) args_3,
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_4) args_4)
{
    return emplace(BSLS_COMPILERFEATURES_FORWARD(ARGS_1, args_1),
                   BSLS_COMPILERFEATURES_FORWARD(ARGS_2, args_2),
                   BSLS_COMPILERFEATURES_FORWARD(ARGS_3, args_3),
                   BSLS_COMPILERFEATURES_FORWARD(ARGS_4, args_4));
}
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_D >= 4

#if BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_D >= 5
template <class TYPE>
template <class ARGS_1,
          class ARGS_2,
          class ARGS_3,
          class ARGS_4,
          class ARGS_5>
inline
TYPE& bdlb::NullableValueRef<TYPE>::makeValueInplace(
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_1) args_1,
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_2) args_2,
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_3) args_3,
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_4) args_4,
                              BSLS_COMPILERFEATURES_FORWARD_REF(ARGS_5) args_5)
{
    return emplace(BSLS_COMPILERFEATURES_FORWARD(ARGS_1, args_1),
                   BSLS_COMPILERFEATURES_FORWARD(ARGS_2, args_2),
                   BSLS_COMPILERFEATURES_FORWARD(ARGS_3, args_3),
                   BSLS_COMPILERFEATURES_FORWARD(ARGS_4, args_4),
                   BSLS_COMPILERFEATURES_FORWARD(ARGS_5, args_5));
}
#endif  // BDLB_NULLABLEVALUEREF_VARIADIC_LIMIT_D >= 5

#else
// The generated code below is a workaround for the absence of perfect
// forwarding in some compilers.
template <class TYPE>
template <class... ARGS>
inline
TYPE& bdlb::NullableValueRef<TYPE>::makeValueInplace(
                               BSLS_COMPILERFEATURES_FORWARD_REF(ARGS)... args)
{
    return emplace(BSLS_COMPILERFEATURES_FORWARD(ARGS, args)...);
}
// }}} END GENERATED CODE
#endif

template <class TYPE>
inline
TYPE bdlb::NullableValueRef<TYPE>::valueOr(const TYPE& otherValue) const
{
    return value_or(otherValue);
}

template <class TYPE>
inline
const TYPE *bdlb::NullableValueRef<TYPE>::valueOrNull() const
{
    return has_value() ? &value() : 0;
}

// FREE FUNCTIONS
template <class HASHALG, class TYPE>
void bdlb::hashAppend(HASHALG&                      hashAlg,
                      const NullableValueRef<TYPE>& input)
{
    using ::BloombergLP::bslh::hashAppend;

    if (!input.has_value()) {
        hashAppend(hashAlg, false);
    }
    else {
        hashAppend(hashAlg, true);
        hashAppend(hashAlg, input.value());
    }
}

// FREE OPERATORS
template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator==(const NullableValueRef<LHS_TYPE>& lhs,
                      const NullableValueRef<RHS_TYPE>& rhs)
{
    if (lhs.has_value()) {
        return rhs.has_value() ? lhs.value() == rhs.value() : false;  // RETURN
    }

    return !rhs.has_value();
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator==(const NullableValueRef<LHS_TYPE>& lhs,
                      const RHS_TYPE&                   rhs)
{
    return lhs.has_value() ? lhs.value() == rhs : false;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator==(const LHS_TYPE&                   lhs,
                      const NullableValueRef<RHS_TYPE>& rhs)
{
    return rhs.has_value() ? lhs == rhs.value(): false;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator!=(const NullableValueRef<LHS_TYPE>& lhs,
                      const NullableValueRef<RHS_TYPE>& rhs)
{
    if (lhs.has_value()) {
        return rhs.has_value() ? lhs.value() != rhs.value() : true;   // RETURN
    }

    return rhs.has_value();
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator!=(const NullableValueRef<LHS_TYPE>& lhs,
                      const RHS_TYPE&                   rhs)
{
    return lhs.has_value() ? lhs.value() != rhs : true;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator!=(const LHS_TYPE&                   lhs,
                      const NullableValueRef<RHS_TYPE>& rhs)
{
    return rhs.has_value() ? lhs != rhs.value() : true;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator<(const NullableValueRef<LHS_TYPE>& lhs,
                     const NullableValueRef<RHS_TYPE>& rhs)
{
    if (!rhs.has_value()) {
        return false;                                                 // RETURN
    }

    return lhs.has_value() ? lhs.value() < rhs.value() : true;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator<(const NullableValueRef<LHS_TYPE>& lhs,
                     const RHS_TYPE&                   rhs)
{
    return lhs.has_value() ? lhs.value() < rhs : true;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator<(const LHS_TYPE&                   lhs,
                     const NullableValueRef<RHS_TYPE>& rhs)
{
    return rhs.has_value() ? lhs < rhs.value() : false;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator<=(const NullableValueRef<LHS_TYPE>& lhs,
                      const NullableValueRef<RHS_TYPE>& rhs)
{
    if (!lhs.has_value()) {
        return true;                                                  // RETURN
    }

    return rhs.has_value() ? lhs.value() <= rhs.value() : false;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator<=(const NullableValueRef<LHS_TYPE>& lhs,
                      const RHS_TYPE&                   rhs)
{
    return lhs.has_value() ?  lhs.value() <= rhs : true;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator<=(const LHS_TYPE&                   lhs,
                      const NullableValueRef<RHS_TYPE>& rhs)
{
    return rhs.has_value() ? lhs <= rhs.value() : false;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator>(const NullableValueRef<LHS_TYPE>& lhs,
                     const NullableValueRef<RHS_TYPE>& rhs)
{
    if (!lhs.has_value()) {
        return false;                                                 // RETURN
    }

    return rhs.has_value() ? lhs.value() > rhs.value() : true;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator>(const NullableValueRef<LHS_TYPE>& lhs,
                     const RHS_TYPE&                   rhs)
{
    return lhs.has_value() ? lhs.value() > rhs : false;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator>(const LHS_TYPE&                   lhs,
                     const NullableValueRef<RHS_TYPE>& rhs)
{
    return rhs.has_value() ? lhs > rhs.value() : true;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator>=(const NullableValueRef<LHS_TYPE>& lhs,
                      const NullableValueRef<RHS_TYPE>& rhs)
{
    if (!rhs.has_value()) {
        return true;                                                  // RETURN
    }

    return lhs.has_value() ? lhs.value() >= rhs.value() : false;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator>=(const NullableValueRef<LHS_TYPE>& lhs,
                      const RHS_TYPE&                   rhs)
{
    return lhs.has_value() ? lhs.value() >= rhs : false;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator>=(const LHS_TYPE&                   lhs,
                      const NullableValueRef<RHS_TYPE>& rhs)
{
    return rhs.has_value() ? lhs >= rhs.value() : true;
}

                       //--------------------------------
                       // Comparisons with bsl::nullopt_t
                       //--------------------------------

template <class TYPE>
inline
bool bdlb::operator==(const NullableValueRef<TYPE>& lhs,
                      const bsl::nullopt_t&) BSLS_KEYWORD_NOEXCEPT
{
    return !lhs.has_value();
}

template <class TYPE>
inline
bool bdlb::operator==(
                   const bsl::nullopt_t&,
                   const NullableValueRef<TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT
{
    return !rhs.has_value();
}

template <class TYPE>
inline bool bdlb::operator!=(const NullableValueRef<TYPE>& lhs,
                             const bsl::nullopt_t& ) BSLS_KEYWORD_NOEXCEPT
{
    return lhs.has_value();
}

template <class TYPE>
inline
bool bdlb::operator!=(
                   const bsl::nullopt_t&,
                   const NullableValueRef<TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT
{
    return rhs.has_value();
}

template <class TYPE>
inline
bool bdlb::operator<(const NullableValueRef<TYPE>&,
                     const bsl::nullopt_t&) BSLS_KEYWORD_NOEXCEPT
{
    return false;
}

template <class TYPE>
inline
bool bdlb::operator<(
                   const bsl::nullopt_t&,
                   const NullableValueRef<TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT
{
    return rhs.has_value();
}

template <class TYPE>
inline
bool bdlb::operator>(const NullableValueRef<TYPE>& lhs,
                     const bsl::nullopt_t&) BSLS_KEYWORD_NOEXCEPT
{
    return lhs.has_value();
}

template <class TYPE>
inline
bool bdlb::operator>(const bsl::nullopt_t&,
                     const NullableValueRef<TYPE>&) BSLS_KEYWORD_NOEXCEPT
{
    return false;
}

template <class TYPE>
inline
bool bdlb::operator<=(const NullableValueRef<TYPE>& lhs,
                      const bsl::nullopt_t&) BSLS_KEYWORD_NOEXCEPT
{
    return !lhs.has_value();
}

template <class TYPE>
inline
bool bdlb::operator<=(
                       const bsl::nullopt_t&,
                       const NullableValueRef<TYPE>&) BSLS_KEYWORD_NOEXCEPT
{
    return true;
}

template <class TYPE>
inline
bool bdlb::operator>=(const NullableValueRef<TYPE>&,
                      const bsl::nullopt_t&) BSLS_KEYWORD_NOEXCEPT
{
    return true;
}

template <class TYPE>
inline
bool bdlb::operator>=(
                   const bsl::nullopt_t&,
                   const NullableValueRef<TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT
{
    return !rhs.has_value();
}

                      // ---------------------------------
                      // class ConstNullableValueRef<TYPE>
                      // ---------------------------------

// PRIVATE ACCESSORS
template <class TYPE>
inline
const bdlb::NullableAllocatedValue<TYPE>&
bdlb::ConstNullableValueRef<TYPE>::getNAV() const
{
    BSLS_ASSERT(!hasOpt());
    return *static_cast<const NullableAllocatedValue<value_type> *>(
                                                                   d_target_p);
}

template <class TYPE>
inline
const bsl::optional<TYPE>&
bdlb::ConstNullableValueRef<TYPE>::getOpt() const
{
    BSLS_ASSERT(hasOpt());
    return *static_cast<const bsl::optional<value_type> *>(d_target_p);
}

template <class TYPE>
inline
bool bdlb::ConstNullableValueRef<TYPE>::hasOpt() const
{
    return d_isTargetOptional;
}

// CREATORS
template <class TYPE>
inline
bdlb::ConstNullableValueRef<TYPE>::ConstNullableValueRef(
                                                const bsl::optional<TYPE>& opt)
: d_target_p(&opt)
, d_isTargetOptional(true)
{
}

template <class TYPE>
inline
bdlb::ConstNullableValueRef<TYPE>::ConstNullableValueRef(
                                       const NullableAllocatedValue<TYPE>& opt)
: d_target_p(&opt)
, d_isTargetOptional(false)
{
}

template <class TYPE>
inline
bdlb::ConstNullableValueRef<TYPE>::ConstNullableValueRef(
                                             const NullableValueRef<TYPE>& ref)
: d_target_p(ref.d_target_p)
, d_isTargetOptional(ref.d_isTargetOptional)
{
}

template <class TYPE>
inline
bdlb::ConstNullableValueRef<TYPE>::ConstNullableValueRef(
                                         const ConstNullableValueRef& original)
: d_target_p(original.d_target_p)
, d_isTargetOptional(original.d_isTargetOptional)
{
}

// ACCESSORS
template <class TYPE>
inline
bool
bdlb::ConstNullableValueRef<TYPE>::has_value() const BSLS_KEYWORD_NOEXCEPT
{
    return hasOpt()
              ? getOpt().has_value()
              : getNAV().has_value();
}

template <class TYPE>
inline
bool
bdlb::ConstNullableValueRef<TYPE>::isNull() const BSLS_KEYWORD_NOEXCEPT
{
    return !has_value();
}

template <class TYPE>
inline
const typename bdlb::ConstNullableValueRef<TYPE>::value_type&
bdlb::ConstNullableValueRef<TYPE>::value() const
{
    return hasOpt()
              ? getOpt().value()
              : getNAV().value();
}


template <class TYPE>
inline
const typename bdlb::ConstNullableValueRef<TYPE>::value_type *
bdlb::ConstNullableValueRef<TYPE>::operator->() const
{
    return hasOpt()
              ? getOpt().operator->()
              : getNAV().operator->();
}

template <class TYPE>
inline
const typename bdlb::ConstNullableValueRef<TYPE>::value_type&
bdlb::ConstNullableValueRef<TYPE>::operator*() const
{
    return hasOpt()
              ? getOpt().operator*()
              : getNAV().operator*();
}

#ifdef BSLS_COMPILERFEATURES_SUPPORT_OPERATOR_EXPLICIT
template <class TYPE>
bdlb::ConstNullableValueRef<TYPE>::operator bool() const BSLS_KEYWORD_NOEXCEPT
{
    return has_value();
}
#endif

template <class TYPE>
template <class ANY_TYPE>
inline
TYPE bdlb::ConstNullableValueRef<TYPE>::value_or(
                                           const ANY_TYPE& default_value) const
{
    if (has_value()) {
        return hasOpt()
                  ? getOpt().value()
                  : getNAV().value();                                 // RETURN
    }
    return default_value;
}

// DEPRECATED FUNCTIONS
template <class TYPE>
inline
const TYPE *
bdlb::ConstNullableValueRef<TYPE>::addressOr(const TYPE *address) const
{
    return has_value() ? &value() : address;
}

template <class TYPE>
inline
TYPE
bdlb::ConstNullableValueRef<TYPE>::valueOr(const TYPE& otherValue) const
{
    return value_or(otherValue);
}

template <class TYPE>
inline
const TYPE *bdlb::ConstNullableValueRef<TYPE>::valueOrNull() const
{
    return has_value() ? &value() : 0;
}

// FREE FUNCTIONS
template <class HASHALG, class TYPE>
void bdlb::hashAppend(HASHALG&                           hashAlg,
                      const ConstNullableValueRef<TYPE>& input)
{
    using ::BloombergLP::bslh::hashAppend;

    if (!input.has_value()) {
        hashAppend(hashAlg, false);
    }
    else {
        hashAppend(hashAlg, true);
        hashAppend(hashAlg, input.value());
    }
}

// FREE OPERATORS
template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator==(const ConstNullableValueRef<LHS_TYPE>& lhs,
                      const ConstNullableValueRef<RHS_TYPE>& rhs)
{
    if (lhs.has_value()) {
        return rhs.has_value() ? lhs.value() == rhs.value() : false;  // RETURN
    }

    return !rhs.has_value();
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator==(const ConstNullableValueRef<LHS_TYPE>& lhs,
                      const RHS_TYPE&                        rhs)
{
    return lhs.has_value() ? lhs.value() == rhs : false;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator==(const LHS_TYPE&                        lhs,
                      const ConstNullableValueRef<RHS_TYPE>& rhs)
{
    return rhs.has_value() ? lhs == rhs.value(): false;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator!=(const ConstNullableValueRef<LHS_TYPE>& lhs,
                      const ConstNullableValueRef<RHS_TYPE>& rhs)
{
    if (lhs.has_value()) {
        return rhs.has_value() ? lhs.value() != rhs.value() : true;   // RETURN
    }

    return rhs.has_value();
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator!=(const ConstNullableValueRef<LHS_TYPE>& lhs,
                      const RHS_TYPE&                        rhs)
{
    return lhs.has_value() ? lhs.value() != rhs : true;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator!=(const LHS_TYPE&                        lhs,
                      const ConstNullableValueRef<RHS_TYPE>& rhs)
{
    return rhs.has_value() ? lhs != rhs.value() : true;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator<(const ConstNullableValueRef<LHS_TYPE>& lhs,
                     const ConstNullableValueRef<RHS_TYPE>& rhs)
{
    if (!rhs.has_value()) {
        return false;                                                 // RETURN
    }

    return lhs.has_value() ? lhs.value() < rhs.value() : true;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator<(const ConstNullableValueRef<LHS_TYPE>& lhs,
                     const RHS_TYPE&                        rhs)
{
    return lhs.has_value() ? lhs.value() < rhs : true;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator<(const LHS_TYPE&                        lhs,
                     const ConstNullableValueRef<RHS_TYPE>& rhs)
{
    return rhs.has_value() ? lhs < rhs.value() : false;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator<=(const ConstNullableValueRef<LHS_TYPE>& lhs,
                      const ConstNullableValueRef<RHS_TYPE>& rhs)
{
    if (!lhs.has_value()) {
        return true;                                                  // RETURN
    }

    return rhs.has_value() ? lhs.value() <= rhs.value() : false;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator<=(const ConstNullableValueRef<LHS_TYPE>& lhs,
                      const RHS_TYPE&                        rhs)
{
    return lhs.has_value() ?  lhs.value() <= rhs : true;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator<=(const LHS_TYPE&                        lhs,
                      const ConstNullableValueRef<RHS_TYPE>& rhs)
{
    return rhs.has_value() ? lhs <= rhs.value() : false;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator>(const ConstNullableValueRef<LHS_TYPE>& lhs,
                     const ConstNullableValueRef<RHS_TYPE>& rhs)
{
    if (!lhs.has_value()) {
        return false;                                                 // RETURN
    }

    return rhs.has_value() ? lhs.value() > rhs.value() : true;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator>(const ConstNullableValueRef<LHS_TYPE>& lhs,
                     const RHS_TYPE&                        rhs)
{
    return lhs.has_value() ? lhs.value() > rhs : false;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator>(const LHS_TYPE&                        lhs,
                     const ConstNullableValueRef<RHS_TYPE>& rhs)
{
    return rhs.has_value() ? lhs > rhs.value() : true;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator>=(const ConstNullableValueRef<LHS_TYPE>& lhs,
                      const ConstNullableValueRef<RHS_TYPE>& rhs)
{
    if (!rhs.has_value()) {
        return true;                                                  // RETURN
    }

    return lhs.has_value() ? lhs.value() >= rhs.value() : false;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator>=(const ConstNullableValueRef<LHS_TYPE>& lhs,
                      const RHS_TYPE&                        rhs)
{
    return lhs.has_value() ? lhs.value() >= rhs : false;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator>=(const LHS_TYPE&                        lhs,
                      const ConstNullableValueRef<RHS_TYPE>& rhs)
{
    return rhs.has_value() ? lhs >= rhs.value() : true;
}

                  //--------------------------------
                  // Comparisons with bsl::nullopt_t
                  //--------------------------------

template <class TYPE>
inline
bool bdlb::operator==(const ConstNullableValueRef<TYPE>& lhs,
                      const bsl::nullopt_t&) BSLS_KEYWORD_NOEXCEPT
{
    return !lhs.has_value();
}

template <class TYPE>
inline
bool bdlb::operator==(
              const bsl::nullopt_t&,
              const ConstNullableValueRef<TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT
{
    return !rhs.has_value();
}

template <class TYPE>
inline bool bdlb::operator!=(const ConstNullableValueRef<TYPE>& lhs,
                             const bsl::nullopt_t& ) BSLS_KEYWORD_NOEXCEPT
{
    return lhs.has_value();
}

template <class TYPE>
inline
bool bdlb::operator!=(
              const bsl::nullopt_t&,
              const ConstNullableValueRef<TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT
{
    return rhs.has_value();
}

template <class TYPE>
inline
bool bdlb::operator<(const ConstNullableValueRef<TYPE>&,
                     const bsl::nullopt_t&) BSLS_KEYWORD_NOEXCEPT
{
    return false;
}

template <class TYPE>
inline
bool bdlb::operator<(
              const bsl::nullopt_t&,
              const ConstNullableValueRef<TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT
{
    return rhs.has_value();
}

template <class TYPE>
inline
bool bdlb::operator>(const ConstNullableValueRef<TYPE>& lhs,
                     const bsl::nullopt_t&) BSLS_KEYWORD_NOEXCEPT
{
    return lhs.has_value();
}

template <class TYPE>
inline
bool bdlb::operator>(
              const bsl::nullopt_t&,
              const ConstNullableValueRef<TYPE>&) BSLS_KEYWORD_NOEXCEPT
{
    return false;
}

template <class TYPE>
inline
bool bdlb::operator<=(const ConstNullableValueRef<TYPE>& lhs,
                      const bsl::nullopt_t&) BSLS_KEYWORD_NOEXCEPT
{
    return !lhs.has_value();
}

template <class TYPE>
inline
bool bdlb::operator<=(
              const bsl::nullopt_t&,
              const ConstNullableValueRef<TYPE>&) BSLS_KEYWORD_NOEXCEPT
{
    return true;
}

template <class TYPE>
inline
bool bdlb::operator>=(const ConstNullableValueRef<TYPE>&,
                      const bsl::nullopt_t&) BSLS_KEYWORD_NOEXCEPT
{
    return true;
}

template <class TYPE>
inline
bool bdlb::operator>=(
              const bsl::nullopt_t&,
              const ConstNullableValueRef<TYPE>& rhs) BSLS_KEYWORD_NOEXCEPT
{
    return !rhs.has_value();
}

     //-------------------------------------------------------------------
     // Comparisons between 'ConstNullableValueRef' and 'NullableValueRef'
     //-------------------------------------------------------------------

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator==(const ConstNullableValueRef<LHS_TYPE>& lhs,
                      const NullableValueRef<RHS_TYPE>&      rhs)
{
    if (lhs.has_value()) {
        return rhs.has_value() ? lhs.value() == rhs.value() : false;  // RETURN
    }

    return !rhs.has_value();
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator==(const NullableValueRef<LHS_TYPE>&      lhs,
                      const ConstNullableValueRef<RHS_TYPE>& rhs)
{
    if (lhs.has_value()) {
        return rhs.has_value() ? lhs.value() == rhs.value() : false;  // RETURN
    }

    return !rhs.has_value();
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator!=(const ConstNullableValueRef<LHS_TYPE>& lhs,
                      const NullableValueRef<RHS_TYPE>&      rhs)
{
    if (lhs.has_value()) {
        return rhs.has_value() ? lhs.value() != rhs.value() : true;   // RETURN
    }

    return rhs.has_value();
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator!=(const NullableValueRef<LHS_TYPE>&      lhs,
                      const ConstNullableValueRef<RHS_TYPE>& rhs)
{
    if (lhs.has_value()) {
        return rhs.has_value() ? lhs.value() != rhs.value() : true;   // RETURN
    }

    return rhs.has_value();
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator<(const ConstNullableValueRef<LHS_TYPE>& lhs,
                     const NullableValueRef<RHS_TYPE>&      rhs)
{
    if (!rhs.has_value()) {
        return false;                                                 // RETURN
    }

    return lhs.has_value() ? lhs.value() < rhs.value() : true;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator<(const NullableValueRef<LHS_TYPE>&      lhs,
                     const ConstNullableValueRef<RHS_TYPE>& rhs)
{
    if (!rhs.has_value()) {
        return false;                                                 // RETURN
    }

    return lhs.has_value() ? lhs.value() < rhs.value() : true;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator<=(const ConstNullableValueRef<LHS_TYPE>& lhs,
                      const NullableValueRef<RHS_TYPE>&      rhs)
{
    if (!lhs.has_value()) {
        return true;                                                  // RETURN
    }

    return rhs.has_value() ? lhs.value() <= rhs.value() : false;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator<=(const NullableValueRef<LHS_TYPE>&      lhs,
                      const ConstNullableValueRef<RHS_TYPE>& rhs)
{
    if (!lhs.has_value()) {
        return true;                                                  // RETURN
    }

    return rhs.has_value() ? lhs.value() <= rhs.value() : false;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator>(const ConstNullableValueRef<LHS_TYPE>& lhs,
                     const NullableValueRef<RHS_TYPE>&      rhs)
{
    if (!lhs.has_value()) {
        return false;                                                 // RETURN
    }

    return rhs.has_value() ? lhs.value() > rhs.value() : true;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator>(const NullableValueRef<LHS_TYPE>&      lhs,
                     const ConstNullableValueRef<RHS_TYPE>& rhs)
{
    if (!lhs.has_value()) {
        return false;                                                 // RETURN
    }

    return rhs.has_value() ? lhs.value() > rhs.value() : true;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator>=(const ConstNullableValueRef<LHS_TYPE>& lhs,
                      const NullableValueRef<RHS_TYPE>&      rhs)
{
    if (!rhs.has_value()) {
        return true;                                                  // RETURN
    }

    return lhs.has_value() ? lhs.value() >= rhs.value() : false;
}

template <class LHS_TYPE, class RHS_TYPE>
inline
bool bdlb::operator>=(const NullableValueRef<LHS_TYPE>&      lhs,
                      const ConstNullableValueRef<RHS_TYPE>& rhs)
{
    if (!rhs.has_value()) {
        return true;                                                  // RETURN
    }

    return lhs.has_value() ? lhs.value() >= rhs.value() : false;
}

}  // close enterprise namespace

#else // if ! defined(DEFINED_BDLB_NULLABLEVALUEREF_H)
# error Not valid except when included from bdlb_nullablevalueref.h
#endif // ! defined(COMPILING_BDLB_NULLABLEVALUEREF_H)

#endif // ! defined(INCLUDED_BDLB_NULLABLEVALUEREF_CPP03)

// ----------------------------------------------------------------------------
// Copyright 2023 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 ----------------------------------
