Alembic: AbcCoreHDF5/SimplePrImpl.h Source File

Alembic 1.8.11

Loading...
Searching...
No Matches
SimplePrImpl.h
1//-*****************************************************************************
2//
3// Copyright (c) 2009-2012,
4// Sony Pictures Imageworks, Inc. and
5// Industrial Light & Magic, a division of Lucasfilm Entertainment Company Ltd.
6//
7// All rights reserved.
8//
9// Redistribution and use in source and binary forms, with or without
10// modification, are permitted provided that the following conditions are
11// met:
12// * Redistributions of source code must retain the above copyright
13// notice, this list of conditions and the following disclaimer.
14// * Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following disclaimer
16// in the documentation and/or other materials provided with the
17// distribution.
18// * Neither the name of Sony Pictures Imageworks, nor
19// Industrial Light & Magic nor the names of their contributors may be used
20// to endorse or promote products derived from this software without specific
21// prior written permission.
22//
23// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34//
35//-*****************************************************************************
36
37#ifndef Alembic_AbcCoreHDF5_SimplePrImpl_h
38#define Alembic_AbcCoreHDF5_SimplePrImpl_h
39
40#include <Alembic/AbcCoreHDF5/Foundation.h>
41
42#include <Alembic/AbcCoreHDF5/OrImpl.h>
43#include <Alembic/AbcCoreHDF5/ArImpl.h>
44#include <Alembic/AbcCoreHDF5/ReadUtil.h>
45#include <Alembic/AbcCoreHDF5/DataTypeRegistry.h>
46#include <Alembic/AbcCoreHDF5/HDF5Util.h>
47
48namespace Alembic {
49namespace AbcCoreHDF5 {
50namespace ALEMBIC_VERSION_NS {
51
52//-*****************************************************************************
53// This templated base class implements the common logic behind both the
54// scalar and array property readers. The only way these two readers differ
55// is the type of sample they read and the way those samples are returned
56// and managed. Scalar samples are simply copied by value, compared by value,
57// and stored by value. Array samples are returned from an optional sample
58// cache.
59//
60// There is a bit of template hoosafudgery going on here, which is always
61// troublesome in foundation libraries, because it is hard to read and
62// hard to decipher errors. I have kept it to a reasonable minimum, but the
63// value of a single code instance is high enough that it's worth a bit of
64// obfuscation.
65//
66// The IMPL class is assumed to have the following functions:
67// void readSample( H5G &iGroup,
68// const std::string &iSampleName,
69// index_t iSampleIndex,
70// SAMPLE oSample );
71//
72//-*****************************************************************************
73template <class ABSTRACT, class IMPL, class SAMPLE>
74 class SimplePrImpl : public ABSTRACT
75{
76protected:
77 SimplePrImpl( AbcA::CompoundPropertyReaderPtr iParent,
78 H5Node & iParentGroup,
79 PropertyHeaderPtr iHeader,
80 uint32_t iNumSamples,
81 uint32_t iFirstChangedIndex,
82 uint32_t iLastChangedIndex );
83
84public:
85 //-*************************************************************************
86 // ABSTRACT API
87 //-*************************************************************************
88 virtual ~SimplePrImpl();
89
90 virtual const AbcA::PropertyHeader &getHeader() const;
91
92 virtual AbcA::ObjectReaderPtr getObject();
93
94 virtual AbcA::CompoundPropertyReaderPtr getParent();
95
96 virtual size_t getNumSamples();
97
98 virtual bool isConstant();
99
100 virtual void getSample( index_t iSampleIndex,
101 SAMPLE oSample );
102
103 virtual std::pair<index_t, chrono_t> getFloorIndex( chrono_t iTime );
104
105 virtual std::pair<index_t, chrono_t> getCeilIndex( chrono_t iTime );
106
107 virtual std::pair<index_t, chrono_t> getNearIndex( chrono_t iTime );
108
109 virtual bool getKey( index_t iSampleIndex, AbcA::ArraySampleKey & oKey );
110
111protected:
112
113 index_t verifySampleIndex( index_t iSampleIndex );
114
115 void checkSamplesIGroup();
116
117 // Parent compound property writer. It must exist.
118 AbcA::CompoundPropertyReaderPtr m_parent;
119
120 // The HDF5 Group associated with the parent property reader.
121 H5Node m_parentGroup;
122
123 // We don't hold a pointer to the object, but instead
124 // get it from the compound property reader.
125
126 // The Header
127 PropertyHeaderPtr m_header;
128
129 // Data Types.
130 hid_t m_fileDataType;
131 bool m_cleanFileDataType;
132 hid_t m_nativeDataType;
133 bool m_cleanNativeDataType;
134
135 // The number of samples that were written. This may be greater
136 // than the number of samples that were stored, because we don't
137 // repeat head or tail samples that repeat
138 uint32_t m_numSamples;
139
140 // The first sample index that is different from sample 0
141 uint32_t m_firstChangedIndex;
142
143 // The last sample index that needed to be written out, if the last sample
144 // repeats m_numSamples will be greater than this.
145 uint32_t m_lastChangedIndex;
146
147 // The simple properties only store samples after the first
148 // sample in a sub group. Therefore, there may not actually be
149 // a group associated with this property.
150 H5Node m_samplesIGroup;
151
152 // used to prevent race condition when setting m_samplesIGroup
153 Alembic::Util::mutex m_samplesIGroupMutex;
154};
155
156//-*****************************************************************************
157//-*****************************************************************************
158//-*****************************************************************************
159// IMPLEMENTATION
160//-*****************************************************************************
161//-*****************************************************************************
162//-*****************************************************************************
163
164//-*****************************************************************************
165template <class ABSTRACT, class IMPL, class SAMPLE>
166SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::SimplePrImpl
167(
168 AbcA::CompoundPropertyReaderPtr iParent,
169 H5Node & iParentGroup,
170 PropertyHeaderPtr iHeader,
171 uint32_t iNumSamples,
172 uint32_t iFirstChangedIndex,
173 uint32_t iLastChangedIndex
174)
175 : m_parent( iParent )
176 , m_parentGroup( iParentGroup )
177 , m_header( iHeader )
178 , m_fileDataType( -1 )
179 , m_cleanFileDataType( false )
180 , m_nativeDataType( -1 )
181 , m_cleanNativeDataType( false )
182 , m_numSamples( iNumSamples )
183 , m_firstChangedIndex( iFirstChangedIndex )
184 , m_lastChangedIndex( iLastChangedIndex )
185{
186 // Validate all inputs.
187 ABCA_ASSERT( m_parent, "Invalid parent" );
188 ABCA_ASSERT( m_parentGroup.isValidObject(), "Invalid parent group" );
189 ABCA_ASSERT( m_header, "Invalid header" );
190 ABCA_ASSERT( m_header->getPropertyType() != AbcA::kCompoundProperty,
191 "Tried to create a simple property with a compound header" );
192
193 // Get data types
194 PlainOldDataType POD = m_header->getDataType().getPod();
195 if ( POD != kStringPOD && POD != kWstringPOD )
196 {
197 m_fileDataType = GetFileH5T( m_header->getDataType(),
198 m_cleanFileDataType );
199 m_nativeDataType = GetNativeH5T( m_header->getDataType(),
200 m_cleanNativeDataType );
201 }
202
203 // Get our name.
204 const std::string &myName = m_header->getName();
205
206 // Validate the first and last changed index
207 ABCA_ASSERT( m_firstChangedIndex <= m_numSamples &&
208 m_lastChangedIndex <= m_numSamples &&
209 m_firstChangedIndex <= m_lastChangedIndex,
210 "Corrupt sampling information for property: " << myName
211 << " first change index: " << m_firstChangedIndex
212 << " last change index: " << m_lastChangedIndex
213 << " total number of samples: " << m_numSamples );
214}
215
216//-*****************************************************************************
217// Destructor is at the end, so that this file has a logical ordering that
218// matches the order of operations (create, get samples, destroy)
219//-*****************************************************************************
220
221//-*****************************************************************************
222template <class ABSTRACT, class IMPL, class SAMPLE>
223const AbcA::PropertyHeader &
224SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::getHeader() const
225{
226 ABCA_ASSERT( m_header, "Invalid header" );
227 return *m_header;
228}
229
230//-*****************************************************************************
231template <class ABSTRACT, class IMPL, class SAMPLE>
232AbcA::ObjectReaderPtr
233SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::getObject()
234{
235 ABCA_ASSERT( m_parent, "Invalid parent" );
236 return m_parent->getObject();
237}
238
239//-*****************************************************************************
240template <class ABSTRACT, class IMPL, class SAMPLE>
241AbcA::CompoundPropertyReaderPtr
242SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::getParent()
243{
244 ABCA_ASSERT( m_parent, "Invalid parent" );
245 return m_parent;
246}
247
248//-*****************************************************************************
249template <class ABSTRACT, class IMPL, class SAMPLE>
250size_t SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::getNumSamples()
251{
252 return ( size_t )m_numSamples;
253}
254
255//-*****************************************************************************
256template <class ABSTRACT, class IMPL, class SAMPLE>
257bool SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::isConstant()
258{
259 // No first change means no changes at all
260 return ( m_firstChangedIndex == 0 );
261}
262
263//-*****************************************************************************
264template <class ABSTRACT, class IMPL, class SAMPLE>
265index_t SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::verifySampleIndex( index_t iIndex )
266{
267 // Verify sample index
268 ABCA_ASSERT( iIndex >= 0 &&
269 iIndex < m_numSamples,
270 "Invalid sample index: " << iIndex
271 << ", should be between 0 and " << m_numSamples-1 );
272
273 // greater than the last index that had a change? read it from there
274 if ( iIndex > m_lastChangedIndex )
275 {
276 iIndex = m_lastChangedIndex;
277 }
278 // less than the first change? map to 0
279 else if ( iIndex < m_firstChangedIndex )
280 {
281 iIndex = 0;
282 }
283
284 return iIndex;
285}
286
287//-*****************************************************************************
288template <class ABSTRACT, class IMPL, class SAMPLE>
289void SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::checkSamplesIGroup()
290{
291 // Create the subsequent samples group.
292 if ( !m_samplesIGroup.isValidObject() )
293 {
294 Alembic::Util::scoped_lock l( m_samplesIGroupMutex );
295
296 if ( m_samplesIGroup.isValidObject() )
297 return;
298
299 std::string samplesIName = m_header->getName() + ".smpi";
300 ABCA_ASSERT( GroupExists( m_parentGroup, samplesIName ),
301 "Invalid property: " << m_header->getName()
302 << ", missing smpi" );
303
304 m_samplesIGroup = OpenGroup( m_parentGroup,
305 samplesIName.c_str() );
306 ABCA_ASSERT( m_samplesIGroup.isValidObject(),
307 "Invalid property: " << m_header->getName()
308 << ", invalid smpi group" );
309 }
310}
311
312//-*****************************************************************************
313template <class ABSTRACT, class IMPL, class SAMPLE>
314std::pair<index_t, chrono_t>
315SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::getFloorIndex( chrono_t iTime )
316{
317 return m_header->getTimeSampling()->getFloorIndex( iTime, m_numSamples );
318}
319
320//-*****************************************************************************
321template <class ABSTRACT, class IMPL, class SAMPLE>
322std::pair<index_t, chrono_t>
323SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::getCeilIndex( chrono_t iTime )
324{
325 return m_header->getTimeSampling()->getCeilIndex( iTime, m_numSamples );
326}
327
328//-*****************************************************************************
329template <class ABSTRACT, class IMPL, class SAMPLE>
330std::pair<index_t, chrono_t>
331SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::getNearIndex( chrono_t iTime )
332{
333 return m_header->getTimeSampling()->getNearIndex( iTime, m_numSamples );
334}
335
336//-*****************************************************************************
337template <class ABSTRACT, class IMPL, class SAMPLE>
338void
339SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::getSample( index_t iSampleIndex,
340 SAMPLE oSample )
341{
342 iSampleIndex = verifySampleIndex( iSampleIndex );
343
344 // Get our name.
345 const std::string &myName = m_header->getName();
346
347 if ( iSampleIndex == 0 )
348 {
349 // Read the sample from the parent group.
350 // Sample 0 is always on the parent group, with
351 // our name + ".smp0" as the name of it.
352 std::string sample0Name = getSampleName( myName, 0 );
353 if ( m_header->getPropertyType() == AbcA::kScalarProperty )
354 {
355 ABCA_ASSERT( AttrExists( m_parentGroup, sample0Name.c_str() ),
356 "Invalid property in SimplePrImpl getSample: "
357 << myName << ", missing smp0" );
358 }
359 else
360 {
361 ABCA_ASSERT( DatasetExists( m_parentGroup, sample0Name ),
362 "Invalid propertyin SimplePrImpl getSample: "
363 << myName << ", missing smp1" );
364 }
365
366 static_cast<IMPL *>( this )->readSample( m_parentGroup.getObject(),
367 sample0Name,
368 iSampleIndex,
369 oSample );
370 }
371 else
372 {
373 checkSamplesIGroup();
374
375 // Read the sample.
376 std::string sampleName = getSampleName( myName, iSampleIndex );
377 static_cast<IMPL *>( this )->readSample( m_samplesIGroup.getObject(),
378 sampleName,
379 iSampleIndex,
380 oSample );
381 }
382}
383
384//-*****************************************************************************
385template <class ABSTRACT, class IMPL, class SAMPLE>
386bool
387SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::getKey( index_t iSampleIndex,
388 AbcA::ArraySampleKey & oKey )
389{
390 iSampleIndex = verifySampleIndex( iSampleIndex );
391
392 // Get our name.
393 const std::string &myName = m_header->getName();
394
395 if ( iSampleIndex == 0 )
396 {
397 // Read the sample from the parent group.
398 // Sample 0 is always on the parent group, with
399 // our name + ".smp0" as the name of it.
400 std::string sample0Name = getSampleName( myName, 0 );
401 if ( m_header->getPropertyType() == AbcA::kScalarProperty )
402 {
403 ABCA_ASSERT( AttrExists( m_parentGroup, sample0Name.c_str() ),
404 "Invalid property in SimplePrImpl getKey: "
405 << myName << ", missing smp0" );
406 }
407 else
408 {
409 ABCA_ASSERT( DatasetExists( m_parentGroup, sample0Name ),
410 "Invalid property in SimplePrImpl getKey: "
411 << myName << ", missing smp1" );
412 }
413
414 return static_cast<IMPL *>( this )->readKey( m_parentGroup.getObject(),
415 sample0Name,
416 oKey );
417 }
418 else
419 {
420 checkSamplesIGroup();
421
422 // Read the sample.
423 std::string sampleName = getSampleName( myName, iSampleIndex );
424 return static_cast<IMPL*>( this )->readKey( m_samplesIGroup.getObject(),
425 sampleName,
426 oKey );
427 }
428}
429
430//-*****************************************************************************
431template <class ABSTRACT, class IMPL, class SAMPLE>
432SimplePrImpl<ABSTRACT,IMPL,SAMPLE>::~SimplePrImpl()
433{
434 // Clean up our samples group, if necessary.
435 CloseObject( m_samplesIGroup );
436
437 if ( m_fileDataType >= 0 && m_cleanFileDataType )
438 {
439 H5Tclose( m_fileDataType );
440 m_fileDataType = -1;
441 }
442
443 if ( m_nativeDataType >= 0 && m_cleanNativeDataType )
444 {
445 H5Tclose( m_nativeDataType );
446 m_nativeDataType = -1;
447 }
448}
449
450} // End namespace ALEMBIC_VERSION_NS
451
452using namespace ALEMBIC_VERSION_NS;
453
454} // End namespace AbcCoreHDF5
455} // End namespace Alembic
456
457#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