// 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
                        //=======================

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

    // CLASS METHODS

    /// 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.
    template <class TO_TYPE, class FROM_TYPE>
    static TO_TYPE cast(FROM_TYPE from);
};

}  // 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];

    /// 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.
    BSLS_ANNOTATION_UNUSED typedef char   TO_TYPE_SizeCheck[
                    sizeof(bsls::Types::IntPtr) >= sizeof(TO_TYPE)   ? 1 : -1];

    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 ----------------------------------
