Commit d7a28eda authored by Quentin Khan's avatar Quentin Khan

Clean up F(Mpi)Buffer{Writer,Reader} implementation

The classes FMpiBufferWriter and FBufferWriter implemented the same
functionality, FMpiBufferReader and FBufferReader did too. This replaces
the FBuffer implementations with the FMpiBuffer ones.

Steps taken:
  - remove FBuffer* implementation
  - rename FMpiBuffer* to FBuffer*
  - clean up code and documentation
  - fix missing includes

A few unused variables warnings are fixed in FAbstractBuffer.hpp.

There was a discrepancy in the getSize method of F(Mpi)BufferReader. The
behaviour of FMpiBufferReader is kept and the unit test is modified.
parent 06958c84
......@@ -24,7 +24,7 @@
/**
* @brief The FAbstractBufferReader class defines what is an abstract buffer reader.
* The buffer used by the mpi algorithm for example should defines this methods.
* The buffer used by the mpi algorithm for example should define this methods.
*/
class FAbstractBufferReader {
public:
......@@ -60,7 +60,7 @@ public:
/**
* @brief The FAbstractBufferWriter class defines what is an abstract buffer writer.
* The buffer used by the mpi algorithm for example should defines this methods.
* The buffer used by the mpi algorithm for example should define this methods.
*/
class FAbstractBufferWriter {
public:
......@@ -73,15 +73,15 @@ public:
virtual void reset() = 0;
template <class ClassType>
void write(const ClassType& object){
void write(const ClassType& /*object*/){
static_assert(sizeof(ClassType) == 0, "Your Buffer should implement write.");
}
template <class ClassType>
void writeAt(const FSize position, const ClassType& object){
void writeAt(const FSize /*position*/, const ClassType& /*object*/){
static_assert(sizeof(ClassType) == 0, "Your Buffer should implement writeAt.");
}
template <class ClassType>
void write(const ClassType* const objects, const FSize inSize){
void write(const ClassType* const /*objects*/, const FSize /*inSize*/){
static_assert(sizeof(ClassType) == 0, "Your Buffer should implement write.");
}
template <class ClassType>
......
......@@ -20,98 +20,217 @@
#ifndef FBUFFERREADER_HPP
#define FBUFFERREADER_HPP
#include "FVector.hpp"
#include <memory>
#include "FAbstractBuffer.hpp"
#include "../Utils/FAssert.hpp"
/** @author Berenger Bramas
* This class provide a fast way to manage a memory and convert
* the content to basic type.
/**
* \brief Provides memory management and conversion to basic type
* \author Cyrille Piacibello, Berenger Bramas, Quentin Khan
*
* Specifie the needed space with reserve, then fill it with data
* finaly read and convert.
* This class is meant to ease data deserialisation through external libraries
* such as MPI.
*
* - Reserve memory.
* - Pass the data() pointer the the library that will fill the buffer.
* - Read using the getValue, fillValue, fillArray methods.
*
* An internal index is kept to know what data has been read.
*/
class FBufferReader : public FAbstractBufferReader {
FVector<char> buffer; //< The memory buffer
FSize index; //< The current index reading position
FSize arrayCapacity; ///< Allocated space
std::unique_ptr<char[]> array; ///< Allocated array
FSize currentIndex; ///< First unread byte
public :
/**
* \brief Construct the reader
*
* \param capacity Buffer capacity in bytes
*/
explicit FBufferReader(const FSize capacity = 512)
: arrayCapacity(capacity),
array(new char[capacity]),
currentIndex(0)
{
FAssertLF(array, "Cannot allocate array");
}
public:
/** Construct with a memory size init to 0 */
explicit FBufferReader(const FSize inCapacity = 0) : buffer(inCapacity), index(0) {
if(inCapacity){
reserve(inCapacity);
virtual ~FBufferReader() = default;
/**
* \brief Discard current buffer and allocate a new one if needed
*
* The read data index is reset.
*
* \param capacity New buffer capacity
*/
void cleanAndResize(const FSize capacity) {
if(capacity != arrayCapacity){
arrayCapacity = capacity;
array.reset(new char[capacity]);
}
currentIndex = 0;
}
/** Destructor */
virtual ~FBufferReader() override {
/**
* \brief Reserve memory if needed, existing data is copied
*
* If the current capacity is enough, this operation is a no-op. Otherwise a
* new buffer is allocated and data is copied from the old buffer before
* discarding it.
*
* \param newCapacity Required minimal capacity
*/
void reserve(const FSize newCapacity) {
if(newCapacity > arrayCapacity) {
std::unique_ptr<char[]> new_array(new char[newCapacity]);
// The array is modified outside the class, we don't know what must
// be copied or not : we copy everything
std::copy(array.get(), array.get()+arrayCapacity, new_array.get());
array = std::move(new_array);
arrayCapacity = newCapacity;
}
}
/** Get the memory area */
/**
* \brief Get pointer to allocated memory
*/
char* data() override {
return buffer.data();
return array.get();
}
/** Get the memory area */
/**
* \brief Get pointer to allocated memory
*/
const char* data() const override {
return buffer.data();
return array.get();
}
/** Size of the meomry initialzed */
/**
* \brief Return already deserialised data size in bytes
*
* \return The size of the subpart of the buffer that has already been
* deserialised.
*/
FSize getSize() const override {
return buffer.getSize();
return currentIndex;
}
/** Move the read index to a position */
void seek(const FSize inIndex) override {
index = inIndex;
/**
* \brief Return the allocated buffer capacity in bytes
*/
FSize getCapacity() const{
return arrayCapacity;
}
/** Get the read position */
FSize tell() const override {
return index;
/**
* \brief Move the read index to a position
*
* \param index Position from the beginning of the buffer to move the read
* index to.
*/
void seek(const FSize index) override {
FAssertLF(index <= arrayCapacity,
"FBufferReader :: can't move index because buffer isn't ",
"long enough ", index, " ", arrayCapacity);
currentIndex = index;
}
/** Reset and allocate nbBytes memory filled with 0 */
void reserve(const FSize nbBytes){
reset();
buffer.set( 0, nbBytes);
/**
* \brief Get the read index value
*/
FSize tell() const override {
return currentIndex;
}
/** Move the read index to 0 */
void reset(){
buffer.clear();
index = 0;
/**
* \brief Deserialise an object at read index
*
* The object is byte copied into a new instance of T which is returned by
* value.
*
* The read index is incremented by sizeof(T).
*
* \tparam T Type of the object to deserialise
*/
template <class T>
T getValue(){
FAssertLF(currentIndex + FSize(sizeof(T)) <= arrayCapacity,
"The buffer does not have enough remaining memory to read a ",
" value of given type");
T value;
fillValue<T>(&value);
return value;
}
/** Get a value with memory cast */
template <class ClassType>
ClassType getValue(){
ClassType value = (*reinterpret_cast<ClassType*>(&buffer[index]));
index += FSize(sizeof(ClassType));
return value;
/**
* \brief Deserialise an object at a specified index
*
* The object is byte copied into a new instance of T which is returned by
* value.
*
* The read index is changed to `index + sizeof(T)`.
*
* \tparam T Type of the object to deserialise
*
* \param index Position of the object
*/
template <class T>
T getValue(const FSize index){
seek(index);
return getValue<T>();
}
/** Fill a value with memory cast */
template <class ClassType>
void fillValue(ClassType* const inValue){
(*inValue) = (*reinterpret_cast<ClassType*>(&buffer[index]));
index += FSize(sizeof(ClassType));
/**
* \brief Deserialise an object to given address
*
* Equivalent to `fillArray(ptr, 1)`.
*
* \tparam T Type of the object to deserialise
*
* \param ptr Pointer to the object to copy to
*/
template <class T>
void fillValue(T* const ptr){
fillArray(ptr, 1);
}
/** Fill one/many value(s) with memcpy */
template <class ClassType>
void fillArray(ClassType* const inArray, const FSize inSize){
memcpy( inArray, &buffer[index], sizeof(ClassType) * inSize);
index += FSize(sizeof(ClassType) * inSize);
/**
* \brief Deserialise contiguous values
*
* The objects are byte copied to the array pointed to by inArray.
*
* The read index is incremented by `count * sizeof(T)`
*
* \tparam T Type of the object to deserialise
*
* \param inArray Array of objects to copy the values to
* \param count Object count in the array
*/
template <class T>
void fillArray(T* const inArray, const FSize count){
FAssertLF(currentIndex + FSize(sizeof(T))*count <= arrayCapacity );
memcpy(inArray, &array[currentIndex], sizeof(T)*count);
currentIndex += sizeof(T)*count;
}
/** Same as fillValue */
template <class ClassType>
FBufferReader& operator>>(ClassType& object){
/**
* \brief Stream-like deserialisation
*
* See fillArray.
*
* \tparam T Type of the object to deserialise
*
* \param object Object to deserialise to
*/
template <class T>
FBufferReader& operator>>(T& object){
fillValue(&object);
return *this;
}
};
#endif // FBUFFERREADER_HPP
};
#endif
......@@ -20,73 +20,168 @@
#ifndef FBUFFERWRITER_HPP
#define FBUFFERWRITER_HPP
#include "FVector.hpp"
#include <memory>
#include "FAbstractBuffer.hpp"
#include "../Utils/FAssert.hpp"
/** @author Berenger Bramas
* This class provide a fast way to manage a memory and fill it
/**
* \brief Provides memory management and byte serialisation
* \author Cyrille Piacibello, Berenger Bramas, Quentin Khan
*
* Put some data
* then insert back if needed
* finaly use data pointer as you like
* This class is meant to ease data byte serialisation to pass through external
* libraries such as MPI.
*
* - Reserve memory.
* - Insert objects.
* - Pass data() pointer to the library.
*
* An internal index is kept to know how much data has been written.
*/
class FBufferWriter : public FAbstractBufferWriter {
private:
FVector<char> buffer; //< The buffer
FSize arrayCapacity; ///< Allocated space
std::unique_ptr<char[]> array; ///< Allocated array
FSize currentIndex; ///< Currently filled space
/**
* \brief Ensure minimum remaining space in the buffer
*
* This methods checks whether there is at least min_rem_cap space left in
* the buffer. If not, a new buffer is allocated and the old data is copied
* into the new one.
*
* \param min_rem_cap Minimum remaining space in the buffer
*/
void expandIfNeeded(const FSize min_rem_cap) {
if( arrayCapacity < currentIndex + min_rem_cap){
arrayCapacity = FSize(double(currentIndex + min_rem_cap + 1) * 1.5);
char* arrayTmp = new char[arrayCapacity];
std::copy(array.get(), array.get()+currentIndex, arrayTmp);
array.reset(arrayTmp);
}
}
public:
/** Constructor with a default capacity of 512 bytes */
explicit FBufferWriter(const FSize inCapacity = 512) : buffer(inCapacity) {
/**
* \brief Construct the writer
*
* \param capacity Buffer capacity in bytes
*/
explicit FBufferWriter(const FSize capacity = 1024)
: arrayCapacity(capacity),
array(new char[capacity]),
currentIndex(0)
{
FAssertLF(array, "Cannot allocate array");
}
/** Destructor */
virtual ~FBufferWriter(){
virtual ~FBufferWriter() = default;
/**
* \brief Change buffer capacity and copy existing data to the new buffer
*
* If write index is bigger than new_capacity, the extra data is lost and
* the write index is changed accordingly.
*/
void resize(const FSize new_capacity){
if(new_capacity != arrayCapacity){
arrayCapacity = new_capacity;
char* arrayTmp = new char[arrayCapacity];
currentIndex = (currentIndex < arrayCapacity ? currentIndex : arrayCapacity-1);
std::copy(array.get(), array.get()+currentIndex, arrayTmp);
array.reset(arrayTmp);
}
}
/** Get allocated memory pointer */
char* data(){
return buffer.data();
/**
* \brief Reset the write index
*
* Subsequent writes will overwrite the buffer.
*/
void reset() override {
currentIndex = 0;
}
/** Get allocated memory pointer */
const char* data() const {
return buffer.data();
/**
* \brief Get pointer to allocated memory
*/
char* data() override {
return array.get();
}
/** Get the filled space */
FSize getSize() const {
return buffer.getSize();
/**
* \brief Get pointer to allocated memory
*/
const char* data() const override {
return array.get();
}
/** Write data by mem cpy */
/**
* \brief Return the written memory size
*/
FSize getSize() const override {
return currentIndex;
}
/**
* \brief Return the allocated buffer capacity in bytes
*/
FSize getCapacity() const {
return arrayCapacity;
}
/**
* \brief Byte copy an object in the buffer
*
* The write index is increased by `sizeof(ClassType)`
*
* \tparam ClassType Type of the object to write
*
* \param object Object to write to the buffer
*/
template <class ClassType>
void write(const ClassType& object){
buffer.memocopy(reinterpret_cast<const char*>(&object), FSize(sizeof(ClassType)));
void write(const ClassType& object) {
write(&object, 1);
}
/** Write back, position + sizeof(object) has to be < size */
/**
* \brief Byte copy an object at given position in the buffer
*
* \tparam ClassType Type of the object to write
*
* \param object Object to write to the buffer
*/
template <class ClassType>
void writeAt(const FSize position, const ClassType& object){
(*reinterpret_cast<ClassType*>(&buffer[position])) = object;
FAssertLF(position+FSize(sizeof(ClassType)) <= currentIndex);
memcpy(&array[position], &object, sizeof(ClassType));
}
/** Write an array */
/**
* \brief Byte copy contiguous objects to the buffer
*
* \tparam ClassType Type of the object to write
*
* \param objects Array of objects to write
* \param count Object count in the array
*/
template <class ClassType>
void write(const ClassType* const objects, const FSize inSize){
buffer.memocopy(reinterpret_cast<const char*>(objects), FSize(sizeof(ClassType)) * inSize);
expandIfNeeded(sizeof(ClassType) * inSize);
memcpy(&array[currentIndex], objects, sizeof(ClassType)*inSize);
currentIndex += sizeof(ClassType)*inSize;
}
/** Equivalent to write */
/**
* \brief Stream-like serialisation
*
* \tparam ClassType Type of the object to write
*/
template <class ClassType>
FBufferWriter& operator<<(const ClassType& object){
write(object);
return *this;
}
/** Reset the writing index, but do not change the capacity */
void reset(){
buffer.clear();
}
};
......
// ===================================================================================
// Copyright ScalFmm 2016 INRIA, Olivier Coulaud, Bérenger Bramas,
// Matthias Messner olivier.coulaud@inria.fr, berenger.bramas@inria.fr
// This software is a computer program whose purpose is to compute the
// FMM.
//
// This software is governed by the CeCILL-C and LGPL licenses and
// abiding by the rules of distribution of free software.
// An extension to the license is given to allow static linking of scalfmm
// inside a proprietary application (no matter its license).
// See the main license file for more details.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public and CeCILL-C Licenses for more details.
// "http://www.cecill.info".
// "http://www.gnu.org/licenses".
// ===================================================================================
#ifndef FMPIBUFFERREADER_HPP
#define FMPIBUFFERREADER_HPP
#include <memory>
#include "../Utils/FMpi.hpp"
#include "FAbstractBuffer.hpp"
#include "../Utils/FAssert.hpp"
/** @author Cyrille Piacibello, Berenger Bramas
* This class provide the same features as FBufferWriter
*
* Put some data
* then insert back if needed
* finally use data pointer as you like
*/
class FMpiBufferReader : public FAbstractBufferReader {
FSize arrayCapacity; //< Allocated space
std::unique_ptr<char[]> array; //< Allocated Array
FSize currentIndex;
public :
/*Constructor with a default arrayCapacity of 512 bytes */
explicit FMpiBufferReader(const FSize inDefaultCapacity = 512):
arrayCapacity(inDefaultCapacity),
array(new char[inDefaultCapacity]),
currentIndex(0){
FAssertLF(array, "Cannot allocate array");
}
/** To change the capacity (but reset the head to 0) */
void cleanAndResize(const FSize newCapacity){
if(newCapacity != arrayCapacity){
arrayCapacity = newCapacity;
array.reset(new char[newCapacity]);
}
currentIndex = 0;
}
/** Destructor
*/
virtual ~FMpiBufferReader(){
}
/** Get allocated memory pointer */
char* data() override {
return array.get();
}
/** Get allocated memory pointer */
const char* data() const override {
return array.get();
}
/** get the filled space */
FSize getSize() const override {
return currentIndex;
}
/** Size of the memory initialized */
FSize getCapacity() const{
return arrayCapacity;
}
/** Move the read index to a position */
void seek(const FSize inIndex) override {
FAssertLF(inIndex <= arrayCapacity, "FMpiBufferReader :: Aborting :: Can't move index because buffer isn't long enough ",inIndex," ",arrayCapacity);
currentIndex = inIndex;
}
/** Get the read position */
FSize tell() const override {
return currentIndex;
}
/** Get a value with memory cast */
template <class ClassType>
ClassType getValue(){
FAssertLF(currentIndex + FSize(sizeof(ClassType)) <= arrayCapacity );
ClassType value;
memcpy(&value, &array[currentIndex], sizeof(ClassType));
currentIndex += sizeof(ClassType);
return value;
}
/** Get a value with memory cast at a specified index */
template <class ClassType>
ClassType getValue(const FSize ind){
currentIndex = ind;
return getValue<ClassType>();
}
/** Fill a value with memory cast */
template <class ClassType>
void fillValue(ClassType* const inValue){
FAssertLF(currentIndex + FSize(sizeof(ClassType)) <= arrayCapacity );
memcpy(inValue, &array[currentIndex], sizeof(ClassType));
currentIndex += sizeof(ClassType);
}
/** Fill one/many value(s) with memcpy */
template <class ClassType>
void fillArray(ClassType* const inArray, const FSize inSize){
FAssertLF(currentIndex + FSize(sizeof(ClassType))*inSize <= arrayCapacity );
memcpy(inArray, &array[currentIndex], sizeof(ClassType)*inSize);
currentIndex += sizeof(ClassType)*inSize;
}
/** Same as fillValue */
template <class ClassType>
FMpiBufferReader& operator>>(ClassType& object){
fillValue(&object);
return *this;
}
};
#endif
// ===================================================================================
// Copyright ScalFmm 2016 INRIA, Olivier Coulaud, Bérenger Bramas,
// Matthias Messner olivier.coulaud@inria.fr, berenger.bramas@inria.fr
// This software is a computer program whose purpose is to compute the
// FMM.
//
// This software is governed by the CeCILL-C and LGPL licenses and
// abiding by the rules of distribution of free software.
// An extension to the license is given to allow static linking of scalfmm
// inside a proprietary application (no matter its license).
// See the main license file for more details.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public and CeCILL-C Licenses for more details.
// "http://www.cecill.info".
// "http://www.gnu.org/licenses".
// ===================================================================================
#ifndef FMPIBUFFERWRITER_HPP
#define FMPIBUFFERWRITER_HPP
#include <memory>
#include "../Utils/FMpi.hpp"
#include "FAbstractBuffer.hpp"
#include "../Utils/FAssert.hpp"
/** @author Cyrille Piacibello, Berenger Bramas
* This class provide the same features as FBufferWriter
*
* Put some data
* then insert back if needed
* finally use data pointer as you like
*/
class FMpiBufferWriter : public FAbstractBufferWriter {
FSize arrayCapacity; //< Allocated Space
std::unique_ptr<char[]> array; //< Allocated Array
FSize currentIndex; //< Currently filled space
/** Test and exit if not enought space */
void expandIfNeeded(const FSize requestedSpace) {
if( arrayCapacity < currentIndex + requestedSpace){
arrayCapacity = FSize(double(currentIndex + requestedSpace + 1) * 1.5);
char* arrayTmp = new char[arrayCapacity];
memcpy(arrayTmp, array.get(), sizeof(char)*currentIndex);
array.reset(arrayTmp);
}
}
public:
/** Constructor with a default arrayCapacity of 512 bytes */
explicit FMpiBufferWriter(const FSize inDefaultCapacity = 1024):
arrayCapacity(inDefaultCapacity),
array(new char[inDefaultCapacity]),
currentIndex(0)
{}
/** To change the capacity (but reset the head to 0 if size if lower) */
void resize(const FSize newCapacity){
if(newCapacity != arrayCapacity){
arrayCapacity = newCapacity;
char* arrayTmp = new char[arrayCapacity];
currentIndex = (currentIndex < arrayCapacity ? currentIndex : arrayCapacity-1);
memcpy(arrayTmp, array.get(), sizeof(char)*currentIndex);
array.reset(arrayTmp);
}
}
/** Destructor */
virtual ~FMpiBufferWriter(){
}
/** Get allocated memory pointer */
char* data() override {
return array.get();
}
/** Get allocated memory pointer */
const char* data() const override {
return array.get();
}
/** Get the filled space */