Loading...
Searching...
No Matches
SimplePwImpl.h
//-*****************************************************************************
//
// Copyright (c) 2009-2013,
// Sony Pictures Imageworks, Inc. and
// Industrial Light & Magic, a division of Lucasfilm Entertainment Company Ltd.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Sony Pictures Imageworks, nor
// Industrial Light & Magic nor the names of their contributors may be used
// to endorse or promote products derived from this software without specific
// prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//-*****************************************************************************
#ifndef Alembic_AbcCoreHDF5_SimplePwImpl_h
#define Alembic_AbcCoreHDF5_SimplePwImpl_h
#include <Alembic/AbcCoreHDF5/Foundation.h>
#include <Alembic/AbcCoreHDF5/WriteUtil.h>
#include <Alembic/AbcCoreHDF5/DataTypeRegistry.h>
#include <Alembic/AbcCoreHDF5/HDF5Util.h>
namespace Alembic {
namespace AbcCoreHDF5 {
namespace ALEMBIC_VERSION_NS {
//-*****************************************************************************
// This templated base class implements the common logic behind both the
// scalar and array property writers. The only way these two writers differ
// is the type of sample they write and the way those samples are stored
// and copied. Scalar samples are simply copied by value, compared by value,
// and stored by value. Array samples are assumed to be "big", and are
// first condensed into a "key" (using a checksum), which is compared
// to other "keys" of previously written samples. However, the primary logic
// of when to compare, when to copy, when to write, and how to manage time
// values is common across both classes, and represents the primary complexity.
// To minimize redundancy, errors, and code size, we create a common base class.
//
// It is assumed that the IMPL class will provide a mechanism for constructing
// a KEY from a SAMPLE.
//
// The IMPL class is assumed to have the following functions:
// KEY computeSampleKey( SAMPLE iSamp ) const;
// bool sameAsPreviousSample( SAMPLE iSamp, const KEY &iKey ) const;
// void copyPreviousSample( index_t iSampleIndex );
// void writeSample( index_t iSampleIndex, SAMPLE iSamp, const KEY &iKey );
//
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE, class KEY>
class SimplePwImpl : public ABSTRACT
{
protected:
SimplePwImpl( AbcA::CompoundPropertyWriterPtr iParent,
hid_t iParentGroup,
const std::string & iName,
const AbcA::MetaData & iMetaData,
const AbcA::DataType & iDataType,
uint32_t iTimeSamplingIndex,
AbcA::PropertyType iPropType );
public:
virtual ~SimplePwImpl();
//-*************************************************************************
// FROM ABSTRACT
//-*************************************************************************
virtual const AbcA::PropertyHeader & getHeader() const;
virtual AbcA::ObjectWriterPtr getObject();
virtual AbcA::CompoundPropertyWriterPtr getParent();
private:
hid_t getSampleIGroup();
public:
// Scalar/Array API
virtual void setSample( SAMPLE iSamp );
virtual void setFromPreviousSample( );
virtual size_t getNumSamples();
virtual void setTimeSamplingIndex( uint32_t iIndex );
protected:
// The parent compound property writer.
AbcA::CompoundPropertyWriterPtr m_parent;
// The parent group. We need to keep this around because we
// don't create our group until we need to. This is guaranteed to
// exist because our parent (or object) is guaranteed to exist.
hid_t m_parentGroup;
// The header which defines this property.
PropertyHeaderPtr m_header;
// The DataTypes for this property.
hid_t m_fileDataType;
bool m_cleanFileDataType;
hid_t m_nativeDataType;
bool m_cleanNativeDataType;
// The group corresponding to this property.
// It may never be created or written.
hid_t m_sampleIGroup;
// Index of the next sample to write
uint32_t m_nextSampleIndex;
// Index representing the first sample that is different from sample 0
uint32_t m_firstChangedIndex;
// Index representing the last sample in which a change has occured
// There is no need to repeat samples if they are the same between this
// index and m_nextSampleIndex
uint32_t m_lastChangedIndex;
// Index representing which TimeSampling from the ArchiveWriter to use.
uint32_t m_timeSamplingIndex;
};
//-*****************************************************************************
//-*****************************************************************************
//-*****************************************************************************
// IMPLEMENTATION
//-*****************************************************************************
//-*****************************************************************************
//-*****************************************************************************
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE, class KEY>
SimplePwImpl<ABSTRACT,IMPL,SAMPLE,KEY>::SimplePwImpl
(
AbcA::CompoundPropertyWriterPtr iParent,
hid_t iParentGroup,
const std::string & iName,
const AbcA::MetaData & iMetaData,
const AbcA::DataType & iDataType,
uint32_t iTimeSamplingIndex,
AbcA::PropertyType iPropType
)
: m_parent( iParent )
, m_parentGroup( iParentGroup )
, m_fileDataType( -1 )
, m_cleanFileDataType( false )
, m_nativeDataType( -1 )
, m_cleanNativeDataType( false )
, m_sampleIGroup( -1 )
, m_nextSampleIndex( 0 )
, m_firstChangedIndex( 0 )
, m_lastChangedIndex( 0 )
, m_timeSamplingIndex(iTimeSamplingIndex)
{
// Check the validity of all inputs.
ABCA_ASSERT( m_parent, "Invalid parent" );
ABCA_ASSERT( iName != "" && iName.find('/') == std::string::npos,
"Invalid name" );
// will assert if TimeSamplingPtr not found
AbcA::TimeSamplingPtr ts =
m_parent->getObject()->getArchive()->getTimeSampling(
m_timeSamplingIndex );
m_header = PropertyHeaderPtr( new AbcA::PropertyHeader( iName, iPropType,
iMetaData, iDataType, ts ) );
ABCA_ASSERT( m_header, "Invalid property header" );
ABCA_ASSERT( m_parentGroup >= 0, "Invalid parent group" );
ABCA_ASSERT( m_header->getDataType().getExtent() > 0,
"Invalid DatatType extent");
// Get data types
PlainOldDataType POD = m_header->getDataType().getPod();
if ( POD != kStringPOD && POD != kWstringPOD )
{
m_fileDataType = GetFileH5T( m_header->getDataType(),
m_cleanFileDataType );
m_nativeDataType = GetNativeH5T( m_header->getDataType(),
m_cleanNativeDataType );
ABCA_ASSERT( m_fileDataType >= 0, "Couldn't get file datatype" );
ABCA_ASSERT( m_nativeDataType >= 0, "Couldn't get native datatype" );
}
}
//-*****************************************************************************
// Destructor is at the end, so that this file has a logical ordering that
// matches the order of operations (create, set samples, destroy)
//-*****************************************************************************
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE, class KEY>
const AbcA::PropertyHeader &
SimplePwImpl<ABSTRACT,IMPL,SAMPLE,KEY>::getHeader() const
{
ABCA_ASSERT( m_header, "Invalid header" );
return *m_header;
}
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE, class KEY>
AbcA::ObjectWriterPtr
SimplePwImpl<ABSTRACT,IMPL,SAMPLE,KEY>::getObject()
{
ABCA_ASSERT( m_parent, "Invalid parent" );
return m_parent->getObject();
}
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE, class KEY>
AbcA::CompoundPropertyWriterPtr
SimplePwImpl<ABSTRACT,IMPL,SAMPLE,KEY>::getParent()
{
ABCA_ASSERT( m_parent, "Invalid parent" );
return m_parent;
}
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE, class KEY>
hid_t SimplePwImpl<ABSTRACT,IMPL,SAMPLE,KEY>::getSampleIGroup()
{
if ( m_sampleIGroup >= 0 )
{
return m_sampleIGroup;
}
ABCA_ASSERT( m_parentGroup >= 0, "invalid parent group" );
ABCA_ASSERT( m_nextSampleIndex > 0,
"can't create sampleI group before numSamples > 1" );
const std::string groupName = m_header->getName() + ".smpi";
hid_t copl = CreationOrderPlist();
PlistCloser plistCloser( copl );
m_sampleIGroup = H5Gcreate2( m_parentGroup,
groupName.c_str(),
H5P_DEFAULT,
copl,
H5P_DEFAULT );
ABCA_ASSERT( m_sampleIGroup >= 0,
"Could not create simple samples group named: "
<< groupName );
return m_sampleIGroup;
}
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE, class KEY>
void SimplePwImpl<ABSTRACT,IMPL,SAMPLE,KEY>::setSample
( SAMPLE iSamp )
{
// Make sure we aren't writing more samples than we have times for
// This applies to acyclic sampling only
ABCA_ASSERT(
!m_header->getTimeSampling()->getTimeSamplingType().isAcyclic() ||
m_header->getTimeSampling()->getNumStoredTimes() >
m_nextSampleIndex,
"Can not write more samples than we have times for when using "
"Acyclic sampling." );
// The Key helps us analyze the sample.
KEY key = static_cast<IMPL*>(this)->computeSampleKey( iSamp );
// We need to write the sample
if ( m_nextSampleIndex == 0 ||
!(static_cast<IMPL*>(this)->sameAsPreviousSample( iSamp, key )) )
{
const std::string &myName = m_header->getName();
// we only need to repeat samples if this is not the first change
if (m_firstChangedIndex != 0)
{
// copy the samples from after the last change to the latest index
for ( index_t smpI = m_lastChangedIndex + 1;
smpI < m_nextSampleIndex; ++smpI )
{
assert( smpI > 0 );
static_cast<IMPL*>(this)->copyPreviousSample(
getSampleIGroup(),
getSampleName( myName, smpI ),
smpI );
}
}
else
{
m_firstChangedIndex = m_nextSampleIndex;
}
// Write this sample, which will update its internal
// cache of what the previously written sample was.
static_cast<IMPL*>(this)->writeSample(
m_nextSampleIndex == 0 ? m_parentGroup : getSampleIGroup(),
getSampleName( myName, m_nextSampleIndex ),
m_nextSampleIndex, iSamp, key );
// this index is now the last change
m_lastChangedIndex = m_nextSampleIndex;
}
m_nextSampleIndex ++;
}
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE, class KEY>
void SimplePwImpl<ABSTRACT,IMPL,SAMPLE,KEY>::setFromPreviousSample
()
{
// Make sure we aren't writing more samples than we have times for
// This applies to acyclic sampling only
ABCA_ASSERT(
!m_header->getTimeSampling()->getTimeSamplingType().isAcyclic() ||
m_header->getTimeSampling()->getNumStoredTimes() >
m_nextSampleIndex,
"Can not set more samples than we have times for when using "
"Acyclic sampling." );
ABCA_ASSERT( m_nextSampleIndex > 0,
"Can't set from previous sample before any samples have been written" );
m_nextSampleIndex ++;
}
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE, class KEY>
size_t SimplePwImpl<ABSTRACT,IMPL,SAMPLE,KEY>::getNumSamples()
{
return ( size_t )m_nextSampleIndex;
}
template <class ABSTRACT, class IMPL, class SAMPLE, class KEY>
void SimplePwImpl<ABSTRACT,IMPL,SAMPLE,KEY>::setTimeSamplingIndex
( uint32_t iIndex )
{
// will assert if TimeSamplingPtr not found
AbcA::TimeSamplingPtr ts =
m_parent->getObject()->getArchive()->getTimeSampling(
iIndex );
ABCA_ASSERT( !ts->getTimeSamplingType().isAcyclic() ||
ts->getNumStoredTimes() >= m_nextSampleIndex,
"Already have written more samples than we have times for when using "
"Acyclic sampling." );
m_header->setTimeSampling(ts);
m_timeSamplingIndex = iIndex;
}
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE, class KEY>
SimplePwImpl<ABSTRACT,IMPL,SAMPLE,KEY>::~SimplePwImpl()
{
// Wrap the whole thing in a try block, so as to prevent
// exceptions from being thrown out of a destructor.
try
{
if ( m_fileDataType >= 0 && m_cleanFileDataType )
{ H5Tclose( m_fileDataType ); }
if ( m_nativeDataType >= 0 && m_cleanNativeDataType )
{ H5Tclose( m_nativeDataType ); }
// Check validity of the group.
ABCA_ASSERT( m_parentGroup >= 0, "Invalid parent group" );
// Close the sampleIGroup if it was open
if ( m_sampleIGroup >= 0 )
{
// this should never have been openened, if a change was never
// detected.
ABCA_ASSERT( m_firstChangedIndex > 0, "Corrupt SimplePwImpl" );
H5Gclose( m_sampleIGroup );
m_sampleIGroup = -1;
}
AbcA::ArchiveWriterPtr archive = m_parent->getObject()->getArchive();
index_t maxSamples = archive->getMaxNumSamplesForTimeSamplingIndex(
m_timeSamplingIndex );
uint32_t numSamples = m_nextSampleIndex;
// a constant property, we wrote the same sample over and over
if ( m_lastChangedIndex == 0 && m_nextSampleIndex > 0 )
{
numSamples = 1;
}
if ( maxSamples < numSamples )
{
archive->setMaxNumSamplesForTimeSamplingIndex( m_timeSamplingIndex,
numSamples );
}
}
catch ( std::exception & exc )
{
std::cerr << "AbcCoreHDF5::SimplePwImpl<A,I,K>::"
<< "~SimplePwImpl(): EXCEPTION: "
<< exc.what() << std::endl;
}
catch ( ... )
{
std::cerr << "AbcCoreHDF5::SimplePwImpl<A,I,K>::~SimplePwImpl(): "
<< "UNKNOWN EXCEPTION: " << std::endl;
}
m_parentGroup = -1;
m_sampleIGroup = -1;
m_fileDataType = -1;
m_nativeDataType = -1;
}
} // End namespace ALEMBIC_VERSION_NS
using namespace ALEMBIC_VERSION_NS;
} // End namespace AbcCoreHDF5
} // End namespace Alembic
#endif
Alembic
Alembic namespace ...
Definition ArchiveInfo.cpp:39
Alembic::AbcCoreHDF5::ALEMBIC_VERSION_NS::PlistCloser
Definition HDF5Util.h:93