Skip to content

Commit dc8a603

Browse files
committed
Canceller : Remove implementation to .inl file
So that the public API fits easily onto a single screen, without being cluttered with implementation detail.
1 parent 2100fb4 commit dc8a603

File tree

2 files changed

+143
-80
lines changed

2 files changed

+143
-80
lines changed

include/IECore/Canceller.h

Lines changed: 13 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -76,91 +76,30 @@ class IECORE_API Canceller : public IECore::RefCounted
7676

7777
public :
7878

79-
Canceller()
80-
: m_cancelled( false ), m_cancellationTime( 0 )
81-
{
82-
}
79+
Canceller();
8380

8481
IE_CORE_DECLAREMEMBERPTR( Canceller )
8582

86-
void cancel()
87-
{
88-
// Store time of first cancellation. We use `compare_exchange_weak()`
89-
// to avoid unwanted updates on subsequent calls.
90-
std::chrono::steady_clock::rep epoch( 0 );
91-
m_cancellationTime.compare_exchange_weak(
92-
epoch,
93-
std::chrono::steady_clock::now().time_since_epoch().count()
94-
);
95-
// Set cancellation flag _after_ storing time, so that
96-
// `elapsedTime()` always sees a valid time.
97-
if( !m_cancelled.exchange( true ) )
98-
{
99-
std::lock_guard lock( m_childrenMutex );
100-
for( const auto &[child, count] : m_children )
101-
{
102-
child->cancel();
103-
}
104-
};
105-
}
106-
107-
bool cancelled() const
108-
{
109-
/// \todo Can we reduce overhead by reading
110-
/// with a more relaxed memory ordering here?
111-
return m_cancelled;
112-
}
83+
void cancel();
84+
bool cancelled() const;
11385

114-
static void check( const Canceller *canceller )
115-
{
116-
if( canceller && canceller->cancelled() )
117-
{
118-
throw Cancelled();
119-
}
120-
}
86+
/// Throws `IECore::Cancelled` if `canceller` is non-null and has
87+
/// been cancelled, otherwise does nothing.
88+
static void check( const Canceller *canceller );
12189

12290
/// Returns the time passed since `cancel()` was first called, or `0` if
12391
/// it has not been called yet.
124-
std::chrono::steady_clock::duration elapsedTime() const
125-
{
126-
if( m_cancelled )
127-
{
128-
return std::chrono::steady_clock::now() - std::chrono::steady_clock::time_point( std::chrono::steady_clock::duration( m_cancellationTime ) );
129-
}
130-
else
131-
{
132-
return std::chrono::steady_clock::duration( 0 );
133-
}
134-
}
92+
std::chrono::steady_clock::duration elapsedTime() const;
13593

13694
/// Adds a child canceller that will be cancelled automatically
13795
/// when this is cancelled. If this is already cancels, then the
13896
/// child is cancelled immediately.
139-
void addChild( const Ptr &child )
140-
{
141-
std::lock_guard lock( m_childrenMutex );
142-
m_children[child]++;
143-
if( m_cancelled )
144-
{
145-
child->cancel();
146-
}
147-
}
97+
void addChild( const Ptr &child );
14898

14999
/// Removes a child canceller. Additions are counted, and actual
150100
/// removal only occurs when the number of removals equals the number
151101
/// of additions.
152-
void removeChild( const Ptr &child )
153-
{
154-
std::lock_guard lock( m_childrenMutex );
155-
auto it = m_children.find( child );
156-
if( it != m_children.end() )
157-
{
158-
if( --it->second == 0 )
159-
{
160-
m_children.erase( it );
161-
}
162-
}
163-
}
102+
void removeChild( const Ptr &child );
164103

165104
/// Convenience class to manage removal of children in an
166105
/// exception-safe way.
@@ -170,17 +109,9 @@ class IECORE_API Canceller : public IECore::RefCounted
170109
public :
171110

172111
/// Adds `child` to `parent`.
173-
ScopedChild( Canceller *parent, const Ptr &child )
174-
: m_parent( parent ), m_child( child )
175-
{
176-
m_parent->addChild( m_child );
177-
}
178-
112+
ScopedChild( Canceller *parent, const Ptr &child );
179113
/// Removes `child` from `parent`.
180-
~ScopedChild()
181-
{
182-
m_parent->removeChild( m_child );
183-
}
114+
~ScopedChild();
184115

185116
private :
186117

@@ -204,4 +135,6 @@ IE_CORE_DECLAREPTR( Canceller )
204135

205136
}; // namespace IECore
206137

138+
#include "IECore/Canceller.inl"
139+
207140
#endif // IECORE_CANCELLER_H

include/IECore/Canceller.inl

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
//////////////////////////////////////////////////////////////////////////
2+
//
3+
// Copyright (c) 2018, Image Engine Design Inc. All rights reserved.
4+
//
5+
// Redistribution and use in source and binary forms, with or without
6+
// modification, are permitted provided that the following conditions are
7+
// met:
8+
//
9+
// * Redistributions of source code must retain the above copyright
10+
// notice, this list of conditions and the following disclaimer.
11+
//
12+
// * Redistributions in binary form must reproduce the above copyright
13+
// notice, this list of conditions and the following disclaimer in the
14+
// documentation and/or other materials provided with the distribution.
15+
//
16+
// * Neither the name of Image Engine Design nor the names of any
17+
// other contributors to this software may be used to endorse or
18+
// promote products derived from this software without specific prior
19+
// written permission.
20+
//
21+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22+
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23+
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24+
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
25+
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26+
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27+
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28+
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29+
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30+
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31+
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32+
//
33+
//////////////////////////////////////////////////////////////////////////
34+
35+
#ifndef IECORE_CANCELLER_INL
36+
#define IECORE_CANCELLER_INL
37+
38+
namespace IECore
39+
{
40+
41+
inline Canceller::Canceller()
42+
: m_cancelled( false ), m_cancellationTime( 0 )
43+
{
44+
}
45+
46+
inline void Canceller::cancel()
47+
{
48+
// Store time of first cancellation. We use `compare_exchange_weak()`
49+
// to avoid unwanted updates on subsequent calls.
50+
std::chrono::steady_clock::rep epoch( 0 );
51+
m_cancellationTime.compare_exchange_weak(
52+
epoch,
53+
std::chrono::steady_clock::now().time_since_epoch().count()
54+
);
55+
// Set cancellation flag _after_ storing time, so that
56+
// `elapsedTime()` always sees a valid time.
57+
if( !m_cancelled.exchange( true ) )
58+
{
59+
std::lock_guard lock( m_childrenMutex );
60+
for( const auto &[child, count] : m_children )
61+
{
62+
child->cancel();
63+
}
64+
};
65+
}
66+
67+
inline bool Canceller::cancelled() const
68+
{
69+
/// \todo Can we reduce overhead by reading
70+
/// with a more relaxed memory ordering here?
71+
return m_cancelled;
72+
}
73+
74+
inline void Canceller::check( const Canceller *canceller )
75+
{
76+
if( canceller && canceller->cancelled() )
77+
{
78+
throw Cancelled();
79+
}
80+
}
81+
82+
inline std::chrono::steady_clock::duration Canceller::elapsedTime() const
83+
{
84+
if( m_cancelled )
85+
{
86+
return std::chrono::steady_clock::now() - std::chrono::steady_clock::time_point( std::chrono::steady_clock::duration( m_cancellationTime ) );
87+
}
88+
else
89+
{
90+
return std::chrono::steady_clock::duration( 0 );
91+
}
92+
}
93+
94+
inline void Canceller::addChild( const Ptr &child )
95+
{
96+
std::lock_guard lock( m_childrenMutex );
97+
m_children[child]++;
98+
if( m_cancelled )
99+
{
100+
child->cancel();
101+
}
102+
}
103+
104+
inline void Canceller::removeChild( const Ptr &child )
105+
{
106+
std::lock_guard lock( m_childrenMutex );
107+
auto it = m_children.find( child );
108+
if( it != m_children.end() )
109+
{
110+
if( --it->second == 0 )
111+
{
112+
m_children.erase( it );
113+
}
114+
}
115+
}
116+
117+
inline Canceller::ScopedChild::ScopedChild( Canceller *parent, const Ptr &child )
118+
: m_parent( parent ), m_child( child )
119+
{
120+
m_parent->addChild( m_child );
121+
}
122+
123+
inline Canceller::ScopedChild::~ScopedChild()
124+
{
125+
m_parent->removeChild( m_child );
126+
}
127+
128+
}; // namespace IECore
129+
130+
#endif // IECORE_CANCELLER_INL

0 commit comments

Comments
 (0)