diff --git a/.gitsubprojects b/.gitsubprojects index 0bd1345..b24e18b 100644 --- a/.gitsubprojects +++ b/.gitsubprojects @@ -1,2 +1,2 @@ # -*- mode: cmake -*- -git_subproject(Servus https://github.com/HBPVIS/Servus.git 62873a5) +git_subproject(Servus https://github.com/HBPVIS/Servus.git 9fb8f08) diff --git a/bin/zerobufCxx.py b/bin/zerobufCxx.py index 96b8f0d..5ce450c 100755 --- a/bin/zerobufCxx.py +++ b/bin/zerobufCxx.py @@ -110,13 +110,34 @@ def get_data_type(self): return "uint32_t" if self.is_zerobuf_type or self.is_enum_type else self.type +class DoxygenDoc(): + """Doxygen documentation for C++ functions""" + def __init__(self, brief="", params=[], ret=""): + self.brief = brief + self.params = params + self.ret = ret + + def to_string(self): + dox = "/**" + NEXTLINE + for i in range(len(self.brief)): + dox += " * " + self.brief[i] + NEXTLINE + dox += " * " + NEXTLINE + for i in range(len(self.params)): + dox += " * @param " + self.params[i] + NEXTLINE + + if self.ret: + dox += " * @return " + self.ret + NEXTLINE + return dox + " **/" + + class Function(): """A C++ Function""" - - def __init__(self, ret_val, function, body, static=False, explicit=False, virtual=False, split=True): + def __init__(self, ret_val, function, body, doxygen=None, static=False, + explicit=False, virtual=False, split=True): self.ret_val = ret_val self.function = function self.body = body + self.doxygen = doxygen self.static = "static " if static else "" self.explicit = "explicit " if explicit else "" self.virtual = "virtual " if virtual else "" @@ -124,17 +145,22 @@ def __init__(self, ret_val, function, body, static=False, explicit=False, virtua def declaration(self): if self.ret_val: - return "{0}{1} {2} {{ {3} }}".format( self.static, self.ret_val, self.function, self.body ) + return "{0}{1} {2} {{ {3} }}".format( self.static, self.ret_val, + self.function, self.body ) # ctor '[initializer list]{ body }' - return "{0}{1}{2} {3}".format( self.virtual, self.explicit, self.function, self.body ) + return "{0}{1}{2} {3}".format( self.virtual, self.explicit, + self.function, self.body ) def definition(self): if self.ret_val: - return "{0}{1} {2};".format( self.static, self.ret_val, self.function, self.body ) + return "{0}{1} {2};".format( self.static, self.ret_val, + self.function, self.body ) # ctor '[initializer list]{ body }' return "{0}{1}{2};".format( self.virtual, self.explicit, self.function ) def write_declaration(self, file): + if self.doxygen: + file.write(NEXTLINE + self.doxygen.to_string()) if self.split_implementation: file.write(NEXTLINE + self.definition()) else: @@ -229,17 +255,22 @@ def ref_getter(self, classname=None): val_type = self.qualified_type(classname) if classname else self.get_cxxtype() return Function("{0}&".format(val_type), "get" + self.cxxName + "()", - "notifyChanging();" + NEXTLINE + - "return _{0};".format(self.cxxname)) + "return _{0};".format(self.cxxname), + DoxygenDoc(["Get a reference to the {0} dynamic member.".format(self.value_type.type), + "WARNING: If the reference is used to modify the object, " + + "notifyChanged() needs to be explicitly called afterwards."], + [], "a reference to the {0} dynamic member.".format(self.value_type.type))) def ref_setter(self, qproperty=False): current_value = "_{0}".format(self.cxxname) return Function("void", "set{0}( const {1}& value )".format(self.cxxName, self.get_cxxtype()), (self.check_value_changed(current_value) if qproperty else "") + - "notifyChanging();" + NEXTLINE + - "{0} = value;".format(current_value) + - self.emit_value_changed(qproperty)) + "{0} = value;".format(current_value) + NEXTLINE + + "notifyChanged();" + self.emit_value_changed(qproperty), + DoxygenDoc(["Set the value of the {0} member.".format(self.value_type.type), + "notifyChanged() is internally called after the change has been done."], + ["value the {0} value to be set in the current object".format(self.value_type.type)])) class FixedSizeMember(ClassMember): @@ -262,9 +293,11 @@ def value_setter(self, qproperty=False): return Function("void", "set{0}( {1} value )".format(self.cxxName, self.get_cxxtype()), (self.check_value_changed(current_value) if qproperty else "") + - "notifyChanging();" + NEXTLINE + - "{0} = value;".format(current_value) + - self.emit_value_changed(qproperty)) + "{0} = value;".format(current_value) + NEXTLINE + + "notifyChanged();" + self.emit_value_changed(qproperty), + DoxygenDoc(["Set the value of the {0} fixed size member.".format(self.value_type.type), + "notifyChanged() is internally called after the change has been done."], + ["value the {0} value to be set in the current object".format(self.value_type.type)])) def getters(self): if self.value_type.is_zerobuf_type: @@ -344,9 +377,12 @@ def size_getter(self): def ptr_getter(self): return Function(self.value_type.type + "*", "get" + self.cxxName + "()", - "notifyChanging();" + NEXTLINE + "return getAllocator().template getItemPtr< {0} >( {1} );".\ - format(self.value_type.type, self.allocator_offset)) + format(self.value_type.type, self.allocator_offset), + DoxygenDoc(["Get a pointer to the {0} fixed size array object.".format(self.value_type.type), + "WARNING: If the pointer is used to modify the object, " + + "notifyChanged() needs to be explicitly called afterwards."], + [], "a pointer to the {0} fixed size array object({0}*).".format(self.value_type.type))) def const_ptr_getter(self): return Function("const {0}*".format(self.value_type.type), @@ -366,10 +402,12 @@ def c_array_setter(self, qproperty=False): return Function("void", "set{0}( {1} value[ {2} ] )".format(self.cxxName, self.value_type.type, self.nElems), (self.check_array_changed(src_ptr) if qproperty else "") + - "notifyChanging();" + NEXTLINE + "::memcpy( {0}, {1}, {2} * sizeof( {3} ));".\ - format(self.data_ptr(), src_ptr, self.nElems, self.value_type.type) + - self.emit_value_changed(qproperty)) + format(self.data_ptr(), src_ptr, self.nElems, self.value_type.type) + NEXTLINE + + "notifyChanged();" + self.emit_value_changed(qproperty), + DoxygenDoc(["Set the value of the {0} fixed size array object from a {0}*.".format(self.value_type.type), + "notifyChanged() is internally called after the change has been done."], + ["value a {0}-length {1} array with the data to be set in the current object".format(self.nElems, self.value_type.type)])) def vector_setter(self, qproperty=False): src_ptr = "value.data()" @@ -378,10 +416,12 @@ def vector_setter(self, qproperty=False): "if( {0} < value.size( ))".format(self.nElems) + NEXTLINE + " return;" + NEXTLINE + (self.check_array_changed(src_ptr) if qproperty else "") + - "notifyChanging();" + NEXTLINE + "::memcpy( {0}, {1}, value.size() * sizeof( {3} ));".\ - format(self.data_ptr(), src_ptr, self.nElems, self.value_type.type) + - self.emit_value_changed(qproperty)) + format(self.data_ptr(), src_ptr, self.nElems, self.value_type.type) + NEXTLINE + + "notifyChanged();" + self.emit_value_changed(qproperty), + DoxygenDoc(["Set the value of the {0} fixed size array object from a {0} std::vector.".format(self.value_type.type), + "notifyChanged() is internally called after the change has been done."], + ["value a std::vector< {0} > with the data to be set in the current object".format(self.value_type.type)])) def getters(self): if self.value_type.is_zerobuf_type: @@ -561,13 +601,15 @@ def vector_dynamic_setter(self, qproperty=False): return Function("void", "set{0}( const {1}& value )".format(self.cxxName, self.vector_type()), (self.check_value_changed(current_value) if qproperty else "") + - "notifyChanging();" + NEXTLINE + "::zerobuf::Vector< {0} > dynamic( getAllocator(), {1} );".\ format(self.value_type.type, self.dynamic_type_index) + NEXTLINE + "dynamic.clear();" + NEXTLINE + "for( const " + self.value_type.type + "& data : value )" + NEXTLINE + - " dynamic.push_back( data );" + - self.emit_value_changed(qproperty)) + " dynamic.push_back( data );" + NEXTLINE + + "notifyChanged();" + self.emit_value_changed(qproperty), + DoxygenDoc(["Set the value of the {0} dynamic object from a {0} std::vector.".format(self.value_type.type), + "notifyChanged() is internally called after the change has been done."], + ["value a std::vector< {0} > object with the data to be set in the current object".format(self.value_type.type)])) def check_c_array_changed(self): return "if( ::memcmp( _{0}.data(), value, size * sizeof( {1} )) == 0 )".\ @@ -579,10 +621,13 @@ def c_pointer_setter(self, qproperty=False): "set{0}( {1} const * value, size_t size )".\ format(self.cxxName, self.value_type.type), (self.check_c_array_changed() if qproperty else "") + - "notifyChanging();" + NEXTLINE + "_copyZerobufArray( value, size * sizeof( {0} ), {1} );".\ - format(self.value_type.type, self.dynamic_type_index) + - self.emit_value_changed(qproperty)) + format(self.value_type.type, self.dynamic_type_index) + NEXTLINE + + "notifyChanged();" + self.emit_value_changed(qproperty), + DoxygenDoc(["Set the value of the {0} dynamic object from a {0}* and size.".format(self.value_type.type), + "notifyChanged() is internally called after the change has been done."], + ["value a pointer to the data to be set in the current object".format(self.value_type.type), + "size the size of the data to be set"])) def vector_pod_getter(self): return Function(self.vector_type(), @@ -595,10 +640,12 @@ def vector_pod_setter(self, qproperty=False): return Function("void", "set{0}( const {1}& value )".format(self.cxxName, self.vector_type()), (self.check_value_changed(current_value) if qproperty else "") + - "notifyChanging();" + NEXTLINE + "_copyZerobufArray( value.data(), value.size() * sizeof( {0} ), {1} );".\ - format(self.value_type.type, self.dynamic_type_index) + - self.emit_value_changed(qproperty)) + format(self.value_type.type, self.dynamic_type_index) + NEXTLINE + + "notifyChanged();" + self.emit_value_changed(qproperty), + DoxygenDoc(["Set the value of the {0} dynamic object from a {0} std::vector.".format(self.value_type.type), + "notifyChanged() is internally called after the change has been done."], + ["value a std::vector< {0} > object with the data to be set in the current object".format(self.value_type.type)])) def string_getter(self): return Function("std::string", @@ -613,10 +660,12 @@ def string_setter(self, qproperty=False): return Function("void", "set{0}( const std::string& value )".format(self.cxxName), (self.check_value_changed(current_value) if qproperty else "") + - "notifyChanging();" + NEXTLINE + "_copyZerobufArray( value.c_str(), value.length(), {0} );".\ - format(self.dynamic_type_index) + - self.emit_value_changed(qproperty)) + format(self.dynamic_type_index) + NEXTLINE + + "notifyChanged();" + self.emit_value_changed(qproperty), + DoxygenDoc(["Set the value of the {0} dynamic object from a std::string.".format(self.value_type.type), + "notifyChanged() is internally called after the change has been done."], + ["value a std::string with the data to be set in the current object"])) def getters(self): if self.value_type.is_zerobuf_type: # Dynamic array of (static) Zerobufs diff --git a/doc/Changelog.md b/doc/Changelog.md index 6a1aae5..7f80b6b 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -2,6 +2,8 @@ # git master +* [48](https://github.com/HBPVIS/ZeroBuf/pull/48): + Fix notifyUpdated usage. Generate doxygen documentation * [49](https://github.com/HBPVIS/ZeroBuf/pull/49): Added the exit event * [52](https://github.com/HBPVIS/ZeroBuf/pull/52): diff --git a/zerobuf/Vector.h b/zerobuf/Vector.h index 5373b31..71d286e 100644 --- a/zerobuf/Vector.h +++ b/zerobuf/Vector.h @@ -47,7 +47,7 @@ class Vector /** @return The pointer to the current allocation of the vector */ const T* data() const { return _alloc->template getDynamic< T >( _index ); } - /** @return true if the two vectors of buitins are identical. */ + /** @return true if the two vectors of builtins are identical. */ bool operator == ( const Vector& rhs ) const; /** @return false if the two vectors are identical. */ bool operator != ( const Vector& rhs ) const; diff --git a/zerobuf/Zerobuf.cpp b/zerobuf/Zerobuf.cpp index 10580e5..b7d78f7 100644 --- a/zerobuf/Zerobuf.cpp +++ b/zerobuf/Zerobuf.cpp @@ -30,7 +30,6 @@ Zerobuf::Zerobuf( AllocatorPtr alloc ) Zerobuf::Zerobuf( Zerobuf&& rhs ) { - rhs.notifyChanging(); _allocator = std::move( rhs._allocator ); rhs._allocator.reset( new NonMovingAllocator( rhs.getZerobufStaticSize(), rhs.getZerobufNumDynamics( ))); @@ -49,9 +48,9 @@ Zerobuf& Zerobuf::operator = ( const Zerobuf& rhs ) if( getTypeIdentifier() != rhs.getTypeIdentifier( )) throw std::runtime_error( "Can't assign Zerobuf of a different type" ); - notifyChanging(); _allocator->copyBuffer( rhs._allocator->getData(), rhs._allocator->getSize( )); + notifyChanged(); return *this; } @@ -63,9 +62,6 @@ Zerobuf& Zerobuf::operator = ( Zerobuf&& rhs ) if( getTypeIdentifier() != rhs.getTypeIdentifier( )) throw std::runtime_error( "Can't assign Zerobuf of a different type" ); - notifyChanging(); - rhs.notifyChanging(); - if( _allocator->isMovable() && rhs._allocator->isMovable( )) _allocator = std::move( rhs._allocator ); else // Sub allocator data can't be moved - need to copy @@ -73,7 +69,8 @@ Zerobuf& Zerobuf::operator = ( Zerobuf&& rhs ) rhs._allocator->getSize( )); rhs._allocator.reset( new NonMovingAllocator( rhs.getZerobufStaticSize(), - rhs.getZerobufNumDynamics( ))); + rhs.getZerobufNumDynamics())); + notifyChanged(); return *this; } @@ -103,8 +100,8 @@ bool Zerobuf::_fromBinary( const void* data, const size_t size ) return false; } - notifyChanging(); _allocator->copyBuffer( data, size ); + notifyChanged(); return true; } @@ -135,7 +132,6 @@ bool Zerobuf::_fromJSON( const std::string& string ) return false; } - notifyChanging(); _parseJSON( json ); compact(); return true; @@ -189,7 +185,6 @@ Allocator& Zerobuf::getAllocator() if( !_allocator ) throw std::runtime_error( "Empty Zerobuf has no allocator" ); - notifyChanging(); return *_allocator; } @@ -208,7 +203,6 @@ void Zerobuf::_copyZerobufArray( const void* data, const size_t size, throw std::runtime_error( "Can't copy data into empty Zerobuf object" ); - notifyChanging(); void* array = _allocator->updateAllocation( arrayNum, false /*no copy*/, size ); ::memcpy( array, data, size ); diff --git a/zerobuf/Zerobuf.h b/zerobuf/Zerobuf.h index b38b185..94465cb 100644 --- a/zerobuf/Zerobuf.h +++ b/zerobuf/Zerobuf.h @@ -34,9 +34,6 @@ class Zerobuf : public servus::Serializable /** @return the number of dynamics fields of this object. */ virtual size_t getZerobufNumDynamics() const = 0; - /** Called if any data in this object is about to change. */ - virtual void notifyChanging() {} - /** * Remove unused holes from the zerobuf. * @@ -73,6 +70,9 @@ class Zerobuf : public servus::Serializable ZEROBUF_API explicit Zerobuf( AllocatorPtr alloc ); // takes ownership of alloc ZEROBUF_API virtual ~Zerobuf(); + /** Called if any data in this object has changed. */ + ZEROBUF_API virtual void notifyChanged() {} + // used by generated ZeroBuf objects ZEROBUF_API const Allocator& getAllocator() const; ZEROBUF_API Allocator& getAllocator();