Skip to content

Instantly share code, notes, and snippets.

@jmarrec
Created June 15, 2026 13:44
Show Gist options
  • Select an option

  • Save jmarrec/c16a288da758fecba50894d4063ca89e to your computer and use it in GitHub Desktop.

Select an option

Save jmarrec/c16a288da758fecba50894d4063ca89e to your computer and use it in GitHub Desktop.
Flattened single-header ObjexxFCL Array1D + dependencies for Compiler Explorer
// Flattened single-header bundle of ObjexxFCL Array1D and its dependencies
// Generated for use on Compiler Explorer
#pragma once
// ===== ObjexxFCL/Array1D.fwd.hh =====
#ifndef ObjexxFCL_Array1D_fwd_hh_INCLUDED
#define ObjexxFCL_Array1D_fwd_hh_INCLUDED
// Array1D Forward Declarations
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// C++ Headers
#include <cstddef>
#include <cstdint>
#include <string>
namespace ObjexxFCL {
// Forward
template< typename > class Array1D;
// Types
typedef Array1D< bool > Array1D_bool;
typedef Array1D< short int > Array1D_short;
typedef Array1D< int > Array1D_int;
typedef Array1D< unsigned short int > Array1D_ushort;
typedef Array1D< std::size_t > Array1D_size;
typedef Array1D< std::int32_t > Array1D_int32;
typedef Array1D< double > Array1D_double;
typedef Array1D< signed char > Array1D_schar;
typedef Array1D< std::string > Array1D_string;
} // ObjexxFCL
#endif // ObjexxFCL_Array1D_fwd_hh_INCLUDED
// ===== ObjexxFCL/Array1.fwd.hh =====
#ifndef ObjexxFCL_Array1_fwd_hh_INCLUDED
#define ObjexxFCL_Array1_fwd_hh_INCLUDED
// Array1 Forward Declarations
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// C++ Headers
#include <cstddef>
#include <cstdint>
#include <string>
namespace ObjexxFCL {
// Forward
template< typename > class Array1;
// Types
typedef Array1< int > Array1_int;
typedef Array1< std::string > Array1_string;
} // ObjexxFCL
#endif // ObjexxFCL_Array1_fwd_hh_INCLUDED
// ===== ObjexxFCL/Array.fwd.hh =====
#ifndef ObjexxFCL_Array_fwd_hh_INCLUDED
#define ObjexxFCL_Array_fwd_hh_INCLUDED
// Array Forward Declarations
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// C++ Headers
#include <cstddef>
#include <cstdint>
#include <string>
namespace ObjexxFCL {
// Forward
template< typename > class Array;
// Types
typedef Array< bool > Array_bool;
typedef Array< short int > Array_short;
typedef Array< int > Array_int;
typedef Array< std::size_t > Array_size;
typedef Array< double > Array_double;
typedef Array< signed char > Array_schar;
} // ObjexxFCL
#endif // ObjexxFCL_Array_fwd_hh_INCLUDED
// ===== ObjexxFCL/Omit.hh =====
#ifndef ObjexxFCL_Omit_hh_INCLUDED
#define ObjexxFCL_Omit_hh_INCLUDED
// Omit: Sentinel for Omitted Argument
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
namespace ObjexxFCL {
// Omit: Sentinel for Omitted Argument
struct Omit
{
}; // Omit
static constexpr Omit _{};
} // ObjexxFCL
#endif // ObjexxFCL_Omit_hh_INCLUDED
// ===== ObjexxFCL/Index.hh =====
#ifndef ObjexxFCL_Index_hh_INCLUDED
#define ObjexxFCL_Index_hh_INCLUDED
// Index: Index Class
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// ObjexxFCL Headers
// C++ Headers
#include <cassert>
#include <iosfwd>
#include <type_traits>
#include <utility>
namespace ObjexxFCL {
// Index: Index Class
class Index
{
public: // Creation
// Default Constructor
Index() :
init_( false ),
i_( 0 )
{}
// Copy Constructor
Index( Index const & I ) :
init_( I.init_ ),
i_( I.i_ )
{}
// Index Constructor
Index( int const i ) :
init_( true ),
i_( i )
{}
// Omit Constructor
Index( Omit ) :
init_( false ),
i_( 0 )
{}
// Destructor
~Index()
{}
public: // Assignment
// Scalar Assignment
Index &
operator =( int const i )
{
init_ = true;
i_ = i;
return *this;
}
public: // Conversion
// int Conversion
operator int() const
{
assert( init_ );
return i_;
}
public: // Predicate
// Initialized?
bool
initialized() const
{
return init_;
}
public: // Inspector
// Index
int
i() const
{
assert( init_ );
return i_;
}
public: // Modifier
// Clear
void
clear()
{
init_ = false;
i_ = 0;
}
// Index Set
Index &
i( int const i )
{
init_ = true;
i_ = i;
return *this;
}
// Swap
void
swap( Index & I )
{
std::swap( init_, I.init_ );
std::swap( i_, I.i_ );
}
private: // Data
bool init_; // Index initialized?
int i_; // Index
}; // Index
// Functions
// Swap
inline
void
swap( Index & a, Index & b )
{
a.swap( b );
}
// Comparison
// Index == Index
inline
bool
operator ==( Index const & a, Index const & b )
{
return ( a.initialized() && b.initialized() ? ( a.i() == b.i() ) : ! ( a.initialized() || b.initialized() ) );
}
// Index != Index
inline
bool
operator !=( Index const & a, Index const & b )
{
return !( a == b );
}
// Index == int
inline
bool
operator ==( Index const & a, int const b )
{
return ( a.initialized() && ( a.i() == b ) );
}
// Index != int
inline
bool
operator !=( Index const & a, int const b )
{
return !( a == b );
}
// int == Index
inline
bool
operator ==( int const a, Index const & b )
{
return ( b.initialized() && ( a == b.i() ) );
}
// int != Index
inline
bool
operator !=( int const a, Index const & b )
{
return !( a == b );
}
// I/O
// Stream >> Index
std::istream &
operator >>( std::istream & stream, Index & a );
// Stream << Index
std::ostream &
operator <<( std::ostream & stream, Index const & a );
} // ObjexxFCL
#endif // ObjexxFCL_Index_hh_INCLUDED
// ===== ObjexxFCL/IndexRange.hh =====
#ifndef ObjexxFCL_IndexRange_hh_INCLUDED
#define ObjexxFCL_IndexRange_hh_INCLUDED
// IndexRange: Index Range Class
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// ObjexxFCL Headers
// C++ Headers
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <initializer_list>
#include <iosfwd>
#include <type_traits>
#include <utility>
namespace ObjexxFCL {
// IndexRange: Index Range Class
//
// Note:
// Zero-size range is indicated by ( l - 1 == u ) and ( size == 0 )
// Upper-unbounded range is indicated by ( l - 2 == u ) and ( size == npos )
// Legal ranges have ( l - 2 <= u ) with l and u in their allowed ranges
class IndexRange
{
public: // Types
// STL style
typedef std::size_t size_type;
// C++ style
typedef std::size_t Size;
public: // Creation
// Default Constructor
IndexRange() :
l_( 1 ),
u_( 0 ),
size_( 0u )
{}
// Copy Constructor
IndexRange( IndexRange const & I ) :
l_( I.l_ ),
u_( I.u_ ),
size_( I.size_ )
{}
// Upper Index Constructor
IndexRange( int const u ) :
l_( 1 ),
u_( clean_u( u ) ),
size_( u_ )
{
assert( legal() );
}
// Index Range Constructor
IndexRange( int const l, int const u ) :
l_( l ),
u_( clean_u( u ) ),
size_( computed_size() )
{
assert( legal() );
}
// Initializer List of Integer Constructor
template< typename U, class = typename std::enable_if< std::is_constructible< int, U >::value >::type >
IndexRange( std::initializer_list< U > const lu ) :
l_( 1 ),
u_( 0 ),
size_( 0u )
{
size_type const n( lu.size() );
assert( n <= 2 );
auto i( lu.begin() );
switch ( n ) {
case 0: // {}
l_ = 1;
u_ = 0;
break;
case 1: // {l}
l_ = int( *i );
u_ = l_ - 2; // Unbounded
break;
case 2: // {l,u}
l_ = int( *i );
u_ = clean_u( *(++i) );
break;
}
size_ = computed_size();
assert( legal() );
}
// Initializer List of Index Constructor
IndexRange( std::initializer_list< Index > const lu ) :
l_( 1 ),
u_( 0 ),
size_( 0u )
{
size_type const n( lu.size() );
assert( n <= 2 );
auto i( lu.begin() );
switch ( n ) {
case 0: // {}
l_ = 1;
u_ = 0;
break;
case 1: // {l}
l_ = i->initialized() ? int( *i ) : 1;
u_ = l_ - 2; // Unbounded
break;
case 2: // {l,u}
l_ = i->initialized() ? int( *i ) : 1;
u_ = (++i)->initialized() ? clean_u( int( *i ) ) : l_ - 2; // Omit => Unbounded
break;
}
size_ = computed_size();
assert( legal() );
}
// Omit Constructor
IndexRange( Omit const ) :
l_( 1 ),
u_( -1 ),
size_( npos )
{}
// Lower Index + Omit Constructor
IndexRange( int const l, Omit const ) :
l_( l ),
u_( l_ - 2 ),
size_( npos )
{}
// Omit + Upper Index Constructor
IndexRange( Omit const, int const u ) :
l_( u + 2 ),
u_( u ),
size_( npos )
{
assert( legal() );
}
// Omit + Omit Constructor
IndexRange( Omit const, Omit const ) :
l_( 1 ),
u_( -1 ),
size_( npos )
{}
// Destructor
~IndexRange()
{}
public: // Assignment
// Copy Assignment
IndexRange &
operator =( IndexRange const & I )
{
if ( this != &I ) {
l_ = I.l_;
u_ = I.u_;
size_ = I.size_;
}
assert( legal() );
return *this;
}
// Upper Index Assignment
IndexRange &
operator =( int const u )
{
l_ = 1;
u_ = clean_u( u );
size_ = u_;
assert( legal() );
return *this;
}
// Initializer List of int Assignment
template< typename U, class = typename std::enable_if< std::is_assignable< int&, U >::value >::type >
IndexRange &
operator =( std::initializer_list< U > const lu )
{
size_type const n( lu.size() );
assert( n <= 2 );
auto i( lu.begin() );
switch ( n ) {
case 0: // {}
l_ = 1;
u_ = 0;
break;
case 1: // {l}
l_ = int( *i );
u_ = l_ - 2; // Unbounded
break;
case 2: // {l,u}
l_ = int( *i );
u_ = clean_u( *(++i) );
break;
}
size_ = computed_size();
assert( legal() );
return *this;
}
// Initializer List of Index Assignment
IndexRange &
operator =( std::initializer_list< Index > const lu )
{
size_type const n( lu.size() );
assert( n <= 2 );
auto i( lu.begin() );
switch ( n ) {
case 0: // {}
l_ = 1;
u_ = 0;
break;
case 1: // {l}
l_ = i->initialized() ? int( *i ) : 1;
u_ = l_ - 2; // Unbounded
break;
case 2: // {l,u}
l_ = i->initialized() ? int( *i ) : 1;
u_ = (++i)->initialized() ? clean_u( int( *i ) ) : l_ - 2; // Omit => Unbounded
break;
}
size_ = computed_size();
assert( legal() );
return *this;
}
// IndexRange Assignment
IndexRange &
assign( IndexRange const & I )
{
l_ = I.l_;
u_ = I.u_;
size_ = I.size_;
assert( legal() );
return *this;
}
// Upper Index Assignment
IndexRange &
assign( int const u )
{
l_ = 1;
u_ = clean_u( u );
size_ = u_;
assert( legal() );
return *this;
}
// Index Range Assignment
IndexRange &
assign( int const l, int const u )
{
l_ = l;
u_ = clean_u( u );
size_ = computed_size();
assert( legal() );
return *this;
}
public: // Subscript
// IndexRange( i ): Internal Index for i
int
operator ()( int const i ) const
{
return l_ + ( i - 1 );
}
// IndexRange[ i ]: Internal Index for Zero-Based i
int
operator []( int const i ) const
{
return l_ + i;
}
public: // Predicate
// Legal?
bool
legal() const
{
return ( ( l_ >= l_min ) && ( u_ <= u_max ) && ( l_ - 2 <= u_ ) );
}
// Bounded?
bool
bounded() const
{
return ( l_ - 1 <= u_ );
}
// Unbounded?
bool
unbounded() const
{
return ( l_ - 2 == u_ );
}
// Empty?
bool
empty() const
{
return ( l_ - 1 == u_ );
}
// Non-Empty?
bool
non_empty() const
{
return ( l_ <= u_ );
}
// Bounded with Positive Size?
bool
positive() const
{
return ( l_ <= u_ );
}
// Contains an Index?
bool
contains( int const i ) const
{
return ( ( l_ <= i ) && ( ( i <= u_ ) || ( size_ == npos ) ) );
}
// Contains Two Indexes?
bool
contains( int const i, int const j ) const
{
return ( contains( i ) && contains( j ) );
}
// Contains Another IndexRange?
bool
contains( IndexRange const & I ) const;
// Intersects Another IndexRange?
bool
intersects( IndexRange const & I ) const;
public: // Inspector
// Lower Index
int
l() const
{
return l_;
}
// Upper Index
int
u() const
{
return u_;
}
// Size
size_type
size() const
{
return size_; // Unbounded => npos
}
// Size
int
isize() const
{
assert( size_ != npos );
return static_cast< int >( size_ );
}
// Offset of an Index
int
offset( int const i ) const
{
return ( i - l_ ); // Doesn't check/require that IndexRange includes i
}
// Last Index
int
last() const
{
return std::max( l_, u_ );
}
// Next Index
int
next( int const i ) const
{
return i + 1; // Doesn't check that this is a valid index
}
public: // Modifier
// Lower Index Set
IndexRange &
l( int const l )
{
if ( l_ - 2 == u_ ) { // Unbounded range
l_ = l;
u_ = l_ - 2; // Reset u_ to maintain unbounded state
} else { // Bounded
l_ = l;
size_ = computed_size();
clean();
}
return *this;
}
// Upper Index Set
IndexRange &
u( int const u )
{
u_ = clean_u( u );
size_ = computed_size();
return *this;
}
// Grow Upper
IndexRange &
grow( int const n = 1 )
{
assert( n >= 0 );
assert( u_ <= u_max - n );
assert( u_ >= l_ - 1 );
u_ += n;
size_ = computed_size();
return *this;
}
// Shrink Upper
IndexRange &
shrink( int const n = 1 )
{
assert( n >= 0 );
assert( u_ >= l_ - 1 );
u_ = clean_u( u_ - n );
size_ = computed_size();
return *this;
}
// Expand to Contain an Index
IndexRange &
contain( int const i )
{
if ( l_ - 1 <= u_ ) { // Bounded
if ( l_ > i ) l_ = i;
if ( u_ < i ) u_ = i;
size_ = computed_size();
} else { // Unbounded
if ( l_ > i ) {
l_ = i;
u_ = l_ - 2; // Reset u_ to maintain unbounded state
}
}
assert( legal() );
return *this;
}
// Expand to Contain Another IndexRange
IndexRange &
contain( IndexRange const & I );
// Intersect with Another IndexRange
IndexRange &
intersect( IndexRange const & I );
// Clear
IndexRange &
clear()
{
l_ = 1;
u_ = 0;
size_ = 0u;
return *this;
}
// Clean
IndexRange &
clean()
{
if ( l_ > u_ ) {
l_ = 1;
u_ = 0;
size_ = 0u;
}
return *this;
}
// Swap
IndexRange &
swap( IndexRange & I )
{
if ( this != &I ) {
std::swap( l_, I.l_ );
std::swap( u_, I.u_ );
std::swap( size_, I.size_ );
}
return *this;
}
private: // Methods
// Computed Size
size_type
computed_size() const
{
return std::max( u_ - l_ + 1, -1 );
}
// Clean Upper Index Value After Lower Index Set
int
clean_u( int const u )
{
return std::max( u, l_ - 1 );
}
public: // Data
static size_type const npos; // Unbounded "size"
static int const l_min; // Min lower index
static int const u_max; // Max upper index
private: // Data
int l_; // Lower index
int u_; // Upper index
size_type size_; // Size (npos iff unbounded)
}; // IndexRange
// Functions
// IndexRange == IndexRange
inline
bool
operator ==( IndexRange const & I, IndexRange const & J )
{
return ( ( I.l() == J.l() ) && ( I.u() == J.u() ) );
}
// IndexRange != IndexRange
inline
bool
operator !=( IndexRange const & I, IndexRange const & J )
{
return !( I == J );
}
// IndexRange < IndexRange
inline
bool
operator <( IndexRange const & I, IndexRange const & J )
{
return ( I.positive() && J.positive() && ( I.u() < J.l() ) );
}
// IndexRange <= IndexRange
inline
bool
operator <=( IndexRange const & I, IndexRange const & J )
{
return ( I.positive() && J.positive() && ( I.u() <= J.l() ) );
}
// IndexRange > IndexRange
inline
bool
operator >( IndexRange const & I, IndexRange const & J )
{
return ( I.positive() && J.positive() && ( I.l() > J.u() ) );
}
// IndexRange >= IndexRange
inline
bool
operator >=( IndexRange const & I, IndexRange const & J )
{
return ( I.positive() && J.positive() && ( I.l() >= J.u() ) );
}
// Swap
inline
void
swap( IndexRange & a, IndexRange & b )
{
a.swap( b );
}
// Stream >> IndexRange
std::istream &
operator >>( std::istream & stream, IndexRange & I );
// Stream << IndexRange
std::ostream &
operator <<( std::ostream & stream, IndexRange const & I );
} // ObjexxFCL
#endif // ObjexxFCL_IndexRange_hh_INCLUDED
// ===== ObjexxFCL/IndexSlice.hh =====
#ifndef ObjexxFCL_IndexSlice_hh_INCLUDED
#define ObjexxFCL_IndexSlice_hh_INCLUDED
// IndexSlice: Index Slice Class
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// ObjexxFCL Headers
// C++ Headers
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <initializer_list>
#include <iosfwd>
#include <type_traits>
#include <utility>
namespace ObjexxFCL {
// IndexSlice: Index Slice Class
class IndexSlice
{
public: // Types
// STL style
typedef std::size_t size_type;
// C++ style
typedef std::size_t Size;
public: // Creation
// Default Constructor
IndexSlice() :
l_init_( false ),
u_init_( false ),
scalar_( false ),
l_( 1 ),
u_( 0 ),
s_( 1 ),
size_( 0u )
{}
// Copy Constructor
IndexSlice( IndexSlice const & I ) :
l_init_( I.l_init_ ),
u_init_( I.u_init_ ),
scalar_( I.scalar_ ),
l_( I.l_ ),
u_( I.u_ ),
s_( I.s_ ),
size_( I.size_ )
{
assert( size_ == computed_size() );
}
// Scalar Constructor
IndexSlice( int const i ) :
l_init_( true ),
u_init_( true ),
scalar_( true ),
l_( i ),
u_( i ),
s_( 1 ),
size_( 1u )
{}
// Index Slice Constructor
IndexSlice( int const l, int const u, int const s = 1 ) :
l_init_( true ),
u_init_( true ),
scalar_( false ),
l_( l ),
u_( u ),
s_( s ),
size_( computed_size() )
{
assert( s_ != 0 );
}
// Initializer List of Integer Constructor
template< typename U, class = typename std::enable_if< std::is_constructible< int, U >::value >::type >
IndexSlice( std::initializer_list< U > const lus ) :
l_init_( lus.size() > 0u ),
u_init_( lus.size() > 1u ),
scalar_( false ),
l_( 1 ),
u_( 0 ),
s_( 1 ),
size_( 0u )
{
size_type const n( lus.size() );
assert( n <= 3 );
auto i( lus.begin() );
switch ( n ) {
case 0: // {}
l_ = 1;
u_ = 0;
s_ = 1;
break;
case 1: // {l}
l_ = *i;
u_ = 0;
s_ = 1;
break;
case 2: // {l,u}
l_ = *i;
u_ = *(++i);
s_ = 1;
break;
case 3: // {l,u,s}
l_ = *i;
u_ = *(++i);
s_ = *(++i);
break;
}
assert( s_ != 0 );
size_ = computed_size();
}
// Initializer List of Index Constructor
IndexSlice( std::initializer_list< Index > const lus ) :
l_init_( ( lus.size() > 0u ) && ( lus.begin()->initialized() ) ),
u_init_( ( lus.size() > 1u ) && ( ( lus.begin() + 1 )->initialized() ) ),
scalar_( false ),
l_( 1 ),
u_( 0 ),
s_( 1 ),
size_( 0u )
{
size_type const n( lus.size() );
assert( n <= 3 );
auto i( lus.begin() );
switch ( n ) {
case 0: // {}
l_ = 1;
u_ = 0;
s_ = 1;
break;
case 1: // {l}
l_ = i->initialized() ? int( *i ) : 1;
u_ = 0;
s_ = 1;
break;
case 2: // {l,u}
l_ = i->initialized() ? int( *i ) : 1;
u_ = (++i)->initialized() ? int( *i ) : 0;
s_ = 1;
break;
case 3: // {l,u,s}
l_ = i->initialized() ? int( *i ) : 1;
u_ = (++i)->initialized() ? int( *i ) : 0;
s_ = (++i)->initialized() ? int( *i ) : 1;
break;
}
assert( s_ != 0 );
size_ = computed_size();
}
// Omit Constructor
IndexSlice( Omit ) :
l_init_( false ),
u_init_( false ),
scalar_( false ),
l_( 1 ),
u_( 0 ),
s_( 1 ),
size_( 0u )
{
assert( s_ != 0 );
}
// Lower Index + Omit Constructor
IndexSlice( int const l, Omit, int const s = 1 ) :
l_init_( true ),
u_init_( false ),
scalar_( false ),
l_( l ),
u_( 0 ),
s_( s ),
size_( 0u )
{
assert( s_ != 0 );
}
// Omit + Upper Index Constructor
IndexSlice( Omit, int const u, int const s = 1 ) :
l_init_( false ),
u_init_( true ),
scalar_( false ),
l_( 1 ),
u_( u ),
s_( s ),
size_( 0u )
{
assert( s_ != 0 );
}
// Omit + Omit Constructor
IndexSlice( Omit, Omit, int const s = 1 ) :
l_init_( false ),
u_init_( false ),
scalar_( false ),
l_( 1 ),
u_( 0 ),
s_( s ),
size_( 0u )
{
assert( s_ != 0 );
}
// Destructor
~IndexSlice()
{}
public: // Assignment
// Scalar Assignment
IndexSlice &
operator =( int const i )
{
l_init_ = true;
u_init_ = true;
scalar_ = true;
l_ = i;
u_ = i;
s_ = 1;
size_ = 1u;
return *this;
}
// Initializer List of int Assignment
IndexSlice &
operator =( std::initializer_list< int > const lus )
{
size_type const n( lus.size() );
assert( n <= 3 );
l_init_ = n > 0u;
u_init_ = n > 1u;
scalar_ = false;
auto i( lus.begin() );
switch ( n ) {
case 0: // {}
l_ = 1;
u_ = 0;
s_ = 1;
break;
case 1: // {l}
l_ = *i;
u_ = 0;
s_ = 1;
break;
case 2: // {l,u}
l_ = *i;
u_ = *(++i);
s_ = 1;
break;
case 3: // {l,u,s}
l_ = *i;
u_ = *(++i);
s_ = *(++i);
break;
}
assert( s_ != 0 );
size_ = computed_size();
return *this;
}
// Initializer List of Index Assignment
IndexSlice &
operator =( std::initializer_list< Index > const lus )
{
size_type const n( lus.size() );
assert( n <= 3 );
auto i( lus.begin() );
l_init_ = ( n > 0u ) && ( i->initialized() );
u_init_ = ( n > 1u ) && ( ( i + 1 )->initialized() );
scalar_ = false;
switch ( n ) {
case 0: // {}
l_ = 1;
u_ = 0;
s_ = 1;
break;
case 1: // {l}
l_ = i->initialized() ? int( *i ) : 1;
u_ = 0;
s_ = 1;
break;
case 2: // {l,u}
l_ = i->initialized() ? int( *i ) : 1;
u_ = (++i)->initialized() ? int( *i ) : 0;
s_ = 1;
break;
case 3: // {l,u,s}
l_ = i->initialized() ? int( *i ) : 1;
u_ = (++i)->initialized() ? int( *i ) : 0;
s_ = (++i)->initialized() ? int( *i ) : 1;
break;
}
assert( s_ != 0 );
size_ = computed_size();
return *this;
}
// Index Slice Assignment
IndexSlice &
assign( int const l, int const u, int const s = 1 )
{
l_init_ = true;
u_init_ = true;
scalar_ = false;
l_ = l;
u_ = u;
s_ = s;
size_ = computed_size();
return *this;
}
public: // Subscript
// IndexSlice( i ) const: Internal Index for i
int
operator ()( int const i ) const
{
assert( l_init_ );
return ( scalar_ ? l_ : l_ + ( i - 1 ) * s_ ); // Doesn't check that i <= size of slice
}
public: // Predicate
// Initialized?
bool
initialized() const
{
return ( l_init_ && u_init_ );
}
// Lower Initialized?
bool
l_initialized() const
{
return l_init_;
}
// Upper Initialized?
bool
u_initialized() const
{
return u_init_;
}
// Scalar?
bool
scalar() const
{
return scalar_;
}
// Contains an Index?
bool
contains( int const i ) const
{
assert( l_init_ && u_init_ );
return ( scalar_ ? i == l_ : ( std::min( l_, u_ ) <= i ) && ( i <= std::max( l_, u_ ) ) && ( ( ( i - l_ ) % s_ ) == 0 ) );
}
public: // Inspector
// Lower (Begin) Index
int
l() const
{
assert( l_initialized() );
return l_;
}
// Upper (End) Index
int
u() const
{
assert( u_initialized() );
return u_;
}
// Step
int
s() const
{
return s_;
}
// Size
size_type
size() const
{
return size_;
}
// Size
int
isize() const
{
return static_cast< int >( size_ );
}
// Last Index
int
last() const
{
assert( initialized() );
assert( s_ != 0 );
return l_ + ( s_ * ( size_ > 0u ? int( size_ - 1u ) : 0 ) ); // Get l_ if size==0
}
// Next Index
int
next( int const i ) const
{
assert( l_init_ );
assert( contains( i ) );
return ( scalar_ ? l_ : i + s_ ); // Doesn't check that this is a valid index
}
// Min Index
int
min() const
{
assert( initialized() );
return std::min( l_, last() );
}
// Max Index
int
max() const
{
assert( initialized() );
return std::max( l_, last() );
}
// Empty or Undefined?
bool
empty() const
{
return ( size_ == 0u );
}
// Non-Empty?
bool
non_empty() const
{
return ( size_ > 0u );
}
public: // Modifier
// Clear
void
clear()
{
l_init_ = false;
u_init_ = false;
scalar_ = false;
l_ = 1;
u_ = 0;
s_ = 1;
size_ = 0u;
}
// Scalar Index Set
IndexSlice &
i( int const i )
{
l_init_ = true;
u_init_ = true;
scalar_ = true;
l_ = i;
u_ = i;
s_ = 1;
size_ = 1u;
return *this;
}
// Lower Index Set
IndexSlice &
l( int const l )
{
l_init_ = true;
scalar_ = false;
l_ = l;
size_ = computed_size();
return *this;
}
// Upper Index Set
IndexSlice &
u( int const u )
{
u_init_ = true;
scalar_ = false;
u_ = u;
size_ = computed_size();
return *this;
}
// Index Set if Uninitialized
void
lud( int const l, int const u )
{
if ( ! l_init_ ) {
l_ = l;
l_init_ = true;
}
if ( ( ! u_init_ ) && ( l - 1 <= u ) ) {
u_ = u;
u_init_ = true;
}
scalar_ = false;
size_ = computed_size();
}
// Swap
void
swap( IndexSlice & I )
{
if ( this != &I ) {
std::swap( l_init_, I.l_init_ );
std::swap( u_init_, I.u_init_ );
std::swap( scalar_, I.scalar_ );
std::swap( l_, I.l_ );
std::swap( u_, I.u_ );
std::swap( s_, I.s_ );
std::swap( size_, I.size_ );
}
}
public: // Friend
// Swap
friend
void
swap( IndexSlice & a, IndexSlice & b )
{
a.swap( b );
}
public: // Comparison
// IndexSlice == IndexSlice
friend
bool
operator ==( IndexSlice const & I, IndexSlice const & J )
{
return ( ( I.l_init_ == J.l_init_ ) && ( I.u_init_ == J.u_init_ ) && ( I.scalar_ == J.scalar_ ) && ( I.l_ == J.l_ ) && ( I.u_ == J.u_ ) && ( I.s_ == J.s_ ) );
}
// IndexSlice != IndexSlice
friend
bool
operator !=( IndexSlice const & I, IndexSlice const & J )
{
return !( I == J );
}
public: // I/O
// Stream >> IndexSlice
friend
std::istream &
operator >>( std::istream & stream, IndexSlice & I );
// Stream << IndexSlice
friend
std::ostream &
operator <<( std::ostream & stream, IndexSlice const & I );
private: // Inspector
// Computed Size
size_type
computed_size() const
{
assert( s_ != 0 || ! l_init_ || ! u_init_ );
return ( l_init_ && u_init_ ? std::max( ( u_ - l_ + s_ ) / s_, 0 ) : 0 );
}
private: // Data
bool l_init_; // Lower index initialized?
bool u_init_; // Upper index initialized?
bool scalar_; // Scalar slice?
int l_; // Lower index
int u_; // Upper index
int s_; // Step
size_type size_; // Size (0 if unknown)
}; // IndexSlice
// Types
typedef IndexSlice ISlice;
// IndexSlice == IndexSlice
bool
operator ==( IndexSlice const & I, IndexSlice const & J );
// IndexSlice != IndexSlice
bool
operator !=( IndexSlice const & I, IndexSlice const & J );
// Stream >> IndexSlice
std::istream &
operator >>( std::istream & stream, IndexSlice & I );
// Stream << IndexSlice
std::ostream &
operator <<( std::ostream & stream, IndexSlice const & I );
// Swap
void
swap( IndexSlice & a, IndexSlice & b );
} // ObjexxFCL
#endif // ObjexxFCL_IndexSlice_hh_INCLUDED
// ===== ObjexxFCL/DimensionSlice.hh =====
#ifndef ObjexxFCL_DimensionSlice_hh_INCLUDED
#define ObjexxFCL_DimensionSlice_hh_INCLUDED
// DimensionSlice: Dimension Slice Class
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// ObjexxFCL Headers
// C++ Headers
#include <cassert>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <limits>
namespace ObjexxFCL {
// DimensionSlice: Dimension Slice Class
class DimensionSlice
{
public: // Types
// STL style
typedef std::size_t size_type;
// C++ style
typedef std::size_t Size;
public: // Creation
// Default Constructor
DimensionSlice() :
m_( 1 ),
k_( 0 ),
u_( 0 )
{}
// Index Slice + Multiplier Constructor
DimensionSlice( IndexSlice const & slice, std::int64_t const multiplier = 1 ) :
m_( slice.s() * multiplier ),
k_( slice.l() * multiplier - m_ ),
u_( slice.isize() )
{
assert( slice.initialized() );
assert( multiplier <= std::numeric_limits< std::int64_t >::max() / std::abs( slice.s() ) );
}
// Index Slice + Multiplier Constructor
DimensionSlice( IndexSlice const & slice, size_type const multiplier ) :
m_( slice.s() * multiplier ),
k_( slice.l() * multiplier - m_ ),
u_( slice.isize() )
{
assert( slice.initialized() );
assert( multiplier <= size_type( std::numeric_limits< std::int64_t >::max() / std::abs( slice.s() ) ) );
}
// Index Slice + Multiplier Constructor
template< typename M >
DimensionSlice( IndexSlice const & slice, M const multiplier ) :
m_( slice.s() * multiplier ),
k_( slice.l() * multiplier - m_ ),
u_( slice.isize() )
{
assert( slice.initialized() );
assert( multiplier <= std::numeric_limits< std::int64_t >::max() / std::abs( slice.s() ) );
}
// Index Range + Index Slice + Multiplier Constructor
DimensionSlice( IndexRange const & range, IndexSlice slice, std::int64_t const multiplier = 1 )
{
slice.lud( range.l(), range.u() );
assert( slice.initialized() );
assert( slice.empty() || range.contains( slice.l(), slice.last() ) );
assert( multiplier <= std::numeric_limits< std::int64_t >::max() / std::abs( slice.s() ) );
m_ = slice.s() * multiplier;
k_ = ( slice.l() * multiplier ) - m_;
u_ = slice.isize();
}
// Index Range + Index Slice + Multiplier Constructor
DimensionSlice( IndexRange const & range, IndexSlice slice, size_type const multiplier )
{
slice.lud( range.l(), range.u() );
assert( slice.initialized() );
assert( slice.empty() || range.contains( slice.l(), slice.last() ) );
assert( multiplier <= size_type( std::numeric_limits< std::int64_t >::max() / std::abs( slice.s() ) ) );
m_ = slice.s() * multiplier;
k_ = ( slice.l() * multiplier ) - m_;
u_ = slice.isize();
}
// Index Range + Index Slice + Multiplier Constructor
template< typename M >
DimensionSlice( IndexRange const & range, IndexSlice slice, M const multiplier )
{
slice.lud( range.l(), range.u() );
assert( slice.initialized() );
assert( slice.empty() || range.contains( slice.l(), slice.last() ) );
assert( multiplier <= std::numeric_limits< std::int64_t >::max() / std::abs( slice.s() ) );
m_ = slice.s() * multiplier;
k_ = ( slice.l() * multiplier ) - m_;
u_ = slice.isize();
}
// Upper Index + Index Slice + Multiplier Constructor
DimensionSlice( int const u, IndexSlice slice, std::int64_t const multiplier = 1 )
{
assert( u >= 0 );
slice.lud( 1, u );
assert( slice.initialized() );
assert( slice.empty() || ( in_range( u, slice.l() ) && in_range( u, slice.last() ) ) );
assert( multiplier <= std::numeric_limits< std::int64_t >::max() / std::abs( slice.s() ) );
m_ = slice.s() * multiplier;
k_ = ( slice.l() * multiplier ) - m_;
u_ = slice.isize();
}
// Upper Index + Index Slice + Multiplier Constructor
DimensionSlice( int const u, IndexSlice slice, size_type const multiplier )
{
assert( u >= 0 );
slice.lud( 1, u );
assert( slice.initialized() );
assert( slice.empty() || ( in_range( u, slice.l() ) && in_range( u, slice.last() ) ) );
assert( multiplier <= size_type( std::numeric_limits< std::int64_t >::max() / std::abs( slice.s() ) ) );
m_ = slice.s() * multiplier;
k_ = ( slice.l() * multiplier ) - m_;
u_ = slice.isize();
}
// Upper Index + Index Slice + Multiplier Constructor
template< typename M >
DimensionSlice( int const u, IndexSlice slice, M const multiplier )
{
assert( u >= 0 );
slice.lud( 1, u );
assert( slice.initialized() );
assert( slice.empty() || ( in_range( u, slice.l() ) && in_range( u, slice.last() ) ) );
assert( multiplier <= std::numeric_limits< std::int64_t >::max() / std::abs( slice.s() ) );
m_ = slice.s() * multiplier;
k_ = ( slice.l() * multiplier ) - m_;
u_ = slice.isize();
}
// Index Range + Multiplier Full Range Constructor
DimensionSlice( IndexRange const & range, size_type const multiplier = 1 )
{
assert( range.bounded() );
assert( multiplier <= size_type( std::numeric_limits< std::int64_t >::max() ) );
m_ = multiplier;
k_ = ( static_cast<std::int64_t>(range.l()) - 1 ) * multiplier;
u_ = range.isize();
}
// Destructor
~DimensionSlice()
{}
public: // Inspector
// Multiplier
std::int64_t
m() const
{
return m_;
}
// Constant
std::int64_t
k() const
{
return k_;
}
// Upper Index
int
u() const
{
return u_;
}
// Size
size_type
z() const
{
return u_;
}
// Size
size_type
size() const
{
return u_;
}
public: // Modifier
// Clear
void
clear()
{
m_ = 1;
k_ = 0;
u_ = 0;
}
protected: // Static Methods
// Is Index in Range of [1,u]
static
bool
in_range( int const u, int const i )
{
return ( ( 1 <= i ) && ( i <= u ) );
}
private: // Data
std::int64_t m_; // Multiplier
std::int64_t k_; // Constant
int u_; // Upper index
}; // DimensionSlice
} // ObjexxFCL
#endif // ObjexxFCL_DimensionSlice_hh_INCLUDED
// ===== ObjexxFCL/BArray.hh =====
#ifndef ObjexxFCL_BArray_hh_INCLUDED
#define ObjexxFCL_BArray_hh_INCLUDED
// BArray: Array Abstract Base Class
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// ObjexxFCL Headers
namespace ObjexxFCL {
// BArray: Array Abstract Base Class
class BArray
{
public: // Types
typedef IndexRange IR;
typedef IndexSlice IS;
typedef DimensionSlice DS;
// STL style
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
// C++ style
typedef std::size_t Size;
typedef std::ptrdiff_t Difference;
protected: // Creation
// Default Constructor
constexpr BArray() = default;
// Copy Constructor
constexpr BArray( BArray const & ) = default;
// Move Constructor
constexpr BArray( BArray && ) noexcept = default;
public: // Creation
// Destructor
virtual
~BArray() = default;
protected: // Assignment
// Copy Assignment
BArray &
operator =( BArray const & ) = default;
// Move Assignment
BArray &
operator =( BArray && ) noexcept = default;
public: // Static Data
static constexpr size_type const npos = static_cast<size_type>(-1); // Unbounded "size"
static constexpr size_type const max_size = static_cast<size_type>(-1) - static_cast<size_type>(1); // Max array size
}; // BArray
} // ObjexxFCL
#endif // ObjexxFCL_BArray_hh_INCLUDED
// ===== ObjexxFCL/align.hh =====
#ifndef ObjexxFCL_align_hh_INCLUDED
#define ObjexxFCL_align_hh_INCLUDED
// Alignment Support
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// C++ Headers
#include <cassert>
#include <cstddef>
#include <cstdint>
// Auto-Selected Alignment
#if defined(__MIC__)
#define OBJEXXFCL_ALIGN_AUTO 64
#elif defined(__AVX__)
#define OBJEXXFCL_ALIGN_AUTO 32
#elif defined(__SSE__)
#define OBJEXXFCL_ALIGN_AUTO 16
#else
#define OBJEXXFCL_ALIGN_AUTO 16
#endif
// Specified Alignment
#ifdef OBJEXXFCL_ALIGN
#if OBJEXXFCL_ALIGN < OBJEXXFCL_ALIGN_AUTO
#undef OBJEXXFCL_ALIGN
#define OBJEXXFCL_ALIGN OBJEXXFCL_ALIGN_AUTO
#endif
static_assert( ( OBJEXXFCL_ALIGN & ( OBJEXXFCL_ALIGN - 1 ) ) == 0, "OBJEXXFCL_ALIGN must be a power of 2" );
#endif
#ifdef OBJEXXFCL_ALIGN
namespace ObjexxFCL {
// Byte Address Rounded Up to Satisfy Alignment
template< typename T >
T *
aligned( T * const mem ) // Can add a variant taking a void * if needed
{
static T const ALIGN( OBJEXXFCL_ALIGN );
static T const zero( 0 );
static T const one( 1 );
static_assert( ( ALIGN > zero ) && ( ( ALIGN & ( ALIGN - one ) ) == zero ), "Byte alignment must be a positive power of 2" ); // Positive power of 2 check
return ( ( mem == nullptr ) || ( ALIGN <= T( 0 ) ) ? mem : reinterpret_cast< T * >( ( reinterpret_cast< std::uintptr_t >( mem ) + static_cast< std::uintptr_t >( ALIGN - 1 ) ) & ~static_cast< std::uintptr_t >( ALIGN - 1 ) ) );
}
// Can Row Length be Padded to Satisfy Alignment?
template< typename T >
bool
paddable()
{
static int const REM( OBJEXXFCL_ALIGN % static_cast< int >( sizeof( T ) ) );
return REM == 0;
}
// Row Length Rounded up to Satisfy Alignment
template< typename T >
T
padded( int const row )
{
static_assert( OBJEXXFCL_ALIGN % static_cast< int >( sizeof( T ) ) == 0, "Type is not row-paddable for the byte alignment" ); // Paddable check
assert( row >= 0 );
static int const MUL( OBJEXXFCL_ALIGN / static_cast< int >( sizeof( T ) ) ); // Aligned multiple of T
int const rem( row % MUL );
return ( rem > 0 ? row + MUL - rem : row );
}
} // ObjexxFCL
#endif
#endif // ObjexxFCL_align_hh_INCLUDED
// ===== ObjexxFCL/AlignedAllocator.hh =====
#ifndef ObjexxFCL_AlignedAllocator_hh_INCLUDED
#define ObjexxFCL_AlignedAllocator_hh_INCLUDED
// Aligned Allocator
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// ObjexxFCL Headers
// C++ Headers
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <new>
namespace ObjexxFCL {
// Aligned Allocator Class Template
template< typename T >
struct AlignedAllocator
{
public: // Types
// STL Style
using size_type = std::size_t;
// C++ Style
using Size = std::size_t;
public: // Static Methods
// Raw allocation size including optional alignment padding
static
size_type
allocation_size( size_type const n )
{
#ifdef OBJEXXFCL_ALIGN
constexpr size_type alignment_overhead( OBJEXXFCL_ALIGN > 0u ? OBJEXXFCL_ALIGN - 1u : 0u );
#else
constexpr size_type alignment_overhead( 0u );
#endif
constexpr size_type max_size( static_cast< size_type >( std::numeric_limits< std::ptrdiff_t >::max() ) );
if ( n > ( max_size - alignment_overhead ) / sizeof( T ) ) {
throw std::bad_array_new_length();
}
return ( n * sizeof( T ) ) + alignment_overhead;
}
// Allocate Raw Array Memory with ::operator new
static
void *
allocate( size_type const n )
{
void * mem( n > 0u ? ::operator new( allocation_size( n ) ) : nullptr );
assert( ( n == 0u ) || ( mem != nullptr ) );
return mem;
}
// Allocate Raw Array Memory with ::operator new Even if Size is Zero
static
void *
allocate_zero( size_type const n )
{
void * mem( ::operator new( allocation_size( n ) ) );
assert( ( n == 0u ) || ( mem != nullptr ) );
return mem;
}
// Aligned Data Pointer for a Given Memory Pointer
static
T *
data( void * const mem )
{
#ifdef OBJEXXFCL_ALIGN
T * p( static_cast< T * >( ( mem == nullptr ) || ( OBJEXXFCL_ALIGN == 0u ) ? mem : reinterpret_cast< void * >( ( reinterpret_cast< std::uintptr_t >( mem ) + static_cast< std::uintptr_t >( OBJEXXFCL_ALIGN - 1 ) ) & ~static_cast< std::uintptr_t >( OBJEXXFCL_ALIGN - 1 ) ) ) );
assert( p >= mem );
assert( reinterpret_cast< std::uintptr_t >( p ) % OBJEXXFCL_ALIGN == 0 );
#else
T * p( static_cast< T * >( mem ) );
#endif
return p;
}
}; // AlignedAllocator
} // ObjexxFCL
#endif // ObjexxFCL_AlignedAllocator_hh_INCLUDED
// ===== ObjexxFCL/ArrayS.fwd.hh =====
#ifndef ObjexxFCL_ArrayS_fwd_hh_INCLUDED
#define ObjexxFCL_ArrayS_fwd_hh_INCLUDED
// ArrayS Forward Declarations
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// C++ Headers
#include <cstddef>
#include <cstdint>
#include <string>
namespace ObjexxFCL {
// Forward
template< typename > class ArrayS;
// Types
typedef ArrayS< double > ArrayS_double;
} // ObjexxFCL
#endif // ObjexxFCL_ArrayS_fwd_hh_INCLUDED
// ===== ObjexxFCL/TypeTraits.hh =====
#ifndef ObjexxFCL_TypeTraits_hh_INCLUDED
#define ObjexxFCL_TypeTraits_hh_INCLUDED
// TypeTraits: Type Traits Template
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// C++ Headers
#include <complex>
#include <cstddef>
#include <ios>
#include <limits>
#include <type_traits>
namespace ObjexxFCL {
template< class A, class B >
inline
bool
same_type_as( A const &, B const & )
{
return std::is_same< A, B >::value;
}
// is_a: Type Test for const Reference Argument
template< class B, class A >
inline
bool
is_a( A const & )
{
return std::is_same< A, B >::value || std::is_base_of< B, A >::value;
}
// is_a: Type Test for non-const Reference Argument
template< class B, class A >
inline
bool
is_a( A & )
{
return std::is_same< A, B >::value || std::is_base_of< B, A >::value;
}
// is_a: Type Test for const Pointer Argument
template< class B, class A >
inline
bool
is_a( A const * )
{
return std::is_same< A, B >::value || std::is_base_of< B, A >::value;
}
// is_a: Type Test for non-const Pointer Argument
template< class B, class A >
inline
bool
is_a( A * )
{
return std::is_same< A, B >::value || std::is_base_of< B, A >::value;
}
// TypeTraits: Type Traits Template
template< typename T >
struct TypeTraits
{
typedef T traits_type;
typedef std::size_t Size;
// Initial Value
static
traits_type
initial_value()
{
return traits_type(); // Use default constructor
}
// Debug Value
static
traits_type
debug_value()
{
return traits_type(); // Use default constructor
}
// Initial Array Value
static
traits_type
initial_array_value()
{
#ifdef OBJEXXFCL_ARRAY_INIT_DEBUG
return debug_value();
#else
return initial_value();
#endif
}
static std::streamsize const precision = 0; // Precision
static Size const width = 0; // Field width
static int const iwidth = 0; // Field width
};
// TypeTraits: Type Traits char Specialization
template<>
struct TypeTraits< char >
{
typedef char traits_type;
typedef std::size_t Size;
// Initial Value
static
traits_type
initial_value()
{
return ' ';
}
// Debug Value
static
traits_type
debug_value()
{
return std::numeric_limits< traits_type >::max();
}
// Initial Array Value
static
traits_type
initial_array_value()
{
#ifdef OBJEXXFCL_ARRAY_INIT_DEBUG
return debug_value();
#else
return initial_value();
#endif
}
static std::streamsize const precision = 0; // Precision
static Size const width = 1; // Field width
static int const iwidth = 1; // Field width
};
// TypeTraits: Type Traits signed char Specialization
template<>
struct TypeTraits< signed char >
{
typedef signed char traits_type;
typedef std::size_t Size;
// Initial Value
static
traits_type
initial_value()
{
return ' ';
}
// Debug Value
static
traits_type
debug_value()
{
return std::numeric_limits< traits_type >::max();
}
// Initial Array Value
static
traits_type
initial_array_value()
{
#ifdef OBJEXXFCL_ARRAY_INIT_DEBUG
return debug_value();
#else
return initial_value();
#endif
}
static std::streamsize const precision = 0; // Precision
static Size const width = 1; // Field width
static int const iwidth = 1; // Field width
};
// TypeTraits: Type Traits unsigned char Specialization
template<>
struct TypeTraits< unsigned char >
{
typedef unsigned char traits_type;
typedef std::size_t Size;
// Initial Value
static
traits_type
initial_value()
{
return ' ';
}
// Debug Value
static
traits_type
debug_value()
{
return std::numeric_limits< traits_type >::max();
}
// Initial Array Value
static
traits_type
initial_array_value()
{
#ifdef OBJEXXFCL_ARRAY_INIT_DEBUG
return debug_value();
#else
return initial_value();
#endif
}
static std::streamsize const precision = 0; // Precision
static Size const width = 1; // Field width
static int const iwidth = 1; // Field width
};
// TypeTraits: Type Traits bool Specialization
template<>
struct TypeTraits< bool >
{
typedef bool traits_type;
typedef std::size_t Size;
// Initial Value
static
traits_type
initial_value()
{
return traits_type(); // Use default constructor
}
// Debug Value
static
traits_type
debug_value()
{
return std::numeric_limits< traits_type >::max();
}
// Initial Array Value
static
traits_type
initial_array_value()
{
#ifdef OBJEXXFCL_ARRAY_INIT_DEBUG
return debug_value();
#else
return initial_value();
#endif
}
static std::streamsize const precision = 0; // Precision
static Size const width = 2; // Field width
static int const iwidth = 2; // Field width
};
// TypeTraits: Type Traits short int Specialization
template<>
struct TypeTraits< short int >
{
typedef short int traits_type;
typedef std::size_t Size;
// Initial Value
static
traits_type
initial_value()
{
return traits_type(); // Use default constructor
}
// Debug Value
static
traits_type
debug_value()
{
return std::numeric_limits< traits_type >::max();
}
// Initial Array Value
static
traits_type
initial_array_value()
{
#ifdef OBJEXXFCL_ARRAY_INIT_DEBUG
return debug_value();
#else
return initial_value();
#endif
}
static std::streamsize const precision = 0; // Precision
static Size const width = 7; // Field width
static int const iwidth = 7; // Field width
};
// TypeTraits: Type Traits unsigned short int Specialization
template<>
struct TypeTraits< unsigned short int >
{
typedef unsigned short int traits_type;
typedef std::size_t Size;
// Initial Value
static
traits_type
initial_value()
{
return traits_type(); // Use default constructor
}
// Debug Value
static
traits_type
debug_value()
{
return std::numeric_limits< traits_type >::max();
}
// Initial Array Value
static
traits_type
initial_array_value()
{
#ifdef OBJEXXFCL_ARRAY_INIT_DEBUG
return debug_value();
#else
return initial_value();
#endif
}
static std::streamsize const precision = 0; // Precision
static Size const width = 7; // Field width
static int const iwidth = 7; // Field width
};
// TypeTraits: Type Traits int Specialization
template<>
struct TypeTraits< int >
{
typedef int traits_type;
typedef std::size_t Size;
// Initial Value
static
traits_type
initial_value()
{
return traits_type(); // Use default constructor
}
// Debug Value
static
traits_type
debug_value()
{
return std::numeric_limits< traits_type >::max();
}
// Initial Array Value
static
traits_type
initial_array_value()
{
#ifdef OBJEXXFCL_ARRAY_INIT_DEBUG
return debug_value();
#else
return initial_value();
#endif
}
static std::streamsize const precision = 0; // Precision
static Size const width = 12; // Field width
static int const iwidth = 12; // Field width
};
// TypeTraits: Type Traits unsigned int Specialization
template<>
struct TypeTraits< unsigned int >
{
typedef unsigned int traits_type;
typedef std::size_t Size;
// Initial Value
static
traits_type
initial_value()
{
return traits_type(); // Use default constructor
}
// Debug Value
static
traits_type
debug_value()
{
return std::numeric_limits< traits_type >::max();
}
// Initial Array Value
static
traits_type
initial_array_value()
{
#ifdef OBJEXXFCL_ARRAY_INIT_DEBUG
return debug_value();
#else
return initial_value();
#endif
}
static std::streamsize const precision = 0; // Precision
static Size const width = 12; // Field width
static int const iwidth = 12; // Field width
};
// TypeTraits: Type Traits long int Specialization
template<>
struct TypeTraits< long int >
{
typedef long int traits_type;
typedef std::size_t Size;
// Initial Value
static
traits_type
initial_value()
{
return traits_type(); // Use default constructor
}
// Debug Value
static
traits_type
debug_value()
{
return std::numeric_limits< traits_type >::max();
}
// Initial Array Value
static
traits_type
initial_array_value()
{
#ifdef OBJEXXFCL_ARRAY_INIT_DEBUG
return debug_value();
#else
return initial_value();
#endif
}
static std::streamsize const precision = 0; // Precision
static Size const width = 23; // Field width
static int const iwidth = 23; // Field width
};
// TypeTraits: Type Traits unsigned long int Specialization
template<>
struct TypeTraits< unsigned long int >
{
typedef unsigned long int traits_type;
typedef std::size_t Size;
// Initial Value
static
traits_type
initial_value()
{
return traits_type(); // Use default constructor
}
// Debug Value
static
traits_type
debug_value()
{
return std::numeric_limits< traits_type >::max();
}
// Initial Array Value
static
traits_type
initial_array_value()
{
#ifdef OBJEXXFCL_ARRAY_INIT_DEBUG
return debug_value();
#else
return initial_value();
#endif
}
static std::streamsize const precision = 0; // Precision
static Size const width = 23; // Field width
static int const iwidth = 23; // Field width
};
// TypeTraits: Type Traits long long int Specialization
template<>
struct TypeTraits< long long int >
{
typedef long long int traits_type;
typedef std::size_t Size;
// Initial Value
static
traits_type
initial_value()
{
return traits_type(); // Use default constructor
}
// Debug Value
static
traits_type
debug_value()
{
return std::numeric_limits< traits_type >::max();
}
// Initial Array Value
static
traits_type
initial_array_value()
{
#ifdef OBJEXXFCL_ARRAY_INIT_DEBUG
return debug_value();
#else
return initial_value();
#endif
}
static std::streamsize const precision = 0; // Precision
static Size const width = 23; // Field width
static int const iwidth = 23; // Field width
};
// TypeTraits: Type Traits unsigned long long int Specialization
template<>
struct TypeTraits< unsigned long long int >
{
typedef unsigned long long int traits_type;
typedef std::size_t Size;
// Initial Value
static
traits_type
initial_value()
{
return traits_type(); // Use default constructor
}
// Debug Value
static
traits_type
debug_value()
{
return std::numeric_limits< traits_type >::max();
}
// Initial Array Value
static
traits_type
initial_array_value()
{
#ifdef OBJEXXFCL_ARRAY_INIT_DEBUG
return debug_value();
#else
return initial_value();
#endif
}
static std::streamsize const precision = 0; // Precision
static Size const width = 23; // Field width
static int const iwidth = 23; // Field width
};
// TypeTraits: Type Traits float Specialization
template<>
struct TypeTraits< float >
{
typedef float traits_type;
typedef std::size_t Size;
// Initial Value
static
traits_type
initial_value()
{
return traits_type(); // Use default constructor
}
// Debug Value
static
traits_type
debug_value()
{
return ( std::numeric_limits< traits_type >::has_signaling_NaN ? std::numeric_limits< traits_type >::signaling_NaN() : std::numeric_limits< traits_type >::max() );
}
// Initial Array Value
static
traits_type
initial_array_value()
{
#ifdef OBJEXXFCL_ARRAY_INIT_DEBUG
return debug_value();
#else
return initial_value();
#endif
}
#ifdef OBJEXXFCL_TYPETRAITS_EXTRA_PRECISION
static std::streamsize const precision = 9; // Precision
#else
static std::streamsize const precision = 8; // Precision
#endif
static Size const width = 15; // Field width
static int const iwidth = 15; // Field width
};
// TypeTraits: Type Traits double Specialization
template<>
struct TypeTraits< double >
{
typedef double traits_type;
typedef std::size_t Size;
// Initial Value
static
traits_type
initial_value()
{
return traits_type(); // Use default constructor
}
// Debug Value
static
traits_type
debug_value()
{
return ( std::numeric_limits< traits_type >::has_signaling_NaN ? std::numeric_limits< traits_type >::signaling_NaN() : std::numeric_limits< traits_type >::max() );
}
// Initial Array Value
static
traits_type
initial_array_value()
{
#ifdef OBJEXXFCL_ARRAY_INIT_DEBUG
return debug_value();
#else
return initial_value();
#endif
}
#ifdef OBJEXXFCL_TYPETRAITS_EXTRA_PRECISION
static std::streamsize const precision = 17; // Precision
#else
static std::streamsize const precision = 16; // Precision
#endif
static Size const width = 23; // Field width
static int const iwidth = 23; // Field width
};
// TypeTraits: Type Traits long double Specialization
template<>
struct TypeTraits< long double >
{
typedef long double traits_type;
typedef std::size_t Size;
// Initial Value
static
traits_type
initial_value()
{
return traits_type(); // Use default constructor
}
// Debug Value
static
traits_type
debug_value()
{
return ( std::numeric_limits< traits_type >::has_signaling_NaN ? std::numeric_limits< traits_type >::signaling_NaN() : std::numeric_limits< traits_type >::max() );
}
// Initial Array Value
static
traits_type
initial_array_value()
{
#ifdef OBJEXXFCL_ARRAY_INIT_DEBUG
return debug_value();
#else
return initial_value();
#endif
}
#ifdef OBJEXXFCL_TYPETRAITS_EXTRA_PRECISION
static std::streamsize const precision = 34; // Precision
#else
static std::streamsize const precision = 33; // Precision
#endif
static Size const width = 42; // Field width
static int const iwidth = 42; // Field width
};
// TypeTraits: Type Traits std::complex< float > Specialization
template<>
struct TypeTraits< std::complex< float > >
{
typedef float value_type;
typedef std::complex< float > traits_type;
typedef std::size_t Size;
// Initial Value
static
traits_type
initial_value()
{
return traits_type(); // Use default constructor
}
// Debug Value
static
traits_type
debug_value()
{
return traits_type( TypeTraits< value_type >::debug_value(), TypeTraits< value_type >::debug_value() );
}
// Initial Array Value
static
traits_type
initial_array_value()
{
#ifdef OBJEXXFCL_ARRAY_INIT_DEBUG
return debug_value();
#else
return initial_value();
#endif
}
#ifdef OBJEXXFCL_TYPETRAITS_EXTRA_PRECISION
static std::streamsize const precision = 9; // Precision
#else
static std::streamsize const precision = 8; // Precision
#endif
static Size const width = 33; // Field width
static int const iwidth = 33; // Field width
};
// TypeTraits: Type Traits std::complex< double > Specialization
template<>
struct TypeTraits< std::complex< double > >
{
typedef double value_type;
typedef std::complex< double > traits_type;
typedef std::size_t Size;
// Initial Value
static
traits_type
initial_value()
{
return traits_type(); // Use default constructor
}
// Debug Value
static
traits_type
debug_value()
{
return traits_type( TypeTraits< value_type >::debug_value(), TypeTraits< value_type >::debug_value() );
}
// Initial Array Value
static
traits_type
initial_array_value()
{
#ifdef OBJEXXFCL_ARRAY_INIT_DEBUG
return debug_value();
#else
return initial_value();
#endif
}
#ifdef OBJEXXFCL_TYPETRAITS_EXTRA_PRECISION
static std::streamsize const precision = 17; // Precision
#else
static std::streamsize const precision = 16; // Precision
#endif
static Size const width = 49; // Field width
static int const iwidth = 49; // Field width
};
// TypeTraits: Type Traits std::complex< long double > Specialization
template<>
struct TypeTraits< std::complex< long double > >
{
typedef long double value_type;
typedef std::complex< long double > traits_type;
typedef std::size_t Size;
// Initial Value
static
traits_type
initial_value()
{
return traits_type(); // Use default constructor
}
// Debug Value
static
traits_type
debug_value()
{
return traits_type( TypeTraits< value_type >::debug_value(), TypeTraits< value_type >::debug_value() );
}
// Initial Array Value
static
traits_type
initial_array_value()
{
#ifdef OBJEXXFCL_ARRAY_INIT_DEBUG
return debug_value();
#else
return initial_value();
#endif
}
#ifdef OBJEXXFCL_TYPETRAITS_EXTRA_PRECISION
static std::streamsize const precision = 34; // Precision
#else
static std::streamsize const precision = 33; // Precision
#endif
static Size const width = 83; // Field width
static int const iwidth = 83; // Field width
};
} // ObjexxFCL
#endif // ObjexxFCL_TypeTraits_hh_INCLUDED
// ===== ObjexxFCL/ArrayS.hh =====
#ifndef ObjexxFCL_ArrayS_hh_INCLUDED
#define ObjexxFCL_ArrayS_hh_INCLUDED
// ArrayS: Slice Array Proxy Abstract Base Class Template
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// ObjexxFCL Headers
// C++ Headers
#include <cassert>
#include <cmath>
#include <cstddef>
#include <cstdlib>
#include <initializer_list>
#include <iomanip>
#include <istream>
#include <limits>
#include <ostream>
#include <type_traits>
namespace ObjexxFCL {
// Forward
template< typename > class Array;
// ArrayS: Slice Array Proxy Abstract Base Class Template
template< typename T >
class ArrayS : public BArray
{
private: // Friend
template< typename > friend class ArrayS;
template< typename > friend class Array;
public: // Types
typedef ArrayS< T > Base;
typedef TypeTraits< T > Traits;
// STL style
typedef T value_type;
typedef T & reference;
typedef T const & const_reference;
typedef T * pointer;
typedef T const * const_pointer;
// C++ style
typedef T Value;
typedef T & Reference;
typedef T const & ConstReference;
typedef T * Pointer;
typedef T const * ConstPointer;
protected: // Creation
// Default Constructor
ArrayS() :
data_( nullptr ),
data_beg_( nullptr ),
data_end_( nullptr ),
size_( 0u ),
contiguous_( false )
{}
// Copy Constructor
ArrayS( ArrayS const & a ) :
BArray( a ),
data_( a.data_ ),
data_beg_( a.data_beg_ ),
data_end_( a.data_end_ ),
size_( a.size_ ),
contiguous_( a.contiguous_ )
{}
// Data Constructor
ArrayS( T const * data, size_type const size ) :
data_( const_cast< T * >( data ) ),
data_beg_( nullptr ),
data_end_( nullptr ),
size_( size ),
contiguous_( false )
{}
// Non-Const Data Constructor
ArrayS( T * data, size_type const size ) :
data_( data ),
data_beg_( nullptr ),
data_end_( nullptr ),
size_( size ),
contiguous_( false )
{}
public: // Creation
// Destructor
virtual
~ArrayS() = default;
public: // Predicate
// Active Array Empty?
bool
empty() const
{
return ( size_ == 0u );
}
// Active Array Size Bounded?
bool
size_bounded() const
{
return true;
}
// Contiguous?
bool
contiguous() const
{
return contiguous_;
}
// Conformable?
template< class A >
bool
conformable( A const & a ) const
{
if ( rank() != a.rank() ) return false;
for ( int i = 1; i <= rank(); ++i ) if ( size( i ) != a.size( i ) ) return false;
return true;
}
// Memory Can Overlap a Range?
bool
overlap( T const * const b, T const * const e ) const
{
if ( ( data_beg_ == nullptr ) || ( data_end_ == nullptr ) || ( b == nullptr ) || ( e == nullptr ) ) { // No active memory range(s)
return false;
} else if ( size_ == 0u ) { // No finite memory range
return false;
} else { // Bounded ranges
assert( data_beg_ <= data_end_ );
assert( b <= e );
return ( ( data_beg_ >= b ? data_beg_ : b ) <= ( data_end_ <= e ? data_end_ : e ) );
}
}
// Memory Can Overlap an Array?
template< template< typename > class A >
bool
overlap( A< T > const & a ) const
{
if ( data_ == nullptr ) { // No active memory range
return false;
} else { // Bounded ranges
return overlap( a.data_beg(), a.data_end() );
}
}
public: // Inspector
// Rank
virtual
int
rank() const = 0;
// Active Array Size
size_type
size() const
{
return size_;
}
// Active Array Size
int
isize() const
{
return static_cast< int >( size_ );
}
// Lower Index of a Dimension
int
l( int const d ) const
{
assert( ( 1 <= d ) && ( d <= rank() ) );
#ifdef NDEBUG
static_cast< void >( d ); // Suppress unused warning
#endif
return 1;
}
// Upper Index of a Dimension
virtual
int
u( int const d ) const = 0;
// Size of a Dimension
virtual
size_type
size( int const d ) const = 0;
// Size of a Dimension
virtual
int
isize( int const d ) const = 0;
// Array Data Pointer
T const *
data() const
{
return data_;
}
// Array Data Pointer
T *
data()
{
return data_;
}
// Array Data Begin Pointer
T const *
data_beg() const
{
return data_beg_;
}
// Array Data Begin Pointer
T *
data_beg()
{
return data_beg_;
}
// Array Data End Pointer
T const *
data_end() const
{
return data_end_;
}
// Array Data End Pointer
T *
data_end()
{
return data_end_;
}
protected: // Static Methods
// Is Last Index in [1,u] Range?
static
bool
in_range( int const u, int const i )
{
assert( u > 0 );
return ( ( 1 <= i ) && ( i <= u ) );
}
// Are Last Two Indexes in [1,u] Range?
static
bool
in_range( int const u, int const i, int const j )
{
assert( u > 0 );
return ( ( 1 <= i ) && ( i <= u ) && ( 1 <= j ) && ( j <= u ) );
}
// Slice Constant for a Scalar Index
static
std::int64_t
slice_k( IR const & range, int const i, std::int64_t const multiplier = 1 )
{
assert( range.contains( i ) );
assert( multiplier <= std::numeric_limits< std::int64_t >::max() / std::abs( i ) );
(void)range; // Suppress unused warning in release builds
return i * multiplier;
}
// Slice Constant for a Scalar Index
static
std::int64_t
slice_k( int const u, int const i, std::int64_t const multiplier = 1 )
{
assert( ( 1 <= i ) && ( i <= u ) );
assert( multiplier <= std::numeric_limits< std::int64_t >::max() / std::abs( i ) );
(void)u; // Suppress unused warning in release builds
return i * multiplier;
}
protected: // Data
T * data_; // Pointer to data array
T * data_beg_; // Pointer to data begin
T * data_end_; // Pointer to data end
size_type const size_; // Size of visible array
bool contiguous_; // Contiguous?
}; // ArrayS
// Conformable?
template< typename T, class A >
inline
bool
conformable( ArrayS< T > const & s, A const & a )
{
return s.conformable( a );
}
// Conformable?
template< class A, typename T >
inline
bool
conformable( A const & a, ArrayS< T > const & s )
{
return s.conformable( a );
}
} // ObjexxFCL
#endif // ObjexxFCL_ArrayS_hh_INCLUDED
// ===== ObjexxFCL/CArrayA.fwd.hh =====
#ifndef ObjexxFCL_CArrayA_fwd_hh_INCLUDED
#define ObjexxFCL_CArrayA_fwd_hh_INCLUDED
// CArrayA Forward Declarations
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// C++ Headers
#include <cstddef>
#include <cstdint>
#include <string>
namespace ObjexxFCL {
// Forward
template< typename > class CArrayA;
// Types
} // ObjexxFCL
#endif // ObjexxFCL_CArrayA_fwd_hh_INCLUDED
// ===== ObjexxFCL/CArrayA.hh =====
#ifndef ObjexxFCL_CArrayA_hh_INCLUDED
#define ObjexxFCL_CArrayA_hh_INCLUDED
// CArrayA: Memory-Managed C Array Wrapper with Alignment Support
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// ObjexxFCL Headers
// C++ Headers
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstddef>
#include <initializer_list>
#include <iomanip>
#include <istream>
#include <iterator>
#include <new>
#include <ostream>
#include <type_traits>
#include <utility>
namespace ObjexxFCL {
// CArrayA: Memory-Managed C Array Wrapper with Alignment Support
template< typename T >
class CArrayA
{
private: // Friend
template< typename > friend class CArrayA; // Friendship across value types
public: // Types
typedef AlignedAllocator< T > Aligned;
typedef TypeTraits< T > Traits;
typedef typename std::conditional< std::is_scalar< T >::value, T const, T const & >::type Tc;
typedef typename std::conditional< std::is_scalar< T >::value, typename std::remove_const< T >::type, T const & >::type Tr;
// STL Style
typedef T value_type;
typedef T & reference;
typedef T const & const_reference;
typedef T * pointer;
typedef T const * const_pointer;
typedef T * iterator;
typedef T const * const_iterator;
typedef std::reverse_iterator< T * > reverse_iterator;
typedef std::reverse_iterator< T const * > const_reverse_iterator;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
// C++ Style
typedef T Value;
typedef T & Reference;
typedef T const & ConstReference;
typedef T * Pointer;
typedef T const * ConstPointer;
typedef T * Iterator;
typedef T const * ConstIterator;
typedef std::reverse_iterator< T * > ReverseIterator;
typedef std::reverse_iterator< T const * > ConstReverseIterator;
typedef std::size_t Size;
typedef std::ptrdiff_t Difference;
// Types to prevent compile failure when std::distance is in scope
typedef void iterator_category;
public: // Creation
// Default Constructor
CArrayA() :
size_( 0u ),
mem_( nullptr ),
data_( nullptr )
{}
// Copy Constructor
CArrayA( CArrayA const & a ) :
size_( a.size_ ),
mem_( Aligned::allocate( size_ ) ),
data_( Aligned::data( mem_ ) )
{
for ( size_type i = 0; i < size_; ++i ) {
new ( data_ + i ) T( a.data_[ i ] );
}
}
// Move Constructor
CArrayA( CArrayA && a ) noexcept :
size_( a.size_ ),
mem_( a.mem_ ),
data_( a.data_ )
{
a.size_ = 0u;
a.mem_ = a.data_ = nullptr;
}
// Copy Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
CArrayA( CArrayA< U > const & a ) :
size_( a.size_ ),
mem_( Aligned::allocate( size_ ) ),
data_( Aligned::data( mem_ ) )
{
for ( size_type i = 0; i < size_; ++i ) {
new ( data_ + i ) T( a.data_[ i ] );
}
}
// Pointer + Size Constructor
CArrayA(
T const * const p,
size_type const size
) :
size_( size ),
mem_( Aligned::allocate( size_ ) ),
data_( Aligned::data( mem_ ) )
{
for ( size_type i = 0; i < size_; ++i ) {
new ( data_ + i ) T( p[ i ] );
}
}
// Pointer + Size Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
CArrayA(
U const * const p,
size_type const size
) :
size_( size ),
mem_( Aligned::allocate( size_ ) ),
data_( Aligned::data( mem_ ) )
{
for ( size_type i = 0; i < size_; ++i ) {
new ( data_ + i ) T( p[ i ] );
}
}
// Iterator Range Constructor Template
template< typename InputIterator >
CArrayA(
InputIterator const beg,
InputIterator const end
) :
size_( end - beg ),
mem_( Aligned::allocate( size_ ) ),
data_( Aligned::data( mem_ ) )
{
if ( size_ > 0u ) {
InputIterator k( beg );
for ( size_type i = 0; i < size_; ++i, ++k ) {
new ( data_ + i ) T( *k );
}
}
}
// Size Constructor: Built-in types are default, not zero, initialized for performance
explicit
CArrayA( size_type const size ) :
size_( size ),
mem_( Aligned::allocate( size_ ) ),
data_( Aligned::data( mem_ ) )
{
for ( size_type i = 0; i < size_; ++i ) {
new ( data_ + i ) T;
}
}
// Size + Uniform Value Constructor
CArrayA(
size_type const size,
Tc t
) :
size_( size ),
mem_( Aligned::allocate( size_ ) ),
data_( Aligned::data( mem_ ) )
{
for ( size_type i = 0; i < size_; ++i ) {
new ( data_ + i ) T( t );
}
}
// Initializer List Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
CArrayA( std::initializer_list< U > const l ) :
size_( l.size() ),
mem_( Aligned::allocate( size_ ) ),
data_( Aligned::data( mem_ ) )
{
auto li( l.begin() );
for ( size_type i = 0; i < size_; ++i, ++li ) {
new ( data_ + i ) T( *li );
}
}
// Destructor
~CArrayA()
{
destroy();
}
public: // Conversion
// Active?
operator bool() const
{
return ( data_ != nullptr );
}
// Data
operator T const *() const
{
return data_;
}
// Data
operator T *()
{
return data_;
}
public: // Assignment
// Copy Assignment
CArrayA &
operator =( CArrayA const & a )
{
if ( this != &a ) {
if ( size_ != a.size_ ) {
destroy();
size_ = a.size_;
mem_ = Aligned::allocate( size_ );
data_ = Aligned::data( mem_ );
for ( size_type i = 0; i < size_; ++i ) {
new ( data_ + i ) T( a.data_[ i ] );
}
} else {
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] = a.data_[ i ];
}
}
}
return *this;
}
// Move Assignment
CArrayA &
operator =( CArrayA && a ) noexcept
{
assert( this != &a );
destroy();
size_ = a.size_;
mem_ = a.mem_;
data_ = a.data_;
a.size_ = 0u;
a.mem_ = a.data_ = nullptr;
return *this;
}
// Copy Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
CArrayA &
operator =( CArrayA< U > const & a )
{
if ( size_ != a.size_ ) {
destroy();
size_ = a.size_;
mem_ = Aligned::allocate( size_ );
data_ = Aligned::data( mem_ );
for ( size_type i = 0; i < size_; ++i ) {
new ( data_ + i ) T( a.data_[ i ] );
}
} else {
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] = T( a.data_[ i ] );
}
}
return *this;
}
// Uniform Value Assignment
CArrayA &
operator =( Tc t )
{
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] = t;
}
return *this;
}
// Initializer List Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
CArrayA &
operator =( std::initializer_list< U > const l )
{
assert( l.size() == size_ );
std::copy( l.begin(), l.end(), data_ );
return *this;
}
// Pointer + Size Assignment
CArrayA &
assign(
T const * const p,
size_type const size
)
{
if ( size_ != size ) {
destroy();
size_ = size;
mem_ = Aligned::allocate( size_ );
data_ = Aligned::data( mem_ );
for ( size_type i = 0; i < size_; ++i ) {
new ( data_ + i ) T( p[ i ] );
}
} else {
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] = p[ i ];
}
}
return *this;
}
// Pointer + Size Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
CArrayA &
assign(
U const * const p,
size_type const size
)
{
if ( size_ != size ) {
destroy();
size_ = size;
mem_ = Aligned::allocate( size_ );
data_ = Aligned::data( mem_ );
for ( size_type i = 0; i < size_; ++i ) {
new ( data_ + i ) T( p[ i ] );
}
} else {
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] = T( p[ i ] );
}
}
return *this;
}
// Iterator Range Assignment Template
template< typename InputIterator >
CArrayA &
assign(
InputIterator const beg,
InputIterator const end
)
{
size_type const size( end - beg );
if ( size_ != size ) {
destroy();
size_ = size;
mem_ = Aligned::allocate( size_ );
data_ = Aligned::data( mem_ );
if ( size_ > 0u ) {
InputIterator k( beg );
for ( size_type i = 0; i < size_; ++i, ++k ) {
new ( data_ + i ) T( *k );
}
}
} else {
if ( size_ > 0u ) {
InputIterator k( beg );
for ( size_type i = 0; i < size_; ++i, ++k ) {
data_[ i ] = T( *k );
}
}
}
return *this;
}
// Size + Value Assignment
CArrayA &
assign(
size_type const size,
Tc t
)
{
if ( size_ != size ) { // Set to new array with uniform values
CArrayA( size, t ).swap( *this );
} else { // Set to uniform value
(*this) = t;
}
return *this;
}
// += CArrayA
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
CArrayA &
operator +=( CArrayA< U > const & a )
{
assert( size_ == a.size_ );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] += T( a.data_[ i ] );
}
return *this;
}
// -= CArrayA
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
CArrayA &
operator -=( CArrayA< U > const & a )
{
assert( size_ == a.size_ );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] -= T( a.data_[ i ] );
}
return *this;
}
// += Value
CArrayA &
operator +=( Tc t )
{
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] += t;
}
return *this;
}
// -= Value
CArrayA &
operator -=( Tc t )
{
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] -= t;
}
return *this;
}
// *= Value
CArrayA &
operator *=( Tc t )
{
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] *= t;
}
return *this;
}
// /= Value
template< typename U, class = typename std::enable_if< std::is_floating_point< U >::value && std::is_assignable< T&, U >::value >::type >
CArrayA &
operator /=( U const & u )
{
assert( u != U( 0 ) );
U const inv_u( U( 1 ) / u );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] *= inv_u;
}
return *this;
}
// /= Value
template< typename U, class = typename std::enable_if< ! std::is_floating_point< U >::value && std::is_assignable< T&, U >::value >::type, typename = void >
CArrayA &
operator /=( U const & u )
{
assert( u != U( 0 ) );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] /= u;
}
return *this;
}
public: // Predicate
// Active?
bool
active() const
{
return ( data_ != nullptr );
}
// Empty?
bool
empty() const
{
return ( size_ == 0u );
}
public: // Inspector
// Size
size_type
size() const
{
return size_;
}
// Lower Index
size_type
l() const
{
return 0u;
}
// Upper index
size_type
u() const
{
return size_ - 1u; // npos if size_ == 0
}
// First Element
Tr
front() const
{
assert( size_ > 0u );
return data_[ 0 ];
}
// Last Element
Tr
back() const
{
assert( size_ > 0u );
return data_[ size_ - 1 ];
}
// Length
T
length() const
{
T length_sq( T( 0 ) );
for ( size_type i = 0; i < size_; ++i ) {
length_sq += data_[ i ] * data_[ i ];
}
return std::sqrt( length_sq );
}
// Length Squared
T
length_squared() const
{
T length_sq( T( 0 ) );
for ( size_type i = 0; i < size_; ++i ) {
length_sq += data_[ i ] * data_[ i ];
}
return length_sq;
}
public: // Modifier
// First Element
T &
front()
{
assert( size_ > 0u );
return data_[ 0 ];
}
// Last Element
T &
back()
{
assert( size_ > 0u );
return data_[ size_ - 1 ];
}
// Resize: Values not Preserved
// Built-in values are uninitialized if size changes
CArrayA &
size( size_type const size )
{
if ( size_ != size ) { // Set to new array
CArrayA( size ).swap( *this );
}
return *this;
}
// Resize to Size With Fill Value: Values Preserved
CArrayA &
resize(
size_type const size,
Tc fill = T()
)
{
if ( size_ < size ) {
CArrayA a( size, fill ); // New array: Elements set to fill fill
for ( size_type i = 0; i < size_; ++i ) { // Copy current values
a.data_[ i ] = data_[ i ];
}
swap( a ); // Swap in new array
} else if ( size_ > size ) {
CArrayA a( size ); // New array
for ( size_type i = 0; i < size; ++i ) { // Copy current values within new range
a.data_[ i ] = data_[ i ];
}
swap( a ); // Swap in new array
}
return *this;
}
// Swap
void
swap( CArrayA & a )
{
std::swap( size_, a.size_ );
std::swap( mem_, a.mem_ );
std::swap( data_, a.data_ );
}
// Clear
CArrayA &
clear()
{
destroy();
size_ = 0u;
mem_ = data_ = nullptr;
return *this;
}
// Normalize to Unit Length
CArrayA &
normalize()
{
T const length_( length() );
assert( length_ > T( 0 ) );
operator /=( length_ );
return *this;
}
public: // Subscript
// CArrayA[ i ] const: 0-Based Indexing
template< typename I, class = typename std::enable_if< std::is_integral< I >::value && std::is_unsigned< I >::value && std::is_const< T >::value >::type >
Tr
operator []( I const i ) const
{
assert( i < size_ );
return data_[ i ];
}
// CArrayA[ i ] const: 0-Based Indexing
template< typename I, class = typename std::enable_if< std::is_integral< I >::value && std::is_signed< I >::value && std::is_const< T >::value >::type, typename = void >
Tr
operator []( I const i ) const
{
assert( ( i >= 0 ) && ( static_cast< size_type >( i ) < size_ ) );
return data_[ i ];
}
// CArrayA[ i ]: 0-Based Indexing
template< typename I, class = typename std::enable_if< std::is_integral< I >::value && std::is_unsigned< I >::value >::type >
T &
operator []( I const i )
{
assert( i < size_ );
return data_[ i ];
}
// CArrayA[ i ]: 0-Based Indexing
template< typename I, class = typename std::enable_if< std::is_integral< I >::value && std::is_signed< I >::value >::type, typename = void >
T &
operator []( I const i )
{
assert( ( i >= 0 ) && ( static_cast< size_type >( i ) < size_ ) );
return data_[ i ];
}
// CArrayA( i ) const: 1-Based Indexing
template< typename I, class = typename std::enable_if< std::is_integral< I >::value && std::is_unsigned< I >::value && std::is_const< T >::value >::type >
Tr
operator ()( I const i ) const
{
assert( ( i > 0u ) && ( i <= size_ ) );
return data_[ i - 1 ];
}
// CArrayA( i ) const: 1-Based Indexing
template< typename I, class = typename std::enable_if< std::is_integral< I >::value && std::is_signed< I >::value && std::is_const< T >::value >::type, typename = void >
Tr
operator ()( I const i ) const
{
assert( ( i > 0 ) && ( static_cast< size_type >( i ) <= size_ ) );
return data_[ i - 1 ];
}
// CArrayA( i ): 1-Based Indexing
template< typename I, class = typename std::enable_if< std::is_integral< I >::value && std::is_unsigned< I >::value >::type >
T &
operator ()( I const i )
{
assert( ( i > 0u ) && ( i <= size_ ) );
return data_[ i - 1 ];
}
// CArrayA( i ): 1-Based Indexing
template< typename I, class = typename std::enable_if< std::is_integral< I >::value && std::is_signed< I >::value >::type, typename = void >
T &
operator ()( I const i )
{
assert( ( i > 0 ) && ( static_cast< size_type >( i ) <= size_ ) );
return data_[ i - 1 ];
}
public: // Iterator
// Begin Iterator
const_iterator
begin() const
{
return data_;
}
// Begin Iterator
iterator
begin()
{
return data_;
}
// End Iterator
const_iterator
end() const
{
return ( data_ != nullptr ? data_ + size_ : nullptr );
}
// End Iterator
iterator
end()
{
return ( data_ != nullptr ? data_ + size_ : nullptr );
}
// Reverse Begin Iterator
const_reverse_iterator
rbegin() const
{
return const_reverse_iterator( data_ != nullptr ? data_ + size_ : nullptr );
}
// Reverse Begin Iterator
reverse_iterator
rbegin()
{
return reverse_iterator( data_ != nullptr ? data_ + size_ : nullptr );
}
// Reverse End Iterator
const_reverse_iterator
rend() const
{
return const_reverse_iterator( data_ );
}
// Reverse End Iterator
reverse_iterator
rend()
{
return reverse_iterator( data_ );
}
public: // Array Accessor
// C Array const Accessor
T const *
operator ()() const
{
return data_;
}
// C Array Non-const Accessor
T *
operator ()()
{
return data_;
}
private: // Methods
// Destruct Elements and Delete Array Memory (Doesn't Nullify Pointers)
void
destroy()
{
size_type i( size_ );
while ( i ) data_[ --i ].~T();
::operator delete( mem_ );
}
private: // Data
size_type size_; // Number of array elements
void * mem_; // Pointer to raw memory
T * data_; // Pointer to data
}; // CArrayA
// Functions
// Magnitude
template< typename T >
inline
T
magnitude( CArrayA< T > const & a )
{
T mag_sq( T( 0 ) );
for ( typename CArrayA< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
mag_sq += a[ i ] * a[ i ];
}
return std::sqrt( mag_sq );
}
// Magnitude Squared
template< typename T >
inline
T
magnitude_squared( CArrayA< T > const & a )
{
T mag_sq( T( 0 ) );
for ( typename CArrayA< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
mag_sq += a[ i ] * a[ i ];
}
return mag_sq;
}
// Distance
template< typename T >
inline
T
distance( CArrayA< T > const & a, CArrayA< T > const & b )
{
assert( a.size() == b.size() );
T distance_sq( T( 0 ) );
for ( typename CArrayA< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
T const distance_i( a[ i ] - b[ i ] );
distance_sq += distance_i * distance_i;
}
return std::sqrt( distance_sq );
}
// Distance Squared
template< typename T >
inline
T
distance_squared( CArrayA< T > const & a, CArrayA< T > const & b )
{
assert( a.size() == b.size() );
T distance_sq( T( 0 ) );
for ( typename CArrayA< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
T const distance_i( a[ i ] - b[ i ] );
distance_sq += distance_i * distance_i;
}
return distance_sq;
}
// Dot Product
template< typename T >
inline
T
dot( CArrayA< T > const & a, CArrayA< T > const & b )
{
assert( a.size() == b.size() );
T sum( T( 0 ) );
for ( typename CArrayA< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
sum += a[ i ] * b[ i ];
}
return sum;
}
// Dot Product
template< typename T >
inline
T
dot_product( CArrayA< T > const & a, CArrayA< T > const & b )
{
assert( a.size() == b.size() );
T sum( T( 0 ) );
for ( typename CArrayA< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
sum += a[ i ] * b[ i ];
}
return sum;
}
// Swap
template< typename T >
inline
void
swap( CArrayA< T > & a, CArrayA< T > & b )
{
a.swap( b );
}
// Comparison
// Are Two CArrayAs Comparable?
template< typename T >
inline
bool
comparable( CArrayA< T > const & a, CArrayA< T > const & b )
{
return ( a.size() == b.size() );
}
// CArrayA == CArrayA
template< typename T >
inline
bool
operator ==( CArrayA< T > const & a, CArrayA< T > const & b )
{
if ( &a == &b ) { // Same objects
return true;
} else if ( a.size() != b.size() ) { // Sizes differ
return false;
} else { // Compare values
for ( typename CArrayA< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( a[ i ] == b[ i ] ) ) return false;
}
return true;
}
}
// CArrayA != CArrayA
template< typename T >
inline
bool
operator !=( CArrayA< T > const & a, CArrayA< T > const & b )
{
return !( a == b );
}
// CArrayA < CArrayA
template< typename T >
inline
bool
operator <( CArrayA< T > const & a, CArrayA< T > const & b )
{
if ( &a == &b ) { // Same objects
return false;
} else if ( a.size() != b.size() ) { // Sizes differ
return false;
} else { // Compare values
for ( typename CArrayA< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( a[ i ] < b[ i ] ) ) return false;
}
return true;
}
}
// CArrayA <= CArrayA
template< typename T >
inline
bool
operator <=( CArrayA< T > const & a, CArrayA< T > const & b )
{
if ( &a == &b ) { // Same objects
return true;
} else if ( a.size() != b.size() ) { // Sizes differ
return false;
} else { // Compare values
for ( typename CArrayA< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( a[ i ] <= b[ i ] ) ) return false;
}
return true;
}
}
// CArrayA >= CArrayA
template< typename T >
inline
bool
operator >=( CArrayA< T > const & a, CArrayA< T > const & b )
{
if ( &a == &b ) { // Same objects
return true;
} else if ( a.size() != b.size() ) { // Sizes differ
return false;
} else { // Compare values
for ( typename CArrayA< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( a[ i ] >= b[ i ] ) ) return false;
}
return true;
}
}
// CArrayA > CArrayA
template< typename T >
inline
bool
operator >( CArrayA< T > const & a, CArrayA< T > const & b )
{
if ( &a == &b ) { // Same objects
return false;
} else if ( a.size() != b.size() ) { // Sizes differ
return false;
} else { // Compare values
for ( typename CArrayA< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( a[ i ] > b[ i ] ) ) return false;
}
return true;
}
}
// CArrayA == Value
template< typename T >
inline
bool
operator ==( CArrayA< T > const & a, typename CArrayA< T >::Tc t )
{
for ( typename CArrayA< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( a[ i ] != t ) return false;
}
return true;
}
// CArrayA != Value
template< typename T >
inline
bool
operator !=( CArrayA< T > const & a, typename CArrayA< T >::Tc t )
{
return !( a == t );
}
// CArrayA < Value
template< typename T >
inline
bool
operator <( CArrayA< T > const & a, typename CArrayA< T >::Tc t )
{
for ( typename CArrayA< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( a[ i ] < t ) ) return false;
}
return true;
}
// CArrayA <= Value
template< typename T >
inline
bool
operator <=( CArrayA< T > const & a, typename CArrayA< T >::Tc t )
{
for ( typename CArrayA< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( a[ i ] <= t ) ) return false;
}
return true;
}
// CArrayA >= Value
template< typename T >
inline
bool
operator >=( CArrayA< T > const & a, typename CArrayA< T >::Tc t )
{
for ( typename CArrayA< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( a[ i ] >= t ) ) return false;
}
return true;
}
// CArrayA > Value
template< typename T >
inline
bool
operator >( CArrayA< T > const & a, typename CArrayA< T >::Tc t )
{
for ( typename CArrayA< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( a[ i ] > t ) ) return false;
}
return true;
}
// Value == CArrayA
template< typename T >
inline
bool
operator ==( typename CArrayA< T >::Tc t, CArrayA< T > const & a )
{
return ( a == t );
}
// Value != CArrayA
template< typename T >
inline
bool
operator !=( typename CArrayA< T >::Tc t, CArrayA< T > const & a )
{
return !( t == a );
}
// Value < CArrayA
template< typename T >
inline
bool
operator <( typename CArrayA< T >::Tc t, CArrayA< T > const & a )
{
for ( typename CArrayA< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( t < a[ i ] ) ) return false;
}
return true;
}
// Value <= CArrayA
template< typename T >
inline
bool
operator <=( typename CArrayA< T >::Tc t, CArrayA< T > const & a )
{
for ( typename CArrayA< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( t <= a[ i ] ) ) return false;
}
return true;
}
// Value >= CArrayA
template< typename T >
inline
bool
operator >=( typename CArrayA< T >::Tc t, CArrayA< T > const & a )
{
for ( typename CArrayA< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( t >= a[ i ] ) ) return false;
}
return true;
}
// Value > CArrayA
template< typename T >
inline
bool
operator >( typename CArrayA< T >::Tc t, CArrayA< T > const & a )
{
for ( typename CArrayA< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( t > a[ i ] ) ) return false;
}
return true;
}
// Generator
// -CArrayA
template< typename T >
inline
CArrayA< T >
operator -( CArrayA< T > const & a )
{
CArrayA< T > r( a );
r *= T( -1 );
return r;
}
// CArrayA + CArrayA
template< typename T >
inline
CArrayA< T >
operator +( CArrayA< T > const & a, CArrayA< T > const & b )
{
CArrayA< T > r( a );
r += b;
return r;
}
// CArrayA - CArrayA
template< typename T >
inline
CArrayA< T >
operator -( CArrayA< T > const & a, CArrayA< T > const & b )
{
CArrayA< T > r( a );
r -= b;
return r;
}
// CArrayA + Value
template< typename T >
inline
CArrayA< T >
operator +( CArrayA< T > const & a, typename CArrayA< T >::Tc t )
{
CArrayA< T > r( a );
r += t;
return r;
}
// Value + CArrayA
template< typename T >
inline
CArrayA< T >
operator +( typename CArrayA< T >::Tc t, CArrayA< T > const & a )
{
CArrayA< T > r( a );
r += t;
return r;
}
// CArrayA - Value
template< typename T >
inline
CArrayA< T >
operator -( CArrayA< T > const & a, typename CArrayA< T >::Tc t )
{
CArrayA< T > r( a );
r -= t;
return r;
}
// Value - CArrayA
template< typename T >
inline
CArrayA< T >
operator -( typename CArrayA< T >::Tc t, CArrayA< T > const & a )
{
CArrayA< T > r( -a );
r += t;
return r;
}
// CArrayA * Value
template< typename T >
inline
CArrayA< T >
operator *( CArrayA< T > const & a, typename CArrayA< T >::Tc t )
{
CArrayA< T > r( a );
r *= t;
return r;
}
// Value * CArrayA
template< typename T >
inline
CArrayA< T >
operator *( typename CArrayA< T >::Tc t, CArrayA< T > const & a )
{
CArrayA< T > r( a );
r *= t;
return r;
}
// CArrayA / Value
template< typename T >
inline
CArrayA< T >
operator /( CArrayA< T > const & a, typename CArrayA< T >::Tc t )
{
CArrayA< T > r( a );
r /= t;
return r;
}
// Stream >> CArrayA
template< typename T >
inline
std::istream &
operator >>( std::istream & stream, CArrayA< T > & a )
{
typedef typename CArrayA< T >::size_type size_type;
if ( stream && ( ! a.emtpy() ) ) {
for ( size_type i = 0, e = a.size(); i < e; ++i ) {
stream >> a[ i ];
if ( ! stream ) break;
}
}
return stream;
}
// Stream << CArrayA
template< typename T >
inline
std::ostream &
operator <<( std::ostream & stream, CArrayA< T > const & a )
{
using std::setw;
typedef TypeTraits< T > Traits;
typedef typename CArrayA< T >::size_type size_type;
if ( stream && ( ! a.emtpy() ) ) {
std::ios_base::fmtflags const old_flags( stream.flags() );
std::streamsize const old_precision( stream.precision( Traits::precision ) );
stream << std::right << std::showpoint << std::uppercase;
size_type const e( a.size() - 1 );
int const w( Traits::iwidth );
for ( size_type i = 0; i < e; ++i ) {
stream << setw( w ) << a[ i ] << ' ';
} stream << setw( w ) << a[ e ];
stream.precision( old_precision );
stream.flags( old_flags );
}
return stream;
}
} // ObjexxFCL
#endif // ObjexxFCL_CArrayA_hh_INCLUDED
// ===== ObjexxFCL/InitializerSentinel.hh =====
#ifndef ObjexxFCL_InitializerSentinel_hh_INCLUDED
#define ObjexxFCL_InitializerSentinel_hh_INCLUDED
// InitializerSentinel: Array Constructor Initializer Sentinel Class
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
namespace ObjexxFCL {
namespace internal {
// InitializerSentinel: Array Constructor Initializer Sentinel Class
struct InitializerSentinel
{
}; // InitializerSentinel
} // internal
} // ObjexxFCL
#endif // ObjexxFCL_InitializerSentinel_hh_INCLUDED
// ===== ObjexxFCL/MArray.hh =====
#ifndef ObjexxFCL_MArray_hh_INCLUDED
#define ObjexxFCL_MArray_hh_INCLUDED
// MArray: Member Array Proxy Abstract Base Class Template
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// ObjexxFCL Headers
// C++ Headers
#include <cassert>
#include <cstddef>
#include <initializer_list>
#include <iomanip>
#include <istream>
#include <ostream>
#include <type_traits>
namespace ObjexxFCL {
// MArray: Member Array Proxy Abstract Base Class Template
template< class A, typename T >
class MArray : public BArray
{
public: // Types
typedef A ArrayType;
typedef typename A::value_type Class;
typedef T Class::* MPtr;
typedef TypeTraits< T > Traits;
// STL style
typedef T value_type;
typedef T & reference;
typedef T const & const_reference;
typedef T * pointer;
typedef T const * const_pointer;
// C++ style
typedef T Value;
typedef T & Reference;
typedef T const & ConstReference;
typedef T * Pointer;
typedef T const * ConstPointer;
protected: // Creation
// Copy Constructor
MArray( MArray const & a ) :
BArray( a ),
array_( a.array_ ),
pmem_( a.pmem_ )
{}
// Constructor
MArray( A & a, T Class::* pmem ) :
array_( a ),
pmem_( pmem )
{}
public: // Creation
// Destructor
virtual
~MArray() = default;
// Copy Assignment
MArray &
operator =( MArray const & a ) = delete;
public: // Predicate
// Allocated
bool
allocated() const
{
return array_.allocated();
}
// Active Array Empty?
bool
empty() const
{
return ( array_.size() == 0u );
}
// Active Array Size Bounded?
bool
size_bounded() const
{
return array_.size_bounded();
}
// Conformable?
template< class Ar >
bool
conformable( Ar const & a ) const
{
return array_.conformable( a );
}
public: // Inspector
// Rank
virtual
int
rank() const = 0;
// Size
size_type
size() const
{
return array_.size();
}
// Size
int
isize() const
{
return array_.isize();
}
// IndexRange of a Dimension
IR
I( int const d ) const
{
return IR( 1, u( d ) );
}
// Lower Index of a Dimension
int
l( int const d ) const
{
assert( ( 1 <= d ) && ( d <= rank() ) );
#ifdef NDEBUG
static_cast< void >( d ); // Suppress unused warning
#endif
return 1;
}
// Upper Index of a Dimension
int
u( int const d ) const
{
return array_.isize( d );
}
// Size of a Dimension
size_type
size( int const d ) const
{
return array_.size( d );
}
// Size of a Dimension
int
isize( int const d ) const
{
return array_.isize( d );
}
// Proxied Array
A const &
array() const
{
return array_;
}
// Proxied Array
A &
array()
{
return array_;
}
protected: // Methods
// Array Index of an Index of Dimension
int
j( int const d, int const i ) const
{
return array_.l( d ) + i - 1;
}
// Array Index of Dimension 1
int
j1( int const i ) const
{
return array_.l1() + i - 1;
}
protected: // Static Methods
// Is Last Index in [1,u] Range?
static
bool
in_range( int const u, int const i )
{
assert( u > 0 );
return ( ( 1 <= i ) && ( i <= u ) );
}
// Are Last Two Indexes in [1,u] Range?
static
bool
in_range( int const u, int const i, int const j )
{
assert( u > 0 );
return ( ( 1 <= i ) && ( i <= u ) && ( 1 <= j ) && ( j <= u ) );
}
protected: // Data
A & array_; // A
T Class::* pmem_; // Pointer to member
}; // MArray
// Conformable?
template< class A, typename T, class Ar >
inline
bool
conformable( MArray< A, T > const & a, Ar const & b )
{
return a.conformable( b );
}
// Conformable?
template< class A, typename T, class Ar >
inline
bool
conformable( Ar const & a, MArray< A, T > const & b )
{
return b.conformable( a );
}
} // ObjexxFCL
#endif // ObjexxFCL_MArray_hh_INCLUDED
// ===== ObjexxFCL/ProxySentinel.hh =====
#ifndef ObjexxFCL_ProxySentinel_hh_INCLUDED
#define ObjexxFCL_ProxySentinel_hh_INCLUDED
// ProxySentinel: Array Constructor Proxy Sentinel Class
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
namespace ObjexxFCL {
namespace internal {
// ProxySentinel: Array Constructor Proxy Sentinel Class
struct ProxySentinel
{
}; // ProxySentinel
} // internal
} // ObjexxFCL
#endif // ObjexxFCL_ProxySentinel_hh_INCLUDED
// ===== ObjexxFCL/Vector2.fwd.hh =====
#ifndef ObjexxFCL_Vector2_fwd_hh_INCLUDED
#define ObjexxFCL_Vector2_fwd_hh_INCLUDED
// Vector2 Forward Declarations
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// C++ Headers
#include <cstddef>
#include <cstdint>
#include <string>
namespace ObjexxFCL {
// Forward
template< typename > class Vector2;
// Types
} // ObjexxFCL
#endif // ObjexxFCL_Vector2_fwd_hh_INCLUDED
// ===== ObjexxFCL/Fmath.hh =====
#ifndef ObjexxFCL_Fmath_hh_INCLUDED
#define ObjexxFCL_Fmath_hh_INCLUDED
// Fortran Intrinsic-Compatible and General Math Functions
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// C++ Headers
#include <algorithm>
#include <cassert>
#include <cfloat>
#include <cmath>
#include <complex>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <limits>
#include <type_traits>
namespace ObjexxFCL {
typedef std::intmax_t SSize;
// min /////
// min( short, short )
inline
short int
min( short int const a, short int const b )
{
return ( a < b ? a : b );
}
// min( int, int )
inline
int
min( int const a, int const b )
{
return ( a < b ? a : b );
}
// min( long, long )
inline
long int
min( long int const a, long int const b )
{
return ( a < b ? a : b );
}
// min( unsigned short, unsigned short )
inline
unsigned short int
min( unsigned short int const a, unsigned short int const b )
{
return ( a < b ? a : b );
}
// min( unsigned, unsigned )
inline
unsigned int
min( unsigned int const a, unsigned int const b )
{
return ( a < b ? a : b );
}
// min( unsigned long, unsigned long )
inline
unsigned long int
min( unsigned long int const a, unsigned long int const b )
{
return ( a < b ? a : b );
}
// min( float, float )
inline
float
min( float const a, float const b )
{
return ( a < b ? a : b );
}
// min( double, double )
inline
double
min( double const a, double const b )
{
return ( a < b ? a : b );
}
// min( long double, long double )
inline
long double
min( long double const a, long double const b )
{
return ( a < b ? a : b );
}
// Use std::min for 2 arguments not covered by the above overloads
using std::min;
// min( short, short, short )
inline
short int
min( short int const a, short int const b, short int const c )
{
return ( a < b ? ( a < c ? a : c ) : ( b < c ? b : c ) );
}
// min( short, short, short, short, ... )
template< typename... Ts >
inline
short int
min( short int const a, short int const b, short int const c, short int const d, Ts const &... o )
{
return min( a < b ? a : b, c < d ? c : d, o... );
}
// min( int, int, int )
inline
int
min( int const a, int const b, int const c )
{
return ( a < b ? ( a < c ? a : c ) : ( b < c ? b : c ) );
}
// min( int, int, int, int, ... )
template< typename... Ts >
inline
int
min( int const a, int const b, int const c, int const d, Ts const &... o )
{
return min( a < b ? a : b, c < d ? c : d, o... );
}
// min( long, long, long )
inline
long int
min( long int const a, long int const b, long int const c )
{
return ( a < b ? ( a < c ? a : c ) : ( b < c ? b : c ) );
}
// min( long, long, long, long, ... )
template< typename... Ts >
inline
long int
min( long int const a, long int const b, long int const c, long int const d, Ts const &... o )
{
return min( a < b ? a : b, c < d ? c : d, o... );
}
// min( unsigned short, unsigned short, unsigned short )
inline
unsigned short int
min( unsigned short int const a, unsigned short int const b, unsigned short int const c )
{
return ( a < b ? ( a < c ? a : c ) : ( b < c ? b : c ) );
}
// min( unsigned short, unsigned short, unsigned short, unsigned short, ... )
template< typename... Ts >
inline
unsigned short int
min( unsigned short int const a, unsigned short int const b, unsigned short int const c, unsigned short int const d, Ts const &... o )
{
return min( a < b ? a : b, c < d ? c : d, o... );
}
// min( unsigned, unsigned, unsigned )
inline
unsigned int
min( unsigned int const a, unsigned int const b, unsigned int const c )
{
return ( a < b ? ( a < c ? a : c ) : ( b < c ? b : c ) );
}
// min( unsigned, unsigned, unsigned, unsigned, ... )
template< typename... Ts >
inline
unsigned int
min( unsigned int const a, unsigned int const b, unsigned int const c, unsigned int const d, Ts const &... o )
{
return min( a < b ? a : b, c < d ? c : d, o... );
}
// min( unsigned long, unsigned long, unsigned long )
inline
unsigned long int
min( unsigned long int const a, unsigned long int const b, unsigned long int const c )
{
return ( a < b ? ( a < c ? a : c ) : ( b < c ? b : c ) );
}
// min( unsigned long, unsigned long, unsigned long, unsigned long, ... )
template< typename... Ts >
inline
unsigned long int
min( unsigned long int const a, unsigned long int const b, unsigned long int const c, unsigned long int const d, Ts const &... o )
{
return min( a < b ? a : b, c < d ? c : d, o... );
}
// min( float, float, float )
inline
float
min( float const a, float const b, float const c )
{
return ( a < b ? ( a < c ? a : c ) : ( b < c ? b : c ) );
}
// min( float, float, float, float, ... )
template< typename... Ts >
inline
float
min( float const a, float const b, float const c, float const d, Ts const &... o )
{
return min( a < b ? a : b, c < d ? c : d, o... );
}
// min( double, double, double )
inline
double
min( double const a, double const b, double const c )
{
return ( a < b ? ( a < c ? a : c ) : ( b < c ? b : c ) );
}
// min( double, double, double, double, ... )
template< typename... Ts >
inline
double
min( double const a, double const b, double const c, double const d, Ts const &... o )
{
return min( a < b ? a : b, c < d ? c : d, o... );
}
// min( long double, long double, long double )
inline
long double
min( long double const a, long double const b, long double const c )
{
return ( a < b ? ( a < c ? a : c ) : ( b < c ? b : c ) );
}
// min( long double, long double, long double, long double, ... )
template< typename... Ts >
inline
long double
min( long double const a, long double const b, long double const c, long double const d, Ts const &... o )
{
return min( a < b ? a : b, c < d ? c : d, o... );
}
// min( a, b, c )
template< typename T >
inline
T const &
min( T const & a, T const & b, T const & c )
{
return ( a < b ? ( a < c ? a : c ) : ( b < c ? b : c ) );
}
// min( a, b, c, d, ... )
template< typename T, typename... Ts >
inline
T const &
min( T const & a, T const & b, T const & c, T const & d, Ts const &... o )
{
return min( a < b ? a : b, c < d ? c : d, o... );
}
// max /////
// max( short, short )
inline
short int
max( short int const a, short int const b )
{
return ( a < b ? b : a );
}
// max( int, int )
inline
int
max( int const a, int const b )
{
return ( a < b ? b : a );
}
// max( long, long )
inline
long int
max( long int const a, long int const b )
{
return ( a < b ? b : a );
}
// max( unsigned short, unsigned short )
inline
unsigned short int
max( unsigned short int const a, unsigned short int const b )
{
return ( a < b ? b : a );
}
// max( unsigned, unsigned )
inline
unsigned int
max( unsigned int const a, unsigned int const b )
{
return ( a < b ? b : a );
}
// max( unsigned long, unsigned long )
inline
unsigned long int
max( unsigned long int const a, unsigned long int const b )
{
return ( a < b ? b : a );
}
// max( float, float )
inline
float
max( float const a, float const b )
{
return ( a < b ? b : a );
}
// max( double, double )
inline
double
max( double const a, double const b )
{
return ( a < b ? b : a );
}
// max( long double, long double )
inline
long double
max( long double const a, long double const b )
{
return ( a < b ? b : a );
}
// Use std::max for 2 arguments not covered by the above overloads
using std::max;
// max( short, short, short )
inline
short int
max( short int const a, short int const b, short int const c )
{
return ( a < b ? ( b < c ? c : b ) : ( a < c ? c : a ) );
}
// max( short, short, short, short, ... )
template< typename... Ts >
inline
short int
max( short int const a, short int const b, short int const c, short int const d, Ts const &... o )
{
return max( a < b ? b : a, c < d ? d : c, o... );
}
// max( int, int, int )
inline
int
max( int const a, int const b, int const c )
{
return ( a < b ? ( b < c ? c : b ) : ( a < c ? c : a ) );
}
// max( int, int, int, int, ... )
template< typename... Ts >
inline
int
max( int const a, int const b, int const c, int const d, Ts const &... o )
{
return max( a < b ? b : a, c < d ? d : c, o... );
}
// max( long, long, long )
inline
long int
max( long int const a, long int const b, long int const c )
{
return ( a < b ? ( b < c ? c : b ) : ( a < c ? c : a ) );
}
// max( long, long, long, long, ... )
template< typename... Ts >
inline
long int
max( long int const a, long int const b, long int const c, long int const d, Ts const &... o )
{
return max( a < b ? b : a, c < d ? d : c, o... );
}
// max( unsigned short, unsigned short, unsigned short )
inline
unsigned short int
max( unsigned short int const a, unsigned short int const b, unsigned short int const c )
{
return ( a < b ? ( b < c ? c : b ) : ( a < c ? c : a ) );
}
// max( unsigned short, unsigned short, unsigned short, unsigned short, ... )
template< typename... Ts >
inline
unsigned short int
max( unsigned short int const a, unsigned short int const b, unsigned short int const c, unsigned short int const d, Ts const &... o )
{
return max( a < b ? b : a, c < d ? d : c, o... );
}
// max( unsigned, unsigned, unsigned )
inline
unsigned int
max( unsigned int const a, unsigned int const b, unsigned int const c )
{
return ( a < b ? ( b < c ? c : b ) : ( a < c ? c : a ) );
}
// max( unsigned, unsigned, unsigned, unsigned, ... )
template< typename... Ts >
inline
unsigned int
max( unsigned int const a, unsigned int const b, unsigned int const c, unsigned int const d, Ts const &... o )
{
return max( a < b ? b : a, c < d ? d : c, o... );
}
// max( unsigned long, unsigned long, unsigned long )
inline
unsigned long int
max( unsigned long int const a, unsigned long int const b, unsigned long int const c )
{
return ( a < b ? ( b < c ? c : b ) : ( a < c ? c : a ) );
}
// max( unsigned long, unsigned long, unsigned long, unsigned long, ... )
template< typename... Ts >
inline
unsigned long int
max( unsigned long int const a, unsigned long int const b, unsigned long int const c, unsigned long int const d, Ts const &... o )
{
return max( a < b ? b : a, c < d ? d : c, o... );
}
// max( float, float, float )
inline
float
max( float const a, float const b, float const c )
{
return ( a < b ? ( b < c ? c : b ) : ( a < c ? c : a ) );
}
// max( float, float, float, float, ... )
template< typename... Ts >
inline
float
max( float const a, float const b, float const c, float const d, Ts const &... o )
{
return max( a < b ? b : a, c < d ? d : c, o... );
}
// max( double, double, double )
inline
double
max( double const a, double const b, double const c )
{
return ( a < b ? ( b < c ? c : b ) : ( a < c ? c : a ) );
}
// max( double, double, double, double, ... )
template< typename... Ts >
inline
double
max( double const a, double const b, double const c, double const d, Ts const &... o )
{
return max( a < b ? b : a, c < d ? d : c, o... );
}
// max( long double, long double, long double )
inline
long double
max( long double const a, long double const b, long double const c )
{
return ( a < b ? ( b < c ? c : b ) : ( a < c ? c : a ) );
}
// max( long double, long double, long double, long double, ... )
template< typename... Ts >
inline
long double
max( long double const a, long double const b, long double const c, long double const d, Ts const &... o )
{
return max( a < b ? b : a, c < d ? d : c, o... );
}
// max( a, b, c )
template< typename T >
inline
T const &
max( T const & a, T const & b, T const & c )
{
return ( a < b ? ( b < c ? c : b ) : ( a < c ? c : a ) );
}
// max( a, b, c, d, ... )
template< typename T, typename... Ts >
inline
T const &
max( T const & a, T const & b, T const & c, T const & d, Ts const &... o )
{
return max( a < b ? b : a, c < d ? d : c, o... );
}
// General /////
// abs( x ) == | x |
template< typename T, class = typename std::enable_if< std::is_arithmetic< T >::value >::type >
inline
T
abs( T const & x )
{
return ( x < T( 0 ) ? -x : x );
}
// FLOOR( x )
template< typename T >
inline
int
FLOOR( T const & x )
{
return int( std::floor( x ) );
}
// CEILING( x )
template< typename T >
inline
int
CEILING( T const & x )
{
return int( std::ceil( x ) );
}
// signum( x )
template< typename T, class = typename std::enable_if< std::is_arithmetic< T >::value >::type >
inline
int
signum( T const & x )
{
return ( x > T( 0 ) ? +1 : ( x < T( 0 ) ? -1 : 0 ) );
}
// sign( x )
template< typename T, class = typename std::enable_if< std::is_arithmetic< T >::value >::type >
inline
int
sign( T const & x )
{
return ( x >= T( 0 ) ? +1 : -1 );
}
// Sign Transfer from Second Argument to First Argument
template< typename X, typename Y, class = typename std::enable_if< std::is_arithmetic< X >::value && std::is_arithmetic< Y >::value, X >::type >
inline
X
sign( X const & x, Y const & y )
{
return ( y >= Y( 0 ) ? abs( x ) : -abs( x ) );
}
// nint( x ): Nearest int
template< typename T >
inline
int
nint( T const & x )
{
return static_cast< int >( x + ( sign( x ) * T( 0.5 ) ) );
}
// nsint( x ): Nearest short int
template< typename T >
inline
short int
nsint( T const & x )
{
return static_cast< short int >( x + ( sign( x ) * T( 0.5 ) ) );
}
// nlint( x ): Nearest long int
template< typename T >
inline
long int
nlint( T const & x )
{
return static_cast< long int >( x + ( sign( x ) * T( 0.5 ) ) );
}
// nlint( x ): Nearest long int
template< typename T >
inline
int64_t
nint64( T const & x )
{
return static_cast< int64_t >( x + ( sign( x ) * T( 0.5 ) ) );
}
// Nearest function selector class for R non-integer or T integer
template< typename R, typename T, bool >
struct NearestSelector
{
static
R
nearest( T const & x )
{
return R( x );
}
};
// Nearest function selector class for R integer and T non-integer
template< typename R, typename T >
struct NearestSelector< R, T, true >
{
static
R
nearest( T const & x )
{
return R( x + ( sign( x ) * T( 0.5 ) ) );
}
};
// nearest< R >( x ): Nearest R
template< typename R, typename T >
inline
R
nearest( T const & x )
{
return NearestSelector< R, T, ( ( std::numeric_limits< R >::is_integer ) && ( ! std::numeric_limits< T >::is_integer ) ) >::nearest( x );
}
// nearest_size( x ): Nearest std::size_t
template< typename T >
inline
std::size_t
nearest_size( T const & x )
{
return std::size_t( x > T( 0 ) ? x + ( sign( x ) * T( 0.5 ) ) : 0 );
}
// nearest_ssize( x ): Nearest SSize
template< typename T >
inline
SSize
nearest_ssize( T const & x )
{
return SSize( x + ( sign( x ) * T( 0.5 ) ) );
}
// nearest_int( x ): Nearest int
template< typename T >
inline
int
nearest_int( T const & x )
{
return static_cast< int >( x + ( sign( x ) * T( 0.5 ) ) );
}
// Mod function selector class for non-integer types
template< typename T, bool >
struct ModSelector
{
static
T
mod( T const & x, T const & y )
{
return ( y != T( 0 ) ? x - ( T( static_cast< SSize >( x / y ) ) * y ) : T( 0 ) );
}
};
// Mod function selector class for integer types
// When used with negative integer arguments this assumes integer division
// rounds towards zero (de facto and future C++ standard)
template< typename T >
struct ModSelector< T, true >
{
static
T
mod( T const & x, T const & y )
{
return ( y != T( 0 ) ? x - ( ( x / y ) * y ) : T( 0 ) );
}
};
// x(mod y) computational modulo returning magnitude < | y | and sign of x
// When used with negative integer arguments this assumes integer division
// rounds towards zero (de facto and future C++ standard)
template< typename T >
inline
T
mod( T const & x, T const & y )
{
return ModSelector< T, std::numeric_limits< T >::is_integer >::mod( x, y );
}
// i(mod n) : float Arguments
inline
float
mod( float const i, float const n )
{
return ( n != 0.0f ? std::fmod( i, n ) : 0.0f );
}
// i(mod n) : double Arguments
inline
double
mod( double const i, double const n )
{
return ( n != 0.0 ? std::fmod( i, n ) : 0.0 );
}
// i(mod n) : long double Arguments
inline
long double
mod( long double const & i, long double const & n )
{
return ( n != 0.0l ? std::fmod( i, n ) : 0.0l );
}
// Modulo function selector class for non-integer types
template< typename T, bool >
struct ModuloSelector
{
static
T
modulo( T const & x, T const & y )
{
return ( y != T( 0 ) ? x - ( std::floor( x / y ) * y ) : x ); // Intel Fortran behavior if y==0
}
};
// Modulo function selector class for integer types
template< typename T >
struct ModuloSelector< T, true >
{
static
T
modulo( T const & x, T const & y )
{
return ( y != T( 0 ) ? x - ( T( std::floor( static_cast< long double >( x ) / y ) ) * y ) : x ); // Intel Fortran behavior if y==0
}
};
// x(mod y) mathematical modulo returning magnitude < | y | and sign of y
template< typename T >
inline
T
modulo( T const & x, T const & y )
{
return ModuloSelector< T, std::numeric_limits< T >::is_integer >::modulo( x, y );
}
// Positive Difference
template< typename T >
inline
T
dim( T const & x, T const & y )
{
return max( x - y, T( 0 ) );
}
// Greatest Common Divisor
template< typename T >
inline
T
gcd( T const & m, T const & n )
{
T lo( min( m, n ) );
T hi( max( m, n ) );
while ( lo > T( 0 ) ) {
T const rem( mod( hi, lo ) );
hi = lo;
lo = rem;
}
return hi;
}
// Complex /////
// Real Part
template< typename T >
inline
T
REAL( std::complex< T > const & c )
{
return c.real();
}
// Real Conversion
template< typename T >
inline
T
REAL( T const & x )
{
return float( x );
}
// Complex Maker
template< typename R, typename I, class = typename std::enable_if< std::is_integral< R >::value && std::is_integral< I >::value >::type >
inline
std::complex< float >
make_complex( R const & r, I const & i )
{
return std::complex< float >( r, i );
}
// Complex Maker
template< typename R, typename I, class = typename std::enable_if< std::is_integral< R >::value && ( ! std::is_integral< I >::value ) >::type >
inline
std::complex< I >
make_complex( R const & r, I const & i )
{
return std::complex< I >( r, i );
}
// Complex Maker
template< typename R, typename I, class = typename std::enable_if< ( ! std::is_integral< R >::value ) && std::is_integral< I >::value >::type >
inline
std::complex< R >
make_complex( R const & r, I const & i )
{
return std::complex< R >( r, i );
}
// Complex Maker
template< typename R, typename I, class = typename std::enable_if< ( ! std::is_integral< R >::value ) && ( ! std::is_integral< I >::value ) && std::is_same< R, I >::value >::type, typename = void >
inline
std::complex< R >
make_complex( R const & r, I const & i )
{
return std::complex< R >( r, i );
}
// Complex Maker
template< typename R, typename I, class = typename std::enable_if< ( ! std::is_integral< R >::value ) && ( ! std::is_integral< I >::value ) && ( ! std::is_same< R, I >::value ) >::type >
inline
std::complex< double >
make_complex( R const & r, I const & i )
{
return std::complex< double >( r, i );
}
// Trigonometric /////
// pi
template< typename T >
inline
T
pi()
{
static T const Pi( T( 4 ) * std::atan( T( 1 ) ) );
return Pi;
}
// pi/2
template< typename T >
inline
T
pi_over_2()
{
static T const Pi__2( T( 2 ) * std::atan( T( 1 ) ) );
return Pi__2;
}
// pi/2
template< typename T >
inline
T
pi__2()
{
static T const Pi__2( T( 2 ) * std::atan( T( 1 ) ) );
return Pi__2;
}
// Radians to Degrees
template< typename T >
inline
T
degrees( T const & r )
{
static T const r2d( T( 180 ) / pi< T >() );
return r * r2d;
}
// Radians to Degrees
template< typename T >
inline
T
deg( T const & r )
{
static T const r2d( T( 180 ) / pi< T >() );
return r * r2d;
}
// Degrees to Radians
template< typename T >
inline
T
radians( T const & d )
{
static T const d2r( pi< T >() / T( 180 ) );
return d * d2r;
}
// Degrees to Radians
template< typename T >
inline
T
rad( T const & d )
{
static T const d2r( pi< T >() / T( 180 ) );
return d * d2r;
}
// Cotangent
template< typename T >
inline
T
cot( T const & r )
{
if ( r == T( 0 ) ) {
return std::numeric_limits< T >::infinity();
} else {
return std::tan( pi_over_2< T >() - r );
}
}
// Arccotangent
template< typename T >
inline
T
acot( T const & x )
{
return pi_over_2< T >() - std::atan( x );
}
// Tangent of Angle in Degrees
template< typename T >
inline
T
tand( T const & d )
{
return std::tan( radians( d ) );
}
// Cotangent of Angle in Degrees
template< typename T >
inline
T
cotd( T const & d )
{
return cot( radians( d ) );
}
// Arcsine in Degrees
template< typename T >
inline
T
asind( T const & x )
{
return degrees( std::asin( x ) );
}
// Arccosine in Degrees
template< typename T >
inline
T
acosd( T const & x )
{
return degrees( std::acos( x ) );
}
// Arctangent in Degrees
template< typename T >
inline
T
atand( T const & x )
{
return degrees( std::atan( x ) );
}
// Arccotangent in Degrees
template< typename T >
inline
T
acotd( T const & x )
{
return degrees( acot( x ) );
}
// Two-Argument Arctangent in Degrees
template< typename T >
inline
T
atan2d( T const & y, T const & x )
{
return degrees( std::atan2( y, x ) );
}
// Error Function /////
// Two-Argument Arctangent in Degrees
template< typename T >
inline
T
erfcx( T const & x )
{
return T( std::exp( x * x ) * std::erfc( x ) );
}
// Power and Roots /////
// square( x ) == x^2
template< typename T, class = typename std::enable_if< std::is_arithmetic< T >::value >::type >
inline
T
square( T const x )
{
return x * x;
}
// cube( x ) == x^3
template< typename T, class = typename std::enable_if< std::is_arithmetic< T >::value >::type >
inline
T
cube( T const x )
{
return x * x * x;
}
// quad( x ) == x^4
template< typename T, class = typename std::enable_if< std::is_arithmetic< T >::value >::type >
inline
T
quad( T const x )
{
T const t( x * x );
return t * t;
}
// pow_2( x ) == x^2
template< typename T, class = typename std::enable_if< std::is_arithmetic< T >::value >::type >
inline
T
pow_2( T const x )
{
return x * x;
}
// pow_3( x ) == x^3
template< typename T, class = typename std::enable_if< std::is_arithmetic< T >::value >::type >
inline
T
pow_3( T const x )
{
return x * x * x;
}
// pow_4( x ) == x^4
template< typename T, class = typename std::enable_if< std::is_arithmetic< T >::value >::type >
inline
T
pow_4( T const x )
{
T const t( x * x );
return t * t;
}
// pow_5( x ) == x^5
template< typename T, class = typename std::enable_if< std::is_arithmetic< T >::value >::type >
inline
T
pow_5( T const x )
{
T const t( x * x );
return t * t * x;
}
// pow_6( x ) == x^6
template< typename T, class = typename std::enable_if< std::is_arithmetic< T >::value >::type >
inline
T
pow_6( T const x )
{
T const t( x * x * x );
return t * t;
}
// pow_7( x ) == x^7
template< typename T, class = typename std::enable_if< std::is_arithmetic< T >::value >::type >
inline
T
pow_7( T const x )
{
T const t( x * x * x );
return t * t * x;
}
// pow_8( x ) == x^8
template< typename T, class = typename std::enable_if< std::is_arithmetic< T >::value >::type >
inline
T
pow_8( T const x )
{
T t( x * x );
t *= t;
return t * t;
}
// pow_9( x ) == x^9
template< typename T, class = typename std::enable_if< std::is_arithmetic< T >::value >::type >
inline
T
pow_9( T const x )
{
T const t( x * x * x );
return t * t * t;
}
// root_4( x ) == x^(1/4)
template< typename T, class = typename std::enable_if< std::is_arithmetic< T >::value >::type >
inline
T
root_4( T const x )
{
return T( std::sqrt( std::sqrt( x ) ) );
}
// root_8( x ) == x^(1/8)
template< typename T, class = typename std::enable_if< std::is_arithmetic< T >::value >::type >
inline
T
root_8( T const x )
{
return T( std::sqrt( std::sqrt( std::sqrt( x ) ) ) );
}
// square( x ) == x^2
template< typename T, class = typename std::enable_if< ! std::is_arithmetic< T >::value >::type >
inline
T
square( T const & x )
{
return x * x;
}
// cube( x ) == x^3
template< typename T, class = typename std::enable_if< ! std::is_arithmetic< T >::value >::type >
inline
T
cube( T const & x )
{
return x * x * x;
}
// quad( x ) == x^4
template< typename T, class = typename std::enable_if< ! std::is_arithmetic< T >::value >::type >
inline
T
quad( T const & x )
{
T const t( x * x );
return t * t;
}
// pow_2( x ) == x^2
template< typename T, class = typename std::enable_if< ! std::is_arithmetic< T >::value >::type >
inline
T
pow_2( T const & x )
{
return x * x;
}
// pow_3( x ) == x^3
template< typename T, class = typename std::enable_if< ! std::is_arithmetic< T >::value >::type >
inline
T
pow_3( T const & x )
{
return x * x * x;
}
// pow_4( x ) == x^4
template< typename T, class = typename std::enable_if< ! std::is_arithmetic< T >::value >::type >
inline
T
pow_4( T const & x )
{
T const t( x * x );
return t * t;
}
// pow_5( x ) == x^5
template< typename T, class = typename std::enable_if< ! std::is_arithmetic< T >::value >::type >
inline
T
pow_5( T const & x )
{
T const t( x * x );
return t * t * x;
}
// pow_6( x ) == x^6
template< typename T, class = typename std::enable_if< ! std::is_arithmetic< T >::value >::type >
inline
T
pow_6( T const & x )
{
T const t( x * x * x );
return t * t;
}
// pow_7( x ) == x^7
template< typename T, class = typename std::enable_if< ! std::is_arithmetic< T >::value >::type >
inline
T
pow_7( T const & x )
{
T const t( x * x * x );
return t * t * x;
}
// pow_8( x ) == x^8
template< typename T, class = typename std::enable_if< ! std::is_arithmetic< T >::value >::type >
inline
T
pow_8( T const & x )
{
T t( x * x );
t *= t;
return t * t;
}
// pow_9( x ) == x^9
template< typename T, class = typename std::enable_if< ! std::is_arithmetic< T >::value >::type >
inline
T
pow_9( T const & x )
{
T const t( x * x * x );
return t * t * t;
}
// Tolerant Comparisons /////
// x == y Within Specified Relative or Absolute Tolerances?
template< typename T >
inline
bool
eq_tol( T const & x, T const & y, T const & r_tol, T const & a_tol = T( 0 ) )
{
using std::abs; // Can use std::abs or user-defined abs
assert( r_tol >= T( 0 ) );
assert( a_tol >= T( 0 ) );
return ( abs( x - y ) <= max( r_tol * max( abs( x ), abs( y ) ), a_tol ) );
}
// x < y Within Specified Relative or Absolute Tolerances?
template< typename T >
inline
bool
lt_tol( T const & x, T const & y, T const & r_tol, T const & a_tol = T( 0 ) )
{
using std::abs; // Can use std::abs or user-defined abs
assert( r_tol >= T( 0 ) );
assert( a_tol >= T( 0 ) );
return ( x < y + max( r_tol * max( abs( x ), abs( y ) ), a_tol ) );
}
// x <= y Within Specified Relative or Absolute Tolerances?
template< typename T >
inline
bool
le_tol( T const & x, T const & y, T const & r_tol, T const & a_tol = T( 0 ) )
{
using std::abs; // Can use std::abs or user-defined abs
assert( r_tol >= T( 0 ) );
assert( a_tol >= T( 0 ) );
return ( x <= y + max( r_tol * max( abs( x ), abs( y ) ), a_tol ) );
}
// x >= y Within Specified Relative or Absolute Tolerances?
template< typename T >
inline
bool
ge_tol( T const & x, T const & y, T const & r_tol, T const & a_tol = T( 0 ) )
{
using std::abs; // Can use std::abs or user-defined abs
assert( r_tol >= T( 0 ) );
assert( a_tol >= T( 0 ) );
return ( x >= y - max( r_tol * max( abs( x ), abs( y ) ), a_tol ) );
}
// x > y Within Specified Relative or Absolute Tolerances?
template< typename T >
inline
bool
gt_tol( T const & x, T const & y, T const & r_tol, T const & a_tol = T( 0 ) )
{
using std::abs; // Can use std::abs or user-defined abs
assert( r_tol >= T( 0 ) );
assert( a_tol >= T( 0 ) );
return ( x > y - max( r_tol * max( abs( x ), abs( y ) ), a_tol ) );
}
} // ObjexxFCL
#endif // ObjexxFCL_Fmath_hh_INCLUDED
// ===== ObjexxFCL/Vector2.hh =====
#ifndef ObjexxFCL_Vector2_hh_INCLUDED
#define ObjexxFCL_Vector2_hh_INCLUDED
// Vector2: Fast 2-Element Vector
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// ObjexxFCL Headers
// C++ Headers
#include <cassert>
#include <cmath>
#include <cstddef>
#include <cstdlib>
#include <initializer_list>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <type_traits>
namespace ObjexxFCL {
// Vector2: Fast 2-Element Vector
// . Heap-free and loop-free for speed
// . Provides direct element access via .x style lookup
// . Use std::array< T, 2 > instead in array/vectorization context
template< typename T >
class Vector2
{
private: // Friends
template< typename > friend class Vector2;
public: // Types
typedef TypeTraits< T > Traits;
typedef typename std::conditional< std::is_scalar< T >::value, T const, T const & >::type Tc;
typedef typename std::conditional< std::is_scalar< T >::value, typename std::remove_const< T >::type, T const & >::type Tr;
// STL Style
typedef T value_type;
typedef T & reference;
typedef T const & const_reference;
typedef T * pointer;
typedef T const * const_pointer;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
// C++ Style
typedef T Value;
typedef T & Reference;
typedef T const & ConstReference;
typedef T * Pointer;
typedef T const * ConstPointer;
typedef std::size_t Size;
typedef std::ptrdiff_t Difference;
public: // Creation
// Default Constructor
Vector2()
#if defined(OBJEXXFCL_ARRAY_INIT) || defined(OBJEXXFCL_ARRAY_INIT_DEBUG)
:
x( Traits::initial_array_value() ),
y( Traits::initial_array_value() )
#endif
{}
// Copy Constructor
Vector2( Vector2 const & v ) :
x( v.x ),
y( v.y )
{}
// Copy Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Vector2( Vector2< U > const & v ) :
x( v.x ),
y( v.y )
{}
// Uniform Value Constructor
explicit
Vector2( Tc t ) :
x( t ),
y( t )
{}
// Value Constructor
Vector2(
Tc x_,
Tc y_
) :
x( x_ ),
y( y_ )
{}
// Initializer List Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Vector2( std::initializer_list< U > const l ) :
x( *l.begin() ),
y( *( l.begin() + 1 ) )
{
assert( l.size() == 2 );
}
// Array Constructor Template
template< typename A, class = typename std::enable_if< std::is_constructible< T, typename A::value_type >::value >::type >
Vector2( A const & a ) :
x( a[ 0 ] ),
y( a[ 1 ] )
{
assert( a.size() == 2 );
}
// Default Vector Named Constructor
static
Vector2
default_vector()
{
return Vector2( T() );
}
// Zero Vector Named Constructor
static
Vector2
zero_vector()
{
return Vector2( T( 0 ) );
}
// x Vector of Specified Length Named Constructor
static
Vector2
x_vector( Tc tar_length = T( 1 ) )
{
return Vector2( tar_length, T( 0 ) );
}
// y Vector of Specified Length Named Constructor
static
Vector2
y_vector( Tc tar_length = T( 1 ) )
{
return Vector2( T( 0 ), tar_length );
}
// Uniform Vector of Specified Length Named Constructor
static
Vector2
uniform_vector( Tc tar_length = T( 1 ) )
{
return Vector2( tar_length / std::sqrt( T( 2 ) ) );
}
// Destructor
~Vector2()
{}
public: // Assignment
// Copy Assignment
Vector2 &
operator =( Vector2 const & v )
{
if ( this != &v ) {
x = v.x;
y = v.y;
}
return *this;
}
// Copy Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector2 &
operator =( Vector2< U > const & v )
{
x = v.x;
y = v.y;
return *this;
}
// Initializer List Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector2 &
operator =( std::initializer_list< U > const l )
{
assert( l.size() == 2 );
auto i( l.begin() );
x = *i;
y = *(++i);
return *this;
}
// Array Assignment Template
template< typename A, class = typename std::enable_if< std::is_assignable< T&, typename A::value_type >::value >::type >
Vector2 &
operator =( A const & a )
{
assert( a.size() == 2 );
x = a[ 0 ];
y = a[ 1 ];
return *this;
}
// += Vector2
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector2 &
operator +=( Vector2< U > const & v )
{
x += v.x;
y += v.y;
return *this;
}
// -= Vector2
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector2 &
operator -=( Vector2< U > const & v )
{
x -= v.x;
y -= v.y;
return *this;
}
// *= Vector2
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector2 &
operator *=( Vector2< U > const & v )
{
x *= v.x;
y *= v.y;
return *this;
}
// /= Vector2
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector2 &
operator /=( Vector2< U > const & v )
{
assert( v.x != T( 0 ) );
assert( v.y != T( 0 ) );
x /= v.x;
y /= v.y;
return *this;
}
// += Initializer List
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector2 &
operator +=( std::initializer_list< U > const l )
{
assert( l.size() == 2 );
auto i( l.begin() );
x += *i;
y += *(++i);
return *this;
}
// -= Initializer List
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector2 &
operator -=( std::initializer_list< U > const l )
{
assert( l.size() == 2 );
auto i( l.begin() );
x -= *i;
y -= *(++i);
return *this;
}
// *= Initializer List
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector2 &
operator *=( std::initializer_list< U > const l )
{
assert( l.size() == 2 );
auto i( l.begin() );
x *= *i;
y *= *(++i);
return *this;
}
// /= Initializer List
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector2 &
operator /=( std::initializer_list< U > const l )
{
assert( l.size() == 2 );
auto i( l.begin() );
assert( *i != T( 0 ) );
assert( *(i+1) != T( 0 ) );
x /= *i;
y /= *(++i);
return *this;
}
// += Array
template< typename A, class = typename std::enable_if< std::is_assignable< T&, typename A::value_type >::value >::type >
Vector2 &
operator +=( A const & a )
{
assert( a.size() == 2 );
x += a[ 0 ];
y += a[ 1 ];
return *this;
}
// -= Array
template< typename A, class = typename std::enable_if< std::is_assignable< T&, typename A::value_type >::value >::type >
Vector2 &
operator -=( A const & a )
{
assert( a.size() == 2 );
x -= a[ 0 ];
y -= a[ 1 ];
return *this;
}
// *= Array
template< typename A, class = typename std::enable_if< std::is_assignable< T&, typename A::value_type >::value >::type >
Vector2 &
operator *=( A const & a )
{
assert( a.size() == 2 );
x *= a[ 0 ];
y *= a[ 1 ];
return *this;
}
// /= Array
template< typename A, class = typename std::enable_if< std::is_assignable< T&, typename A::value_type >::value >::type >
Vector2 &
operator /=( A const & a )
{
assert( a.size() == 2 );
assert( a[ 0 ] != T( 0 ) );
assert( a[ 1 ] != T( 0 ) );
x /= a[ 0 ];
y /= a[ 1 ];
return *this;
}
// = Value
Vector2 &
operator =( Tc t )
{
x = y = t;
return *this;
}
// += Value
Vector2 &
operator +=( Tc t )
{
x += t;
y += t;
return *this;
}
// -= Value
Vector2 &
operator -=( Tc t )
{
x -= t;
y -= t;
return *this;
}
// *= Value
Vector2 &
operator *=( Tc t )
{
x *= t;
y *= t;
return *this;
}
// /= Value
template< typename U, class = typename std::enable_if< std::is_floating_point< U >::value && std::is_assignable< T&, U >::value >::type, typename = void >
Vector2 &
operator /=( U const & u )
{
assert( u != U( 0 ) );
U const inv_u( U( 1 ) / u );
x *= inv_u;
y *= inv_u;
return *this;
}
// /= Value
template< typename U, class = typename std::enable_if< ! std::is_floating_point< U >::value && std::is_assignable< T&, U >::value >::type, typename = void, typename = void >
Vector2 &
operator /=( U const & u )
{
assert( u != U( 0 ) );
x /= u;
y /= u;
return *this;
}
// Value Assignment
Vector2 &
assign(
Tc x_,
Tc y_
)
{
x = x_;
y = y_;
return *this;
}
public: // Assignment: Scaled
// Assign Value * Vector2
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector2 &
scaled_assign( Tc t, Vector2< U > const & v )
{
x = t * v.x;
y = t * v.y;
return *this;
}
// Add Value * Vector2
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector2 &
scaled_add( Tc t, Vector2< U > const & v )
{
x += t * v.x;
y += t * v.y;
return *this;
}
// Subtract Value * Vector2
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector2 &
scaled_sub( Tc t, Vector2< U > const & v )
{
x -= t * v.x;
y -= t * v.y;
return *this;
}
// Multiply by Value * Vector2
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector2 &
scaled_mul( Tc t, Vector2< U > const & v )
{
x *= t * v.x;
y *= t * v.y;
return *this;
}
// Divide by Value * Vector2
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector2 &
scaled_div( Tc t, Vector2< U > const & v )
{
assert( t != T( 0 ) );
assert( v.x != T( 0 ) );
assert( v.y != T( 0 ) );
x /= t * v.x;
y /= t * v.y;
return *this;
}
public: // Subscript
// Vector2[ i ] const: 0-Based Index
Tr
operator []( size_type const i ) const
{
assert( i <= 1 );
return ( i == 0 ? x : y );
}
// Vector2[ i ]: 0-Based Index
T &
operator []( size_type const i )
{
assert( i <= 1 );
return ( i == 0 ? x : y );
}
// Vector2( i ) const: 1-Based Index
Tr
operator ()( size_type const i ) const
{
assert( ( 1 <= i ) && ( i <= 2 ) );
return ( i == 1 ? x : y );
}
// Vector2( i ): 1-Based Index
T &
operator ()( size_type const i )
{
assert( ( 1 <= i ) && ( i <= 2 ) );
return ( i == 1 ? x : y );
}
public: // Properties: Predicates
// Is Zero Vector?
bool
is_zero() const
{
static T const ZERO( 0 );
return ( x == ZERO ) && ( y == ZERO );
}
// Is Unit Vector?
bool
is_unit() const
{
return ( length_squared() == T( 1 ) );
}
public: // Properties: General
// Size
Size
size() const
{
return 2u;
}
// Length
T
length() const
{
return std::sqrt( ( x * x ) + ( y * y ) );
}
// Length Squared
T
length_squared() const
{
return ( x * x ) + ( y * y );
}
// Magnitude
T
magnitude() const
{
return std::sqrt( ( x * x ) + ( y * y ) );
}
// Magnitude
T
mag() const
{
return std::sqrt( ( x * x ) + ( y * y ) );
}
// Magnitude Squared
T
magnitude_squared() const
{
return ( x * x ) + ( y * y );
}
// Magnitude Squared
T
mag_squared() const
{
return ( x * x ) + ( y * y );
}
// L1 Norm
T
norm_L1() const
{
return std::abs( x ) + std::abs( y );
}
// L2 Norm
T
norm_L2() const
{
return std::sqrt( ( x * x ) + ( y * y ) );
}
// L-infinity Norm
T
norm_Linf() const
{
return std::max( std::abs( x ), std::abs( y ) );
}
// Distance to a Vector2
T
distance( Vector2 const & v ) const
{
return std::sqrt( square( x - v.x ) + square( y - v.y ) );
}
// Distance Squared to a Vector2
T
distance_squared( Vector2 const & v ) const
{
return square( x - v.x ) + square( y - v.y );
}
// Dot Product with a Vector2
T
dot( Vector2 const & v ) const
{
return ( x * v.x ) + ( y * v.y );
}
// Dot Product with an Array
template< typename A, class = typename std::enable_if< std::is_assignable< T&, typename A::value_type >::value >::type >
T
dot( A const & a ) const
{
assert( a.size() == 2 );
return ( x * a[ 0 ] ) + ( y * a[ 1 ] );
}
// Cross Product with a Vector2
T
cross( Vector2 const & v ) const
{
return ( x * v.y ) - ( y * v.x );
}
// Cross Product with an Array
template< typename A, class = typename std::enable_if< std::is_assignable< T&, typename A::value_type >::value >::type >
T
cross( A const & a ) const
{
assert( a.size() == 2 );
return ( x * a[ 1 ] ) - ( y * a[ 0 ] );
}
// Alias for Element 1
Tr
x1() const
{
return x;
}
// Alias for Element 1
T &
x1()
{
return x;
}
// Alias for Element 2
Tr
x2() const
{
return y;
}
// Alias for Element 2
T &
x2()
{
return y;
}
public: // Modifiers
// Zero
Vector2 &
zero()
{
x = y = T( 0 );
return *this;
}
// Negate
Vector2 &
negate()
{
x = -x;
y = -y;
return *this;
}
// Normalize to a Length
Vector2 &
normalize( Tc tar_length = T( 1 ) )
{
T const cur_length( length() );
assert( cur_length != T ( 0 ) );
T const dilation( tar_length / cur_length );
x *= dilation;
y *= dilation;
return *this;
}
// Normalize to a Length: Zero Vector2 if Length is Zero
Vector2 &
normalize_zero( Tc tar_length = T( 1 ) )
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
x *= dilation;
y *= dilation;
} else { // Set zero vector
x = y = T( 0 );
}
return *this;
}
// Normalize to a Length: Uniform Vector2 if Length is Zero
Vector2 &
normalize_uniform( Tc tar_length = T( 1 ) )
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
x *= dilation;
y *= dilation;
} else { // Set uniform vector
operator =( uniform_vector( tar_length ) );
}
return *this;
}
// Normalize to a Length: x Vector2 if Length is Zero
Vector2 &
normalize_x( Tc tar_length = T( 1 ) )
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
x *= dilation;
y *= dilation;
} else { // Set x vector
x = tar_length;
y = T( 0 );
}
return *this;
}
// Normalize to a Length: y Vector2 if Length is Zero
Vector2 &
normalize_y( Tc tar_length = T( 1 ) )
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
x *= dilation;
y *= dilation;
} else { // Set y vector
y = tar_length;
x = T( 0 );
}
return *this;
}
// Minimum Coordinates with a Vector2
Vector2 &
min( Vector2 const & v )
{
x = ( x <= v.x ? x : v.x );
y = ( y <= v.y ? y : v.y );
return *this;
}
// Maximum Coordinates with a Vector2
Vector2 &
max( Vector2 const & v )
{
x = ( x >= v.x ? x : v.x );
y = ( y >= v.y ? y : v.y );
return *this;
}
// Add a Vector2
Vector2 &
add( Vector2 const & v )
{
x += v.x;
y += v.y;
return *this;
}
// Sum a Vector2
Vector2 &
sum( Vector2 const & v )
{
x += v.x;
y += v.y;
return *this;
}
// Subtract a Vector2
Vector2 &
sub( Vector2 const & v )
{
x -= v.x;
y -= v.y;
return *this;
}
// Subtract a Vector2
Vector2 &
subtract( Vector2 const & v )
{
x -= v.x;
y -= v.y;
return *this;
}
// Project Normal to a Vector2
Vector2 &
project_normal( Vector2 const & v )
{
assert( v.length_squared() != T( 0 ) );
T const c( dot( v ) / v.length_squared() );
x -= c * v.x;
y -= c * v.y;
return *this;
}
// Project onto a Vector2
Vector2 &
project_parallel( Vector2 const & v )
{
assert( v.length_squared() != T( 0 ) );
T const c( dot( v ) / v.length_squared() );
x = c * v.x;
y = c * v.y;
return *this;
}
public: // Generators
// -Vector2 (Negated)
Vector2
operator -() const
{
return Vector2( -x, -y );
}
// Negated
Vector2
negated() const
{
return Vector2( -x, -y );
}
// Normalized to a Length
Vector2
normalized( Tc tar_length = T( 1 ) ) const
{
T const cur_length( length() );
assert( cur_length != T ( 0 ) );
T const dilation( tar_length / cur_length );
return Vector2(
x * dilation,
y * dilation
);
}
// Normalized to a Length: Zero Vector2 if Length is Zero
Vector2
normalized_zero( Tc tar_length = T( 1 ) ) const
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
return Vector2(
x * dilation,
y * dilation
);
} else { // Return zero vector
return Vector2( T( 0 ) );
}
}
// Normalized to a Length: Uniform Vector2 if Length is Zero
Vector2
normalized_uniform( Tc tar_length = T( 1 ) ) const
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
return Vector2(
x * dilation,
y * dilation
);
} else { // Return uniform vector
return uniform_vector( tar_length );
}
}
// Normalized to a Length: x Vector2 if Length is Zero
Vector2
normalized_x( Tc tar_length = T( 1 ) ) const
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
return Vector2(
x * dilation,
y * dilation
);
} else { // Return x vector
return Vector2( tar_length, T( 0 ), T( 0 ) );
}
}
// Normalized to a Length: y Vector2 if Length is Zero
Vector2
normalized_y( Tc tar_length = T( 1 ) ) const
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
return Vector2(
x * dilation,
y * dilation
);
} else { // Return y vector
return Vector2( T( 0 ), tar_length, T( 0 ) );
}
}
// Projected Normal to a Vector2
Vector2
projected_normal( Vector2 const & v ) const
{
assert( v.length_squared() != T( 0 ) );
T const c( dot( v ) / v.length_squared() );
return Vector2( x - ( c * v.x ), y - ( c * v.y ) );
}
// Projected onto a Vector2
Vector2
projected_parallel( Vector2 const & v ) const
{
assert( v.length_squared() != T( 0 ) );
T const c( dot( v ) / v.length_squared() );
return Vector2( c * v.x, c * v.y );
}
public: // Static Methods
// Square of a value
static
T
square( Tc t )
{
return t * t;
}
// Value Clipped to [-1,1]
static
T
sin_cos_range( Tc t )
{
return std::min( std::max( t, T( -1 ) ), T( 1 ) );
}
// Add 2*Pi to a Negative Value
static
T
bump_up_angle( Tc t )
{
static T const Two_Pi( T( 2 ) * std::acos( -1.0 ) );
return ( t >= T( 0 ) ? t : Two_Pi + t );
}
public: // Data
T x, y; // Elements
}; // Vector2
// Length
template< typename T >
inline
T
length( Vector2< T > const & v )
{
return v.length();
}
// Length Squared
template< typename T >
inline
T
length_squared( Vector2< T > const & v )
{
return v.length_squared();
}
// Magnitude
template< typename T >
inline
T
magnitude( Vector2< T > const & v )
{
return v.magnitude();
}
// Magnitude
template< typename T >
inline
T
mag( Vector2< T > const & v )
{
return v.mag();
}
// Magnitude Squared
template< typename T >
inline
T
magnitude_squared( Vector2< T > const & v )
{
return v.magnitude_squared();
}
// Magnitude Squared
template< typename T >
inline
T
mag_squared( Vector2< T > const & v )
{
return v.mag_squared();
}
// Vector2 == Vector2
template< typename T >
inline
bool
operator ==( Vector2< T > const & a, Vector2< T > const & b )
{
return ( a.x == b.x ) && ( a.y == b.y );
}
// Vector2 != Vector2
template< typename T >
inline
bool
operator !=( Vector2< T > const & a, Vector2< T > const & b )
{
return ( a.x != b.x ) || ( a.y != b.y );
}
// Vector2 < Vector2: Lexicographic
template< typename T >
inline
bool
operator <( Vector2< T > const & a, Vector2< T > const & b )
{
return (
( a.x < b.x ? true :
( b.x < a.x ? false : // a.x == b.x
( a.y < b.y ) ) )
);
}
// Vector2 <= Vector2: Lexicographic
template< typename T >
inline
bool
operator <=( Vector2< T > const & a, Vector2< T > const & b )
{
return (
( a.x < b.x ? true :
( b.x < a.x ? false : // a.x == b.x
( a.y <= b.y ) ) )
);
}
// Vector2 >= Vector2: Lexicographic
template< typename T >
inline
bool
operator >=( Vector2< T > const & a, Vector2< T > const & b )
{
return (
( a.x > b.x ? true :
( b.x > a.x ? false : // a.x == b.x
( a.y >= b.y ) ) )
);
}
// Vector2 > Vector2: Lexicographic
template< typename T >
inline
bool
operator >( Vector2< T > const & a, Vector2< T > const & b )
{
return (
( a.x > b.x ? true :
( b.x > a.x ? false : // a.x == b.x
( a.y > b.y ) ) )
);
}
// Vector2 < Vector2: Element-wise
template< typename T >
inline
bool
lt( Vector2< T > const & a, Vector2< T > const & b )
{
return ( a.x < b.x ) && ( a.y < b.y );
}
// Vector2 <= Vector2: Element-wise
template< typename T >
inline
bool
le( Vector2< T > const & a, Vector2< T > const & b )
{
return ( a.x <= b.x ) && ( a.y <= b.y );
}
// Vector2 >= Vector2: Element-wise
template< typename T >
inline
bool
ge( Vector2< T > const & a, Vector2< T > const & b )
{
return ( a.x >= b.x ) && ( a.y >= b.y );
}
// Vector2 > Vector2: Element-wise
template< typename T >
inline
bool
gt( Vector2< T > const & a, Vector2< T > const & b )
{
return ( a.x > b.x ) && ( a.y > b.y );
}
// Vector2 == Value
template< typename T >
inline
bool
operator ==( Vector2< T > const & v, typename Vector2< T >::Tc t )
{
return ( v.x == t ) && ( v.y == t );
}
// Vector2 != Value
template< typename T >
inline
bool
operator !=( Vector2< T > const & v, typename Vector2< T >::Tc t )
{
return ( v.x != t ) || ( v.y != t );
}
// Vector2 < Value
template< typename T >
inline
bool
operator <( Vector2< T > const & v, typename Vector2< T >::Tc t )
{
return ( v.x < t ) && ( v.y < t );
}
// Vector2 <= Value
template< typename T >
inline
bool
operator <=( Vector2< T > const & v, typename Vector2< T >::Tc t )
{
return ( v.x <= t ) && ( v.y <= t );
}
// Vector2 >= Value
template< typename T >
inline
bool
operator >=( Vector2< T > const & v, typename Vector2< T >::Tc t )
{
return ( v.x >= t ) && ( v.y >= t );
}
// Vector2 > Value
template< typename T >
inline
bool
operator >( Vector2< T > const & v, typename Vector2< T >::Tc t )
{
return ( v.x > t ) && ( v.y > t );
}
// Value == Vector2
template< typename T >
inline
bool
operator ==( typename Vector2< T >::Tc t, Vector2< T > const & v )
{
return ( t == v.x ) && ( t == v.y );
}
// Value != Vector2
template< typename T >
inline
bool
operator !=( typename Vector2< T >::Tc t, Vector2< T > const & v )
{
return ( t != v.x ) || ( t != v.y );
}
// Value < Vector2
template< typename T >
inline
bool
operator <( typename Vector2< T >::Tc t, Vector2< T > const & v )
{
return ( t < v.x ) && ( t < v.y );
}
// Value <= Vector2
template< typename T >
inline
bool
operator <=( typename Vector2< T >::Tc t, Vector2< T > const & v )
{
return ( t <= v.x ) && ( t <= v.y );
}
// Value >= Vector2
template< typename T >
inline
bool
operator >=( typename Vector2< T >::Tc t, Vector2< T > const & v )
{
return ( t >= v.x ) && ( t >= v.y );
}
// Value > Vector2
template< typename T >
inline
bool
operator >( typename Vector2< T >::Tc t, Vector2< T > const & v )
{
return ( t > v.x ) && ( t > v.y );
}
// Equal Length?
template< typename T >
inline
bool
equal_length( Vector2< T > const & a, Vector2< T > const & b )
{
return ( a.length_squared() == b.length_squared() );
}
// Not Equal Length?
template< typename T >
inline
bool
not_equal_length( Vector2< T > const & a, Vector2< T > const & b )
{
return ( a.length_squared() != b.length_squared() );
}
// Vector2 + Vector2
template< typename T >
inline
Vector2< T >
operator +( Vector2< T > const & a, Vector2< T > const & b )
{
return Vector2< T >( a.x + b.x, a.y + b.y );
}
// Vector2 + Value
template< typename T >
inline
Vector2< T >
operator +( Vector2< T > const & v, typename Vector2< T >::Tc t )
{
return Vector2< T >( v.x + t, v.y + t );
}
// Value + Vector2
template< typename T >
inline
Vector2< T >
operator +( typename Vector2< T >::Tc t, Vector2< T > const & v )
{
return Vector2< T >( t + v.x, t + v.y );
}
// Vector2 - Vector2
template< typename T >
inline
Vector2< T >
operator -( Vector2< T > const & a, Vector2< T > const & b )
{
return Vector2< T >( a.x - b.x, a.y - b.y );
}
// Vector2 - Value
template< typename T >
inline
Vector2< T >
operator -( Vector2< T > const & v, typename Vector2< T >::Tc t )
{
return Vector2< T >( v.x - t, v.y - t );
}
// Value - Vector2
template< typename T >
inline
Vector2< T >
operator -( typename Vector2< T >::Tc t, Vector2< T > const & v )
{
return Vector2< T >( t - v.x, t - v.y );
}
// Vector2 * Vector2
template< typename T >
inline
Vector2< T >
operator *( Vector2< T > const & a, Vector2< T > const & b )
{
return Vector2< T >( a.x * b.x, a.y * b.y );
}
// Vector2 * Value
template< typename T >
inline
Vector2< T >
operator *( Vector2< T > const & v, typename Vector2< T >::Tc t )
{
return Vector2< T >( v.x * t, v.y * t );
}
// Value * Vector2
template< typename T >
inline
Vector2< T >
operator *( typename Vector2< T >::Tc t, Vector2< T > const & v )
{
return Vector2< T >( t * v.x, t * v.y );
}
// Vector2 / Vector2
template< typename T >
inline
Vector2< T >
operator /( Vector2< T > const & a, Vector2< T > const & b )
{
assert( b.x != T( 0 ) );
assert( b.y != T( 0 ) );
return Vector2< T >( a.x / b.x, a.y / b.y );
}
// Vector2 / Value
template< typename T, typename U, class = typename std::enable_if< std::is_floating_point< U >::value && std::is_assignable< T&, U >::value >::type >
inline
Vector2< T >
operator /( Vector2< T > const & v, U const & u )
{
assert( u != U( 0 ) );
U const inv_u( U ( 1 ) / u );
return Vector2< T >( v.x * inv_u, v.y * inv_u );
}
// Vector2 / Value
template< typename T, typename U, class = typename std::enable_if< ! std::is_floating_point< U >::value && std::is_assignable< T&, U >::value >::type, typename = void >
inline
Vector2< T >
operator /( Vector2< T > const & v, U const & u )
{
assert( u != U( 0 ) );
return Vector2< T >( v.x / u, v.y / u );
}
// Value / Vector2
template< typename T >
inline
Vector2< T >
operator /( typename Vector2< T >::Tc t, Vector2< T > const & v )
{
assert( v.x != T( 0 ) );
assert( v.y != T( 0 ) );
return Vector2< T >( t / v.x, t / v.y );
}
// Minimum of Two Vector2s
template< typename T >
inline
Vector2< T >
min( Vector2< T > const & a, Vector2< T > const & b )
{
return Vector2< T >(
( a.x <= b.x ? a.x : b.x ),
( a.y <= b.y ? a.y : b.y )
);
}
// Minimum of Three Vector2s
template< typename T >
inline
Vector2< T >
min( Vector2< T > const & a, Vector2< T > const & b, Vector2< T > const & c )
{
return Vector2< T >(
ObjexxFCL::min( a.x, b.x, c.x ),
ObjexxFCL::min( a.y, b.y, c.y )
);
}
// Minimum of Four Vector2s
template< typename T >
inline
Vector2< T >
min( Vector2< T > const & a, Vector2< T > const & b, Vector2< T > const & c, Vector2< T > const & d )
{
return Vector2< T >(
ObjexxFCL::min( a.x, b.x, c.x, d.x ),
ObjexxFCL::min( a.y, b.y, c.y, d.y )
);
}
// Maximum of Two Vector2s
template< typename T >
inline
Vector2< T >
max( Vector2< T > const & a, Vector2< T > const & b )
{
return Vector2< T >(
( a.x >= b.x ? a.x : b.x ),
( a.y >= b.y ? a.y : b.y )
);
}
// Maximum of Three Vector2s
template< typename T >
inline
Vector2< T >
max( Vector2< T > const & a, Vector2< T > const & b, Vector2< T > const & c )
{
return Vector2< T >(
ObjexxFCL::max( a.x, b.x, c.x ),
ObjexxFCL::max( a.y, b.y, c.y )
);
}
// Maximum of Four Vector2s
template< typename T >
inline
Vector2< T >
max( Vector2< T > const & a, Vector2< T > const & b, Vector2< T > const & c, Vector2< T > const & d )
{
return Vector2< T >(
ObjexxFCL::max( a.x, b.x, c.x, d.x ),
ObjexxFCL::max( a.y, b.y, c.y, d.y )
);
}
// Sum of Two Vector2s
template< typename T >
inline
Vector2< T >
sum( Vector2< T > const & a, Vector2< T > const & b )
{
return Vector2< T >( a.x + b.x, a.y + b.y );
}
// Sum of Three Vector2s
template< typename T >
inline
Vector2< T >
sum( Vector2< T > const & a, Vector2< T > const & b, Vector2< T > const & c )
{
return Vector2< T >( a.x + b.x + c.x, a.y + b.y + c.y );
}
// Sum of Four Vector2s
template< typename T >
inline
Vector2< T >
sum( Vector2< T > const & a, Vector2< T > const & b, Vector2< T > const & c, Vector2< T > const & d )
{
return Vector2< T >( a.x + b.x + c.x + d.x, a.y + b.y + c.y + d.y );
}
// Subtract of Two Vector2s
template< typename T >
inline
Vector2< T >
sub( Vector2< T > const & a, Vector2< T > const & b )
{
return Vector2< T >( a.x - b.x, a.y - b.y );
}
// Subtract of Two Vector2s
template< typename T >
inline
Vector2< T >
subtract( Vector2< T > const & a, Vector2< T > const & b )
{
return Vector2< T >( a.x - b.x, a.y - b.y );
}
// Midpoint of Two Vector2s
template< typename T >
inline
Vector2< T >
mid( Vector2< T > const & a, Vector2< T > const & b )
{
return Vector2< T >(
T( 0.5 * ( a.x + b.x ) ),
T( 0.5 * ( a.y + b.y ) )
);
}
// Center of Two Vector2s
template< typename T >
inline
Vector2< T >
cen( Vector2< T > const & a, Vector2< T > const & b )
{
return Vector2< T >(
T( 0.5 * ( a.x + b.x ) ),
T( 0.5 * ( a.y + b.y ) )
);
}
// Center of Three Vector2s
template< typename T >
inline
Vector2< T >
cen( Vector2< T > const & a, Vector2< T > const & b, Vector2< T > const & c )
{
static long double const third( 1.0 / 3.0 );
return Vector2< T >(
T( third * ( a.x + b.x + c.x ) ),
T( third * ( a.y + b.y + c.y ) )
);
}
// Center of Four Vector2s
template< typename T >
inline
Vector2< T >
cen( Vector2< T > const & a, Vector2< T > const & b, Vector2< T > const & c, Vector2< T > const & d )
{
return Vector2< T >(
T( 0.25 * ( a.x + b.x + c.x + d.x ) ),
T( 0.25 * ( a.y + b.y + c.y + d.y ) )
);
}
// Distance
template< typename T >
inline
T
distance( Vector2< T > const & a, Vector2< T > const & b )
{
return std::sqrt( Vector2< T >::square( a.x - b.x ) + Vector2< T >::square( a.y - b.y ) );
}
// Distance Squared
template< typename T >
inline
T
distance_squared( Vector2< T > const & a, Vector2< T > const & b )
{
return Vector2< T >::square( a.x - b.x ) + Vector2< T >::square( a.y - b.y );
}
// Dot Product
template< typename T >
inline
T
dot( Vector2< T > const & a, Vector2< T > const & b )
{
return ( a.x * b.x ) + ( a.y * b.y );
}
// Cross Product
template< typename T >
inline
T
cross( Vector2< T > const & a, Vector2< T > const & b )
{
return ( a.x * b.y ) - ( a.y * b.x );
}
// Angle Between Two Vector2s (in Radians on [0,pi])
template< typename T >
inline
T
angle( Vector2< T > const & a, Vector2< T > const & b )
{
T const axb( std::abs( a.cross( b ) ) );
T const adb( a.dot( b ) );
return ( ( axb != T( 0 ) ) || ( adb != T( 0 ) ) ? Vector2< T >::bump_up_angle( std::atan2( axb, adb ) ) : T( 0 ) ); // More accurate than dot-based for angles near 0 and Pi
}
// Angle abc Formed by Three Vector2s (in Radians on [0,pi])
template< typename T >
inline
T
angle( Vector2< T > const & a, Vector2< T > const & b, Vector2< T > const & c )
{
return angle( a - b, c - b );
}
// Cosine of Angle Between Two Vector2s
template< typename T >
inline
T
cos( Vector2< T > const & a, Vector2< T > const & b )
{
T const mag( std::sqrt( a.length_squared() * b.length_squared() ) );
return ( mag > T( 0 ) ? Vector2< T >::sin_cos_range( a.dot( b ) / mag ) : T( 1 ) );
}
// Cosine of Angle abc Formed by Three Vector2s
template< typename T >
inline
T
cos( Vector2< T > const & a, Vector2< T > const & b, Vector2< T > const & c )
{
return cos( a - b, c - b );
}
// Sine of Angle Between Two Vector2s
template< typename T >
inline
T
sin( Vector2< T > const & a, Vector2< T > const & b )
{
T const mag( std::sqrt( a.length_squared() * b.length_squared() ) );
return ( mag > T( 0 ) ? std::abs( Vector2< T >::sin_cos_range( a.cross( b ) / mag ) ) : T( 0 ) );
}
// Sine of Angle abc Formed by Three Vector2s
template< typename T >
inline
T
sin( Vector2< T > const & a, Vector2< T > const & b, Vector2< T > const & c )
{
return sin( a - b, c - b );
}
// Directed Angle Between Two Vector2s (in Radians on [0,2*pi])
template< typename T >
inline
T
dir_angle( Vector2< T > const & a, Vector2< T > const & b )
{
T const axb( a.cross( b ) );
T const adb( a.dot( b ) );
return ( ( axb != T( 0 ) ) || ( adb != T( 0 ) ) ? Vector2< T >::bump_up_angle( std::atan2( axb, adb ) ) : T( 0 ) );
}
// Directed Angle abc Formed by Three Vector2s (in Radians on [0,2*pi])
template< typename T >
inline
T
dir_angle( Vector2< T > const & a, Vector2< T > const & b, Vector2< T > const & c )
{
return dir_angle( a - b, c - b );
}
// Cosine of Directed Angle Between Two Vector2s
template< typename T >
inline
T
dir_cos( Vector2< T > const & a, Vector2< T > const & b )
{
T const mag( std::sqrt( a.length_squared() * b.length_squared() ) );
return ( mag > T( 0 ) ? Vector2< T >::sin_cos_range( a.dot( b ) / mag ) : T( 1 ) );
}
// Cosine of Directed Angle abc Formed by Three Vector2s
template< typename T >
inline
T
dir_cos( Vector2< T > const & a, Vector2< T > const & b, Vector2< T > const & c )
{
return dir_cos( a - b, c - b );
}
// Sine of Directed Angle Between Two Vector2s
template< typename T >
inline
T
dir_sin( Vector2< T > const & a, Vector2< T > const & b )
{
T const mag( std::sqrt( a.length_squared() * b.length_squared() ) );
return ( mag > T( 0 ) ? Vector2< T >::sin_cos_range( a.cross( b ) / mag ) : T( 0 ) );
}
// Sine of Directed Angle abc Formed by Three Vector2s
template< typename T >
inline
T
dir_sin( Vector2< T > const & a, Vector2< T > const & b, Vector2< T > const & c )
{
return dir_sin( a - b, c - b );
}
// Stream << Vector2 output operator
template< typename T >
std::ostream &
operator <<( std::ostream & stream, Vector2< T > const & v )
{
// Types
typedef TypeTraits< T > Traits;
// Save current stream state and set persistent state
std::ios_base::fmtflags const old_flags( stream.flags() );
std::streamsize const old_precision( stream.precision( Traits::precision ) );
stream << std::right << std::showpoint << std::uppercase;
// Output Vector2
std::size_t const w( Traits::width );
stream << std::setw( w ) << v.x << ' ' << std::setw( w ) << v.y;
// Restore previous stream state
stream.precision( old_precision );
stream.flags( old_flags );
return stream;
}
// Stream >> Vector2 input operator
// Supports whitespace-separated values with optional commas between values as long as whitespace is also present
// String or char values containing whitespace or commas or enclosed in quotes are not supported
// Vector can optionally be enclosed in parentheses () or square brackets []
template< typename T >
std::istream &
operator >>( std::istream & stream, Vector2< T > & v )
{
bool parens( false ); // Opening ( present?
bool brackets( false ); // Opening [ present?
{ // x
std::string input_string;
stream >> input_string;
if ( input_string == "(" ) { // Skip opening (
stream >> input_string;
parens = true;
} else if ( input_string[ 0 ] == '(' ) { // Skip opening (
input_string.erase( 0, 1 );
brackets = true;
} else if ( input_string == "[" ) { // Skip opening [
stream >> input_string;
brackets = true;
} else if ( input_string[ 0 ] == '[' ) { // Skip opening [
input_string.erase( 0, 1 );
brackets = true;
}
std::string::size_type const input_size( input_string.size() );
if ( ( input_size > 0 ) && ( input_string[ input_size - 1 ] == ',' ) ) {
input_string.erase( input_size - 1 ); // Remove trailing ,
}
std::istringstream num_stream( input_string );
num_stream >> v.x;
}
{ // y
std::string input_string;
stream >> input_string;
if ( input_string == "," ) { // Skip ,
stream >> input_string;
} else if ( input_string[ 0 ] == ',' ) { // Skip leading ,
input_string.erase( 0, 1 );
}
std::string::size_type input_size( input_string.size() );
if ( parens || brackets ) { // Remove closing ) or ]
if ( input_size > 0 ) {
if ( parens ) {
if ( input_string[ input_size - 1 ] == ')' ) { // Remove closing )
input_string.erase( input_size - 1 );
--input_size;
}
} else if ( brackets ) {
if ( input_string[ input_size - 1 ] == ']' ) { // Remove closing ]
input_string.erase( input_size - 1 );
--input_size;
}
}
}
}
if ( ( input_size > 0 ) && ( input_string[ input_size - 1 ] == ',' ) ) {
input_string.erase( input_size - 1 ); // Remove trailing ,
}
std::istringstream num_stream( input_string );
num_stream >> v.y;
}
// Remove closing ) or ] if opening ( or [ present
if ( parens || brackets ) { // Remove closing ) or ]
while ( ( stream.peek() == ' ' ) || ( stream.peek() == '\t' ) ) {
stream.ignore();
}
if ( parens ) { // Remove closing ) if present
if ( stream.peek() == ')' ) stream.ignore();
} else if ( brackets ) { // Remove closing ] if present
if ( stream.peek() == ']' ) stream.ignore();
}
}
return stream;
}
} // ObjexxFCL
#endif // ObjexxFCL_Vector2_hh_INCLUDED
// ===== ObjexxFCL/Vector3.fwd.hh =====
#ifndef ObjexxFCL_Vector3_fwd_hh_INCLUDED
#define ObjexxFCL_Vector3_fwd_hh_INCLUDED
// Vector3 Forward Declarations
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// C++ Headers
#include <cstddef>
#include <cstdint>
#include <string>
namespace ObjexxFCL {
// Forward
template< typename > class Vector3;
// Types
} // ObjexxFCL
#endif // ObjexxFCL_Vector3_fwd_hh_INCLUDED
// ===== ObjexxFCL/Vector3.hh =====
#ifndef ObjexxFCL_Vector3_hh_INCLUDED
#define ObjexxFCL_Vector3_hh_INCLUDED
// Vector3: Fast 3-Element Vector
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// ObjexxFCL Headers
// C++ Headers
#include <cassert>
#include <cmath>
#include <cstddef>
#include <cstdlib>
#include <initializer_list>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <type_traits>
namespace ObjexxFCL {
// Vector3: Fast 3-Element Vector
// . Heap-free and loop-free for speed
// . Provides direct element access via .x style lookup
// . Use std::array< T, 3 > instead in array/vectorization context
template< typename T >
class Vector3
{
private: // Friends
template< typename > friend class Vector3;
public: // Types
typedef TypeTraits< T > Traits;
typedef typename std::conditional< std::is_scalar< T >::value, T const, T const & >::type Tc;
typedef typename std::conditional< std::is_scalar< T >::value, typename std::remove_const< T >::type, T const & >::type Tr;
// STL Style
typedef T value_type;
typedef T & reference;
typedef T const & const_reference;
typedef T * pointer;
typedef T const * const_pointer;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
// C++ Style
typedef T Value;
typedef T & Reference;
typedef T const & ConstReference;
typedef T * Pointer;
typedef T const * ConstPointer;
typedef std::size_t Size;
typedef std::ptrdiff_t Difference;
public: // Creation
// Default Constructor
Vector3()
#if defined(OBJEXXFCL_ARRAY_INIT) || defined(OBJEXXFCL_ARRAY_INIT_DEBUG)
:
x( Traits::initial_array_value() ),
y( Traits::initial_array_value() ),
z( Traits::initial_array_value() )
#endif
{}
// Copy Constructor
Vector3( Vector3 const & v ) :
x( v.x ),
y( v.y ),
z( v.z )
{}
// Copy Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Vector3( Vector3< U > const & v ) :
x( v.x ),
y( v.y ),
z( v.z )
{}
// Uniform Value Constructor
explicit
Vector3( Tc t ) :
x( t ),
y( t ),
z( t )
{}
// Value Constructor
Vector3(
Tc x_,
Tc y_,
Tc z_
) :
x( x_ ),
y( y_ ),
z( z_ )
{}
// Initializer List Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Vector3( std::initializer_list< U > const l ) :
x( *l.begin() ),
y( *( l.begin() + 1 ) ),
z( *( l.begin() + 2 ) )
{
assert( l.size() == 3 );
}
// Array Constructor Template
template< typename A, class = typename std::enable_if< std::is_constructible< T, typename A::value_type >::value >::type >
Vector3( A const & a ) :
x( a[ 0 ] ),
y( a[ 1 ] ),
z( a[ 2 ] )
{
assert( a.size() == 3 );
}
// Default Vector Named Constructor
static
Vector3
default_vector()
{
return Vector3( T() );
}
// Zero Vector Named Constructor
static
Vector3
zero_vector()
{
return Vector3( T( 0 ) );
}
// x Vector of Specified Length Named Constructor
static
Vector3
x_vector( Tc tar_length = T( 1 ) )
{
return Vector3( tar_length, T( 0 ), T( 0 ) );
}
// y Vector of Specified Length Named Constructor
static
Vector3
y_vector( Tc tar_length = T( 1 ) )
{
return Vector3( T( 0 ), tar_length, T( 0 ) );
}
// z Vector of Specified Length Named Constructor
static
Vector3
z_vector( Tc tar_length = T( 1 ) )
{
return Vector3( T( 0 ), T( 0 ), tar_length );
}
// Uniform Vector of Specified Length Named Constructor
static
Vector3
uniform_vector( Tc tar_length = T( 1 ) )
{
return Vector3( tar_length / std::sqrt( T( 3 ) ) );
}
// Destructor
~Vector3()
{}
public: // Assignment
// Copy Assignment
Vector3 &
operator =( Vector3 const & v )
{
if ( this != &v ) {
x = v.x;
y = v.y;
z = v.z;
}
return *this;
}
// Copy Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector3 &
operator =( Vector3< U > const & v )
{
x = v.x;
y = v.y;
z = v.z;
return *this;
}
// Initializer List Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector3 &
operator =( std::initializer_list< U > const l )
{
assert( l.size() == 3 );
auto i( l.begin() );
x = *i;
y = *(++i);
z = *(++i);
return *this;
}
// Array Assignment Template
template< typename A, class = typename std::enable_if< std::is_assignable< T&, typename A::value_type >::value >::type >
Vector3 &
operator =( A const & a )
{
assert( a.size() == 3 );
x = a[ 0 ];
y = a[ 1 ];
z = a[ 2 ];
return *this;
}
// += Vector3
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector3 &
operator +=( Vector3< U > const & v )
{
x += v.x;
y += v.y;
z += v.z;
return *this;
}
// -= Vector3
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector3 &
operator -=( Vector3< U > const & v )
{
x -= v.x;
y -= v.y;
z -= v.z;
return *this;
}
// *= Vector3
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector3 &
operator *=( Vector3< U > const & v )
{
x *= v.x;
y *= v.y;
z *= v.z;
return *this;
}
// /= Vector3
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector3 &
operator /=( Vector3< U > const & v )
{
assert( v.x != T( 0 ) );
assert( v.y != T( 0 ) );
assert( v.z != T( 0 ) );
x /= v.x;
y /= v.y;
z /= v.z;
return *this;
}
// += Initializer List
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector3 &
operator +=( std::initializer_list< U > const l )
{
assert( l.size() == 3 );
auto i( l.begin() );
x += *i;
y += *(++i);
z += *(++i);
return *this;
}
// -= Initializer List
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector3 &
operator -=( std::initializer_list< U > const l )
{
assert( l.size() == 3 );
auto i( l.begin() );
x -= *i;
y -= *(++i);
z -= *(++i);
return *this;
}
// *= Initializer List
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector3 &
operator *=( std::initializer_list< U > const l )
{
assert( l.size() == 3 );
auto i( l.begin() );
x *= *i;
y *= *(++i);
z *= *(++i);
return *this;
}
// /= Initializer List
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector3 &
operator /=( std::initializer_list< U > const l )
{
assert( l.size() == 3 );
auto i( l.begin() );
assert( *i != T( 0 ) );
assert( *(i+1) != T( 0 ) );
assert( *(i+2) != T( 0 ) );
x /= *i;
y /= *(++i);
z /= *(++i);
return *this;
}
// += Array
template< typename A, class = typename std::enable_if< std::is_assignable< T&, typename A::value_type >::value >::type >
Vector3 &
operator +=( A const & a )
{
assert( a.size() == 3 );
x += a[ 0 ];
y += a[ 1 ];
z += a[ 2 ];
return *this;
}
// -= Array
template< typename A, class = typename std::enable_if< std::is_assignable< T&, typename A::value_type >::value >::type >
Vector3 &
operator -=( A const & a )
{
assert( a.size() == 3 );
x -= a[ 0 ];
y -= a[ 1 ];
z -= a[ 2 ];
return *this;
}
// *= Array
template< typename A, class = typename std::enable_if< std::is_assignable< T&, typename A::value_type >::value >::type >
Vector3 &
operator *=( A const & a )
{
assert( a.size() == 3 );
x *= a[ 0 ];
y *= a[ 1 ];
z *= a[ 2 ];
return *this;
}
// /= Array
template< typename A, class = typename std::enable_if< std::is_assignable< T&, typename A::value_type >::value >::type >
Vector3 &
operator /=( A const & a )
{
assert( a.size() == 3 );
assert( a[ 0 ] != T( 0 ) );
assert( a[ 1 ] != T( 0 ) );
assert( a[ 2 ] != T( 0 ) );
x /= a[ 0 ];
y /= a[ 1 ];
z /= a[ 2 ];
return *this;
}
// = Value
Vector3 &
operator =( Tc t )
{
x = y = z = t;
return *this;
}
// += Value
Vector3 &
operator +=( Tc t )
{
x += t;
y += t;
z += t;
return *this;
}
// -= Value
Vector3 &
operator -=( Tc t )
{
x -= t;
y -= t;
z -= t;
return *this;
}
// *= Value
Vector3 &
operator *=( Tc t )
{
x *= t;
y *= t;
z *= t;
return *this;
}
// /= Value
template< typename U, class = typename std::enable_if< std::is_floating_point< U >::value && std::is_assignable< T&, U >::value >::type, typename = void >
Vector3 &
operator /=( U const & u )
{
assert( u != U( 0 ) );
U const inv_u( U( 1 ) / u );
x *= inv_u;
y *= inv_u;
z *= inv_u;
return *this;
}
// /= Value
template< typename U, class = typename std::enable_if< ! std::is_floating_point< U >::value && std::is_assignable< T&, U >::value >::type, typename = void, typename = void >
Vector3 &
operator /=( U const & u )
{
assert( u != U( 0 ) );
x /= u;
y /= u;
z /= u;
return *this;
}
// Value Assignment
Vector3 &
assign(
Tc x_,
Tc y_,
Tc z_
)
{
x = x_;
y = y_;
z = z_;
return *this;
}
public: // Assignment: Scaled
// Assign Value * Vector3
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector3 &
scaled_assign( Tc t, Vector3< U > const & v )
{
x = t * v.x;
y = t * v.y;
z = t * v.z;
return *this;
}
// Add Value * Vector3
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector3 &
scaled_add( Tc t, Vector3< U > const & v )
{
x += t * v.x;
y += t * v.y;
z += t * v.z;
return *this;
}
// Subtract Value * Vector3
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector3 &
scaled_sub( Tc t, Vector3< U > const & v )
{
x -= t * v.x;
y -= t * v.y;
z -= t * v.z;
return *this;
}
// Multiply by Value * Vector3
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector3 &
scaled_mul( Tc t, Vector3< U > const & v )
{
x *= t * v.x;
y *= t * v.y;
z *= t * v.z;
return *this;
}
// Divide by Value * Vector3
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector3 &
scaled_div( Tc t, Vector3< U > const & v )
{
assert( t != T( 0 ) );
assert( v.x != T( 0 ) );
assert( v.y != T( 0 ) );
assert( v.z != T( 0 ) );
x /= t * v.x;
y /= t * v.y;
z /= t * v.z;
return *this;
}
public: // Subscript
// Vector3[ i ] const: 0-Based Index
Tr
operator []( size_type const i ) const
{
assert( i <= 2 );
return ( i == 0 ? x : ( i == 1 ? y : z ) );
}
// Vector3[ i ]: 0-Based Index
T &
operator []( size_type const i )
{
assert( i <= 2 );
return ( i == 0 ? x : ( i == 1 ? y : z ) );
}
// Vector3( i ) const: 1-Based Index
Tr
operator ()( size_type const i ) const
{
assert( ( 1 <= i ) && ( i <= 3 ) );
return ( i == 1 ? x : ( i == 2 ? y : z ) );
}
// Vector3( i ): 1-Based Index
T &
operator ()( size_type const i )
{
assert( ( 1 <= i ) && ( i <= 3 ) );
return ( i == 1 ? x : ( i == 2 ? y : z ) );
}
public: // Properties: Predicates
// Is Zero Vector?
bool
is_zero() const
{
static T const ZERO( 0 );
return ( x == ZERO ) && ( y == ZERO ) && ( z == ZERO );
}
// Is Unit Vector?
bool
is_unit() const
{
return ( length_squared() == T( 1 ) );
}
public: // Properties: General
// Size
Size
size() const
{
return 3u;
}
// Length
T
length() const
{
return std::sqrt( ( x * x ) + ( y * y ) + ( z * z ) );
}
// Length Squared
T
length_squared() const
{
return ( x * x ) + ( y * y ) + ( z * z );
}
// Magnitude
T
magnitude() const
{
return std::sqrt( ( x * x ) + ( y * y ) + ( z * z ) );
}
// Magnitude
T
mag() const
{
return std::sqrt( ( x * x ) + ( y * y ) + ( z * z ) );
}
// Magnitude Squared
T
magnitude_squared() const
{
return ( x * x ) + ( y * y ) + ( z * z );
}
// Magnitude Squared
T
mag_squared() const
{
return ( x * x ) + ( y * y ) + ( z * z );
}
// L1 Norm
T
norm_L1() const
{
return std::abs( x ) + std::abs( y ) + std::abs( z );
}
// L2 Norm
T
norm_L2() const
{
return std::sqrt( ( x * x ) + ( y * y ) + ( z * z ) );
}
// L-infinity Norm
T
norm_Linf() const
{
return ObjexxFCL::max( std::abs( x ), std::abs( y ), std::abs( z ) );
}
// Distance to a Vector3
T
distance( Vector3 const & v ) const
{
return std::sqrt( square( x - v.x ) + square( y - v.y ) + square( z - v.z ) );
}
// Distance Squared to a Vector3
T
distance_squared( Vector3 const & v ) const
{
return square( x - v.x ) + square( y - v.y ) + square( z - v.z );
}
// Dot Product with a Vector3
T
dot( Vector3 const & v ) const
{
return ( x * v.x ) + ( y * v.y ) + ( z * v.z );
}
// Dot Product with an Array
template< typename A, class = typename std::enable_if< std::is_assignable< T&, typename A::value_type >::value >::type >
T
dot( A const & a ) const
{
assert( a.size() == 3 );
return ( x * a[ 0 ] ) + ( y * a[ 1 ] ) + ( z * a[ 2 ] );
}
// Cross Product with a Vector3
Vector3
cross( Vector3 const & v ) const
{
return Vector3(
( y * v.z ) - ( z * v.y ),
( z * v.x ) - ( x * v.z ),
( x * v.y ) - ( y * v.x )
);
}
// Cross Product with an Array
template< typename A, class = typename std::enable_if< std::is_assignable< T&, typename A::value_type >::value >::type >
Vector3
cross( A const & a ) const
{
assert( a.size() == 3 );
return Vector3(
( y * a[ 2 ] ) - ( z * a[ 1 ] ),
( z * a[ 0 ] ) - ( x * a[ 2 ] ),
( x * a[ 1 ] ) - ( y * a[ 0 ] )
);
}
// Alias for Element 1
Tr
x1() const
{
return x;
}
// Alias for Element 1
T &
x1()
{
return x;
}
// Alias for Element 2
Tr
x2() const
{
return y;
}
// Alias for Element 2
T &
x2()
{
return y;
}
// Alias for Element 3
Tr
x3() const
{
return z;
}
// Alias for Element 3
T &
x3()
{
return z;
}
public: // Modifiers
// Zero
Vector3 &
zero()
{
x = y = z = T( 0 );
return *this;
}
// Negate
Vector3 &
negate()
{
x = -x;
y = -y;
z = -z;
return *this;
}
// Normalize to a Length
Vector3 &
normalize( Tc tar_length = T( 1 ) )
{
T const cur_length( length() );
assert( cur_length != T ( 0 ) );
T const dilation( tar_length / cur_length );
x *= dilation;
y *= dilation;
z *= dilation;
return *this;
}
// Normalize to a Length: Zero Vector3 if Length is Zero
Vector3 &
normalize_zero( Tc tar_length = T( 1 ) )
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
x *= dilation;
y *= dilation;
z *= dilation;
} else { // Set zero vector
x = y = z = T( 0 );
}
return *this;
}
// Normalize to a Length: Uniform Vector3 if Length is Zero
Vector3 &
normalize_uniform( Tc tar_length = T( 1 ) )
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
x *= dilation;
y *= dilation;
z *= dilation;
} else { // Set uniform vector
operator =( uniform_vector( tar_length ) );
}
return *this;
}
// Normalize to a Length: x Vector3 if Length is Zero
Vector3 &
normalize_x( Tc tar_length = T( 1 ) )
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
x *= dilation;
y *= dilation;
z *= dilation;
} else { // Set x vector
x = tar_length;
y = z = T( 0 );
}
return *this;
}
// Normalize to a Length: y Vector3 if Length is Zero
Vector3 &
normalize_y( Tc tar_length = T( 1 ) )
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
x *= dilation;
y *= dilation;
z *= dilation;
} else { // Set y vector
y = tar_length;
x = z = T( 0 );
}
return *this;
}
// Normalize to a Length: z Vector3 if Length is Zero
Vector3 &
normalize_z( Tc tar_length = T( 1 ) )
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
x *= dilation;
y *= dilation;
z *= dilation;
} else { // Set z vector
z = tar_length;
x = y = T( 0 );
}
return *this;
}
// Minimum Coordinates with a Vector3
Vector3 &
min( Vector3 const & v )
{
x = ( x <= v.x ? x : v.x );
y = ( y <= v.y ? y : v.y );
z = ( z <= v.z ? z : v.z );
return *this;
}
// Maximum Coordinates with a Vector3
Vector3 &
max( Vector3 const & v )
{
x = ( x >= v.x ? x : v.x );
y = ( y >= v.y ? y : v.y );
z = ( z >= v.z ? z : v.z );
return *this;
}
// Add a Vector3
Vector3 &
add( Vector3 const & v )
{
x += v.x;
y += v.y;
z += v.z;
return *this;
}
// Sum a Vector3
Vector3 &
sum( Vector3 const & v )
{
x += v.x;
y += v.y;
z += v.z;
return *this;
}
// Subtract a Vector3
Vector3 &
sub( Vector3 const & v )
{
x -= v.x;
y -= v.y;
z -= v.z;
return *this;
}
// Subtract a Vector3
Vector3 &
subtract( Vector3 const & v )
{
x -= v.x;
y -= v.y;
z -= v.z;
return *this;
}
// Project Normal to a Vector3
Vector3 &
project_normal( Vector3 const & v )
{
assert( v.length_squared() != T( 0 ) );
T const c( dot( v ) / v.length_squared() );
x -= c * v.x;
y -= c * v.y;
z -= c * v.z;
return *this;
}
// Project onto a Vector3
Vector3 &
project_parallel( Vector3 const & v )
{
assert( v.length_squared() != T( 0 ) );
T const c( dot( v ) / v.length_squared() );
x = c * v.x;
y = c * v.y;
z = c * v.z;
return *this;
}
public: // Generators
// -Vector3 (Negated)
Vector3
operator -() const
{
return Vector3( -x, -y, -z );
}
// Negated
Vector3
negated() const
{
return Vector3( -x, -y, -z );
}
// Normalized to a Length
Vector3
normalized( Tc tar_length = T( 1 ) ) const
{
T const cur_length( length() );
assert( cur_length != T ( 0 ) );
T const dilation( tar_length / cur_length );
return Vector3(
x * dilation,
y * dilation,
z * dilation
);
}
// Normalized to a Length: Zero Vector3 if Length is Zero
Vector3
normalized_zero( Tc tar_length = T( 1 ) ) const
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
return Vector3(
x * dilation,
y * dilation,
z * dilation
);
} else { // Return zero vector
return Vector3( T( 0 ) );
}
}
// Normalized to a Length: Uniform Vector3 if Length is Zero
Vector3
normalized_uniform( Tc tar_length = T( 1 ) ) const
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
return Vector3(
x * dilation,
y * dilation,
z * dilation
);
} else { // Return uniform vector
return uniform_vector( tar_length );
}
}
// Normalized to a Length: x Vector3 if Length is Zero
Vector3
normalized_x( Tc tar_length = T( 1 ) ) const
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
return Vector3(
x * dilation,
y * dilation,
z * dilation
);
} else { // Return x vector
return Vector3( tar_length, T( 0 ), T( 0 ) );
}
}
// Normalized to a Length: y Vector3 if Length is Zero
Vector3
normalized_y( Tc tar_length = T( 1 ) ) const
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
return Vector3(
x * dilation,
y * dilation,
z * dilation
);
} else { // Return y vector
return Vector3( T( 0 ), tar_length, T( 0 ) );
}
}
// Normalized to a Length: z Vector3 if Length is Zero
Vector3
normalized_z( Tc tar_length = T( 1 ) ) const
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
return Vector3(
x * dilation,
y * dilation,
z * dilation
);
} else { // Return z vector
return Vector3( tar_length, T( 0 ), T( 0 ), tar_length );
}
}
// Projected Normal to a Vector3
Vector3
projected_normal( Vector3 const & v ) const
{
assert( v.length_squared() != T( 0 ) );
T const c( dot( v ) / v.length_squared() );
return Vector3( x - ( c * v.x ), y - ( c * v.y ), z - ( c * v.z ) );
}
// Projected onto a Vector3
Vector3
projected_parallel( Vector3 const & v ) const
{
assert( v.length_squared() != T( 0 ) );
T const c( dot( v ) / v.length_squared() );
return Vector3( c * v.x, c * v.y, c * v.z );
}
public: // Static Methods
// Square of a value
static
T
square( Tc t )
{
return t * t;
}
// Value Clipped to [-1,1]
static
T
sin_cos_range( Tc t )
{
return std::min( std::max( t, T( -1 ) ), T( 1 ) );
}
// Add 2*Pi to a Negative Value
static
T
bump_up_angle( Tc t )
{
static T const Two_Pi( T( 2 ) * std::acos( -1.0 ) );
return ( t >= T( 0 ) ? t : Two_Pi + t );
}
public: // Data
T x, y, z; // Elements
}; // Vector3
// Length
template< typename T >
inline
T
length( Vector3< T > const & v )
{
return v.length();
}
// Length Squared
template< typename T >
inline
T
length_squared( Vector3< T > const & v )
{
return v.length_squared();
}
// Magnitude
template< typename T >
inline
T
magnitude( Vector3< T > const & v )
{
return v.magnitude();
}
// Magnitude
template< typename T >
inline
T
mag( Vector3< T > const & v )
{
return v.mag();
}
// Magnitude Squared
template< typename T >
inline
T
magnitude_squared( Vector3< T > const & v )
{
return v.magnitude_squared();
}
// Magnitude Squared
template< typename T >
inline
T
mag_squared( Vector3< T > const & v )
{
return v.mag_squared();
}
// Vector3 == Vector3
template< typename T >
inline
bool
operator ==( Vector3< T > const & a, Vector3< T > const & b )
{
return ( a.x == b.x ) && ( a.y == b.y ) && ( a.z == b.z );
}
// Vector3 != Vector3
template< typename T >
inline
bool
operator !=( Vector3< T > const & a, Vector3< T > const & b )
{
return ( a.x != b.x ) || ( a.y != b.y ) || ( a.z != b.z );
}
// Vector3 < Vector3: Lexicographic
template< typename T >
inline
bool
operator <( Vector3< T > const & a, Vector3< T > const & b )
{
return (
( a.x < b.x ? true :
( b.x < a.x ? false : // a.x == b.x
( a.y < b.y ? true :
( b.y < a.y ? false : // a.y == b.y
( a.z < b.z ) ) ) ) )
);
}
// Vector3 <= Vector3: Lexicographic
template< typename T >
inline
bool
operator <=( Vector3< T > const & a, Vector3< T > const & b )
{
return (
( a.x < b.x ? true :
( b.x < a.x ? false : // a.x == b.x
( a.y < b.y ? true :
( b.y < a.y ? false : // a.y == b.y
( a.z <= b.z ) ) ) ) )
);
}
// Vector3 >= Vector3: Lexicographic
template< typename T >
inline
bool
operator >=( Vector3< T > const & a, Vector3< T > const & b )
{
return (
( a.x > b.x ? true :
( b.x > a.x ? false : // a.x == b.x
( a.y > b.y ? true :
( b.y > a.y ? false : // a.y == b.y
( a.z >= b.z ) ) ) ) )
);
}
// Vector3 > Vector3: Lexicographic
template< typename T >
inline
bool
operator >( Vector3< T > const & a, Vector3< T > const & b )
{
return (
( a.x > b.x ? true :
( b.x > a.x ? false : // a.x == b.x
( a.y > b.y ? true :
( b.y > a.y ? false : // a.y == b.y
( a.z > b.z ) ) ) ) )
);
}
// Vector3 < Vector3: Element-wise
template< typename T >
inline
bool
lt( Vector3< T > const & a, Vector3< T > const & b )
{
return ( a.x < b.x ) && ( a.y < b.y ) && ( a.z < b.z );
}
// Vector3 <= Vector3: Element-wise
template< typename T >
inline
bool
le( Vector3< T > const & a, Vector3< T > const & b )
{
return ( a.x <= b.x ) && ( a.y <= b.y ) && ( a.z <= b.z );
}
// Vector3 >= Vector3: Element-wise
template< typename T >
inline
bool
ge( Vector3< T > const & a, Vector3< T > const & b )
{
return ( a.x >= b.x ) && ( a.y >= b.y ) && ( a.z >= b.z );
}
// Vector3 > Vector3: Element-wise
template< typename T >
inline
bool
gt( Vector3< T > const & a, Vector3< T > const & b )
{
return ( a.x > b.x ) && ( a.y > b.y ) && ( a.z > b.z );
}
// Vector3 == Value
template< typename T >
inline
bool
operator ==( Vector3< T > const & v, typename Vector3< T >::Tc t )
{
return ( v.x == t ) && ( v.y == t ) && ( v.z == t );
}
// Vector3 != Value
template< typename T >
inline
bool
operator !=( Vector3< T > const & v, typename Vector3< T >::Tc t )
{
return ( v.x != t ) || ( v.y != t ) || ( v.z != t );
}
// Vector3 < Value
template< typename T >
inline
bool
operator <( Vector3< T > const & v, typename Vector3< T >::Tc t )
{
return ( v.x < t ) && ( v.y < t ) && ( v.z < t );
}
// Vector3 <= Value
template< typename T >
inline
bool
operator <=( Vector3< T > const & v, typename Vector3< T >::Tc t )
{
return ( v.x <= t ) && ( v.y <= t ) && ( v.z <= t );
}
// Vector3 >= Value
template< typename T >
inline
bool
operator >=( Vector3< T > const & v, typename Vector3< T >::Tc t )
{
return ( v.x >= t ) && ( v.y >= t ) && ( v.z >= t );
}
// Vector3 > Value
template< typename T >
inline
bool
operator >( Vector3< T > const & v, typename Vector3< T >::Tc t )
{
return ( v.x > t ) && ( v.y > t ) && ( v.z > t );
}
// Value == Vector3
template< typename T >
inline
bool
operator ==( typename Vector3< T >::Tc t, Vector3< T > const & v )
{
return ( t == v.x ) && ( t == v.y ) && ( t == v.z );
}
// Value != Vector3
template< typename T >
inline
bool
operator !=( typename Vector3< T >::Tc t, Vector3< T > const & v )
{
return ( t != v.x ) || ( t != v.y ) || ( t != v.z );
}
// Value < Vector3
template< typename T >
inline
bool
operator <( typename Vector3< T >::Tc t, Vector3< T > const & v )
{
return ( t < v.x ) && ( t < v.y ) && ( t < v.z );
}
// Value <= Vector3
template< typename T >
inline
bool
operator <=( typename Vector3< T >::Tc t, Vector3< T > const & v )
{
return ( t <= v.x ) && ( t <= v.y ) && ( t <= v.z );
}
// Value >= Vector3
template< typename T >
inline
bool
operator >=( typename Vector3< T >::Tc t, Vector3< T > const & v )
{
return ( t >= v.x ) && ( t >= v.y ) && ( t >= v.z );
}
// Value > Vector3
template< typename T >
inline
bool
operator >( typename Vector3< T >::Tc t, Vector3< T > const & v )
{
return ( t > v.x ) && ( t > v.y ) && ( t > v.z );
}
// Equal Length?
template< typename T >
inline
bool
equal_length( Vector3< T > const & a, Vector3< T > const & b )
{
return ( a.length_squared() == b.length_squared() );
}
// Not Equal Length?
template< typename T >
inline
bool
not_equal_length( Vector3< T > const & a, Vector3< T > const & b )
{
return ( a.length_squared() != b.length_squared() );
}
// Vector3 + Vector3
template< typename T >
inline
Vector3< T >
operator +( Vector3< T > const & a, Vector3< T > const & b )
{
return Vector3< T >( a.x + b.x, a.y + b.y, a.z + b.z );
}
// Vector3 + Value
template< typename T >
inline
Vector3< T >
operator +( Vector3< T > const & v, typename Vector3< T >::Tc t )
{
return Vector3< T >( v.x + t, v.y + t, v.z + t );
}
// Value + Vector3
template< typename T >
inline
Vector3< T >
operator +( typename Vector3< T >::Tc t, Vector3< T > const & v )
{
return Vector3< T >( t + v.x, t + v.y, t + v.z );
}
// Vector3 - Vector3
template< typename T >
inline
Vector3< T >
operator -( Vector3< T > const & a, Vector3< T > const & b )
{
return Vector3< T >( a.x - b.x, a.y - b.y, a.z - b.z );
}
// Vector3 - Value
template< typename T >
inline
Vector3< T >
operator -( Vector3< T > const & v, typename Vector3< T >::Tc t )
{
return Vector3< T >( v.x - t, v.y - t, v.z - t );
}
// Value - Vector3
template< typename T >
inline
Vector3< T >
operator -( typename Vector3< T >::Tc t, Vector3< T > const & v )
{
return Vector3< T >( t - v.x, t - v.y, t - v.z );
}
// Vector3 * Vector3
template< typename T >
inline
Vector3< T >
operator *( Vector3< T > const & a, Vector3< T > const & b )
{
return Vector3< T >( a.x * b.x, a.y * b.y, a.z * b.z );
}
// Vector3 * Value
template< typename T >
inline
Vector3< T >
operator *( Vector3< T > const & v, typename Vector3< T >::Tc t )
{
return Vector3< T >( v.x * t, v.y * t, v.z * t );
}
// Value * Vector3
template< typename T >
inline
Vector3< T >
operator *( typename Vector3< T >::Tc t, Vector3< T > const & v )
{
return Vector3< T >( t * v.x, t * v.y, t * v.z );
}
// Vector3 / Vector3
template< typename T >
inline
Vector3< T >
operator /( Vector3< T > const & a, Vector3< T > const & b )
{
assert( b.x != T( 0 ) );
assert( b.y != T( 0 ) );
assert( b.z != T( 0 ) );
return Vector3< T >( a.x / b.x, a.y / b.y, a.z / b.z );
}
// Vector3 / Value
template< typename T, typename U, class = typename std::enable_if< std::is_floating_point< U >::value && std::is_assignable< T&, U >::value >::type >
inline
Vector3< T >
operator /( Vector3< T > const & v, U const & u )
{
assert( u != U( 0 ) );
U const inv_u( U ( 1 ) / u );
return Vector3< T >( v.x * inv_u, v.y * inv_u, v.z * inv_u );
}
// Vector3 / Value
template< typename T, typename U, class = typename std::enable_if< ! std::is_floating_point< U >::value && std::is_assignable< T&, U >::value >::type, typename = void >
inline
Vector3< T >
operator /( Vector3< T > const & v, U const & u )
{
assert( u != U( 0 ) );
return Vector3< T >( v.x / u, v.y / u, v.z / u );
}
// Value / Vector3
template< typename T >
inline
Vector3< T >
operator /( typename Vector3< T >::Tc t, Vector3< T > const & v )
{
assert( v.x != T( 0 ) );
assert( v.y != T( 0 ) );
assert( v.z != T( 0 ) );
return Vector3< T >( t / v.x, t / v.y, t / v.z );
}
// Minimum of Two Vector3s
template< typename T >
inline
Vector3< T >
min( Vector3< T > const & a, Vector3< T > const & b )
{
return Vector3< T >(
( a.x <= b.x ? a.x : b.x ),
( a.y <= b.y ? a.y : b.y ),
( a.z <= b.z ? a.z : b.z )
);
}
// Minimum of Three Vector3s
template< typename T >
inline
Vector3< T >
min( Vector3< T > const & a, Vector3< T > const & b, Vector3< T > const & c )
{
return Vector3< T >(
ObjexxFCL::min( a.x, b.x, c.x ),
ObjexxFCL::min( a.y, b.y, c.y ),
ObjexxFCL::min( a.z, b.z, c.z )
);
}
// Minimum of Four Vector3s
template< typename T >
inline
Vector3< T >
min( Vector3< T > const & a, Vector3< T > const & b, Vector3< T > const & c, Vector3< T > const & d )
{
return Vector3< T >(
ObjexxFCL::min( a.x, b.x, c.x, d.x ),
ObjexxFCL::min( a.y, b.y, c.y, d.y ),
ObjexxFCL::min( a.z, b.z, c.z, d.z )
);
}
// Maximum of Two Vector3s
template< typename T >
inline
Vector3< T >
max( Vector3< T > const & a, Vector3< T > const & b )
{
return Vector3< T >(
( a.x >= b.x ? a.x : b.x ),
( a.y >= b.y ? a.y : b.y ),
( a.z >= b.z ? a.z : b.z )
);
}
// Maximum of Three Vector3s
template< typename T >
inline
Vector3< T >
max( Vector3< T > const & a, Vector3< T > const & b, Vector3< T > const & c )
{
return Vector3< T >(
ObjexxFCL::max( a.x, b.x, c.x ),
ObjexxFCL::max( a.y, b.y, c.y ),
ObjexxFCL::max( a.z, b.z, c.z )
);
}
// Maximum of Four Vector3s
template< typename T >
inline
Vector3< T >
max( Vector3< T > const & a, Vector3< T > const & b, Vector3< T > const & c, Vector3< T > const & d )
{
return Vector3< T >(
ObjexxFCL::max( a.x, b.x, c.x, d.x ),
ObjexxFCL::max( a.y, b.y, c.y, d.y ),
ObjexxFCL::max( a.z, b.z, c.z, d.z )
);
}
// Sum of Two Vector3s
template< typename T >
inline
Vector3< T >
sum( Vector3< T > const & a, Vector3< T > const & b )
{
return Vector3< T >( a.x + b.x, a.y + b.y, a.z + b.z );
}
// Sum of Three Vector3s
template< typename T >
inline
Vector3< T >
sum( Vector3< T > const & a, Vector3< T > const & b, Vector3< T > const & c )
{
return Vector3< T >( a.x + b.x + c.x, a.y + b.y + c.y, a.z + b.z + c.z );
}
// Sum of Four Vector3s
template< typename T >
inline
Vector3< T >
sum( Vector3< T > const & a, Vector3< T > const & b, Vector3< T > const & c, Vector3< T > const & d )
{
return Vector3< T >( a.x + b.x + c.x + d.x, a.y + b.y + c.y + d.y, a.z + b.z + c.z + d.z );
}
// Subtract of Two Vector3s
template< typename T >
inline
Vector3< T >
sub( Vector3< T > const & a, Vector3< T > const & b )
{
return Vector3< T >( a.x - b.x, a.y - b.y, a.z - b.z );
}
// Subtract of Two Vector3s
template< typename T >
inline
Vector3< T >
subtract( Vector3< T > const & a, Vector3< T > const & b )
{
return Vector3< T >( a.x - b.x, a.y - b.y, a.z - b.z );
}
// Midpoint of Two Vector3s
template< typename T >
inline
Vector3< T >
mid( Vector3< T > const & a, Vector3< T > const & b )
{
return Vector3< T >(
T( 0.5 * ( a.x + b.x ) ),
T( 0.5 * ( a.y + b.y ) ),
T( 0.5 * ( a.z + b.z ) )
);
}
// Center of Two Vector3s
template< typename T >
inline
Vector3< T >
cen( Vector3< T > const & a, Vector3< T > const & b )
{
return Vector3< T >(
T( 0.5 * ( a.x + b.x ) ),
T( 0.5 * ( a.y + b.y ) ),
T( 0.5 * ( a.z + b.z ) )
);
}
// Center of Three Vector3s
template< typename T >
inline
Vector3< T >
cen( Vector3< T > const & a, Vector3< T > const & b, Vector3< T > const & c )
{
static long double const third( 1.0 / 3.0 );
return Vector3< T >(
T( third * ( a.x + b.x + c.x ) ),
T( third * ( a.y + b.y + c.y ) ),
T( third * ( a.z + b.z + c.z ) )
);
}
// Center of Four Vector3s
template< typename T >
inline
Vector3< T >
cen( Vector3< T > const & a, Vector3< T > const & b, Vector3< T > const & c, Vector3< T > const & d )
{
return Vector3< T >(
T( 0.25 * ( a.x + b.x + c.x + d.x ) ),
T( 0.25 * ( a.y + b.y + c.y + d.y ) ),
T( 0.25 * ( a.z + b.z + c.z + d.z ) )
);
}
// Distance
template< typename T >
inline
T
distance( Vector3< T > const & a, Vector3< T > const & b )
{
return std::sqrt( Vector3< T >::square( a.x - b.x ) + Vector3< T >::square( a.y - b.y ) + Vector3< T >::square( a.z - b.z ) );
}
// Distance Squared
template< typename T >
inline
T
distance_squared( Vector3< T > const & a, Vector3< T > const & b )
{
return Vector3< T >::square( a.x - b.x ) + Vector3< T >::square( a.y - b.y ) + Vector3< T >::square( a.z - b.z );
}
// Dot Product
template< typename T >
inline
T
dot( Vector3< T > const & a, Vector3< T > const & b )
{
return ( a.x * b.x ) + ( a.y * b.y ) + ( a.z * b.z );
}
// Cross Product
template< typename T >
inline
Vector3< T >
cross( Vector3< T > const & a, Vector3< T > const & b )
{
return Vector3< T >(
( a.y * b.z ) - ( a.z * b.y ),
( a.z * b.x ) - ( a.x * b.z ),
( a.x * b.y ) - ( a.y * b.x )
);
}
// Angle Between Two Vector3s (in Radians on [0,pi])
template< typename T >
inline
T
angle( Vector3< T > const & a, Vector3< T > const & b )
{
T const axb( a.cross( b ).magnitude() );
T const adb( a.dot( b ) );
return ( ( axb != T( 0 ) ) || ( adb != T( 0 ) ) ? Vector3< T >::bump_up_angle( std::atan2( axb, adb ) ) : T( 0 ) ); // More accurate than dot-based for angles near 0 and Pi
}
// Angle abc Formed by Three Vector3s (in Radians on [0,pi])
template< typename T >
inline
T
angle( Vector3< T > const & a, Vector3< T > const & b, Vector3< T > const & c )
{
return angle( a - b, c - b );
}
// Cosine of Angle Between Two Vector3s
template< typename T >
inline
T
cos( Vector3< T > const & a, Vector3< T > const & b )
{
T const mag( std::sqrt( a.length_squared() * b.length_squared() ) );
return ( mag > T( 0 ) ? Vector3< T >::sin_cos_range( a.dot( b ) / mag ) : T( 1 ) );
}
// Cosine of Angle abc Formed by Three Vector3s
template< typename T >
inline
T
cos( Vector3< T > const & a, Vector3< T > const & b, Vector3< T > const & c )
{
return cos( a - b, c - b );
}
// Sine of Angle Between Two Vector3s
template< typename T >
inline
T
sin( Vector3< T > const & a, Vector3< T > const & b )
{
T const mag( std::sqrt( a.length_squared() * b.length_squared() ) );
return ( mag > T( 0 ) ? std::abs( Vector3< T >::sin_cos_range( a.cross( b ).magnitude() / mag ) ) : T( 0 ) );
}
// Sine of Angle abc Formed by Three Vector3s
template< typename T >
inline
T
sin( Vector3< T > const & a, Vector3< T > const & b, Vector3< T > const & c )
{
return sin( a - b, c - b );
}
// Stream << Vector3 output operator
template< typename T >
std::ostream &
operator <<( std::ostream & stream, Vector3< T > const & v )
{
// Types
typedef TypeTraits< T > Traits;
// Save current stream state and set persistent state
std::ios_base::fmtflags const old_flags( stream.flags() );
std::streamsize const old_precision( stream.precision( Traits::precision ) );
stream << std::right << std::showpoint << std::uppercase;
// Output Vector3
std::size_t const w( Traits::width );
stream << std::setw( w ) << v.x << ' ' << std::setw( w ) << v.y << ' ' << std::setw( w ) << v.z;
// Restore previous stream state
stream.precision( old_precision );
stream.flags( old_flags );
return stream;
}
// Stream >> Vector3 input operator
// Supports whitespace-separated values with optional commas between values as long as whitespace is also present
// String or char values containing whitespace or commas or enclosed in quotes are not supported
// Vector can optionally be enclosed in parentheses () or square brackets []
template< typename T >
std::istream &
operator >>( std::istream & stream, Vector3< T > & v )
{
bool parens( false ); // Opening ( present?
bool brackets( false ); // Opening [ present?
{ // x
std::string input_string;
stream >> input_string;
if ( input_string == "(" ) { // Skip opening (
stream >> input_string;
parens = true;
} else if ( input_string[ 0 ] == '(' ) { // Skip opening (
input_string.erase( 0, 1 );
brackets = true;
} else if ( input_string == "[" ) { // Skip opening [
stream >> input_string;
brackets = true;
} else if ( input_string[ 0 ] == '[' ) { // Skip opening [
input_string.erase( 0, 1 );
brackets = true;
}
std::string::size_type const input_size( input_string.size() );
if ( ( input_size > 0 ) && ( input_string[ input_size - 1 ] == ',' ) ) {
input_string.erase( input_size - 1 ); // Remove trailing ,
}
std::istringstream num_stream( input_string );
num_stream >> v.x;
}
{ // y
std::string input_string;
stream >> input_string;
if ( input_string == "," ) { // Skip ,
stream >> input_string;
} else if ( input_string[ 0 ] == ',' ) { // Skip leading ,
input_string.erase( 0, 1 );
}
std::string::size_type const input_size( input_string.size() );
if ( ( input_size > 0 ) && ( input_string[ input_size - 1 ] == ',' ) ) {
input_string.erase( input_size - 1 ); // Remove trailing ,
}
std::istringstream num_stream( input_string );
num_stream >> v.y;
}
{ // z
std::string input_string;
stream >> input_string;
if ( input_string == "," ) { // Skip ,
stream >> input_string;
} else if ( input_string[ 0 ] == ',' ) { // Skip leading ,
input_string.erase( 0, 1 );
}
std::string::size_type input_size( input_string.size() );
if ( parens || brackets ) { // Remove closing ) or ]
if ( input_size > 0 ) {
if ( parens ) {
if ( input_string[ input_size - 1 ] == ')' ) { // Remove closing )
input_string.erase( input_size - 1 );
--input_size;
}
} else if ( brackets ) {
if ( input_string[ input_size - 1 ] == ']' ) { // Remove closing ]
input_string.erase( input_size - 1 );
--input_size;
}
}
}
}
if ( ( input_size > 0 ) && ( input_string[ input_size - 1 ] == ',' ) ) {
input_string.erase( input_size - 1 ); // Remove trailing ,
}
std::istringstream num_stream( input_string );
num_stream >> v.z;
}
// Remove closing ) or ] if opening ( or [ present
if ( parens || brackets ) { // Remove closing ) or ]
while ( ( stream.peek() == ' ' ) || ( stream.peek() == '\t' ) ) {
stream.ignore();
}
if ( parens ) { // Remove closing ) if present
if ( stream.peek() == ')' ) stream.ignore();
} else if ( brackets ) { // Remove closing ] if present
if ( stream.peek() == ']' ) stream.ignore();
}
}
return stream;
}
} // ObjexxFCL
#endif // ObjexxFCL_Vector3_hh_INCLUDED
// ===== ObjexxFCL/Vector4.fwd.hh =====
#ifndef ObjexxFCL_Vector4_fwd_hh_INCLUDED
#define ObjexxFCL_Vector4_fwd_hh_INCLUDED
// Vector3 Forward Declarations
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// C++ Headers
#include <cstddef>
#include <cstdint>
#include <string>
namespace ObjexxFCL {
// Forward
template< typename > class Vector4;
// Types
} // ObjexxFCL
#endif // ObjexxFCL_Vector3_fwd_hh_INCLUDED
// ===== ObjexxFCL/Vector4.hh =====
#ifndef ObjexxFCL_Vector4_hh_INCLUDED
#define ObjexxFCL_Vector4_hh_INCLUDED
// Vector4: Fast 4-Element Vector
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// ObjexxFCL Headers
// C++ Headers
#include <cassert>
#include <cmath>
#include <cstddef>
#include <cstdlib>
#include <initializer_list>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <type_traits>
namespace ObjexxFCL {
// Vector4: Fast 4-Element Vector
// . Heap-free and loop-free for speed
// . Provides direct element access via .x style lookup
// . Use std::array< T, 4 > instead in array/vectorization context
template< typename T >
class Vector4
{
private: // Friends
template< typename > friend class Vector4;
public: // Types
typedef TypeTraits< T > Traits;
typedef typename std::conditional< std::is_scalar< T >::value, T const, T const & >::type Tc;
typedef typename std::conditional< std::is_scalar< T >::value, typename std::remove_const< T >::type, T const & >::type Tr;
// STL Style
typedef T value_type;
typedef T & reference;
typedef T const & const_reference;
typedef T * pointer;
typedef T const * const_pointer;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
// C++ Style
typedef T Value;
typedef T & Reference;
typedef T const & ConstReference;
typedef T * Pointer;
typedef T const * ConstPointer;
typedef std::size_t Size;
typedef std::ptrdiff_t Difference;
public: // Creation
// Default Constructor
Vector4()
#if defined(OBJEXXFCL_ARRAY_INIT) || defined(OBJEXXFCL_ARRAY_INIT_DEBUG)
:
x( Traits::initial_array_value() ),
y( Traits::initial_array_value() ),
z( Traits::initial_array_value() ),
w( Traits::initial_array_value() )
#endif
{}
// Copy Constructor
Vector4( Vector4 const & v ) :
x( v.x ),
y( v.y ),
z( v.z ),
w( v.w )
{}
// Copy Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Vector4( Vector4< U > const & v ) :
x( v.x ),
y( v.y ),
z( v.z ),
w( v.w )
{}
// Uniform Value Constructor
explicit
Vector4( Tc t ) :
x( t ),
y( t ),
z( t ),
w( t )
{}
// Value Constructor
Vector4(
Tc x_,
Tc y_,
Tc z_,
Tc w_
) :
x( x_ ),
y( y_ ),
z( z_ ),
w( w_ )
{}
// Initializer List Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Vector4( std::initializer_list< U > const l ) :
x( *l.begin() ),
y( *( l.begin() + 1 ) ),
z( *( l.begin() + 2 ) ),
w( *( l.begin() + 3 ) )
{
assert( l.size() == 4 );
}
// Array Constructor Template
template< typename A, class = typename std::enable_if< std::is_constructible< T, typename A::value_type >::value >::type >
Vector4( A const & a ) :
x( a[ 0 ] ),
y( a[ 1 ] ),
z( a[ 2 ] ),
w( a[ 3 ] )
{
assert( a.size() == 4 );
}
// Default Vector Named Constructor
static
Vector4
default_vector()
{
return Vector4( T() );
}
// Zero Vector Named Constructor
static
Vector4
zero_vector()
{
return Vector4( T( 0 ) );
}
// x Vector of Specified Length Named Constructor
static
Vector4
x_vector( Tc tar_length = T( 1 ) )
{
return Vector4( tar_length, T( 0 ), T( 0 ), T( 0 ) );
}
// y Vector of Specified Length Named Constructor
static
Vector4
y_vector( Tc tar_length = T( 1 ) )
{
return Vector4( T( 0 ), tar_length, T( 0 ), T( 0 ) );
}
// z Vector of Specified Length Named Constructor
static
Vector4
z_vector( Tc tar_length = T( 1 ) )
{
return Vector4( T( 0 ), T( 0 ), tar_length, T( 0 ) );
}
// W Vector of Specified Length Named Constructor
static
Vector4
W_vector( Tc tar_length = T( 1 ) )
{
return Vector4( T( 0 ), T( 0 ), T( 0 ), tar_length, T( 0 ) );
}
// Uniform Vector of Specified Length Named Constructor
static
Vector4
uniform_vector( Tc tar_length = T( 1 ) )
{
return Vector4( tar_length / T( 2 ) );
}
// Destructor
~Vector4()
{}
public: // Assignment
// Copy Assignment
Vector4 &
operator =( Vector4 const & v )
{
if ( this != &v ) {
x = v.x;
y = v.y;
z = v.z;
w = v.w;
}
return *this;
}
// Copy Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector4 &
operator =( Vector4< U > const & v )
{
x = v.x;
y = v.y;
z = v.z;
w = v.w;
return *this;
}
// Initializer List Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector4 &
operator =( std::initializer_list< U > const l )
{
assert( l.size() == 4 );
auto i( l.begin() );
x = *i;
y = *(++i);
z = *(++i);
w = *(++i);
return *this;
}
// Array Assignment Template
template< typename A, class = typename std::enable_if< std::is_assignable< T&, typename A::value_type >::value >::type >
Vector4 &
operator =( A const & a )
{
assert( a.size() == 4 );
x = a[ 0 ];
y = a[ 1 ];
z = a[ 2 ];
w = a[ 3 ];
return *this;
}
// += Vector4
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector4 &
operator +=( Vector4< U > const & v )
{
x += v.x;
y += v.y;
z += v.z;
w += v.w;
return *this;
}
// -= Vector4
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector4 &
operator -=( Vector4< U > const & v )
{
x -= v.x;
y -= v.y;
z -= v.z;
w -= v.w;
return *this;
}
// *= Vector4
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector4 &
operator *=( Vector4< U > const & v )
{
x *= v.x;
y *= v.y;
z *= v.z;
w *= v.w;
return *this;
}
// /= Vector4
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector4 &
operator /=( Vector4< U > const & v )
{
assert( v.x != T( 0 ) );
assert( v.y != T( 0 ) );
assert( v.z != T( 0 ) );
assert( v.w != T( 0 ) );
x /= v.x;
y /= v.y;
z /= v.z;
w /= v.w;
return *this;
}
// += Initializer List
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector4 &
operator +=( std::initializer_list< U > const l )
{
assert( l.size() == 4 );
auto i( l.begin() );
x += *i;
y += *(++i);
z += *(++i);
w += *(++i);
return *this;
}
// -= Initializer List
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector4 &
operator -=( std::initializer_list< U > const l )
{
assert( l.size() == 4 );
auto i( l.begin() );
x -= *i;
y -= *(++i);
z -= *(++i);
w -= *(++i);
return *this;
}
// *= Initializer List
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector4 &
operator *=( std::initializer_list< U > const l )
{
assert( l.size() == 4 );
auto i( l.begin() );
x *= *i;
y *= *(++i);
z *= *(++i);
w *= *(++i);
return *this;
}
// /= Initializer List
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector4 &
operator /=( std::initializer_list< U > const l )
{
assert( l.size() == 4 );
auto i( l.begin() );
assert( *i != T( 0 ) );
assert( *(i+1) != T( 0 ) );
assert( *(i+2) != T( 0 ) );
assert( *(i+3) != T( 0 ) );
x /= *i;
y /= *(++i);
z /= *(++i);
w /= *(++i);
return *this;
}
// += Array
template< typename A, class = typename std::enable_if< std::is_assignable< T&, typename A::value_type >::value >::type >
Vector4 &
operator +=( A const & a )
{
assert( a.size() == 4 );
x += a[ 0 ];
y += a[ 1 ];
z += a[ 2 ];
w += a[ 3 ];
return *this;
}
// -= Array
template< typename A, class = typename std::enable_if< std::is_assignable< T&, typename A::value_type >::value >::type >
Vector4 &
operator -=( A const & a )
{
assert( a.size() == 4 );
x -= a[ 0 ];
y -= a[ 1 ];
z -= a[ 2 ];
w -= a[ 3 ];
return *this;
}
// *= Array
template< typename A, class = typename std::enable_if< std::is_assignable< T&, typename A::value_type >::value >::type >
Vector4 &
operator *=( A const & a )
{
assert( a.size() == 4 );
x *= a[ 0 ];
y *= a[ 1 ];
z *= a[ 2 ];
w *= a[ 3 ];
return *this;
}
// /= Array
template< typename A, class = typename std::enable_if< std::is_assignable< T&, typename A::value_type >::value >::type >
Vector4 &
operator /=( A const & a )
{
assert( a.size() == 4 );
assert( a[ 0 ] != T( 0 ) );
assert( a[ 1 ] != T( 0 ) );
assert( a[ 2 ] != T( 0 ) );
assert( a[ 3 ] != T( 0 ) );
x /= a[ 0 ];
y /= a[ 1 ];
z /= a[ 2 ];
w /= a[ 3 ];
return *this;
}
// = Value
Vector4 &
operator =( Tc t )
{
x = y = z = w = t;
return *this;
}
// += Value
Vector4 &
operator +=( Tc t )
{
x += t;
y += t;
z += t;
w += t;
return *this;
}
// -= Value
Vector4 &
operator -=( Tc t )
{
x -= t;
y -= t;
z -= t;
w -= t;
return *this;
}
// *= Value
Vector4 &
operator *=( Tc t )
{
x *= t;
y *= t;
z *= t;
w *= t;
return *this;
}
// /= Value
template< typename U, class = typename std::enable_if< std::is_floating_point< U >::value && std::is_assignable< T&, U >::value >::type, typename = void >
Vector4 &
operator /=( U const & u )
{
assert( u != U( 0 ) );
U const inv_u( U( 1 ) / u );
x *= inv_u;
y *= inv_u;
z *= inv_u;
w *= inv_u;
return *this;
}
// /= Value
template< typename U, class = typename std::enable_if< ! std::is_floating_point< U >::value && std::is_assignable< T&, U >::value >::type, typename = void, typename = void >
Vector4 &
operator /=( U const & u )
{
assert( u != U( 0 ) );
x /= u;
y /= u;
z /= u;
w /= u;
return *this;
}
// Value Assignment
Vector4 &
assign(
Tc x_,
Tc y_,
Tc z_,
Tc w_
)
{
x = x_;
y = y_;
z = z_;
w = w_;
return *this;
}
public: // Assignment: Scaled
// Assign Value * Vector4
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector4 &
scaled_assign( Tc t, Vector4< U > const & v )
{
x = t * v.x;
y = t * v.y;
z = t * v.z;
w = t * v.w;
return *this;
}
// Add Value * Vector4
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector4 &
scaled_add( Tc t, Vector4< U > const & v )
{
x += t * v.x;
y += t * v.y;
z += t * v.z;
w += t * v.w;
return *this;
}
// Subtract Value * Vector4
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector4 &
scaled_sub( Tc t, Vector4< U > const & v )
{
x -= t * v.x;
y -= t * v.y;
z -= t * v.z;
w -= t * v.w;
return *this;
}
// Multiply by Value * Vector4
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector4 &
scaled_mul( Tc t, Vector4< U > const & v )
{
x *= t * v.x;
y *= t * v.y;
z *= t * v.z;
w *= t * v.w;
return *this;
}
// Divide by Value * Vector4
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Vector4 &
scaled_div( Tc t, Vector4< U > const & v )
{
assert( t != T( 0 ) );
assert( v.x != T( 0 ) );
assert( v.y != T( 0 ) );
assert( v.z != T( 0 ) );
assert( v.w != T( 0 ) );
x /= t * v.x;
y /= t * v.y;
z /= t * v.z;
w /= t * v.w;
return *this;
}
public: // Subscript
// Vector4[ i ] const: 0-Based Index
Tr
operator []( size_type const i ) const
{
assert( i <= 3 );
return ( i < 2 ? ( i == 0 ? x : y ) : ( i == 2 ? z : w ) );
}
// Vector4[ i ]: 0-Based Index
T &
operator []( size_type const i )
{
assert( i <= 3 );
return ( i < 2 ? ( i == 0 ? x : y ) : ( i == 2 ? z : w ) );
}
// Vector4( i ) const: 1-Based Index
Tr
operator ()( size_type const i ) const
{
assert( ( 1 <= i ) && ( i <= 4 ) );
return ( i <= 2 ? ( i == 1 ? x : y ) : ( i == 3 ? z : w ) );
}
// Vector4( i ): 1-Based Index
T &
operator ()( size_type const i )
{
assert( ( 1 <= i ) && ( i <= 4 ) );
return ( i <= 2 ? ( i == 1 ? x : y ) : ( i == 3 ? z : w ) );
}
public: // Properties: Predicates
// Is Zero Vector?
bool
is_zero() const
{
static T const ZERO( 0 );
return ( x == ZERO ) && ( y == ZERO ) && ( z == ZERO ) && ( w == ZERO );
}
// Is Unit Vector?
bool
is_unit() const
{
return ( length_squared() == T( 1 ) );
}
public: // Properties: General
// Size
Size
size() const
{
return 4u;
}
// Length
T
length() const
{
return std::sqrt( ( x * x ) + ( y * y ) + ( z * z ) + ( w * w ) );
}
// Length Squared
T
length_squared() const
{
return ( x * x ) + ( y * y ) + ( z * z ) + ( w * w );
}
// Magnitude
T
magnitude() const
{
return std::sqrt( ( x * x ) + ( y * y ) + ( z * z ) + ( w * w ) );
}
// Magnitude
T
mag() const
{
return std::sqrt( ( x * x ) + ( y * y ) + ( z * z ) + ( w * w ) );
}
// Magnitude Squared
T
magnitude_squared() const
{
return ( x * x ) + ( y * y ) + ( z * z ) + ( w * w );
}
// Magnitude Squared
T
mag_squared() const
{
return ( x * x ) + ( y * y ) + ( z * z ) + ( w * w );
}
// L1 Norm
T
norm_L1() const
{
return std::abs( x ) + std::abs( y ) + std::abs( z ) + std::abs( w );
}
// L2 Norm
T
norm_L2() const
{
return std::sqrt( ( x * x ) + ( y * y ) + ( z * z ) + ( w * w ) );
}
// L-infinity Norm
T
norm_Linf() const
{
return ObjexxFCL::max( std::abs( x ), std::abs( y ), std::abs( z ), std::abs( w ) );
}
// Distance to a Vector4
T
distance( Vector4 const & v ) const
{
return std::sqrt( square( x - v.x ) + square( y - v.y ) + square( z - v.z ) + square( w - v.w ) );
}
// Distance Squared to a Vector4
T
distance_squared( Vector4 const & v ) const
{
return square( x - v.x ) + square( y - v.y ) + square( z - v.z ) + square( w - v.w );
}
// Dot Product with a Vector4
T
dot( Vector4 const & v ) const
{
return ( x * v.x ) + ( y * v.y ) + ( z * v.z ) + ( w * v.w );
}
// Dot Product with an Array
template< typename A, class = typename std::enable_if< std::is_assignable< T&, typename A::value_type >::value >::type >
T
dot( A const & a ) const
{
assert( a.size() == 4 );
return ( x * a[ 0 ] ) + ( y * a[ 1 ] ) + ( z * a[ 2 ] ) + ( w * a[ 3 ] );
}
// Alias for Element 1
Tr
x1() const
{
return x;
}
// Alias for Element 1
T &
x1()
{
return x;
}
// Alias for Element 2
Tr
x2() const
{
return y;
}
// Alias for Element 2
T &
x2()
{
return y;
}
// Alias for Element 3
Tr
x3() const
{
return z;
}
// Alias for Element 3
T &
x3()
{
return z;
}
// Alias for Element 4
Tr
x4() const
{
return w;
}
// Alias for Element 4
T &
x4()
{
return w;
}
public: // Modifiers
// Zero
Vector4 &
zero()
{
x = y = z = w = T( 0 );
return *this;
}
// Negate
Vector4 &
negate()
{
x = -x;
y = -y;
z = -z;
w = -w;
return *this;
}
// Normalize to a Length
Vector4 &
normalize( Tc tar_length = T( 1 ) )
{
T const cur_length( length() );
assert( cur_length != T ( 0 ) );
T const dilation( tar_length / cur_length );
x *= dilation;
y *= dilation;
z *= dilation;
w *= dilation;
return *this;
}
// Normalize to a Length: Zero Vector4 if Length is Zero
Vector4 &
normalize_zero( Tc tar_length = T( 1 ) )
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
x *= dilation;
y *= dilation;
z *= dilation;
w *= dilation;
} else { // Set zero vector
x = y = z = w = T( 0 );
}
return *this;
}
// Normalize to a Length: Uniform Vector4 if Length is Zero
Vector4 &
normalize_uniform( Tc tar_length = T( 1 ) )
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
x *= dilation;
y *= dilation;
z *= dilation;
w *= dilation;
} else { // Set uniform vector
operator =( uniform_vector( tar_length ) );
}
return *this;
}
// Normalize to a Length: x Vector4 if Length is Zero
Vector4 &
normalize_x( Tc tar_length = T( 1 ) )
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
x *= dilation;
y *= dilation;
z *= dilation;
w *= dilation;
} else { // Set x vector
x = tar_length;
y = z = w = T( 0 );
}
return *this;
}
// Normalize to a Length: y Vector4 if Length is Zero
Vector4 &
normalize_y( Tc tar_length = T( 1 ) )
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
x *= dilation;
y *= dilation;
z *= dilation;
w *= dilation;
} else { // Set y vector
y = tar_length;
x = z = w = T( 0 );
}
return *this;
}
// Normalize to a Length: z Vector4 if Length is Zero
Vector4 &
normalize_z( Tc tar_length = T( 1 ) )
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
x *= dilation;
y *= dilation;
z *= dilation;
w *= dilation;
} else { // Set z vector
z = tar_length;
x = y = w = T( 0 );
}
return *this;
}
// Normalize to a Length: w Vector4 if Length is Zero
Vector4 &
normalize_w( Tc tar_length = T( 1 ) )
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
x *= dilation;
y *= dilation;
z *= dilation;
w *= dilation;
} else { // Set z vector
w = tar_length;
x = y = z = T( 0 );
}
return *this;
}
// Minimum Coordinates with a Vector4
Vector4 &
min( Vector4 const & v )
{
x = ( x <= v.x ? x : v.x );
y = ( y <= v.y ? y : v.y );
z = ( z <= v.z ? z : v.z );
w = ( w <= v.w ? w : v.w );
return *this;
}
// Maximum Coordinates with a Vector4
Vector4 &
max( Vector4 const & v )
{
x = ( x >= v.x ? x : v.x );
y = ( y >= v.y ? y : v.y );
z = ( z >= v.z ? z : v.z );
w = ( w >= v.w ? w : v.w );
return *this;
}
// Add a Vector4
Vector4 &
add( Vector4 const & v )
{
x += v.x;
y += v.y;
z += v.z;
w += v.w;
return *this;
}
// Sum a Vector4
Vector4 &
sum( Vector4 const & v )
{
x += v.x;
y += v.y;
z += v.z;
w += v.w;
return *this;
}
// Subtract a Vector4
Vector4 &
sub( Vector4 const & v )
{
x -= v.x;
y -= v.y;
z -= v.z;
w -= v.w;
return *this;
}
// Subtract a Vector4
Vector4 &
subtract( Vector4 const & v )
{
x -= v.x;
y -= v.y;
z -= v.z;
w -= v.w;
return *this;
}
// Project Normal to a Vector4
Vector4 &
project_normal( Vector4 const & v )
{
assert( v.length_squared() != T( 0 ) );
T const c( dot( v ) / v.length_squared() );
x -= c * v.x;
y -= c * v.y;
z -= c * v.z;
w -= c * v.w;
return *this;
}
// Project onto a Vector4
Vector4 &
project_parallel( Vector4 const & v )
{
assert( v.length_squared() != T( 0 ) );
T const c( dot( v ) / v.length_squared() );
x = c * v.x;
y = c * v.y;
z = c * v.z;
w = c * v.w;
return *this;
}
public: // Generators
// -Vector4 (Negated)
Vector4
operator -() const
{
return Vector4( -x, -y, -z, -w );
}
// Negated
Vector4
negated() const
{
return Vector4( -x, -y, -z, -w );
}
// Normalized to a Length
Vector4
normalized( Tc tar_length = T( 1 ) ) const
{
T const cur_length( length() );
assert( cur_length != T ( 0 ) );
T const dilation( tar_length / cur_length );
return Vector4(
x * dilation,
y * dilation,
z * dilation,
w * dilation
);
}
// Normalized to a Length: Zero Vector4 if Length is Zero
Vector4
normalized_zero( Tc tar_length = T( 1 ) ) const
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
return Vector4(
x * dilation,
y * dilation,
z * dilation,
w * dilation
);
} else { // Return zero vector
return Vector4( T( 0 ) );
}
}
// Normalized to a Length: Uniform Vector4 if Length is Zero
Vector4
normalized_uniform( Tc tar_length = T( 1 ) ) const
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
return Vector4(
x * dilation,
y * dilation,
z * dilation,
w * dilation
);
} else { // Return uniform vector
return uniform_vector( tar_length );
}
}
// Normalized to a Length: x Vector4 if Length is Zero
Vector4
normalized_x( Tc tar_length = T( 1 ) ) const
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
return Vector4(
x * dilation,
y * dilation,
z * dilation,
w * dilation
);
} else { // Return x vector
return Vector4( tar_length, T( 0 ), T( 0 ), T( 0 ) );
}
}
// Normalized to a Length: y Vector4 if Length is Zero
Vector4
normalized_y( Tc tar_length = T( 1 ) ) const
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
return Vector4(
x * dilation,
y * dilation,
z * dilation,
w * dilation
);
} else { // Return y vector
return Vector4( T( 0 ), tar_length, T( 0 ), T( 0 ) );
}
}
// Normalized to a Length: z Vector4 if Length is Zero
Vector4
normalized_z( Tc tar_length = T( 1 ) ) const
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
return Vector4(
x * dilation,
y * dilation,
z * dilation,
w * dilation
);
} else { // Return z vector
return Vector4( tar_length, T( 0 ), T( 0 ), tar_length, T( 0 ) );
}
}
// Normalized to a Length: w Vector4 if Length is Zero
Vector4
normalized_w( Tc tar_length = T( 1 ) ) const
{
T const cur_length( length() );
if ( cur_length > T( 0 ) ) {
T const dilation( tar_length / cur_length );
return Vector4(
x * dilation,
y * dilation,
z * dilation,
w * dilation
);
} else { // Return z vector
return Vector4( tar_length, T( 0 ), T( 0 ), T( 0 ), tar_length );
}
}
// Projected Normal to a Vector4
Vector4
projected_normal( Vector4 const & v ) const
{
assert( v.length_squared() != T( 0 ) );
T const c( dot( v ) / v.length_squared() );
return Vector4( x - ( c * v.x ), y - ( c * v.y ), z - ( c * v.z ), w - ( c * v.w ) );
}
// Projected onto a Vector4
Vector4
projected_parallel( Vector4 const & v ) const
{
assert( v.length_squared() != T( 0 ) );
T const c( dot( v ) / v.length_squared() );
return Vector4( c * v.x, c * v.y, c * v.z, c * v.w );
}
public: // Static Methods
// Square of a value
static
T
square( Tc t )
{
return t * t;
}
// Value Clipped to [-1,1]
static
T
sin_cos_range( Tc t )
{
return std::min( std::max( t, T( -1 ) ), T( 1 ) );
}
// Add 2*Pi to a Negative Value
static
T
bump_up_angle( Tc t )
{
static T const Two_Pi( T( 2 ) * std::acos( -1.0 ) );
return ( t >= T( 0 ) ? t : Two_Pi + t );
}
public: // Data
T x, y, z, w; // Elements
}; // Vector4
// Length
template< typename T >
inline
T
length( Vector4< T > const & v )
{
return v.length();
}
// Length Squared
template< typename T >
inline
T
length_squared( Vector4< T > const & v )
{
return v.length_squared();
}
// Magnitude
template< typename T >
inline
T
magnitude( Vector4< T > const & v )
{
return v.magnitude();
}
// Magnitude
template< typename T >
inline
T
mag( Vector4< T > const & v )
{
return v.mag();
}
// Magnitude Squared
template< typename T >
inline
T
magnitude_squared( Vector4< T > const & v )
{
return v.magnitude_squared();
}
// Magnitude Squared
template< typename T >
inline
T
mag_squared( Vector4< T > const & v )
{
return v.mag_squared();
}
// Vector4 == Vector4
template< typename T >
inline
bool
operator ==( Vector4< T > const & a, Vector4< T > const & b )
{
return ( a.x == b.x ) && ( a.y == b.y ) && ( a.z == b.z ) && ( a.w == b.w );
}
// Vector4 != Vector4
template< typename T >
inline
bool
operator !=( Vector4< T > const & a, Vector4< T > const & b )
{
return ( a.x != b.x ) || ( a.y != b.y ) || ( a.z != b.z ) || ( a.w != b.w );
}
// Vector4 < Vector4: Lexicographic
template< typename T >
inline
bool
operator <( Vector4< T > const & a, Vector4< T > const & b )
{
return (
( a.x < b.x ? true :
( b.x < a.x ? false : // a.x == b.x
( a.y < b.y ? true :
( b.y < a.y ? false : // a.y == b.y
( a.z < b.z ? true :
( b.z < a.z ? false : // a.z == b.z
( a.w < b.w ) ) ) ) ) ) )
);
}
// Vector4 <= Vector4: Lexicographic
template< typename T >
inline
bool
operator <=( Vector4< T > const & a, Vector4< T > const & b )
{
return (
( a.x < b.x ? true :
( b.x < a.x ? false : // a.x == b.x
( a.y < b.y ? true :
( b.y < a.y ? false : // a.y == b.y
( a.z < b.z ? true :
( b.z < a.z ? false : // a.z == b.z
( a.w <= b.w ) ) ) ) ) ) )
);
}
// Vector4 >= Vector4: Lexicographic
template< typename T >
inline
bool
operator >=( Vector4< T > const & a, Vector4< T > const & b )
{
return (
( a.x > b.x ? true :
( b.x > a.x ? false : // a.x == b.x
( a.y > b.y ? true :
( b.y > a.y ? false : // a.y == b.y
( a.z > b.z ? true :
( b.z > a.z ? false : // a.z == b.z
( a.w >= b.w ) ) ) ) ) ) )
);
}
// Vector4 > Vector4: Lexicographic
template< typename T >
inline
bool
operator >( Vector4< T > const & a, Vector4< T > const & b )
{
return (
( a.x > b.x ? true :
( b.x > a.x ? false : // a.x == b.x
( a.y > b.y ? true :
( b.y > a.y ? false : // a.y == b.y
( a.z > b.z ? true :
( b.z > a.z ? false : // a.z == b.z
( a.w > b.w ) ) ) ) ) ) )
);
}
// Vector4 < Vector4: Element-wise
template< typename T >
inline
bool
lt( Vector4< T > const & a, Vector4< T > const & b )
{
return ( a.x < b.x ) && ( a.y < b.y ) && ( a.z < b.z ) && ( a.w < b.w );
}
// Vector4 <= Vector4: Element-wise
template< typename T >
inline
bool
le( Vector4< T > const & a, Vector4< T > const & b )
{
return ( a.x <= b.x ) && ( a.y <= b.y ) && ( a.z <= b.z ) && ( a.w <= b.w );
}
// Vector4 >= Vector4: Element-wise
template< typename T >
inline
bool
ge( Vector4< T > const & a, Vector4< T > const & b )
{
return ( a.x >= b.x ) && ( a.y >= b.y ) && ( a.z >= b.z ) && ( a.w >= b.w );
}
// Vector4 > Vector4: Element-wise
template< typename T >
inline
bool
gt( Vector4< T > const & a, Vector4< T > const & b )
{
return ( a.x > b.x ) && ( a.y > b.y ) && ( a.z > b.z ) && ( a.w > b.w );
}
// Vector4 == Value
template< typename T >
inline
bool
operator ==( Vector4< T > const & v, typename Vector4< T >::Tc t )
{
return ( v.x == t ) && ( v.y == t ) && ( v.z == t ) && ( v.w == t );
}
// Vector4 != Value
template< typename T >
inline
bool
operator !=( Vector4< T > const & v, typename Vector4< T >::Tc t )
{
return ( v.x != t ) || ( v.y != t ) || ( v.z != t ) || ( v.w != t );
}
// Vector4 < Value
template< typename T >
inline
bool
operator <( Vector4< T > const & v, typename Vector4< T >::Tc t )
{
return ( v.x < t ) && ( v.y < t ) && ( v.z < t ) && ( v.w < t );
}
// Vector4 <= Value
template< typename T >
inline
bool
operator <=( Vector4< T > const & v, typename Vector4< T >::Tc t )
{
return ( v.x <= t ) && ( v.y <= t ) && ( v.z <= t ) && ( v.w <= t );
}
// Vector4 >= Value
template< typename T >
inline
bool
operator >=( Vector4< T > const & v, typename Vector4< T >::Tc t )
{
return ( v.x >= t ) && ( v.y >= t ) && ( v.z >= t ) && ( v.w >= t );
}
// Vector4 > Value
template< typename T >
inline
bool
operator >( Vector4< T > const & v, typename Vector4< T >::Tc t )
{
return ( v.x > t ) && ( v.y > t ) && ( v.z > t ) && ( v.w > t );
}
// Value == Vector4
template< typename T >
inline
bool
operator ==( typename Vector4< T >::Tc t, Vector4< T > const & v )
{
return ( t == v.x ) && ( t == v.y ) && ( t == v.z ) && ( t == v.w );
}
// Value != Vector4
template< typename T >
inline
bool
operator !=( typename Vector4< T >::Tc t, Vector4< T > const & v )
{
return ( t != v.x ) || ( t != v.y ) || ( t != v.z ) || ( t != v.w );
}
// Value < Vector4
template< typename T >
inline
bool
operator <( typename Vector4< T >::Tc t, Vector4< T > const & v )
{
return ( t < v.x ) && ( t < v.y ) && ( t < v.z ) && ( t < v.w );
}
// Value <= Vector4
template< typename T >
inline
bool
operator <=( typename Vector4< T >::Tc t, Vector4< T > const & v )
{
return ( t <= v.x ) && ( t <= v.y ) && ( t <= v.z ) && ( t <= v.w );
}
// Value >= Vector4
template< typename T >
inline
bool
operator >=( typename Vector4< T >::Tc t, Vector4< T > const & v )
{
return ( t >= v.x ) && ( t >= v.y ) && ( t >= v.z ) && ( t >= v.w );
}
// Value > Vector4
template< typename T >
inline
bool
operator >( typename Vector4< T >::Tc t, Vector4< T > const & v )
{
return ( t > v.x ) && ( t > v.y ) && ( t > v.z ) && ( t > v.w );
}
// Equal Length?
template< typename T >
inline
bool
equal_length( Vector4< T > const & a, Vector4< T > const & b )
{
return ( a.length_squared() == b.length_squared() );
}
// Not Equal Length?
template< typename T >
inline
bool
not_equal_length( Vector4< T > const & a, Vector4< T > const & b )
{
return ( a.length_squared() != b.length_squared() );
}
// Vector4 + Vector4
template< typename T >
inline
Vector4< T >
operator +( Vector4< T > const & a, Vector4< T > const & b )
{
return Vector4< T >( a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w );
}
// Vector4 + Value
template< typename T >
inline
Vector4< T >
operator +( Vector4< T > const & v, typename Vector4< T >::Tc t )
{
return Vector4< T >( v.x + t, v.y + t, v.z + t, v.w + t );
}
// Value + Vector4
template< typename T >
inline
Vector4< T >
operator +( typename Vector4< T >::Tc t, Vector4< T > const & v )
{
return Vector4< T >( t + v.x, t + v.y, t + v.z, t + v.w );
}
// Vector4 - Vector4
template< typename T >
inline
Vector4< T >
operator -( Vector4< T > const & a, Vector4< T > const & b )
{
return Vector4< T >( a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w );
}
// Vector4 - Value
template< typename T >
inline
Vector4< T >
operator -( Vector4< T > const & v, typename Vector4< T >::Tc t )
{
return Vector4< T >( v.x - t, v.y - t, v.z - t, v.w - t );
}
// Value - Vector4
template< typename T >
inline
Vector4< T >
operator -( typename Vector4< T >::Tc t, Vector4< T > const & v )
{
return Vector4< T >( t - v.x, t - v.y, t - v.z, t - v.w );
}
// Vector4 * Vector4
template< typename T >
inline
Vector4< T >
operator *( Vector4< T > const & a, Vector4< T > const & b )
{
return Vector4< T >( a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w );
}
// Vector4 * Value
template< typename T >
inline
Vector4< T >
operator *( Vector4< T > const & v, typename Vector4< T >::Tc t )
{
return Vector4< T >( v.x * t, v.y * t, v.z * t, v.w * t );
}
// Value * Vector4
template< typename T >
inline
Vector4< T >
operator *( typename Vector4< T >::Tc t, Vector4< T > const & v )
{
return Vector4< T >( t * v.x, t * v.y, t * v.z, t * v.w );
}
// Vector4 / Vector4
template< typename T >
inline
Vector4< T >
operator /( Vector4< T > const & a, Vector4< T > const & b )
{
assert( b.x != T( 0 ) );
assert( b.y != T( 0 ) );
assert( b.z != T( 0 ) );
assert( b.w != T( 0 ) );
return Vector4< T >( a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w );
}
// Vector4 / Value
template< typename T, typename U, class = typename std::enable_if< std::is_floating_point< U >::value && std::is_assignable< T&, U >::value >::type >
inline
Vector4< T >
operator /( Vector4< T > const & v, U const & u )
{
assert( u != U( 0 ) );
U const inv_u( U ( 1 ) / u );
return Vector4< T >( v.x * inv_u, v.y * inv_u, v.z * inv_u, v.w * inv_u );
}
// Vector4 / Value
template< typename T, typename U, class = typename std::enable_if< ! std::is_floating_point< U >::value && std::is_assignable< T&, U >::value >::type, typename = void >
inline
Vector4< T >
operator /( Vector4< T > const & v, U const & u )
{
assert( u != U( 0 ) );
return Vector4< T >( v.x / u, v.y / u, v.z / u, v.w / u );
}
// Value / Vector4
template< typename T >
inline
Vector4< T >
operator /( typename Vector4< T >::Tc t, Vector4< T > const & v )
{
assert( v.x != T( 0 ) );
assert( v.y != T( 0 ) );
assert( v.z != T( 0 ) );
assert( v.w != T( 0 ) );
return Vector4< T >( t / v.x, t / v.y, t / v.z, t / v.w );
}
// Minimum of Two Vector4s
template< typename T >
inline
Vector4< T >
min( Vector4< T > const & a, Vector4< T > const & b )
{
return Vector4< T >(
( a.x <= b.x ? a.x : b.x ),
( a.y <= b.y ? a.y : b.y ),
( a.z <= b.z ? a.z : b.z ),
( a.w <= b.w ? a.w : b.w )
);
}
// Minimum of Three Vector4s
template< typename T >
inline
Vector4< T >
min( Vector4< T > const & a, Vector4< T > const & b, Vector4< T > const & c )
{
return Vector4< T >(
ObjexxFCL::min( a.x, b.x, c.x ),
ObjexxFCL::min( a.y, b.y, c.y ),
ObjexxFCL::min( a.z, b.z, c.z ),
ObjexxFCL::min( a.w, b.w, c.w )
);
}
// Minimum of Four Vector4s
template< typename T >
inline
Vector4< T >
min( Vector4< T > const & a, Vector4< T > const & b, Vector4< T > const & c, Vector4< T > const & d )
{
return Vector4< T >(
ObjexxFCL::min( a.x, b.x, c.x, d.x ),
ObjexxFCL::min( a.y, b.y, c.y, d.y ),
ObjexxFCL::min( a.z, b.z, c.z, d.z ),
ObjexxFCL::min( a.w, b.w, c.w, d.w )
);
}
// Maximum of Two Vector4s
template< typename T >
inline
Vector4< T >
max( Vector4< T > const & a, Vector4< T > const & b )
{
return Vector4< T >(
( a.x >= b.x ? a.x : b.x ),
( a.y >= b.y ? a.y : b.y ),
( a.z >= b.z ? a.z : b.z ),
( a.w >= b.w ? a.w : b.w )
);
}
// Maximum of Three Vector4s
template< typename T >
inline
Vector4< T >
max( Vector4< T > const & a, Vector4< T > const & b, Vector4< T > const & c )
{
return Vector4< T >(
ObjexxFCL::max( a.x, b.x, c.x ),
ObjexxFCL::max( a.y, b.y, c.y ),
ObjexxFCL::max( a.z, b.z, c.z ),
ObjexxFCL::max( a.w, b.w, c.w )
);
}
// Maximum of Four Vector4s
template< typename T >
inline
Vector4< T >
max( Vector4< T > const & a, Vector4< T > const & b, Vector4< T > const & c, Vector4< T > const & d )
{
return Vector4< T >(
ObjexxFCL::max( a.x, b.x, c.x, d.x ),
ObjexxFCL::max( a.y, b.y, c.y, d.y ),
ObjexxFCL::max( a.z, b.z, c.z, d.z ),
ObjexxFCL::max( a.w, b.w, c.w, d.w )
);
}
// Sum of Two Vector4s
template< typename T >
inline
Vector4< T >
sum( Vector4< T > const & a, Vector4< T > const & b )
{
return Vector4< T >( a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w );
}
// Sum of Three Vector4s
template< typename T >
inline
Vector4< T >
sum( Vector4< T > const & a, Vector4< T > const & b, Vector4< T > const & c )
{
return Vector4< T >( a.x + b.x + c.x, a.y + b.y + c.y, a.z + b.z + c.z, a.w + b.w + c.w );
}
// Sum of Four Vector4s
template< typename T >
inline
Vector4< T >
sum( Vector4< T > const & a, Vector4< T > const & b, Vector4< T > const & c, Vector4< T > const & d )
{
return Vector4< T >( a.x + b.x + c.x + d.x, a.y + b.y + c.y + d.y, a.z + b.z + c.z + d.z, a.w + b.w + c.w + d.w );
}
// Subtract of Two Vector4s
template< typename T >
inline
Vector4< T >
sub( Vector4< T > const & a, Vector4< T > const & b )
{
return Vector4< T >( a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w );
}
// Subtract of Two Vector4s
template< typename T >
inline
Vector4< T >
subtract( Vector4< T > const & a, Vector4< T > const & b )
{
return Vector4< T >( a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w );
}
// Midpoint of Two Vector4s
template< typename T >
inline
Vector4< T >
mid( Vector4< T > const & a, Vector4< T > const & b )
{
return Vector4< T >(
T( 0.5 * ( a.x + b.x ) ),
T( 0.5 * ( a.y + b.y ) ),
T( 0.5 * ( a.z + b.z ) ),
T( 0.5 * ( a.w + b.w ) )
);
}
// Center of Two Vector4s
template< typename T >
inline
Vector4< T >
cen( Vector4< T > const & a, Vector4< T > const & b )
{
return Vector4< T >(
T( 0.5 * ( a.x + b.x ) ),
T( 0.5 * ( a.y + b.y ) ),
T( 0.5 * ( a.z + b.z ) ),
T( 0.5 * ( a.w + b.w ) )
);
}
// Center of Three Vector4s
template< typename T >
inline
Vector4< T >
cen( Vector4< T > const & a, Vector4< T > const & b, Vector4< T > const & c )
{
static long double const third( 1.0 / 3.0 );
return Vector4< T >(
T( third * ( a.x + b.x + c.x ) ),
T( third * ( a.y + b.y + c.y ) ),
T( third * ( a.z + b.z + c.z ) ),
T( third * ( a.w + b.w + c.w ) )
);
}
// Center of Four Vector4s
template< typename T >
inline
Vector4< T >
cen( Vector4< T > const & a, Vector4< T > const & b, Vector4< T > const & c, Vector4< T > const & d )
{
return Vector4< T >(
T( 0.25 * ( a.x + b.x + c.x + d.x ) ),
T( 0.25 * ( a.y + b.y + c.y + d.y ) ),
T( 0.25 * ( a.z + b.z + c.z + d.z ) ),
T( 0.25 * ( a.w + b.w + c.w + d.w ) )
);
}
// Distance
template< typename T >
inline
T
distance( Vector4< T > const & a, Vector4< T > const & b )
{
return std::sqrt( Vector4< T >::square( a.x - b.x ) + Vector4< T >::square( a.y - b.y ) + Vector4< T >::square( a.z - b.z ) + Vector4< T >::square( a.w - b.w ) );
}
// Distance Squared
template< typename T >
inline
T
distance_squared( Vector4< T > const & a, Vector4< T > const & b )
{
return Vector4< T >::square( a.x - b.x ) + Vector4< T >::square( a.y - b.y ) + Vector4< T >::square( a.z - b.z ) + Vector4< T >::square( a.w - b.w );
}
// Dot Product
template< typename T >
inline
T
dot( Vector4< T > const & a, Vector4< T > const & b )
{
return ( a.x * b.x ) + ( a.y * b.y ) + ( a.z * b.z ) + ( a.w * b.w );
}
// Angle Between Two Vector4s (in Radians on [0,pi])
template< typename T >
inline
T
angle( Vector4< T > const & a, Vector4< T > const & b )
{
T const mag( std::sqrt( a.length_squared() * b.length_squared() ) );
return ( mag > T( 0 ) ? std::acos( Vector4< T >::sin_cos_range( a.dot( b ) / mag ) ) : T( 0 ) );
}
// Angle abc Formed by Three Vector4s (in Radians on [0,pi])
template< typename T >
inline
T
angle( Vector4< T > const & a, Vector4< T > const & b, Vector4< T > const & c )
{
return angle( a - b, c - b );
}
// Cosine of Angle Between Two Vector4s
template< typename T >
inline
T
cos( Vector4< T > const & a, Vector4< T > const & b )
{
T const mag( std::sqrt( a.length_squared() * b.length_squared() ) );
return ( mag > T( 0 ) ? Vector4< T >::sin_cos_range( a.dot( b ) / mag ) : T( 1 ) );
}
// Cosine of Angle abc Formed by Three Vector4s
template< typename T >
inline
T
cos( Vector4< T > const & a, Vector4< T > const & b, Vector4< T > const & c )
{
return cos( a - b, c - b );
}
// Sine of Angle Between Two Vector4s
template< typename T >
inline
T
sin( Vector4< T > const & a, Vector4< T > const & b )
{
return std::sin( angle( a, b ) );
}
// Sine of Angle abc Formed by Three Vector4s
template< typename T >
inline
T
sin( Vector4< T > const & a, Vector4< T > const & b, Vector4< T > const & c )
{
return sin( a - b, c - b );
}
// Stream << Vector4 output operator
template< typename T >
std::ostream &
operator <<( std::ostream & stream, Vector4< T > const & v )
{
// Types
typedef TypeTraits< T > Traits;
// Save current stream state and set persistent state
std::ios_base::fmtflags const old_flags( stream.flags() );
std::streamsize const old_precision( stream.precision( Traits::precision ) );
stream << std::right << std::showpoint << std::uppercase;
// Output Vector4
std::size_t const w( Traits::width );
stream << std::setw( w ) << v.x << ' ' << std::setw( w ) << v.y << ' ' << std::setw( w ) << v.z << ' ' << std::setw( w ) << v.w;
// Restore previous stream state
stream.precision( old_precision );
stream.flags( old_flags );
return stream;
}
// Stream >> Vector4 input operator
// Supports whitespace-separated values with optional commas between values as long as whitespace is also present
// String or char values containing whitespace or commas or enclosed in quotes are not supported
// Vector can optionally be enclosed in parentheses () or square brackets []
template< typename T >
std::istream &
operator >>( std::istream & stream, Vector4< T > & v )
{
bool parens( false ); // Opening ( present?
bool brackets( false ); // Opening [ present?
{ // x
std::string input_string;
stream >> input_string;
if ( input_string == "(" ) { // Skip opening (
stream >> input_string;
parens = true;
} else if ( input_string[ 0 ] == '(' ) { // Skip opening (
input_string.erase( 0, 1 );
brackets = true;
} else if ( input_string == "[" ) { // Skip opening [
stream >> input_string;
brackets = true;
} else if ( input_string[ 0 ] == '[' ) { // Skip opening [
input_string.erase( 0, 1 );
brackets = true;
}
std::string::size_type const input_size( input_string.size() );
if ( ( input_size > 0 ) && ( input_string[ input_size - 1 ] == ',' ) ) {
input_string.erase( input_size - 1 ); // Remove trailing ,
}
std::istringstream num_stream( input_string );
num_stream >> v.x;
}
{ // y
std::string input_string;
stream >> input_string;
if ( input_string == "," ) { // Skip ,
stream >> input_string;
} else if ( input_string[ 0 ] == ',' ) { // Skip leading ,
input_string.erase( 0, 1 );
}
std::string::size_type const input_size( input_string.size() );
if ( ( input_size > 0 ) && ( input_string[ input_size - 1 ] == ',' ) ) {
input_string.erase( input_size - 1 ); // Remove trailing ,
}
std::istringstream num_stream( input_string );
num_stream >> v.y;
}
{ // z
std::string input_string;
stream >> input_string;
if ( input_string == "," ) { // Skip ,
stream >> input_string;
} else if ( input_string[ 0 ] == ',' ) { // Skip leading ,
input_string.erase( 0, 1 );
}
std::string::size_type const input_size( input_string.size() );
if ( ( input_size > 0 ) && ( input_string[ input_size - 1 ] == ',' ) ) {
input_string.erase( input_size - 1 ); // Remove trailing ,
}
std::istringstream num_stream( input_string );
num_stream >> v.z;
}
{ // w
std::string input_string;
stream >> input_string;
if ( input_string == "," ) { // Skip ,
stream >> input_string;
} else if ( input_string[ 0 ] == ',' ) { // Skip leading ,
input_string.erase( 0, 1 );
}
std::string::size_type input_size( input_string.size() );
if ( parens || brackets ) { // Remove closing ) or ]
if ( input_size > 0 ) {
if ( parens ) {
if ( input_string[ input_size - 1 ] == ')' ) { // Remove closing )
input_string.erase( input_size - 1 );
--input_size;
}
} else if ( brackets ) {
if ( input_string[ input_size - 1 ] == ']' ) { // Remove closing ]
input_string.erase( input_size - 1 );
--input_size;
}
}
}
}
if ( ( input_size > 0 ) && ( input_string[ input_size - 1 ] == ',' ) ) {
input_string.erase( input_size - 1 ); // Remove trailing ,
}
std::istringstream num_stream( input_string );
num_stream >> v.w;
}
// Remove closing ) or ] if opening ( or [ present
if ( parens || brackets ) { // Remove closing ) or ]
while ( ( stream.peek() == ' ' ) || ( stream.peek() == '\t' ) ) {
stream.ignore();
}
if ( parens ) { // Remove closing ) if present
if ( stream.peek() == ')' ) stream.ignore();
} else if ( brackets ) { // Remove closing ] if present
if ( stream.peek() == ']' ) stream.ignore();
}
}
return stream;
}
} // ObjexxFCL
#endif // ObjexxFCL_Vector4_hh_INCLUDED
// ===== ObjexxFCL/Array.hh =====
#ifndef ObjexxFCL_Array_hh_INCLUDED
#define ObjexxFCL_Array_hh_INCLUDED
// Array: Array Abstract Base Class
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// ObjexxFCL Headers
// C++ Headers
#include <algorithm>
#include <array>
#include <cassert>
#include <cmath>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <initializer_list>
#include <iomanip>
#include <istream>
#include <iterator>
#include <limits>
#include <memory>
#include <new>
#include <ostream>
#include <type_traits>
#include <typeinfo>
#include <utility>
#include <vector>
namespace ObjexxFCL {
// Array: Array Abstract Base Class
//
// Note:
// Can hold numeric or non-numeric values: Numeric operations on non-numeric values won't compile
// Any meaningful array index ranges can be specified as in Fortran
// Zero-sized arrays are supported but have no valid indices
// Argument/proxy arrays can have unbounded/unknown size
// For efficiency constructors without initializer function or value do not initialize the array
// For efficiency bounds checking is only active via asserts in debug builds
template< typename T >
class Array : public BArray
{
private: // Friend
template< typename > friend class Array;
protected: // Types
typedef internal::InitializerSentinel InitializerSentinel;
typedef internal::ProxySentinel ProxySentinel;
public: // Types
typedef Array< T > Base;
typedef AlignedAllocator< T > Aligned;
typedef TypeTraits< T > Traits;
// STL style
typedef T value_type;
typedef T & reference;
typedef T const & const_reference;
typedef T * pointer;
typedef T const * const_pointer;
typedef T * iterator;
typedef T const * const_iterator;
typedef std::reverse_iterator< T * > reverse_iterator;
typedef std::reverse_iterator< T const * > const_reverse_iterator;
// C++ style
typedef T Value;
typedef T & Reference;
typedef T const & ConstReference;
typedef T * Pointer;
typedef T const * ConstPointer;
typedef T * Iterator;
typedef T const * ConstIterator;
typedef std::reverse_iterator< T * > ReverseIterator;
typedef std::reverse_iterator< T const * > ConstReverseIterator;
protected: // Creation
// Default Constructor
Array() :
owner_( true ),
capacity_( 0u ),
size_( 0u ),
mem_( nullptr ),
data_( nullptr ),
shift_( 0 ),
sdata_( nullptr )
{}
// Copy Constructor
Array( Array const & a ) :
BArray( a ),
owner_( true ),
capacity_( size_of( a.size_ ) ),
size_( capacity_ ),
mem_( a.data_ != nullptr ? Aligned::allocate_zero( capacity_ ) : nullptr ),
data_( a.data_ != nullptr ? Aligned::data( mem_ ) : nullptr ),
shift_( a.shift_ ),
sdata_( data_ - shift_ )
{
for ( size_type i = 0; i < size_; ++i ) {
new ( data_ + i ) T( a.data_[ i ] );
}
}
// Move Constructor
Array( Array && a ) noexcept :
BArray( std::move( a ) ),
owner_( a.owner_ ),
capacity_( a.capacity_ ),
size_( a.size_ ),
mem_( a.mem_ ),
data_( a.data_ ),
shift_( a.shift_ ),
sdata_( a.sdata_ )
{
a.capacity_ = a.size_ = 0u;
a.mem_ = a.data_ = a.sdata_ = nullptr;
a.shift_ = 0;
}
// Copy Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
explicit
Array( Array< U > const & a ) :
owner_( true ),
capacity_( size_of( a.size() ) ),
size_( capacity_ ),
mem_( a.data_ != nullptr ? Aligned::allocate_zero( capacity_ ) : nullptr ),
data_( a.data_ != nullptr ? Aligned::data( mem_ ) : nullptr ),
shift_( a.shift_ ),
sdata_( data_ - shift_ )
{
for ( size_type i = 0; i < size_; ++i ) {
new ( data_ + i ) T( a.data_[ i ] );
}
}
// Slice Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
explicit
Array( ArrayS< U > const & a ) :
owner_( true ),
capacity_( size_of( a.size() ) ),
size_( capacity_ ),
mem_( Aligned::allocate_zero( capacity_ ) ),
data_( Aligned::data( mem_ ) ),
shift_( 0 ),
sdata_( nullptr )
{}
// MArray Constructor Template
template< class A, typename M >
explicit
Array( MArray< A, M > const & a ) :
owner_( true ),
capacity_( size_of( a.size() ) ),
size_( capacity_ ),
mem_( Aligned::allocate_zero( capacity_ ) ),
data_( Aligned::data( mem_ ) ),
shift_( 0 ),
sdata_( nullptr )
{}
// Size Constructor
explicit
Array( size_type const size ) :
owner_( true ),
capacity_( size_of( size ) ),
size_( capacity_ ),
mem_( Aligned::allocate_zero( capacity_ ) ),
data_( Aligned::data( mem_ ) ),
shift_( 0 ),
sdata_( nullptr )
{
#if defined(OBJEXXFCL_ARRAY_INIT) || defined(OBJEXXFCL_ARRAY_INIT_DEBUG)
T const fill( Traits::initial_array_value() );
#endif
for ( size_type i = 0; i < size_; ++i ) {
#if defined(OBJEXXFCL_ARRAY_INIT) || defined(OBJEXXFCL_ARRAY_INIT_DEBUG)
new ( data_ + i ) T( fill );
#else
new ( data_ + i ) T;
#endif
}
}
// Size + InitializerSentinel Constructor
Array( size_type const size, InitializerSentinel ) :
owner_( true ),
capacity_( size_of( size ) ),
size_( capacity_ ),
mem_( Aligned::allocate_zero( capacity_ ) ),
data_( Aligned::data( mem_ ) ),
shift_( 0 ),
sdata_( nullptr )
{}
// Initializer List Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array( std::initializer_list< U > const l ) :
owner_( true ),
capacity_( l.size() ),
size_( capacity_ ),
mem_( Aligned::allocate_zero( capacity_ ) ),
data_( Aligned::data( mem_ ) ),
shift_( 0 ),
sdata_( nullptr )
{
auto il( l.begin() );
for ( size_type i = 0; i < size_; ++i, ++il ) {
new ( data_ + i ) T( *il );
}
}
// std::array Constructor Template
template< typename U, Size s, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array( std::array< U, s > const & a ) :
owner_( true ),
capacity_( s ),
size_( capacity_ ),
mem_( Aligned::allocate_zero( capacity_ ) ),
data_( Aligned::data( mem_ ) ),
shift_( 0 ),
sdata_( nullptr )
{
auto ia( a.begin() );
for ( size_type i = 0; i < size_; ++i, ++ia ) {
new ( data_ + i ) T( *ia );
}
}
// std::vector Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array( std::vector< U > const & v ) :
owner_( true ),
capacity_( v.size() ),
size_( capacity_ ),
mem_( Aligned::allocate_zero( capacity_ ) ),
data_( Aligned::data( mem_ ) ),
shift_( 0 ),
sdata_( nullptr )
{
auto iv( v.begin() );
for ( size_type i = 0; i < size_; ++i, ++iv ) {
new ( data_ + i ) T( *iv );
}
}
// Vector2 Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array( Vector2< U > const & v ) :
owner_( true ),
capacity_( 2u ),
size_( capacity_ ),
mem_( Aligned::allocate_zero( capacity_ ) ),
data_( Aligned::data( mem_ ) ),
shift_( 0 ),
sdata_( nullptr )
{
new ( &data_[ 0 ] ) T( v.x );
new ( &data_[ 1 ] ) T( v.y );
}
// Vector3 Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array( Vector3< U > const & v ) :
owner_( true ),
capacity_( 3u ),
size_( capacity_ ),
mem_( Aligned::allocate_zero( capacity_ ) ),
data_( Aligned::data( mem_ ) ),
shift_( 0 ),
sdata_( nullptr )
{
new ( &data_[ 0 ] ) T( v.x );
new ( &data_[ 1 ] ) T( v.y );
new ( &data_[ 2 ] ) T( v.z );
}
// Vector4 Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array( Vector4< U > const & v ) :
owner_( true ),
capacity_( 4u ),
size_( capacity_ ),
mem_( Aligned::allocate_zero( capacity_ ) ),
data_( Aligned::data( mem_ ) ),
shift_( 0 ),
sdata_( nullptr )
{
new ( &data_[ 0 ] ) T( v.x );
new ( &data_[ 1 ] ) T( v.y );
new ( &data_[ 2 ] ) T( v.z );
new ( &data_[ 3 ] ) T( v.w );
}
// Iterator Range Constructor Template
template< class Iterator, typename = decltype( *std::declval< Iterator & >(), void(), ++std::declval< Iterator & >(), void() ) >
Array( Iterator const beg, Iterator const end ) :
owner_( true ),
capacity_( end - beg ),
size_( capacity_ ),
mem_( Aligned::allocate_zero( capacity_ ) ),
data_( Aligned::data( mem_ ) ),
shift_( 0 ),
sdata_( nullptr )
{
size_type i( 0u );
for ( Iterator ii = beg; ii != end; ++ii, ++i ) {
new ( data_ + i ) T( *ii );
}
}
// Default Proxy Constructor
Array( ProxySentinel ) :
owner_( false ),
capacity_( 0u ),
size_( 0u ),
mem_( nullptr ),
data_( nullptr ),
shift_( 0 ),
sdata_( nullptr )
{}
// Array Proxy Constructor
Array( Array const & a, ProxySentinel ) :
owner_( false ),
capacity_( a.capacity_ ),
size_( a.size_ ),
mem_( nullptr ),
data_( a.data_ ),
shift_( 0 ),
sdata_( nullptr )
{}
// Slice Proxy Constructor
Array( ArrayS< T > const & a, ProxySentinel ) :
owner_( false ),
capacity_( a.size() ),
size_( a.size() ),
mem_( nullptr ),
data_( a.data_beg_ ),
shift_( 0 ),
sdata_( nullptr )
{
assert( a.contiguous() );
}
// Value Proxy Constructor
Array( T const & t, ProxySentinel ) :
owner_( false ),
capacity_( npos ), // Unknown
size_( npos ), // Unbounded
mem_( nullptr ),
data_( const_cast< T * >( &t ) ),
shift_( 0 ),
sdata_( nullptr )
{}
public: // Creation
// Destructor
virtual
~Array()
{
if ( owner_ ) destroy();
}
protected: // Assignment: Array
// Copy Assignment
void
operator =( Array const & a )
{
assert( size_bounded() );
assert( size_ == a.size_ );
if ( overlap( a ) ) { // Overlap-safe
CArrayA< T > c( size_ );
for ( size_type i = 0; i < size_; ++i ) {
c[ i ] = a[ i ];
}
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] = c[ i ];
}
} else { // Not overlap-safe
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] = a[ i ];
}
}
}
// Move Assignment
void
operator =( Array && a ) noexcept
{
assert( this != &a );
assert( owner_ == a.owner_ );
if ( owner_ ) destroy();
capacity_ = a.capacity_;
size_ = a.size_;
mem_ = a.mem_;
data_ = a.data_;
shift_ = a.shift_;
sdata_ = a.sdata_;
a.capacity_ = a.size_ = 0u;
a.mem_ = a.data_ = a.sdata_ = nullptr;
a.shift_ = 0;
}
// Copy Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
void
operator =( Array< U > const & a )
{
assert( size_bounded() );
assert( size_ == a.size() );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] = a[ i ];
}
}
// Initializer List Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
void
operator =( std::initializer_list< U > const l )
{
assert( size_ == l.size() );
std::copy( l.begin(), l.end(), data_ );
}
// std::array Assignment Template
template< typename U, Size s, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
void
operator =( std::array< U, s > const & a )
{
assert( size_ == s );
std::copy( a.begin(), a.end(), data_ );
}
// std::vector Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
void
operator =( std::vector< U > const & v )
{
assert( size_ == v.size() );
std::copy( v.begin(), v.end(), data_ );
}
// Vector2 Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
void
operator =( Vector2< U > const & v )
{
assert( size_ == 2u );
operator []( 0 ) = v.x;
operator []( 1 ) = v.y;
}
// Vector3 Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
void
operator =( Vector3< U > const & v )
{
assert( size_ == 3u );
operator []( 0 ) = v.x;
operator []( 1 ) = v.y;
operator []( 2 ) = v.z;
}
// Vector4 Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
void
operator =( Vector4< U > const & v )
{
assert( size_ == 4u );
operator []( 0 ) = v.x;
operator []( 1 ) = v.y;
operator []( 2 ) = v.z;
operator []( 3 ) = v.w;
}
// += Array
void
operator +=( Array const & a )
{
assert( size_bounded() );
assert( size_ == a.size() );
if ( overlap( a ) ) { // Overlap-safe
CArrayA< T > c( size_ );
for ( size_type i = 0; i < size_; ++i ) {
c[ i ] = a[ i ];
}
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] += c[ i ];
}
} else { // Not overlap-safe
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] += a[ i ];
}
}
}
// -= Array
void
operator -=( Array const & a )
{
assert( size_bounded() );
assert( size_ == a.size() );
if ( overlap( a ) ) { // Overlap-safe
CArrayA< T > c( size_ );
for ( size_type i = 0; i < size_; ++i ) {
c[ i ] = a[ i ];
}
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] -= c[ i ];
}
} else { // Not overlap-safe
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] -= a[ i ];
}
}
}
// += Array Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
void
operator +=( Array< U > const & a )
{
assert( size_bounded() );
assert( size_ == a.size() );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] += a[ i ];
}
}
// -= Array Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
void
operator -=( Array< U > const & a )
{
assert( size_bounded() );
assert( size_ == a.size() );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] -= a[ i ];
}
}
// *= Array Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
void
operator *=( Array< U > const & a )
{
assert( size_bounded() );
assert( size_ == a.size() );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] *= a[ i ];
}
}
// += std::array Template
template< typename U, Size s, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
void
operator +=( std::array< U, s > const & a )
{
assert( size_ == s );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] += a[ i ];
}
}
// -= std::array Template
template< typename U, Size s, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
void
operator -=( std::array< U, s > const & a )
{
assert( size_ == s );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] -= a[ i ];
}
}
// += std::vector Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
void
operator +=( std::vector< U > const & v )
{
assert( size_ == v.size() );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] += v[ i ];
}
}
// -= std::vector Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
void
operator -=( std::vector< U > const & v )
{
assert( size_ == v.size() );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] -= v[ i ];
}
}
public: // Assignment: Value
// = Value
Array &
operator =( T const & t )
{
assert( size_bounded() );
if ( data_ ) std::fill_n( data_, size_, t );
return *this;
}
// += Value
Array &
operator +=( T const & t )
{
assert( size_bounded() );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] += t;
}
return *this;
}
// -= Value
Array &
operator -=( T const & t )
{
assert( size_bounded() );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] -= t;
}
return *this;
}
// *= Value
Array &
operator *=( T const & t )
{
assert( size_bounded() );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] *= t;
}
return *this;
}
// /= Value
template< typename U, class = typename std::enable_if< std::is_floating_point< U >::value && std::is_assignable< T&, U >::value >::type >
Array &
operator /=( U const & u )
{
assert( size_bounded() );
assert( u != U( 0 ) );
U const inv_u( U( 1 ) / u );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] *= inv_u;
}
return *this;
}
// /= Value
template< typename U, class = typename std::enable_if< ! std::is_floating_point< U >::value && std::is_assignable< T&, U >::value >::type, typename = void >
Array &
operator /=( U const & u )
{
assert( size_bounded() );
assert( u != U( 0 ) );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] /= u;
}
return *this;
}
public: // Subscript
// array[ i ] const: Linear Subscript
T const &
operator []( size_type const i ) const
{
assert( ( i < size_ ) || ( size_ == npos ) );
return data_[ i ];
}
// array[ i ]: Linear Subscript
T &
operator []( size_type const i )
{
assert( ( i < size_ ) || ( size_ == npos ) );
return data_[ i ];
}
public: // Predicate
// Owner?
bool
owner() const
{
return owner_;
}
// Proxy?
bool
proxy() const
{
return ! owner_;
}
// Active?
bool
active() const
{
return ( data_ != nullptr );
}
// Allocated
bool
allocated() const
{
return ( data_ != nullptr );
}
// Active Array Empty?
bool
empty() const
{
return ( size_ == 0u );
}
// Active Array Size Bounded?
bool
size_bounded() const
{
return ( size_ != npos );
}
// Memory Can Overlap a Range?
bool
overlap( T const * const b, T const * const e ) const
{
if ( ( data_ == nullptr ) || ( b == nullptr ) || ( e == nullptr ) ) { // No active memory range(s)
return false;
} else if ( size_ == 0u ) { // No finite memory range
return false;
} else if ( size_ == npos ) { // No memory upper bound
return ( e >= data_ );
} else { // Bounded ranges
assert( b <= e );
T const * const de( data_ + size_ - 1 ); // Data end pointer
return ( ( data_ >= b ? data_ : b ) <= ( de <= e ? de : e ) );
}
}
// Memory Can Overlap an Array?
template< template< typename > class A >
bool
overlap( A< T > const & a ) const
{
if ( data_ == nullptr ) { // No active memory range
return false;
} else { // Bounded ranges
return overlap( a.data_beg(), a.data_end() );
}
}
public: // Inspector
// Rank
virtual
int
rank() const = 0;
// Data Size
size_type
capacity() const
{
return capacity_;
}
// Active Array Size
size_type
size() const
{
return size_;
}
// Active Array Size
int
isize() const
{
assert( size_ != npos );
return static_cast< int >( size_ );
}
// IndexRange of a Dimension
virtual
IR const &
I( int const d ) const = 0;
// Lower Index of a Dimension
virtual
int
l( int const d ) const = 0;
// Upper Index of a Dimension
virtual
int
u( int const d ) const = 0;
// Size of a Dimension
virtual
size_type
size( int const d ) const = 0;
// Size of a Dimension
virtual
int
isize( int const d ) const = 0;
// Begin Iterator
const_iterator
begin() const
{
return data_;
}
// Begin Iterator
iterator
begin()
{
return data_;
}
// End Iterator
const_iterator
end() const
{
return ( ( data_ != nullptr ) && ( size_ != npos ) ? data_ + size_ : nullptr );
}
// End Iterator
iterator
end()
{
return ( ( data_ != nullptr ) && ( size_ != npos ) ? data_ + size_ : nullptr );
}
// Reverse Begin Iterator
const_reverse_iterator
rbegin() const
{
return const_reverse_iterator( ( data_ != nullptr ) && ( size_ != npos ) ? data_ + size_ : nullptr );
}
// Reverse Begin Iterator
reverse_iterator
rbegin()
{
return reverse_iterator( ( data_ != nullptr ) && ( size_ != npos ) ? data_ + size_ : nullptr );
}
// Reverse End Iterator
const_reverse_iterator
rend() const
{
return const_reverse_iterator( data_ );
}
// Reverse End Iterator
reverse_iterator
rend()
{
return reverse_iterator( data_ );
}
// Data Pointer
T const *
data() const
{
return data_;
}
// Data Pointer
T *
data()
{
return data_;
}
// Data Begin Pointer
T const *
data_beg() const
{
return data_;
}
// Data Begin Pointer
T *
data_beg()
{
return data_;
}
// Data End Pointer
T const *
data_end() const
{
return ( ( data_ != nullptr ) && ( size_ > 0u ) && ( size_ != npos ) ? data_ + size_ - 1 : nullptr );
}
// Data End Pointer
T *
data_end()
{
return ( ( data_ != nullptr ) && ( size_ > 0u ) && ( size_ != npos ) ? data_ + size_ - 1 : nullptr );
}
public: // Modifier
// Clear
virtual
Array &
clear()
{
if ( owner_ ) destroy();
capacity_ = size_ = 0u;
mem_ = data_ = sdata_ = nullptr;
shift_ = 0;
return *this;
}
public: // Comparison: Predicate
// Array == Value
friend
bool
eq( Array const & a, T const & t )
{
assert( a.size_bounded() );
if ( a.empty() ) return true;
for ( size_type i = 0, e = a.size_; i < e; ++i ) {
if ( ! ( a[ i ] == t ) ) return false;
}
return true;
}
// Value == Array
friend
bool
eq( T const & t, Array const & a )
{
return eq( a, t );
}
public: // Comparison: Predicate: Any
// Any Array == Value
friend
bool
any_eq( Array const & a, T const & t )
{
assert( a.size_bounded() );
if ( a.empty() ) return false;
for ( size_type i = 0, e = a.size_; i < e; ++i ) {
if ( a[ i ] == t ) return true;
}
return false;
}
// Any Value == Array
friend
bool
any_eq( T const & t, Array const & a )
{
return any_eq( a, t );
}
// Any Array != Value
friend
bool
any_ne( Array const & a, T const & t )
{
return ! eq( a, t );
}
// Any Value != Array
friend
bool
any_ne( T const & t, Array const & a )
{
return ! eq( a, t );
}
// Any Array < Value
friend
bool
any_lt( Array const & a, T const & t )
{
assert( a.size_bounded() );
if ( a.empty() ) return false;
for ( size_type i = 0, e = a.size_; i < e; ++i ) {
if ( a[ i ] < t ) return true;
}
return false;
}
// Any Value < Array
friend
bool
any_lt( T const & t, Array const & a )
{
assert( a.size_bounded() );
if ( a.empty() ) return false;
for ( size_type i = 0, e = a.size_; i < e; ++i ) {
if ( t < a[ i ] ) return true;
}
return false;
}
// Any Array <= Value
friend
bool
any_le( Array const & a, T const & t )
{
assert( a.size_bounded() );
if ( a.empty() ) return false;
for ( size_type i = 0, e = a.size_; i < e; ++i ) {
if ( a[ i ] <= t ) return true;
}
return false;
}
// Any Value <= Array
friend
bool
any_le( T const & t, Array const & a )
{
assert( a.size_bounded() );
if ( a.empty() ) return false;
for ( size_type i = 0, e = a.size_; i < e; ++i ) {
if ( t <= a[ i ] ) return true;
}
return false;
}
// Any Array > Value
friend
bool
any_gt( Array const & a, T const & t )
{
return any_lt( t, a );
}
// Any Value > Array
friend
bool
any_gt( T const & t, Array const & a )
{
return any_lt( a, t );
}
// Any Array >= Value
friend
bool
any_ge( Array const & a, T const & t )
{
return any_le( t, a );
}
// Any Value >= Array
friend
bool
any_ge( T const & t, Array const & a )
{
return any_le( a, t );
}
public: // Comparison: Predicate: All
// All Array != Value
friend
bool
all_ne( Array const & a, T const & t )
{
return ! any_eq( a, t );
}
// All Value != Array
friend
bool
all_ne( T const & t, Array const & a )
{
return ! any_eq( a, t );
}
// All Array <= Value
friend
bool
all_le( Array const & a, T const & t )
{
return le( a, t );
}
// All Value <= Array
friend
bool
all_le( T const & t, Array const & a )
{
return le( t, a );
}
// All Value > Array
friend
bool
all_gt( T const & t, Array const & a )
{
return gt( t, a );
}
// All Value >= Array
friend
bool
all_ge( T const & t, Array const & a )
{
return ge( t, a );
}
public: // Comparison: Count
// Count Array == Value
friend
size_type
count_eq( Array const & a, T const & t )
{
assert( a.size_bounded() );
if ( a.empty() ) return 0;
size_type n( 0u );
for ( size_type i = 0, e = a.size_; i < e; ++i ) {
if ( a[ i ] == t ) ++n;
}
return n;
}
// Count Value == Array
friend
size_type
count_eq( T const & t, Array const & a )
{
return count_eq( a, t );
}
// Count Array != Value
friend
size_type
count_ne( Array const & a, T const & t )
{
assert( a.size_bounded() );
if ( a.empty() ) return 0;
size_type n( 0u );
for ( size_type i = 0, e = a.size_; i < e; ++i ) {
if ( a[ i ] != t ) ++n;
}
return n;
}
// Count Value != Array
friend
size_type
count_ne( T const & t, Array const & a )
{
return count_ne( a, t );
}
// Count Array < Value
friend
size_type
count_lt( Array const & a, T const & t )
{
assert( a.size_bounded() );
if ( a.empty() ) return 0;
size_type n( 0u );
for ( size_type i = 0, e = a.size_; i < e; ++i ) {
if ( a[ i ] < t ) ++n;
}
return n;
}
// Count Value < Array
friend
size_type
count_lt( T const & t, Array const & a )
{
return count_gt( a, t );
}
// Count Array <= Value
friend
size_type
count_le( Array const & a, T const & t )
{
assert( a.size_bounded() );
if ( a.empty() ) return 0;
size_type n( 0u );
for ( size_type i = 0, e = a.size_; i < e; ++i ) {
if ( a[ i ] <= t ) ++n;
}
return n;
}
// Count Value <= Array
friend
size_type
count_le( T const & t, Array const & a )
{
return count_ge( a, t );
}
// Count Array > Value
friend
size_type
count_gt( Array const & a, T const & t )
{
assert( a.size_bounded() );
if ( a.empty() ) return 0;
size_type n( 0u );
for ( size_type i = 0, e = a.size_; i < e; ++i ) {
if ( a[ i ] > t ) ++n;
}
return n;
}
// Count Value > Array
friend
size_type
count_gt( T const & t, Array const & a )
{
return count_lt( a, t );
}
// Count Array >= Value
friend
size_type
count_ge( Array const & a, T const & t )
{
assert( a.size_bounded() );
if ( a.empty() ) return 0;
size_type n( 0u );
for ( size_type i = 0, e = a.size_; i < e; ++i ) {
if ( a[ i ] >= t ) ++n;
}
return n;
}
// Count Value >= Array
friend
size_type
count_ge( T const & t, Array const & a )
{
return count_le( a, t );
}
protected: // Comparison: Predicate
// Array == Array
friend
bool
eq( Array const & a, Array const & b )
{
assert( a.size_bounded() );
assert( a.size_ == b.size_ );
if ( ( &a == &b ) || a.empty() ) return true;
for ( size_type i = 0, e = a.size_; i < e; ++i ) {
if ( ! ( a[ i ] == b[ i ] ) ) return false;
}
return true;
}
protected: // Comparison: Elemental
// Array == Array
friend
void
eq_elemental( Array const & a, Array const & b, Array< bool > & r )
{
assert( a.size() == b.size() );
assert( a.size() == r.size() );
for ( size_type i = 0, e = a.size(); i < e; ++i ) {
r[ i ] = ( a[ i ] == b[ i ] );
}
}
// Array != Array
friend
void
ne_elemental( Array const & a, Array const & b, Array< bool > & r )
{
assert( a.size() == b.size() );
assert( a.size() == r.size() );
for ( size_type i = 0, e = a.size(); i < e; ++i ) {
r[ i ] = ( a[ i ] != b[ i ] );
}
}
// Array < Array
friend
void
lt_elemental( Array const & a, Array const & b, Array< bool > & r )
{
assert( a.size() == b.size() );
assert( a.size() == r.size() );
for ( size_type i = 0, e = a.size(); i < e; ++i ) {
r[ i ] = ( a[ i ] < b[ i ] );
}
}
// Array <= Array
friend
void
le_elemental( Array const & a, Array const & b, Array< bool > & r )
{
assert( a.size() == b.size() );
assert( a.size() == r.size() );
for ( size_type i = 0, e = a.size(); i < e; ++i ) {
r[ i ] = ( a[ i ] <= b[ i ] );
}
}
// Array > Array
friend
void
gt_elemental( Array const & a, Array const & b, Array< bool > & r )
{
assert( a.size() == b.size() );
assert( a.size() == r.size() );
for ( size_type i = 0, e = a.size(); i < e; ++i ) {
r[ i ] = ( a[ i ] > b[ i ] );
}
}
// Array >= Array
friend
void
ge_elemental( Array const & a, Array const & b, Array< bool > & r )
{
assert( a.size() == b.size() );
assert( a.size() == r.size() );
for ( size_type i = 0, e = a.size(); i < e; ++i ) {
r[ i ] = ( a[ i ] >= b[ i ] );
}
}
// Array == Value
friend
void
eq_elemental( Array const & a, T const & t, Array< bool > & r )
{
assert( a.size() == r.size() );
for ( size_type i = 0, e = a.size(); i < e; ++i ) {
r[ i ] = ( a[ i ] == t );
}
}
// Array != Value
friend
void
ne_elemental( Array const & a, T const & t, Array< bool > & r )
{
assert( a.size() == r.size() );
for ( size_type i = 0, e = a.size(); i < e; ++i ) {
r[ i ] = ( a[ i ] != t );
}
}
// Array < Value
friend
void
lt_elemental( Array const & a, T const & t, Array< bool > & r )
{
assert( a.size() == r.size() );
for ( size_type i = 0, e = a.size(); i < e; ++i ) {
r[ i ] = ( a[ i ] < t );
}
}
// Array <= Value
friend
void
le_elemental( Array const & a, T const & t, Array< bool > & r )
{
assert( a.size() == r.size() );
for ( size_type i = 0, e = a.size(); i < e; ++i ) {
r[ i ] = ( a[ i ] <= t );
}
}
// Array > Value
friend
void
gt_elemental( Array const & a, T const & t, Array< bool > & r )
{
assert( a.size() == r.size() );
for ( size_type i = 0, e = a.size(); i < e; ++i ) {
r[ i ] = ( a[ i ] > t );
}
}
// Array >= Value
friend
void
ge_elemental( Array const & a, T const & t, Array< bool > & r )
{
assert( a.size() == r.size() );
for ( size_type i = 0, e = a.size(); i < e; ++i ) {
r[ i ] = ( a[ i ] >= t );
}
}
// Value == Array
friend
void
eq_elemental( T const & t, Array const & b, Array< bool > & r )
{
assert( b.size() == r.size() );
for ( size_type i = 0, e = b.size(); i < e; ++i ) {
r[ i ] = ( t == b[ i ] );
}
}
// Value != Array
friend
void
ne_elemental( T const & t, Array const & b, Array< bool > & r )
{
assert( b.size() == r.size() );
for ( size_type i = 0, e = b.size(); i < e; ++i ) {
r[ i ] = ( t != b[ i ] );
}
}
// Value < Array
friend
void
lt_elemental( T const & t, Array const & b, Array< bool > & r )
{
assert( b.size() == r.size() );
for ( size_type i = 0, e = b.size(); i < e; ++i ) {
r[ i ] = ( t < b[ i ] );
}
}
// Value <= Array
friend
void
le_elemental( T const & t, Array const & b, Array< bool > & r )
{
assert( b.size() == r.size() );
for ( size_type i = 0, e = b.size(); i < e; ++i ) {
r[ i ] = ( t <= b[ i ] );
}
}
// Value > Array
friend
void
gt_elemental( T const & t, Array const & b, Array< bool > & r )
{
assert( b.size() == r.size() );
for ( size_type i = 0, e = b.size(); i < e; ++i ) {
r[ i ] = ( t > b[ i ] );
}
}
// Value >= Array
friend
void
ge_elemental( T const & t, Array const & b, Array< bool > & r )
{
assert( b.size() == r.size() );
for ( size_type i = 0, e = b.size(); i < e; ++i ) {
r[ i ] = ( t >= b[ i ] );
}
}
protected: // Methods
// Shift Setup
void
shift_set( difference_type const shift )
{
shift_ = shift;
sdata_ = data_ - shift_;
}
// Shift Setup Without Setting Shifted Data Pointer
void
shift_only_set( difference_type const shift )
{
shift_ = shift;
}
// Active Array Size Setup
void
size_set( size_type const size )
{
assert( size <= capacity_ );
size_ = size;
}
// Resize a Real Array: Return Whether Reallocation Happened
bool
resize( size_type const size )
{
assert( owner_ );
assert( size != npos );
if ( ( data_ == nullptr ) || ( capacity_ < size ) || ( ( capacity_ == size_ ) && ( size != size_ ) ) ) {
destroy();
capacity_ = size_ = size;
mem_ = Aligned::allocate_zero( capacity_ );
data_ = Aligned::data( mem_ );
sdata_ = data_ - shift_;
return true; // Reallocated: Elements not constructed
} else {
size_type i( size_ );
while ( i > size ) { // Destruct removed elements
data_[ --i ].~T();
}
size_ = size;
sdata_ = data_ - shift_;
return false; // Not reallocated
}
}
// Reserve Capacity in a Real Array
void
reserve_capacity( size_type const n )
{
assert( owner_ );
assert( n <= max_size );
if ( capacity_ < n ) {
void * new_mem = Aligned::allocate_zero( n );
T * new_data = Aligned::data( new_mem );
if ( size_ > 0u ) uninitialized_move_or_copy( data_, data_ + size_, new_data );
destroy();
capacity_ = n;
mem_ = new_mem;
data_ = new_data;
sdata_ = data_ - shift_;
}
}
// Shrink Capacity to Size in a Real Array
void
shrink_capacity()
{
assert( owner_ );
if ( capacity_ > size_ ) {
void * new_mem = Aligned::allocate_zero( size_ );
T * new_data = Aligned::data( new_mem );
if ( size_ > 0u ) uninitialized_move_or_copy( data_, data_ + size_, new_data );
destroy();
capacity_ = size_;
mem_ = new_mem;
data_ = new_data;
sdata_ = data_ - shift_;
}
}
// Append Value by Copy in a Real Array
void
do_push_back_copy( T const & t )
{
assert( owner_ );
assert( size_ < npos - 1 );
size_type const new_size( size_ + 1 );
assert( new_size <= max_size );
if ( capacity_ < new_size ) {
capacity_ = std::min( std::max( capacity_ << 1, new_size ), max_size );
void * const new_mem = Aligned::allocate_zero( capacity_ );
T * const new_data = Aligned::data( new_mem );
new ( &new_data[ size_ ] ) T( t );
if ( size_ > 0u ) uninitialized_move_or_copy( data_, data_ + size_, new_data );
destroy();
mem_ = new_mem;
data_ = new_data;
sdata_ = data_ - shift_;
} else {
new ( &data_[ size_ ] ) T( t );
}
size_ = new_size;
}
// Append Value by Move in a Real Array
void
do_push_back_move( T && t )
{
assert( owner_ );
assert( size_ < npos - 1 );
size_type const new_size( size_ + 1 );
assert( new_size <= max_size );
if ( capacity_ < new_size ) {
capacity_ = std::min( std::max( capacity_ << 1, new_size ), max_size );
void * const new_mem = Aligned::allocate_zero( capacity_ );
T * const new_data = Aligned::data( new_mem );
new ( &new_data[ size_ ] ) T( std::move( t ) );
if ( size_ > 0u ) uninitialized_move_or_copy( data_, data_ + size_, new_data );
destroy();
mem_ = new_mem;
data_ = new_data;
sdata_ = data_ - shift_;
} else {
new ( &data_[ size_ ] ) T( std::move( t ) );
}
size_ = new_size;
}
// Append Value by Move in a Real Array
void
do_pop_back()
{
if ( size_ > 0u ) {
--size_;
data_[ size_ ].~T();
}
}
// Insert Value by Copy in a Real Array
iterator
do_insert_copy( const_iterator pos, T const & t )
{
assert( owner_ );
assert( size_ < npos - 1 );
assert( data_ <= pos );
assert( pos <= end() );
size_type const new_size( size_ + 1 );
assert( new_size <= max_size );
iterator const old_pos( data_ + ( pos - data_ ) );
iterator const old_end( end() );
if ( capacity_ < new_size ) {
capacity_ = std::min( std::max( capacity_ << 1, new_size ), max_size );
void * const new_mem = Aligned::allocate_zero( capacity_ );
T * const new_data = Aligned::data( new_mem );
iterator const new_pos( new_data + ( pos - data_ ) );
new ( &*new_pos ) T( t );
if ( data_ < pos ) uninitialized_move_or_copy( data_, old_pos, new_data );
if ( pos < old_end ) uninitialized_move_or_copy( old_pos, old_end, new_pos + 1 );
destroy();
size_ = new_size;
mem_ = new_mem;
data_ = new_data;
sdata_ = data_ - shift_;
return new_pos;
} else {
if ( pos == old_end ) {
new ( &*old_end ) T( t );
} else {
T const tt( t );
uninitialized_move_or_copy( old_end - 1, old_end, old_end );
if ( size_ > 1u ) move_or_copy_backward( old_pos, old_end - 1, old_end );
*old_pos = tt;
}
size_ = new_size;
return old_pos;
}
}
// Insert Value by Move in a Real Array
iterator
do_insert_move( const_iterator pos, T && t )
{
assert( owner_ );
assert( size_ < npos - 1 );
assert( data_ <= pos );
assert( pos <= end() );
size_type const new_size( size_ + 1 );
assert( new_size <= max_size );
iterator const old_pos( data_ + ( pos - data_ ) );
iterator const old_end( end() );
if ( capacity_ < new_size ) {
capacity_ = std::min( std::max( capacity_ << 1, new_size ), max_size );
void * const new_mem = Aligned::allocate_zero( capacity_ );
T * const new_data = Aligned::data( new_mem );
iterator const new_pos( new_data + ( pos - data_ ) );
new ( &*new_pos ) T( std::move( t ) );
if ( data_ < pos ) uninitialized_move_or_copy( data_, old_pos, new_data );
if ( pos < old_end ) uninitialized_move_or_copy( old_pos, old_end, new_pos + 1 );
destroy();
size_ = new_size;
mem_ = new_mem;
data_ = new_data;
sdata_ = data_ - shift_;
return new_pos;
} else {
if ( pos == old_end ) {
new ( &*old_end ) T( std::move( t ) );
} else {
uninitialized_move_or_copy( old_end - 1, old_end, old_end );
if ( size_ > 1u ) move_or_copy_backward( old_pos, old_end - 1, old_end );
*old_pos = std::move( t );
}
size_ = new_size;
return old_pos;
}
}
// Insert Multiples of a Value by Copy in a Real Array
iterator
do_insert_n( const_iterator pos, size_type n, T const & t )
{
assert( owner_ );
assert( size_ < npos - n );
assert( data_ <= pos );
assert( pos <= end() );
size_type const new_size( size_ + n );
assert( new_size <= max_size );
iterator const old_pos( data_ + ( pos - data_ ) );
iterator const old_end( end() );
if ( capacity_ < new_size ) {
capacity_ = std::min( std::max( capacity_ << 1, new_size ), max_size );
void * const new_mem = Aligned::allocate_zero( capacity_ );
T * const new_data = Aligned::data( new_mem );
iterator const new_pos( new_data + ( pos - data_ ) );
std::uninitialized_fill_n( new_pos, n, t );
if ( data_ < pos ) uninitialized_move_or_copy( data_, old_pos, new_data );
if ( pos < old_end ) uninitialized_move_or_copy( old_pos, old_end, new_pos + n );
destroy();
size_ = new_size;
mem_ = new_mem;
data_ = new_data;
sdata_ = data_ - shift_;
return new_pos;
} else {
if ( pos == old_end ) {
std::uninitialized_fill_n( old_end, n, t );
} else {
T const tt( t );
iterator const k( old_pos + n < old_end ? old_end - n : old_pos );
uninitialized_move_or_copy( k, old_end, k + n );
move_or_copy_backward( old_pos, k, old_end );
size_type const ni( std::min( n, static_cast< size_type >( old_end - old_pos ) ) );
std::fill_n( old_pos, ni, tt );
if ( ni < n ) std::uninitialized_fill_n( old_end, n - ni, tt );
}
size_ = new_size;
return old_pos;
}
}
// Insert Iterator Range in a Real Array
template< typename Iterator, class = typename std::enable_if<
std::is_same< typename std::iterator_traits< Iterator >::iterator_category, std::input_iterator_tag >::value ||
std::is_same< typename std::iterator_traits< Iterator >::iterator_category, std::forward_iterator_tag >::value ||
std::is_same< typename std::iterator_traits< Iterator >::iterator_category, std::bidirectional_iterator_tag >::value ||
std::is_same< typename std::iterator_traits< Iterator >::iterator_category, std::random_access_iterator_tag >::value
>::type >
iterator
do_insert_iterator( const_iterator pos, Iterator first, Iterator last ) // Like std containers first and last may not be iterators to this Array
{
assert( owner_ );
size_type const n( std::distance( first, last ) );
assert( size_ < npos - n );
assert( data_ <= pos );
assert( pos <= end() );
size_type const new_size( size_ + n );
assert( new_size <= max_size );
iterator const old_pos( data_ + ( pos - data_ ) );
iterator const old_end( end() );
if ( capacity_ < new_size ) {
capacity_ = std::min( std::max( capacity_ << 1, new_size ), max_size );
void * const new_mem = Aligned::allocate_zero( capacity_ );
T * const new_data = Aligned::data( new_mem );
iterator const new_pos( new_data + ( pos - data_ ) );
std::copy( first, last, new_pos );
if ( data_ < pos ) uninitialized_move_or_copy( data_, old_pos, new_data );
if ( pos < old_end ) uninitialized_move_or_copy( old_pos, old_end, new_pos + n );
destroy();
size_ = new_size;
mem_ = new_mem;
data_ = new_data;
sdata_ = data_ - shift_;
return new_pos;
} else {
if ( pos == old_end ) {
std::uninitialized_copy( first, last, old_pos );
} else {
iterator const k( old_pos + n < old_end ? old_end - n : old_pos );
uninitialized_move_or_copy( k, old_end, k + n );
move_or_copy_backward( old_pos, k, old_end );
size_type const ni( std::min( n, static_cast< size_type >( old_end - old_pos ) ) );
std::copy( first, first + ni, old_pos );
if ( ni < n ) std::uninitialized_copy( first + ni, last, old_pos + ni );
}
size_ = new_size;
return old_pos;
}
}
// Insert Initializer List in a Real Array
iterator
do_insert_initializer_list( const_iterator pos, std::initializer_list< T > il )
{
assert( owner_ );
size_type const n( il.size() );
assert( size_ < npos - n );
assert( data_ <= pos );
assert( pos <= end() );
size_type const new_size( size_ + n );
assert( new_size <= max_size );
iterator const old_pos( data_ + ( pos - data_ ) );
iterator const old_end( end() );
if ( capacity_ < new_size ) {
capacity_ = std::min( std::max( capacity_ << 1, new_size ), max_size );
void * const new_mem = Aligned::allocate_zero( capacity_ );
T * const new_data = Aligned::data( new_mem );
iterator const new_pos( new_data + ( pos - data_ ) );
std::copy( il.begin(), il.end(), new_pos );
if ( data_ < pos ) uninitialized_move_or_copy( data_, old_pos, new_data );
if ( pos < old_end ) uninitialized_move_or_copy( old_pos, old_end, new_pos + n );
destroy();
size_ = new_size;
mem_ = new_mem;
data_ = new_data;
sdata_ = data_ - shift_;
return new_pos;
} else {
if ( pos == old_end ) {
std::uninitialized_copy( il.begin(), il.end(), old_pos );
} else {
iterator const k( old_pos + n < old_end ? old_end - n : old_pos );
uninitialized_move_or_copy( k, old_end, k + n );
move_or_copy_backward( old_pos, k, old_end );
size_type const ni( std::min( n, static_cast< size_type >( old_end - old_pos ) ) );
std::copy( il.begin(), il.begin() + ni, old_pos );
if ( ni < n ) std::uninitialized_copy( il.begin() + ni, il.end(), old_pos + ni );
}
size_ = new_size;
return old_pos;
}
}
// Insert Value Constructed in Place in a Real Array
template< typename... Args >
iterator
do_emplace( const_iterator pos, Args &&... args )
{
assert( owner_ );
assert( size_ < npos - 1 );
assert( data_ <= pos );
assert( pos <= end() );
size_type const new_size( size_ + 1 );
assert( new_size <= max_size );
iterator const old_pos( data_ + ( pos - data_ ) );
iterator const old_end( end() );
if ( capacity_ < new_size ) {
capacity_ = std::min( std::max( capacity_ << 1, new_size ), max_size );
void * const new_mem = Aligned::allocate_zero( capacity_ );
T * const new_data = Aligned::data( new_mem );
iterator const new_pos( new_data + ( pos - data_ ) );
new ( &*new_pos ) T( std::forward< Args >( args )... );
if ( data_ < pos ) uninitialized_move_or_copy( data_, old_pos, new_data );
if ( pos < old_end ) uninitialized_move_or_copy( old_pos, old_end, new_pos + 1 );
destroy();
size_ = new_size;
mem_ = new_mem;
data_ = new_data;
sdata_ = data_ - shift_;
return new_pos;
} else {
if ( pos == old_end ) {
new ( &*pos ) T( std::forward< Args >( args )... );
} else {
new ( &data_[ size_ ] ) T( data_[ size_ - 1 ] );
move_or_copy_backward( old_pos, old_end - 1, old_end );
*pos = T( std::forward< Args >( args )... );
}
size_ = new_size;
return old_pos;
}
}
// Append Value Constructed in Place in a Real Array
template< typename... Args >
void
do_emplace_back( Args &&... args )
{
assert( owner_ );
assert( size_ < npos - 1 );
size_type const new_size( size_ + 1 );
assert( new_size <= max_size );
if ( capacity_ < new_size ) {
capacity_ = std::min( std::max( capacity_ << 1, new_size ), max_size );
void * const new_mem = Aligned::allocate_zero( capacity_ );
T * const new_data = Aligned::data( new_mem );
new ( &new_data[ size_ ] ) T( std::forward< Args >( args )... );
if ( size_ > 0u ) uninitialized_move_or_copy( data_, data_ + size_, new_data );
destroy();
mem_ = new_mem;
data_ = new_data;
sdata_ = data_ - shift_;
} else {
new ( &data_[ size_ ] ) T( std::forward< Args >( args )... );
}
size_ = new_size;
}
// Erase Iterator in a Real Array
iterator
do_erase( const_iterator pos )
{
assert( owner_ );
assert( data_ <= pos );
assert( pos < end() );
iterator const old_pos( data_ + ( pos - data_ ) );
iterator const old_end( end() );
move_or_copy( old_pos + 1, old_end, old_pos );
old_end->~T();
--size_;
return old_pos;
}
// Erase Iterator Range in a Real Array
iterator
do_erase_iterator( const_iterator first, const_iterator last )
{
assert( owner_ );
assert( ( data_ <= first ) || ( first == last ) );
assert( ( first <= last ) || ( first == last ) );
assert( ( last <= end() ) || ( first == last ) );
size_type const n( std::distance( first, last ) );
iterator const start( data_ + ( first - data_ ) );
if ( n > 0u ) {
iterator const stop( data_ + ( last - data_ ) );
iterator const old_end( end() );
move_or_copy( stop, old_end, start );
for ( auto i = stop; i != old_end; ++i ) i->~T();
size_ -= n;
}
return start;
}
// Swap
void
swapB( Array & v )
{
assert( owner_ );
assert( v.owner_ );
std::swap( capacity_, v.capacity_ );
std::swap( size_, v.size_ );
std::swap( mem_, v.mem_ );
std::swap( data_, v.data_ );
std::swap( shift_, v.shift_ );
std::swap( sdata_, v.sdata_ );
}
// Initialize by Uniform Value
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
void
initialize( U const & u )
{
assert( owner_ );
for ( size_type i = 0; i < size_; ++i ) {
new ( data_ + i ) T( u );
}
}
// Initialize by Array
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
void
initialize( Array< U > const & a )
{
assert( owner_ );
assert( size_ == a.size_ );
for ( size_type i = 0; i < size_; ++i ) {
new ( data_ + i ) T( a[ i ] );
}
}
// Initialize an Element
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
void
initialize( size_type const i, U const & u )
{
assert( owner_ );
new ( data_ + i ) T( u );
}
// Uniform Assignment
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
void
assign( U const & u )
{
assert( owner_ );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] = T( u );
}
}
// Element Assignment
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
void
assign( size_type const i, U const & u )
{
data_[ i ] = T( u );
}
// Assign Array
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
void
assign( Array< U > const & a )
{
assert( size_bounded() );
assert( size_ == a.size_ );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] = T( a[ i ] );
}
}
// Switch to Size Construction
void
reconstruct_by_size( size_type const size )
{
assert( owner_ );
destroy();
capacity_ = size_ = size;
assert( size_bounded() );
mem_ = Aligned::allocate_zero( capacity_ );
data_ = Aligned::data( mem_ );
#if defined(OBJEXXFCL_ARRAY_INIT) || defined(OBJEXXFCL_ARRAY_INIT_DEBUG)
T const fill( Traits::initial_array_value() );
#endif
for ( size_type i = 0; i < size_; ++i ) {
#if defined(OBJEXXFCL_ARRAY_INIT) || defined(OBJEXXFCL_ARRAY_INIT_DEBUG)
new ( data_ + i ) T( fill );
#else
new ( data_ + i ) T;
#endif
}
}
// Conformable Move
void
conformable_move( Array & a )
{
assert( this != &a );
assert( owner_ == a.owner_ );
destroy();
capacity_ = a.capacity_;
mem_ = a.mem_;
data_ = a.data_;
sdata_ = data_ - shift_;
a.capacity_ = a.size_ = 0u;
a.mem_ = a.data_ = a.sdata_ = nullptr;
a.shift_ = 0;
}
protected: // Static Methods
// Array Size Product of Specified Bounded Dimensional Sizes
static
size_type
size_of( size_type const s1 )
{
assert( s1 != npos );
return s1;
}
// Array Size Product of Specified Bounded Dimensional Sizes
static
size_type
size_of( size_type const s1, size_type const s2 )
{
assert( s1 != npos );
assert( s2 != npos );
assert( ( s2 == 0 ) || ( s1 <= max_size / s2 ) );
return s1 * s2;
}
// Array Size Product of Specified Bounded Dimensional Sizes
static
size_type
size_of( size_type const s1, size_type const s2, size_type const s3 )
{
return size_of( size_of( s1, s2 ), s3 );
}
// Array Size Product of Specified Bounded Dimensional Sizes
static
size_type
size_of( size_type const s1, size_type const s2, size_type const s3, size_type const s4 )
{
return size_of( size_of( s1, s2 ), size_of( s3, s4 ) );
}
// Array Size Product of Specified Bounded Dimensional Sizes
static
size_type
size_of( size_type const s1, size_type const s2, size_type const s3, size_type const s4, size_type const s5 )
{
return size_of( size_of( size_of( s1, s2 ), size_of( s3, s4 ) ), s5 );
}
// Array Size Product of Specified Bounded Dimensional Sizes
static
size_type
size_of( size_type const s1, size_type const s2, size_type const s3, size_type const s4, size_type const s5, size_type const s6 )
{
return size_of( size_of( size_of( s1, s2 ), size_of( s3, s4 ) ), size_of( s5, s6 ) );
}
// Array Size Product of Specified Bounded IndexRanges
static
size_type
size_of( IR const & I1 )
{
return size_of( I1.size() );
}
// Array Size Product of Specified Bounded IndexRanges
static
size_type
size_of( IR const & I1, IR const & I2 )
{
return size_of( I1.size(), I2.size() );
}
// Array Size Product of Specified Bounded IndexRanges
static
size_type
size_of( IR const & I1, IR const & I2, IR const & I3 )
{
return size_of( I1.size(), I2.size(), I3.size() );
}
// Array Size Product of Specified Bounded IndexRanges
static
size_type
size_of( IR const & I1, IR const & I2, IR const & I3, IR const & I4 )
{
return size_of( I1.size(), I2.size(), I3.size(), I4.size() );
}
// Array Size Product of Specified Bounded IndexRanges
static
size_type
size_of( IR const & I1, IR const & I2, IR const & I3, IR const & I4, IR const & I5 )
{
return size_of( I1.size(), I2.size(), I3.size(), I4.size(), I5.size() );
}
// Array Size Product of Specified Bounded IndexRanges
static
size_type
size_of( IR const & I1, IR const & I2, IR const & I3, IR const & I4, IR const & I5, IR const & I6 )
{
return size_of( I1.size(), I2.size(), I3.size(), I4.size(), I5.size(), I6.size() );
}
// Slice Constant for a Scalar Index
static
std::int64_t
slice_k( IR const & range, int const i, std::int64_t const multiplier = 1 )
{
assert( range.contains( i ) );
assert( multiplier <= std::numeric_limits< std::int64_t >::max() / std::abs( i ) );
(void)range; // Suppress unused warning in release builds
return i * multiplier;
}
// Slice Constant for a Scalar Index
static
std::int64_t
slice_k( IR const & range, int const i, size_type const multiplier )
{
assert( range.contains( i ) );
assert( multiplier <= size_type( std::numeric_limits< std::int64_t >::max() / std::abs( i ) ) );
(void)range; // Suppress unused warning in release builds
return i * multiplier;
}
// Slice Constant for a Scalar Index
static
std::int64_t
slice_k( int const u, int const i, std::int64_t const multiplier = 1 )
{
assert( ( 1 <= i ) && ( i <= u ) );
assert( multiplier <= std::numeric_limits< std::int64_t >::max() / std::abs( i ) );
(void)u; // Suppress unused warning in release builds
return i * multiplier;
}
// Slice Constant for a Scalar Index
static
std::int64_t
slice_k( int const u, int const i, size_type const multiplier )
{
assert( ( 1 <= i ) && ( i <= u ) );
assert( multiplier <= size_type( std::numeric_limits< std::int64_t >::max() / std::abs( i ) ) );
(void)u; // Suppress unused warning in release builds
return i * multiplier;
}
// Move if Movable: Movable Overload
template< typename U, class = typename std::enable_if< std::is_move_assignable< U >::value >::type >
static
U &&
move_if( U & u )
{
return std::move( u );
}
// Move if Movable: Non-Movable Overload
template< typename U, class = typename std::enable_if< ! std::is_move_assignable< U >::value >::type, typename = void >
static
U &
move_if( U & u )
{
return u;
}
// Move or Copy: Move Overload
template< typename InputIterator, typename OutputIterator, typename U = T, class = typename std::enable_if< std::is_move_assignable< U >::value >::type >
static
OutputIterator
move_or_copy( InputIterator beg, InputIterator end, OutputIterator out )
{
return std::move( beg, end, out );
}
// Move or Copy: Copy Overload
template< typename InputIterator, typename OutputIterator, typename U = T, class = typename std::enable_if< ! std::is_move_assignable< U >::value >::type, typename = void >
static
OutputIterator
move_or_copy( InputIterator beg, InputIterator end, OutputIterator out )
{
return std::copy( beg, end, out );
}
// Move or Copy Backward: Move Overload
template< typename InputIterator, typename OutputIterator, typename U = T, class = typename std::enable_if< std::is_move_assignable< U >::value >::type >
static
OutputIterator
move_or_copy_backward( InputIterator beg, InputIterator end, OutputIterator out )
{
return std::move_backward( beg, end, out );
}
// Move or Copy Backward: Copy Overload
template< typename InputIterator, typename OutputIterator, typename U = T, class = typename std::enable_if< ! std::is_move_assignable< U >::value >::type, typename = void >
static
OutputIterator
move_or_copy_backward( InputIterator beg, InputIterator end, OutputIterator out )
{
return std::copy_backward( beg, end, out );
}
// Move or Copy: Move Overload
template< typename InputIterator, typename OutputIterator, typename U = T, class = typename std::enable_if< std::is_move_assignable< U >::value >::type >
static
OutputIterator
uninitialized_move_or_copy( InputIterator beg, InputIterator end, OutputIterator out )
{
return std::uninitialized_copy( std::make_move_iterator( beg ), std::make_move_iterator( end ), out );
}
// Move or Copy: Copy Overload
template< typename InputIterator, typename OutputIterator, typename U = T, class = typename std::enable_if< ! std::is_move_assignable< U >::value >::type, typename = void >
static
OutputIterator
uninitialized_move_or_copy( InputIterator beg, InputIterator end, OutputIterator out )
{
return std::uninitialized_copy( beg, end, out );
}
private: // Methods
// Destruct Elements and Delete Array Memory (Doesn't Nullify Pointers)
void
destroy()
{
if ( data_ != nullptr ) {
size_type i( size_ );
while ( i ) {
data_[ --i ].~T();
}
}
::operator delete( mem_ );
}
protected: // Data
bool const owner_; // Owner of data array?
size_type capacity_; // Size of data array
size_type size_; // Size of active array
void * mem_; // Pointer to raw memory
T * data_; // Pointer to data array
difference_type shift_; // Array shift
T * sdata_; // Shifted pointer to data array
}; // Array
// Stream >> Array
template< typename T >
inline
std::istream &
operator >>( std::istream & stream, Array< T > & a )
{
if ( stream && ( a.size() > 0u ) ) {
for ( BArray::size_type i = 0, e = a.size(); i < e; ++i ) {
stream >> a[ i ];
if ( ! stream ) break;
}
}
return stream;
}
// Stream << Array
template< typename T >
inline
std::ostream &
operator <<( std::ostream & stream, Array< T > const & a )
{
typedef TypeTraits< T > Traits;
if ( stream && ( a.size() > 0u ) ) {
std::ios_base::fmtflags const old_flags( stream.flags() );
std::streamsize const old_precision( stream.precision( Traits::precision ) );
stream << std::right << std::showpoint << std::uppercase;
int const w( Traits::iwidth );
for ( BArray::size_type i = 0, e = a.size() - 1; i < e; ++i ) {
stream << std::setw( w ) << a[ i ] << ' ';
if ( ! stream ) break;
} if ( stream ) stream << std::setw( w ) << a[ a.size() - 1 ];
stream.precision( old_precision );
stream.flags( old_flags );
}
return stream;
}
namespace fmt {
// List-Directed Format: Array
template< typename T >
inline
std::string
LD( Array< T > const & a )
{
std::string s;
std::size_t const n( a.size() );
if ( n > 0u ) {
s.reserve( n * TypeTraits< T >::width );
for ( std::size_t i = 0; i < n; ++i ) {
s.append( fmt::LD( a[ i ] ) );
}
}
return s;
}
} // fmt
} // ObjexxFCL
#endif // ObjexxFCL_Array_hh_INCLUDED
// ===== ObjexxFCL/Array1S.fwd.hh =====
#ifndef ObjexxFCL_Array1S_fwd_hh_INCLUDED
#define ObjexxFCL_Array1S_fwd_hh_INCLUDED
// Array1S Forward Declarations
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// C++ Headers
#include <cstddef>
#include <cstdint>
#include <string>
namespace ObjexxFCL {
// Forward
template< typename > class Array1S;
// Types
typedef Array1S< bool > Array1S_bool;
typedef Array1S< int > Array1S_int;
typedef Array1S< std::string > Array1S_string;
} // ObjexxFCL
#endif // ObjexxFCL_Array1S_fwd_hh_INCLUDED
// ===== ObjexxFCL/ArrayRS.fwd.hh =====
#ifndef ObjexxFCL_ArrayRS_fwd_hh_INCLUDED
#define ObjexxFCL_ArrayRS_fwd_hh_INCLUDED
// ArrayRS Forward Declarations
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// C++ Headers
#include <cstddef>
#include <cstdint>
#include <string>
namespace ObjexxFCL {
// Forward
template< typename, int > class ArrayRS;
// Types
} // ObjexxFCL
#endif // ObjexxFCL_ArrayRS_fwd_hh_INCLUDED
// ===== ObjexxFCL/ArrayRS.hh =====
#ifndef ObjexxFCL_ArrayRS_hh_INCLUDED
#define ObjexxFCL_ArrayRS_hh_INCLUDED
// ArrayRS: Rank Slice Array Proxy Abstract Base Class Template
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// ObjexxFCL Headers
namespace ObjexxFCL {
// ArrayRS: Rank Slice Array Proxy Abstract Base Class Template
template< typename T, int Rank >
class ArrayRS : public ArrayS< T >
{
private: // Types
typedef ArrayS< T > Super;
private: // Friend
template< typename, int > friend class ArrayRS;
public: // Types
typedef typename Super::Base Base;
typedef typename Super::Traits Traits;
typedef typename Super::IR IR;
typedef typename Super::IS IS;
typedef typename Super::DS DS;
// STL Style
typedef typename Super::value_type value_type;
typedef typename Super::reference reference;
typedef typename Super::const_reference const_reference;
typedef typename Super::pointer pointer;
typedef typename Super::const_pointer const_pointer;
typedef typename Super::size_type size_type;
typedef typename Super::difference_type difference_type;
// C++ Style
typedef typename Super::Value Value;
typedef typename Super::Reference Reference;
typedef typename Super::ConstReference ConstReference;
typedef typename Super::Pointer Pointer;
typedef typename Super::ConstPointer ConstPointer;
typedef typename Super::Size Size;
typedef typename Super::Difference Difference;
using Super::isize;
using Super::overlap;
using Super::size;
protected: // Types
using Super::in_range;
using Super::slice_k;
using Super::contiguous_;
using Super::data_;
using Super::data_beg_;
using Super::data_end_;
using Super::size_;
protected: // Creation
// Default Constructor
ArrayRS()
{}
// Copy Constructor
ArrayRS( ArrayRS const & a ) :
Super( a )
{}
// Data Constructor
ArrayRS( T const * data, size_type const size ) :
Super( data, size )
{}
// Non-Const Data Constructor
ArrayRS( T * data, size_type const size ) :
Super( data, size )
{}
public: // Creation
// Destructor
virtual
~ArrayRS() = default;
public: // Predicate
// Conformable?
template< template< typename > class A, typename U >
bool
conformable( A< U > const & a ) const
{
if ( Rank != a.rank() ) return false;
for ( int i = 1; i <= Rank; ++i ) if ( size( i ) != a.size( i ) ) return false;
return true;
}
public: // Inspector
// Rank
int
rank() const
{
return Rank;
}
}; // ArrayRS
} // ObjexxFCL
#endif // ObjexxFCL_ArrayRS_hh_INCLUDED
// ===== ObjexxFCL/CArray.fwd.hh =====
#ifndef ObjexxFCL_CArray_fwd_hh_INCLUDED
#define ObjexxFCL_CArray_fwd_hh_INCLUDED
// CArray Forward Declarations
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// C++ Headers
#include <cstddef>
#include <cstdint>
#include <string>
namespace ObjexxFCL {
// Forward
template< typename > class CArray;
// Types
typedef CArray< bool > CArray_bool;
typedef CArray< short int > CArray_short;
typedef CArray< int > CArray_int;
typedef CArray< std::size_t > CArray_size;
typedef CArray< double > CArray_double;
typedef CArray< signed char > CArray_schar;
typedef CArray< std::string > CArray_string;
} // ObjexxFCL
#endif // ObjexxFCL_CArray_fwd_hh_INCLUDED
// ===== ObjexxFCL/CArray.hh =====
#ifndef ObjexxFCL_CArray_hh_INCLUDED
#define ObjexxFCL_CArray_hh_INCLUDED
// CArray: Memory-Managed C Array Wrapper
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// ObjexxFCL Headers
// C++ Headers
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstddef>
#include <initializer_list>
#include <iomanip>
#include <istream>
#include <iterator>
#include <ostream>
#include <type_traits>
#include <utility>
namespace ObjexxFCL {
// CArray: Memory-Managed C Array Wrapper
template< typename T >
class CArray
{
private: // Friend
template< typename > friend class CArray; // Friendship across value types
public: // Types
typedef TypeTraits< T > Traits;
typedef typename std::conditional< std::is_scalar< T >::value, T const, T const & >::type Tc;
typedef typename std::conditional< std::is_scalar< T >::value, typename std::remove_const< T >::type, T const & >::type Tr;
// STL Style
typedef T value_type;
typedef T & reference;
typedef T const & const_reference;
typedef T * pointer;
typedef T const * const_pointer;
typedef T * iterator;
typedef T const * const_iterator;
typedef std::reverse_iterator< T * > reverse_iterator;
typedef std::reverse_iterator< T const * > const_reverse_iterator;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
// C++ Style
typedef T Value;
typedef T & Reference;
typedef T const & ConstReference;
typedef T * Pointer;
typedef T const * ConstPointer;
typedef T * Iterator;
typedef T const * ConstIterator;
typedef std::reverse_iterator< T * > ReverseIterator;
typedef std::reverse_iterator< T const * > ConstReverseIterator;
typedef std::size_t Size;
typedef std::ptrdiff_t Difference;
// Types to prevent compile failure when std::distance is in scope
typedef void iterator_category;
public: // Creation
// Default Constructor
CArray() :
size_( 0u ),
data_( nullptr )
{}
// Copy Constructor
CArray( CArray const & a ) :
size_( a.size_ ),
data_( size_ > 0u ? new T[ size_ ] : nullptr )
{
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] = a.data_[ i ];
}
}
// Move Constructor
CArray( CArray && a ) noexcept :
size_( a.size_ ),
data_( a.data_ )
{
a.size_ = 0u;
a.data_ = nullptr;
}
// Copy Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
CArray( CArray< U > const & a ) :
size_( a.size_ ),
data_( size_ > 0u ? new T[ size_ ] : nullptr )
{
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] = T( a.data_[ i ] );
}
}
// Pointer + Size Constructor
CArray(
T const * const p,
size_type const size
) :
size_( size ),
data_( size_ > 0u ? new T[ size_ ] : nullptr )
{
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] = p[ i ];
}
}
// Pointer + Size Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
CArray(
U const * const p,
size_type const size
) :
size_( size ),
data_( size_ > 0u ? new T[ size_ ] : nullptr )
{
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] = T( p[ i ] );
}
}
// Iterator Range Constructor Template
template< typename InputIterator >
CArray(
InputIterator const beg,
InputIterator const end
) :
size_( end - beg ),
data_( size_ > 0u ? new T[ size_ ] : nullptr )
{
if ( size_ > 0u ) {
InputIterator k( beg );
for ( size_type i = 0; i < size_; ++i, ++k ) {
data_[ i ] = T( *k );
}
}
}
// Size Constructor: Built-in types are default, not zero, initialized for performance
explicit
CArray( size_type const size ) :
size_( size ),
data_( size_ > 0u ? new T[ size_ ] : nullptr )
{}
// Size + Uniform Value Constructor
CArray(
size_type const size,
Tc t
) :
size_( size ),
data_( size_ > 0u ? new T[ size_ ] : nullptr )
{
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] = t;
}
}
// Initializer List Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
CArray( std::initializer_list< U > const l ) :
size_( l.size() ),
data_( size_ > 0u ? new T[ size_ ] : nullptr )
{
std::copy( l.begin(), l.end(), data_ );
}
// Destructor
~CArray()
{
delete[] data_;
}
public: // Conversion
// Active?
operator bool() const
{
return ( data_ != nullptr );
}
// Data
operator T const *() const
{
return data_;
}
// Data
operator T *()
{
return data_;
}
public: // Assignment
// Copy Assignment
CArray &
operator =( CArray const & a )
{
if ( this != &a ) {
if ( size_ != a.size_ ) {
size_ = a.size_;
delete[] data_; data_ = ( size_ > 0u ? new T[ size_ ] : nullptr );
}
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] = a.data_[ i ];
}
}
return *this;
}
// Move Assignment
CArray &
operator =( CArray && a ) noexcept
{
assert( this != &a );
size_ = a.size_;
delete[] data_; data_ = a.data_;
a.size_ = 0u;
a.data_ = nullptr;
return *this;
}
// Copy Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
CArray &
operator =( CArray< U > const & a )
{
if ( size_ != a.size_ ) {
size_ = a.size_;
delete[] data_; data_ = ( size_ > 0u ? new T[ size_ ] : nullptr );
}
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] = T( a.data_[ i ] );
}
return *this;
}
// Uniform Value Assignment
CArray &
operator =( Tc t )
{
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] = t;
}
return *this;
}
// Initializer List Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
CArray &
operator =( std::initializer_list< U > const l )
{
assert( l.size() == size_ );
std::copy( l.begin(), l.end(), data_ );
return *this;
}
// Pointer + Size Assignment
CArray &
assign(
T const * const p,
size_type const size
)
{
if ( size_ != size ) {
size_ = size;
delete[] data_; data_ = ( size_ > 0u ? new T[ size_ ] : nullptr );
}
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] = p[ i ];
}
return *this;
}
// Pointer + Size Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
CArray &
assign(
U const * const p,
size_type const size
)
{
if ( size_ != size ) {
size_ = size;
delete[] data_; data_ = ( size_ > 0u ? new T[ size_ ] : nullptr );
}
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] = T( p[ i ] );
}
return *this;
}
// Iterator Range Assignment Template
template< typename InputIterator >
CArray &
assign(
InputIterator const beg,
InputIterator const end
)
{
size_type const size( end - beg );
if ( size_ != size ) {
size_ = size;
delete[] data_; data_ = ( size_ > 0u ? new T[ size_ ] : nullptr );
}
if ( size_ > 0u ) {
InputIterator k( beg );
for ( size_type i = 0; i < size_; ++i, ++k ) {
data_[ i ] = T( *k );
}
}
return *this;
}
// Size + Value Assignment
CArray &
assign(
size_type const size,
Tc t
)
{
if ( size_ != size ) { // Set to new array with uniform values
CArray( size, t ).swap( *this );
} else { // Set to uniform value
(*this) = t;
}
return *this;
}
// += CArray
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
CArray &
operator +=( CArray< U > const & a )
{
assert( size_ == a.size_ );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] += T( a.data_[ i ] );
}
return *this;
}
// -= CArray
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
CArray &
operator -=( CArray< U > const & a )
{
assert( size_ == a.size_ );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] -= T( a.data_[ i ] );
}
return *this;
}
// += Value
CArray &
operator +=( Tc t )
{
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] += t;
}
return *this;
}
// -= Value
CArray &
operator -=( Tc t )
{
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] -= t;
}
return *this;
}
// *= Value
CArray &
operator *=( Tc t )
{
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] *= t;
}
return *this;
}
// /= Value
template< typename U, class = typename std::enable_if< std::is_floating_point< U >::value && std::is_assignable< T&, U >::value >::type >
CArray &
operator /=( U const & u )
{
assert( u != U( 0 ) );
U const inv_u( U( 1 ) / u );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] *= inv_u;
}
return *this;
}
// /= Value
template< typename U, class = typename std::enable_if< ! std::is_floating_point< U >::value && std::is_assignable< T&, U >::value >::type, typename = void >
CArray &
operator /=( U const & u )
{
assert( u != U( 0 ) );
for ( size_type i = 0; i < size_; ++i ) {
data_[ i ] /= u;
}
return *this;
}
public: // Predicate
// Active?
bool
active() const
{
return ( data_ != nullptr );
}
// Empty?
bool
empty() const
{
return ( size_ == 0u );
}
public: // Inspector
// Size
size_type
size() const
{
return size_;
}
// Lower Index
size_type
l() const
{
return 0u;
}
// Upper index
size_type
u() const
{
return size_ - 1u; // npos if size_ == 0
}
// First Element
Tr
front() const
{
assert( size_ > 0u );
return data_[ 0 ];
}
// Last Element
Tr
back() const
{
assert( size_ > 0u );
return data_[ size_ - 1 ];
}
// Length
T
length() const
{
T length_sq( T( 0 ) );
for ( size_type i = 0; i < size_; ++i ) {
length_sq += data_[ i ] * data_[ i ];
}
return std::sqrt( length_sq );
}
public: // Modifier
// First Element
T &
front()
{
assert( size_ > 0u );
return data_[ 0 ];
}
// Last Element
T &
back()
{
assert( size_ > 0u );
return data_[ size_ - 1 ];
}
// Resize: Values not Preserved
// Built-in values are uninitialized if size changes
CArray &
size( size_type const size )
{
if ( size_ != size ) { // Set to new array
CArray( size ).swap( *this );
}
return *this;
}
// Resize to Size With Fill Value: Values Preserved
CArray &
resize(
size_type const size,
Tc fill = T()
)
{
if ( size_ < size ) {
CArray a( size, fill ); // New array: Elements set to fill fill
for ( size_type i = 0; i < size_; ++i ) { // Copy current values
a.data_[ i ] = data_[ i ];
}
swap( a ); // Swap in new array
} else if ( size_ > size ) {
CArray a( size ); // New array
for ( size_type i = 0; i < size; ++i ) { // Copy current values within new range
a.data_[ i ] = data_[ i ];
}
swap( a ); // Swap in new array
}
return *this;
}
// Swap
void
swap( CArray & a )
{
std::swap( size_, a.size_ );
std::swap( data_, a.data_ );
}
// Clear
CArray &
clear()
{
size_ = 0u;
delete[] data_; data_ = nullptr;
return *this;
}
// Normalize to Unit Length
CArray &
normalize()
{
T const length_( length() );
assert( length_ > T( 0 ) );
operator /=( length_ );
return *this;
}
public: // Subscript
// CArray[ i ] const: 0-Based Indexing
template< typename I, class = typename std::enable_if< std::is_integral< I >::value && std::is_unsigned< I >::value && std::is_const< T >::value >::type >
Tr
operator []( I const i ) const
{
assert( i < size_ );
return data_[ i ];
}
// CArray[ i ] const: 0-Based Indexing
template< typename I, class = typename std::enable_if< std::is_integral< I >::value && std::is_signed< I >::value && std::is_const< T >::value >::type, typename = void >
Tr
operator []( I const i ) const
{
assert( ( i >= 0 ) && ( static_cast< size_type >( i ) < size_ ) );
return data_[ i ];
}
// CArray[ i ]: 0-Based Indexing
template< typename I, class = typename std::enable_if< std::is_integral< I >::value && std::is_unsigned< I >::value >::type >
T &
operator []( I const i )
{
assert( i < size_ );
return data_[ i ];
}
// CArray[ i ]: 0-Based Indexing
template< typename I, class = typename std::enable_if< std::is_integral< I >::value && std::is_signed< I >::value >::type, typename = void >
T &
operator []( I const i )
{
assert( ( i >= 0 ) && ( static_cast< size_type >( i ) < size_ ) );
return data_[ i ];
}
// CArray( i ) const: 1-Based Indexing
template< typename I, class = typename std::enable_if< std::is_integral< I >::value && std::is_unsigned< I >::value && std::is_const< T >::value >::type >
Tr
operator ()( I const i ) const
{
assert( ( i > 0u ) && ( i <= size_ ) );
return data_[ i - 1 ];
}
// CArray( i ) const: 1-Based Indexing
template< typename I, class = typename std::enable_if< std::is_integral< I >::value && std::is_signed< I >::value && std::is_const< T >::value >::type, typename = void >
Tr
operator ()( I const i ) const
{
assert( ( i > 0 ) && ( static_cast< size_type >( i ) <= size_ ) );
return data_[ i - 1 ];
}
// CArray( i ): 1-Based Indexing
template< typename I, class = typename std::enable_if< std::is_integral< I >::value && std::is_unsigned< I >::value >::type >
T &
operator ()( I const i )
{
assert( ( i > 0u ) && ( i <= size_ ) );
return data_[ i - 1 ];
}
// CArray( i ): 1-Based Indexing
template< typename I, class = typename std::enable_if< std::is_integral< I >::value && std::is_signed< I >::value >::type, typename = void >
T &
operator ()( I const i )
{
assert( ( i > 0 ) && ( static_cast< size_type >( i ) <= size_ ) );
return data_[ i - 1 ];
}
public: // Iterator
// Begin Iterator
const_iterator
begin() const
{
return data_;
}
// Begin Iterator
iterator
begin()
{
return data_;
}
// End Iterator
const_iterator
end() const
{
return ( data_ != nullptr ? data_ + size_ : nullptr );
}
// End Iterator
iterator
end()
{
return ( data_ != nullptr ? data_ + size_ : nullptr );
}
// Reverse Begin Iterator
const_reverse_iterator
rbegin() const
{
return const_reverse_iterator( data_ != nullptr ? data_ + size_ : nullptr );
}
// Reverse Begin Iterator
reverse_iterator
rbegin()
{
return reverse_iterator( data_ != nullptr ? data_ + size_ : nullptr );
}
// Reverse End Iterator
const_reverse_iterator
rend() const
{
return const_reverse_iterator( data_ );
}
// Reverse End Iterator
reverse_iterator
rend()
{
return reverse_iterator( data_ );
}
public: // Array Accessor
// C Array const Accessor
T const *
operator ()() const
{
return data_;
}
// C Array Non-const Accessor
T *
operator ()()
{
return data_;
}
private: // Data
size_type size_; // Number of array elements
T * data_; // C array
}; // CArray
// Functions
// Magnitude
template< typename T >
inline
T
magnitude( CArray< T > const & a )
{
T mag_sq( T( 0 ) );
for ( typename CArray< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
mag_sq += a[ i ] * a[ i ];
}
return std::sqrt( mag_sq );
}
// Magnitude Squared
template< typename T >
inline
T
magnitude_squared( CArray< T > const & a )
{
T mag_sq( T( 0 ) );
for ( typename CArray< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
mag_sq += a[ i ] * a[ i ];
}
return mag_sq;
}
// Distance
template< typename T >
inline
T
distance( CArray< T > const & a, CArray< T > const & b )
{
assert( a.size() == b.size() );
T distance_sq( T( 0 ) );
for ( typename CArray< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
T const distance_i( a[ i ] - b[ i ] );
distance_sq += distance_i * distance_i;
}
return std::sqrt( distance_sq );
}
// Distance Squared
template< typename T >
inline
T
distance_squared( CArray< T > const & a, CArray< T > const & b )
{
assert( a.size() == b.size() );
T distance_sq( T( 0 ) );
for ( typename CArray< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
T const distance_i( a[ i ] - b[ i ] );
distance_sq += distance_i * distance_i;
}
return distance_sq;
}
// Dot Product
template< typename T >
inline
T
dot( CArray< T > const & a, CArray< T > const & b )
{
assert( a.size() == b.size() );
T sum( T( 0 ) );
for ( typename CArray< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
sum += a[ i ] * b[ i ];
}
return sum;
}
// Dot Product
template< typename T >
inline
T
dot_product( CArray< T > const & a, CArray< T > const & b )
{
assert( a.size() == b.size() );
T sum( T( 0 ) );
for ( typename CArray< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
sum += a[ i ] * b[ i ];
}
return sum;
}
// Swap
template< typename T >
inline
void
swap( CArray< T > & a, CArray< T > & b )
{
a.swap( b );
}
// Comparison
// Are Two CArrays Comparable?
template< typename T >
inline
bool
comparable( CArray< T > const & a, CArray< T > const & b )
{
return ( a.size() == b.size() );
}
// CArray == CArray
template< typename T >
inline
bool
operator ==( CArray< T > const & a, CArray< T > const & b )
{
if ( &a == &b ) { // Same objects
return true;
} else if ( a.size() != b.size() ) { // Sizes differ
return false;
} else { // Compare values
for ( typename CArray< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( a[ i ] == b[ i ] ) ) return false;
}
return true;
}
}
// CArray != CArray
template< typename T >
inline
bool
operator !=( CArray< T > const & a, CArray< T > const & b )
{
return !( a == b );
}
// CArray < CArray
template< typename T >
inline
bool
operator <( CArray< T > const & a, CArray< T > const & b )
{
if ( &a == &b ) { // Same objects
return false;
} else if ( a.size() != b.size() ) { // Sizes differ
return false;
} else { // Compare values
for ( typename CArray< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( a[ i ] < b[ i ] ) ) return false;
}
return true;
}
}
// CArray <= CArray
template< typename T >
inline
bool
operator <=( CArray< T > const & a, CArray< T > const & b )
{
if ( &a == &b ) { // Same objects
return true;
} else if ( a.size() != b.size() ) { // Sizes differ
return false;
} else { // Compare values
for ( typename CArray< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( a[ i ] <= b[ i ] ) ) return false;
}
return true;
}
}
// CArray >= CArray
template< typename T >
inline
bool
operator >=( CArray< T > const & a, CArray< T > const & b )
{
if ( &a == &b ) { // Same objects
return true;
} else if ( a.size() != b.size() ) { // Sizes differ
return false;
} else { // Compare values
for ( typename CArray< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( a[ i ] >= b[ i ] ) ) return false;
}
return true;
}
}
// CArray > CArray
template< typename T >
inline
bool
operator >( CArray< T > const & a, CArray< T > const & b )
{
if ( &a == &b ) { // Same objects
return false;
} else if ( a.size() != b.size() ) { // Sizes differ
return false;
} else { // Compare values
for ( typename CArray< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( a[ i ] > b[ i ] ) ) return false;
}
return true;
}
}
// CArray == Value
template< typename T >
inline
bool
operator ==( CArray< T > const & a, typename CArray< T >::Tc t )
{
for ( typename CArray< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( a[ i ] != t ) return false;
}
return true;
}
// CArray != Value
template< typename T >
inline
bool
operator !=( CArray< T > const & a, typename CArray< T >::Tc t )
{
return !( a == t );
}
// CArray < Value
template< typename T >
inline
bool
operator <( CArray< T > const & a, typename CArray< T >::Tc t )
{
for ( typename CArray< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( a[ i ] < t ) ) return false;
}
return true;
}
// CArray <= Value
template< typename T >
inline
bool
operator <=( CArray< T > const & a, typename CArray< T >::Tc t )
{
for ( typename CArray< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( a[ i ] <= t ) ) return false;
}
return true;
}
// CArray >= Value
template< typename T >
inline
bool
operator >=( CArray< T > const & a, typename CArray< T >::Tc t )
{
for ( typename CArray< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( a[ i ] >= t ) ) return false;
}
return true;
}
// CArray > Value
template< typename T >
inline
bool
operator >( CArray< T > const & a, typename CArray< T >::Tc t )
{
for ( typename CArray< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( a[ i ] > t ) ) return false;
}
return true;
}
// Value == CArray
template< typename T >
inline
bool
operator ==( typename CArray< T >::Tc t, CArray< T > const & a )
{
return ( a == t );
}
// Value != CArray
template< typename T >
inline
bool
operator !=( typename CArray< T >::Tc t, CArray< T > const & a )
{
return !( t == a );
}
// Value < CArray
template< typename T >
inline
bool
operator <( typename CArray< T >::Tc t, CArray< T > const & a )
{
for ( typename CArray< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( t < a[ i ] ) ) return false;
}
return true;
}
// Value <= CArray
template< typename T >
inline
bool
operator <=( typename CArray< T >::Tc t, CArray< T > const & a )
{
for ( typename CArray< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( t <= a[ i ] ) ) return false;
}
return true;
}
// Value >= CArray
template< typename T >
inline
bool
operator >=( typename CArray< T >::Tc t, CArray< T > const & a )
{
for ( typename CArray< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( t >= a[ i ] ) ) return false;
}
return true;
}
// Value > CArray
template< typename T >
inline
bool
operator >( typename CArray< T >::Tc t, CArray< T > const & a )
{
for ( typename CArray< T >::size_type i = 0, ie = a.size(); i < ie; ++i ) {
if ( !( t > a[ i ] ) ) return false;
}
return true;
}
// Generator
// -CArray
template< typename T >
inline
CArray< T >
operator -( CArray< T > const & a )
{
CArray< T > r( a );
r *= T( -1 );
return r;
}
// CArray + CArray
template< typename T >
inline
CArray< T >
operator +( CArray< T > const & a, CArray< T > const & b )
{
CArray< T > r( a );
r += b;
return r;
}
// CArray - CArray
template< typename T >
inline
CArray< T >
operator -( CArray< T > const & a, CArray< T > const & b )
{
CArray< T > r( a );
r -= b;
return r;
}
// CArray + Value
template< typename T >
inline
CArray< T >
operator +( CArray< T > const & a, typename CArray< T >::Tc t )
{
CArray< T > r( a );
r += t;
return r;
}
// Value + CArray
template< typename T >
inline
CArray< T >
operator +( typename CArray< T >::Tc t, CArray< T > const & a )
{
CArray< T > r( a );
r += t;
return r;
}
// CArray - Value
template< typename T >
inline
CArray< T >
operator -( CArray< T > const & a, typename CArray< T >::Tc t )
{
CArray< T > r( a );
r -= t;
return r;
}
// Value - CArray
template< typename T >
inline
CArray< T >
operator -( typename CArray< T >::Tc t, CArray< T > const & a )
{
CArray< T > r( -a );
r += t;
return r;
}
// CArray * Value
template< typename T >
inline
CArray< T >
operator *( CArray< T > const & a, typename CArray< T >::Tc t )
{
CArray< T > r( a );
r *= t;
return r;
}
// Value * CArray
template< typename T >
inline
CArray< T >
operator *( typename CArray< T >::Tc t, CArray< T > const & a )
{
CArray< T > r( a );
r *= t;
return r;
}
// CArray / Value
template< typename T >
inline
CArray< T >
operator /( CArray< T > const & a, typename CArray< T >::Tc t )
{
CArray< T > r( a );
r /= t;
return r;
}
// Stream >> CArray
template< typename T >
inline
std::istream &
operator >>( std::istream & stream, CArray< T > & a )
{
typedef typename CArray< T >::size_type size_type;
if ( stream && ( ! a.emtpy() ) ) {
for ( size_type i = 0, e = a.size(); i < e; ++i ) {
stream >> a[ i ];
if ( ! stream ) break;
}
}
return stream;
}
// Stream << CArray
template< typename T >
inline
std::ostream &
operator <<( std::ostream & stream, CArray< T > const & a )
{
using std::setw;
typedef TypeTraits< T > Traits;
typedef typename CArray< T >::size_type size_type;
if ( stream && ( ! a.emtpy() ) ) {
std::ios_base::fmtflags const old_flags( stream.flags() );
std::streamsize const old_precision( stream.precision( Traits::precision ) );
stream << std::right << std::showpoint << std::uppercase;
size_type const e( a.size() - 1 );
int const w( Traits::iwidth );
for ( size_type i = 0; i < e; ++i ) {
stream << setw( w ) << a[ i ] << ' ';
} stream << setw( w ) << a[ e ];
stream.precision( old_precision );
stream.flags( old_flags );
}
return stream;
}
} // ObjexxFCL
#endif // ObjexxFCL_CArray_hh_INCLUDED
// ===== ObjexxFCL/Array1S.hh =====
#ifndef ObjexxFCL_Array1S_hh_INCLUDED
#define ObjexxFCL_Array1S_hh_INCLUDED
// Array1S: 1D Slice Array Proxy
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// ObjexxFCL Headers
// C++ Headers
#include <array>
#include <vector>
namespace ObjexxFCL {
// Array1S: 1D Slice Array Proxy
template< typename T >
class Array1S : public ArrayRS< T, 1 >
{
private: // Types
typedef ArrayRS< T, 1 > Super;
private: // Friend
template< typename > friend class Array1S;
public: // Types
typedef typename Super::Base Base;
typedef typename Super::Traits Traits;
typedef typename Super::IR IR;
typedef typename Super::IS IS;
typedef typename Super::DS DS;
// STL Style
typedef typename Super::value_type value_type;
typedef typename Super::reference reference;
typedef typename Super::const_reference const_reference;
typedef typename Super::pointer pointer;
typedef typename Super::const_pointer const_pointer;
typedef typename Super::size_type size_type;
typedef typename Super::difference_type difference_type;
// C++ Style
typedef typename Super::Value Value;
typedef typename Super::Reference Reference;
typedef typename Super::ConstReference ConstReference;
typedef typename Super::Pointer Pointer;
typedef typename Super::ConstPointer ConstPointer;
typedef typename Super::Size Size;
typedef typename Super::Difference Difference;
using Super::isize;
using Super::overlap;
using Super::size;
protected: // Types
using Super::in_range;
using Super::slice_k;
using Super::contiguous_;
using Super::data_;
using Super::data_beg_;
using Super::data_end_;
using Super::size_;
public: // Creation
// Default Constructor
Array1S() :
m_( 1 ),
k_( 0 ),
u_( 0 )
{}
// Copy Constructor
Array1S( Array1S const & a ) :
Super( a ),
m_( a.m_ ),
k_( a.k_ ),
u_( a.u_ )
{
data_set();
}
// Data Constructor
Array1S( T const * data, std::int64_t const k, DS const & d ) :
Super( data, d.z() ),
m_( d.m() ),
k_( k + d.k() ),
u_( d.u() )
{
contiguous_ = computed_contiguous();
data_set();
}
// Non-Const Data Constructor
Array1S( T * data, std::int64_t const k, DS const & d ) :
Super( data, d.z() ),
m_( d.m() ),
k_( k + d.k() ),
u_( d.u() )
{
contiguous_ = computed_contiguous();
data_set();
}
// Array Constructor
template< template< typename > class A >
Array1S( A< T > const & a ) :
Super( a.data(), a.size() ),
m_( 1 ),
k_( -m_ ),
u_( a.isize() )
{
contiguous_ = true;
data_set();
}
// Destructor
virtual
~Array1S() = default;
public: // Assignment: Array
// Copy Assignment
Array1S &
operator =( Array1S const & a )
{
if ( this != &a ) {
assert( conformable( a ) );
if ( overlap( a ) ) { // Overlap-safe
CArray< T > c( size_ );
for ( int i = 1; i <= u_; ++i ) {
c( i ) = a( i );
}
for ( int i = 1; i <= u_; ++i ) {
operator ()( i ) = c( i );
}
} else { // Not overlap-safe
for ( int i = 1; i <= u_; ++i ) {
operator ()( i ) = a( i );
}
}
}
return *this;
}
// += Array Template
template< template< typename > class A >
Array1S &
operator +=( A< T > const & a )
{
assert( conformable( a ) );
if ( overlap( a ) ) { // Overlap-safe
CArray< T > c( size_ );
for ( int i = 1, j = a.l(); i <= u_; ++i, ++j ) {
c( i ) = a( j );
}
for ( int i = 1; i <= u_; ++i ) {
operator ()( i ) += c( i );
}
} else { // Not overlap-safe
for ( int i = 1, j = a.l(); i <= u_; ++i, ++j ) {
operator ()( i ) += a( j );
}
}
return *this;
}
// *= std::array Template
template< typename U, Size s, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1S &
operator *=( std::array< U, s > const & a )
{
assert( size_ == s );
auto r( a.begin() );
for ( int i = 1; i <= u_; ++i, ++r ) {
operator ()( i ) *= *r;
}
return *this;
}
// += std::array Template
template< typename U, Size s, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1S &
operator +=( std::array< U, s > const & a )
{
assert( size_ == s );
auto r( a.begin() );
for ( int i = 1; i <= u_; ++i, ++r ) {
operator ()( i ) += *r;
}
return *this;
}
public: // Assignment: Value
template< typename U, Size s, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1S &
operator =( std::array< U, s > const & a )
{
assert( size_ == s );
auto r( a.begin() );
for ( int i = 1; i <= u_; ++i, ++r ) {
operator ()( i ) = *r;
}
return *this;
}
// Initializer List Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1S &
operator =( std::initializer_list< U > const l )
{
assert( size_ == l.size() );
auto r( l.begin() );
for ( int i = 1; i <= u_; ++i, ++r ) {
operator ()( i ) = *r;
}
return *this;
}
// = Value
Array1S &operator=(T const &t) {
for (int i = 1; i <= u_; ++i) {
operator()(i) = t;
}
return *this;
}
// *= Value
Array1S &
operator *=( T const & t )
{
for ( int i = 1; i <= u_; ++i ) {
operator ()( i ) *= t;
}
return *this;
}
// /= Value
template< typename U, class = typename std::enable_if< std::is_floating_point< U >::value && std::is_assignable< T&, U >::value >::type >
Array1S &
operator /=( U const & u )
{
assert( u != U( 0 ) );
U const inv_u( U( 1 ) / u );
for ( int i = 1; i <= u_; ++i ) {
operator ()( i ) *= inv_u;
}
return *this;
}
// /= Value
template< typename U, class = typename std::enable_if< ! std::is_floating_point< U >::value && std::is_assignable< T&, U >::value >::type, typename = void >
Array1S &
operator /=( U const & u )
{
assert( u != U( 0 ) );
for ( int i = 1; i <= u_; ++i ) {
operator ()( i ) /= u;
}
return *this;
}
public: // Subscript
// array( i ) const
T const &
operator ()( int const i ) const
{
assert( contains( i ) );
return data_[ k_ + ( m_ * i ) ];
}
// array( i )
T &
operator ()( int const i )
{
assert( contains( i ) );
return data_[ k_ + ( m_ * i ) ];
}
// Linear Index
size_type
index( int const i ) const
{
return k_ + ( m_ * i );
}
// array[ i ] const: 0-Based Subscript
T const &
operator []( size_type const i ) const
{
assert( i < std::numeric_limits< size_type >::max() );
assert( contains( static_cast< int >( i + 1 ) ) );
return data_[ k_ + ( m_ * ( i + 1 ) ) ];
}
// array[ i ]: 0-Based Subscript
T &
operator []( size_type const i )
{
assert( i < std::numeric_limits< int >::max() );
assert( contains( static_cast< int >( i + 1 ) ) );
return data_[ k_ + ( m_ * ( i + 1 ) ) ];
}
public: // Slice Proxy Generators
// array( s ) const
Array1S
operator ()( IS const & s ) const
{
DS const d( u_, s, m_ );
return Array1S( data_, k_, d );
}
// array( s )
Array1S
operator ()( IS const & s )
{
DS const d( u_, s, m_ );
return Array1S( data_, k_, d );
}
// array( {s} ) const
template< typename U, class = typename std::enable_if< std::is_constructible< int, U >::value >::type >
Array1S
operator ()( std::initializer_list< U > const l ) const
{
IS const s( l );
DS const d( u_, s, m_ );
return Array1S( data_, k_, d );
}
// array( {s} )
template< typename U, class = typename std::enable_if< std::is_constructible< int, U >::value >::type >
Array1S
operator ()( std::initializer_list< U > const l )
{
IS const s( l );
DS const d( u_, s, m_ );
return Array1S( data_, k_, d );
}
public: // Predicate
// Contains Indexed Element?
bool
contains( int const i ) const
{
return in_range( u_, i );
}
// Conformable?
template< typename U >
bool
conformable( Array1S< U > const & a ) const
{
return ( u_ == a.u_ );
}
// Conformable?
template< class A >
bool
conformable( A const & a ) const
{
return ( ( a.rank() == 1 ) && ( size_ == a.size() ) );
}
// Equal Dimensions?
template< typename U >
bool
equal_dimensions( Array1S< U > const & a ) const
{
return conformable( a );
}
// Equal Dimensions?
template< class A >
bool
equal_dimensions( A const & a ) const
{
return conformable( a );
}
public: // Inspector
// IndexRange of a Dimension
IR
I( int const d ) const
{
switch ( d ) {
case 1:
return I1();
default:
assert( false );
return I1();
}
}
// Upper Index of a Dimension
int
u( int const d ) const
{
switch ( d ) {
case 1:
return u_;
default:
assert( false );
return u_;
}
}
// Size of a Dimension
size_type
size( int const d ) const
{
switch ( d ) {
case 1:
return u_;
default:
assert( false );
return u_;
}
}
// Size of a Dimension
int
isize( int const d ) const
{
switch ( d ) {
case 1:
return u_;
default:
assert( false );
return u_;
}
}
// IndexRange
IR
I() const
{
return IR( 1, u_ );
}
// Lower Index
int
l() const
{
return 1;
}
// Upper Index
int
u() const
{
return u_;
}
// IndexRange of Dimension 1
IR
I1() const
{
return IR( 1, u_ );
}
// Lower Index of Dimension 1
int
l1() const
{
return 1;
}
// Upper Index of Dimension 1
int
u1() const
{
return u_;
}
// Size of Dimension 1
size_type
size1() const
{
return u_;
}
// Size of Dimension 1
int
isize1() const
{
return u_;
}
// Shift for Proxy
std::ptrdiff_t
shift() const
{
return 1;
}
public:
// Slice == Value
friend
bool
eq( Array1S const & a, T const & t )
{
if ( a.empty() ) return true;
for ( int i = 1, e = a.u(); i <= e; ++i ) {
if ( ! ( a( i ) == t ) ) return false;
}
return true;
}
// Any Slice != Value
friend
bool
any_ne( Array1S const & a, T const & t )
{
return ! eq( a, t );
}
// Any Slice < Value
friend
bool
any_lt( Array1S const & a, T const & t )
{
if ( a.empty() ) return false;
for ( int i = 1, e = a.u(); i <= e; ++i ) {
if ( a( i ) < t ) return true;
}
return false;
}
// Any Slice > Value
friend
bool
any_gt( Array1S const & a, T const & t )
{
return any_lt( t, a );
}
// Any Value < Slice
friend
bool
any_lt( T const & t, Array1S const & a )
{
if ( a.empty() ) return false;
for ( int i = 1, e = a.u(); i <= e; ++i ) {
if ( t < a( i ) ) return true;
}
return false;
}
private: // Methods
// Contiguous?
bool
computed_contiguous() const
{
return m_ == 1;
}
// Memory Range Set
void
data_set()
{
if ( size_ > 0u ) { // Non-empty slice
data_beg_ = data_end_ = data_ + k_;
data_beg_ += m_ * ( m_ >= 0 ? 1 : u_ );
data_end_ += m_ * ( m_ <= 0 ? 1 : u_ );
} else {
data_ = data_beg_ = data_end_ = nullptr;
}
}
private: // Data
std::int64_t const m_; // Multiplier
std::int64_t const k_; // Constant
int const u_; // Upper index
}; // Array1S
// Conformable?
template< typename U, typename V >
inline
bool
conformable( Array1S< U > const & a, Array1S< V > const & b )
{
return a.conformable( b );
}
// Magnitude
template< typename T >
inline
T
magnitude( Array1S< T > const & a )
{
T mag_sq( T( 0 ) );
for ( int i = 1, e = a.u(); i <= e; ++i ) {
T const mag_i( a( i ) );
mag_sq += mag_i * mag_i;
}
return std::sqrt( mag_sq );
}
// Magnitude Squared
template< typename T >
inline
T
magnitude_squared( Array1S< T > const & a )
{
T mag_sq( T( 0 ) );
for ( int i = 1, e = a.u(); i <= e; ++i ) {
T const mag_i( a( i ) );
mag_sq += mag_i * mag_i;
}
return mag_sq;
}
// Distance
template< typename T >
inline
T
distance( Array1S< T > const & a, Array1S< T > const & b )
{
assert( a.size() == b.size() );
T distance_sq( T( 0 ) );
for ( int i = 1, e = a.u(); i <= e; ++i ) {
T const distance_i( a( i ) - b( i ) );
distance_sq += distance_i * distance_i;
}
return std::sqrt( distance_sq );
}
// Distance
template< typename T >
inline
T
distance( Array1S< T > const & a, Vector2< T > const & b )
{
assert( a.size() == 2u );
T distance_sq( T( 0 ) );
for ( int i = a.l(), j = b.l(), e = a.u(); i <= e; ++i, ++j ) {
T const distance_i( a( i ) - b( j ) );
distance_sq += distance_i * distance_i;
}
return std::sqrt( distance_sq );
}
// Distance
template< typename T >
inline
T
distance( Vector2< T > const & a, Array1S< T > const & b )
{
return distance( b, a );
}
// Distance
template< typename T >
inline
T
distance( Array1S< T > const & a, Vector3< T > const & b )
{
assert( a.size() == 3u );
T distance_sq( T( 0 ) );
for ( int i = a.l(), j = b.l(), e = a.u(); i <= e; ++i, ++j ) {
T const distance_i( a( i ) - b( j ) );
distance_sq += distance_i * distance_i;
}
return std::sqrt( distance_sq );
}
// Distance
template< typename T >
inline
T
distance( Vector3< T > const & a, Array1S< T > const & b )
{
return distance( b, a );
}
// Distance
template< typename T >
inline
T
distance( Array1S< T > const & a, Vector4< T > const & b )
{
assert( a.size() == 4u );
T distance_sq( T( 0 ) );
for ( int i = a.l(), j = b.l(), e = a.u(); i <= e; ++i, ++j ) {
T const distance_i( a( i ) - b( j ) );
distance_sq += distance_i * distance_i;
}
return std::sqrt( distance_sq );
}
// Distance
template< typename T >
inline
T
distance( Vector4< T > const & a, Array1S< T > const & b )
{
return distance( b, a );
}
// Distance Squared
template< typename T >
inline
T
distance_squared( Array1S< T > const & a, Array1S< T > const & b )
{
assert( a.size() == b.size() );
T distance_sq( T( 0 ) );
for ( int i = 1, e = a.u(); i <= e; ++i ) {
T const distance_i( a( i ) - b( i ) );
distance_sq += distance_i * distance_i;
}
return distance_sq;
}
// Distance Squared
template< typename T >
inline
T
distance_squared( Array1S< T > const & a, Vector2< T > const & b )
{
assert( a.size() == 2u );
T distance_sq( T( 0 ) );
for ( int i = a.l(), j = b.l(), e = a.u(); i <= e; ++i, ++j ) {
T const distance_i( a( i ) - b( j ) );
distance_sq += distance_i * distance_i;
}
return distance_sq;
}
// Distance Squared
template< typename T >
inline
T
distance_squared( Vector2< T > const & a, Array1S< T > const & b )
{
return distance_squared( b, a );
}
// Distance Squared
template< typename T >
inline
T
distance_squared( Array1S< T > const & a, Vector3< T > const & b )
{
assert( a.size() == 3u );
T distance_sq( T( 0 ) );
for ( int i = a.l(), j = b.l(), e = a.u(); i <= e; ++i, ++j ) {
T const distance_i( a( i ) - b( j ) );
distance_sq += distance_i * distance_i;
}
return distance_sq;
}
// Distance Squared
template< typename T >
inline
T
distance_squared( Vector3< T > const & a, Array1S< T > const & b )
{
return distance_squared( b, a );
}
// Distance Squared
template< typename T >
inline
T
distance_squared( Array1S< T > const & a, Vector4< T > const & b )
{
assert( a.size() == 4u );
T distance_sq( T( 0 ) );
for ( int i = a.l(), j = b.l(), e = a.u(); i <= e; ++i, ++j ) {
T const distance_i( a( i ) - b( j ) );
distance_sq += distance_i * distance_i;
}
return distance_sq;
}
// Distance Squared
template< typename T >
inline
T
distance_squared( Vector4< T > const & a, Array1S< T > const & b )
{
return distance_squared( b, a );
}
// Dot Product
template< typename T >
inline
T
dot( Array1S< T > const & a, Array1S< T > const & b )
{
assert( a.size() == b.size() );
T result( T( 0 ) );
for ( int i = 1, e = a.u(); i <= e; ++i ) {
result += a( i ) * b( i );
}
return result;
}
// Dot Product of Boolean Arrays
inline
bool
dot( Array1S< bool > const & a, Array1S< bool > const & b )
{
assert( a.size() == b.size() );
bool result( false );
for ( int i = 1, e = a.u(); i <= e; ++i ) {
if ( a( i ) && b( i ) ) {
result = true;
break;
}
}
return result;
}
// Dot Product with Vector2
template< typename T >
inline
T
dot( Array1S< T > const & a, Vector2< T > const & b )
{
assert( a.size() == 2u );
T result( T( 0 ) );
for ( int i = 1, e = a.u(); i <= e; ++i ) {
result += a( i ) * b( i );
}
return result;
}
// Dot Product with Vector2
template< typename T >
inline
T
dot( Vector2< T > const & a, Array1S< T > const & b )
{
return dot( b, a );
}
// Dot Product with Vector3
template< typename T >
inline
T
dot( Array1S< T > const & a, Vector3< T > const & b )
{
assert( a.size() == 3u );
T result( T( 0 ) );
for ( int i = 1, e = a.u(); i <= e; ++i ) {
result += a( i ) * b( i );
}
return result;
}
// Dot Product with Vector3
template< typename T >
inline
T
dot( Vector3< T > const & a, Array1S< T > const & b )
{
return dot( b, a );
}
// Dot Product with Vector4
template< typename T >
inline
T
dot( Array1S< T > const & a, Vector4< T > const & b )
{
assert( a.size() == 4u );
T result( T( 0 ) );
for ( int i = 1, e = a.u(); i <= e; ++i ) {
result += a( i ) * b( i );
}
return result;
}
// Dot Product with Vector4
template< typename T >
inline
T
dot( Vector4< T > const & a, Array1S< T > const & b )
{
return dot( b, a );
}
// Dot Product (Fortran Intrinsic Name)
template< typename T >
inline
T
dot_product( Array1S< T > const & a, Array1S< T > const & b )
{
return dot( a, b );
}
// Dot Product of Boolean Arrays (Fortran Intrinsic Name)
inline
bool
dot_product( Array1S< bool > const & a, Array1S< bool > const & b )
{
return dot( a, b );
}
// Cross Product of 2-Tuples
template< typename T >
inline
T
cross2( Vector2< T > const & a, Array1S< T > const & b )
{
return cross2( b, a );
}
// Stream >> Array1S
template< typename T >
inline
std::istream &
operator >>( std::istream & stream, Array1S< T > & a )
{
if ( stream && ( a.size() > 0u ) ) {
for ( int i = 1, e = a.u(); i <= e; ++i ) {
stream >> a( i );
if ( ! stream ) break;
}
}
return stream;
}
// Stream << Array1S
template< typename T >
inline
std::ostream &
operator <<( std::ostream & stream, Array1S< T > const & a )
{
typedef TypeTraits< T > Traits;
if ( stream && ( a.size() > 0u ) ) {
std::ios_base::fmtflags const old_flags( stream.flags() );
std::streamsize const old_precision( stream.precision( Traits::precision ) );
stream << std::right << std::showpoint << std::uppercase;
int const w( Traits::iwidth );
for ( int i = 1, e = a.u(); i <= e; ++i ) {
stream << std::setw( w ) << a( i ) << ' ';
if ( ! stream ) break;
}
stream.precision( old_precision );
stream.flags( old_flags );
}
return stream;
}
namespace fmt {
// List-Directed Format: Array1S
template< typename T >
inline
std::string
LD( Array1S< T > const & a )
{
std::string s;
std::size_t const n( a.size() );
if ( n > 0u ) {
s.reserve( n * TypeTraits< T >::width );
for ( int i = 1, e = a.u(); i <= e; ++i ) {
s.append( fmt::LD( a( i ) ) );
}
}
return s;
}
} // fmt
} // ObjexxFCL
#endif // ObjexxFCL_Array1S_hh_INCLUDED
// ===== ObjexxFCL/MArrayR.hh =====
#ifndef ObjexxFCL_MArrayR_hh_INCLUDED
#define ObjexxFCL_MArrayR_hh_INCLUDED
// MArrayR: Rank Member Array Proxy Abstract Base Class Template
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// ObjexxFCL Headers
namespace ObjexxFCL {
// MArrayR: Rank Member Array Proxy Abstract Base Class Template
template< class A, typename T, int Rank >
class MArrayR : public MArray< A, T >
{
private: // Types
typedef MArray< A, T > Super;
private: // Friend
template< typename, typename, int > friend class MArrayR;
public: // Types
typedef typename Super::ArrayType ArrayType;
typedef typename Super::Class Class;
typedef typename Super::MPtr MPtr;
typedef typename Super::Traits Traits;
typedef typename Super::IR IR;
// STL Style
typedef typename Super::value_type value_type;
typedef typename Super::reference reference;
typedef typename Super::const_reference const_reference;
typedef typename Super::pointer pointer;
typedef typename Super::const_pointer const_pointer;
typedef typename Super::size_type size_type;
typedef typename Super::difference_type difference_type;
// C++ Style
typedef typename Super::Value Value;
typedef typename Super::Reference Reference;
typedef typename Super::ConstReference ConstReference;
typedef typename Super::Pointer Pointer;
typedef typename Super::ConstPointer ConstPointer;
typedef typename Super::Size Size;
typedef typename Super::Difference Difference;
using Super::isize;
using Super::l;
using Super::u;
using Super::size;
protected: // Types
using Super::in_range;
using Super::array_;
using Super::pmem_;
protected: // Creation
// Copy Constructor
MArrayR( MArrayR const & a ) :
Super( a )
{
assert( a.rank() == Rank );
}
// Constructor
MArrayR( A & a, T Class::* pmem ) :
Super( a, pmem )
{}
public: // Creation
// Destructor
virtual
~MArrayR() = default;
// Copy Assignment
MArrayR &
operator =( MArrayR const & a ) = delete;
public: // Inspector
// Rank
int
rank() const
{
return Rank;
}
}; // MArrayR
} // ObjexxFCL
#endif // ObjexxFCL_MArrayR_hh_INCLUDED
// ===== ObjexxFCL/MArray1.hh =====
#ifndef ObjexxFCL_MArray1_hh_INCLUDED
#define ObjexxFCL_MArray1_hh_INCLUDED
// MArray1: 1D Member Array Proxy
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// ObjexxFCL Headers
// C++ Headers
#include <array>
#include <cmath>
#include <vector>
namespace ObjexxFCL {
// MArray1: 1D Member Array Proxy
template< class A, typename T >
class MArray1 : public MArrayR< A, T, 1 >
{
private: // Types
typedef MArrayR< A, T, 1 > Super;
private: // Friend
template< typename, typename > friend class MArray1;
public: // Types
typedef typename Super::ArrayType ArrayType;
typedef typename Super::Class Class;
typedef typename Super::MPtr MPtr;
typedef typename Super::Traits Traits;
typedef typename Super::IR IR;
// STL Style
typedef typename Super::value_type value_type;
typedef typename Super::reference reference;
typedef typename Super::const_reference const_reference;
typedef typename Super::pointer pointer;
typedef typename Super::const_pointer const_pointer;
typedef typename Super::size_type size_type;
typedef typename Super::difference_type difference_type;
// C++ Style
typedef typename Super::Value Value;
typedef typename Super::Reference Reference;
typedef typename Super::ConstReference ConstReference;
typedef typename Super::Pointer Pointer;
typedef typename Super::ConstPointer ConstPointer;
typedef typename Super::Size Size;
typedef typename Super::Difference Difference;
using Super::isize;
using Super::l;
using Super::u;
using Super::size;
protected: // Types
using Super::in_range;
using Super::j1;
using Super::array_;
using Super::pmem_;
public: // Creation
// Copy Constructor
MArray1( MArray1 const & a ) :
Super( a )
{}
// Constructor
MArray1( A & a, T Class::* pmem ) :
Super( a, pmem )
{}
// Destructor
virtual
~MArray1() = default;
public: // Assignment: Array
// Copy Assignment
MArray1 &
operator =( MArray1 const & a )
{
if ( this != &a ) {
assert( conformable( a ) );
for ( int i = 1, e = u(); i <= e; ++i ) {
operator ()( i ) = a( i ); // Not overlap-safe
}
}
return *this;
}
// Copy Assignment Template
template< typename Aa, typename Ta >
MArray1 &
operator =( MArray1< Aa, Ta > const & a )
{
assert( conformable( a ) );
for ( int i = 1, e = u(); i <= e; ++i ) {
operator ()( i ) = a( i ); // Not overlap-safe
}
return *this;
}
// Array Assignment Template
template< template< typename > class Ar, typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
MArray1 &
operator =( Ar< U > const & a )
{
assert( conformable( a ) );
for ( int i = 1, j = a.l(), e = u(); i <= e; ++i, ++j ) {
operator ()( i ) = a( j ); // Not overlap-safe
}
return *this;
}
// Initializer List Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
MArray1 &
operator =( std::initializer_list< U > const l )
{
assert( size() == l.size() );
auto r( l.begin() );
for ( int i = 1, e = u(); i <= e; ++i, ++r ) {
operator ()( i ) = *r;
}
return *this;
}
// std::array Assignment Template
template< typename U, Size s, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
MArray1 &
operator =( std::array< U, s > const & a )
{
assert( size() == s );
auto r( a.begin() );
for ( int i = 1, e = u(); i <= e; ++i, ++r ) {
operator ()( i ) = *r;
}
return *this;
}
// std::vector Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
MArray1 &
operator =( std::vector< U > const & v )
{
assert( size() == v.size() );
auto r( v.begin() );
for ( int i = 1, e = u(); i <= e; ++i, ++r ) {
operator ()( i ) = *r;
}
return *this;
}
// Vector2 Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
MArray1 &
operator =( Vector2< U > const & v )
{
assert( size() == 2u );
operator ()( 1 ) = v.x;
operator ()( 2 ) = v.y;
return *this;
}
// Vector3 Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
MArray1 &
operator =( Vector3< U > const & v )
{
assert( size() == 3u );
operator ()( 1 ) = v.x;
operator ()( 2 ) = v.y;
operator ()( 3 ) = v.z;
return *this;
}
// Vector4 Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
MArray1 &
operator =( Vector4< U > const & v )
{
assert( size() == 4u );
operator ()( 1 ) = v.x;
operator ()( 2 ) = v.y;
operator ()( 3 ) = v.z;
operator ()( 3 ) = v.w;
return *this;
}
public: // Assignment: Value
// = Value
MArray1 &
operator =( T const & t )
{
for ( int i = 1, e = u(); i <= e; ++i ) {
operator ()( i ) = t;
}
return *this;
}
// = Value Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
MArray1 &
operator =( U const & t )
{
for ( int i = 1, e = u(); i <= e; ++i ) {
operator ()( i ) = t;
}
return *this;
}
public: // Subscript
// array( i ) const
T const &
operator ()( int const i ) const
{
assert( contains( i ) );
return array_( j1( i ) ).*pmem_;
}
// array( i )
T &
operator ()( int const i )
{
assert( contains( i ) );
return array_( j1( i ) ).*pmem_;
}
// array[ i ] const: 0-Based Subscript
T const &
operator []( size_type const i ) const
{
assert( i < std::numeric_limits< int >::max() );
assert( contains( static_cast< int >( i + 1 ) ) );
return array_( j1( static_cast< int >( i + 1 ) ) ).*pmem_;
}
// array[ i ]: 0-Based Subscript
T &
operator []( size_type const i )
{
assert( i < std::numeric_limits< int >::max() );
assert( contains( static_cast< int >( i + 1 ) ) );
return array_( j1( static_cast< int >( i + 1 ) ) ).*pmem_;
}
public: // Predicate
// Contains Indexed Element?
bool
contains( int const i ) const
{
return in_range( u(), i );
}
// Conformable?
template< typename Aa, typename Ta >
bool
conformable( MArray1< Aa, Ta > const & a ) const
{
return ( size() == a.size() );
}
// Conformable?
template< class Ar >
bool
conformable( Ar const & a ) const
{
return ( ( a.rank() == 1 ) && ( size() == a.size() ) );
}
// Equal Dimensions?
template< typename Aa, typename Ta >
bool
equal_dimensions( MArray1< Aa, Ta > const & a ) const
{
return conformable( a );
}
// Equal Dimensions?
template< class Ar >
bool
equal_dimensions( Ar const & a ) const
{
return conformable( a );
}
public: // Inspector
// IndexRange
IR
I() const
{
return IR( 1, u() );
}
// Lower Index
int
l() const
{
return 1;
}
// Upper Index
int
u() const
{
return array_.isize1();
}
// IndexRange of Dimension 1
IR
I1() const
{
return IR( 1, u1() );
}
// Lower Index of Dimension 1
int
l1() const
{
return 1;
}
// Upper Index of Dimension 1
int
u1() const
{
return array_.isize1();
}
// Size of Dimension 1
size_type
size1() const
{
return array_.size1();
}
// Size of Dimension 1
int
isize1() const
{
return array_.isize1();
}
// Length
T
length() const
{
T length_sq( T( 0 ) );
for ( int i = 1, e = u(); i <= e; ++i ) {
T const length_i( operator ()( i ) );
length_sq += length_i * length_i;
}
return std::sqrt( length_sq );
}
public: // Modifier
// Normalize to Unit Length
MArray1 &
normalize()
{
T const length_( length() );
assert( length_ > T( 0 ) );
operator /=( length_ );
return *this;
}
}; // MArray1
namespace fmt {
// List-Directed Format: MArray1
template< class A, typename T >
inline
std::string
LD( MArray1< A, T > const & a )
{
std::string s;
std::size_t const n( a.size() );
if ( n > 0u ) {
s.reserve( n * TypeTraits< T >::width );
for ( int i = 1, e = a.u(); i <= e; ++i ) {
s.append( fmt::LD( a( i ) ) );
}
}
return s;
}
} // fmt
} // ObjexxFCL
#endif // ObjexxFCL_MArray1_hh_INCLUDED
// ===== ObjexxFCL/Array1.hh =====
#ifndef ObjexxFCL_Array1_hh_INCLUDED
#define ObjexxFCL_Array1_hh_INCLUDED
// Array1: 1D Array Abstract Base Class
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// ObjexxFCL Headers
// C++ Headers
#include <cmath>
namespace ObjexxFCL {
// Forward
template< typename > class Array1D;
template< typename > class Array1A;
// Array1: 1D Array Abstract Base Class
template< typename T >
class Array1 : public Array< T >
{
private: // Types
typedef Array< T > Super;
private: // Friend
template< typename > friend class Array1;
template< typename > friend class Array1D;
template< typename > friend class Array1A;
protected: // Types
typedef internal::InitializerSentinel InitializerSentinel;
typedef internal::ProxySentinel ProxySentinel;
public: // Types
typedef typename Super::Base Base;
typedef typename Super::IR IR;
typedef typename Super::IS IS;
typedef typename Super::DS DS;
// STL Style
typedef typename Super::value_type value_type;
typedef typename Super::reference reference;
typedef typename Super::const_reference const_reference;
typedef typename Super::pointer pointer;
typedef typename Super::const_pointer const_pointer;
typedef typename Super::iterator iterator;
typedef typename Super::const_iterator const_iterator;
typedef typename Super::reverse_iterator reverse_iterator;
typedef typename Super::const_reverse_iterator const_reverse_iterator;
typedef typename Super::size_type size_type;
typedef typename Super::difference_type difference_type;
// C++ Style
typedef typename Super::Value Value;
typedef typename Super::Reference Reference;
typedef typename Super::ConstReference ConstReference;
typedef typename Super::Pointer Pointer;
typedef typename Super::ConstPointer ConstPointer;
typedef typename Super::Iterator Iterator;
typedef typename Super::ConstIterator ConstIterator;
typedef typename Super::ReverseIterator ReverseIterator;
typedef typename Super::ConstReverseIterator ConstReverseIterator;
typedef typename Super::Size Size;
typedef typename Super::Difference Difference;
typedef void iterator_category; // Prevent compile failure when std::distance is in scope
using Super::isize;
using Super::npos;
using Super::overlap;
using Super::size;
protected: // Types
using Super::shift_set;
using Super::size_of;
using Super::slice_k;
using Super::swapB;
using Super::capacity_;
using Super::data_;
using Super::sdata_;
using Super::shift_;
using Super::size_;
protected: // Creation
// Default Constructor
Array1() = default;
// Copy Constructor
Array1( Array1 const & a ) :
Super( a ),
I_( a.I_ )
{}
// Move Constructor
Array1( Array1 && a ) noexcept :
Super( std::move( a ) ),
I_( a.I_ )
{
a.clear_move();
}
// Copy Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
explicit
Array1( Array1< U > const & a ) :
Super( a ),
I_( a.I_ )
{}
// Slice Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
explicit
Array1( Array1S< U > const & a ) :
Super( a ),
I_( a.u() )
{}
// MArray Constructor Template
template< class A, typename M >
explicit
Array1( MArray1< A, M > const & a ) :
Super( a ),
I_( a.u() )
{}
// IndexRange Constructor
explicit
Array1( IR const & I ) :
Super( size_of( I ) ),
I_( I )
{}
// IndexRange + InitializerSentinel Constructor
Array1( IR const & I, InitializerSentinel initialized ) :
Super( size_of( I ), initialized ),
I_( I )
{}
// Initializer List Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array1( std::initializer_list< U > const l ) :
Super( l ),
I_( static_cast< int >( l.size() ) )
{}
// Index Range + Initializer List Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array1( IR const & I, std::initializer_list< U > const l ) :
Super( l ),
I_( I )
{
assert( size_of( I ) == l.size() );
}
// std::array Constructor Template
template< typename U, Size s, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array1( std::array< U, s > const & a ) :
Super( a ),
I_( static_cast< int >( s ) )
{}
// std::vector Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array1( std::vector< U > const & v ) :
Super( v ),
I_( static_cast< int >( v.size() ) )
{}
// Vector2 Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array1( Vector2< U > const & v ) :
Super( v ),
I_( 2 )
{}
// Vector3 Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array1( Vector3< U > const & v ) :
Super( v ),
I_( 3 )
{}
// Vector4 Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array1( Vector4< U > const & v ) :
Super( v ),
I_( 4 )
{}
// Iterator Range Constructor Template
template< class Iterator, typename = decltype( *std::declval< Iterator & >(), void(), ++std::declval< Iterator & >(), void() ) >
Array1( Iterator const beg, Iterator const end ) :
Super( beg, end ),
I_( static_cast< int >( size_ ) )
{}
// Default Proxy Constructor
Array1( ProxySentinel proxy ) :
Super( proxy )
{}
// Copy Proxy Constructor
Array1( Array1 const & a, ProxySentinel proxy ) :
Super( a, proxy ),
I_( a.I_ )
{}
// Slice Proxy Constructor
Array1( Array1S< T > const & a, ProxySentinel proxy ) :
Super( a, proxy ),
I_( a.u() )
{}
// Base Proxy Constructor
Array1( Base const & a, ProxySentinel proxy ) :
Super( a, proxy ),
I_( a.isize() )
{}
// Value Proxy Constructor
Array1( T const & t, ProxySentinel proxy ) :
Super( t, proxy ),
I_( _ )
{}
// Copy + IndexRange Proxy Constructor
Array1( Array1 const & a, IR const & I, ProxySentinel proxy ) :
Super( a, proxy ),
I_( I )
{}
// Slice + IndexRange Proxy Constructor
Array1( Array1S< T > const & a, IR const & I, ProxySentinel proxy ) :
Super( a, proxy ),
I_( I )
{}
// Base + IndexRange Proxy Constructor
Array1( Base const & a, IR const & I, ProxySentinel proxy ) :
Super( a, proxy ),
I_( I )
{}
// Value + IndexRange Proxy Constructor
Array1( T const & t, IR const & I, ProxySentinel proxy ) :
Super( t, proxy ),
I_( I )
{}
public: // Creation
// Destructor
virtual
~Array1() = default;
public: // Assignment: Array
// Copy Assignment
Array1 &
operator =( Array1 const & a )
{
if ( this != &a ) {
if ( ( conformable( a ) ) || ( ! dimension_assign( a.I_ ) ) ) {
Super::operator =( a );
} else {
Super::initialize( a );
}
}
return *this;
}
// Copy Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator =( Array1< U > const & a )
{
if ( ( conformable( a ) ) || ( ! dimension_assign( a.I_ ) ) ) {
Super::operator =( a );
} else {
Super::initialize( a );
}
return *this;
}
// Slice Assignment
Array1 &
operator =( Array1S< T > const & a )
{
size_type l( 0u );
if ( ( conformable( a ) ) || ( ! dimension_assign( a.I() ) ) ) {
if ( overlap( a ) ) { // Overlap-safe
CArrayA< T > c( a.size() );
for ( int i = 1, e = a.u(); i <= e; ++i, ++l ) {
c[ l ] = a( i );
}
for ( size_type i = 0; i < c.size(); ++i ) {
data_[ i ] = c[ i ];
}
} else { // Not overlap-safe
for ( int i = 1, e = a.u(); i <= e; ++i, ++l ) {
data_[ l ] = a( i );
}
}
} else {
for ( int i = 1, e = a.u(); i <= e; ++i, ++l ) {
new ( data_ + l ) T( a( i ) );
}
}
return *this;
}
// Slice Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator =( Array1S< U > const & a )
{
size_type l( 0u );
if ( ( conformable( a ) ) || ( ! dimension_assign( a.I() ) ) ) {
for ( int i = 1, e = a.u(); i <= e; ++i, ++l ) {
data_[ l ] = a( i );
}
} else {
for ( int i = 1, e = a.u(); i <= e; ++i, ++l ) {
new ( data_ + l ) T( a( i ) );
}
}
return *this;
}
// Initializer List Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator =( std::initializer_list< U > const l )
{
Super::operator =( l );
return *this;
}
// std::array Assignment Template
template< typename U, Size s, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator =( std::array< U, s > const & a )
{
Super::operator =( a );
return *this;
}
// std::vector Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator =( std::vector< U > const & v )
{
Super::operator =( v );
return *this;
}
// Vector2 Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator =( Vector2< U > const & v )
{
Super::operator =( v );
return *this;
}
// Vector3 Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator =( Vector3< U > const & v )
{
Super::operator =( v );
return *this;
}
// Vector4 Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator =( Vector4< U > const & v )
{
Super::operator =( v );
return *this;
}
// += Array Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator +=( Array1< U > const & a )
{
assert( conformable( a ) );
Super::operator +=( a );
return *this;
}
// -= Array Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator -=( Array1< U > const & a )
{
assert( conformable( a ) );
Super::operator -=( a );
return *this;
}
// *= Array Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator *=( Array1< U > const & a )
{
assert( conformable( a ) );
Super::operator *=( a );
return *this;
}
// /= Array Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator /=( Array1< U > const & a )
{
assert( conformable( a ) );
Super::operator /=( a );
return *this;
}
// += Slice
Array1 &
operator +=( Array1S< T > const & a )
{
assert( conformable( a ) );
size_type l( 0u );
if ( overlap( a ) ) { // Overlap-safe
CArrayA< T > c( a.size() );
for ( int i = 1, e = a.u(); i <= e; ++i, ++l ) {
c[ l ] = a( i );
}
for ( size_type i = 0; i < c.size(); ++i ) {
data_[ i ] += c[ i ];
}
} else { // Not overlap-safe
for ( int i = 1, e = a.u(); i <= e; ++i, ++l ) {
data_[ l ] += a( i );
}
}
return *this;
}
// -= Slice
Array1 &
operator -=( Array1S< T > const & a )
{
assert( conformable( a ) );
size_type l( 0u );
if ( overlap( a ) ) { // Overlap-safe
CArrayA< T > c( a.size() );
for ( int i = 1, e = a.u(); i <= e; ++i, ++l ) {
c[ l ] = a( i );
}
for ( size_type i = 0; i < c.size(); ++i ) {
data_[ i ] -= c[ i ];
}
} else { // Not overlap-safe
for ( int i = 1, e = a.u(); i <= e; ++i, ++l ) {
data_[ l ] -= a( i );
}
}
return *this;
}
// *= Slice
Array1 &
operator *=( Array1S< T > const & a )
{
assert( conformable( a ) );
size_type l( 0u );
if ( overlap( a ) ) { // Overlap-safe
CArrayA< T > c( a.size() );
for ( int i = 1, e = a.u(); i <= e; ++i, ++l ) {
c[ l ] = a( i );
}
for ( size_type i = 0; i < c.size(); ++i ) {
data_[ i ] *= c[ i ];
}
} else { // Not overlap-safe
for ( int i = 1, e = a.u(); i <= e; ++i, ++l ) {
data_[ l ] *= a( i );
}
}
return *this;
}
// /= Slice
Array1 &
operator /=( Array1S< T > const & a )
{
assert( conformable( a ) );
size_type l( 0u );
if ( overlap( a ) ) { // Overlap-safe
CArrayA< T > c( a.size() );
for ( int i = 1, e = a.u(); i <= e; ++i, ++l ) {
assert( a( i ) != T( 0 ) );
c[ l ] = a( i );
}
for ( size_type i = 0; i < c.size(); ++i ) {
data_[ i ] /= c[ i ];
}
} else { // Not overlap-safe
for ( int i = 1, e = a.u(); i <= e; ++i, ++l ) {
assert( a( i ) != T( 0 ) );
data_[ l ] /= a( i );
}
}
return *this;
}
// += Slice Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator +=( Array1S< U > const & a )
{
assert( conformable( a ) );
size_type l( 0u );
for ( int i = 1, e = a.u(); i <= e; ++i, ++l ) {
data_[ l ] += a( i );
}
return *this;
}
// -= Slice Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator -=( Array1S< U > const & a )
{
assert( conformable( a ) );
size_type l( 0u );
for ( int i = 1, e = a.u(); i <= e; ++i, ++l ) {
data_[ l ] -= a( i );
}
return *this;
}
// *= Slice Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator *=( Array1S< U > const & a )
{
assert( conformable( a ) );
size_type l( 0u );
for ( int i = 1, e = a.u(); i <= e; ++i, ++l ) {
data_[ l ] *= a( i );
}
return *this;
}
// /= Slice Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator /=( Array1S< U > const & a )
{
assert( conformable( a ) );
size_type l( 0u );
for ( int i = 1, e = a.u(); i <= e; ++i, ++l ) {
assert( a( i ) != T( 0 ) );
data_[ l ] /= a( i );
}
return *this;
}
// += Initializer List Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator +=( std::initializer_list< U > const l )
{
Super::operator +=( l );
return *this;
}
// -= Initializer List Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator -=( std::initializer_list< U > const l )
{
Super::operator -=( l );
return *this;
}
// *= Initializer List Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator *=( std::initializer_list< U > const l )
{
Super::operator *=( l );
return *this;
}
// /= Initializer List Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator /=( std::initializer_list< U > const l )
{
Super::operator /=( l );
return *this;
}
// += std::array Template
template< typename U, Size s, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator +=( std::array< U, s > const & a )
{
Super::operator +=( a );
return *this;
}
// -= std::array Template
template< typename U, Size s, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator -=( std::array< U, s > const & a )
{
Super::operator -=( a );
return *this;
}
// *= std::array Template
template< typename U, Size s, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator *=( std::array< U, s > const & a )
{
Super::operator *=( a );
return *this;
}
// /= std::array Template
template< typename U, Size s, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator /=( std::array< U, s > const & a )
{
Super::operator /=( a );
return *this;
}
// += std::vector Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator +=( std::vector< U > const & v )
{
Super::operator +=( v );
return *this;
}
// -= std::vector Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator -=( std::vector< U > const & v )
{
Super::operator -=( v );
return *this;
}
// *= std::vector Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator *=( std::vector< U > const & v )
{
Super::operator *=( v );
return *this;
}
// /= std::vector Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator /=( std::vector< U > const & v )
{
Super::operator /=( v );
return *this;
}
// += Vector2 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator +=( Vector2< U > const & v )
{
Super::operator +=( v );
return *this;
}
// -= Vector2 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator -=( Vector2< U > const & v )
{
Super::operator -=( v );
return *this;
}
// *= Vector2 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator *=( Vector2< U > const & v )
{
Super::operator *=( v );
return *this;
}
// /= Vector2 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator /=( Vector2< U > const & v )
{
Super::operator /=( v );
return *this;
}
// += Vector3 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator +=( Vector3< U > const & v )
{
Super::operator +=( v );
return *this;
}
// -= Vector3 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator -=( Vector3< U > const & v )
{
Super::operator -=( v );
return *this;
}
// *= Vector3 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator *=( Vector3< U > const & v )
{
Super::operator *=( v );
return *this;
}
// /= Vector3 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator /=( Vector3< U > const & v )
{
Super::operator /=( v );
return *this;
}
// += Vector4 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator +=( Vector4< U > const & v )
{
Super::operator +=( v );
return *this;
}
// -= Vector4 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator -=( Vector4< U > const & v )
{
Super::operator -=( v );
return *this;
}
// *= Vector4 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator *=( Vector4< U > const & v )
{
Super::operator *=( v );
return *this;
}
// /= Vector4 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1 &
operator /=( Vector4< U > const & v )
{
Super::operator /=( v );
return *this;
}
public: // Assignment: Value
// = Value
Array1 &
operator =( T const & t )
{
Super::operator =( t );
return *this;
}
// += Value
Array1 &
operator +=( T const & t )
{
Super::operator +=( t );
return *this;
}
// -= Value
Array1 &
operator -=( T const & t )
{
Super::operator -=( t );
return *this;
}
// *= Value
Array1 &
operator *=( T const & t )
{
Super::operator *=( t );
return *this;
}
// /= Value
Array1 &
operator /=( T const & t )
{
Super::operator /=( t );
return *this;
}
public: // Subscript
// array( i ) const
T const &
operator ()( int const i ) const
{
assert( contains( i ) );
return sdata_[ i ];
}
// array( i )
T &
operator ()( int const i )
{
assert( contains( i ) );
return sdata_[ i ];
}
// Linear Index
size_type
index( int const i ) const
{
return i - shift_;
}
public: // Slice Proxy Generators
// array( s ) const
Array1S< T >
operator ()( IS const & s ) const
{
DS const d( I_, s );
return Array1S< T >( data_, -shift_, d );
}
// array( s )
Array1S< T >
operator ()( IS const & s )
{
DS const d( I_, s );
return Array1S< T >( data_, -shift_, d );
}
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) // VC++2013 bug work-around
// array( {s} ) const
Array1S< T >
operator ()( std::initializer_list< int > const l ) const
{
IS const s( l );
DS const d( I_, s );
return Array1S< T >( data_, -shift_, d );
}
// array( {s} )
Array1S< T >
operator ()( std::initializer_list< int > const l )
{
IS const s( l );
DS const d( I_, s );
return Array1S< T >( data_, -shift_, d );
}
#else
// array( {s} ) const
template< typename U, class = typename std::enable_if< std::is_constructible< int, U >::value >::type >
Array1S< T >
operator ()( std::initializer_list< U > const l ) const
{
IS const s( l );
DS const d( I_, s );
return Array1S< T >( data_, -shift_, d );
}
// array( {s} )
template< typename U, class = typename std::enable_if< std::is_constructible< int, U >::value >::type >
Array1S< T >
operator ()( std::initializer_list< U > const l )
{
IS const s( l );
DS const d( I_, s );
return Array1S< T >( data_, -shift_, d );
}
#endif
public: // Predicate
// Contains Indexed Element?
bool
contains( int const i ) const
{
return I_.contains( i );
}
// Conformable?
template< typename U >
bool
conformable( Array1< U > const & a ) const
{
return ( size_ == a.size() );
}
// Conformable?
template< typename U >
bool
conformable( Array1S< U > const & a ) const
{
return ( size_ == a.size() );
}
// Equal Dimensions?
template< typename U >
bool
equal_dimensions( Array1< U > const & a ) const
{
return ( I_ == a.I_ );
}
// Equal Dimensions?
template< typename U >
bool
equal_dimensions( Array1S< U > const & a ) const
{
return ( ( l() == 1 ) && ( u() == a.u() ) );
}
public: // Inspector
// Rank
int
rank() const
{
return 1;
}
// IndexRange of a Dimension
IR const &
I( int const d ) const
{
switch ( d ) {
case 1:
return I_;
default:
assert( false );
return I_;
}
}
// Lower Index of a Dimension
int
l( int const d ) const
{
switch ( d ) {
case 1:
return l1();
default:
assert( false );
return l1();
}
}
// Upper Index of a Dimension
int
u( int const d ) const
{
switch ( d ) {
case 1:
return u1();
default:
assert( false );
return u1();
}
}
// Size of a Dimension
size_type
size( int const d ) const
{
switch ( d ) {
case 1:
return size1();
default:
assert( false );
return size1();
}
}
// Size of a Dimension
int
isize( int const d ) const
{
switch ( d ) {
case 1:
return isize1();
default:
assert( false );
return isize1();
}
}
// IndexRange
IR const &
I() const
{
return I_;
}
// Lower Index
int
l() const
{
return I_.l();
}
// Upper Index
int
u() const
{
return I_.u();
}
// IndexRange of Dimension 1
IR const &
I1() const
{
return I_;
}
// Lower Index of Dimension 1
int
l1() const
{
return I_.l();
}
// Upper Index of Dimension 1
int
u1() const
{
return I_.u();
}
// Size of Dimension 1
size_type
size1() const
{
return I_.size();
}
// Size of Dimension 1
int
isize1() const
{
return I_.isize();
}
// Length
T
length() const
{
T length_sq( T( 0 ) );
for ( int i = l(), e = u(); i <= e; ++i ) {
T const length_i( sdata_[ i ] );
length_sq += length_i * length_i;
}
return std::sqrt( length_sq );
}
public: // Modifier
// Clear
Array1 &
clear()
{
Super::clear();
I_.clear();
shift_set( 1 );
return *this;
}
// Normalize to Unit Length
Array1 &
normalize()
{
T const length_( length() );
assert( length_ > T( 0 ) );
operator /=( length_ );
return *this;
}
public: // MArray Generators
// Template Helpers
template< typename U > class Wrapper {};
typedef typename std::conditional< std::is_class< T >::value, T, Wrapper< T > >::type ClassT;
// MArray Generator
template< typename M >
MArray1< Array1 const, M >
ma( M ClassT::* pmem ) const
{
return MArray1< Array1 const, M >( *this, pmem );
}
// MArray Generator
template< typename M >
MArray1< Array1, M >
ma( M ClassT::* pmem )
{
return MArray1< Array1, M >( *this, pmem );
}
public: // Comparison: Predicate
// Array1 == Array1
friend
bool
eq( Array1 const & a, Array1 const & b )
{
assert( a.size_bounded() );
assert( a.conformable( b ) );
return eq( static_cast< Super const & >( a ), static_cast< Super const & >( b ) );
}
public: // Comparison: Predicate: Any
// Array1 == Array1
friend
bool
any_eq( Array1 const & a, Array1 const & b )
{
assert( a.size_bounded() );
assert( a.conformable( b ) );
return any_eq( static_cast< Super const & >( a ), static_cast< Super const & >( b ) );
}
public: // Comparison: Predicate: Slice
// Array1 == Array1S
friend
bool
eq( Array1 const & a, Array1S< T > const & b )
{
assert( a.size_bounded() );
assert( a.conformable( b ) );
if ( a.empty() ) return true;
size_type l( 0u );
for ( int i = 1, e = b.u(); i <= e; ++i, ++l ) {
if ( ! ( a[ l ] == b( i ) ) ) return false;
}
return true;
}
// Array1S == Array1
friend
bool
eq( Array1S< T > const & a, Array1 const & b )
{
return eq( b, a );
}
protected: // Functions
// Dimension by IndexRange
virtual
bool
dimension_assign( IR const & I ) = 0;
// Clear on Move
void
clear_move()
{
I_.clear();
shift_set( 1 );
}
// Swap
void
swap1( Array1 & v )
{
swapB( v );
I_.swap( v.I_ );
}
protected: // Data
IR I_; // Index range
}; // Array1
// Conformable?
template< typename U, typename V >
inline
bool
conformable( Array1< U > const & a, Array1< V > const & b )
{
return a.conformable( b );
}
// Conformable?
template< typename U, typename V >
inline
bool
conformable( Array1< U > const & a, Array1S< V > const & b )
{
return a.conformable( b );
}
// Conformable?
template< typename U, typename V >
inline
bool
conformable( Array1S< U > const & a, Array1< V > const & b )
{
return b.conformable( a );
}
// Equal Dimensions?
template< typename U, typename V >
inline
bool
equal_dimensions( Array1< U > const & a, Array1< V > const & b )
{
return a.equal_dimensions( b );
}
// Magnitude
template< typename T >
inline
T
magnitude( Array1< T > const & a )
{
T mag_sq( T( 0 ) );
for ( int i = a.l(), e = a.u(); i <= e; ++i ) {
T const mag_i( a( i ) );
mag_sq += mag_i * mag_i;
}
return std::sqrt( mag_sq );
}
// Magnitude Squared
template< typename T >
inline
T
magnitude_squared( Array1< T > const & a )
{
T mag_sq( T( 0 ) );
for ( int i = a.l(), e = a.u(); i <= e; ++i ) {
T const mag_i( a( i ) );
mag_sq += mag_i * mag_i;
}
return mag_sq;
}
// Distance
template< typename T >
inline
T
distance( Array1< T > const & a, Array1< T > const & b )
{
assert( a.size() == b.size() );
T distance_sq( T( 0 ) );
for ( int i = a.l(), j = b.l(), e = a.u(); i <= e; ++i, ++j ) {
T const distance_i( a( i ) - b( j ) );
distance_sq += distance_i * distance_i;
}
return std::sqrt( distance_sq );
}
// Distance
template< typename T >
inline
T
distance( Array1< T > const & a, Array1S< T > const & b )
{
assert( a.size() == b.size() );
T distance_sq( T( 0 ) );
for ( int i = a.l(), j = b.l(), e = a.u(); i <= e; ++i, ++j ) {
T const distance_i( a( i ) - b( j ) );
distance_sq += distance_i * distance_i;
}
return std::sqrt( distance_sq );
}
// Distance
template< typename T >
inline
T
distance( Array1S< T > const & a, Array1< T > const & b )
{
return distance( b, a );
}
// Distance
template< typename T >
inline
T
distance( Array1< T > const & a, Vector2< T > const & b )
{
assert( a.size() == 2u );
T distance_sq( T( 0 ) );
for ( int i = a.l(), j = b.l(), e = a.u(); i <= e; ++i, ++j ) {
T const distance_i( a( i ) - b( j ) );
distance_sq += distance_i * distance_i;
}
return std::sqrt( distance_sq );
}
// Distance
template< typename T >
inline
T
distance( Vector2< T > const & a, Array1< T > const & b )
{
return distance( b, a );
}
// Distance
template< typename T >
inline
T
distance( Array1< T > const & a, Vector3< T > const & b )
{
assert( a.size() == 3u );
T distance_sq( T( 0 ) );
for ( int i = a.l(), j = b.l(), e = a.u(); i <= e; ++i, ++j ) {
T const distance_i( a( i ) - b( j ) );
distance_sq += distance_i * distance_i;
}
return std::sqrt( distance_sq );
}
// Distance
template< typename T >
inline
T
distance( Vector3< T > const & a, Array1< T > const & b )
{
return distance( b, a );
}
// Distance
template< typename T >
inline
T
distance( Array1< T > const & a, Vector4< T > const & b )
{
assert( a.size() == 4u );
T distance_sq( T( 0 ) );
for ( int i = a.l(), j = b.l(), e = a.u(); i <= e; ++i, ++j ) {
T const distance_i( a( i ) - b( j ) );
distance_sq += distance_i * distance_i;
}
return std::sqrt( distance_sq );
}
// Distance
template< typename T >
inline
T
distance( Vector4< T > const & a, Array1< T > const & b )
{
return distance( b, a );
}
// Distance Squared
template< typename T >
inline
T
distance_squared( Array1< T > const & a, Array1< T > const & b )
{
assert( a.size() == b.size() );
T distance_sq( T( 0 ) );
for ( int i = a.l(), j = b.l(), e = a.u(); i <= e; ++i, ++j ) {
T const distance_i( a( i ) - b( j ) );
distance_sq += distance_i * distance_i;
}
return distance_sq;
}
// Distance Squared
template< typename T >
inline
T
distance_squared( Array1< T > const & a, Array1S< T > const & b )
{
assert( a.size() == b.size() );
T distance_sq( T( 0 ) );
for ( int i = a.l(), j = b.l(), e = a.u(); i <= e; ++i, ++j ) {
T const distance_i( a( i ) - b( j ) );
distance_sq += distance_i * distance_i;
}
return distance_sq;
}
// Distance Squared
template< typename T >
inline
T
distance_squared( Array1S< T > const & a, Array1< T > const & b )
{
return distance_squared( b, a );
}
// Distance Squared
template< typename T >
inline
T
distance_squared( Array1< T > const & a, Vector2< T > const & b )
{
assert( a.size() == 2u );
T distance_sq( T( 0 ) );
for ( int i = a.l(), j = b.l(), e = a.u(); i <= e; ++i, ++j ) {
T const distance_i( a( i ) - b( j ) );
distance_sq += distance_i * distance_i;
}
return distance_sq;
}
// Distance Squared
template< typename T >
inline
T
distance_squared( Vector2< T > const & a, Array1< T > const & b )
{
return distance_squared( b, a );
}
// Distance Squared
template< typename T >
inline
T
distance_squared( Array1< T > const & a, Vector3< T > const & b )
{
assert( a.size() == 3u );
T distance_sq( T( 0 ) );
for ( int i = a.l(), j = b.l(), e = a.u(); i <= e; ++i, ++j ) {
T const distance_i( a( i ) - b( j ) );
distance_sq += distance_i * distance_i;
}
return distance_sq;
}
// Distance Squared
template< typename T >
inline
T
distance_squared( Vector3< T > const & a, Array1< T > const & b )
{
return distance_squared( b, a );
}
// Distance Squared
template< typename T >
inline
T
distance_squared( Array1< T > const & a, Vector4< T > const & b )
{
assert( a.size() == 4u );
T distance_sq( T( 0 ) );
for ( int i = a.l(), j = b.l(), e = a.u(); i <= e; ++i, ++j ) {
T const distance_i( a( i ) - b( j ) );
distance_sq += distance_i * distance_i;
}
return distance_sq;
}
// Distance Squared
template< typename T >
inline
T
distance_squared( Vector4< T > const & a, Array1< T > const & b )
{
return distance_squared( b, a );
}
// Dot Product
template< typename T >
inline
T
dot( Array1< T > const & a, Array1< T > const & b )
{
assert( a.size() == b.size() );
T result( T( 0 ) );
for ( int i = a.l(), j = b.l(), e = a.u(); i <= e; ++i, ++j ) {
result += a( i ) * b( j );
}
return result;
}
// Dot Product
template< typename T >
inline
T
dot( Array1< T > const & a, Array1S< T > const & b )
{
assert( a.size() == b.size() );
T result( T( 0 ) );
for ( int i = a.l(), j = b.l(), e = a.u(); i <= e; ++i, ++j ) {
result += a( i ) * b( j );
}
return result;
}
// Dot Product
template< typename T >
inline
T
dot( Array1S< T > const & a, Array1< T > const & b )
{
return dot( b, a );
}
// Dot Product of Boolean Arrays
inline
bool
dot( Array1< bool > const & a, Array1< bool > const & b )
{
assert( a.size() == b.size() );
bool result( false );
for ( int i = a.l(), j = b.l(), e = a.u(); i <= e; ++i, ++j ) {
if ( a( i ) && b( j ) ) {
result = true;
break;
}
}
return result;
}
// Dot Product of Boolean Arrays
inline
bool
dot( Array1< bool > const & a, Array1S< bool > const & b )
{
assert( a.size() == b.size() );
bool result( false );
for ( int i = a.l(), j = b.l(), e = a.u(); i <= e; ++i, ++j ) {
if ( a( i ) && b( j ) ) {
result = true;
break;
}
}
return result;
}
// Dot Product of Boolean Arrays
inline
bool
dot( Array1S< bool > const & a, Array1< bool > const & b )
{
return dot( b, a );
}
// Dot Product with Vector2
template< typename T >
inline
T
dot( Array1< T > const & a, Vector2< T > const & b )
{
assert( a.size() == 2u );
T result( T( 0 ) );
for ( int i = 1, e = a.u(); i <= e; ++i ) {
result += a( i ) * b( i );
}
return result;
}
// Dot Product with Vector2
template< typename T >
inline
T
dot( Vector2< T > const & a, Array1< T > const & b )
{
return dot( b, a );
}
// Dot Product with Vector3
template< typename T >
inline
T
dot( Array1< T > const & a, Vector3< T > const & b )
{
assert( a.size() == 3u );
T result( T( 0 ) );
for ( int i = 1, e = a.u(); i <= e; ++i ) {
result += a( i ) * b( i );
}
return result;
}
// Dot Product with Vector3
template< typename T >
inline
T
dot( Vector3< T > const & a, Array1< T > const & b )
{
return dot( b, a );
}
// Dot Product with Vector4
template< typename T >
inline
T
dot( Array1< T > const & a, Vector4< T > const & b )
{
assert( a.size() == 4u );
T result( T( 0 ) );
for ( int i = 1, e = a.u(); i <= e; ++i ) {
result += a( i ) * b( i );
}
return result;
}
// Dot Product with Vector4
template< typename T >
inline
T
dot( Vector4< T > const & a, Array1< T > const & b )
{
return dot( b, a );
}
// Dot Product (Fortran Intrinsic Name)
template< typename T >
inline
T
dot_product( Array1< T > const & a, Array1< T > const & b )
{
return dot( a, b );
}
// Dot Product (Fortran Intrinsic Name)
template< typename T >
inline
T
dot_product( Array1< T > const & a, Array1S< T > const & b )
{
return dot( a, b );
}
// Dot Product (Fortran Intrinsic Name)
template< typename T >
inline
T
dot_product( Array1S< T > const & a, Array1< T > const & b )
{
return dot( a, b );
}
// Dot Product of Boolean Arrays (Fortran Intrinsic Name)
inline
bool
dot_product( Array1< bool > const & a, Array1< bool > const & b )
{
return dot( a, b );
}
// Dot Product of Boolean Arrays (Fortran Intrinsic Name)
inline
bool
dot_product( Array1< bool > const & a, Array1S< bool > const & b )
{
return dot( a, b );
}
// Dot Product of Boolean Arrays (Fortran Intrinsic Name)
inline
bool
dot_product( Array1S< bool > const & a, Array1< bool > const & b )
{
return dot( a, b );
}
// Cross Product of 2-Tuples
template< typename T >
inline
T
cross2( Vector2< T > const & a, Array1< T > const & b )
{
return cross2( b, a );
}
} // ObjexxFCL
#endif // ObjexxFCL_Array1_hh_INCLUDED
// ===== ObjexxFCL/Array1D.hh =====
#ifndef ObjexxFCL_Array1D_hh_INCLUDED
#define ObjexxFCL_Array1D_hh_INCLUDED
// Array1D: 1D Array
//
// Project: Objexx Fortran-C++ Library (ObjexxFCL)
//
// Version: 4.2.0
//
// Language: C++
//
// Copyright (c) 2000-2017 Objexx Engineering, Inc. All Rights Reserved.
// Use of this source code or any derivative of it is restricted by license.
// Licensing is available from Objexx Engineering, Inc.: http://objexx.com
// ObjexxFCL Headers
// C++ Headers
#include <functional>
namespace ObjexxFCL {
// Array1D: 1D Array
template< typename T >
class Array1D : public Array1< T >
{
private: // Types
typedef Array1< T > Super;
typedef internal::InitializerSentinel InitializerSentinel;
private: // Friend
template< typename > friend class Array1D;
friend class Array1A< T >;
public: // Types
typedef typename Super::Base Base;
typedef typename Super::Traits Traits;
typedef typename Super::IR IR;
// STL Style
typedef typename Super::value_type value_type;
typedef typename Super::reference reference;
typedef typename Super::const_reference const_reference;
typedef typename Super::pointer pointer;
typedef typename Super::const_pointer const_pointer;
typedef typename Super::iterator iterator;
typedef typename Super::const_iterator const_iterator;
typedef typename Super::reverse_iterator reverse_iterator;
typedef typename Super::const_reverse_iterator const_reverse_iterator;
typedef typename Super::size_type size_type;
typedef typename Super::difference_type difference_type;
// C++ Style
typedef typename Super::Value Value;
typedef typename Super::Reference Reference;
typedef typename Super::ConstReference ConstReference;
typedef typename Super::Pointer Pointer;
typedef typename Super::ConstPointer ConstPointer;
typedef typename Super::Iterator Iterator;
typedef typename Super::ConstIterator ConstIterator;
typedef typename Super::ReverseIterator ReverseIterator;
typedef typename Super::ConstReverseIterator ConstReverseIterator;
typedef typename Super::Size Size;
typedef typename Super::Difference Difference;
typedef std::function< void( Array1D< T > & ) > InitializerFunction;
using Super::conformable;
using Super::contains;
using Super::index;
using Super::isize1;
using Super::l;
using Super::operator ();
using Super::operator [];
using Super::size1;
using Super::u;
protected: // Types
using Super::assign;
using Super::clear_move;
using Super::initialize;
using Super::move_if;
using Super::move_or_copy;
using Super::move_or_copy_backward;
using Super::resize;
using Super::shift_set;
using Super::shift_only_set;
using Super::size_of;
using Super::swap1;
using Super::capacity_;
using Super::data_;
using Super::I_;
using Super::sdata_;
using Super::shift_;
using Super::size_;
public: // Creation
// Default Constructor
Array1D()
{
shift_ = 1; // For std::vector-like API
}
// Copy Constructor
Array1D( Array1D const & a ) :
Super( a )
{}
// Move Constructor
Array1D( Array1D && a ) noexcept :
Super( std::move( a ) )
{
}
// Copy Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
explicit
Array1D( Array1D< U > const & a ) :
Super( a )
{}
// Super Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
explicit
Array1D( Array1< U > const & a ) :
Super( a )
{}
// Slice Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
explicit
Array1D( Array1S< U > const & a ) :
Super( a )
{
setup_real();
size_type l( 0u );
for ( int i = 1, e = a.u(); i <= e; ++i, ++l ) {
initialize( l, a( i ) );
}
}
// MArray Constructor Template
template< class A, typename M >
explicit
Array1D( MArray1< A, M > const & a ) :
Super( a )
{
setup_real();
size_type l( 0u );
for ( int i = 1, e = a.u(); i <= e; ++i, ++l ) {
initialize( l, a( i ) );
}
}
// IndexRange Constructor
explicit
Array1D( IR const & I ) :
Super( I )
{
setup_real();
}
// IndexRange + Initializer Value Constructor
Array1D( IR const & I, T const & t ) :
Super( I, InitializerSentinel{} )
{
setup_real();
initialize( t );
}
// IndexRange + Initializer Function Constructor
Array1D( IR const & I, InitializerFunction const & fxn ) :
Super( I, InitializerSentinel{} )
{
setup_real();
initialize( fxn );
}
// IndexRange + Initializer List Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array1D( IR const & I, std::initializer_list< U > const l ) :
Super( I, l )
{
setup_real();
}
// IndexRange + Super Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array1D( IR const & I, Array1< U > const & a ) :
Super( I, InitializerSentinel{} )
{
assert( conformable( a ) );
setup_real();
initialize( a );
}
// IndexRange + Slice Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array1D( IR const & I, Array1S< U > const & a ) :
Super( I, InitializerSentinel{} )
{
assert( conformable( a ) );
setup_real();
size_type l( 0u );
for ( int i = 1, e = a.u(); i <= e; ++i, ++l ) {
initialize( l, a( i ) );
}
}
// Super + IndexRange Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array1D( Array1< U > const & a, IR const & I ) :
Super( I, InitializerSentinel{} )
{
assert( conformable( a ) );
setup_real();
initialize( a );
}
// IndexRange + Base Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array1D( IR const & I, Array< U > const & a ) :
Super( I, InitializerSentinel{} )
{
assert( size_ == a.size() );
setup_real();
initialize( a );
}
// Base + IndexRange Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array1D( Array< U > const & a, IR const & I ) :
Super( I, InitializerSentinel{} )
{
assert( size_ == a.size() );
setup_real();
initialize( a );
}
// Initializer List Index Range Constructor Template
template< typename U, class = typename std::enable_if< ! std::is_constructible< T, U >::value >::type >
explicit
Array1D( std::initializer_list< U > const l ) :
Super( IR( l ) )
{
assert( l.size() == 2 );
setup_real();
}
// Initializer List of Values Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value && ! ( std::is_same< U, int >::value || std::is_same< U, Index >::value ) >::type, typename = void >
Array1D( std::initializer_list< U > const l ) :
Super( l )
{
setup_real();
}
// Initializer List of Values or Index Range Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value && ( std::is_same< U, int >::value || std::is_same< U, Index >::value ) >::type, typename = void, typename = void >
Array1D( std::initializer_list< U > const l ) :
Super( l )
{ // Note: 2 item lists of index-like elements treated as index range: Others treated as values: See ObjexxFCL.Users.Array.html
#ifdef OBJEXXFCL_DISALLOW_AMBIGUOUS_INITIALIZER_LIST_CONSTRUCTORS
assert( l.size() != 2 ); // Avoid ambiguity with IndexRange {l,u} usage
#endif
if ( l.size() == 2 ) { // Treat as an IndexRange
I_ = l;
Base::reconstruct_by_size( size_of( I_ ) );
}
setup_real();
}
// Initializer List Index Range + Initializer Value Constructor Template
template< typename U >
Array1D( std::initializer_list< U > const l, T const & t ) :
Super( IR( l ), InitializerSentinel{} )
{
assert( l.size() == 2 );
setup_real();
initialize( t );
}
// Initializer List Index Range + Initializer Function Constructor Template
template< typename U >
Array1D( std::initializer_list< U > const l, InitializerFunction const & fxn ) :
Super( IR( l ), InitializerSentinel{} )
{
assert( l.size() == 2 );
setup_real();
initialize( fxn );
}
// Initializer List Index Range + Super Constructor Template
template< typename U, typename V, class = typename std::enable_if< std::is_constructible< T, V >::value >::type >
Array1D( std::initializer_list< U > const l, Array1< V > const & a ) :
Super( IR( l ), InitializerSentinel{} )
{
assert( l.size() == 2 );
assert( conformable( a ) );
setup_real();
initialize( a );
}
// Initializer List Index Range + Base Constructor Template
template< typename U, typename V, class = typename std::enable_if< std::is_constructible< T, V >::value >::type >
Array1D( std::initializer_list< U > const l, Array< V > const & a ) :
Super( IR( l ), InitializerSentinel{} )
{
assert( l.size() == 2 );
assert( size_ == a.size() );
setup_real();
initialize( a );
}
// std::array Constructor Template
template< typename U, Size s >
Array1D( std::array< U, s > const & a ) :
Super( a )
{
setup_real();
}
// std::vector Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array1D( std::vector< U > const & v ) :
Super( v )
{
setup_real();
}
// Vector2 Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array1D( Vector2< U > const & v ) :
Super( v )
{
setup_real();
}
// Vector3 Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array1D( Vector3< U > const & v ) :
Super( v )
{
setup_real();
}
// Vector4 Constructor Template
template< typename U, class = typename std::enable_if< std::is_constructible< T, U >::value >::type >
Array1D( Vector4< U > const & v ) :
Super( v )
{
setup_real();
}
// Iterator Range Constructor Template
template< class Iterator, typename = decltype( *std::declval< Iterator & >(), void(), ++std::declval< Iterator & >(), void() ) >
Array1D( Iterator const beg, Iterator const end ) :
Super( beg, end )
{
setup_real();
}
// Array Range Named Constructor Template
template< typename U >
static
Array1D
range( Array1< U > const & a )
{
return Array1D( a.I() );
}
// Array Range + Initializer Value Named Constructor Template
template< typename U >
static
Array1D
range( Array1< U > const & a, T const & t )
{
return Array1D( a.I(), t );
}
// Array Shape Named Constructor Template
template< typename U >
static
Array1D
shape( Array1< U > const & a )
{
return Array1D( a.isize() );
}
// Array Shape + Initializer Value Named Constructor Template
template< typename U >
static
Array1D
shape( Array1< U > const & a, T const & t )
{
return Array1D( a.isize(), t );
}
// Slice Shape Named Constructor Template
template< typename U >
static
Array1D
shape( Array1S< U > const & a )
{
return Array1D( a.isize() );
}
// Slice Shape + Initializer Value Named Constructor Template
template< typename U >
static
Array1D
shape( Array1S< U > const & a, T const & t )
{
return Array1D( a.isize(), t );
}
// One-Based Copy Named Constructor Template
template< typename U >
static
Array1D
one_based( Array1< U > const & a )
{
return Array1D( a.isize(), a );
}
// One-Based Slice Named Constructor Template
template< typename U >
static
Array1D
one_based( Array1S< U > const & a )
{
return Array1D( a.isize(), a );
}
// Initializer List One-Based Named Constructor Template
template< typename U >
static
Array1D
one_based( std::initializer_list< U > const l )
{
return Array1D( static_cast< int >( l.size() ), l );
}
// Destructor
virtual
~Array1D() = default;
private: // Creation
// IndexRange Raw Constructor
explicit
Array1D( IR const & I, InitializerSentinel initialized ) :
Super( I, initialized )
{
setup_real();
}
public: // Assignment: Array
// Copy Assignment
Array1D &
operator =( Array1D const & a )
{
if ( this != &a ) {
if ( ( conformable( a ) ) || ( ! size_real( a.I_ ) ) ) {
Base::operator =( a );
} else {
Base::initialize( a );
}
}
return *this;
}
// Move Assignment
Array1D &
operator =( Array1D && a ) noexcept
{
if ( conformable( a ) ) {
Base::conformable_move( a );
} else {
Base::operator =( std::move( a ) );
I_ = a.I_;
}
a.clear_move();
return *this;
}
// Super Assignment
Array1D &
operator =( Super const & a )
{
if ( this != &a ) {
if ( ( conformable( a ) ) || ( ! size_real( a.I_ ) ) ) {
Base::operator =( a );
} else {
Base::initialize( a );
}
}
return *this;
}
// Super Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator =( Array1< U > const & a )
{
if ( ( conformable( a ) ) || ( ! size_real( a.I_ ) ) ) {
Base::operator =( a );
} else {
Base::initialize( a );
}
return *this;
}
// Slice Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator =( Array1S< U > const & a )
{
Super::operator =( a );
return *this;
}
// Initializer List Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator =( std::initializer_list< U > const l )
{
Base::operator =( l );
return *this;
}
// std::array Assignment Template
template< typename U, Size s, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator =( std::array< U, s > const & a )
{
Base::operator =( a );
return *this;
}
// std::vector Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator =( std::vector< U > const & v )
{
Base::operator =( v );
return *this;
}
// Vector2 Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator =( Vector2< U > const & v )
{
Base::operator =( v );
return *this;
}
// Vector3 Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator =( Vector3< U > const & v )
{
Base::operator =( v );
return *this;
}
// Vector4 Assignment Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator =( Vector4< U > const & v )
{
Base::operator =( v );
return *this;
}
// += Array Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator +=( Array1< U > const & a )
{
Super::operator +=( a );
return *this;
}
// -= Array Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator -=( Array1< U > const & a )
{
Super::operator -=( a );
return *this;
}
// *= Array Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator *=( Array1< U > const & a )
{
Super::operator *=( a );
return *this;
}
// /= Array Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator /=( Array1< U > const & a )
{
Super::operator /=( a );
return *this;
}
// += Slice Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator +=( Array1S< U > const & a )
{
Super::operator +=( a );
return *this;
}
// -= Slice Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator -=( Array1S< U > const & a )
{
Super::operator -=( a );
return *this;
}
// *= Slice Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator *=( Array1S< U > const & a )
{
Super::operator *=( a );
return *this;
}
// /= Slice Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator /=( Array1S< U > const & a )
{
Super::operator /=( a );
return *this;
}
// += Initializer List Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator +=( std::initializer_list< U > const l )
{
Base::operator +=( l );
return *this;
}
// -= Initializer List Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator -=( std::initializer_list< U > const l )
{
Base::operator -=( l );
return *this;
}
// *= Initializer List Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator *=( std::initializer_list< U > const l )
{
Base::operator *=( l );
return *this;
}
// /= Initializer List Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator /=( std::initializer_list< U > const l )
{
Base::operator /=( l );
return *this;
}
// += std::array Template
template< typename U, Size s, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator +=( std::array< U, s > const & a )
{
Base::operator +=( a );
return *this;
}
// -= std::array Template
template< typename U, Size s, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator -=( std::array< U, s > const & a )
{
Base::operator -=( a );
return *this;
}
// *= std::array Template
template< typename U, Size s, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator *=( std::array< U, s > const & a )
{
Base::operator *=( a );
return *this;
}
// /= std::array Template
template< typename U, Size s, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator /=( std::array< U, s > const & a )
{
Base::operator /=( a );
return *this;
}
// += std::vector Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator +=( std::vector< U > const & v )
{
Base::operator +=( v );
return *this;
}
// -= std::vector Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator -=( std::vector< U > const & v )
{
Base::operator -=( v );
return *this;
}
// *= std::vector Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator *=( std::vector< U > const & v )
{
Base::operator *=( v );
return *this;
}
// /= std::vector Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator /=( std::vector< U > const & v )
{
Base::operator /=( v );
return *this;
}
// += Vector2 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator +=( Vector2< U > const & v )
{
Base::operator +=( v );
return *this;
}
// -= Vector2 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator -=( Vector2< U > const & v )
{
Base::operator -=( v );
return *this;
}
// *= Vector2 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator *=( Vector2< U > const & v )
{
Base::operator *=( v );
return *this;
}
// /= Vector2 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator /=( Vector2< U > const & v )
{
Base::operator /=( v );
return *this;
}
// += Vector3 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator +=( Vector3< U > const & v )
{
Base::operator +=( v );
return *this;
}
// -= Vector3 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator -=( Vector3< U > const & v )
{
Base::operator -=( v );
return *this;
}
// *= Vector3 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator *=( Vector3< U > const & v )
{
Base::operator *=( v );
return *this;
}
// /= Vector3 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator /=( Vector3< U > const & v )
{
Base::operator /=( v );
return *this;
}
// += Vector4 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator +=( Vector4< U > const & v )
{
Base::operator +=( v );
return *this;
}
// -= Vector4 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator -=( Vector4< U > const & v )
{
Base::operator -=( v );
return *this;
}
// *= Vector4 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator *=( Vector4< U > const & v )
{
Base::operator *=( v );
return *this;
}
// /= Vector4 Template
template< typename U, class = typename std::enable_if< std::is_assignable< T&, U >::value >::type >
Array1D &
operator /=( Vector4< U > const & v )
{
Base::operator /=( v );
return *this;
}
public: // Assignment: Value
// = Value
Array1D &
operator =( T const & t )
{
Base::operator =( t );
return *this;
}
// += Value
Array1D &
operator +=( T const & t )
{
Base::operator +=( t );
return *this;
}
// -= Value
Array1D &
operator -=( T const & t )
{
Base::operator -=( t );
return *this;
}
// *= Value
Array1D &
operator *=( T const & t )
{
Base::operator *=( t );
return *this;
}
// /= Value
Array1D &
operator /=( T const & t )
{
Base::operator /=( t );
return *this;
}
public: // Modifier
// Clear
Array1D &
clear()
{
Super::clear();
return *this;
}
// Dimension by IndexRange
Array1D &
allocate( IR const & I )
{
dimension_real( I );
return *this;
}
// Dimension by Array Template
template< typename U >
Array1D &
allocate( Array1< U > const & a )
{
dimension_real( a.I_ );
return *this;
}
// Deallocate
Array1D &
deallocate()
{
Super::clear();
return *this;
}
// Dimension by IndexRange
Array1D &
dimension( IR const & I )
{
dimension_real( I );
return *this;
}
// Dimension by IndexRange + Initializer Value
Array1D &
dimension( IR const & I, T const & t )
{
dimension_real( I, t );
return *this;
}
// Dimension by IndexRange + Initializer Function
Array1D &
dimension( IR const & I, InitializerFunction const & fxn )
{
dimension_real( I, fxn );
return *this;
}
// Dimension by Array Template
template< typename U >
Array1D &
dimension( Array1< U > const & a )
{
dimension_real( a.I_ );
return *this;
}
// Dimension by Array + Initializer Value Template
template< typename U >
Array1D &
dimension( Array1< U > const & a, T const & t )
{
dimension_real( a.I_, t );
return *this;
}
// Dimension by Array + Initializer Function Template
template< typename U >
Array1D &
dimension( Array1< U > const & a, InitializerFunction const & fxn )
{
dimension_real( a.I_, fxn );
return *this;
}
// Data-Preserving Redimension by IndexRange
Array1D &
redimension( IR const & I )
{
if ( size_ == 0u ) { // No data
return dimension( I );
} else if ( I.size() <= capacity_ ) { // Use existing capacity
size_type const new_size( I.size() );
if ( new_size > size_ ) { // Initialize new tail elements
#if defined(OBJEXXFCL_ARRAY_INIT) || defined(OBJEXXFCL_ARRAY_INIT_DEBUG)
T const fill( Traits::initial_array_value() );
#endif
for ( size_type i = size_; i < new_size; ++i ) {
#if defined(OBJEXXFCL_ARRAY_INIT) || defined(OBJEXXFCL_ARRAY_INIT_DEBUG)
new ( data_ + i ) T( fill );
#else
new ( data_ + i ) T;
#endif
}
}
std::ptrdiff_t const off( I_.l() - I.l() );
if ( off > 0 ) { // Move elements up
size_type const offu( off );
size_type const stop( offu < new_size ? std::min( size_, new_size - offu ) : 0u );
move_or_copy_backward( data_, data_ + stop, data_ + stop + off );
} else if ( off < 0 ) { // Move elements down
size_type const offu( -off );
size_type const stop( offu < size_ ? std::min( size_, new_size + offu ) : 0u );
if ( offu < stop ) move_or_copy( data_ + offu, data_ + stop, data_ );
}
if ( new_size < size_ ) { // Destruct removed tail elements
for ( size_type i = new_size; i < size_; ++i ) {
data_[ i ].~T();
}
}
I_ = I;
shift_set( I_.l() );
size_ = new_size;
return *this;
} else { // Allocate new space
Array1D o( I, InitializerSentinel{} );
auto const l_( l() );
auto const I_l_( I.l() );
auto const l_max_( std::max( l_, I_l_ ) );
auto const u_( u() );
auto const I_u_( I.u() );
auto const u_min_( std::min( u_, I_u_ ) );
if ( I_l_ < l_ ) { // Initialize new lower elements
#if defined(OBJEXXFCL_ARRAY_INIT) || defined(OBJEXXFCL_ARRAY_INIT_DEBUG)
T const fill( Traits::initial_array_value() );
#endif
for ( int i = I_l_, e = std::min( l_ - 1, I_u_ ); i <= e; ++i ) {
#if defined(OBJEXXFCL_ARRAY_INIT) || defined(OBJEXXFCL_ARRAY_INIT_DEBUG)
new ( &o( i ) ) T( fill );
#else
new ( &o( i ) ) T;
#endif
}
}
if ( l_max_ <= u_min_ ) { // Ranges overlap
for ( int i = l_max_; i <= u_min_; ++i ) {
new ( &o( i ) ) T( move_if( operator ()( i ) ) );
}
}
if ( u_ < I_u_ ) { // Initialize new upper elements
#if defined(OBJEXXFCL_ARRAY_INIT) || defined(OBJEXXFCL_ARRAY_INIT_DEBUG)
T const fill( Traits::initial_array_value() );
#endif
for ( int i = std::max( u_ + 1, I_l_ ); i <= I_u_; ++i ) {
#if defined(OBJEXXFCL_ARRAY_INIT) || defined(OBJEXXFCL_ARRAY_INIT_DEBUG)
new ( &o( i ) ) T( fill );
#else
new ( &o( i ) ) T;
#endif
}
}
swap1( o );
return *this;
}
}
// Data-Preserving Redimension by IndexRange + Fill Value
Array1D &
redimension( IR const & I, T const & t )
{
if ( size_ == 0u ) { // No data
return dimension( I, t );
} else if ( I.size() <= capacity_ ) { // Use existing capacity
size_type const new_size( I.size() );
if ( new_size > size_ ) { // Initialize new tail elements
for ( size_type i = size_; i < new_size; ++i ) {
new ( data_ + i ) T( t );
}
}
std::ptrdiff_t const off( I_.l() - I.l() );
if ( off > 0 ) { // Move elements up
size_type const offu( off );
size_type const stop( offu < new_size ? std::min( size_, new_size - offu ) : 0u );
move_or_copy_backward( data_, data_ + stop, data_ + stop + off );
std::fill_n( data_, std::min( offu, std::min( size_, new_size ) ), t );
} else if ( off < 0 ) { // Move elements down
size_type const offu( -off );
size_type const stop( offu < size_ ? std::min( size_, new_size + offu ) : 0u );
if ( offu < stop ) {
move_or_copy( data_ + offu, data_ + stop, data_ );
std::fill_n( data_ + ( stop - offu ), std::min( size_, new_size ) - ( stop - offu ), t );
} else {
std::fill_n( data_, std::min( size_, new_size ), t );
}
}
if ( new_size < size_ ) { // Destruct removed tail elements
for ( size_type i = new_size; i < size_; ++i ) {
data_[ i ].~T();
}
}
I_ = I;
shift_set( I_.l() );
size_ = new_size;
return *this;
} else { // Allocate new space
Array1D o( I, InitializerSentinel{} );
auto const l_( l() );
auto const I_l_( I.l() );
auto const l_max_( std::max( l_, I_l_ ) );
auto const u_( u() );
auto const I_u_( I.u() );
auto const u_min_( std::min( u_, I_u_ ) );
if ( I_l_ < l_ ) { // Fill new lower elements
for ( int i = I_l_, e = std::min( l_ - 1, I_u_ ); i <= e; ++i ) {
new ( &o( i ) ) T( t );
}
}
if ( l_max_ <= u_min_ ) { // Ranges overlap
for ( int i = l_max_; i <= u_min_; ++i ) {
new ( &o( i ) ) T( move_if( operator ()( i ) ) );
}
}
if ( u_ < I_u_ ) { // Fill new upper elements
for ( int i = std::max( u_ + 1, I_l_ ); i <= I_u_; ++i ) {
new ( &o( i ) ) T( t );
}
}
swap1( o );
return *this;
}
}
// Data-Preserving Redimension by Array Template
template< typename U >
Array1D &
redimension( Array1< U > const & a )
{
return redimension( a.I_ );
}
// Data-Preserving Redimension by Array + Fill Value Template
template< typename U >
Array1D &
redimension( Array1< U > const & a, T const & t )
{
return redimension( a.I_, t );
}
// Append Value: Grow by 1
Array1D &
append( T const & t )
{
if ( capacity_ == size_ ) { // Grow by 1
Array1D o( IndexRange( l(), u() + 1 ), InitializerSentinel{} );
for ( int i = l(), e = u(); i <= e; ++i ) {
new ( &o( i ) ) T( move_if( operator ()( i ) ) );
}
swap1( o );
new ( data_ + size_ - 1 ) T( t );
} else {
I_.grow();
++size_;
operator ()( u() ) = t;
}
return *this;
}
// Append Value: Grow by 1
template< typename U = T, class = typename std::enable_if< std::is_move_assignable< U >::value >::type >
Array1D &
append( T && t )
{
if ( capacity_ == size_ ) { // Grow by 1
Array1D o( IndexRange( l(), u() + 1 ), InitializerSentinel{} );
for ( int i = l(), e = u(); i <= e; ++i ) {
new ( &o( i ) ) T( std::move( operator ()( i ) ) );
}
swap1( o );
new ( data_ + size_ - 1 ) T( std::move( t ) );
} else {
I_.grow();
++size_;
operator ()( u() ) = std::move( t );
}
return *this;
}
// Swap
Array1D &
swap( Array1D & v )
{
using std::swap;
swap1( v );
return *this;
}
public: // std::vector-like API
// First Value
T const &
front() const
{
assert( size_ > 0u );
return operator []( 0u );
}
// First Value
T &
front()
{
assert( size_ > 0u );
return operator []( 0u );
}
// Last Value
T const &
back() const
{
assert( size_ > 0u );
return operator []( size_ - 1 );
}
// Last Value
T &
back()
{
assert( size_ > 0u );
return operator []( size_ - 1 );
}
// Append Value by Copy
Array1D &
push_back( T const & t )
{
I_.grow();
Base::do_push_back_copy( t );
return *this;
}
// Append Value by Move
template< typename U = T, class = typename std::enable_if< std::is_move_assignable< U >::value >::type >
Array1D &
push_back( T && t )
{
I_.grow();
Base::do_push_back_move( std::move( t ) );
return *this;
}
// Remove Last Value
Array1D &
pop_back()
{
if ( size_ > 0u ) {
I_.shrink();
Base::do_pop_back();
}
return *this;
}
// Insert Value by Copy
iterator
insert( const_iterator pos, T const & t )
{
I_.grow();
return Base::do_insert_copy( pos, t );
}
// Insert Value by Move
template< typename U = T, class = typename std::enable_if< std::is_move_assignable< U >::value >::type >
iterator
insert( const_iterator pos, T && t )
{
I_.grow();
return Base::do_insert_move( pos, std::move( t ) );
}
// Insert Multiple Copies of a Value
iterator
insert( const_iterator pos, size_type n, T const & t )
{
I_.grow( static_cast< int >( n ) );
return Base::do_insert_n( pos, n, t );
}
// Insert Iterator Range
template< typename Iterator, class = typename std::enable_if<
std::is_same< typename std::iterator_traits< Iterator >::iterator_category, std::input_iterator_tag >::value ||
std::is_same< typename std::iterator_traits< Iterator >::iterator_category, std::forward_iterator_tag >::value ||
std::is_same< typename std::iterator_traits< Iterator >::iterator_category, std::bidirectional_iterator_tag >::value ||
std::is_same< typename std::iterator_traits< Iterator >::iterator_category, std::random_access_iterator_tag >::value
>::type >
iterator
insert( const_iterator pos, Iterator first, Iterator last )
{
I_.grow( static_cast< int >( std::distance( first, last ) ) );
return Base::do_insert_iterator( pos, first, last );
}
// Insert Initializer List
iterator
insert( const_iterator pos, std::initializer_list< T > il )
{
I_.grow( static_cast< int >( il.size() ) );
return Base::do_insert_initializer_list( pos, il );
}
// Insert Value Constructed in Place
template< typename... Args >
iterator
emplace( const_iterator pos, Args &&... args )
{
I_.grow();
return Base::do_emplace( pos, std::forward< Args >( args )... );
}
// Append Value Constructed in Place
template< typename... Args >
Array1D &
emplace_back( Args &&... args )
{
I_.grow();
Base::do_emplace_back( std::forward< Args >( args )... );
return *this;
}
// Erase Iterator
iterator
erase( const_iterator pos )
{
I_.shrink();
return Base::do_erase( pos );
}
// Erase Iterator Range
iterator
erase( const_iterator first, const_iterator last )
{
I_.shrink( static_cast< int >( std::distance( first, last ) ) );
return Base::do_erase_iterator( first, last );
}
// Reserve Capacity
Array1D &
reserve( size_type const n )
{
Base::reserve_capacity( n );
return *this;
}
protected: // Functions
// Dimension by IndexRange
bool
dimension_assign( IR const & I )
{
return size_real( I );
}
// Initialize to Default State
void
initialize()
{
#if defined(OBJEXXFCL_ARRAY_INIT) || defined(OBJEXXFCL_ARRAY_INIT_DEBUG)
std::uninitialized_fill_n( data_, size_, Traits::initial_array_value() );
#else
for ( size_type i = 0; i < size_; ++i ) {
new ( data_ + i ) T;
}
#endif
}
// Initialize by Function
void
initialize( InitializerFunction const & fxn )
{
initialize();
fxn( *this );
}
// Assignment to Default State
void
assign()
{
#if defined(OBJEXXFCL_ARRAY_INIT) || defined(OBJEXXFCL_ARRAY_INIT_DEBUG)
std::fill_n( data_, size_, Traits::initial_array_value() );
#endif
}
private: // Functions
// Set Up for IndexRange Constructor
void
setup_real()
{
shift_set( I_.l() );
}
// Size by IndexRange
bool
size_real( IR const & I )
{
I_.assign( I );
shift_only_set( I_.l() );
return resize( size_of( I_ ) );
}
// Dimension by IndexRange
void
dimension_real( IR const & I )
{
if ( size_real( I ) ) {
initialize();
} else {
#if defined(OBJEXXFCL_ARRAY_INIT) || defined(OBJEXXFCL_ARRAY_INIT_DEBUG)
assign();
#endif
}
}
// Dimension by IndexRange + Initializer Value
void
dimension_real( IR const & I, T const & t )
{
if ( size_real( I ) ) {
initialize( t );
} else {
assign( t );
}
}
// Dimension by IndexRange + Initializer Function
void
dimension_real( IR const & I, InitializerFunction const & fxn )
{
if ( size_real( I ) ) initialize();
fxn( *this );
}
}; // Array1D
// Swap
template< typename T >
inline
void
swap( Array1D< T > & a, Array1D< T > & b )
{
a.swap( b );
}
// Comparison: Elemental
// Array == Array
template< typename T >
inline
Array1D< bool >
operator ==( Array1< T > const & a, Array1< T > const & b )
{
assert( conformable( a, b ) );
Array1D< bool > r( Array1D< bool >::shape( a ) );
eq_elemental( a, b, r );
return r;
}
// Array != Array
template< typename T >
inline
Array1D< bool >
operator !=( Array1< T > const & a, Array1< T > const & b )
{
assert( conformable( a, b ) );
Array1D< bool > r( Array1D< bool >::shape( a ) );
ne_elemental( a, b, r );
return r;
}
// Array < Array
template< typename T >
inline
Array1D< bool >
operator <( Array1< T > const & a, Array1< T > const & b )
{
assert( conformable( a, b ) );
Array1D< bool > r( Array1D< bool >::shape( a ) );
lt_elemental( a, b, r );
return r;
}
// Array <= Array
template< typename T >
inline
Array1D< bool >
operator <=( Array1< T > const & a, Array1< T > const & b )
{
assert( conformable( a, b ) );
Array1D< bool > r( Array1D< bool >::shape( a ) );
le_elemental( a, b, r );
return r;
}
// Array > Array
template< typename T >
inline
Array1D< bool >
operator >( Array1< T > const & a, Array1< T > const & b )
{
assert( conformable( a, b ) );
Array1D< bool > r( Array1D< bool >::shape( a ) );
gt_elemental( a, b, r );
return r;
}
// Array >= Array
template< typename T >
inline
Array1D< bool >
operator >=( Array1< T > const & a, Array1< T > const & b )
{
assert( conformable( a, b ) );
Array1D< bool > r( Array1D< bool >::shape( a ) );
ge_elemental( a, b, r );
return r;
}
// Array == Value
template< typename T >
inline
Array1D< bool >
operator ==( Array1< T > const & a, T const & t )
{
Array1D< bool > r( Array1D< bool >::shape( a ) );
eq_elemental( a, t, r );
return r;
}
// Array != Value
template< typename T >
inline
Array1D< bool >
operator !=( Array1< T > const & a, T const & t )
{
Array1D< bool > r( Array1D< bool >::shape( a ) );
ne_elemental( a, t, r );
return r;
}
// Array < Value
template< typename T >
inline
Array1D< bool >
operator <( Array1< T > const & a, T const & t )
{
Array1D< bool > r( Array1D< bool >::shape( a ) );
lt_elemental( a, t, r );
return r;
}
// Array <= Value
template< typename T >
inline
Array1D< bool >
operator <=( Array1< T > const & a, T const & t )
{
Array1D< bool > r( Array1D< bool >::shape( a ) );
le_elemental( a, t, r );
return r;
}
// Array > Value
template< typename T >
inline
Array1D< bool >
operator >( Array1< T > const & a, T const & t )
{
Array1D< bool > r( Array1D< bool >::shape( a ) );
gt_elemental( a, t, r );
return r;
}
// Array >= Value
template< typename T >
inline
Array1D< bool >
operator >=( Array1< T > const & a, T const & t )
{
Array1D< bool > r( Array1D< bool >::shape( a ) );
ge_elemental( a, t, r );
return r;
}
// Value == Array
template< typename T >
inline
Array1D< bool >
operator ==( T const & t, Array1< T > const & b )
{
return ( b == t );
}
// Value != Array
template< typename T >
inline
Array1D< bool >
operator !=( T const & t, Array1< T > const & b )
{
return ( b != t );
}
// Value < Array
template< typename T >
inline
Array1D< bool >
operator <( T const & t, Array1< T > const & b )
{
return ( b > t );
}
// Value <= Array
template< typename T >
inline
Array1D< bool >
operator <=( T const & t, Array1< T > const & b )
{
return ( b >= t );
}
// Value > Array
template< typename T >
inline
Array1D< bool >
operator >( T const & t, Array1< T > const & b )
{
return ( b < t );
}
// Value >= Array
template< typename T >
inline
Array1D< bool >
operator >=( T const & t, Array1< T > const & b )
{
return ( b <= t );
}
// Comparison: Elemental: Slice
// Slice == Slice
template< typename T >
inline
Array1D< bool >
operator ==( Array1S< T > const & a, Array1S< T > const & b )
{
assert( conformable( a, b ) );
Array1D< bool > r( Array1D< bool >::shape( a ) );
for ( int i = 1, e = r.u(); i <= e; ++i ) {
r( i ) = ( a( i ) == b( i ) );
}
return r;
}
// Slice != Slice
template< typename T >
inline
Array1D< bool >
operator !=( Array1S< T > const & a, Array1S< T > const & b )
{
assert( conformable( a, b ) );
Array1D< bool > r( Array1D< bool >::shape( a ) );
for ( int i = 1, e = r.u(); i <= e; ++i ) {
r( i ) = ( a( i ) != b( i ) );
}
return r;
}
// Slice < Slice
template< typename T >
inline
Array1D< bool >
operator <( Array1S< T > const & a, Array1S< T > const & b )
{
assert( conformable( a, b ) );
Array1D< bool > r( Array1D< bool >::shape( a ) );
for ( int i = 1, e = r.u(); i <= e; ++i ) {
r( i ) = ( a( i ) < b( i ) );
}
return r;
}
// Slice <= Slice
template< typename T >
inline
Array1D< bool >
operator <=( Array1S< T > const & a, Array1S< T > const & b )
{
assert( conformable( a, b ) );
Array1D< bool > r( Array1D< bool >::shape( a ) );
for ( int i = 1, e = r.u(); i <= e; ++i ) {
r( i ) = ( a( i ) <= b( i ) );
}
return r;
}
// Slice > Slice
template< typename T >
inline
Array1D< bool >
operator >( Array1S< T > const & a, Array1S< T > const & b )
{
assert( conformable( a, b ) );
Array1D< bool > r( Array1D< bool >::shape( a ) );
for ( int i = 1, e = r.u(); i <= e; ++i ) {
r( i ) = ( a( i ) > b( i ) );
}
return r;
}
// Slice >= Slice
template< typename T >
inline
Array1D< bool >
operator >=( Array1S< T > const & a, Array1S< T > const & b )
{
assert( conformable( a, b ) );
Array1D< bool > r( Array1D< bool >::shape( a ) );
for ( int i = 1, e = r.u(); i <= e; ++i ) {
r( i ) = ( a( i ) >= b( i ) );
}
return r;
}
// Slice == Array
template< typename T >
inline
Array1D< bool >
operator ==( Array1S< T > const & a, Array1< T > const & b )
{
assert( conformable( a, b ) );
Array1D< bool > r( Array1D< bool >::shape( a ) );
BArray::size_type l( 0u );
for ( int i = 1, e = r.u(); i <= e; ++i, ++l ) {
r( i ) = ( a( i ) == b[ l ] );
}
return r;
}
// Slice != Array
template< typename T >
inline
Array1D< bool >
operator !=( Array1S< T > const & a, Array1< T > const & b )
{
assert( conformable( a, b ) );
Array1D< bool > r( Array1D< bool >::shape( a ) );
BArray::size_type l( 0u );
for ( int i = 1, e = r.u(); i <= e; ++i, ++l ) {
r( i ) = ( a( i ) != b[ l ] );
}
return r;
}
// Slice < Array
template< typename T >
inline
Array1D< bool >
operator <( Array1S< T > const & a, Array1< T > const & b )
{
assert( conformable( a, b ) );
Array1D< bool > r( Array1D< bool >::shape( a ) );
BArray::size_type l( 0u );
for ( int i = 1, e = r.u(); i <= e; ++i, ++l ) {
r( i ) = ( a( i ) < b[ l ] );
}
return r;
}
// Slice <= Array
template< typename T >
inline
Array1D< bool >
operator <=( Array1S< T > const & a, Array1< T > const & b )
{
assert( conformable( a, b ) );
Array1D< bool > r( Array1D< bool >::shape( a ) );
BArray::size_type l( 0u );
for ( int i = 1, e = r.u(); i <= e; ++i, ++l ) {
r( i ) = ( a( i ) <= b[ l ] );
}
return r;
}
// Slice > Array
template< typename T >
inline
Array1D< bool >
operator >( Array1S< T > const & a, Array1< T > const & b )
{
assert( conformable( a, b ) );
Array1D< bool > r( Array1D< bool >::shape( a ) );
BArray::size_type l( 0u );
for ( int i = 1, e = r.u(); i <= e; ++i, ++l ) {
r( i ) = ( a( i ) > b[ l ] );
}
return r;
}
// Slice >= Array
template< typename T >
inline
Array1D< bool >
operator >=( Array1S< T > const & a, Array1< T > const & b )
{
assert( conformable( a, b ) );
Array1D< bool > r( Array1D< bool >::shape( a ) );
BArray::size_type l( 0u );
for ( int i = 1, e = r.u(); i <= e; ++i, ++l ) {
r( i ) = ( a( i ) >= b[ l ] );
}
return r;
}
// Array == Slice
template< typename T >
inline
Array1D< bool >
operator ==( Array1< T > const & a, Array1S< T > const & b )
{
return ( b == a );
}
// Array != Slice
template< typename T >
inline
Array1D< bool >
operator !=( Array1< T > const & a, Array1S< T > const & b )
{
return ( b != a );
}
// Array < Slice
template< typename T >
inline
Array1D< bool >
operator <( Array1< T > const & a, Array1S< T > const & b )
{
return ( b > a );
}
// Array <= Slice
template< typename T >
inline
Array1D< bool >
operator <=( Array1< T > const & a, Array1S< T > const & b )
{
return ( b >= a );
}
// Array > Slice
template< typename T >
inline
Array1D< bool >
operator >( Array1< T > const & a, Array1S< T > const & b )
{
return ( b < a );
}
// Array >= Slice
template< typename T >
inline
Array1D< bool >
operator >=( Array1< T > const & a, Array1S< T > const & b )
{
return ( b <= a );
}
// Slice == Value
template< typename T >
inline
Array1D< bool >
operator ==( Array1S< T > const & a, T const & t )
{
Array1D< bool > r( Array1D< bool >::shape( a ) );
for ( int i = 1, e = r.u(); i <= e; ++i ) {
r( i ) = ( a( i ) == t );
}
return r;
}
// Slice != Value
template< typename T >
inline
Array1D< bool >
operator !=( Array1S< T > const & a, T const & t )
{
Array1D< bool > r( Array1D< bool >::shape( a ) );
for ( int i = 1, e = r.u(); i <= e; ++i ) {
r( i ) = ( a( i ) != t );
}
return r;
}
// Slice < Value
template< typename T >
inline
Array1D< bool >
operator <( Array1S< T > const & a, T const & t )
{
Array1D< bool > r( Array1D< bool >::shape( a ) );
for ( int i = 1, e = r.u(); i <= e; ++i ) {
r( i ) = ( a( i ) < t );
}
return r;
}
// Slice <= Value
template< typename T >
inline
Array1D< bool >
operator <=( Array1S< T > const & a, T const & t )
{
Array1D< bool > r( Array1D< bool >::shape( a ) );
for ( int i = 1, e = r.u(); i <= e; ++i ) {
r( i ) = ( a( i ) <= t );
}
return r;
}
// Slice > Value
template< typename T >
inline
Array1D< bool >
operator >( Array1S< T > const & a, T const & t )
{
Array1D< bool > r( Array1D< bool >::shape( a ) );
for ( int i = 1, e = r.u(); i <= e; ++i ) {
r( i ) = ( a( i ) > t );
}
return r;
}
// Slice >= Value
template< typename T >
inline
Array1D< bool >
operator >=( Array1S< T > const & a, T const & t )
{
Array1D< bool > r( Array1D< bool >::shape( a ) );
for ( int i = 1, e = r.u(); i <= e; ++i ) {
r( i ) = ( a( i ) >= t );
}
return r;
}
// Value == Slice
template< typename T >
inline
Array1D< bool >
operator ==( T const & t, Array1S< T > const & b )
{
return ( b == t );
}
// Value != Slice
template< typename T >
inline
Array1D< bool >
operator !=( T const & t, Array1S< T > const & b )
{
return ( b != t );
}
// Value < Slice
template< typename T >
inline
Array1D< bool >
operator <( T const & t, Array1S< T > const & b )
{
return ( b > t );
}
// Value <= Slice
template< typename T >
inline
Array1D< bool >
operator <=( T const & t, Array1S< T > const & b )
{
return ( b >= t );
}
// Value > Slice
template< typename T >
inline
Array1D< bool >
operator >( T const & t, Array1S< T > const & b )
{
return ( b < t );
}
// Value >= Slice
template< typename T >
inline
Array1D< bool >
operator >=( T const & t, Array1S< T > const & b )
{
return ( b <= t );
}
// Generator
// -Array
template< typename T >
inline
Array1D< T >
operator -( Array1< T > const & a )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r *= T( -1 );
return r;
}
// Array + Array
template< typename T >
inline
Array1D< T >
operator +( Array1< T > const & a, Array1< T > const & b )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r += b;
return r;
}
// Array - Array
template< typename T >
inline
Array1D< T >
operator -( Array1< T > const & a, Array1< T > const & b )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r -= b;
return r;
}
// Array * Array
template< typename T >
inline
Array1D< T >
operator *( Array1< T > const & a, Array1< T > const & b )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r *= b;
return r;
}
// Array / Array
template< typename T >
inline
Array1D< T >
operator /( Array1< T > const & a, Array1< T > const & b )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r /= b;
return r;
}
// Array + Value
template< typename T >
inline
Array1D< T >
operator +( Array1< T > const & a, T const & t )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r += t;
return r;
}
// Value + Array
template< typename T >
inline
Array1D< T >
operator +( T const & t, Array1< T > const & a )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r += t;
return r;
}
// Array - Value
template< typename T >
inline
Array1D< T >
operator -( Array1< T > const & a, T const & t )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r -= t;
return r;
}
// Value - Array
template< typename T >
inline
Array1D< T >
operator -( T const & t, Array1< T > const & a )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r *= T( -1 );
r += t;
return r;
}
// Array * Value
template< typename T >
inline
Array1D< T >
operator *( Array1< T > const & a, T const & t )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r *= t;
return r;
}
// Value * Array
template< typename T >
inline
Array1D< T >
operator *( T const & t, Array1< T > const & a )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r *= t;
return r;
}
// Array / Value
template< typename T >
inline
Array1D< T >
operator /( Array1< T > const & a, T const & t )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r /= t;
return r;
}
// Value / Array
template< typename T >
inline
Array1D< T >
operator /( T const & t, Array1< T > const & a )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r.invert();
r *= t;
return r;
}
// Generator: Slice
// -Slice
template< typename T >
inline
Array1D< T >
operator -( Array1S< T > const & a )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r *= T( -1 );
return r;
}
// Slice + Slice
template< typename T >
inline
Array1D< T >
operator +( Array1S< T > const & a, Array1S< T > const & b )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r += b;
return r;
}
// Slice - Slice
template< typename T >
inline
Array1D< T >
operator -( Array1S< T > const & a, Array1S< T > const & b )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r -= b;
return r;
}
// Slice * Slice
template< typename T >
inline
Array1D< T >
operator *( Array1S< T > const & a, Array1S< T > const & b )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r *= b;
return r;
}
// Slice / Slice
template< typename T >
inline
Array1D< T >
operator /( Array1S< T > const & a, Array1S< T > const & b )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r /= b;
return r;
}
// Slice + Array
template< typename T >
inline
Array1D< T >
operator +( Array1S< T > const & a, Array1< T > const & b )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r += b;
return r;
}
// Slice - Array
template< typename T >
inline
Array1D< T >
operator -( Array1S< T > const & a, Array1< T > const & b )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r -= b;
return r;
}
// Slice * Array
template< typename T >
inline
Array1D< T >
operator *( Array1S< T > const & a, Array1< T > const & b )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r *= b;
return r;
}
// Slice / Array
template< typename T >
inline
Array1D< T >
operator /( Array1S< T > const & a, Array1< T > const & b )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r /= b;
return r;
}
// Array + Slice
template< typename T >
inline
Array1D< T >
operator +( Array1< T > const & a, Array1S< T > const & b )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r += b;
return r;
}
// Array - Slice
template< typename T >
inline
Array1D< T >
operator -( Array1< T > const & a, Array1S< T > const & b )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r -= b;
return r;
}
// Array * Slice
template< typename T >
inline
Array1D< T >
operator *( Array1< T > const & a, Array1S< T > const & b )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r *= b;
return r;
}
// Array / Slice
template< typename T >
inline
Array1D< T >
operator /( Array1< T > const & a, Array1S< T > const & b )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r /= b;
return r;
}
// Slice + Value
template< typename T >
inline
Array1D< T >
operator +( Array1S< T > const & a, T const & t )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r += t;
return r;
}
// Value + Slice
template< typename T >
inline
Array1D< T >
operator +( T const & t, Array1S< T > const & a )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r += t;
return r;
}
// Slice - Value
template< typename T >
inline
Array1D< T >
operator -( Array1S< T > const & a, T const & t )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r -= t;
return r;
}
// Value - Slice
template< typename T >
inline
Array1D< T >
operator -( T const & t, Array1S< T > const & a )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r *= T( -1 );
r += t;
return r;
}
// Slice * Value
template< typename T >
inline
Array1D< T >
operator *( Array1S< T > const & a, T const & t )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r *= t;
return r;
}
// Value * Slice
template< typename T >
inline
Array1D< T >
operator *( T const & t, Array1S< T > const & a )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r *= t;
return r;
}
// Slice / Value
template< typename T >
inline
Array1D< T >
operator /( Array1S< T > const & a, T const & t )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r /= t;
return r;
}
// Value / Slice
template< typename T >
inline
Array1D< T >
operator /( T const & t, Array1S< T > const & a )
{
Array1D< T > r( Array1D< T >::one_based( a ) );
r.invert();
r *= t;
return r;
}
// Cross Product of 3-Tuples
template< typename T >
inline
Array1D< T >
cross( Array1< T > const & a, Array1< T > const & b )
{
assert( conformable( a, b ) );
assert( a.size() == 3u );
Array1D< T > c( 3 );
c[ 0 ] = ( a[ 1 ] * b[ 2 ] ) - ( a[ 2 ] * b[ 1 ] );
c[ 1 ] = ( a[ 2 ] * b[ 0 ] ) - ( a[ 0 ] * b[ 2 ] );
c[ 2 ] = ( a[ 0 ] * b[ 1 ] ) - ( a[ 1 ] * b[ 0 ] );
return c;
}
// Cross Product of 3-Tuples
template< typename T >
inline
Array1D< T >
cross( Array1< T > const & a, Array1S< T > const & b )
{
assert( conformable( a, b ) );
assert( a.size() == 3u );
Array1D< T > c( 3 );
c[ 0 ] = ( a[ 1 ] * b[ 2 ] ) - ( a[ 2 ] * b[ 1 ] );
c[ 1 ] = ( a[ 2 ] * b[ 0 ] ) - ( a[ 0 ] * b[ 2 ] );
c[ 2 ] = ( a[ 0 ] * b[ 1 ] ) - ( a[ 1 ] * b[ 0 ] );
return c;
}
// Cross Product of 3-Tuples
template< typename T >
inline
Array1D< T >
cross( Array1S< T > const & a, Array1< T > const & b )
{
assert( conformable( a, b ) );
assert( a.size() == 3u );
Array1D< T > c( 3 );
c[ 0 ] = ( a[ 1 ] * b[ 2 ] ) - ( a[ 2 ] * b[ 1 ] );
c[ 1 ] = ( a[ 2 ] * b[ 0 ] ) - ( a[ 0 ] * b[ 2 ] );
c[ 2 ] = ( a[ 0 ] * b[ 1 ] ) - ( a[ 1 ] * b[ 0 ] );
return c;
}
// Cross Product of 3-Tuples
template< typename T >
inline
Array1D< T >
cross( Array1S< T > const & a, Array1S< T > const & b )
{
assert( conformable( a, b ) );
assert( a.size() == 3u );
Array1D< T > c( 3 );
c[ 0 ] = ( a[ 1 ] * b[ 2 ] ) - ( a[ 2 ] * b[ 1 ] );
c[ 1 ] = ( a[ 2 ] * b[ 0 ] ) - ( a[ 0 ] * b[ 2 ] );
c[ 2 ] = ( a[ 0 ] * b[ 1 ] ) - ( a[ 1 ] * b[ 0 ] );
return c;
}
// Cross Product of 3-Tuples
template< typename T >
inline
Array1D< T >
cross_product( Array1< T > const & a, Array1< T > const & b )
{
return cross( a, b );
}
// Cross Product of 3-Tuples
template< typename T >
inline
Array1D< T >
cross_product( Array1< T > const & a, Array1S< T > const & b )
{
return cross( a, b );
}
// Cross Product of 3-Tuples
template< typename T >
inline
Array1D< T >
cross_product( Array1S< T > const & a, Array1< T > const & b )
{
return cross( a, b );
}
// Cross Product of 3-Tuples
template< typename T >
inline
Array1D< T >
cross_product( Array1S< T > const & a, Array1S< T > const & b )
{
return cross( a, b );
}
} // ObjexxFCL
#endif // ObjexxFCL_Array1D_hh_INCLUDED
// ===== Out-of-line statics (normally in IndexRange.cc) =====
namespace ObjexxFCL {
IndexRange::size_type const IndexRange::npos = static_cast< size_type >( -1 );
int const IndexRange::l_min = -( static_cast< int >( ( static_cast< unsigned int >( -1 ) / 2u ) ) - 1 );
int const IndexRange::u_max = static_cast< int >( ( static_cast< unsigned int >( -1 ) / 2u ) );
} // ObjexxFCL
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment