Home | History | Annotate | Download | only in ext
      1 // Custom pointer adapter and sample storage policies
      2 
      3 // Copyright (C) 2008, 2009 Free Software Foundation, Inc.
      4 //
      5 // This file is part of the GNU ISO C++ Library.  This library is free
      6 // software; you can redistribute it and/or modify it under the
      7 // terms of the GNU General Public License as published by the
      8 // Free Software Foundation; either version 3, or (at your option)
      9 // any later version.
     10 
     11 // This library is distributed in the hope that it will be useful,
     12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 // GNU General Public License for more details.
     15 
     16 // Under Section 7 of GPL version 3, you are granted additional
     17 // permissions described in the GCC Runtime Library Exception, version
     18 // 3.1, as published by the Free Software Foundation.
     19 
     20 // You should have received a copy of the GNU General Public License and
     21 // a copy of the GCC Runtime Library Exception along with this program;
     22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     23 // <http://www.gnu.org/licenses/>.
     24 
     25 /**
     26  * @file ext/pointer.h
     27  * @author Bob Walters
     28  *
     29  * Provides reusable _Pointer_adapter for assisting in the development of
     30  * custom pointer types that can be used with the standard containers via
     31  * the allocator::pointer and allocator::const_pointer typedefs.
     32  */
     33 
     34 #ifndef _POINTER_H
     35 #define _POINTER_H 1
     36 
     37 #include <iosfwd>
     38 #include <bits/stl_iterator_base_types.h>
     39 #include <ext/cast.h>
     40 #include <ext/type_traits.h>
     41 
     42 _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx)
     43 
     44   /**
     45    * @brief A storage policy for use with _Pointer_adapter<> which yields a
     46    *        standard pointer.
     47    *
     48    *  A _Storage_policy is required to provide 4 things:
     49    *    1) A get() API for returning the stored pointer value.
     50    *    2) An set() API for storing a pointer value.
     51    *    3) An element_type typedef to define the type this points to.
     52    *    4) An operator<() to support pointer comparison.
     53    *    5) An operator==() to support pointer comparison.
     54    */
     55   template<typename _Tp>
     56     class _Std_pointer_impl
     57     {
     58     public:
     59       // the type this pointer points to.
     60       typedef _Tp element_type;
     61 
     62       // A method to fetch the pointer value as a standard T* value;
     63       inline _Tp*
     64       get() const
     65       { return _M_value; }
     66 
     67       // A method to set the pointer value, from a standard T* value;
     68       inline void
     69       set(element_type* __arg)
     70       { _M_value = __arg; }
     71 
     72       // Comparison of pointers
     73       inline bool
     74       operator<(const _Std_pointer_impl& __rarg) const
     75       { return (_M_value < __rarg._M_value); }
     76 
     77       inline bool
     78       operator==(const _Std_pointer_impl& __rarg) const
     79       { return (_M_value == __rarg._M_value); }
     80 
     81     private:
     82       element_type* _M_value;
     83     };
     84 
     85   /**
     86    * @brief A storage policy for use with _Pointer_adapter<> which stores
     87    *        the pointer's address as an offset value which is relative to
     88    *        its own address.
     89    *
     90    * This is intended for pointers
     91    * within shared memory regions which might be mapped at different
     92    * addresses by different processes.  For null pointers, a value of 1 is
     93    * used.  (0 is legitimate sometimes for nodes in circularly linked lists)
     94    * This value was chosen as the least likely to generate an incorrect null,
     95    * As there is no reason why any normal pointer would point 1 byte into
     96    * its own pointer address.
     97    */
     98   template<typename _Tp>
     99     class _Relative_pointer_impl
    100     {
    101     public:
    102       typedef _Tp element_type;
    103 
    104       _Tp*
    105       get() const
    106       {
    107         if (_M_diff == 1)
    108           return 0;
    109         else
    110           return reinterpret_cast<_Tp*>(reinterpret_cast<_UIntPtrType>(this)
    111 					+ _M_diff);
    112       }
    113 
    114       void
    115       set(_Tp* __arg)
    116       {
    117         if (!__arg)
    118           _M_diff = 1;
    119         else
    120           _M_diff = reinterpret_cast<_UIntPtrType>(__arg)
    121                     - reinterpret_cast<_UIntPtrType>(this);
    122       }
    123 
    124       // Comparison of pointers
    125       inline bool
    126       operator<(const _Relative_pointer_impl& __rarg) const
    127       { return (reinterpret_cast<_UIntPtrType>(this->get())
    128 		< reinterpret_cast<_UIntPtrType>(__rarg.get())); }
    129 
    130       inline bool
    131       operator==(const _Relative_pointer_impl& __rarg) const
    132       { return (reinterpret_cast<_UIntPtrType>(this->get())
    133 		== reinterpret_cast<_UIntPtrType>(__rarg.get())); }
    134 
    135     private:
    136       typedef __gnu_cxx::__conditional_type<
    137 	 (sizeof(unsigned long) >= sizeof(void*)),
    138 	 unsigned long, unsigned long long>::__type _UIntPtrType;
    139       _UIntPtrType _M_diff;
    140     };
    141 
    142   /**
    143    * Relative_pointer_impl needs a specialization for const T because of
    144    * the casting done during pointer arithmetic.
    145    */
    146   template<typename _Tp>
    147     class _Relative_pointer_impl<const _Tp>
    148     {
    149     public:
    150       typedef const _Tp element_type;
    151 
    152       const _Tp*
    153       get() const
    154       {
    155         if (_M_diff == 1)
    156           return 0;
    157         else
    158           return reinterpret_cast<const _Tp*>
    159 	      (reinterpret_cast<_UIntPtrType>(this) + _M_diff);
    160       }
    161 
    162       void
    163       set(const _Tp* __arg)
    164       {
    165         if (!__arg)
    166           _M_diff = 1;
    167         else
    168           _M_diff = reinterpret_cast<_UIntPtrType>(__arg)
    169                     - reinterpret_cast<_UIntPtrType>(this);
    170       }
    171 
    172       // Comparison of pointers
    173       inline bool
    174       operator<(const _Relative_pointer_impl& __rarg) const
    175       { return (reinterpret_cast<_UIntPtrType>(this->get())
    176 		< reinterpret_cast<_UIntPtrType>(__rarg.get())); }
    177 
    178       inline bool
    179       operator==(const _Relative_pointer_impl& __rarg) const
    180       { return (reinterpret_cast<_UIntPtrType>(this->get())
    181 		== reinterpret_cast<_UIntPtrType>(__rarg.get())); }
    182 
    183     private:
    184       typedef __gnu_cxx::__conditional_type
    185 	<(sizeof(unsigned long) >= sizeof(void*)),
    186 	 unsigned long, unsigned long long>::__type _UIntPtrType;
    187       _UIntPtrType _M_diff;
    188     };
    189 
    190   /**
    191    * The specialization on this type helps resolve the problem of
    192    * reference to void, and eliminates the need to specialize _Pointer_adapter
    193    * for cases of void*, const void*, and so on.
    194    */
    195   struct _Invalid_type { };
    196 
    197   template<typename _Tp>
    198     struct _Reference_type
    199     { typedef _Tp& reference; };
    200 
    201   template<>
    202     struct _Reference_type<void>
    203     { typedef _Invalid_type& reference; };
    204 
    205   template<>
    206     struct _Reference_type<const void>
    207     { typedef const _Invalid_type& reference; };
    208 
    209   template<>
    210     struct _Reference_type<volatile void>
    211     { typedef volatile _Invalid_type&  reference; };
    212 
    213   template<>
    214     struct _Reference_type<volatile const void>
    215     { typedef const volatile _Invalid_type&  reference; };
    216 
    217   /**
    218    * This structure accomodates the way in which std::iterator_traits<>
    219    * is normally specialized for const T*, so that value_type is still T.
    220    */
    221   template<typename _Tp>
    222     struct _Unqualified_type
    223     { typedef _Tp type; };
    224 
    225   template<typename _Tp>
    226     struct _Unqualified_type<const _Tp>
    227     { typedef _Tp type; };
    228 
    229   template<typename _Tp>
    230     struct _Unqualified_type<volatile _Tp>
    231     { typedef volatile _Tp type; };
    232 
    233   template<typename _Tp>
    234     struct _Unqualified_type<volatile const _Tp>
    235     { typedef volatile _Tp type; };
    236 
    237   /**
    238    * The following provides an 'alternative pointer' that works with the
    239    * containers when specified as the pointer typedef of the allocator.
    240    *
    241    * The pointer type used with the containers doesn't have to be this class,
    242    * but it must support the implicit conversions, pointer arithmetic,
    243    * comparison operators, etc. that are supported by this class, and avoid
    244    * raising compile-time ambiguities.  Because creating a working pointer can
    245    * be challenging, this pointer template was designed to wrapper an
    246    * easier storage policy type, so that it becomes reusable for creating
    247    * other pointer types.
    248    *
    249    * A key point of this class is also that it allows container writers to
    250    * 'assume' Alocator::pointer is a typedef for a normal pointer.  This class
    251    * supports most of the conventions of a true pointer, and can, for instance
    252    * handle implicit conversion to const and base class pointer types.  The
    253    * only impositions on container writers to support extended pointers are:
    254    * 1) use the Allocator::pointer typedef appropriately for pointer types.
    255    * 2) if you need pointer casting, use the __pointer_cast<> functions
    256    *    from ext/cast.h.  This allows pointer cast operations to be overloaded
    257    *    is necessary by custom pointers.
    258    *
    259    * Note:  The const qualifier works with this pointer adapter as follows:
    260    *
    261    * _Tp*             == _Pointer_adapter<_Std_pointer_impl<_Tp> >;
    262    * const _Tp*       == _Pointer_adapter<_Std_pointer_impl<const _Tp> >;
    263    * _Tp* const       == const _Pointer_adapter<_Std_pointer_impl<_Tp> >;
    264    * const _Tp* const == const _Pointer_adapter<_Std_pointer_impl<const _Tp> >;
    265    */
    266   template<typename _Storage_policy>
    267     class _Pointer_adapter : public _Storage_policy
    268     {
    269     public:
    270       typedef typename _Storage_policy::element_type element_type;
    271 
    272       // These are needed for iterator_traits
    273       typedef std::random_access_iterator_tag                iterator_category;
    274       typedef typename _Unqualified_type<element_type>::type value_type;
    275       typedef std::ptrdiff_t                                 difference_type;
    276       typedef _Pointer_adapter                               pointer;
    277       typedef typename _Reference_type<element_type>::reference  reference;
    278 
    279       // Reminder: 'const' methods mean that the method is valid when the
    280       // pointer is immutable, and has nothing to do with whether the
    281       // 'pointee' is const.
    282 
    283       // Default Constructor (Convert from element_type*)
    284       _Pointer_adapter(element_type* __arg = 0)
    285       { _Storage_policy::set(__arg); }
    286 
    287       // Copy constructor from _Pointer_adapter of same type.
    288       _Pointer_adapter(const _Pointer_adapter& __arg)
    289       { _Storage_policy::set(__arg.get()); }
    290 
    291       // Convert from _Up* if conversion to element_type* is valid.
    292       template<typename _Up>
    293         _Pointer_adapter(_Up* __arg)
    294         { _Storage_policy::set(__arg); }
    295 
    296       // Conversion from another _Pointer_adapter if _Up if static cast is
    297       // valid.
    298       template<typename _Up>
    299         _Pointer_adapter(const _Pointer_adapter<_Up>& __arg)
    300         { _Storage_policy::set(__arg.get()); }
    301 
    302       // Destructor
    303       ~_Pointer_adapter() { }
    304 
    305       // Assignment operator
    306       _Pointer_adapter&
    307       operator=(const _Pointer_adapter& __arg)
    308       {
    309         _Storage_policy::set(__arg.get());
    310         return *this;
    311       }
    312 
    313       template<typename _Up>
    314         _Pointer_adapter&
    315         operator=(const _Pointer_adapter<_Up>& __arg)
    316         {
    317           _Storage_policy::set(__arg.get());
    318           return *this;
    319         }
    320 
    321       template<typename _Up>
    322         _Pointer_adapter&
    323         operator=(_Up* __arg)
    324         {
    325           _Storage_policy::set(__arg);
    326           return *this;
    327         }
    328 
    329       // Operator*, returns element_type&
    330       inline reference
    331       operator*() const
    332       { return *(_Storage_policy::get()); }
    333 
    334       // Operator->, returns element_type*
    335       inline element_type*
    336       operator->() const
    337       { return _Storage_policy::get(); }
    338 
    339       // Operator[], returns a element_type& to the item at that loc.
    340       inline reference
    341       operator[](std::ptrdiff_t __index) const
    342       { return _Storage_policy::get()[__index]; }
    343 
    344       // To allow implicit conversion to "bool", for "if (ptr)..."
    345     private:
    346       typedef element_type*(_Pointer_adapter::*__unspecified_bool_type)() const;
    347 
    348     public:
    349       operator __unspecified_bool_type() const
    350       {
    351         return _Storage_policy::get() == 0 ? 0 :
    352                          &_Pointer_adapter::operator->;
    353       }
    354 
    355       // ! operator (for: if (!ptr)...)
    356       inline bool
    357       operator!() const
    358       { return (_Storage_policy::get() == 0); }
    359 
    360       // Pointer differences
    361       inline friend std::ptrdiff_t
    362       operator-(const _Pointer_adapter& __lhs, element_type* __rhs)
    363       { return (__lhs.get() - __rhs); }
    364 
    365       inline friend std::ptrdiff_t
    366       operator-(element_type* __lhs, const _Pointer_adapter& __rhs)
    367       { return (__lhs - __rhs.get()); }
    368 
    369       template<typename _Up>
    370         inline friend std::ptrdiff_t
    371         operator-(const _Pointer_adapter& __lhs, _Up* __rhs)
    372         { return (__lhs.get() - __rhs); }
    373 
    374       template<typename _Up>
    375         inline friend std::ptrdiff_t
    376         operator-(_Up* __lhs, const _Pointer_adapter& __rhs)
    377         { return (__lhs - __rhs.get()); }
    378 
    379       template<typename _Up>
    380         inline std::ptrdiff_t
    381         operator-(const _Pointer_adapter<_Up>& __rhs) const
    382         { return (_Storage_policy::get() - __rhs.get()); }
    383 
    384       // Pointer math
    385       // Note: There is a reason for all this overloading based on different
    386       // integer types.  In some libstdc++-v3 test cases, a templated
    387       // operator+ is declared which can match any types.  This operator
    388       // tends to "steal" the recognition of _Pointer_adapter's own operator+
    389       // unless the integer type matches perfectly.
    390 
    391 #define _CXX_POINTER_ARITH_OPERATOR_SET(INT_TYPE) \
    392       inline friend _Pointer_adapter \
    393       operator+(const _Pointer_adapter& __lhs, INT_TYPE __offset) \
    394       { return _Pointer_adapter(__lhs.get() + __offset); } \
    395 \
    396       inline friend _Pointer_adapter \
    397       operator+(INT_TYPE __offset, const _Pointer_adapter& __rhs) \
    398       { return _Pointer_adapter(__rhs.get() + __offset); } \
    399 \
    400       inline friend _Pointer_adapter \
    401       operator-(const _Pointer_adapter& __lhs, INT_TYPE __offset) \
    402       { return _Pointer_adapter(__lhs.get() - __offset); } \
    403 \
    404       inline _Pointer_adapter& \
    405       operator+=(INT_TYPE __offset) \
    406       { \
    407         _Storage_policy::set(_Storage_policy::get() + __offset); \
    408         return *this; \
    409       } \
    410 \
    411       inline _Pointer_adapter& \
    412       operator-=(INT_TYPE __offset) \
    413       { \
    414         _Storage_policy::set(_Storage_policy::get() - __offset); \
    415         return *this; \
    416       } \
    417 // END of _CXX_POINTER_ARITH_OPERATOR_SET macro
    418 
    419       // Expand into the various pointer arithmatic operators needed.
    420       _CXX_POINTER_ARITH_OPERATOR_SET(short);
    421       _CXX_POINTER_ARITH_OPERATOR_SET(unsigned short);
    422       _CXX_POINTER_ARITH_OPERATOR_SET(int);
    423       _CXX_POINTER_ARITH_OPERATOR_SET(unsigned int);
    424       _CXX_POINTER_ARITH_OPERATOR_SET(long);
    425       _CXX_POINTER_ARITH_OPERATOR_SET(unsigned long);
    426 
    427       // Mathematical Manipulators
    428       inline _Pointer_adapter&
    429       operator++()
    430       {
    431         _Storage_policy::set(_Storage_policy::get() + 1);
    432         return *this;
    433       }
    434 
    435       inline _Pointer_adapter
    436       operator++(int __unused)
    437       {
    438         _Pointer_adapter tmp(*this);
    439         _Storage_policy::set(_Storage_policy::get() + 1);
    440         return tmp;
    441       }
    442 
    443       inline _Pointer_adapter&
    444       operator--()
    445       {
    446         _Storage_policy::set(_Storage_policy::get() - 1);
    447         return *this;
    448       }
    449 
    450       inline _Pointer_adapter
    451       operator--(int)
    452       {
    453         _Pointer_adapter tmp(*this);
    454         _Storage_policy::set(_Storage_policy::get() - 1);
    455         return tmp;
    456       }
    457 
    458     }; // class _Pointer_adapter
    459 
    460 
    461 #define _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(OPERATOR,BLANK) \
    462   template<typename _Tp1, typename _Tp2> \
    463     inline bool \
    464     operator OPERATOR##BLANK (const _Pointer_adapter<_Tp1>& __lhs, _Tp2 __rhs) \
    465     { return __lhs.get() OPERATOR##BLANK __rhs; } \
    466 \
    467   template<typename _Tp1, typename _Tp2> \
    468     inline bool \
    469     operator OPERATOR##BLANK (_Tp1 __lhs, const _Pointer_adapter<_Tp2>& __rhs) \
    470     { return __lhs OPERATOR##BLANK __rhs.get(); } \
    471 \
    472   template<typename _Tp1, typename _Tp2> \
    473     inline bool \
    474     operator OPERATOR##BLANK (const _Pointer_adapter<_Tp1>& __lhs, \
    475                               const _Pointer_adapter<_Tp2>& __rhs) \
    476     { return __lhs.get() OPERATOR##BLANK __rhs.get(); } \
    477 \
    478 // End GCC_CXX_POINTER_COMPARISON_OPERATION_SET Macro
    479 
    480   // Expand into the various comparison operators needed.
    481   _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(==,);
    482   _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(!=,);
    483   _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(<,);
    484   _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(<=,);
    485   _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(>,);
    486   _GCC_CXX_POINTER_COMPARISON_OPERATION_SET(>=,);
    487 
    488   // These are here for expressions like "ptr == 0", "ptr != 0"
    489   template<typename _Tp>
    490     inline bool
    491     operator==(const _Pointer_adapter<_Tp>& __lhs, int __rhs)
    492     { return __lhs.get() == reinterpret_cast<void*>(__rhs); }
    493 
    494   template<typename _Tp>
    495     inline bool
    496     operator==(int __lhs, const _Pointer_adapter<_Tp>& __rhs)
    497     { return __rhs.get() == reinterpret_cast<void*>(__lhs); }
    498 
    499   template<typename _Tp>
    500     inline bool
    501     operator!=(const _Pointer_adapter<_Tp>& __lhs, int __rhs)
    502     { return __lhs.get() != reinterpret_cast<void*>(__rhs); }
    503 
    504   template<typename _Tp>
    505     inline bool
    506     operator!=(int __lhs, const _Pointer_adapter<_Tp>& __rhs)
    507     { return __rhs.get() != reinterpret_cast<void*>(__lhs); }
    508 
    509   /**
    510    * Comparison operators for _Pointer_adapter defer to the base class'es
    511    * comparison operators, when possible.
    512    */
    513   template<typename _Tp>
    514     inline bool
    515     operator==(const _Pointer_adapter<_Tp>& __lhs,
    516                const _Pointer_adapter<_Tp>& __rhs)
    517     { return __lhs._Tp::operator==(__rhs); }
    518 
    519   template<typename _Tp>
    520     inline bool
    521     operator<=(const _Pointer_adapter<_Tp>& __lhs,
    522                const _Pointer_adapter<_Tp>& __rhs)
    523     { return __lhs._Tp::operator<(__rhs) || __lhs._Tp::operator==(__rhs); }
    524 
    525   template<typename _Tp>
    526     inline bool
    527     operator!=(const _Pointer_adapter<_Tp>& __lhs,
    528                const _Pointer_adapter<_Tp>& __rhs)
    529     { return !(__lhs._Tp::operator==(__rhs)); }
    530 
    531   template<typename _Tp>
    532     inline bool
    533     operator>(const _Pointer_adapter<_Tp>& __lhs,
    534               const _Pointer_adapter<_Tp>& __rhs)
    535     { return !(__lhs._Tp::operator<(__rhs) || __lhs._Tp::operator==(__rhs)); }
    536 
    537   template<typename _Tp>
    538     inline bool
    539     operator>=(const _Pointer_adapter<_Tp>& __lhs,
    540                const _Pointer_adapter<_Tp>& __rhs)
    541     { return !(__lhs._Tp::operator<(__rhs)); }
    542 
    543   template<typename _CharT, typename _Traits, typename _StoreT>
    544     inline std::basic_ostream<_CharT, _Traits>&
    545     operator<<(std::basic_ostream<_CharT, _Traits>& __os,
    546                const _Pointer_adapter<_StoreT>& __p)
    547     { return (__os << __p.get()); }
    548 
    549 _GLIBCXX_END_NAMESPACE
    550 
    551 #endif // _POINTER_H
    552