// bslmt_entrypointfunctoradapter.h                                   -*-C++-*-
#ifndef INCLUDED_BSLMT_ENTRYPOINTFUNCTORADAPTER
#define INCLUDED_BSLMT_ENTRYPOINTFUNCTORADAPTER

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

//@PURPOSE: Provide types and utilities to simplify thread creation.
//
//@CLASSES:
//      EntryPointFunctorAdapter: Encapsulate invokable object with allocator.
//  EntryPointFunctorAdapterUtil: Dynamic allocation of adapter objects.
//
//@DESCRIPTION: This component defines a type, 'EntryPointFunctorAdapter', that
// contains a single instance of a parameterized invokable type along with an
// allocator to manage it.  The parameterized type must provide a copy
// constructor and 'void operator()()'.
//
// This component also provides a C-linkage function
// 'bslmt_EntryPointFunctorAdapter_invoker' that operates on a pointer to
// 'EntryPointFunctorAdapter', invoking the invokable object contained within
// it and then deallocating the adapter object along with the contained
// invokable object.  Together, 'EntryPointFunctorAdapter' and
// 'bslmt_EntryPointFunctorAdapter_invoker' simplify the process of invoking a
// generic functor as a C-style callback, such as a thread entry point.
//
// Finally, this component provides 'EntryPointFunctorAdapterUtil', a namespace
// for a utility function that dynamically allocates instances of
// 'EntryPointFunctorAdapter'.
//
///Usage
///-----
// This section illustrates the intended use of this component.
//
///Example 1: Wrapping a C++ Invokable Type
/// - - - - - - - - - - - - - - - - - - - -
// Suppose we have an existing interface for invoking a C-linkage function and
// passing a void* argument to it.  This situation may arise when starting
// threads or in general when registering a C-style callback.  A simplistic
// example of such a function is:
//..
//  extern "C" {
//     typedef void *(*CallbackFunction)(void*);
//  }
//
//  void *executeWithArgument(CallbackFunction funcPtr, void *argument)
//  {
//     return funcPtr(argument);
//  }
//..
// In this example, we want to use this interface to invoke a C++-style
// functor.  Our approach will be to use
// 'bslmt_EntryPointFunctorAdapter_invoker' as the C-linkage callback function,
// and a dynamically allocated value of 'EntryPointFunctorAdapter' as the
// 'void*' argument.
//
// First, we define a C++ functor type.  This type implements the job of
// counting the number of words in a string held by value.
//..
//  class WordCountJob {
//      // DATA
//      bsl::string  d_message;
//      int         *d_result_p; // held, not owned
//
//    public:
//      // TRAITS
//      BSLMF_NESTED_TRAIT_DECLARATION(WordCountJob,
//                                     bslma::UsesBslmaAllocator);
//
//      // CREATORS
//      WordCountJob(const bslstl::StringRef&  message,
//                   int                      *result,
//                   bslma::Allocator         *basicAllocator = 0);
//          // Create a new functor that, upon execution, counts the number of
//          // words (contiguous sequences of non-space characters) in the
//          // specified 'message' and stores the count in the specified
//          // 'result' address.  Optionally specify a 'basicAllocator' used to
//          // supply memory.  If 'basicAllocator' is 0, the currently
//          // installed default allocator is used.
//
//      WordCountJob(const WordCountJob&  original,
//                   bslma::Allocator    *basicAllocator = 0);
//          // Create a new functor that performs the same calculation as the
//          // specified 'other' functor.  Optionally specify a
//          // 'basicAllocator' used to supply memory.  If 'basicAllocator' is
//          // 0, the currently installed default allocator is used.
//
//      // MANIPULATORS
//      void operator()();
//          // Count the number of words in the message and store the count in
//          // the address specified on construction.
//  };
//
//  inline
//  WordCountJob::WordCountJob(const bslstl::StringRef&  message,
//                             int                      *result,
//                             bslma::Allocator         *basicAllocator)
//  : d_message(message, basicAllocator)
//  , d_result_p(result)
//  {}
//
//  inline
//  WordCountJob::WordCountJob(const WordCountJob&  original,
//                             bslma::Allocator    *basicAllocator)
//  : d_message(original.d_message, basicAllocator)
//  , d_result_p(original.d_result_p)
//  {}
//
//  void WordCountJob::operator()()
//  {
//      bool inWord = false;
//      *d_result_p = 0;
//      for (unsigned i = 0; i < d_message.length(); ++i) {
//          if (isspace(d_message[i])) {
//              inWord = false;
//          } else if (!inWord) {
//              inWord = true;
//              ++(*d_result_p);
//          }
//      }
//  }
//..
// Next, we dynamically allocate an 'EntryPointFunctorAdapter' wrapping an
// instance of this functor:
//..
//  int result = 0;
//  WordCountJob job("The quick brown fox jumped over the lazy dog.",
//                   &result);
//
//  bslma::ManagedPtr<
//      bslmt::EntryPointFunctorAdapter<WordCountJob> > threadData;
//  bslmt::EntryPointFunctorAdapterUtil::allocateAdapter(&threadData,
//                                                       job,
//                                                       "");
//..
// Finally, we use 'bslmt_EntryPointFunctorAdapter_invoker' to invoke the job
// in the context of a C-linkage function.  Note that
// 'bslmt_EntryPointFunctorAdapter_invoker' will deallocate the adapter object
// and the contained invokable job after executing it, so we must release the
// adapter from memory management via 'ManagedPtr'.  (In general, system APIs
// that register callbacks may fail; newly allocated adapters are loaded into
// 'ManagedPtr' to aid in proper error and exception handling, outside the
// scope of this example.)
//..
//  executeWithArgument(bslmt_EntryPointFunctorAdapter_invoker,
//                      threadData.ptr());
//  threadData.release();
//  assert(9 == result);
//..

#include <bslscm_version.h>

#include <bslmt_platform.h>
#include <bslmt_threadutilimpl_pthread.h>
#include <bslmt_threadutilimpl_win32.h>

#include <bslalg_constructorproxy.h>

#include <bslma_allocator.h>
#include <bslma_default.h>
#include <bslma_managedptr.h>
#include <bslma_rawdeleterguard.h>

#include <bsl_string.h>

namespace BloombergLP {

extern "C" {

void *bslmt_EntryPointFunctorAdapter_invoker(void* argument);
    // Interpreting 'argument' as an 'EntryPointFunctorAdapter_Base*', invoke
    // 'argument->function(argument)'.  Do not use outside this component.

}

namespace bslmt {

template <class THREAD_POLICY>
struct ThreadUtilImpl;

struct EntryPointFunctorAdapterUtil;

class EntryPointFunctorAdapter_Base {
    // This component-private type provides a non-templated view of
    // 'EntryPointFunctorAdapter' for accessing the invoker function.  Do not
    // use outside this component.

  public:
    // PUBLIC TYPES
    typedef void (*InvokerFunction)(void*);
        // 'InvokerFunction' is an alias for the type of function pointer held
        // in an EntryPointFunctorAdapter_Base.  Instances of the function are
        // intended to interpret their argument as an
        // 'EntryPointFunctorAdapter<TYPE>*'.

  private:
    InvokerFunction d_function; // Function to operate on template object

  protected:
    // PROTECTED CREATORS
    explicit EntryPointFunctorAdapter_Base(InvokerFunction function);
        // Create a new object holding the specified 'function'.

  public:
    // PUBLIC ACCESSORS
    InvokerFunction function() const;
        // Return the function supplied at construction.
};

template <typename TYPE>
class EntryPointFunctorAdapter : private EntryPointFunctorAdapter_Base {
    // Hold a copy of an instance of parameterized type, along with the
    // allocator used to manage the copy.  'TYPE' shall have a copy
    // constructor, and declare the 'bslma::UsesBslmaAllocator' trait if it
    // uses 'bslma::Allocator' as an argument to its copy constructor.

    // DATA
    bslalg::ConstructorProxy<TYPE> d_functor;
    bsl::string                    d_threadName;

    // FRIENDS
    friend struct EntryPointFunctorAdapterUtil;

  private:
    // NOT IMPLEMENTED
    EntryPointFunctorAdapter(const EntryPointFunctorAdapter&);
    EntryPointFunctorAdapter& operator=(const EntryPointFunctorAdapter&);

    // PRIVATE CREATORS
    EntryPointFunctorAdapter(const TYPE&               functor,
                             const bslstl::StringRef&  threadName,
                             bslma::Allocator         *allocator);
        // Create a new managed object holding copies of the specified
        // 'functor' and 'threadName' values and using the specified
        // 'allocator' to supply memory.

    // PRIVATE CLASS METHODS
    static void invokerFunction(void *adapter);
        // Interpreting the specified 'adapter' as an
        // 'EntryPointFunctorAdapter<TYPE>*', invoke 'd_object' and then
        // deallocate 'adapter' using the allocator used by '*adapter'.

    // PRIVATE MANIPULATORS
    TYPE& functor();
        // Return a reference to the functor.

  public:
    //! ~EntryPointFunctorAdapter() = default;
        // Destroy this object and the underlying managed object.  Note that
        // this public destructor is generated by the compiler.
};

struct EntryPointFunctorAdapterUtil {

    // CLASS METHODS
    template<typename TYPE>
    static void allocateAdapter(
       bslma::ManagedPtr<EntryPointFunctorAdapter<TYPE> > *adapter,
       const TYPE&                                         invokable,
       const bslstl::StringRef&                            threadName,
       bslma::Allocator                                   *basicAllocator = 0);
        // Allocate a new 'EntryPointFunctorAdapter' holding copies of the
        // specified 'invokable' object and 'threadName', and load the result
        // into the specified 'adapter'.  Optionally specify a 'basicAllocator'
        // used to supply memory.  If 'basicAllocator' is 0, the currently
        // installed default allocator is used.
};

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

                    // -----------------------------------
                    // class EntryPointFunctorAdapter_Base
                    // -----------------------------------

// PROTECTED CREATORS
inline
EntryPointFunctorAdapter_Base::EntryPointFunctorAdapter_Base(
                                                      InvokerFunction function)
: d_function(function)
{}

// PUBLIC ACCESSORS
inline
EntryPointFunctorAdapter_Base::InvokerFunction
EntryPointFunctorAdapter_Base::function() const
{
    return d_function;
}

                      // ------------------------------
                      // class EntryPointFunctorAdapter
                      // ------------------------------

// PRIVATE CLASS METHODS
template <typename TYPE>
inline
void EntryPointFunctorAdapter<TYPE>::invokerFunction(void *adapterRaw)
{
    EntryPointFunctorAdapter<TYPE> *adapter =
                      static_cast<EntryPointFunctorAdapter<TYPE>*>(adapterRaw);

    bslma::Allocator *a = adapter->d_threadName.get_allocator().mechanism();
    bslma::RawDeleterGuard<EntryPointFunctorAdapter<TYPE>,
                           bslma::Allocator> adapterGuard(adapter, a);

    if (false == adapter->d_threadName.empty()) {
        ThreadUtilImpl<Platform::ThreadPolicy>::setThreadName(
                                                        adapter->d_threadName);
    }

    adapter->functor()();
}

// PRIVATE CREATORS
template <typename TYPE>
inline
EntryPointFunctorAdapter<TYPE>::EntryPointFunctorAdapter(
                                          const TYPE&               functor,
                                          const bslstl::StringRef&  threadName,
                                          bslma::Allocator         *allocator)
: EntryPointFunctorAdapter_Base(&invokerFunction)
, d_functor(functor, allocator)
, d_threadName(threadName, allocator)
{}

// PRIVATE MANIPULATORS
template <typename TYPE>
inline
TYPE& EntryPointFunctorAdapter<TYPE>::functor()
{
    return d_functor.object();
}

                    // ----------------------------------
                    // class EntryPointFunctorAdapterUtil
                    // ----------------------------------

template <typename TYPE>
inline
void EntryPointFunctorAdapterUtil::allocateAdapter(
          bslma::ManagedPtr<EntryPointFunctorAdapter<TYPE> > *adapter,
          const TYPE&                                         invokable,
          const bslstl::StringRef&                            threadName,
          bslma::Allocator                                   *basicAllocator)
{
    bslma::Allocator *allocator = bslma::Default::allocator(basicAllocator);
    adapter->load(new (*allocator) EntryPointFunctorAdapter<TYPE>(invokable,
                                                                  threadName,
                                                                  allocator),
                  allocator);
}

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

#endif

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