// bsls_pointercastutil.h                                             -*-C++-*-
#ifndef INCLUDED_BSLS_POINTERCASTUTIL
#define INCLUDED_BSLS_POINTERCASTUTIL

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

//@PURPOSE: Provide function to cast between function and data pointers.
//
//@CLASSES:
//  bsls::PointerCastUtil: namespace for pointer-casting function
//
//@DESCRIPTION: This component, 'bsls::PointerCastUtil', provides a utility
// function to allow casting between function and data pointers without
// triggering compiler warnings.  Such casts are legal in the latest C++
// standard, but were not always so.
//
///Usage
//------
// This section illustrates intended use of this component.
//
///Example 1: Using a function pointer as a closure parameter
/// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Suppose there is an event-handling service that requires registration of a
// combination of object and closure value, and that invokes a method on the
// object, passing back the closure.
//
// First we define the service and its handler:
//..
//  struct Handler { virtual void handle(void *closure) = 0; };
//  class Service {
//      Handler *d_handler_p;
//      void    *d_closure_p;
//    public:
//      void registerHandler(Handler *handler, void *closure = 0) {
//          d_handler_p = handler;
//          d_closure_p = closure;
//      }
//      void eventOccurred() { d_handler_p->handle(d_closure_p); }
//  };
//..
// Then, we want to define a handler that will receive a function pointer as
// the closure object and invoke it.  In order to do that, we must cast it to a
// function pointer, but some compilers may not allow it.  We can use
// 'bsls::PointerCastUtil::cast' to accomplish this:
//..
//  struct MyHandler : Handler {
//      void handle(void *closure) {
//           bsls::PointerCastUtil::cast<void(*)()>(closure)();
//      }
//  };
//..
// Next, we will set up a sample service and our handler function:
//..
//  Service aService;
//  static int counter = 0;
//  void event() { ++counter; }
//..
// Finally, we will register our handler and then trigger events to verify that
// our handler is recording them correctly.  To register the function pointer
// as a closure object, we must cast it to a data pointer.  Again, we can use
// 'bsls::PointerCastUtil::cast' to accomplish this:
//..
//  MyHandler ah;
//  aService.registerHandler(&ah, bsls::PointerCastUtil::cast<void *>(event));
//  aService.eventOccurred();
//  aService.eventOccurred();
//  assert(counter == 2);
//..

#include <bsls_annotation.h>
#include <bsls_types.h>

namespace BloombergLP {
namespace bsls {

                        //=======================
                        // struct PointerCastUtil
                        //=======================

struct PointerCastUtil {
    // This 'struct' provides a namespace for a 'static' utility function that
    // allows casting between function and data pointers.

    // CLASS METHODS
    template <class TO_TYPE, class FROM_TYPE>
    static TO_TYPE cast(FROM_TYPE from);
        // Return the specified 'from' value cast to 'TO_TYPE', casting it in
        // two steps, first to an integer type the size of a pointer and then
        // to the target type.  This function is intended to be used to cast
        // between function and data pointers, as doing such a cast directly
        // was once illegal.  The behavior is undefined unless both 'FROM_TYPE'
        // and 'TO_TYPE' are not larger than the intermediate integer type.
};

}  // close package namespace

template <class TO_TYPE, class FROM_TYPE>
inline
TO_TYPE bsls::PointerCastUtil::cast(FROM_TYPE from)
{
    BSLS_ANNOTATION_UNUSED typedef char FROM_TYPE_SizeCheck[
                    sizeof(bsls::Types::IntPtr) >= sizeof(FROM_TYPE) ? 1 : -1];
    BSLS_ANNOTATION_UNUSED typedef char   TO_TYPE_SizeCheck[
                    sizeof(bsls::Types::IntPtr) >= sizeof(TO_TYPE)   ? 1 : -1];
        // Static asserts ensuring that neither 'FROM_TYPE' nor 'TO_TYPE' is
        // larger than the intermediate integer type.  Note that 'bslmf_assert'
        // cannot be used here because of package dependency rules.

    return reinterpret_cast<TO_TYPE>(
                                  reinterpret_cast<bsls::Types::IntPtr>(from));
}

}  // close enterprise namespace

#endif

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