| /************************************************************************ |
| * |
| * 23.vector.allocator.cpp: |
| * |
| * Test exercising vector specialized on a user-defined allocator |
| * with a user-defined pointer type. |
| * |
| * $Id$ |
| * |
| *************************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed |
| * with this work for additional information regarding copyright |
| * ownership. The ASF licenses this file to you 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. |
| * |
| * Copyright 2007 Rogue Wave Software, Inc. |
| * |
| **************************************************************************/ |
| |
| // disable debug iterators to prevent compilation errors |
| #include <rw/_config.h> |
| |
| #ifndef _RWSTD_NO_DEBUG_ITER |
| # define _RWSTD_NO_DEBUG_ITER |
| #endif // _RWSTD_NO_DEBUG_ITER |
| |
| #include <memory> |
| #include <vector> |
| #include <cstddef> // for ptrdiff_t, size_t |
| |
| #include <rw_driver.h> |
| |
| /**************************************************************************/ |
| |
| // DESCRIPTION: |
| // Test instantiates std::vector on a user-defined type, user-defined |
| // allocator and a user-defined pointer type, making sure that everything |
| // still compiles and runs with expected results |
| |
| // Note: 20.1.5, p2, Allocator requirements specifies that the type |
| // std::allocator<T>::pointer be a "pointer to T", which might |
| // make this test case not well-defined; it is expected that |
| // this will be changed in a future revision of the Standard |
| |
| // user-defined pointer type |
| template <class T> |
| struct Pointer |
| { |
| typedef T value_type; |
| typedef std::size_t size_type; |
| typedef std::ptrdiff_t difference_type; |
| typedef value_type* pointer; |
| typedef const value_type* const_pointer; |
| typedef value_type& reference; |
| typedef const value_type& const_reference; |
| typedef std::random_access_iterator_tag iterator_category; |
| |
| Pointer (): offset_ (0) { } |
| |
| Pointer (const Pointer &rhs) |
| : offset_ (rhs.offset_) { } |
| |
| Pointer (difference_type off, int) : offset_ (off) {} |
| |
| reference operator* () const { |
| return *_RWSTD_REINTERPRET_CAST (pointer, offset_); |
| } |
| |
| bool operator== (const Pointer &rhs) const { |
| return offset_ == rhs.offset_; |
| } |
| |
| bool operator!= (const Pointer &rhs) const { |
| return !operator== (rhs); |
| } |
| |
| bool operator< (const Pointer &rhs) const { |
| return offset_ < rhs.offset_; |
| } |
| |
| bool operator<= (const Pointer &rhs) const { |
| return !(*this > rhs); |
| } |
| |
| bool operator> (const Pointer &rhs) const { |
| return rhs < *this; |
| } |
| |
| bool operator>= (const Pointer &rhs) const { |
| return !(*this < rhs); |
| } |
| |
| Pointer& operator++ () { |
| pointer ptr = _RWSTD_REINTERPRET_CAST (pointer, offset_); |
| offset_ = _RWSTD_REINTERPRET_CAST (difference_type, ++ptr); |
| return *this; |
| } |
| |
| Pointer& operator-- () { |
| pointer ptr = _RWSTD_REINTERPRET_CAST (pointer, offset_); |
| offset_ = _RWSTD_REINTERPRET_CAST (difference_type, --ptr); |
| return *this; |
| } |
| |
| Pointer& operator+= (difference_type i) { |
| pointer ptr = _RWSTD_REINTERPRET_CAST (pointer, offset_); |
| offset_ = _RWSTD_REINTERPRET_CAST (difference_type, ptr += i); |
| return *this; |
| } |
| |
| Pointer& operator-= (difference_type i) { |
| return *this += -i; |
| } |
| |
| Pointer operator+ (difference_type i) const { |
| return Pointer (*this) += i; |
| } |
| |
| Pointer operator- (difference_type i) const { |
| return Pointer (*this) -= i; |
| } |
| |
| difference_type operator- (const Pointer &rhs) const { |
| pointer p1 = _RWSTD_REINTERPRET_CAST (pointer, offset_); |
| pointer p2 = _RWSTD_REINTERPRET_CAST (pointer, rhs.offset_); |
| return p1 - p2; |
| } |
| |
| difference_type offset_; |
| |
| private: |
| |
| // deliberately not defined to detect their use |
| void operator++ (int); |
| void operator-- (int); |
| |
| }; |
| |
| /**************************************************************************/ |
| |
| // user-defined allocator |
| template <class T> |
| class Allocator |
| { |
| public: |
| typedef T value_type; |
| typedef std::size_t size_type; |
| typedef std::ptrdiff_t difference_type; |
| typedef Pointer<T> pointer; |
| typedef const Pointer<T> const_pointer; |
| typedef T& reference; |
| typedef const T& const_reference; |
| typedef std::random_access_iterator_tag iterator_category; |
| |
| pointer address (reference r) const { |
| return pointer (_RWSTD_REINTERPRET_CAST (difference_type, &r), 1); |
| } |
| |
| const_pointer address (const_reference r) const { |
| return const_pointer (_RWSTD_REINTERPRET_CAST (difference_type, &r), |
| 1); |
| } |
| |
| Allocator () throw () {} |
| |
| template <class U> |
| Allocator (const Allocator<U>&) throw () {} |
| |
| pointer allocate (size_type n, const void* = 0) { |
| void* const ptr = operator new (n * sizeof (T)); |
| return pointer (_RWSTD_REINTERPRET_CAST (difference_type, ptr), 1); |
| } |
| |
| void deallocate (pointer ptr, size_type) { |
| operator delete (_RWSTD_REINTERPRET_CAST (void*, ptr.offset_)); |
| } |
| |
| void construct (pointer ptr, const_reference val) { |
| new (_RWSTD_REINTERPRET_CAST (void*, ptr.offset_)) value_type (val); |
| } |
| |
| void destroy (pointer ptr) { |
| _RWSTD_REINTERPRET_CAST (T*, ptr.offset_)->~value_type (); |
| } |
| |
| size_type max_size () const throw () { |
| return size_type (-1) / sizeof (T); |
| } |
| |
| template <class U> |
| struct rebind { typedef Allocator<U> other; }; |
| |
| bool operator== (const Allocator&) const { |
| return 1; |
| } |
| |
| bool operator!= (const Allocator &rhs) const { |
| return !operator== (rhs); |
| } |
| }; |
| |
| /**************************************************************************/ |
| |
| // user-defined type |
| struct MyClass |
| { |
| int i_; |
| int j_; |
| }; |
| |
| /**************************************************************************/ |
| |
| #ifndef _RWSTD_NO_EXPLICIT_INSTANTIATION |
| |
| // explicitly instantiate to better exercise the template |
| template class std::vector<MyClass, Allocator<MyClass> >; |
| |
| #endif // _RWSTD_NO_EXPLICIT_INSTANTIATION |
| |
| |
| static int |
| run_test (int, char**) |
| { |
| rw_warn (0, 0, __LINE__, "debugging iterators disabled"); |
| |
| typedef std::vector<MyClass, Allocator<MyClass> > Vector; |
| |
| const Vector::size_type nelems = 256; |
| |
| const MyClass value = { 0, 0 }; |
| |
| Vector v (nelems, value); |
| |
| rw_assert (nelems == v.size (), 0, __LINE__, |
| "vector(%zu, value_type).size() == %1$zu, got %zu", |
| nelems, v.size ()); |
| |
| Vector ().swap (v); |
| |
| rw_assert (0 == v.size (), 0, __LINE__, |
| "vector().swap(vector&).size() == 0, got %zu", |
| v.size ()); |
| |
| Vector::size_type i; |
| |
| for (i = 0; i != nelems; ++i) |
| v.push_back (value); |
| |
| rw_assert (nelems == v.size (), 0, __LINE__, |
| "vector::size() == %1$zu, got %zu", |
| nelems, v.size ()); |
| |
| return 0; |
| } |
| |
| /**************************************************************************/ |
| |
| int main (int argc, char** argv) |
| { |
| return rw_test (argc, argv, __FILE__, |
| "lib.vector", |
| "with a user-defined allocator and pointer types", |
| run_test, |
| "", |
| (void*)0); |
| } |