Files
opm-common/opm/parser/eclipse/Deck/DeckItem.cpp
Jørgen Kvalsvik 3f9e6a7be5 DeckItem can be automatically allocated.
Using a virtual base class DeckItem that exposed DeckInt/Double/String
types means it cannot be held in a vector and managed automatically
without unique_ptr, which is clunky and makes iterator aliases
impossible. This patch moves the unique_ptr details into DeckItem which
now behaves as if it was virtual, except it only forwards calls to its
inner, managed object (much like private implementation).

This gives the benefit of automatic/stack allocation, and no particular
drawback aside from slightly less obvious implementation. Clients can
still call get< int > on a DeckItem::double, but that was also possible
with the virtual solution (i.e. nothing lost).
2016-02-18 13:26:55 +01:00

401 lines
13 KiB
C++

/*
Copyright 2013 Statoil ASA.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/parser/eclipse/Deck/DeckItem.hpp>
#include <opm/parser/eclipse/Units/Dimension.hpp>
#include <boost/algorithm/string.hpp>
#include <stdexcept>
namespace Opm {
template< typename T >
class DeckTypeItem : public DeckItemBase {
public:
const std::string& name() const override;
bool defaultApplied( size_t ) const override;
bool hasValue( size_t ) const override;
size_t size() const override;
void push_back( T );
void push_back( T, size_t numValues );
void push_backDefault( T );
void push_backDummyDefault() override;
const T& get( size_t ) const;
const std::vector< T >& getData() const;
protected:
DeckTypeItem( const std::string& );
private:
std::string item_name;
std::vector< bool > dataPointDefaulted;
std::vector< T > data;
};
template< typename T >
class DeckItemT : public DeckTypeItem< T > {
private:
using DeckTypeItem< T >::DeckTypeItem;
std::unique_ptr< DeckItemBase > clone() const override;
friend class DeckItem;
};
template<>
class DeckItemT< double > : public DeckTypeItem< double > {
public:
using DeckTypeItem< double >::DeckTypeItem;
const double& getSI( size_t ) const;
const std::vector< double >& getSIData() const;
void push_backDimension(
std::shared_ptr< const Dimension > activeDimension,
std::shared_ptr< const Dimension > defaultDimension );
private:
const std::vector< double >& assertSIData() const;
std::unique_ptr< DeckItemBase > clone() const override;
std::vector< double > SIdata;
std::vector< std::shared_ptr< const Dimension > > dimensions;
friend class DeckItem;
};
template< typename T >
DeckTypeItem< T >::DeckTypeItem( const std::string& name ) :
item_name( name )
{}
template< typename T >
const std::string& DeckTypeItem< T >::name() const {
return this->item_name;
}
template< typename T >
bool DeckTypeItem< T >::defaultApplied( size_t index ) const {
return this->dataPointDefaulted.at( index );
}
template< typename T >
bool DeckTypeItem< T >::hasValue( size_t index ) const {
return index < this->size();
}
template< typename T >
size_t DeckTypeItem< T >::size() const {
return this->data.size();
}
template< typename T >
void DeckTypeItem< T >::push_back( T x ) {
if( this->dataPointDefaulted.size() != this->data.size() )
throw std::logic_error("To add a value to an item, no \"pseudo defaults\" can be added before");
this->data.push_back( x );
this->dataPointDefaulted.push_back( false );
}
template< typename T >
void DeckTypeItem< T >::push_backDefault( T data ) {
if( this->dataPointDefaulted.size() != this->data.size() )
throw std::logic_error("To add a value to an item, no \"pseudo defaults\" can be added before");
this->data.push_back( data );
this->dataPointDefaulted.push_back(true);
}
template< typename T >
void DeckTypeItem< T >::push_backDummyDefault() {
if( this->dataPointDefaulted.size() != 0 )
throw std::logic_error("Pseudo defaults can only be specified for empty items");
this->dataPointDefaulted.push_back( true );
}
template< typename T >
void DeckTypeItem< T >::push_back( T x, size_t numValues ) {
if( this->dataPointDefaulted.size() != this->data.size() )
throw std::logic_error("To add a value to an item, no \"pseudo defaults\" can be added before");
this->data.insert( this->data.end(), numValues, x );
this->dataPointDefaulted.insert( this->dataPointDefaulted.end(), numValues, false );
}
template< typename T >
const T& DeckTypeItem< T >::get( size_t index ) const {
return this->data.at( index );
}
template< typename T >
const std::vector< T >& DeckTypeItem< T >::getData() const {
return this->data;
}
const double& DeckItemT< double >::getSI( size_t index ) const {
return this->assertSIData().at( index );
}
const std::vector< double >& DeckItemT< double >::getSIData() const {
return this->assertSIData();
}
void DeckItemT< double >::push_backDimension(
std::shared_ptr< const Dimension > activeDimension,
std::shared_ptr< const Dimension > defaultDimension ) {
if( this->size() == 0 || this->defaultApplied( this->size() - 1 ) )
this->dimensions.push_back( defaultDimension );
else
this->dimensions.push_back( activeDimension );
}
template< typename T >
std::unique_ptr< DeckItemBase > DeckItemT< T >::clone() const {
return std::unique_ptr< DeckItemBase > { new DeckItemT< T >( *this ) };
}
std::unique_ptr< DeckItemBase > DeckItemT< double >::clone() const {
return std::unique_ptr< DeckItemBase > { new DeckItemT< double >( *this ) };
}
const std::vector< double >& DeckItemT< double >::assertSIData() const {
if( this->dimensions.size() <= 0 )
throw std::invalid_argument("No dimension has been set for item:" + this->name() + " can not ask for SI data");
// we already converted this item to SI?
if( this->SIdata.size() > 0 ) return this->SIdata;
/*
* This is an unobservable state change - SIData is lazily converted to
* SI units, so externally the object still behaves as const
*/
auto& data = const_cast< DeckItemT< double >* >( this )->SIdata;
data.resize( this->size() );
for( size_t index = 0; index < this->size(); index++ ) {
const auto dimIndex = ( index % dimensions.size() );
data[ index ] = this->dimensions[ dimIndex ]
->convertRawToSi( this->get( index ) );
}
return data;
}
template< typename Ptr >
static inline DeckItem::type typeof_item( Ptr* item ) {
if( dynamic_cast< DeckItemT< int >* >( item ) )
return DeckItem::type::integer;
if( dynamic_cast< DeckItemT< std::string >* >( item ) )
return DeckItem::type::string;
if( dynamic_cast< DeckItemT< double >* >( item ) )
return DeckItem::type::fdouble;
return DeckItem::type::unknown;
}
static inline std::string typetag_to_string( DeckItem::type x ) {
switch( x ) {
case DeckItem::type::integer: return "int";
case DeckItem::type::string: return "std::string";
case DeckItem::type::fdouble: return "double";
case DeckItem::type::unknown: return "unknown";
}
return "unknown";
}
template< typename T > static std::string typename_string();
template<>
std::string typename_string< int >() {
return "int";
}
template<>
std::string typename_string< double >() {
return "double";
}
template<>
std::string typename_string< std::string >() {
return "std::string";
}
template< typename T >
static inline DeckItemT< T >* conv( std::unique_ptr< DeckItemBase >& ptr ) {
if( auto* d = dynamic_cast< DeckItemT< T >* >( ptr.get() ) )
return d;
throw std::logic_error(
"Treating item " + ptr->name()
+ " as " + typename_string< T >()
+ ", but is "
+ typetag_to_string( typeof_item( ptr.get() ) ) );
}
template< typename T >
static inline
const DeckItemT< T >* conv( const std::unique_ptr< DeckItemBase >& ptr ) {
if( auto* d = dynamic_cast< const DeckItemT< T >* >( ptr.get() ) )
return d;
throw std::logic_error(
"Treating item " + ptr->name()
+ " as " + typename_string< T >()
+ ", but is "
+ typetag_to_string( typeof_item( ptr.get() ) ) );
}
DeckItem::DeckItem( const DeckItem& rhs ) :
ptr( rhs.ptr->clone() )
{}
DeckItem::DeckItem( std::unique_ptr< DeckItemBase >&& x ) :
ptr( std::move( x ) )
{}
template< typename T >
DeckItem DeckItem::make( const std::string& name ) {
return DeckItem( std::unique_ptr< DeckItemBase > { new DeckItemT< T >( name ) } );
}
const std::string& DeckItem::name() const {
return this->ptr->name();
}
bool DeckItem::defaultApplied( size_t index ) const {
return this->ptr->defaultApplied( index );
}
bool DeckItem::hasValue( size_t index ) const {
return this->ptr->hasValue( index );
}
size_t DeckItem::size() const {
return this->ptr->size();
}
template< typename T >
const T& DeckItem::get( size_t index ) const {
return conv< T >( this->ptr )->get( index );
}
template< typename T >
const std::vector< T >& DeckItem::getData() const {
return conv< T >( this->ptr )->getData();
}
template< typename T >
void DeckItem::push_back( T x ) {
return conv< T >( this->ptr )->push_back( x );
}
template< typename T >
void DeckItem::push_back( T x, size_t n ) {
return conv< T >( this->ptr )->push_back( x, n );
}
template< typename T >
void DeckItem::push_backDefault( T x ) {
return conv< T >( this->ptr )->push_backDefault( x );
}
template<>
void DeckItem::push_back( const char* x ) {
return conv< std::string >( this->ptr )->push_back( x );
}
template<>
void DeckItem::push_back( const char* x, size_t n ) {
return conv< std::string >( this->ptr )->push_back( x, n );
}
template<>
void DeckItem::push_backDefault( const char* x ) {
return conv< std::string >( this->ptr )->push_backDefault( x );
}
void DeckItem::push_backDummyDefault() {
return this->ptr->push_backDummyDefault();
}
std::string DeckItem::getTrimmedString( size_t index ) const {
return boost::algorithm::trim_copy(
conv< std::string >( this->ptr )->get( index )
);
}
double DeckItem::getSIDouble( size_t index ) const {
return conv< double >( this->ptr )->getSI( index );
}
const std::vector< double >& DeckItem::getSIDoubleData() const {
return conv< double >( this->ptr )->getSIData();
}
void DeckItem::push_backDimension( std::shared_ptr< const Dimension > active,
std::shared_ptr< const Dimension > def ) {
return conv< double >( this->ptr )->push_backDimension( active, def );
}
DeckItem::type DeckItem::typeof() const {
return typeof_item( this->ptr.get() );
}
/*
* Explicit template instantiations. These must be manually maintained and
* updated with changes in DeckItem so that code is emitted.
*/
template class DeckTypeItem< int >;
template class DeckTypeItem< double >;
template class DeckTypeItem< std::string >;
template class DeckItemT< int >;
template class DeckItemT< double >;
template class DeckItemT< std::string >;
template DeckItem DeckItem::make< int >( const std::string& );
template DeckItem DeckItem::make< double >( const std::string& );
template DeckItem DeckItem::make< std::string >( const std::string& );
template const int& DeckItem::get< int >( size_t ) const;
template const double& DeckItem::get< double >( size_t ) const;
template const std::string& DeckItem::get< std::string >( size_t ) const;
template const std::vector< int >& DeckItem::getData< int >() const;
template const std::vector< double >& DeckItem::getData< double >() const;
template const std::vector< std::string >& DeckItem::getData< std::string >() const;
template void DeckItem::push_back< int >( int );
template void DeckItem::push_back< double >( double );
template void DeckItem::push_back< std::string >( std::string );
template void DeckItem::push_back< int >( int, size_t );
template void DeckItem::push_back< double >( double, size_t );
template void DeckItem::push_back< std::string >( std::string, size_t );
template void DeckItem::push_backDefault< int >( int );
template void DeckItem::push_backDefault< double >( double );
template void DeckItem::push_backDefault< std::string >( std::string );
}