Coverage Report

Created: 2023-03-26 07:07

/src/alembic/lib/Alembic/AbcCoreOgawa/SpwImpl.cpp
Line
Count
Source (jump to first uncovered line)
1
//-*****************************************************************************
2
//
3
// Copyright (c) 2013,
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
#include <Alembic/AbcCoreOgawa/SpwImpl.h>
38
#include <Alembic/AbcCoreOgawa/CpwImpl.h>
39
#include <Alembic/AbcCoreOgawa/WriteUtil.h>
40
41
namespace Alembic {
42
namespace AbcCoreOgawa {
43
namespace ALEMBIC_VERSION_NS {
44
45
//-*****************************************************************************
46
SpwImpl::SpwImpl( AbcA::CompoundPropertyWriterPtr iParent,
47
                  Ogawa::OGroupPtr iGroup,
48
                  PropertyHeaderPtr iHeader,
49
                  size_t iIndex ) :
50
    m_parent( iParent ), m_header( iHeader ), m_group( iGroup ),
51
    m_index( iIndex )
52
0
{
53
0
    ABCA_ASSERT( m_parent, "Invalid parent" );
54
0
    ABCA_ASSERT( m_header, "Invalid property header" );
55
0
    ABCA_ASSERT( m_group, "Invalid group" );
56
57
0
    if ( m_header->header.getPropertyType() != AbcA::kScalarProperty )
58
0
    {
59
0
        ABCA_THROW( "Attempted to create a ScalarPropertyWriter from a "
60
0
                    "non-scalar property type" );
61
0
    }
62
0
}
63
64
65
//-*****************************************************************************
66
SpwImpl::~SpwImpl()
67
0
{
68
0
    AbcA::ArchiveWriterPtr archive = m_parent->getObject()->getArchive();
69
70
0
    index_t maxSamples = archive->getMaxNumSamplesForTimeSamplingIndex(
71
0
            m_header->timeSamplingIndex );
72
73
0
    Util::uint32_t numSamples = m_header->nextSampleIndex;
74
75
    // a constant property, we wrote the same sample over and over
76
0
    if ( m_header->lastChangedIndex == 0 && numSamples > 0 )
77
0
    {
78
0
        numSamples = 1;
79
0
    }
80
81
0
    if ( maxSamples < numSamples )
82
0
    {
83
0
        archive->setMaxNumSamplesForTimeSamplingIndex(
84
0
            m_header->timeSamplingIndex, numSamples );
85
0
    }
86
87
0
    Util::SpookyHash hash;
88
0
    hash.Init(0, 0);
89
0
    HashPropertyHeader( m_header->header, hash );
90
91
    // mix in the accumulated hash if we have samples
92
0
    if ( numSamples != 0 )
93
0
    {
94
0
        hash.Update( m_hash.d, 16 );
95
0
    }
96
97
0
    Util::uint64_t hash0, hash1;
98
0
    hash.Final( &hash0, &hash1 );
99
0
    Util::shared_ptr< CpwImpl > parent =
100
0
        Alembic::Util::dynamic_pointer_cast< CpwImpl,
101
0
            AbcA::CompoundPropertyWriter > ( m_parent );
102
0
    parent->fillHash( m_index, hash0, hash1 );
103
0
}
104
105
//-*****************************************************************************
106
void SpwImpl::setFromPreviousSample()
107
0
{
108
109
    // Make sure we aren't writing more samples than we have times for
110
    // This applies to acyclic sampling only
111
0
    ABCA_ASSERT(
112
0
        !m_header->header.getTimeSampling()->getTimeSamplingType().isAcyclic()
113
0
        || m_header->header.getTimeSampling()->getNumStoredTimes() >
114
0
        m_header->nextSampleIndex,
115
0
        "Can not set more samples than we have times for when using "
116
0
        "Acyclic sampling." );
117
118
0
    ABCA_ASSERT( m_header->nextSampleIndex > 0,
119
0
        "Can't set from previous sample before any samples have been written" );
120
121
0
    Util::Digest digest = m_previousWrittenSampleID->getKey().digest;
122
0
    Util::SpookyHash::ShortEnd(m_hash.words[0], m_hash.words[1],
123
0
                               digest.words[0], digest.words[1]);
124
0
    m_header->nextSampleIndex ++;
125
0
}
126
127
//-*****************************************************************************
128
void SpwImpl::setSample( const void *iSamp )
129
0
{
130
    // Make sure we aren't writing more samples than we have times for
131
    // This applies to acyclic sampling only
132
0
    ABCA_ASSERT(
133
0
        !m_header->header.getTimeSampling()->getTimeSamplingType().isAcyclic()
134
0
        || m_header->header.getTimeSampling()->getNumStoredTimes() >
135
0
        m_header->nextSampleIndex,
136
0
        "Can not write more samples than we have times for when using "
137
0
        "Acyclic sampling." );
138
139
0
    AbcA::ArraySample samp( iSamp, m_header->header.getDataType(),
140
0
                            AbcA::Dimensions(1) );
141
142
     // The Key helps us analyze the sample.
143
0
     AbcA::ArraySample::Key key = samp.getKey();
144
145
     // mask out the non-string POD since Ogawa can safely share the same data
146
     // even if it originated from a different POD
147
     // the non-fixed sizes of our strings (plus added null characters) makes
148
     // determing the sie harder so strings are handled seperately
149
0
    if ( key.origPOD != Alembic::Util::kStringPOD &&
150
0
         key.origPOD != Alembic::Util::kWstringPOD )
151
0
    {
152
0
        key.origPOD = Alembic::Util::kInt8POD;
153
0
        key.readPOD = Alembic::Util::kInt8POD;
154
0
    }
155
156
    // We need to write the sample
157
0
    if ( m_header->nextSampleIndex == 0  ||
158
0
        !( m_previousWrittenSampleID &&
159
0
            key == m_previousWrittenSampleID->getKey() ) )
160
0
    {
161
162
        // we only need to repeat samples if this is not the first change
163
0
        if (m_header->firstChangedIndex != 0)
164
0
        {
165
            // copy the samples from after the last change to the latest index
166
0
            for ( index_t smpI = m_header->lastChangedIndex + 1;
167
0
                smpI < m_header->nextSampleIndex; ++smpI )
168
0
            {
169
0
                assert( smpI > 0 );
170
0
                CopyWrittenData( m_group, m_previousWrittenSampleID );
171
0
            }
172
0
        }
173
174
        // Write this sample, which will update its internal
175
        // cache of what the previously written sample was.
176
0
        AbcA::ArchiveWriterPtr awp = this->getObject()->getArchive();
177
178
        // Write the sample.
179
        // This distinguishes between string, wstring, and regular arrays.
180
0
        m_previousWrittenSampleID =
181
0
            WriteData( GetWrittenSampleMap( awp ), m_group, samp, key );
182
183
0
        if (m_header->firstChangedIndex == 0)
184
0
        {
185
0
            m_header->firstChangedIndex = m_header->nextSampleIndex;
186
0
        }
187
        // this index is now the last change
188
0
        m_header->lastChangedIndex = m_header->nextSampleIndex;
189
0
    }
190
191
0
    if ( m_header->nextSampleIndex == 0 )
192
0
    {
193
0
        m_hash = m_previousWrittenSampleID->getKey().digest;
194
0
    }
195
0
    else
196
0
    {
197
0
        Util::Digest digest = m_previousWrittenSampleID->getKey().digest;
198
0
        Util::SpookyHash::ShortEnd( m_hash.words[0], m_hash.words[1],
199
0
                                    digest.words[0], digest.words[1] );
200
0
    }
201
202
0
    m_header->nextSampleIndex ++;
203
0
}
204
205
//-*****************************************************************************
206
AbcA::ScalarPropertyWriterPtr SpwImpl::asScalarPtr()
207
0
{
208
0
    return shared_from_this();
209
0
}
210
211
//-*****************************************************************************
212
size_t SpwImpl::getNumSamples()
213
0
{
214
0
    return ( size_t )m_header->nextSampleIndex;
215
0
}
216
217
//-*****************************************************************************
218
void SpwImpl::setTimeSamplingIndex( Util::uint32_t iIndex )
219
0
{
220
    // will assert if TimeSamplingPtr not found
221
0
    AbcA::TimeSamplingPtr ts =
222
0
        m_parent->getObject()->getArchive()->getTimeSampling( iIndex );
223
224
0
    ABCA_ASSERT( !ts->getTimeSamplingType().isAcyclic() ||
225
0
        ts->getNumStoredTimes() >= m_header->nextSampleIndex,
226
0
        "Already have written more samples than we have times for when using "
227
0
        "Acyclic sampling." );
228
229
0
    m_header->header.setTimeSampling(ts);
230
0
    m_header->timeSamplingIndex = iIndex;
231
0
}
232
233
//-*****************************************************************************
234
const AbcA::PropertyHeader & SpwImpl::getHeader() const
235
0
{
236
0
    ABCA_ASSERT( m_header, "Invalid header" );
237
0
    return m_header->header;
238
0
}
239
240
//-*****************************************************************************
241
AbcA::ObjectWriterPtr SpwImpl::getObject()
242
0
{
243
0
    ABCA_ASSERT( m_parent, "Invalid parent" );
244
0
    return m_parent->getObject();
245
0
}
246
247
//-*****************************************************************************
248
AbcA::CompoundPropertyWriterPtr SpwImpl::getParent()
249
0
{
250
0
    ABCA_ASSERT( m_parent, "Invalid parent" );
251
0
    return m_parent;
252
0
}
253
254
} // End namespace ALEMBIC_VERSION_NS
255
} // End namespace AbcCoreOgawa
256
} // End namespace Alembic