// bslstl_referencewrapper.h                                          -*-C++-*-
#ifndef INCLUDED_BSLSTL_REFERENCEWRAPPER
#define INCLUDED_BSLSTL_REFERENCEWRAPPER

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

//@PURPOSE: Provide copyable, assignable object wrapper for references.
//
//@CLASSES:
//  bsl::reference_wrapper: class object to hold a reference to an object
//
//@CANONICAL_HEADER: bsl_functional.h
//
//@DESCRIPTION: This component provides 'bsl::reference_wrapper', a reduced
//  implementation of the standard C++2011 template of the same name, which
//  simply wraps a reference into a copyable, assignable object to allow it to
//  be stored in a place that cannot normally hold a reference, such as a
//  standard container.  Because a reference wrapper is convertible to its
//  contained reference type, it can be passed to functions that take such a
//  reference.
//
//  This component also provides the (free) helper functions 'bsl::ref' and
//  'bsl::cref' that may be used to generate 'reference_wrapper' objects more
//  concisely than with the constructor.
//
//  NOTE: This component is a partial implementation of the standard class,
//  omitting support for use as a function object, and is in any case of
//  limited usefulness in a pure C++98 environment.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Sorted References
/// - - - - - - - - - - - - - -
// Let us suppose that we wish to handle objects that will be passed to a
// comparison function expecting references to the objects.  Let us suppose
// further that these objects are large enough that we would not wish to move
// them around bodily as they are sorted.  Note that plausible examples of uses
// for this component are limited in freestanding C++98.
//
// First, let us define the large-object type:
//..
//  struct Canary {
//      static const int s_size = 1000;
//      Canary *d_values[s_size];
//      Canary();
//  };
//
//  Canary::Canary()
//  {
//       for (int i = 0; i < s_size; ++i) {
//           d_values[i] = this;
//       }
//  }
//..
// Next, we define the comparison function:
//..
//  bool operator<(Canary const& a, Canary const& b)
//  {
//      return a.d_values[0] < b.d_values[0];
//  }
//..
// Finally, we define a generic function to sort two items:
//..
//  template <typename T>
//  void sortTwoItems(T& a, T& b)
//  {
//      if (b < a) {
//          T tmp(a);
//          a = b;
//          b = tmp;
//      }
//  }
//..
// We can call 'sortTwoItems' on wrappers representing 'Canary' objects
// without need to move actual, large 'Canary' objects about.  In the call to
// 'sortTwoItems', below, the 'operator=' used in it is that of
// 'bsl::reference_wrapper<Canary>', but the 'operator<' used is the one
// declared for 'Canary&' arguments.  All of the conversions needed are
// applied implicitly:
//..
//  Canary canaries[2];
//  bsl::reference_wrapper<Canary> canaryA = bsl::ref(canaries[1]);
//  bsl::reference_wrapper<Canary> canaryB = bsl::ref(canaries[0]);
//  sortTwoItems(canaryA, canaryB);
//
//  assert(&canaryA.get() == canaries);
//  assert(&canaryB.get() == canaries + 1);
//..

#include <bslscm_version.h>

#include <bslmf_isbitwisemoveable.h>
#include <bslmf_isreferencewrapper.h>

#include <bsls_keyword.h>
#include <bsls_libraryfeatures.h>
#include <bsls_util.h>  // for BloombergLP::bsls::Util::addressOf

#ifdef BSLS_LIBRARYFEATURES_HAS_CPP11_BASELINE_LIBRARY
#include <functional>

#define BSLSTL_REFRENCEWRAPPER_IS_ALIASED

namespace bsl {
using std::cref;
using std::ref;
using std::reference_wrapper;
}  // close enterprise namespace
#endif

#ifndef BSLSTL_REFRENCEWRAPPER_IS_ALIASED
namespace bsl {

                    // =======================
                    // class reference_wrapper
                    // =======================

template <class T>
class reference_wrapper {
    // This class is a wrapper that encapsulates an object reference, enabling
    // operations not possible on actual references, including assignment,
    // copying, and storage in standard containers.  When stored in a
    // container, it enables functions defined to operate on references to the
    // type represented to be called on the container elements.

  private:
    // DATA
    T *d_represented_p;  // the represented object (not owned)

  public:
    // TYPES
    typedef T type;

    // CREATORS
    reference_wrapper(T& object) BSLS_KEYWORD_NOEXCEPT;             // IMPLICIT
        // Create a reference wrapper representing the specified 'object'.

    //! reference_wrapper(const reference_wrapper& original) = default;
        // Create a reference wrapper referring to the same object as the
        // specified 'original'.

    //! ~reference_wrapper() = default;
        // Destroy this object.

    // MANIPULATORS
    //! reference_wrapper& operator=(const reference_wrapper& rhs) = default;
        // Assign this object to refer to the same object as the specified
        // 'rhs', and return '*this'.

    // ACCESSORS
    T& get() const BSLS_KEYWORD_NOEXCEPT;
        // Return a reference to the object that '*this' represents.

    operator T&() const BSLS_KEYWORD_NOEXCEPT;
        // Return a reference to the object that '*this' represents.
};

// FREE FUNCTIONS
template <class T>
reference_wrapper<const T> cref(const T& object) BSLS_KEYWORD_NOEXCEPT;
    // Return a reference wrapper representing a 'const' view of the specified
    // 'object'.

template <class T>
reference_wrapper<const T> cref(reference_wrapper<T> original)
                                                         BSLS_KEYWORD_NOEXCEPT;
    // Return a reference wrapper representing a 'const' view of the same
    // object as the specified 'original'.

template <class T>
reference_wrapper<T> ref(T& object) BSLS_KEYWORD_NOEXCEPT;
    // Return a reference wrapper that represents the specified 'object'.

template <class T>
reference_wrapper<T> ref(reference_wrapper<T> original) BSLS_KEYWORD_NOEXCEPT;
    // Return a reference wrapper that represents the same object as the
    // specified 'original'.

}  // close namespace bsl

// ============================================================================
//                      INLINE DEFINITIONS
// ============================================================================

                    // -----------------------
                    // class reference_wrapper
                    // -----------------------

// CREATORS
template <class T>
inline
bsl::reference_wrapper<T>::reference_wrapper(T& object) BSLS_KEYWORD_NOEXCEPT
  : d_represented_p(BloombergLP::bsls::Util::addressOf(object))
{
}

// ACCESSORS
template <class T>
inline
T& bsl::reference_wrapper<T>::get() const BSLS_KEYWORD_NOEXCEPT
{
    return *d_represented_p;
}

template <class T>
inline
bsl::reference_wrapper<T>::operator T&() const BSLS_KEYWORD_NOEXCEPT
{
    return *d_represented_p;
}

// FREE FUNCTIONS
template <class T>
inline
bsl::reference_wrapper<const T> bsl::cref(const T& object)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return reference_wrapper<const T>(object);
}

template <class T>
inline
bsl::reference_wrapper<const T> bsl::cref(bsl::reference_wrapper<T> original)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return cref(original.get());
}

template <class T>
inline
bsl::reference_wrapper<T> bsl::ref(T& object) BSLS_KEYWORD_NOEXCEPT
{
    return reference_wrapper<T>(object);
}

template <class T>
inline
bsl::reference_wrapper<T> bsl::ref(bsl::reference_wrapper<T> original)
                                                          BSLS_KEYWORD_NOEXCEPT
{
    return ref(original.get());
}

// TRAITS

namespace BloombergLP {
namespace bslmf {

template <class T>
struct IsBitwiseMoveable<bsl::reference_wrapper<T> > : bsl::true_type { };

}  // close namespace bslmf
}  // close enterprise namespace

#endif // BSLSTL_REFRENCEWRAPPER_IS_ALIASED

namespace BloombergLP {
namespace bslmf {

template <class T>
struct IsReferenceWrapper<bsl::reference_wrapper<T> > : bsl::true_type { };

}  // close namespace bslmf
}  // close enterprise namespace

#endif

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