Loading...
Searching...
No Matches
SimplePrImpl.h
//-*****************************************************************************
//
// Copyright (c) 2009-2012,
// 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_SimplePrImpl_h
#define Alembic_AbcCoreHDF5_SimplePrImpl_h
#include <Alembic/AbcCoreHDF5/Foundation.h>
#include <Alembic/AbcCoreHDF5/OrImpl.h>
#include <Alembic/AbcCoreHDF5/ArImpl.h>
#include <Alembic/AbcCoreHDF5/ReadUtil.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 readers. The only way these two readers differ
// is the type of sample they read and the way those samples are returned
// and managed. Scalar samples are simply copied by value, compared by value,
// and stored by value. Array samples are returned from an optional sample
// cache.
//
// There is a bit of template hoosafudgery going on here, which is always
// troublesome in foundation libraries, because it is hard to read and
// hard to decipher errors. I have kept it to a reasonable minimum, but the
// value of a single code instance is high enough that it's worth a bit of
// obfuscation.
//
// The IMPL class is assumed to have the following functions:
// void readSample( H5G &iGroup,
// const std::string &iSampleName,
// index_t iSampleIndex,
// SAMPLE oSample );
//
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE>
class SimplePrImpl : public ABSTRACT
{
protected:
SimplePrImpl( AbcA::CompoundPropertyReaderPtr iParent,
H5Node & iParentGroup,
PropertyHeaderPtr iHeader,
uint32_t iNumSamples,
uint32_t iFirstChangedIndex,
uint32_t iLastChangedIndex );
public:
//-*************************************************************************
// ABSTRACT API
//-*************************************************************************
virtual ~SimplePrImpl();
virtual const AbcA::PropertyHeader &getHeader() const;
virtual AbcA::ObjectReaderPtr getObject();
virtual AbcA::CompoundPropertyReaderPtr getParent();
virtual size_t getNumSamples();
virtual bool isConstant();
virtual void getSample( index_t iSampleIndex,
SAMPLE oSample );
virtual std::pair<index_t, chrono_t> getFloorIndex( chrono_t iTime );
virtual std::pair<index_t, chrono_t> getCeilIndex( chrono_t iTime );
virtual std::pair<index_t, chrono_t> getNearIndex( chrono_t iTime );
virtual bool getKey( index_t iSampleIndex, AbcA::ArraySampleKey & oKey );
protected:
index_t verifySampleIndex( index_t iSampleIndex );
void checkSamplesIGroup();
// Parent compound property writer. It must exist.
AbcA::CompoundPropertyReaderPtr m_parent;
// The HDF5 Group associated with the parent property reader.
H5Node m_parentGroup;
// We don't hold a pointer to the object, but instead
// get it from the compound property reader.
// The Header
PropertyHeaderPtr m_header;
// Data Types.
hid_t m_fileDataType;
bool m_cleanFileDataType;
hid_t m_nativeDataType;
bool m_cleanNativeDataType;
// The number of samples that were written. This may be greater
// than the number of samples that were stored, because we don't
// repeat head or tail samples that repeat
uint32_t m_numSamples;
// The first sample index that is different from sample 0
uint32_t m_firstChangedIndex;
// The last sample index that needed to be written out, if the last sample
// repeats m_numSamples will be greater than this.
uint32_t m_lastChangedIndex;
// The simple properties only store samples after the first
// sample in a sub group. Therefore, there may not actually be
// a group associated with this property.
H5Node m_samplesIGroup;
// used to prevent race condition when setting m_samplesIGroup
Alembic::Util::mutex m_samplesIGroupMutex;
};
//-*****************************************************************************
//-*****************************************************************************
//-*****************************************************************************
// IMPLEMENTATION
//-*****************************************************************************
//-*****************************************************************************
//-*****************************************************************************
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE>
SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::SimplePrImpl
(
AbcA::CompoundPropertyReaderPtr iParent,
H5Node & iParentGroup,
PropertyHeaderPtr iHeader,
uint32_t iNumSamples,
uint32_t iFirstChangedIndex,
uint32_t iLastChangedIndex
)
: m_parent( iParent )
, m_parentGroup( iParentGroup )
, m_header( iHeader )
, m_fileDataType( -1 )
, m_cleanFileDataType( false )
, m_nativeDataType( -1 )
, m_cleanNativeDataType( false )
, m_numSamples( iNumSamples )
, m_firstChangedIndex( iFirstChangedIndex )
, m_lastChangedIndex( iLastChangedIndex )
{
// Validate all inputs.
ABCA_ASSERT( m_parent, "Invalid parent" );
ABCA_ASSERT( m_parentGroup.isValidObject(), "Invalid parent group" );
ABCA_ASSERT( m_header, "Invalid header" );
ABCA_ASSERT( m_header->getPropertyType() != AbcA::kCompoundProperty,
"Tried to create a simple property with a compound header" );
// 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 );
}
// Get our name.
const std::string &myName = m_header->getName();
// Validate the first and last changed index
ABCA_ASSERT( m_firstChangedIndex <= m_numSamples &&
m_lastChangedIndex <= m_numSamples &&
m_firstChangedIndex <= m_lastChangedIndex,
"Corrupt sampling information for property: " << myName
<< " first change index: " << m_firstChangedIndex
<< " last change index: " << m_lastChangedIndex
<< " total number of samples: " << m_numSamples );
}
//-*****************************************************************************
// Destructor is at the end, so that this file has a logical ordering that
// matches the order of operations (create, get samples, destroy)
//-*****************************************************************************
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE>
const AbcA::PropertyHeader &
SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::getHeader() const
{
ABCA_ASSERT( m_header, "Invalid header" );
return *m_header;
}
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE>
AbcA::ObjectReaderPtr
SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::getObject()
{
ABCA_ASSERT( m_parent, "Invalid parent" );
return m_parent->getObject();
}
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE>
AbcA::CompoundPropertyReaderPtr
SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::getParent()
{
ABCA_ASSERT( m_parent, "Invalid parent" );
return m_parent;
}
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE>
size_t SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::getNumSamples()
{
return ( size_t )m_numSamples;
}
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE>
bool SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::isConstant()
{
// No first change means no changes at all
return ( m_firstChangedIndex == 0 );
}
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE>
index_t SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::verifySampleIndex( index_t iIndex )
{
// Verify sample index
ABCA_ASSERT( iIndex >= 0 &&
iIndex < m_numSamples,
"Invalid sample index: " << iIndex
<< ", should be between 0 and " << m_numSamples-1 );
// greater than the last index that had a change? read it from there
if ( iIndex > m_lastChangedIndex )
{
iIndex = m_lastChangedIndex;
}
// less than the first change? map to 0
else if ( iIndex < m_firstChangedIndex )
{
iIndex = 0;
}
return iIndex;
}
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE>
void SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::checkSamplesIGroup()
{
// Create the subsequent samples group.
if ( !m_samplesIGroup.isValidObject() )
{
Alembic::Util::scoped_lock l( m_samplesIGroupMutex );
if ( m_samplesIGroup.isValidObject() )
return;
std::string samplesIName = m_header->getName() + ".smpi";
ABCA_ASSERT( GroupExists( m_parentGroup, samplesIName ),
"Invalid property: " << m_header->getName()
<< ", missing smpi" );
m_samplesIGroup = OpenGroup( m_parentGroup,
samplesIName.c_str() );
ABCA_ASSERT( m_samplesIGroup.isValidObject(),
"Invalid property: " << m_header->getName()
<< ", invalid smpi group" );
}
}
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE>
std::pair<index_t, chrono_t>
SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::getFloorIndex( chrono_t iTime )
{
return m_header->getTimeSampling()->getFloorIndex( iTime, m_numSamples );
}
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE>
std::pair<index_t, chrono_t>
SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::getCeilIndex( chrono_t iTime )
{
return m_header->getTimeSampling()->getCeilIndex( iTime, m_numSamples );
}
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE>
std::pair<index_t, chrono_t>
SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::getNearIndex( chrono_t iTime )
{
return m_header->getTimeSampling()->getNearIndex( iTime, m_numSamples );
}
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE>
void
SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::getSample( index_t iSampleIndex,
SAMPLE oSample )
{
iSampleIndex = verifySampleIndex( iSampleIndex );
// Get our name.
const std::string &myName = m_header->getName();
if ( iSampleIndex == 0 )
{
// Read the sample from the parent group.
// Sample 0 is always on the parent group, with
// our name + ".smp0" as the name of it.
std::string sample0Name = getSampleName( myName, 0 );
if ( m_header->getPropertyType() == AbcA::kScalarProperty )
{
ABCA_ASSERT( AttrExists( m_parentGroup, sample0Name.c_str() ),
"Invalid property in SimplePrImpl getSample: "
<< myName << ", missing smp0" );
}
else
{
ABCA_ASSERT( DatasetExists( m_parentGroup, sample0Name ),
"Invalid propertyin SimplePrImpl getSample: "
<< myName << ", missing smp1" );
}
static_cast<IMPL *>( this )->readSample( m_parentGroup.getObject(),
sample0Name,
iSampleIndex,
oSample );
}
else
{
checkSamplesIGroup();
// Read the sample.
std::string sampleName = getSampleName( myName, iSampleIndex );
static_cast<IMPL *>( this )->readSample( m_samplesIGroup.getObject(),
sampleName,
iSampleIndex,
oSample );
}
}
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE>
bool
SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::getKey( index_t iSampleIndex,
AbcA::ArraySampleKey & oKey )
{
iSampleIndex = verifySampleIndex( iSampleIndex );
// Get our name.
const std::string &myName = m_header->getName();
if ( iSampleIndex == 0 )
{
// Read the sample from the parent group.
// Sample 0 is always on the parent group, with
// our name + ".smp0" as the name of it.
std::string sample0Name = getSampleName( myName, 0 );
if ( m_header->getPropertyType() == AbcA::kScalarProperty )
{
ABCA_ASSERT( AttrExists( m_parentGroup, sample0Name.c_str() ),
"Invalid property in SimplePrImpl getKey: "
<< myName << ", missing smp0" );
}
else
{
ABCA_ASSERT( DatasetExists( m_parentGroup, sample0Name ),
"Invalid property in SimplePrImpl getKey: "
<< myName << ", missing smp1" );
}
return static_cast<IMPL *>( this )->readKey( m_parentGroup.getObject(),
sample0Name,
oKey );
}
else
{
checkSamplesIGroup();
// Read the sample.
std::string sampleName = getSampleName( myName, iSampleIndex );
return static_cast<IMPL*>( this )->readKey( m_samplesIGroup.getObject(),
sampleName,
oKey );
}
}
//-*****************************************************************************
template <class ABSTRACT, class IMPL, class SAMPLE>
SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::~SimplePrImpl()
{
// Clean up our samples group, if necessary.
CloseObject( m_samplesIGroup );
if ( m_fileDataType >= 0 && m_cleanFileDataType )
{
H5Tclose( m_fileDataType );
m_fileDataType = -1;
}
if ( m_nativeDataType >= 0 && m_cleanNativeDataType )
{
H5Tclose( m_nativeDataType );
m_nativeDataType = -1;
}
}
} // End namespace ALEMBIC_VERSION_NS
using namespace ALEMBIC_VERSION_NS;
} // End namespace AbcCoreHDF5
} // End namespace Alembic
#endif
Alembic::AbcCoreHDF5::ALEMBIC_VERSION_NS::H5Node
Definition HDF5Hierarchy.h:50
Alembic::Util::ALEMBIC_VERSION_NS::mutex
Definition Foundation.h:176
Alembic
Alembic namespace ...
Definition ArchiveInfo.cpp:39
Alembic::AbcCoreAbstract::ALEMBIC_VERSION_NS::ArraySampleKey
Definition ArraySampleKey.h:48