// bsls_util.h -*-C++-*- #ifndef INCLUDED_BSLS_UTIL #define INCLUDED_BSLS_UTIL #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide essential, low-level support for portable generic code. // //@CLASSES: // bsls::Util: utility class supplying essential, low-level functionality // //@MACROS: // BSLS_UTIL_ADDRESSOF(OBJ): address of 'OBJ', even if 'operator&' overloaded // //@DESCRIPTION: This component defines a utility 'struct', 'bsls::Util', that // serves as a namespace for a suite of pure functions that supply essential // low-level support for implementing portable generic facilities such as might // be found in the C++ standard library. // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: Obtain the Address of a 'class' That Defines 'operator&'. /// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // There are times, especially within low-level library functions, where it is // necessary to obtain the address of an object even if that object's class // overloads 'operator&' to return something other than the object's address. // // First, we create a special reference-like type that can refer to a single // bit within a byte (inline implementations are provided in class scope for // ease of exposition): //.. // class BitReference { // // // DATA // char *d_byte_p; // int d_bitpos; // // public: // // CREATORS // BitReference(char *byteptr = 0, int bitpos = 0) // IMPLICIT // : d_byte_p(byteptr) // , d_bitpos(bitpos) // { // } // // // ACCESSORS // operator bool() const { return (*d_byte_p >> d_bitpos) & 1; } // // char *byteptr() const { return d_byte_p; } // int bitpos() const { return d_bitpos; } // }; //.. // Then, we create a pointer-like type that can point to a single bit: //.. // class BitPointer { // // // DATA // char *d_byte_p; // int d_bitpos; // // public: // // CREATORS // BitPointer(char *byteptr = 0, int bitpos = 0) // IMPLICIT // : d_byte_p(byteptr) // , d_bitpos(bitpos) // { // } // // // ACCESSORS // BitReference operator*() const // { // return BitReference(d_byte_p, d_bitpos); // } // // // etc. // }; //.. // Next, we overload 'operator&' for 'BitReference' to return a 'BitPointer' // instead of a raw pointer, completing the setup: //.. // inline BitPointer operator&(const BitReference& ref) // { // return BitPointer(ref.byteptr(), ref.bitpos()); // } //.. // Then, we note that there are times when it might be desirable to get the // true address of a 'BitReference'. Since the above overload prevents the // obvious syntax from working, we use 'bsls::Util::addressOf' to accomplish // this task. // // Next, we create a 'BitReference' object: //.. // char c[4]; // BitReference br(c, 3); //.. // Now, we invoke 'bsls::Util::addressOf' to obtain and save the address of // 'br': //.. // BitReference *p = bsls::Util::addressOf(br); // OK // // BitReference *p = &br; // Won't compile //.. // Notice that the commented line illustrates canonical use of 'operator&' that // would not compile in this example. // // Finally, we verify that address obtained is the correct one, running some // sanity checks: //.. // assert(0 != p); // assert(c == p->byteptr()); // assert(3 == p->bitpos()); //.. #include <bsls_compilerfeatures.h> #include <bsls_keyword.h> #include <bsls_platform.h> namespace BloombergLP { namespace bsls { template <class TYPE> struct Util_Identity { // This class template provides an easy way to alias a function pointer // type when used as the return type of a function. The syntax for a // function returning a function pointer is otherwise quite obscure, and // difficult to read. As we want to return function pointers taking // parameters and returning a result specified by template parameters // below, it is not possible to define a simple typedef to the function // type outside the function template itself. typedef TYPE type; // alias of the template parameter 'TYPE'. }; #ifdef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES template <class TYPE> struct Util_RemoveReference { typedef TYPE type; }; template <class TYPE> struct Util_RemoveReference<TYPE&> { typedef TYPE type; }; template <class TYPE> struct Util_RemoveReference<TYPE&&> { typedef TYPE type; }; template <class TYPE> struct Util_AssertNotLvalue { typedef int type; }; template <class TYPE> struct Util_AssertNotLvalue<TYPE&> { static_assert(sizeof(typename Util_Identity<TYPE>::type) == 0, "Cannot forward an rvalue as an lvalue."); typedef int type; }; #endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES // =========== // struct Util // =========== struct Util { // This 'struct' provides a namespace for essential low-level functions for // implementing portable generic facilities such as the C++ standard // library. // CLASS METHODS template <class TYPE> static TYPE *addressOf(TYPE& obj); // Return the address of the specified 'obj', even if 'operator&' is // overloaded for objects of type 'BSLS_TYPE'. Behavior is undefined // unless 'BSLS_TYPE' is an object type. Note that this function // conforms to the C++11 definition for 'addressof' as specified in the // section [specialized.addressof] (20.6.12.1) of the C++11 standard, // except that function types, which are not object types, are // supported by 'std::addressof' in C++11. template <class RESULT> static typename Util_Identity<RESULT()>::type *addressOf(RESULT (&fn)()); template <class RESULT, class ARG> static typename Util_Identity<RESULT(ARG)>::type *addressOf(RESULT (&fn)(ARG)); template <class RESULT, class ARG1, class ARG2> static typename Util_Identity<RESULT(ARG1, ARG2)>::type *addressOf( RESULT (&fn)(ARG1, ARG2)); // Return the address of the specified function 'fn'. Note that this // implementation supports functions of only a limited number of // parameters, determined by the current needs of the BDE software. A // more general form that will support an arbitrary number of function // parameters will be available with C++11. #ifdef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES template <class TYPE> static BSLS_KEYWORD_CONSTEXPR TYPE&& forward(typename Util_RemoveReference<TYPE>::type& t) BSLS_KEYWORD_NOEXCEPT; template <class TYPE> static BSLS_KEYWORD_CONSTEXPR TYPE&& forward(typename Util_RemoveReference<TYPE>::type&& t) BSLS_KEYWORD_NOEXCEPT; // Return a reference to the specified 't' of non-deduced 'TYPE'. If // 'TYPE' is an lvalue-reference type, then the result will be an // lvalue-reference, and an rvalue-refernce otherwise. Note that as // 'TYPE' is not deduced, it must be explicitly specified by the caller // of this function. Also note that while this function may return an // rvalue-reference, it cannot extend the lifetime of temporaries // beyond the expression that calls this function; storing an rvalue // reference to the result will lead to undefined behavior. #endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES }; } // close package namespace // ====== // MACROS // ====== // The following macros are private to the BDE implementation and not intended // for widespread use. They support the BDE STL decision for the standard // containers to support types that overload 'operator&' only on the Microsoft // platform. This support is provided on Microsoft to enable containers // holding the 'CComPtr' type from the Microsoft Foundation Class library // (which overloads 'operator&'), but is not provided on UNIX platforms to // avoid additional template bloat in the 'big' only to support a class design // that is almost certainly an error. #ifdef BSLS_PLATFORM_CMP_MSVC # define BSLS_UTIL_ADDRESSOF(OBJ) ::BloombergLP::bsls::Util::addressOf(OBJ) # if !defined(BDE_USE_ADDRESSOF) # define BDE_USE_ADDRESSOF # endif #else # define BSLS_UTIL_ADDRESSOF(OBJ) (&(OBJ)) #endif namespace bsls { // This macro takes the address of an object by calling 'Util::addressOf' on // Windows, and simply taking the address with the '&' operator on all other // platforms. // ============================================================================ // INLINE FUNCTION DEFINITIONS // ============================================================================ // CLASS METHODS template <class TYPE> inline TYPE *Util::addressOf(TYPE& obj) { return static_cast<TYPE *>( static_cast<void *>( const_cast<char *>(&reinterpret_cast<const volatile char&>(obj)))); } template <class RESULT> inline typename Util_Identity<RESULT()>::type * Util::addressOf(RESULT (&fn)()) { return fn; } template <class RESULT, class ARG> inline typename Util_Identity<RESULT(ARG)>::type * Util::addressOf(RESULT (&fn)(ARG)) { return fn; } template <class RESULT, class ARG1, class ARG2> inline typename Util_Identity<RESULT(ARG1, ARG2)>::type * Util::addressOf(RESULT (&fn)(ARG1, ARG2)) { return fn; } #ifdef BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES template <class TYPE> BSLS_KEYWORD_CONSTEXPR TYPE&& Util::forward(typename Util_RemoveReference<TYPE>::type& t) BSLS_KEYWORD_NOEXCEPT { return static_cast<TYPE&&>(t); } template <class TYPE> BSLS_KEYWORD_CONSTEXPR TYPE&& Util::forward(typename Util_RemoveReference<TYPE>::type&& t) BSLS_KEYWORD_NOEXCEPT { static_assert(sizeof(typename Util_AssertNotLvalue<TYPE>::type) > 0, "Just to trigger instantiation of the checker template."); return static_cast<TYPE&&>(t); } #endif // BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2013 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------