Skip to content

Commit 1f8b082

Browse files
committed
fixes #488 - allow StructMeta copyFrom / deepcopyFrom / updateFrom to work on base types as well
Signed-off-by: Rob Ambalu <[email protected]>
1 parent c11cf7c commit 1f8b082

File tree

3 files changed

+65
-16
lines changed

3 files changed

+65
-16
lines changed

cpp/csp/engine/Struct.cpp

+39-16
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,22 @@ bool StructMeta::isDerivedType( const StructMeta * derived, const StructMeta * b
201201
return b != nullptr;
202202
}
203203

204+
const StructMeta * StructMeta::commonBase( const StructMeta * x, const StructMeta * y )
205+
{
206+
const StructMeta * m = x;
207+
while( m && m != y )
208+
m = m -> m_base.get();
209+
210+
if( !m )
211+
{
212+
m = y;
213+
while( m && m != x )
214+
m = m -> m_base.get();
215+
}
216+
return m;
217+
218+
}
219+
204220
void StructMeta::initialize( Struct * s ) const
205221
{
206222
//TODO optimize initialize to use default if availbel instead of constructing
@@ -231,25 +247,29 @@ void StructMeta::copyFrom( const Struct * src, Struct * dest )
231247
if( unlikely( src == dest ) )
232248
return;
233249

234-
if( dest -> meta() != src -> meta() &&
235-
!StructMeta::isDerivedType( src -> meta(), dest -> meta() ) )
236-
CSP_THROW( TypeError, "Attempting to copy from struct type '" << src -> meta() -> name() << "' to struct type '" << dest -> meta() -> name()
237-
<< "'. copy_from may only be used to copy from same type or derived types" );
250+
const StructMeta * meta = commonBase( src -> meta(), dest -> meta() );
251+
if( !meta )
252+
{
253+
CSP_THROW( TypeError, "Attempting to copy from struct type '" << src -> meta() -> name() << "' to struct type '" << dest -> meta() -> name()
254+
<< "'. copy_from may only be used to copy from struct with a common base type" );
255+
}
238256

239-
dest -> meta() -> copyFromImpl( src, dest, false );
257+
meta -> copyFromImpl( src, dest, false );
240258
}
241259

242260
void StructMeta::deepcopyFrom( const Struct * src, Struct * dest )
243261
{
244262
if( unlikely( src == dest ) )
245263
return;
246264

247-
if( dest -> meta() != src -> meta() &&
248-
!StructMeta::isDerivedType( src -> meta(), dest -> meta() ) )
249-
CSP_THROW( TypeError, "Attempting to deepcopy from struct type '" << src -> meta() -> name() << "' to struct type '" << dest -> meta() -> name()
250-
<< "'. deepcopy_from may only be used to copy from same type or derived types" );
251-
252-
dest -> meta() -> copyFromImpl( src, dest, true );
265+
const StructMeta * meta = commonBase( src -> meta(), dest -> meta() );
266+
if( !meta )
267+
{
268+
CSP_THROW( TypeError, "Attempting to deepcopy from struct type '" << src -> meta() -> name() << "' to struct type '" << dest -> meta() -> name()
269+
<< "'. deepcopy_from may only be used to copy from struct with a common base type" );
270+
}
271+
272+
meta -> copyFromImpl( src, dest, true );
253273
}
254274

255275
void StructMeta::copyFromImpl( const Struct * src, Struct * dest, bool deepcopy ) const
@@ -291,12 +311,15 @@ void StructMeta::updateFrom( const Struct * src, Struct * dest )
291311
if( unlikely( src == dest ) )
292312
return;
293313

294-
if( dest -> meta() != src -> meta() &&
295-
!StructMeta::isDerivedType( src -> meta(), dest -> meta() ) )
296-
CSP_THROW( TypeError, "Attempting to update from struct type '" << src -> meta() -> name() << "' to struct type '" << dest -> meta() -> name()
297-
<< "'. update_from may only be used to update from same type or derived types" );
314+
const StructMeta * meta = commonBase( src -> meta(), dest -> meta() );
315+
316+
if( !meta )
317+
{
318+
CSP_THROW( TypeError, "Attempting to update from struct type '" << src -> meta() -> name() << "' to struct type '" << dest -> meta() -> name()
319+
<< "'. update_from may only be used to update from struct with a common base type" );
320+
}
298321

299-
dest -> meta() -> updateFromImpl( src, dest );
322+
meta -> updateFromImpl( src, dest );
300323
}
301324

302325
void StructMeta::updateFromImpl( const Struct * src, Struct * dest ) const

cpp/csp/engine/Struct.h

+1
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,7 @@ class StructMeta : public std::enable_shared_from_this<StructMeta>
634634

635635
//returns true if derived == base or if derived is a derived type of base
636636
static bool isDerivedType( const StructMeta * derived, const StructMeta * base );
637+
static const StructMeta * commonBase( const StructMeta * x, const StructMeta * y );
637638

638639
template<typename T>
639640
std::shared_ptr<typename StructField::upcast<T>::type> getMetaField( const char * fieldname, const char * expectedtype );

csp/tests/impl/test_struct.py

+25
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,15 @@ def test_copy_from(self):
692692
for key in blank.metadata().keys():
693693
self.assertEqual(getattr(blank, key), getattr(source, key), (typ, typ2, key))
694694

695+
# Test other direction ( derived copy from base )
696+
blank = typ2()
697+
source = typ()
698+
for key in typ.metadata().keys():
699+
setattr(source, key, values[key])
700+
blank.copy_from( source )
701+
for key in source.metadata().keys():
702+
self.assertEqual(getattr(blank, key), getattr(source, key), (typ, typ2, key))
703+
695704
def test_copy_from_unsets(self):
696705
source = DerivedMixed(i=1, f=2.3, i2=4, s2="woodchuck")
697706
dest1 = DerivedMixed(i=5, b=True, l2=[1, 2, 3])
@@ -712,6 +721,14 @@ def test_copy_from_unsets(self):
712721
self.assertFalse(hasattr(dest2, "s")) # unsets
713722
self.assertFalse(hasattr(dest2, "a1"))
714723

724+
# from base class -> derived
725+
dest3 = DerivedMixed()
726+
dest3.copy_from(dest2)
727+
self.assertTrue(dest3.i == 1) # overrides already set value
728+
self.assertTrue(dest3.f == 2.3) # adds
729+
self.assertTrue(dest3.s == "banana") # no unsets
730+
self.assertTrue(dest3.a1 == [4, 5, 6])
731+
715732
def test_deepcopy_from(self):
716733
source = StructWithLists(
717734
struct_list=[BaseNative(i=123)], fast_list=[BaseNative(i=123)], dialect_generic_list=[{"a": 1}]
@@ -751,6 +768,14 @@ def test_update_from(self):
751768
self.assertTrue(dest2.s == "banana") # no unsets
752769
self.assertTrue(dest2.a1 == [4, 5, 6])
753770

771+
# update from base class
772+
dest3 = DerivedMixed()
773+
dest3.update_from(dest2)
774+
self.assertTrue(dest3.i == 1) # overrides already set value
775+
self.assertTrue(dest3.f == 2.3) # adds
776+
self.assertTrue(dest3.s == "banana") # no unsets
777+
self.assertTrue(dest3.a1 == [4, 5, 6])
778+
754779
def test_update(self):
755780
dest = DerivedMixed(i2=5, b=True, l2=[1, 2, 3], s="foo")
756781
dest.update(f2=5.5, s2="bar")

0 commit comments

Comments
 (0)