Teuchos - Trilinos Tools Package Version of the Day
ArrayRCP_test.cpp
// @HEADER
// ***********************************************************************
//
//                    Teuchos: Common Tools Package
//                 Copyright (2004) Sandia Corporation
//
// Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
// license for use of this work by or on behalf of the U.S. Government.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Michael A. Heroux (maherou@sandia.gov)
//
// ***********************************************************************
// @HEADER

#include "Teuchos_ArrayRCP.hpp"
#include "Teuchos_Array.hpp"
#include "Teuchos_CommandLineProcessor.hpp"
#include "Teuchos_GlobalMPISession.hpp"
#include "Teuchos_VerboseObject.hpp"
#include "Teuchos_StandardCatchMacros.hpp"
#include "Teuchos_Version.hpp"
#include "Teuchos_Assert.hpp"
#include "Teuchos_LocalTestingHelpers.hpp"


// Temporarily uncomment any or all of these macros to see compilation
// failures for code that is rightfully not supposed to compile (which is a
// wonderful thing)! The fact that this code does not compile show that the
// design of the Teuchos::ArrayRCP class supports full support of
// const projection in all of its forms when dealing with arrays of objects.
//#define SHOW_COMPILE_FAILURE_1
//#define SHOW_COMPILE_FAILURE_2
//#define SHOW_COMPILE_FAILURE_3


//
// Iterator testing function
//

template<class T>
bool test_ArrayRCP_iterators(
  const Teuchos::ArrayRCP<T> &ptr,
  Teuchos::FancyOStream &out
  )
{

  using Teuchos::ArrayRCP;
  using Teuchos::null;
  using Teuchos::arcp;

  bool success = true;

  out
    << "\n***"
    << "\n*** Testing iterators and accessors for ptr = " << ptr
    << "\n***\n";

  Teuchos::OSTab tab(out);

  const int size = ptr.size();

  // Pointer ++
 
  {
    out << "\nChecking ++itr and < ...\n";
    ArrayRCP<T> itr = ptr;
    for( int i = 0; itr < ptr+size; ++i, ++itr )
      TEST_FOR_EXCEPT( !(*itr == ptr[i]) );
  }
 
  {
    out << "\nChecking itr++ and <= ...\n";
    ArrayRCP<T> itr = ptr;
    for( int i = 0; itr <= ptr+size-1; ++i, itr++ )
      TEST_FOR_EXCEPT( !(*itr == ptr[i]) );
  }
 
  {
    out << "\nChecking itr+=1 and != ...\n";
    ArrayRCP<T> itr = ptr;
    for( int i = 0; itr != ptr+size; ++i, itr+=1 )
      TEST_FOR_EXCEPT( !(*itr == ptr[i]) );
  }
 
  {
    out << "\nChecking itr=itr+1 and == ...\n";
    ArrayRCP<T> itr = ptr;
    for( int i = 0; !( itr == ptr+size ); ++i, itr=itr+1 )
      TEST_FOR_EXCEPT( !(*itr == ptr[i]) );
  }

  // Pointer --
 
  {
    out << "\nChecking --itr and >= ...\n";
    ArrayRCP<T> itr = ptr+size-1;
    for( int i = size-1; itr >= ptr; --i, --itr )
      TEST_FOR_EXCEPT( !(*itr == ptr[i]) );
  }
 
  {
    out << "\nChecking itr-- and > ...\n";
    ArrayRCP<T> itr = ptr+size-1;
    for( int i = size-1; itr+1 > ptr; i--, itr-- )
      TEST_FOR_EXCEPT( !(*itr == ptr[i]) );
  }
 
  {
    out << "\nChecking itr-=1 and != ...\n";
    ArrayRCP<T> itr = ptr+size-1;
    for( int i = size-1; itr+1 != ptr; i--, itr-=1 )
      TEST_FOR_EXCEPT( !(*itr == ptr[i]) );
  }
 
  {
    out << "\nChecking itr=itr-1 and == ...\n";
    ArrayRCP<T> itr = ptr+size-1;
    for( int i = size-1; !( itr+1 == ptr ); i--, itr=itr-1 )
      TEST_FOR_EXCEPT( !(*itr == ptr[i]) );
  }

  // Iterator - Iterator
 
  {
    out << "\nChecking ptr.end() - ptr.begin() == ptr.size() ...\n";
    TEUCHOS_ASSERT_EQUALITY( ptr.end() - ptr.begin(), ptr.size() );
  }

  // Iterator ++
 
  {
    out << "\nChecking iterator ++itr and < ...\n";
    typename ArrayRCP<T>::const_iterator itr = ptr.begin();
    for( int i = 0; itr < ptr.end(); ++i, ++itr )
      TEST_FOR_EXCEPT( !(*itr == ptr[i]) );
  }
 
  {
    out << "\nChecking iterator itr++ and <= ...\n";
    typename ArrayRCP<T>::const_iterator itr = ptr.begin();
    for( int i = 0; itr <= ptr.end()-1; ++i, itr++ )
      TEST_FOR_EXCEPT( !(*itr == ptr[i]) );
  }
 
  {
    out << "\nChecking iterator itr+=1 and != ...\n";
    typename ArrayRCP<T>::const_iterator itr = ptr.begin();
    for( int i = 0; itr != ptr.end(); ++i, itr+=1 )
      TEST_FOR_EXCEPT( !(*itr == ptr[i]) );
  }
 
  {
    out << "\nChecking iterator itr=itr+1 and == ...\n";
    typename ArrayRCP<T>::const_iterator itr = ptr.begin();
    for( int i = 0; !( itr == ptr.end() ); ++i, itr=itr+1 )
      TEST_FOR_EXCEPT( !(*itr == ptr[i]) );
  }

  // Iterator --
 
  {
    out << "\nChecking iterator --itr and >= ...\n";
    typename ArrayRCP<T>::const_iterator itr = ptr.begin()+size-1;
    for( int i = size-1; itr >= ptr.begin(); --i, --itr )
      TEST_FOR_EXCEPT( !(*itr == ptr[i]) );
  }
 
  {
    out << "\nChecking iterator itr-- and > ...\n";
    typename ArrayRCP<T>::const_iterator itr = ptr.begin()+size-1;
    for( int i = size-1; itr+1 > ptr.begin(); i--, itr-- )
      TEST_FOR_EXCEPT( !(*itr == ptr[i]) );
  }
 
  {
    out << "\nChecking iterator itr-=1 and != ...\n";
    typename ArrayRCP<T>::const_iterator itr = ptr.begin()+size-1;
    for( int i = size-1; itr+1 != ptr.begin(); i--, itr-=1 )
      TEST_FOR_EXCEPT( !(*itr == ptr[i]) );
  }
 
  {
    out << "\nChecking iterator itr=itr-1 and == ...\n";
    typename ArrayRCP<T>::const_iterator itr = ptr.begin()+size-1;
    for( int i = size-1; !( itr+1 == ptr.begin() ); i--, itr=itr-1 )
      TEST_FOR_EXCEPT( !(*itr == ptr[i]) );
  }

  return success;

}


//
// Main testing function for a specific ArrayRCP
//


template<class T>
bool test_ArrayRCP(
  const Teuchos::ArrayRCP<T> &ptr,
  Teuchos::FancyOStream &out
  )
{

  using Teuchos::ArrayView;
  using Teuchos::ArrayRCP;
  using Teuchos::arcp;
  using Teuchos::arcp_const_cast;
  using Teuchos::as;

  bool success = true, result;
 
  out
    << "\n***"
    << "\n*** Testing ptr = " << ptr
    << "\n***\n";

  Teuchos::OSTab tab(out);

  const int n = ptr.size();
 
  {
    out << "\nInitializing data ...\n";
    for( int i = 0; i < n; ++i )
      ptr[i] = i;
  }

  TEST_FOR_EXCEPT( !(&*ptr == ptr.get()) );
  TEST_FOR_EXCEPT( !(&*ptr == ptr.getRawPtr()) );

  result = test_ArrayRCP_iterators(ptr,out);
  if (!result) success = false;

  //
  out << "\nTest const casting ...\n";
  //

  {
    const ArrayRCP<const T> cptr2 = ptr;
    const ArrayRCP<T> ptr3 = arcp_const_cast<T>(cptr2);
    TEST_COMPARE_ARRAYS( ptr3, ptr );
  }

  //
  out << "\nTest views ...\n";
  //

  {
    out << "\nTest full non-const subview ...\n";
    const ArrayView<T> av2 = ptr(0,n);
    TEST_COMPARE_ARRAYS( av2, ptr );
  }

  {
    out << "\nTest full shorthand non-const subview ...\n";
    const ArrayView<T> av2 = ptr();
    TEST_COMPARE_ARRAYS( av2, ptr );
  }

  {
    out << "\nTest full const subview ...\n";
    const ArrayView<const T> cav2 = ptr.getConst()(0,n);
    TEST_COMPARE_ARRAYS( cav2, ptr );
  }

  {
    out << "\nTest full non-const to const subview ...\n";
    const ArrayView<const T> cav2 = ptr(0,n);
    TEST_COMPARE_ARRAYS( cav2, ptr );
  }

  {
    out << "\nTest full short-hand const subview ...\n";
    const ArrayView<const T> cav2 = ptr.getConst()();
    TEST_COMPARE_ARRAYS( cav2, ptr );
  }

  {
    out << "\nTest implicit conversion from ArrayRCP<T> to ArrayView<T> ...\n";
    const ArrayView<T> av2 = ptr();
    TEST_COMPARE_ARRAYS( av2, ptr );
  }

  {
    out << "\nTest implicit conversion from ArrayRCP<const T> to ArrayView<const T> ...\n";
    const ArrayView<const T> av2 = ptr.getConst()();
    TEST_COMPARE_ARRAYS( av2, ptr );
  }

  {
    out << "\nTest almost implicit conversion from ArrayRCP<T> to ArrayView<const T> ...\n";
    const ArrayView<const T> av2 = ptr();
    TEST_COMPARE_ARRAYS( av2, ptr );
  }

  {
    out << "\nTest implicit conversion from ArrayRCP<T> to ArrayRCP<const T> ...\n";
    const ArrayRCP<const T> ptr2 = ptr;
    TEST_COMPARE_ARRAYS( ptr2, ptr );
  }

  {
    out << "\nTest clone of ArrayView<T> to ArrayRCP<T> ...\n";
    const ArrayRCP<T> ptr2 = Teuchos::arcpClone<T>(ptr());
    TEST_COMPARE_ARRAYS( ptr2, ptr );
  }

  {
    out << "\nTest clone of ArrayPtr<const T> to ArrayRCP<T> ...\n";
    const ArrayRCP<T> ptr2 = Teuchos::arcpClone<T>(ptr.getConst()());
    TEST_COMPARE_ARRAYS( ptr2, ptr );
  }
  {
    out << "\nTest extra data ...\n";
    ArrayRCP<T> ptr2 = arcp<T>(n);
    Teuchos::set_extra_data( as<int>(1), "int", Teuchos::inOutArg(ptr2) );
    TEST_EQUALITY_CONST( Teuchos::get_extra_data<int>(ptr2, "int"), 1);
  }

  return success;

}


//
// Main driver program
//


int main( int argc, char* argv[] )
{

  Teuchos::GlobalMPISession mpiSession(&argc, &argv);

  using Teuchos::CommandLineProcessor;
  using Teuchos::null;
  using Teuchos::RCP;
  using Teuchos::rcp;
  using Teuchos::ArrayRCP;
  using Teuchos::arcp;
  using Teuchos::arcp_reinterpret_cast;
  
  bool success = true, result;
 
  Teuchos::RCP<Teuchos::FancyOStream>
    out = Teuchos::VerboseObjectBase::getDefaultOStream();
 
  try {

    // Read options from the commandline
    int num_ints = 10;
    int num_doubles = 10;
    CommandLineProcessor clp(false); // Don't throw exceptions
    clp.setOption( "num-ints", &num_ints, "Number of ints to allocate space for" );
    clp.setOption( "num-doubles", &num_doubles, "Number of doubles to allocate space for" );
    CommandLineProcessor::EParseCommandLineReturn parse_return = clp.parse(argc,argv);
    if( parse_return != CommandLineProcessor::PARSE_SUCCESSFUL ) {
      *out << "\nEnd Result: TEST FAILED" << std::endl;
      return parse_return;
    }

    const int sizeOfDouble = sizeof(double);
    const int sizeOfInt = sizeof(int);

    const int total_bytes = num_doubles*sizeOfDouble + num_ints*sizeOfInt;

    *out << std::endl << Teuchos::Teuchos_Version() << std::endl;
 
    *out << "\nTesting basic ArrayRCP functionality ...\n";

    ArrayRCP<char>
      char_ptr1 = arcp<char>(total_bytes);

    *out << "\nchar_ptr1 = " << char_ptr1 << "\n";

    TEST_FOR_EXCEPT( !(char_ptr1.size() == total_bytes) );
    TEST_FOR_EXCEPT( !(char_ptr1.lowerOffset() == 0) );
    TEST_FOR_EXCEPT( !(char_ptr1.upperOffset() == total_bytes-1) );
#ifndef __sun
    TEST_FOR_EXCEPT( !(char_ptr1.count() == 1) );
#endif
    result = test_ArrayRCP(char_ptr1,*out);
    if (!result) success = false;

    ArrayRCP<char>
      char_ptr2 = null;

    *out << "\nchar_ptr2 = " << char_ptr2 << "\n";

    TEST_FOR_EXCEPT( !(char_ptr2.size() == 0) );
    TEST_FOR_EXCEPT( !(char_ptr2.get() == NULL) );
#ifndef __sun
    TEST_FOR_EXCEPT( !(char_ptr2.count() == 0) );
#endif

    ArrayRCP<char>
      char_ptr2b(char_ptr1); // excplicitly test copy constructor

    *out << "\nchar_ptr2b = " << char_ptr2b << "\n";

    TEST_FOR_EXCEPT( !(char_ptr2b.size() == total_bytes) );
    TEST_FOR_EXCEPT( !(char_ptr2b.lowerOffset() == 0) );
    TEST_FOR_EXCEPT( !(char_ptr2b.upperOffset() == total_bytes-1) );
#ifndef __sun
    TEST_FOR_EXCEPT( !(char_ptr2b.count() == 2) );
#endif
    result = test_ArrayRCP(char_ptr2b,*out);
    if (!result) success = false;

    char_ptr2b = null;

    TEST_FOR_EXCEPT( !(char_ptr2b.size() == 0) );
    TEST_FOR_EXCEPT( !(char_ptr2.get() == NULL) );
#ifndef __sun
    TEST_FOR_EXCEPT( !(char_ptr2b.count() == 0) );
    TEST_FOR_EXCEPT( !(char_ptr1.count() == 1) );
#endif

    ArrayRCP<char>
      char_ptr3 = char_ptr1.persistingView(total_bytes/2,total_bytes/2);

#ifndef __sun
    TEST_FOR_EXCEPT( !(char_ptr1.count() == 2) );
    TEST_FOR_EXCEPT( !(char_ptr3.count() == 2) );
#endif
    TEST_FOR_EXCEPT( !(char_ptr3.lowerOffset() == 0) );
    TEST_FOR_EXCEPT( !(char_ptr3.upperOffset() == total_bytes/2-1) );
    result = test_ArrayRCP(char_ptr3,*out);
    if (!result) success = false;

    *out << "\nchar_ptr3 = " << char_ptr3 << "\n";

    *out << "\nBreak up char_ptr1 into views of double and int data\n";

    int offset = 0;
 
    ArrayRCP<double> double_ptr1 = arcp_reinterpret_cast<double>(
      char_ptr1.persistingView(offset,sizeOfDouble*num_doubles)
      );

    *out << "\ndouble_ptr1 = " << double_ptr1 << "\n";

#ifndef __sun
    // 2007/11/30: rabartl: Even to this day, the Sun compiler (version CC:
    // Sun C++ 5.7 Patch 117830-07 2006/03/15 on sass9000) does not destroy
    // objects as required by the C++ standard!  This is unbelievelable!
    TEST_FOR_EXCEPT( !(char_ptr1.count() == 3) );
    TEST_FOR_EXCEPT( !(double_ptr1.count() == 3) );
#endif
    TEST_FOR_EXCEPT( !(double_ptr1.size() == num_doubles) );

    result = test_ArrayRCP(double_ptr1,*out);
    if (!result) success = false;
 
    offset += sizeOfDouble*num_doubles;

    ArrayRCP<int> int_ptr1 = arcp_reinterpret_cast<int>(
      char_ptr1.persistingView(offset,sizeOfInt*num_ints)
      );

    *out << "\nint_ptr1 = " << int_ptr1 << "\n";

#ifndef __sun
    // 2007/11/30: rabartl: See comment above
    TEST_FOR_EXCEPT( !(char_ptr1.count() == 4) );
    TEST_FOR_EXCEPT( !(int_ptr1.count() == 4) );
#endif
    TEST_FOR_EXCEPT( !(int_ptr1.size() == num_ints) );

    result = test_ArrayRCP(int_ptr1,*out);
    if (!result) success = false;

    *out << "\nCreating a constant view of double_ptr1\n";
 
    ArrayRCP<const double>
      double_ptr2 = double_ptr1.getConst();

    result = test_ArrayRCP_iterators(double_ptr2,*out);
    if (!result) success = false;

#ifdef SHOW_COMPILE_FAILURE_1
    // This will not compile since this function tries to use operator[] to
    // change data but it can't since it returns a reference to a const
    // double!
    for( int i = 0; i < double_ptr2.size(); ++i ) {
      double_ptr2[i] = 1.0; // Error, you can change the value!
    }
#endif

    *out << "\nCreating an array of RCP objects!\n";

    ArrayRCP<RCP<double> >
      rcp_ptr1 = arcp<RCP<double> >(num_doubles);

    for( int i = 0; i < num_doubles; ++i )
      rcp_ptr1[i] = rcp(new double(i));

    result = test_ArrayRCP_iterators(rcp_ptr1,*out);
    if (!result) success = false;

    *out << "\nCreating a const view of rcp_ptr1\n";

    ArrayRCP<const RCP<double> >
      rcp_ptr2 = rcp_ptr1.getConst();

    result = test_ArrayRCP_iterators(rcp_ptr2,*out);
    if (!result) success = false;

    *out << "\nCreating an ARCP<double*> object doubleptr_ptr1 and dynamically allocation each element\n";

    ArrayRCP<double*>
      doubleptr_ptr1 = arcp<double*>(total_bytes);

    for( int i = 0; i < doubleptr_ptr1.size(); ++i )
      doubleptr_ptr1[i] = new double(i);

    result = test_ArrayRCP_iterators(doubleptr_ptr1,*out);
    if (!result) success = false;

    *out << "\nCreating an ARCP<double*const> view of a doubleptr_ptr1\n";
 
    ArrayRCP<double*const>
      doubleptr_ptr2 = doubleptr_ptr1.getConst();

    result = test_ArrayRCP_iterators(doubleptr_ptr2,*out);
    if (!result) success = false;

#ifdef SHOW_COMPILE_FAILURE_2
    // This will not compile since this function tries to use operator[] to
    // change data but it can't since it returns a reference to a double*const
    // object!
    for( int i = 0; i < doubleptr_ptr2.size(); ++i ) {
      *doubleptr_ptr2[i] = 1.0; // Fine, you can change the value that is being pointed to for this entry!
      doubleptr_ptr2[i] = NULL; // Error, you can't change the pointer entry!
    }
#endif

    *out << "\nCreating an ARCP<const double * const> view of a doubleptr_ptr1\n";
 
    ArrayRCP<const double*const>
      doubleptr_ptr3 = Teuchos::arcp_implicit_cast<const double*const>(doubleptr_ptr1);

    result = test_ArrayRCP_iterators(doubleptr_ptr3,*out);
    if (!result) success = false;

#ifdef SHOW_COMPILE_FAILURE_3
    // This will not compile since this function tries to use operator[] to
    // change data but it can't since it returns a reference to a double*const
    // object!
    for( int i = 0; i < doubleptr_ptr3.size(); ++i ) {
      *doubleptr_ptr3[i] = 1.0; // Error, you can't change the value that is being pointed to!
      doubleptr_ptr3[i] = NULL; // Error, you can't change the pointer either!
    }
#endif

    for( int i = 0; i < doubleptr_ptr1.size(); ++i )
      delete doubleptr_ptr1[i];

    *out << "\nWrapping RCP<std::vector<T> > objects as ArrayRCP objects ...\n";

    {

      ArrayRCP<char>
        vchar_ptr1 = arcp(rcp(new std::vector<char>(total_bytes)));
      
      *out << "\nvchar_ptr1 = " << vchar_ptr1 << "\n";
      
      result = test_ArrayRCP(vchar_ptr1,*out);
      if (!result) success = false;
      
      ArrayRCP<const char> vchar_ptr2 = vchar_ptr1;
 
      *out << "\nvchar_ptr2 = " << vchar_ptr2 << "\n";
      
      result = test_ArrayRCP_iterators(vchar_ptr2, *out);
      if (!result) success = false;
      
#ifndef __sun
      // RAB: 2006/07/12: The sun compiler declares this call to
      // get_std_vector(...) to be ambiguous (which is nonsense based on
      // everything I know about C++)!
      TEST_FOR_EXCEPT( Teuchos::get_std_vector(vchar_ptr1)->size() != static_cast<size_t>(total_bytes) );
#endif
      TEST_FOR_EXCEPT( vchar_ptr1.size() != static_cast<Teuchos_Ordinal>(total_bytes) );
      TEST_FOR_EXCEPT( vchar_ptr2.size() != static_cast<Teuchos_Ordinal>(total_bytes) );
      
    }

    *out << "\nWrapping RCP<ARray<T> > objects as ArrayRCP objects ...\n";

    {

      ArrayRCP<char>
        vchar_ptr1 = arcp(rcp(new Teuchos::Array<char>(total_bytes)));
      
      *out << "\nvchar_ptr1 = " << vchar_ptr1 << "\n";
      
      result = test_ArrayRCP(vchar_ptr1,*out);
      if (!result) success = false;

/*      
      ArrayRCP<const char> vchar_ptr2 =
        arcp(
          Teuchos::rcp_implicit_cast<const std::vector<char> >(
            Teuchos::get_std_vector(vchar_ptr1)
            )
          );
*/

    }
 
    // ToDo: Fill in the rest of the tests!
 
    *out << "\nAll tests for ArrayRCP seem to check out!\n";
 
  }
  TEUCHOS_STANDARD_CATCH_STATEMENTS(true,std::cerr,success);
 
  if(success)
    *out << "\nEnd Result: TEST PASSED" << std::endl; 
 
  return ( success ? 0 : 1 );
 
}
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines