Boost logo

Boost :

From: Daniel Frey (daniel.frey_at_[hidden])
Date: 2002-06-26 03:17:08


Daniel Frey wrote:
>
> Dietmar Kuehl wrote:
> >
> > On Monday 24 June 2002 13:48, Daniel Frey wrote:
> > > I noticed that boost doesn't have any helper for sizeof_array.
> >
> > One of the very first submissions to Boost was my "array.h" header which
> > hasn't made it from the beta directory into the approved library part yet: It
> > also contains obviously useful function 'begin()' and 'end()' for the obvious
> > propose.
>
> Time to look at it again? Maybe we can merge the best of it into a new
> header/library. What I noticed about your array_traits.h are three
> things:
>
> Before we start implementing anything, we should agree on the objectives
> of such a library. I'd prefer not to mix STL-stuff with the "old"
> arrays. Other opinions?

Seems there are not many opinions. I made a list of objectives for
myself:

a) Provide safe array operations for common tasks
b) Provide glue code to ease integration with the STL

What I don't need is a class that treates arrays the same as containers.
My rationale is, that this would create a new style of using containers
which is IMHO not a good idea and that it might/will lead to some
difficulties that contradict the objectives a) and b). Another rational
is: Scott Meyers, Effective STL, Item 2: Beware the illusion of
container-independent code :)

Given that, I rearranged the code a bit to remove the clash for
boost::array and I added new 'at'-like functions to implement checked
array access. The new header and a sample test program should be
attached to this posting.

Regards, Daniel

--
Daniel Frey
aixigo AG - financial training, research and technology
Schloß-Rahe-Straße 15, 52072 Aachen, Germany
fon: +49 (0)241 936737-42, fax: +49 (0)241 936737-99
eMail: daniel.frey_at_[hidden], web: http://www.aixigo.de

#if !defined( BOOST_ARRAY_TRAITS_HPP )
#define BOOST_ARRAY_TRAITS_HPP

#include <cstddef>
#include <stdexcept>
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>

namespace boost
{
   template< typename T > class array_traits
   {
   private:
      BOOST_STATIC_ASSERT( ::boost::is_array< T >::value );

   public:
      typedef typename remove_bounds< T >::type value_type;
      typedef typename add_pointer< value_type >::type iterator;
      typedef typename add_reference< value_type >::type reference;

      BOOST_STATIC_CONSTANT( std::size_t, size = sizeof( T ) / sizeof( value_type ) );
   };

   // Safe sizeof for arrays
   template< typename T >
   std::size_t
   inline array_size( T& )
   {
      return ::boost::array_traits< T >::size;
   }

   // Work-around for missing 'typeof'
   template< typename T, std::size_t N >
   const char ( &array_to_sizeof( T(&)[N] ) )[N];

   template< typename T, std::size_t N >
   const char ( &array_to_sizeof( const T(&)[N] ) )[N];

   template< typename T, std::size_t N >
   const char ( &array_to_sizeof( volatile T(&)[N] ) )[N];

   template< typename T, std::size_t N >
   const char ( &array_to_sizeof( const volatile T(&)[N] ) )[N];
   
   // Compile-time version of protected element access
   template< std::size_t N, typename T >
   typename array_traits< T >::reference
   inline array_at( T& array )
   {
      BOOST_STATIC_ASSERT( N < ::boost::array_traits< T >::size );
      return array[ N ];
   }

   // Runtime version of protected element access
   template< typename T >
   typename array_traits< T >::reference
   inline array_at( T& array, std::size_t N )
   {
      if( N >= array_size( array ) ) {
         // To do: Create message with values from N
         // and array_size() for a better error description
         throw std::range_error( "boost::array_at() range error" );
      }
      return array[ N ];
   }

   // Glue code for using arrays in the STL
   template< typename T >
   typename array_traits< T >::iterator
   inline array_begin( T& array )
   {
      return array;
   }

   template< typename T >
   typename array_traits< T >::iterator
   inline array_end( T& array )
   {
      return array + array_size( array );
   }
}

#endif // !defined( BOOST_ARRAY_TRAITS_HPP )


#include <iostream>
#include <algorithm>
#include <vector>
#include "array_traits.hpp"

int main()
{
    // The basic tests
    char s1[]= "Hello, world!";
    std::cout << boost::array_size( s1 ) << std::endl;

    const int s2[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    std::cout << boost::array_size( s2 ) << std::endl;

    volatile long s3[][2] = { { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 9, 10 } };
    std::cout << boost::array_size( s3 ) << std::endl;
    for( size_t i = 0; i < boost::array_size( s3 ); ++i ) {
        for( size_t j = 0; j < boost::array_size( s3[i] ); ++j ) {
            std::cout << s3[i][j] << " ";
        }
    }
    std::cout << std::endl;

    const volatile double s4[20] = {};
    std::cout << boost::array_size( s4 ) << std::endl;

    unsigned short s5[21][2] = {};
    std::cout << boost::array_size( s5 ) << std::endl;

    // Static tests
    typedef double A[23];
    const double s6[] = { 12.34, 23.45, 34.56 };
    enum {
        // An easy one
        X = boost::array_traits< A >::size,

        // Currently, only this works
        Y = sizeof( boost::array_to_sizeof( s6 ) ),

        // Given the keyword 'typeof', you should use:
        // ( Note: GCC needs '__typeof' instead of 'typeof' )
        Z = boost::array_traits< __typeof( s6 ) >::size
    };
    std::cout << X << " " << Y << " " << Z << std::endl;

    // Test the glue for STL algorithms
    std::ostream_iterator< const double > ois( std::cout, " " );
    std::copy( boost::array_begin( s6 ), boost::array_end( s6 ), ois );
    std::cout << std::endl;

    std::vector< double > v1( boost::array_begin( s6 ), boost::array_end( s6 ) );
    std::cout << v1.size() << std::endl;

    // Safety stuff
    try {
        // Classic (non-protected) array access
        std::cout << s6[ 2 ] << std::endl;

        // Compile-time protected array access
        std::cout << boost::array_at< 2 >( s6 ) << std::endl;

        // Runtime protected array access
        std::cout << boost::array_at( s6, 2 ) << std::endl;

        // See how it fails... :)
        for( int i = 0; i < 5; ++i )
            std::cout << boost::array_at( s6, i ) << std::endl;
    }
    catch( std::runtime_error& e ) {
        std::cout << "Caught exception: " << e.what() << std::endl;
    }

    // Tests that prevent compilation:
    
    // Common error #1
    // const char* e1 = "This won't work!";
    // std::cout << boost::array_size( e1 ) << std::endl;

    // Common error #2
    // int* e2 = new int[42];
    // std::cout << boost::array_size( e2 ) << std::endl;
    // delete[] e2;
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk