Commit 73db0b9d authored by COULAUD Olivier's avatar COULAUD Olivier
parents b44b1753 3947aac0
......@@ -50,6 +50,7 @@ OPTION( ScalFMM_USE_DOUBLE_PRECISION "Set to ON to compile in double precision"
OPTION( ScalFMM_ATTACHE_SOURCE "Set to ON to compile with -g" OFF )
OPTION( ScalFMM_USE_ADDONS "Set to ON to compile add ons" OFF )
OPTION( ScalFMM_USE_SSE "Set to ON to compile with sse support" ON )
OPTION( ScalFMM_USE_ASSERT "Set to ON to enable safe tests during execution" ON )
# Set scalfmm to default libraries
SET(SCALFMM_LIBRARIES "")
#
......@@ -90,9 +91,9 @@ else()
# Compile Release flags
#
SET(CMAKE_BUILD_TYPE Release)
# force -O2 in release
SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2")
STRING(REPLACE "-O3" "" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} )
# force -O3 in release
SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")
STRING(REPLACE "-O2" "" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} )
# if compiler is intel add -ip
IF(CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
SET(ScaLFMM_CXX_FLAGS "${ScaLFMM_CXX_FLAGS} -ip")
......@@ -104,9 +105,9 @@ else()
ELSE(APPLE)
# Test if not apple and 64bits
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
SET(SCALFMM_FLAGS_OPTI_RELEASE "-m64 -ffast-math -flto -march=native -funroll-loops" CACHE STRING "Set your optimization flags for release mode.")
SET(SCALFMM_FLAGS_OPTI_RELEASE "-m64 -ffast-math -flto -march=native -funroll-loops -ftree-vectorize" CACHE STRING "Set your optimization flags for release mode.")
else()
SET(SCALFMM_FLAGS_OPTI_RELEASE "-ffast-math -flto -march=native -funroll-loops" CACHE STRING "Set your optimization flags for release mode.")
SET(SCALFMM_FLAGS_OPTI_RELEASE "-ffast-math -flto -march=native -funroll-loops -ftree-vectorize" CACHE STRING "Set your optimization flags for release mode.")
endif()
ENDIF(APPLE)
# ADD_DEFINITIONS(${SCALFMM_FLAGS_OPTI_RELEASE})
......@@ -175,6 +176,12 @@ endif()
# Use Mem stats
MESSAGE( STATUS "ScalFMM_USE_MEM_STATS = ${ScalFMM_USE_MEM_STATS}" )
# Use Log
MESSAGE( STATUS "ScalFMM_USE_LOG = ${ScalFMM_USE_LOG}" )
# Use Assert
MESSAGE( STATUS "ScalFMM_USE_ASSERT = ${ScalFMM_USE_ASSERT}" )
# Add CBLAS
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${CBLAS_LIBRARIES}")
......
This source diff could not be displayed because it is too large. You can view the blob instead.
No preview for this file type
Please follow those rules when developing:
==========================================
Static (variables, members, attributes) should start with a capital letter
Class name should start with a capital letter
Mix capital and normal letter to write names (IAmAName) no underscore (but if you have several variables that looks the same be careful: thisIsAXVariable thisIsAYVariable)
Put const every where it is possible (method, value, pointer etc.)
Declare variables usually as late as possible (we are not in C so do not declare every thing at the beginning of a function)
Declare index in the for loop where they are used
Use pre-inc if possible
If an parameter is changed by a function use pointer else use const ref
Please do not name variables with one letter (except it is related to a mathematical formula but then this one should be in the comment in latex format)
Try not to have function bigger than 100 lines
Be consistent
Methods should start with a verb or an action (get, compute, print, etc...)
Please follow those rules when developing in scalfmm:
=====================================================
1 - Static (variables, members, attributes) should start with a capital letter
2 - Class name should start with a capital letter
3 - Mix capital and normal letter to write names (IAmAStaticName, iAmAName) no underscore (but if you have several variables that looks the same be careful: thisIsAXVariable thisIsAYVariable)
4 - Put const every where it is possible (method, value, pointer etc.)
5 - Declare variables usually as late as possible (we are not in old C so do not declare every thing at the beginning of a function). Of course, variable that are used in a loop but with always the same value can be declared at the function beginning.
6 - Declare index in the for loop where they are used (and their names should start with "idx")
7 - Use pre-inc if possible (even if the compiler will optimized post-inc for native type)
8 - If a parameter is changed by a function use pointer else use const ref (if the size of object is less than 20 Bytes you can pass it by value, moreover if it is intensively used!)
9 - Please do not name variables with one letter (except if it is related to a mathematical formula but then this one should be in the comment in latex format)
10 - Try not to have function bigger than 100 lines
11 - Be consistent
12 - Methods should start with a verb or an action (get, compute, print, etc...)
13 - If some code are here temporary (for testing, assertion, etc), put it in a section "{}", and add a comment that explicitly says that it can be removed "todo remove this section" for example.
14 - Sometime no comment is better than outdated (or wrong copy-pasted) comments.
15 - Plain-data struct can be used if it seams natural to use container without method.
Why everything is inside the HPP!? A discussion about why scalfmm should stay like this for now
......
/*! \page contacts Contacts
*
* \section authors Authors
* ScalFmm is a library for the Fast Multipole Method (FMM). It is
* written in C++ and use OpenMP and MPI to support parallel
* execution. It is developed by the HiePACS team at the INRIA.
* You can contact the development team for any questions at
* <ul>
* <li> scalfmm-public-support@lists.gforge.inria.fr</li>
* </ul>
* If you want to see others projects of HiePACS Inria teams, please
* see : https://team.inria.fr/hiepacs/ .
* \section contributors Contributors
*
* <ul>
* <li> Olivier Coulaud </li>
* <li> Bérenger Bramas </li>
* <li> Cyrille Piacibello </li>
* </ul>
*/
/*! \page install Downloading, Building and Installing ScalFMM
*
* \section download Download ScalFMM
*
* To download ScalFmm go on http://scalfmm-public.gforge.inria.fr/download.html.
*
* You can stay in touch of the updates and new version by registering
* to the users mailing list
* (scalfmm-public-users@lists.gforge.inria.fr) which has a very low
* traffic (one email per month) at :
* http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/scalfmm-public-users.
*
* \section secNecessary Require
*
* <ul>
* <li> CMake for compiling, ccmake for configuring the build </li>
* <li> Open MP </li>
* <li> MPI, if you want to use distributed version of the algorithm </li>
* <li> A compiler supporting C++ 2011 </li>
* </ul>
*
* \section build Build
* How to build ScalFMM
* <ul>
* <li> Go to scalfmm/Build directory </li>
* <li> type <b> $> cmake .. </b>
* <ul>
* <li> If you want to enable MPI, use <b> $> cmake .. -DSCALFMM_USE_MPI=ON </b> </li>
* </ul>
* </li>
* <li> then configure your build with <b> $> ccmake .. </b> if needed </li>
* <li> then type <b> $> make name_of_exec </b> </li>
* </ul>
*
* \subsection conf Configuration of the build
*
* This is all the build options you can modify.
*
* <ul>
* <li> CMAKE_INSTALL_PREFIX : to choose where to install ScalFmm </li>
* <li> DSCALFMM_USE_MPI : to use and enable MPI. Warning, you need to use this parameter at the first cmake command you write. </li>
* <li> SCALFMM_ATTACHE_SOURCE : to build with -g </li>
* <li> SCALFMM_BUILD_DEBUG : to build in debug mode of cmake (with -O0) </li>
* <li> SCALFMM_BUILD_TESTS : to build the text and the examples </li>
* <li> SCALFMM_BUILD_UTESTS : to build the unit tests </li>
* <li> SCALFMM_USE_ADDONS : to activate add ons </li>
* <ul>
* <li> SCALFMM_ADDON_FMMAPI : to build Fmm Api </li>
* </ul>
* <li> SCALFMM_USE_DOUBLE_PRECISION : to build in double precision </li>
* <li> SCALFMM_USE_MEM_STATS : to use memory stats (which count any new/delete done during a simulation) </li>
* <li> SCALFMM_USE_BLAS : to enable blas (needed by most of the kernel) </li>
* <ul>
* <li> SCALFMM_USE_MKL_AS_BLAS : to use MKL as blas </li>
* </ul>
* <li> SCALFMM_USE_TRACE : to create trace </li>
* <ul>
* <li> SCALFMM_USE_ITAC : to use Intel ITAC tool as trace generator </li>
* </ul>
* </ul>
*
* Once the library is built, you may want to install it : <b> $> make
* install </b>. Note that it is not an obligation to install ScalFmm
* to use it. You can build it and use it from the Build directory.
* The whole project is documented using Doxygen. You can build the doc
* by typing <b> $> make doc </b> in the Build directory.
*
*
*/
/*! \page License License information
*
*
* The library is under LGPL + CeCILL-C licenses. In case of conflict
* the more restrictive has to be used. We encourage users to have a
* look to the official license websites in case of doubts.
*
* See the GNU General Public and CeCILL-C Licenses for more details.
* "http://www.cecill.info". "http://www.gnu.org/licenses".
*
* ScalFmm is under software patent number
* IDDN.FR.001.100030.000.S.P.2012.000.31235. If you need a more
* flexible license, please do not hesitate to contact us.
*
* 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.
*
*
*/
This diff is collapsed.
// This page contains the special doxygen pages and mainpage.
/*!
* @mainpage ScalFmm
*
* \section overV Overview
*
* ScalFMM is a software library to simulate N-body interactions using
* the Fast Multipole Method.
*
* The library offers two methods to compute interactions between
* bodies when the potential decays like 1/r. The first method is the
* classical FMM based on spherical harmonic expansions and the second is
* the Black-Box method which is an independent kernel formulation
* (introduced by E. Darve @ Stanford). With this method, we can now
* easily add new non oscillatory kernels in our library. For the
* classical method, two approaches are used to decrease the complexity
* of the operators. We consider either matrix formulation that allows us
* to use BLAS routines or rotation matrices to speed up the M2L
* operator.
*
* ScalFMM intends to offer all the functionalities needed to perform
* large parallel simulations while enabling an easy customization of
* the simulation components: kernels, particles and cells. It works
* in parallel in a shared/distributed memory model using OpenMP and
* MPI. The software architecture has been designed with two major
* objectives: being easy to maintain and easy to understand. There is
* two main parts:
* <ul>
* <li> the management of the octree and the
* parallelization of the method; </li>
* <li> The kernels. This new
* architecture allow us to easily add new FMM algorithm or kernels
* and new paradigm of parallelization. </li>
* </ul>
*
*
* To download build and install the application, please see \ref
* install.
*
* The \ref quick can help you to understand the architectur of the
* library.
*
* This software is distributed under a specific License. For more
* informations, see \ref License.
*
* If you want to cite the project and/or the team, please contact
* us. See \ref contacts page.
*
*/
......@@ -10,6 +10,7 @@ cmake ..
# Or if you want to use MPI
cmake .. -DScalFMM_USE_MPI=ON
# Configure, for example with:
ccmake ..
# turn on/off the options you want
......@@ -29,6 +30,3 @@ cd scalfmm/Build
make doc
# This will create a Html dir
browser scalfmm/Build/Doc/html/index.html
......@@ -19,7 +19,7 @@
#include "../Utils/FGlobal.hpp"
#include "../Utils/FPoint.hpp"
#include "../Containers/FVector.hpp"
#include "../Utils/FAssertable.hpp"
#include "../Utils/FAssert.hpp"
#include "../Utils/FGlobalPeriodic.hpp"
......@@ -37,13 +37,13 @@
* tree.
*/
template <class OctreeClass, class ContainerClass, class ParticleClass, class ConverterClass >
class FOctreeArranger : FAssertable {
class FOctreeArranger {
OctreeClass* const tree; //< The tree to work on
public:
/** Basic constructor */
FOctreeArranger(OctreeClass* const inTree) : tree(inTree) {
fassert(tree, "Tree cannot be null", __LINE__ , __FILE__ );
FAssertLF(tree, "Tree cannot be null" );
}
/** Arrange */
......
......@@ -18,7 +18,7 @@
#include "../Utils/FGlobal.hpp"
#include "../Containers/FVector.hpp"
#include "../Utils/FAssertable.hpp"
#include "../Utils/FAssert.hpp"
#include "../Utils/FMpi.hpp"
#include "../Utils/FGlobalPeriodic.hpp"
......@@ -36,7 +36,7 @@
* tree.
*/
template <class OctreeClass, class ContainerClass, class ParticleClass, class ConverterClass >
class FOctreeArrangerProc : FAssertable {
class FOctreeArrangerProc {
/** Interval is the min/max morton index
* for a proc
*/
......@@ -64,7 +64,7 @@ class FOctreeArrangerProc : FAssertable {
public:
/** Basic constructor */
FOctreeArrangerProc(OctreeClass* const inTree) : tree(inTree) {
fassert(tree, "Tree cannot be null", __LINE__ , __FILE__ );
FAssertLF(tree, "Tree cannot be null");
}
/** return false if the tree is empty after processing */
......
......@@ -16,9 +16,6 @@
#ifndef FABSTRACTSENDABLE_HPP
#define FABSTRACTSENDABLE_HPP
class FBufferReader;
class FBufferWriter;
/**
* @author Berenger Bramas (berenger.bramas@inria.fr)
* @class FAbstractSendable
......@@ -36,18 +33,30 @@ protected:
///////////////////////////////////////////////
/** Save your data */
virtual void serializeUp(FBufferWriter&) const = 0;
template <class BufferWriterClass>
void serializeUp(BufferWriterClass&) const{
static_assert(sizeof(BufferWriterClass) == 0 , "Your class should implement serializeUp");
}
/** Retrieve your data */
virtual void deserializeUp(FBufferReader&) = 0;
template <class BufferReaderClass>
void deserializeUp(BufferReaderClass&){
static_assert(sizeof(BufferWriterClass) == 0 , "Your class should implement deserializeUp");
}
///////////////////////////////////////////////
// For Downward pass
///////////////////////////////////////////////
/** Save your data */
virtual void serializeDown(FBufferWriter&) const = 0;
template <class BufferWriterClass>
void serializeDown(BufferWriterClass&) const{
static_assert(sizeof(BufferWriterClass) == 0 , "Your class should implement serializeDown");
}
/** Retrieve your data */
virtual void deserializeDown(FBufferReader&) = 0;
template <class BufferReaderClass>
void deserializeDown(BufferReaderClass&){
static_assert(sizeof(BufferWriterClass) == 0 , "Your class should implement deserializeDown");
}
};
......
......@@ -16,8 +16,6 @@
#ifndef FABSTRACTSERIALIZABLE_HPP
#define FABSTRACTSERIALIZABLE_HPP
class FBufferReader;
class FBufferWriter;
/**
* @author Berenger Bramas (berenger.bramas@inria.fr)
......@@ -29,8 +27,14 @@ class FBufferWriter;
*/
class FAbstractSerializable {
protected:
virtual void save(FBufferWriter&) const = 0;
virtual void restore(FBufferReader&) = 0;
template <class BufferWriterClass>
void save(BufferWriterClass&) const{
static_assert(sizeof(BufferWriterClass) == 0 , "Your class should implement save");
}
template <class BufferReaderClass>
void restore(BufferReaderClass&){
static_assert(sizeof(BufferReaderClass) == 0 , "Your class should implement restore");
}
};
#endif // FABSTRACTSERIALIZABLE_HPP
......@@ -16,7 +16,7 @@
#ifndef FBASICCELL_HPP
#define FBASICCELL_HPP
#include "FAbstractSerializable.hpp"
#include "../Extensions/FExtendMortonIndex.hpp"
#include "../Extensions/FExtendCoordinate.hpp"
......@@ -34,19 +34,21 @@
*
*
*/
class FBasicCell : public FExtendMortonIndex, public FExtendCoordinate {
class FBasicCell : public FExtendMortonIndex, public FExtendCoordinate, public FAbstractSerializable {
public:
/** Default destructor */
virtual ~FBasicCell(){
}
/** Save the current cell in a buffer */
void save(FBufferWriter& buffer) const{
template <class BufferWriterClass>
void save(BufferWriterClass& buffer) const{
FExtendMortonIndex::save(buffer);
FExtendCoordinate::save(buffer);
}
/** Restore the current cell from a buffer */
void restore(FBufferReader& buffer){
template <class BufferReaderClass>
void restore(BufferReaderClass& buffer){
FExtendMortonIndex::restore(buffer);
FExtendCoordinate::restore(buffer);
}
......
......@@ -17,6 +17,7 @@
#define FBASICPARTICLECONTAINER_HPP
#include "FAbstractParticleContainer.hpp"
#include "FAbstractSerializable.hpp"
#include "../Utils/FAlignedMemory.hpp"
#include "../Utils/FMath.hpp"
......@@ -42,7 +43,7 @@
* @code AStruct* strucs = container.getAttributes<0>();
*/
template <unsigned NbAttributesPerParticle, class AttributeClass = FReal >
class FBasicParticleContainer : public FAbstractParticleContainer {
class FBasicParticleContainer : public FAbstractParticleContainer, public FAbstractSerializable {
protected:
/** The number of particles in the container */
int nbParticles;
......@@ -248,11 +249,12 @@ public:
/** The size to send a leaf */
int getSavedSize() const{
return int(nbParticles * (3 * sizeof(FReal) + NbAttributesPerParticle * sizeof(AttributeClass)));
return int(sizeof(nbParticles) + nbParticles * (3 * sizeof(FReal) + NbAttributesPerParticle * sizeof(AttributeClass)));
}
/** Save the current cell in a buffer */
void save(FBufferWriter& buffer) const{
template <class BufferWriterClass>
void save(BufferWriterClass& buffer) const{
buffer << nbParticles;
for(int idx = 0 ; idx < 3 ; ++idx){
buffer.write(positions[idx], nbParticles);
......@@ -262,7 +264,8 @@ public:
}
}
/** Restore the current cell from a buffer */
void restore(FBufferReader& buffer){
template <class BufferReaderClass>
void restore(BufferReaderClass& buffer){
buffer >> nbParticles;
if( nbParticles >= allocatedParticles ){
// allocate memory
......
......@@ -16,7 +16,6 @@
#ifndef FTESTCELL_HPP
#define FTESTCELL_HPP
#include "FBasicCell.hpp"
/**
......@@ -63,13 +62,15 @@ public:
/////////////////////////////////////////////////
/** Save the current cell in a buffer */
void save(FBufferWriter& buffer) const{
template <class BufferWriterClass>
void save(BufferWriterClass& buffer) const{
FBasicCell::save(buffer);
buffer << dataDown << dataUp;
}
/** Restore the current cell from a buffer */
void restore(FBufferReader& buffer){
template <class BufferReaderClass>
void restore(BufferReaderClass& buffer){
FBasicCell::restore(buffer);
buffer >> dataDown >> dataUp;
}
......@@ -77,22 +78,27 @@ public:
/////////////////////////////////////////////////
/** Serialize only up data in a buffer */
void serializeUp(FBufferWriter& buffer) const {
template <class BufferWriterClass>
void serializeUp(BufferWriterClass& buffer) const {
buffer << this->dataUp;
}
/** Deserialize only up data in a buffer */
void deserializeUp(FBufferReader& buffer){
template <class BufferReaderClass>
void deserializeUp(BufferReaderClass& buffer){
buffer >> this->dataUp;
}
/** Serialize only down data in a buffer */
void serializeDown(FBufferWriter& buffer) const {
template <class BufferWriterClass>
void serializeDown(BufferWriterClass& buffer) const {
buffer << this->dataDown;
}
/** Deserialize only up data in a buffer */
void deserializeDown(FBufferReader& buffer){
template <class BufferReaderClass>
void deserializeDown(BufferReaderClass& buffer){
buffer >> this->dataDown;
}
};
......
......@@ -186,8 +186,9 @@ void ValidateFMMAlgo(OctreeClass* const tree){
for(int idxPart = 0 ; idxPart < octreeIterator.getCurrentListTargets()->getNbParticles() ; ++idxPart){
if( (!isUsingTsm && dataDown[idxPart] != NbPart - 1) ||
(isUsingTsm && dataDown[idxPart] != NbPart) ){
std::cout << "Problem L2P + P2P : " << dataDown[idxPart] <<
"(" << octreeIterator.getCurrentGlobalIndex() << ")\n";
std::cout << "Problem L2P + P2P : " << dataDown[idxPart] << ", " <<
" NbPart : " << NbPart << ", " <<
" ( Index " << octreeIterator.getCurrentGlobalIndex() << ")\n";
}
}
} while(octreeIterator.moveRight());
......
......@@ -17,7 +17,7 @@
#define FTYPEDLEAF_HPP
#include "../Utils/FAssertable.hpp"
#include "../Utils/FAssert.hpp"
#include "FAbstractLeaf.hpp"
#include "FParticleType.hpp"
......@@ -33,7 +33,7 @@
* Particles should be typed to enable targets/sources difference.
*/
template< class ContainerClass>
class FTypedLeaf : public FAbstractLeaf<ContainerClass>, public FAssertable {
class FTypedLeaf : public FAbstractLeaf<ContainerClass> {
ContainerClass sources; //< The sources containers
ContainerClass targets; //< The targets containers
......
#ifndef FABSTRACTBUFFER_HPP
#define FABSTRACTBUFFER_HPP
class FAbstractBufferReader {
public:
virtual ~FAbstractBufferReader(){
}
virtual char* data() = 0;
virtual const char* data() const = 0;
virtual int getSize() const = 0;
virtual void seek(const int inIndex) = 0;
virtual int tell() const = 0;
template <class ClassType>
ClassType getValue(){
static_assert(sizeof(ClassType) == 0, "Your Buffer should implement getValue.");
return ClassType();
}
template <class ClassType>
void fillValue(ClassType* const){
static_assert(sizeof(ClassType) == 0, "Your Buffer should implement fillValue.");
}
template <class ClassType>
void fillArray(ClassType* const , const int ){
static_assert(sizeof(ClassType) == 0, "Your Buffer should implement fillArray.");
}
template <class ClassType>
FAbstractBufferReader& operator>>(ClassType& ){
static_assert(sizeof(ClassType) == 0, "Your Buffer should implement operator>>.");
return *this;
}
};
class FAbstractBufferWriter {
public:
virtual ~FAbstractBufferWriter(){
}
virtual char* data() = 0;
virtual const char* data() const = 0;
virtual int getSize() const = 0;
virtual void reset() = 0;
template <class ClassType>
void write(const ClassType& object){
static_assert(sizeof(ClassType) == 0, "Your Buffer should implement write.");
}
template <class ClassType>
void writeAt(const int position, const ClassType& object){
static_assert(sizeof(ClassType) == 0, "Your Buffer should implement writeAt.");
}
template <class ClassType>
void write(const ClassType* const objects, const int inSize){
static_assert(sizeof(ClassType) == 0, "Your Buffer should implement write.");
}
template <class ClassType>
FAbstractBufferWriter& operator<<(const ClassType& ){
static_assert(sizeof(ClassType) == 0, "Your Buffer should implement operator<<.");
return *this;
}
};
#endif // FABSTRACTBUFFER_HPP
......@@ -17,7 +17,7 @@
#define FBUFFERREADER_HPP
#include "FVector.hpp"
#include "FAbstractBuffer.hpp"
/** @author Berenger Bramas
* This class provide a fast way to manage a memory and convert
......@@ -26,7 +26,7 @@
* Specifie the needed space with reserve, then fill it with data
* finaly read and convert.
*/
class FBufferReader {
class FBufferReader : public FAbstractBufferReader {
FVector<char> buffer; //< The memory buffer
int index; //< The current index reading position
......
......@@ -17,6 +17,7 @@
#define FBUFFERWRITER_HPP
#include "FVector.hpp"
#include "FAbstractBuffer.hpp"
/** @author Berenger Bramas
* This class provide a fast way to manage a memory and fill it
......@@ -25,7 +26,7 @@
* then insert back if needed
* finaly use data pointer as you like
*/
class FBufferWriter {
class FBufferWriter : public FAbstractBufferWriter {
private: