// bslstl_function.h                                                  -*-C++-*-
#ifndef INCLUDED_BSLSTL_FUNCTION
#define INCLUDED_BSLSTL_FUNCTION

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

//@PURPOSE: Provide a polymorphic function object with a specific prototype.
//
//@CLASSES:
// bsl::function: polymorphic function object with a specific prototype.
//
//@CANONICAL_HEADER: bsl_functional.h
//
//@DESCRIPTION: This component provides a single class template,
// `bsl::function`, implementing the standard template `std::function`, a
// runtime-polymorphic wrapper that encapsulates an arbitrary callable object
// (the *target*) and allows the wrapped object to be invoked.  `bsl::function`
// extends `std::function` by adding allocator support in a manner consistent
// with standards proposal P0987 (http://wg21.link/P0987).
//
// Objects of type `bsl::function` generalize the notion of function pointers
// and are generally used to pass callbacks to a non-template function or
// class.  For example, `bsl::function<RET (ARG1, ARG2, ...)>` can be used
// similarly to `RET (*)(ARG1, ARG2, ...)` but, unlike the function pointer,
// the `bsl::function` can hold a non-function callable type such as pointer to
// member function, pointer to member data, lambda expression, or functor
// (class type having an `operator()`).  A `bsl::function` can also be "empty",
// i.e., having no target object.  In a `bool` context, a `bsl::function`
// object will evaluate to false if it is empty, and true otherwise.  The
// target type is determined at runtime using *type* *erasure* in the
// constructors and can be changed by means of assignment, but the function
// prototype (argument types and return type) is specified as a template
// parameter at compile time.
//
// An instantiation of `bsl::function` is an in-core value-semantic type whose
// salient attributes are the type and value of its target, if any.  The
// `bsl::function` owns the target object and manages its lifetime; copying or
// moving the `bsl::function` object copies or moves the target and destroying
// the `bsl::function` destroys the target.  Somewhat counter-intuitively, the
// target is always mutable within the `bsl::function`; when wrapping a class
// type, calling a `bsl::function` can modify its target object, even if the
// `bsl::function` itself is const-qualified.
//
// Although, as a value-semantic type, `bsl::function` does have an abstract
// notion of "value", there is no general equality operator comparing between
// two `bsl::function` objects.  This limitation is a consequence of the target
// type not being required to provide equality comparison operators.  The
// `operator==` overloads that *are* provided compare a `bsl::function` against
// the null pointer and do not satisfy the requirements we typically expect for
// value-semantic equality operators.
//
///Invocation
///----------
// Calling an empty `bsl::function` object will cause it to throw a
// `bsl::bad_function_call` exception.  Given a non-empty object of type
// `bsl::function<RET(ARG0, ARG1, ...)>` invoked with arguments `arg0`, `arg1`,
// ..., invocation of the target follows the definition of *INVOKE* in section
// [func.require] of the C++ standard.  These rules are summarized in the
// following table:
// ```
// +----------------------------+-----------------------+
// | Type of target object, 'f' | Invocation expression |
// +============================+=======================+
// | Functor, function, or      | f(arg0, arg1, ...)    |
// | pointer to function        |                       |
// +----------------------------+-----------------------+
// | Pointer to member function | (arg0X.*f)(arg1, ...) |
// +----------------------------+-----------------------+
// | Pointer to member data     | arg0X.*f              |
// +----------------------------+-----------------------+
// ```
// The arguments to `f` must be implicitly convertible from the corresponding
// argument types `ARG0`, `ARG1`, ... and the return value of the call
// expression must be implicitly convertible to `RET`, unless `RET` is `void`.
//
// In the case of a pointer to member function, `R (T::*f)(...)`, or pointer to
// data member `R T::*f`, `arg0X` is one of the following:
//
// * `arg0` if `ARG0` is `T` or derived from `T`
// * `arg0.get()` if `ARG0` is a specialization of `reference_wrapper`
// * `(*arg0)` if `ARG0` is a pointer type or pointer-like type (e.g., a smart
//   pointer).
//
// Note that, consistent with the C++ Standard definition of *INVOKE*, we
// consider pointer-to-member-function and pointer-to-member-data types to be
// "callable" even though, strictly speaking, they cannot be called directly
// due to the lack of an `operator()`.
//
///Allocator Usage
///---------------
// The C++11 standard specified a type erasure scheme for allocator support in
// `std::function`.  This specification was never implemented by any vendor or
// popular open-source standard library and allocator support was removed from
// the 2017 standard version of `std::function`.  A new design for
// allocator support using `std::pmr::polymorphic_allocator` instead of type
// erasure is currently part of version 3 of the Library Fundamentals Technical
// Specification (LFTS 3), after acceptance of paper P0987
// (http://wg21.link/P0987).  This component follows the P0987 specification,
// substituting `bsl::allocator` for `std::pmr::polymorphic_allocator`.
//
// `bsl::function` meets the requirements for an allocator-aware type.
// Specifically:
//
// * The type `allocator_type` is an alias for `bsl::allocator<char>`,
// * Every constructor can be invoked with an allocator argument, using the
//   `bsl::allocator_arg_t` leading-allocator argument convention.
// * `get_allocator()` returns the allocator specified at construction.
//
// There are two uses for the allocator in `bsl::function`:
//
// 1. To allocate storage for holding the target object.
// 2. To pass to the constructor of the wrapped object if the wrapped object is
//    allocator aware.
//
///Small-object Optimization
///-------------------------
// A `bsl::function` class has a buffer capable of holding a small callable
// object without allocating dynamic memory.  The buffer is guaranteed to be
// large enough to hold a pointer to function, pointer to member function,
// pointer to member data, a `bsl::reference_wrapper`, or a stateless functor.
// In practice, it is large enough to hold many stateful functors up to six
// times the size of a `void *`.  Note that, even if the target object is
// stored in the small object buffer, memory might still be allocated by the
// target object itself.
//
// There are only two circumstances under which `bsl::function` will store the
// target object in allocated memory:
//
// 1. If the object is too large to fit into the small object buffer
// 2. If the object has a move constructor that might throw an exception
//
// The second restriction allows the move constructor and swap operation on
// `bsl::function` to be `noexcept`, as required by the C++ Standard.
//
///Usage
///-----
// In this section we show intended use of this component.
//
///Example 1: Polymorphic Invocation
///- - - - - - - - - - - - - - - - -
// In this example, we create a single `bsl::function` object, then assign it
// to callable objects of different types at run time.
//
// First, we define a simple function that returns the XOR of its two integer
// arguments:
// ```
// int intXor(int a, int b) { return a ^ b; }
// ```
// Next, we create a `bsl::function` that takes two integers and returns an
// integer.  Because we have not initialized the object with a target, it
// starts out as empty and evaluates to false in a Boolean context:
// ```
// void main()
// {
//     bsl::function<int(int, int)> funcObject;
//     assert(! funcObject);
// ```
// Next, we use assignment to give it the value of (a pointer to) `intXor` and
// test that we can invoke it to get the expected result:
// ```
//     funcObject = intXor;
//     assert(funcObject);
//     assert(5 == funcObject(6, 3));
// ```
// Next, we assign an instance of `std::plus<int>` functor to `funcObject`,
// which then holds a copy of it, and again test that we get the expected
// result when we invoke `funcObject`.
// ```
//     funcObject = std::plus<int>();
//     assert(funcObject);
//     assert(9 == funcObject(6, 3));
// ```
// Then, if we are using C++11 or later, we assign it to a lambda expression
// that multiplies its arguments:
// ```
//   #if BSLS_COMPILERFEATURES_CPLUSPLUS >= 201103L
//     funcObject = [](int a, int b) { return a * b; };
//     assert(funcObject);
//     assert(18 == funcObject(6, 3));
//   #endif
// ```
// Finally, we assign `funcObject` to `nullptr`, which makes it empty again:
// ```
//     funcObject = bsl::nullptr_t();
//     assert(! funcObject);
// }
// ```
//
///Example 2: Use in a Generic Algorithm
///- - - - - - - - - - - - - - - - - - -
// Suppose we want to define an algorithm that performs a mutating operation on
// every element of an array of integers.  The inputs are pointers to the first
// and last element to transform, a pointer to the first element into which the
// to write the output, and an operation that takes an integer in and produces
// an integer return value.  Although the pointer arguments have known type
// (`int *`), the type of the transformation operation can be anything that can
// be called with an integral argument and produces an integral return value.
// We do not want to accept this operation as a template argument, however
// (perhaps because our algorithm is sufficiently complex and/or proprietary
// that we want to keep it out of header files).  We solve these disparate
// requirements by passing the operation as a `bsl::function` object, whose
// type is known at compile time but which can be set to an arbitrary
// operation at run time:
// ```
// /// Apply my special algorithm to the elements in the contiguous address
// /// range from the specified `begin` pointer up to but not including the
// /// specified `end` pointer, writing the result to the contiguous range
// /// starting at the specified `output` pointer.  The specified `op`
// /// function is applied to each element before it is fed into the
// /// algorithm.
// void myAlgorithm(const int                      *begin,
//                  const int                      *end,
//                  int                            *output,
//                  const bsl::function<int(int)>&  op);
// ```
// For the purpose of illustration, `myAlgorithm` is a simple loop that
// invokes the specified `op` on each element in the input range and writes it
// directly to the output:
// ```
// void myAlgorithm(const int                      *begin,
//                  const int                      *end,
//                  int                            *output,
//                  const bsl::function<int(int)>&  op)
// {
//     for (; begin != end; ++begin) {
//         *output++ = op(*begin);
//     }
// }
// ```
// Next, we define input and output arrays to be used throughout the rest of
// this example:
// ```
// static const std::size_t DATA_SIZE = 5;
// static const int         testInput[DATA_SIZE] = { 4, 3, -2, 9, -7 };
// static int               testOutput[DATA_SIZE];
// ```
// Next, we define a function that simply negates its argument:
// ```
// long negate(long v) { return -v; }
//     // Return the arithmetic negation of the specified 'v' integer.
// ```
// Then, we test our algorithm using our negation function:
// ```
// /// Test the use of the `negation` function with `myAlgorithm`.
// bool testNegation()
// {
//     myAlgorithm(testInput, testInput + DATA_SIZE, testOutput, negate);
//
//     for (std::size_t i = 0; i < DATA_SIZE; ++i) {
//         if (-testInput[i] != testOutput[i]) {
//             return false;                                         // RETURN
//         }
//     }
//     return true;
// }
// ```
// Note that the prototype for `negate` is not identical to the prototype used
// to instantiate the `op` argument in `myAlgorithm`.  All that is required is
// that each argument to `op` be convertible to the corresponding argument in
// the function and that the return type of the function be convertible to the
// return type of `op`.
//
// Next, we get a bit more sophisticated and define an operation that produces
// a running sum over its inputs.  A running sum requires holding on to state,
// so we define a functor class for this purpose:
// ```
// /// Keep a running total of all of the inputs provided to `operator()`.
// class RunningSum {
//
//     // DATA
//     int d_sum;
//
//   public:
//     // CREATORS
//
//     // Create a `RunningSum` with initial value set to the specified
//     // `initial` argument.
//     explicit RunningSum(int initial = 0) : d_sum(initial) { }
//
//     // MANIPULATORS
//
//     // Add the specified `v` to the running sum and return the running
//     // sum.
//     int operator()(int v)
//         { return d_sum += v; }
// };
// ```
// Then, we test `myAlgorithm` with `RunningSum`:
// ```
// /// Test the user of `RunningSum` with `myAlgorithm`.
// bool testRunningSum()
// {
//     myAlgorithm(testInput, testInput+DATA_SIZE, testOutput, RunningSum());
//
//     int sum = 0;
//     for (std::size_t i = 0; i < DATA_SIZE; ++i) {
//         sum += testInput[i];
//         if (sum != testOutput[i]) {
//             return false;                                         // RETURN
//         }
//     }
//     return true;
// }
// ```
// Note that `RunningSum::operator()` is a mutating operation and that, within
// `myAlgorithm`, `op` is const.  Even though `bsl::function` owns a copy of
// its target, logical constness does not apply, as per the standard.
//
// Finally, we run our tests and validate the results:
// ```
// void main()
// {
//     assert(testNegation());
//     assert(testRunningSum());
// }
// ```
//
///Example 3: A Parallel Work queue
///- - - - - - - - - - - - - - - -
// In this example, we'll simulate a simple library whereby worker threads take
// work items from a queue and execute them asynchronously.  This simulation is
// single-threaded, but keeps metrics on how much work each worker accomplished
// so that we can get a rough idea of how much parallelism was expressed by the
// program.
//
// We start by defining a work item type to be stored in our work queue.  This
// type is simply a `bsl::function` taking a `WorkQueue` pointer argument and
// returning `void`.
// ```
// class WorkQueue;  // Forward declaration
//
// typedef bsl::function<void(WorkQueue *)> WorkItem;
// ```
// Next, we define a work queue class.  For simplicity, we'll implement our
// queue as a fixed-sized circular buffer and (because this is a
// single-threaded simulation), ignore synchronization concerns.
// ```
// /// A FIFO queue of tasks to be executed.
// class WorkQueue {
//
//     // PRIVATE CONSTANTS
//     static const int k_MAX_ITEMS = 16;
//
//     // DATA
//     int      d_numItems;
//     int      d_head;
//     WorkItem d_items[k_MAX_ITEMS];
//
//   public:
//     // CREATORS
//
//     /// Create an empty work queue.
//     WorkQueue()
//         : d_numItems(0), d_head(0) { }
//
//     // MANIPULATORS
//
//     /// Move the work item at the head of the queue into the specified
//     /// `result` and remove it from the queue.  The behavior is
//     /// undefined if this queue is empty.
//     void dequeue(WorkItem *result)
//     {
//         assert(d_numItems > 0);
//         *result = bslmf::MovableRefUtil::move(d_items[d_head]);
//         d_head = (d_head + 1) % k_MAX_ITEMS;  // circular
//         --d_numItems;
//     }
//
//     /// Enqueue the specified `item` work item onto the tail of the
//     /// queue.  The work is moved from `item`.
//     void enqueue(bslmf::MovableRef<WorkItem> item)
//     {
//         int tail = (d_head + d_numItems++) % k_MAX_ITEMS; // circular
//         assert(d_numItems <= k_MAX_ITEMS);
//         d_items[tail] = bslmf::MovableRefUtil::move(item);
//     }
//
//     // ACCESSORS
//
//     /// Return true if there are no items in the queue; otherwise return
//     /// false.
//     bool isEmpty() const { return 0 == d_numItems; }
//
//     /// Return the number of items currently in the queue.
//     int size() const { return d_numItems; }
// };
// ```
// Next, we'll create a worker class that represents the state of a worker
// thread:
// ```
// /// A simulated worker thread.
// class Worker {
//
//     // DATA
//     bool d_isIdle;             // True if the worker is idle
//
//   public:
//     // CREATORS
//
//     /// Create an idle worker.
//     Worker()
//         : d_isIdle(true) { }
//
//     // MANIPULATORS
//
//     /// Dequeue a task from the specified `queue` and execute it
//     /// (asynchronously, in theory).  The behavior is undefined unless
//     /// this worker is idle before the call to `run`.
//     void run(WorkQueue *queue);
//
//     // ACCESSORS
//
//     /// Return whether this worker is idle.  An idle worker is one that
//     /// can except work.
//     bool isIdle() const { return d_isIdle; }
// };
// ```
// Next, we implement the `run` function, which removes a `bsl::function`
// object from the work queue and then executes it, passing the work queue as
// the sole argument:
// ```
// void Worker::run(WorkQueue *queue)
// {
//     if (queue->isEmpty()) {
//         // No work to do
//         return;                                                   // RETURN
//     }
//
//     WorkItem task;
//     queue->dequeue(&task);
//
//     d_isIdle = false;  // We're about to do work.
//     task(queue);       // Do the work.
//     d_isIdle = true;   // We're idle again.
// }
// ```
// Now, we implement a simple scheduler containing a work queue and an array of
// four workers, which are run in a round-robin fashion:
// ```
// /// Parallel work scheduler.
// class Scheduler {
//
//     // PRIVATE CONSTANTS
//     static const int k_NUM_WORKERS = 4;
//
//     // DATA
//     WorkQueue d_workQueue;
//     Worker    d_workers[k_NUM_WORKERS];
//
//   public:
//     // CREATORS
//
//     /// Create a scheduler and enqueue the specified `initialTask`.
//     explicit Scheduler(bslmf::MovableRef<WorkItem> initialTask)
//     {
//         d_workQueue.enqueue(bslmf::MovableRefUtil::move(initialTask));
//     }
//
//     // MANIPULATORS
//
//     /// Execute the tasks in the work queue (theoretically in parallel)
//     /// until the queue is empty.
//     void run();
// };
// ```
// Next, we implement the scheduler's `run` method: which does a round-robin
// scheduling of the workers, allowing each to pull work off of the queue and
// run it.  As tasks are run, they may enqueue more work.  The scheduler
// returns when there are no more tasks in the queue.
// ```
// void Scheduler::run()
// {
//     while (! d_workQueue.isEmpty()) {
//         for (int i = 0; i < k_NUM_WORKERS; ++i) {
//             if (d_workers[i].isIdle()) {
//                 d_workers[i].run(&d_workQueue);
//             }
//         }
//     }
// }
// ```
// Next, we create a job for the parallel system to execute.  A popular
// illustration of parallel execution is the quicksort algorithm, which is a
// recursive algorithm whereby the input array is partitioned into a low and
// high half and quicksort is recursively applied, in parallel, to the two
// halves.  We define a class that encapsulates an invocation of quicksort on
// an input range:
// ```
// /// A functor class to execute parallel quicksort on a contiguous range
// /// of elements of specified `TYPE` supplied at construction.
// template <class TYPE>
// class QuickSortTask {
//
//     // DATA
//     TYPE *d_begin_p;
//     TYPE *d_end_p;
//
//     // PRIVATE CLASS METHODS
//
//     /// Partition the contiguous range specified by `[begin, end)` and
//     /// return an iterator, `mid`, such that every element in the range
//     /// `[begin, mid)` is less than `*mid` and every element in the
//     /// range `[mid + 1, end)` is not less than `*mid`.  The behavior is
//     /// undefined unless `begin < end`.
//     static TYPE* partition(TYPE *begin, TYPE *end);
//
//   public:
//     // CREATORS
//
//     /// Create a task to sort the contiguous range from the item at the
//     /// specified `begin` location up to but not included the item at
//     /// the specified `end` location.
//     QuickSortTask(TYPE *begin, TYPE *end)
//         : d_begin_p(begin), d_end_p(end) { }
//
//     // MANIPULATORS
//
//     /// Preform the sort in parallel using the specified `queue` to
//     /// enqueue parallel work.
//     void operator()(WorkQueue *queue);
// };
// ```
// Next we implement the `partition` method, using a variation of the Lomuto
// partition scheme:
// ```
// template <class TYPE>
// TYPE* QuickSortTask<TYPE>::partition(TYPE *begin, TYPE *end)
// {
//     using std::swap;
//
//     swap(begin[(end - begin) / 2], end[-1]); // Put pivot at end
//     TYPE& pivot = *--end;
//     TYPE *divider = begin;
//     for (; begin != end; ++begin) {
//         if (*begin < pivot) {
//             swap(*divider, *begin);
//             ++divider;
//         }
//     }
//     swap(*divider, pivot);  // Put pivot in the middle
//     return divider;
// }
// ```
// Then we define the call operator for our task type, which performs the
// quicksort:
// ```
// template <class TYPE>
// void QuickSortTask<TYPE>::operator()(WorkQueue *queue)
// {
//     if (d_end_p - d_begin_p < 2) {
//         // Zero or one element. End recursion.
//         return;                                                   // RETURN
//     }
//
//     // Partition returns end iterator for low partition == begin iterator
//     // for high partition.
//     TYPE *mid = partition(d_begin_p, d_end_p);
//
//     // Asynchronously sort the two partitions
//     WorkItem sortLoPart(QuickSortTask(d_begin_p, mid));
//     WorkItem sortHiPart(QuickSortTask(mid + 1, d_end_p));
//     queue->enqueue(bslmf::MovableRefUtil::move(sortLoPart));
//     queue->enqueue(bslmf::MovableRefUtil::move(sortHiPart));
// }
// ```
// Finally, we use our scheduler and our `QuickSortTask` to sort an array
// initially containing the integers between 1 and 31 in random order:
// ```
// void main()
// {
//     short data[] = {
//         23, 12, 2, 28, 1, 10, 5, 13, 15, 8, 19, 14, 31, 29, 9, 11, 24, 3,
//         30, 7, 17, 27, 20, 21, 18, 4, 22, 25, 16, 6, 26
//     };
//
//     static const int DATA_SIZE = sizeof(data) / sizeof(data[0]);
//
//     WorkItem  initialTask(QuickSortTask<short>(data, data + DATA_SIZE));
//     Scheduler sched(bslmf::MovableRefUtil::move(initialTask));
//     sched.run();
//
//     // Validate results
//     for (int i = 0; i < DATA_SIZE; ++i) {
//         assert(i + 1 == data[i]);
//     }
// }
// ```

#include <bslscm_version.h>

#include <bslma_allocator.h>
#include <bslma_bslallocator.h>
#include <bslma_usesbslmaallocator.h>

#include <bslmf_allocatorargt.h>
#include <bslmf_assert.h>
#include <bslmf_forwardingtype.h>
#include <bslmf_isintegral.h>
#include <bslmf_movableref.h>
#include <bslmf_nestedtraitdeclaration.h>
#include <bslmf_usesallocatorargt.h>
#include <bslmf_util.h>    // 'forward(V)'

#include <bsls_assert.h>
#include <bsls_buildtarget.h>
#include <bsls_compilerfeatures.h>
#include <bsls_deprecatefeature.h>
#include <bsls_exceptionutil.h>
#include <bsls_keyword.h>
#include <bsls_nullptr.h>
#include <bsls_platform.h>
#include <bsls_unspecifiedbool.h>
#include <bsls_util.h>     // 'forward<T>(V)'

#ifdef BDE_BUILD_TARGET_EXC
#include <bslstl_badfunctioncall.h>
#endif
#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
#include <bslstl_pair.h>
#endif
#include <bslstl_referencewrapper.h>

// Sub-components:
#ifdef BSLSTL_FUNCTION_VARIADIC_LIMIT
#define BSLSTL_FUNCTION_INVOKERUTIL_VARIADIC_LIMIT \
    BSLSTL_FUNCTION_VARIADIC_LIMIT
#endif
#include <bslstl_function_invokerutil.h>
#include <bslstl_function_isreferencecompatible.h>
#include <bslstl_function_rep.h>
#include <bslstl_function_smallobjectoptimization.h>

#include <cstddef>
#include <cstdlib>
#include <typeinfo>
#include <utility>

#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
#include <stdlib.h>  // Import global-scope 'abs(double)'
#endif

#if BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES
// clang-format off
// Include version that can be compiled with C++03
// Generated on Mon Jan 13 08:31:39 2025
// Command line: sim_cpp11_features.pl bslstl_function.h

# define COMPILING_BSLSTL_FUNCTION_H
# include <bslstl_function_cpp03.h>
# undef COMPILING_BSLSTL_FUNCTION_H

// clang-format on
#else

// 'BSLS_ASSERT' filename fix -- See {'bsls_assertimputil'}
#ifdef BSLS_ASSERTIMPUTIL_AVOID_STRING_CONSTANTS
namespace BloombergLP {
extern const char s_bslstl_function_h[];
#undef BSLS_ASSERTIMPUTIL_FILE
#define BSLS_ASSERTIMPUTIL_FILE BloombergLP::s_bslstl_function_h
}  // close enterprise namespace
#endif

// FORWARD DECLARATIONS
namespace bsl {

/// Forward declaration.
template <class PROTOTYPE>
class function;

}  // close namespace bsl

namespace BloombergLP {

#ifndef BDE_OMIT_INTERNAL_DEPRECATED

/// Forward declaration of legacy `bdef_Function` in order to implement
/// by-reference conversion from `bsl::function<F>`.  This declaration
/// produces a by-name cyclic dependency between `bsl` and `bde` in order to
/// allow legacy code to transition to `bsl::function` from (the deprecated)
/// `bdef_Function`.  The conversion, and therefore this forward reference,
/// should not appear in the open-source version of this component.
template <class PROTOTYPE>
class bdef_Function;

#endif // BDE_OMIT_INTERNAL_DEPRECATED

namespace bslstl {

                        // =================================
                        // struct template Function_ArgTypes
                        // =================================

/// This component-private struct template provides the following nested
/// typedefs for `bsl::function` for a specified `PROTOTYPE` which must be a
/// function type:
/// ```
/// argument_type        -- Only if PROTOTYPE takes exactly one argument
/// first_argument_type  -- Only if PROTOTYPE takes exactly two arguments
/// second_argument_type -- Only if PROTOTYPE takes exactly two arguments
/// ```
/// The C++ Standard requires that `function` define these typedefs for
/// compatibility with one- and two-argument legacy (now deprecated) functor
/// adaptors.  `bsl::function` publicly inherits from an instantiation of
/// this template in order to conditionally declare the above nested types.
/// This primary (unspecialized) template provides no typedefs.
template <class PROTOTYPE>
struct Function_ArgTypes {
};

/// This component-private specialization of `Function_ArgTypes` is for
/// function prototypes that take exactly one argument and provides an
/// `argument_type` nested typedef.
template <class RET, class ARG>
struct Function_ArgTypes<RET(ARG)> {

    // PUBLIC TYPES

    /// @DEPRECATED: This typedef is deprecated in C++17, for details see
    /// https://isocpp.org/files/papers/p0005r4.html.
    BSLS_DEPRECATE_FEATURE("bsl",
                           "deprecated_cpp17_standard_library_features",
                           "do not use")
    typedef ARG argument_type;
};

/// This component-private specialization of `Function_ArgTypes` is for
/// functions that take exactly two arguments and provides
/// `first_argument_type` and `second_argument_type` nested typedefs.
template <class RET, class ARG1, class ARG2>
struct Function_ArgTypes<RET(ARG1, ARG2)> {

    // PUBLIC TYPES

    /// @DEPRECATED: This typedef is deprecated in C++17, for details see
    /// https://isocpp.org/files/papers/p0005r4.html.
    BSLS_DEPRECATE_FEATURE("bsl",
                           "deprecated_cpp17_standard_library_features",
                           "do not use")
    typedef ARG1 first_argument_type;

    BSLS_DEPRECATE_FEATURE("bsl",
                           "deprecated_cpp17_standard_library_features",
                           "do not use")
    /// @DEPRECATED: This typedef is deprecated in C++17, for details see
    /// https://isocpp.org/files/papers/p0005r4.html.
    typedef ARG2 second_argument_type;
};

                        // ================================
                        // class template Function_Variadic
                        // ================================

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=13

template <class PROTOTYPE>
class Function_Variadic;  // Primary template is never instantiated

/// This component-private class template contains the physical
/// representation and provides the variadic interfaces for `bsl::function`
/// (see class and component documentation for `bsl::function`).
/// `bsl::function` publicly inherits from an instantiation of this
/// template.  This implementation class exists to 1) minimize the amount of
/// variadic template expansion required in C++03 using the
/// `sim_cpp11_features.pl` utility and 2) work around issues with the Sun
/// CC compiler, which has trouble with argument type deduction when a
/// template argument has a partial specialization (as `Function_Variadic`
/// does).  `bsl::function` does not have a partial specialization and
/// delegates to the `Function_Variadic` base class only those parts of the
/// interface and implementation that depend on decomposing the function
/// prototype into a return type and variadic list of argument types.
template <class RET, class... ARGS>
class Function_Variadic<RET(ARGS...)> : public Function_ArgTypes<RET(ARGS...)>
{

    // PRIVATE TYPES
    typedef bslstl::Function_Rep Function_Rep;

    /// Type of invocation function.  A generic function pointer is stored
    /// in the representation and is cast to this type to invoke the
    /// specific type of target stored in this wrapper.
    typedef RET Invoker(const Function_Rep *,
                        typename bslmf::ForwardingType<ARGS>::Type...);

    // `protected` to workaround a Sun bug when instantiating `bsl::function`
    // implicitly from an `extern "C"` function pointer, e.g. in a `bind`
    // expression.
  protected:
    // DATA
    Function_Rep d_rep;   // Non-templated representation

  private:
    // NOT IMPLEMENTED
    Function_Variadic(const Function_Variadic&) BSLS_KEYWORD_DELETED;

    /// This component-private base class is not directly copyable.
    Function_Variadic&
    operator=(const Function_Variadic&) BSLS_KEYWORD_DELETED;

    // FRIENDS
    friend class bsl::function<RET(ARGS...)>;

  public:
    // PUBLIC TYPES
    typedef RET                          result_type;
    typedef Function_Rep::allocator_type allocator_type;

    // CREATORS

    /// Create an empty object.  Use the specified `allocator` (e.g., the
    /// address of a `bslma::Allocator`) to supply memory.
    Function_Variadic(const allocator_type& allocator);

    /// Destroy this object and its target object.
    //! ~Function_Variadic() = default;

    // MANIPULATORS

    /// If this object is empty, throw `bsl::bad_function_call`; otherwise
    /// invoke the target object with the specified `args...` and return the
    /// result (after conversion to `RET`).  Note that, even though it is
    /// declared `const`, this call operator can mutate the target object
    /// and is thus considered a manipulator rather than an accessor.
    RET operator()(ARGS... args) const;
};

#endif

              // =================================================
              // struct template Function_IsInvocableWithPrototype
              // =================================================

/// Forward declaration of the component-private
/// `Function_IsInvocableWithPrototype` `struct` template.  The primary
/// (unspecialized) template is not defined.  This `struct` template
/// implements a boolean metafunction that publicly inherits from
/// `bsl::true_type` if an object of the specified `FUNC` type is invocable
/// under the specified `PROTOTYPE`, and inherits from `bsl::false_type`
/// otherwise.  An object of `FUNC` type is invocable under the `PROTOTYPE`
/// if it is Lvalue-Callable with the arguments of the `PROTOTYPE`, and
/// returns an object of type convertible to the return type of the
/// `PROTOTYPE`.  If the return type of the `PROTOTYPE` is `void`, then any
/// type is considered convertible to the return type of the `PROTOTYPE`.
/// In C++03, `FUNC` is considered Lvalue-Callable with the argument and
/// return types of the `PROTOTYPE` if it is not an integral type.  This
/// `struct` template requires `PROTOTYPE` to be an unqualified function
/// type.
template <class PROTOTYPE, class FUNC>
struct Function_IsInvocableWithPrototype;

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

namespace bsl {

                    // =======================
                    // class template function
                    // =======================

/// This class template implements the C++ Standard Library `std::function`
/// template, enhanced for allocator support as per Standards Proposal
/// P0987.  An instantiation of this template generalizes the notion of a
/// pointer to a function having the specified `PROTOTYPE` expressed as a
/// function type (e.g., `int(const char *, float)`).  An object of this
/// class wraps a copy of the callable object specified at construction (if
/// any), such as a function pointer, member-function pointer, member-data
/// pointer, or functor object.  The wrapped object (called the *target* or
/// *target* *object*) is owned by the `bsl::function` object (unlike the
/// function pointer that it mimics).  Invoking the `bsl::function` object
/// will invoke the target (or throw an exception, if there is no target).
/// Note that `function` will compile only if `PROTOTYPE` is a function
/// type.
///
/// To optimize away many heap allocations, objects of this type have a
/// buffer into which small callable objects can be stored.  In order to
/// qualify for this small-object optimization, a callable type must not
/// only fit in the buffer but must also be nothrow move constructible.  The
/// latter constraint allows this type to be nothrow move constructible and
/// nothrow swappable, as required by the C++ Standard.  The small object
/// buffer is guaranteed to be large enough to hold a pointer to function,
/// pointer to member function, pointer to member data, a
/// `bsl::reference_wrapper`, or an empty struct.  Although the standard
/// does not specify a minimum size beyond the aforementioned guarantee,
/// many small structs will fit in the small object buffer, as defined in
/// the `bslstl_function_smallobjectoptimization` component.
template <class PROTOTYPE>
class function : public BloombergLP::bslstl::Function_Variadic<PROTOTYPE> {

  private:
    // PRIVATE TYPES
    typedef BloombergLP::bslstl::Function_Variadic<PROTOTYPE> Base;
    typedef BloombergLP::bslstl::Function_Rep                 Function_Rep;
    typedef BloombergLP::bslmf::MovableRefUtil                MovableRefUtil;

    /// Abbreviation for metafunction that determines whether a reference
    /// from `FROM` can be cast to a reference to `TO` without loss of
    /// information.
    template <class FROM, class TO>
    struct IsReferenceCompatible
    : BloombergLP::bslstl::Function_IsReferenceCompatible<FROM, TO>::type {
    };

    /// Abbreviation for metafunction used to provide a C++03-compatible
    /// implementation of `std::decay` that treats `bslmf::MovableReference`
    /// as an rvalue reference.
    template <class TYPE>
    struct Decay : MovableRefUtil::Decay<TYPE> {
    };

    /// Abbreviation for a metafunction used to determine whether an object
    /// of the specified `FUNC` is callable with argument types of the
    /// specified `PROTOTYPE` and returns a type convertible to the return
    /// type of the `PROTOTYPE`.
    template <class FUNC>
    struct IsInvocableWithPrototype
    : BloombergLP::bslstl::Function_IsInvocableWithPrototype<PROTOTYPE, FUNC> {
    };

#ifndef BSLS_COMPILERFEATURES_SUPPORT_OPERATOR_EXPLICIT
    /// Unique type that evaluates to true or false in a boolean control
    /// construct such as an `if` or `while` statement.  In C++03,
    /// `function` is implicitly convertible to this type but is not
    /// implicitly convertible to `bool`.  In C++11 and later, `function` is
    /// explicitly convertible to `bool`, so this type is not needed.
    typedef BloombergLP::bsls::UnspecifiedBool<function> UnspecifiedBoolUtil;
    typedef typename UnspecifiedBoolUtil::BoolType       UnspecifiedBool;

    // NOT IMPLEMENTED

    /// Since `function` does not support `operator==` and `operator!=`,
    /// they must be deliberately suppressed; otherwise `function` objects
    /// would be implicitly comparable by implicit conversion to
    /// `UnspecifiedBool`.
    bool operator==(const function&) const;  // Declared but not defined
    bool operator!=(const function&) const;  // Declared but not defined
#endif // !defined(BSLS_COMPILERFEATURES_SUPPORT_OPERATOR_EXPLICIT)

    // PRIVATE MANIPULATORS

    /// Set the target of this `function` by constructing from the specified
    /// `func` callable object.  If the type of `func` is a movable
    /// reference, then the target is constructed by extended move
    /// construction; otherwise by extended copy construction.
    /// Instantiation will fail unless `FUNC` is a callable type that is
    /// invocable with arguments in `PROTOTYPE` and yields a return type
    /// that is convertible to the return type in `PROTOTYPE`.
    template <class FUNC>
    void installFunc(BSLS_COMPILERFEATURES_FORWARD_REF(FUNC) func);

  public:
    // TRAITS
    BSLMF_NESTED_TRAIT_DECLARATION(function,
                                   BloombergLP::bslma::UsesBslmaAllocator);
    BSLMF_NESTED_TRAIT_DECLARATION(function,
                                   BloombergLP::bslmf::UsesAllocatorArgT);
    BSLMF_NESTED_TRAIT_DECLARATION(function,
                                   bsl::is_nothrow_move_constructible);

    // TYPES
    typedef Function_Rep::allocator_type allocator_type;

    // CREATORS
    function() BSLS_KEYWORD_NOEXCEPT;
    function(nullptr_t) BSLS_KEYWORD_NOEXCEPT;                      // IMPLICIT
    function(allocator_arg_t       ,
             const allocator_type& allocator) BSLS_KEYWORD_NOEXCEPT;

    /// Create an empty `function` object.  Optionally specify an
    /// `allocator` (e.g., the address of a `bslma::Allocator` object) to
    /// supply memory; otherwise, the default allocator is used.
    function(allocator_arg_t       ,
             const allocator_type& allocator,
             nullptr_t             ) BSLS_KEYWORD_NOEXCEPT;

    /// Create an object wrapping the specified `func` callable object.  Use
    /// the default allocator to supply memory.  If `func` is a null pointer
    /// or null pointer-to-member, then the resulting object will be empty.
    /// This constructor will not participate in overload resolution if
    /// `func` is of the same type as (or reference compatible with) this
    /// object (to avoid ambiguity with the copy and move constructors) or
    /// is an integral type (to avoid matching null pointer literals).  In
    /// C++03, this function will not participate in overload resolution if
    /// `FUNC` is a `MovableRef` (see overload, below), and instantiation
    /// will fail unless `FUNC` is invocable using the arguments and return
    /// type specified in `PROTOTYPE`.  In C++11 and later, this function
    /// will not participate in overload resolution if `FUNC` is not
    /// invocable using the arguments and return type specified in
    /// `PROTOTYPE`.  Note that this constructor implicitly converts from
    /// any type that is so invocable.
    template <class FUNC>
    function(BSLS_COMPILERFEATURES_FORWARD_REF(FUNC) func,          // IMPLICIT
             typename enable_if<
                    ! IsReferenceCompatible<typename Decay<FUNC>::type,
                                            function>::value
                 &&   IsInvocableWithPrototype<
                                             typename Decay<FUNC>::type>::value
#ifndef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
                 && ! MovableRefUtil::IsMovableReference<FUNC>::value
#endif
#ifdef BSLS_PLATFORM_CMP_IBM
                 && ! is_function<FUNC>::value
#endif
                 , int>::type = 0)
        : Base(allocator_type())
    {
        ///Implementation Note
        ///- - - - - - - - - -
        // The body of this constructor must be inlined inplace because the use
        // of `enable_if` will otherwise break the MSVC 2010 compiler.
        //
        // The `! bsl::is_function<FUNC>::value` constraint is required in
        // C++03 mode when using the IBM XL C++ compiler.  In C++03,
        // `BSLS_COMPILERFEATURES_FORWARD_REF(FUNC) func` expands to
        // `const FUNC& func`.  A conforming compiler deduces a
        // reference-to-function type for `func` when it binds to a function
        // argument.  The IBM XL C++ compiler erroneously does not collapse the
        // `const` qualifier when `FUNC` is deduced to be a function type, and
        // instead attempts to deduce the type of `func` to be a reference to a
        // `const`-qualified function.  This causes substitution to fail
        // because function-typed expressions are never `const`.  This
        // component solves the problem by accepting a `func` having a function
        // type as a pointer to a (non-`const`) function.  An overload for the
        // corresponding constructor is defined below.

        installFunc(BSLS_COMPILERFEATURES_FORWARD(FUNC, func));
    }

#ifdef BSLS_PLATFORM_CMP_IBM
    template <class FUNC>
    function(FUNC                                            *func, // IMPLICIT
             typename enable_if<is_function<FUNC>::value, int>::type = 0)

        : Base(allocator_type())
    {
        ///Implementation Note
        ///- - - - - - - - - -
        // This constructor overload only exists to work around an IBM XL C++
        // compiler defect.  See the implementation notes for the above
        // constructor overload for more information.
        //
        // This constructor also forwards the `func` as a pointer-to-function
        // type to downstream operations in order to work around the
        // aforementioned reference-to-function type deduction defects.
        //
        // Further, note that instantiation of this constructor will fail
        // unless `FUNC` is invocable using the arguments and return type
        // specified in `PROTOTYPE`.  This component assumes that the IBM XL
        // C++ compiler does not support C++11 or later.

        installFunc(func);
    }
#endif

#ifndef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES
    /// Create an object wrapping the specified `func` callable object.
    /// This constructor (ctor 2) is identical to the previous constructor
    /// (ctor 1) except that, in C++03 ctor 2 provides for explicit
    /// construction from a `MovableRef` referencing a callable type, rather
    /// than an implicit conversion for `FUNC` not being a `MovableRef`.  In
    /// C++11, overload resolution matching an argument of type `T&&` to a
    /// parameter of type `T` (exact match) is always preferred over
    /// matching `T&&` to `bsl::function` (conversion).  In C++03, however
    /// `MovableRef` is not a real reference type, so it sometimes creates
    /// overload ambiguities whereby matching `MovableRef<T>` to `T`
    /// (conversion) is no better than matching `MovableRef<T>` to
    /// `bsl::function` (also conversion).  This ambiguity is resolved by
    /// making this constructor from `MovableRef<T>` explicit, while leaving
    /// other constructor from `FUNC` implicit.  This means that
    /// `move` will fail in a narrow set of cases in C++03, as shown below:
    /// ```
    ///  typedef bsl::function<void(int)> Obj;
    ///  MyCallableType x;
    ///
    ///  Obj f1 = x;                              // OK
    ///  Obj f2 = bslmf::MovableRefUtil::move(x); // No conversion in C++03
    ///  Obj f3(bslmf::MovableRefUtil::move(x));  // OK, normal ctor call
    ///
    ///  void y(const Obj& f);
    ///  y(x);                                    // OK
    ///  y(bslmf::MovableRefUtil::move(x));       // Not found in C++03
    ///  y(Obj(bslmf::MovableRefUtil::move(x)));  // OK, explicit cast
    /// ```
    /// As you can see from the examples above, there are simple workarounds
    /// for the problem cases, although generic code might need to be extra
    /// careful.
    template <class FUNC>
    explicit function(const BloombergLP::bslmf::MovableRef<FUNC>& func,
             typename enable_if<
                    ! IsReferenceCompatible<typename Decay<FUNC>::type,
                                            function>::value
                 &&   IsInvocableWithPrototype<
                                             typename Decay<FUNC>::type>::value
                 , int>::type = 0)
        : Base(allocator_type())
    {
        ///Implementation Note
        ///- - - - - - - - - -
        // The body of this constructor must inlined inplace because the use of
        // `enable_if` will otherwise break the MSVC 2010 compiler.

        installFunc(BloombergLP::bslmf::MovableRefUtil::move(func));
    }
#endif

    /// Create an object wrapping the specified `func` callable object.  Use
    /// the specified `allocator` (i.e., the address of a `bslma::Allocator`
    /// object) to supply memory.  If `func` is a null pointer or null
    /// pointer-to-member, then the resulting object will be empty.  This
    /// constructor will not participate in overload resolution if `func` is
    /// of the same type as (or reference compatible with) this object (to
    /// avoid ambiguity with the extended copy and move constructors) or is
    /// an integral type (to avoid matching null pointer literals).  In
    /// C++03, this function will not participate in overload resolution if
    /// `FUNC` is a `MovableRef` (see overload, below), and instantiation
    /// will fail unless `FUNC` is invocable using the arguments and return
    /// type specified in `PROTOTYPE`.  In C++11 and later, this function
    /// will not participate in overload resolution if `FUNC` is not
    /// invocable using the arguments and return type specified in
    /// `PROTOTYPE`.  Note that this constructor implicitly converts from
    /// any type that is so invocable.
    template <class FUNC>
    function(allocator_arg_t,
             const allocator_type&                   allocator,
             BSLS_COMPILERFEATURES_FORWARD_REF(FUNC) func,
             typename enable_if<
                    ! IsReferenceCompatible<typename Decay<FUNC>::type,
                                            function>::value
                 &&   IsInvocableWithPrototype<
                                             typename Decay<FUNC>::type>::value
#ifdef BSLS_PLATFORM_CMP_IBM
                 && ! is_function<FUNC>::value
#endif
                 , int>::type = 0)
        : Base(allocator)
    {
        ///Implementation Note
        ///- - - - - - - - - -
        // The body of this constructor must inlined inplace because the use of
        // `enable_if` will otherwise break the MSVC 2010 compiler.
        //
        // The `! bsl::is_function<FUNC>::value` constraint is required in
        // C++03 mode when using the IBM XL C++ compiler.  In C++03,
        // `BSLS_COMPILERFEATURES_FORWARD_REF(FUNC) func` expands to
        // `const FUNC& func`.  A conforming compiler deduces a
        // reference-to-function type for `func` when it binds to a function
        // argument.  The IBM XL C++ compiler erroneously does not collapse the
        // `const` qualifier when `FUNC` is deduced to be a function type, and
        // instead attempts to deduce the type of `func` to be a reference to a
        // `const`-qualified function.  This causes substitution to fail
        // because function-typed expressions are never `const`.  This
        // component solves the problem by accepting a `func` having a function
        // type as a pointer to a (non-`const`) function.  An overload for the
        // corresponding constructor is defined below.

        installFunc(BSLS_COMPILERFEATURES_FORWARD(FUNC, func));
    }

#ifdef BSLS_PLATFORM_CMP_IBM
    template <class FUNC>
    function(allocator_arg_t,
             const allocator_type&                                   allocator,
             FUNC                                                   *func,
             typename enable_if<is_function<FUNC>::value, int>::type = 0)
        : Base(allocator)
    {
        ///Implementation Note
        ///- - - - - - - - - -
        // This constructor overload only exists to work around an IBM XL C++
        // compiler defect.  See the implementation notes for the above
        // constructor overload for more information.
        //
        // This constructor also forwards the `func` as a pointer-to-function
        // type to downstream operations in order to work around the
        // aforementioned reference-to-function type deduction defects.
        //
        // Further, note that instantiation of this constructor will fail
        // unless `FUNC` is invocable using the arguments and return type
        // specified in `PROTOTYPE`.  This component assumes that the IBM XL
        // C++ compiler does not support C++11 or later.

        installFunc(func);
    }
#endif

    /// Create a `function` having the same value as (i.e., wrapping a copy
    /// of the target held by) the specified `original` object.  Optionally
    /// specify an `allocator` (e.g., the address of a `bslma::Allocator`
    /// object) to supply memory; otherwise, the default allocator is used.
    function(const function&       original);
    function(allocator_arg_t       ,
             const allocator_type& allocator,
             const function&       original);

    /// Create a `function` having the same target as the specified
    /// `original` object.  Use `original.get_allocator()` as the allocator
    /// to supply memory.  The `original` object is set to empty after the
    /// new object is created.  If the target qualifies for the small-object
    /// optimization (see class-level documentation), then it is
    /// move-constructed into the new object; otherwise ownership of the
    /// target is transferred without using the target's move constructor.
    function(BloombergLP::bslmf::MovableRef<function> original)
                                             BSLS_KEYWORD_NOEXCEPT; // IMPLICIT

    /// Create a `function` having the same value as (i.e., wrapping a copy
    /// of the target held by) the specified `original` object.  Use the
    /// specified `allocator` (e.g., the address of a `bslma::Allocator`
    /// object) to supply memory.  If `allocator == original.allocator()`,
    /// this object is created as if by move construction; otherwise it is
    /// created as if by extended copy construction using `allocator`.
    function(allocator_arg_t                          ,
             const allocator_type&                    allocator,
             BloombergLP::bslmf::MovableRef<function> original);

    // MANIPULATORS

    /// Set the target of this object to a copy of the target (if any)
    /// held by the specified `rhs` object, destroy the target (if any)
    /// previously held by `*this`, and return `*this`.  The result is
    /// equivalent to having constructed `*this` from `rhs` using the
    /// extended copy constructor with allocator `this->get_allocator()`.
    /// If an exception is thrown, `*this` is not modified (i.e., copy
    /// assignment provides the strong exception guarantee).
    function& operator=(const function& rhs);

    /// Set the target of this object to the target (if any) held by the
    /// specified `rhs` object, destroy the target (if any) previously held
    /// by `*this`, and return `*this`.  The result is equivalent to having
    /// constructed `*this` from `rhs` using the extended move constructor
    /// with allocator `this->get_allocator()`.  If an exception is thrown,
    /// `rhs` will have a valid but unspecified value and `*this` will not
    /// be modified.  Note that an exception will never be thrown if
    /// `get_allocator() == rhs.get_allocator()`.
    function& operator=(BloombergLP::bslmf::MovableRef<function> rhs);

    /// Set the target of this object to the specified `rhs` callable
    /// object, destroy the previous target (if any), and return `*this`.
    /// The result is equivalent to having constructed `*this` from
    /// `std::forward<FUNC>(rhs)` and `this->get_allocator()`.  Note that
    /// this assignment operator will not participate in overload resolution
    /// if `func` is of the same type as this object (to avoid ambiguity
    /// with the copy and move assignment operators.)  In C++03,
    /// instantiation will fail unless `FUNC` is invocable with the
    /// arguments and return type specified in `PROTOTYPE`.  In C++11 and
    /// later, this assignment operator will not participate in overload
    /// resolution unless `FUNC` is invocable with the arguments and return
    /// type specified in `PROTOTYPE`.
    template <class FUNC>
    typename enable_if<
           ! IsReferenceCompatible<typename Decay<FUNC>::type, function>::value
        &&   IsInvocableWithPrototype<typename Decay<FUNC>::type>::value
     , function&>::type
    operator=(BSLS_COMPILERFEATURES_FORWARD_REF(FUNC) rhs)
    {
        ///Implementation Note
        ///- - - - - - - - - -
        // The body of this operator must inlined inplace because the use of
        // `enable_if` will otherwise break the MSVC 2010 compiler.

        function(allocator_arg, this->get_allocator(),
                 BSLS_COMPILERFEATURES_FORWARD(FUNC, rhs)).swap(*this);
        return *this;
    }

#ifdef BSLS_PLATFORM_CMP_IBM
    /// Set the target of this object to the specified `rhs` function
    /// pointer.  This overload exists only for the IBM compiler, which has
    /// trouble decaying functions to function pointers in
    /// pass-by-const-reference template arguments.
    template <class FUNC>
    typename enable_if<is_function<FUNC>::value, function&>::type
    operator=(FUNC *rhs)
    {
        ///Implementation Note
        ///- - - - - - - - - -
        // The body of this operator must inlined inplace.
        //
        // Further, note that instantiation of this assignment operator will
        // fail unless `FUNC` is invocable using the arguments and return type
        // specified in `PROTOTYPE`.  This component assumes that the IBM XL
        // C++ compiler does not support C++11 or later.

        function(allocator_arg, this->get_allocator(), rhs).swap(*this);
        return *this;
    }
#endif

    /// Destroy the current target (if any) of this object, then set the
    /// target to the specified `rhs` wrapper containing a reference to a
    /// callable object and return `*this`.  The result is equivalent to
    /// having constructed `*this` from `rhs` and `this->get_allocator()`.
    /// Note that this assignment is a separate overload only because it is
    /// unconditionally `noexcept`.
    template <class FUNC>
    typename enable_if<
             IsInvocableWithPrototype<typename Decay<FUNC>::type>::value
     , function &>::type
    operator=(bsl::reference_wrapper<FUNC> rhs) BSLS_KEYWORD_NOEXCEPT
    {
        /// Implementation Note
        ///- - - - - - - - - -
        // The body of this operator must inlined inplace because the use of
        // 'enable_if' will otherwise break the MSVC 2010 compiler.

        function(allocator_arg, this->get_allocator(), rhs).swap(*this);
        return *this;
    }

    /// Set this object to empty and return `*this`.
    function& operator=(nullptr_t) BSLS_KEYWORD_NOEXCEPT;

    // Inherit 'operator()' from 'Function_Variadic' base class.

    /// If this object is empty, throw `bsl::bad_function_call`; otherwise
    /// invoke the target object with the specified `args...` and return the
    /// result (after conversion to `RET`).  Note that, even though it is
    /// declared `const`, this call operator can mutate the target object
    /// and is thus considered a manipulator rather than an accessor.
    using Base::operator();

    /// Exchange the targets held by this `function` and the specified
    /// `other` `function`.  The behavior is undefined unless
    /// `get_allocator() == other.get_allocator()`.
    void swap(function& other) BSLS_KEYWORD_NOEXCEPT;

    /// If `TP` is the same type as the target object, returns a pointer
    /// granting modifiable access to the target; otherwise return a null
    /// pointer.
    template<class TP> TP* target() BSLS_KEYWORD_NOEXCEPT;

    // ACCESSORS
#ifdef BSLS_COMPILERFEATURES_SUPPORT_OPERATOR_EXPLICIT
    /// (C++11 and later) Return false if this object is empty, otherwise
    /// return true.  Note that this is an explicit conversion operator and
    /// is typically invoked implicitly in contexts such as in the condition
    /// of an `if` or `while` statement, though it can also be invoked via
    /// an explicit cast.
    explicit  // Explicit conversion available only with C++11
    operator bool() const BSLS_KEYWORD_NOEXCEPT;
#else
    /// (C++03 only) Return a null value if this object is empty, otherwise
    /// an arbitrary non-null value.  Note that this operator will be
    /// invoked implicitly in boolean contexts such as in the condition of
    /// an `if` or `while` statement, but does not constitute an implicit
    /// conversion to `bool`.
    operator UnspecifiedBool() const BSLS_KEYWORD_NOEXCEPT
    {
        // Inplace inlined to work around xlC bug when out-of-line.
        return UnspecifiedBoolUtil::makeValue(0 != this->d_rep.invoker());
    }
#endif

    /// Return (a copy of) the allocator used to supply memory for this
    /// `function`.
    allocator_type get_allocator() const BSLS_KEYWORD_NOEXCEPT;

    /// If `TP` is the same type as the target object, returns a pointer
    /// granting read-only access to the target; otherwise return a null
    /// pointer.
    template<class TP> const TP* target() const BSLS_KEYWORD_NOEXCEPT;

    /// Return `typeid(void)` if this object is empty; otherwise
    /// `typeid(FUNC)` where `FUNC` is the type of the target object.
    const std::type_info& target_type() const BSLS_KEYWORD_NOEXCEPT;

#ifndef BDE_OMIT_INTERNAL_DEPRECATED
    // LEGACY METHODS

    /// Return `*this`, converted to a mutable `bdef_Function` reference by
    /// downcasting.  The behavior is undefined unless `bdef_Function<F*>`
    /// is derived from `bsl::function<F>` and adds no new data members.
    ///
    /// @DEPRECATED: Use `bsl::function` instead of `bdef_Function`.
    operator BloombergLP::bdef_Function<PROTOTYPE *>&() BSLS_KEYWORD_NOEXCEPT;

    /// Return `*this` converted to a const `bdef_Function` reference by
    /// downcasting.  The behavior is undefined unless `bdef_Function<F*>`
    /// is derived from `bsl::function<F>` and adds no new data members.
    ///
    /// @DEPRECATED: Use `bsl::function` instead of `bdef_Function`.
    operator const BloombergLP::bdef_Function<PROTOTYPE *>&() const
                                                         BSLS_KEYWORD_NOEXCEPT;

    // LEGACY ACCESSORS

    /// Return `get_allocator().mechanism()`.  Note that this function exists
    /// for BDE compatibility and is not part of the C++ Standard Library.
    ///
    /// @DEPRECATED: Use `get_allocator()` instead.
    BloombergLP::bslma::Allocator *allocator() const BSLS_KEYWORD_NOEXCEPT;

    /// Return `true` if this `function` is empty or if it is non-empty and
    /// its target qualifies for the small-object optimization (and is thus
    /// allocated within this object's footprint); otherwise, return false.
    ///
    /// @DEPRECATED: Runtime checking of this optimization is discouraged.
    bool isInplace() const BSLS_KEYWORD_NOEXCEPT;
#endif
};

#ifdef BSLS_COMPILERFEATURES_SUPPORT_CTAD
// CLASS TEMPLATE DEDUCTION GUIDES

/// Deduce the template parameter `PROTOTYPE` from the signature of the
/// function supplied to the constructor of `function`.
template<class RET, class... ARGS>
function(RET(*)(ARGS...)) -> function<RET(ARGS...)>;

/// Deduce the template parameter `PROTOTYPE` from the signature of the
/// function supplied to the constructor of `function`.
template<class ALLOC, class RET, class... ARGS>
function(allocator_arg_t, ALLOC, RET(*)(ARGS...)) -> function<RET(ARGS...)>;


/// This struct provides a set of template `meta-functions` that extract
/// the signature of a class member function, stripping any qualifiers such
/// as `const`, `noexcept` or `&`.
struct FunctionDeductionHelper {

  public:
    // PUBLIC TYPES
    template<class FUNCTOR>
    struct StripSignature {};

    template<class RET, class FUNCTOR, class ...ARGS>
    struct StripSignature<RET (FUNCTOR::*) (ARGS...)>
        { using Sig = RET(ARGS...); };

    template<class RET, class FUNCTOR, class ...ARGS>
    struct StripSignature<RET (FUNCTOR::*) (ARGS...) const>
        { using Sig = RET(ARGS...); };

    template<class RET, class FUNCTOR, class ...ARGS>
    struct StripSignature<RET (FUNCTOR::*) (ARGS...) noexcept>
        { using Sig = RET(ARGS...); };

    template<class RET, class FUNCTOR, class ...ARGS>
    struct StripSignature<RET (FUNCTOR::*) (ARGS...) const noexcept>
        { using Sig = RET(ARGS...); };

    template<class RET, class FUNCTOR, class ...ARGS>
    struct StripSignature<RET (FUNCTOR::*) (ARGS...) &>
        { using Sig = RET(ARGS...); };

    template<class RET, class FUNCTOR, class ...ARGS>
    struct StripSignature<RET (FUNCTOR::*) (ARGS...) const &>
        { using Sig = RET(ARGS...); };

    template<class RET, class FUNCTOR, class ...ARGS>
    struct StripSignature<RET (FUNCTOR::*) (ARGS...) & noexcept>
        { using Sig = RET(ARGS...); };

    template<class RET, class FUNCTOR, class ...ARGS>
    struct StripSignature<RET (FUNCTOR::*) (ARGS...) const & noexcept>
        { using Sig = RET(ARGS...); };
};

/// Deduce the template parameter `PROTOTYPE` from the signature of the
/// `operator()` of the functor supplied to the constructor of `function`.
template <
    class FP,
    class PROTOTYPE = typename
        FunctionDeductionHelper::StripSignature<decltype(&FP::operator())>::Sig
    >
function(FP) -> function<PROTOTYPE>;

/// Deduce the template parameter `PROTOTYPE` from the signature of the
/// `operator()` of the functor supplied to the constructor of `function`.
template <
    class ALLOC,
    class FP,
    class PROTOTYPE = typename
        FunctionDeductionHelper::StripSignature<decltype(&FP::operator())>::Sig
    >
function(allocator_arg_t, ALLOC, FP) -> function<PROTOTYPE>;
#endif

// FREE FUNCTIONS
template <class PROTOTYPE>
bool operator==(const function<PROTOTYPE>&, nullptr_t) BSLS_KEYWORD_NOEXCEPT;

/// Return true if the `function` argument is empty, otherwise return false.
template <class PROTOTYPE>
bool operator==(nullptr_t, const function<PROTOTYPE>&) BSLS_KEYWORD_NOEXCEPT;

template <class PROTOTYPE>
bool operator!=(const function<PROTOTYPE>&, nullptr_t) BSLS_KEYWORD_NOEXCEPT;

/// Return false if the `function` argument is empty, otherwise return true.
template <class PROTOTYPE>
bool operator!=(nullptr_t, const function<PROTOTYPE>&) BSLS_KEYWORD_NOEXCEPT;

/// Exchange the targets held by the specified `a` and specified `b`
/// objects.  The behavior is undefined unless 'a.get_allocator() ==
/// b.get_allocator()'.
template <class PROTOTYPE>
void swap(function<PROTOTYPE>& a,function<PROTOTYPE>& b) BSLS_KEYWORD_NOEXCEPT;

}  // close namespace bsl

// ============================================================================
//                     TEMPLATE AND INLINE FUNCTION DEFINITIONS
// ============================================================================

namespace BloombergLP {

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES

                        // --------------------------------
                        // class template Function_Variadic
                        // --------------------------------

// CREATORS
template <class RET, class... ARGS>
inline
bslstl::Function_Variadic<RET(ARGS...)>::
Function_Variadic(const allocator_type& allocator)
    : d_rep(allocator)
{
}

// MANIPULATORS
template <class RET, class... ARGS>
inline
RET bslstl::Function_Variadic<RET(ARGS...)>::operator()(ARGS... args) const
{
    // BDE_VERIFY pragma: push
    // BDE_VERIFY pragma: -SAL01 // Possible strict-aliasing violation
    Invoker *invoker_p = reinterpret_cast<Invoker*>(d_rep.invoker());
    // BDE_VERIFY pragma: pop

#ifdef BDE_BUILD_TARGET_EXC
    if (! invoker_p) {
        throw bsl::bad_function_call();
    }
#else
    // Non-exception build
    BSLS_ASSERT_OPT(invoker_p);
#endif

    // It is not necessary to call 'std::forward<ARGS>' because 'args...'  is
    // not composed of forwarding references.  The arguments to 'invoker_p',
    // however, are not the same as 'args...' but compatible types produced by
    // 'bslmf::ForwardingTypes' for efficiency.
    return invoker_p(&d_rep, args...);
}

#endif

namespace bslstl {

#if !BSLS_COMPILERFEATURES_SIMULATE_CPP11_FEATURES // $var-args=13

             // -------------------------------------------------
             // struct template Function_IsInvocableWithPrototype
             // -------------------------------------------------

#ifdef BSLSTL_FUNCTION_INVOKERUTIL_SUPPORT_IS_FUNC_INVOCABLE

/// This component-private `struct` template provides a boolean metafunction
/// that derives from `bsl::true_type` if a `bsl::function` object having a
/// prototype of `RET(ARGS...)` is constructible from an object of type
/// `FUNC`, and derives from `bsl::false_type` otherwise.  This metafunction
/// is a wrapper around `bsl::invoke_result` that unwraps `FUNC` if it is a
/// specialization of `bslalg::NothrowMovableWrapper`; and, if
/// `bsl::invoke_result` provides a nested `type` typedef for `FUNC` and
/// `RET` is non-void, checks that the return type of the invoke operation
/// on `FUNC` is convertible to `RET`.
template <class RET, class FUNC, class... ARGS>
struct Function_IsInvocableWithPrototype<RET(ARGS...), FUNC>
: Function_InvokerUtil::IsFuncInvocable<RET(ARGS...), FUNC> {
};

#else // if !defined(BSLSTL_FUNCTION_INVOKERUTIL_SUPPORT_IS_FUNC_INVOCABLE)

/// This component-private `struct` template provides a partial
/// specialization of `Function_IsInvocableWithPrototype` for any `FUNC`
/// type, and for `PROTOTYPE` types that are function types.  This
/// specialization only exists in pre-C++11 (e.g. C++03) compilers.  It
/// approximates a boolean metafunction for detecting whether the specified
/// `FUNC` type is Lvalue-Callable with the prototype `RET(ARGS...)`.  This
/// approximation is extremely coarse, and only checks that the `FUNC` is
/// not an integral type.  It does this for the sole purpose of ensuring
/// that there are no overload resolution ambiguities in the constructors
/// and assignment operators of `bsl::function`, which provide overloads for
/// both integral types (to accept the literal `0` is a null pointer
/// constant), and for callable types like `FUNC`.
template <class RET, class FUNC, class... ARGS>
struct Function_IsInvocableWithPrototype<RET(ARGS...), FUNC>
: bsl::integral_constant<bool, !bsl::is_integral<FUNC>::value> {
};

#endif // !defined(BSLSTL_FUNCTION_INVOKERUTIL_SUPPORT_IS_FUNC_INVOCABLE)
#endif

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

                        // ----------------------------
                        // class template bsl::function
                        // ----------------------------

// PRIVATE MANIPULATORS
template <class PROTOTYPE>
template <class FUNC>
inline
void bsl::function<PROTOTYPE>::installFunc(
                                  BSLS_COMPILERFEATURES_FORWARD_REF(FUNC) func)
{
    typedef BloombergLP::bslstl::Function_InvokerUtil InvokerUtil;
    typedef InvokerUtil::GenericInvoker               GenericInvoker;
    typedef typename Decay<FUNC>::type                DecayedFunc;

    const DecayedFunc& decayedFunc = func;  // Force function-to-pointer decay.
    GenericInvoker *const invoker =
        InvokerUtil::invokerForFunc<PROTOTYPE>(decayedFunc);

    this->d_rep.installFunc(BSLS_COMPILERFEATURES_FORWARD(FUNC, func),
                            invoker);
}

// CREATORS
template <class PROTOTYPE>
inline bsl::function<PROTOTYPE>::function() BSLS_KEYWORD_NOEXCEPT
    : Base(allocator_type())
{
}

template <class PROTOTYPE>
inline bsl::function<PROTOTYPE>::function(nullptr_t) BSLS_KEYWORD_NOEXCEPT
    : Base(allocator_type())
{
}

template <class PROTOTYPE>
inline
bsl::function<PROTOTYPE>::function(allocator_arg_t       ,
                                   const allocator_type& allocator)
                                                          BSLS_KEYWORD_NOEXCEPT
    : Base(allocator)
{
}

template <class PROTOTYPE>
inline
bsl::function<PROTOTYPE>::function(allocator_arg_t       ,
                                   const allocator_type& allocator,
                                   nullptr_t) BSLS_KEYWORD_NOEXCEPT
    : Base(allocator)
{
}

template <class PROTOTYPE>
inline bsl::function<PROTOTYPE>::function(const function& original)
    : Base(allocator_type())
{
    this->d_rep.copyInit(original.d_rep);
}

template <class PROTOTYPE>
inline bsl::function<PROTOTYPE>::function(allocator_arg_t,
                                          const allocator_type& allocator,
                                          const function&       original)
    : Base(allocator)
{
    this->d_rep.copyInit(original.d_rep);
}

template <class PROTOTYPE>
inline
bsl::function<PROTOTYPE>::function(
       BloombergLP::bslmf::MovableRef<function> original) BSLS_KEYWORD_NOEXCEPT
    : Base(MovableRefUtil::access(original).get_allocator())
{
    this->d_rep.moveInit(&MovableRefUtil::access(original).d_rep);
}

template <class PROTOTYPE>
inline bsl::function<PROTOTYPE>::function(
                            allocator_arg_t,
                            const allocator_type&                    allocator,
                            BloombergLP::bslmf::MovableRef<function> original)
    : Base(allocator)
{
    this->d_rep.moveInit(&MovableRefUtil::access(original).d_rep);
}

// MANIPULATORS
template <class PROTOTYPE>
inline bsl::function<PROTOTYPE>&
bsl::function<PROTOTYPE>::operator=(const function& rhs)
{
    function temp(allocator_arg, this->get_allocator(), rhs);
    this->d_rep.makeEmpty();            // Won't throw
    this->d_rep.moveInit(&temp.d_rep);  // Won't throw
    return *this;
}

template <class PROTOTYPE>
inline bsl::function<PROTOTYPE>&
bsl::function<PROTOTYPE>::operator=(
                                  BloombergLP::bslmf::MovableRef<function> rhs)
{
    function temp(allocator_arg, this->get_allocator(),
                  MovableRefUtil::move(rhs));
    this->d_rep.makeEmpty();            // Won't throw
    this->d_rep.moveInit(&temp.d_rep);  // Won't throw
    return *this;
}

template <class PROTOTYPE>
inline bsl::function<PROTOTYPE>&
bsl::function<PROTOTYPE>::operator=(nullptr_t) BSLS_KEYWORD_NOEXCEPT
{
    this->d_rep.makeEmpty();
    return *this;
}

template <class PROTOTYPE>
inline
void bsl::function<PROTOTYPE>::swap(function& other) BSLS_KEYWORD_NOEXCEPT
{
    this->d_rep.swap(other.d_rep);  // Won't throw
}

template <class PROTOTYPE>
template<class TP>
inline
TP *bsl::function<PROTOTYPE>::target() BSLS_KEYWORD_NOEXCEPT
{
    return this->d_rep.template target<TP>();
}

// ACCESSORS

#ifdef BSLS_COMPILERFEATURES_SUPPORT_OPERATOR_EXPLICIT
template <class PROTOTYPE>
inline
bsl::function<PROTOTYPE>::operator bool() const BSLS_KEYWORD_NOEXCEPT
{
    // If there is an invoker, then this function is non-empty (return true);
    // otherwise it is empty (return false).
    return 0 != this->d_rep.invoker();
}
#endif // BSLS_COMPILERFEATURES_SUPPORT_OPERATOR_EXPLICIT

template <class PROTOTYPE>
inline
typename bsl::function<PROTOTYPE>::allocator_type
bsl::function<PROTOTYPE>::get_allocator() const BSLS_KEYWORD_NOEXCEPT
{
    return this->d_rep.get_allocator();
}

template <class PROTOTYPE>
template<class TP>
inline
const TP* bsl::function<PROTOTYPE>::target() const BSLS_KEYWORD_NOEXCEPT
{
    return this->d_rep.template target<TP>();
}

template <class PROTOTYPE>
const std::type_info&
bsl::function<PROTOTYPE>::target_type() const BSLS_KEYWORD_NOEXCEPT
{
    return this->d_rep.target_type();
}

#ifndef BDE_OMIT_INTERNAL_DEPRECATED
// CONVERSIONS TO LEGACY TYPE
template <class PROTOTYPE>
inline
bsl::function<PROTOTYPE>::operator BloombergLP::bdef_Function<PROTOTYPE *>&()
                                                          BSLS_KEYWORD_NOEXCEPT
{
    typedef BloombergLP::bdef_Function<PROTOTYPE *> Ret;
    return *static_cast<Ret*>(this);
}

template <class PROTOTYPE>
inline
bsl::function<PROTOTYPE>::
operator const BloombergLP::bdef_Function<PROTOTYPE *>&() const
                                                          BSLS_KEYWORD_NOEXCEPT
{
    typedef const BloombergLP::bdef_Function<PROTOTYPE *> Ret;
    return *static_cast<Ret*>(this);
}

template <class PROTOTYPE>
inline
BloombergLP::bslma::Allocator *
bsl::function<PROTOTYPE>::allocator() const BSLS_KEYWORD_NOEXCEPT
{
    return get_allocator().mechanism();
}

template <class PROTOTYPE>
inline
bool bsl::function<PROTOTYPE>::isInplace() const BSLS_KEYWORD_NOEXCEPT
{
    return this->d_rep.isInplace();
}
#endif // BDE_OMIT_INTERNAL_DEPRECATED

// FREE FUNCTIONS
template <class PROTOTYPE>
inline
bool bsl::operator==(const bsl::function<PROTOTYPE>& f,
                     bsl::nullptr_t) BSLS_KEYWORD_NOEXCEPT
{
    return !f;
}

template <class PROTOTYPE>
inline
bool bsl::operator==(bsl::nullptr_t,
                     const bsl::function<PROTOTYPE>& f) BSLS_KEYWORD_NOEXCEPT
{
    return !f;
}

template <class PROTOTYPE>
inline
bool bsl::operator!=(const bsl::function<PROTOTYPE>& f,
                     bsl::nullptr_t                   ) BSLS_KEYWORD_NOEXCEPT
{
    return !!f;
}

template <class PROTOTYPE>
inline
bool bsl::operator!=(bsl::nullptr_t,
                     const bsl::function<PROTOTYPE>& f) BSLS_KEYWORD_NOEXCEPT
{
    return !!f;
}

template <class PROTOTYPE>
inline
void bsl::swap(bsl::function<PROTOTYPE>& a,
               bsl::function<PROTOTYPE>& b) BSLS_KEYWORD_NOEXCEPT
{
    a.swap(b);
}

       // --------------------------------------------------------------
       // specialization of class template Function_InvokerUtil_Dispatch
       // --------------------------------------------------------------

namespace BloombergLP {
namespace bslstl {

/// Specialization of null checker for instantiations of `bsl::function`.
/// This specialization treats an empty `bsl::function` as a null object.
template <class PROTO>
struct Function_InvokerUtilNullCheck<bsl::function<PROTO> > {

    // CLASS METHODS

    /// Return true if the `bsl::function` specified by `f` is empty; else
    /// false.
    static bool isNull(const bsl::function<PROTO>& f)
    {
        return !f;
    }
};

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

// Undo `BSLS_ASSERT` filename fix -- See {`bsls_assertimputil`}
#ifdef BSLS_ASSERTIMPUTIL_AVOID_STRING_CONSTANTS
#undef BSLS_ASSERTIMPUTIL_FILE
#define BSLS_ASSERTIMPUTIL_FILE BSLS_ASSERTIMPUTIL_DEFAULTFILE
#endif

#endif // End C++11 code

#endif // End C++11 code

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