<commit_before>/*
    Copyright (c) 2007 Volker Krause <vkrause@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This library 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 Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#include "notificationmessage_p.h"

#include <QDBusMetaType>
#include <QDebug>
#include <QHash>

using namespace Akonadi;

class NotificationMessage::Private : public QSharedData
{
  public:
    Private() : QSharedData(),
      type( NotificationMessage::InvalidType ),
      operation( NotificationMessage::InvalidOp ),
      uid( -1 ),
      parentCollection( -1 ),
      parentDestCollection( -1 )
    {}

    Private( const Private &other ) : QSharedData( other )
    {
      sessionId = other.sessionId;
      type = other.type;
      operation = other.operation;
      uid = other.uid;
      remoteId = other.remoteId;
      resource = other.resource;
      parentCollection = other.parentCollection;
      parentDestCollection = other.parentDestCollection;
      mimeType = other.mimeType;
      parts = other.parts;
    }

    bool compareWithoutOp( const Private &other ) const
    {
      return sessionId == other.sessionId
          && type == other.type
          && uid == other.uid
          && remoteId == other.remoteId
          && resource == other.resource
          && parentCollection == other.parentCollection
          && parentDestCollection == other.parentDestCollection
          && mimeType == other.mimeType
          && parts == other.parts;
    }

    bool operator==(const Private &other ) const
    {
      return operation == other.operation && compareWithoutOp( other );
    }

    QByteArray sessionId;
    NotificationMessage::Type type;
    NotificationMessage::Operation operation;
    Id uid;
    QString remoteId;
    QByteArray resource;
    Id parentCollection;
    Id parentDestCollection;
    QString mimeType;
    QStringList parts;
};

NotificationMessage::NotificationMessage() :
    d( new Private )
{
}

NotificationMessage::NotificationMessage(const NotificationMessage & other) :
    d( other.d )
{
}

NotificationMessage::~ NotificationMessage()
{
}

NotificationMessage & NotificationMessage::operator =(const NotificationMessage & other)
{
  if ( this != &other )
    d = other.d;
  return *this;
}

bool NotificationMessage::operator ==(const NotificationMessage & other) const
{
  return d == other.d;
}

void NotificationMessage::registerDBusTypes()
{
  qDBusRegisterMetaType<Akonadi::NotificationMessage>();
  qDBusRegisterMetaType<Akonadi::NotificationMessage::List>();
}

QByteArray NotificationMessage::sessionId() const
{
  return d->sessionId;
}

void NotificationMessage::setSessionId( const QByteArray &sessionId )
{
  d->sessionId = sessionId;
}

NotificationMessage::Type NotificationMessage::type() const
{
  return d->type;
}

void NotificationMessage::setType(Type type)
{
  d->type = type;
}

NotificationMessage::Operation NotificationMessage::operation() const
{
  return d->operation;
}

void NotificationMessage::setOperation(Operation op)
{
  d->operation = op;
}

NotificationMessage::Id NotificationMessage::uid() const
{
  return d->uid;
}

void NotificationMessage::setUid(Id uid)
{
  d->uid = uid;
}

QString NotificationMessage::remoteId() const
{
  return d->remoteId;
}

void NotificationMessage::setRemoteId(const QString & rid)
{
  d->remoteId = rid;
}

QByteArray NotificationMessage::resource() const
{
  return d->resource;
}

void NotificationMessage::setResource(const QByteArray & res)
{
  d->resource = res;
}

NotificationMessage::Id NotificationMessage::parentCollection() const
{
  return d->parentCollection;
}

NotificationMessage::Id NotificationMessage::parentDestCollection() const
{
  return d->parentDestCollection;
}

void NotificationMessage::setParentCollection(Id parent)
{
  d->parentCollection = parent;
}

void NotificationMessage::setParentDestCollection( Id parent )
{
  d->parentDestCollection = parent;
}

QString NotificationMessage::mimeType() const
{
  return d->mimeType;
}

void NotificationMessage::setMimeType(const QString & mimeType)
{
  d->mimeType = mimeType;
}

QStringList NotificationMessage::itemParts() const
{
  return d->parts;
}

void NotificationMessage::setItemParts(const QStringList & parts)
{
  d->parts = parts;
}

QString NotificationMessage::toString() const
{
  QString rv;
  switch ( type() ) {
    case Item:
      rv += QLatin1String( "Item " );
      break;
    case Collection:
      rv += QLatin1String( "Collection " );
      break;
  }
  rv += QString::fromLatin1( "(%1, %2) " ).arg( uid() ).arg( remoteId() );
  if ( parentDestCollection() >= 0 )
    rv += QString::fromLatin1( "from " );
  else
    rv += QString::fromLatin1( "in " );
  if ( parentCollection() >= 0 )
    rv += QString::fromLatin1( "collection %1 " ).arg( parentCollection() );
  switch ( operation() ) {
    case Add:
      rv += QLatin1String( "added" );
      break;
    case Modify:
      rv += QLatin1String( "modified" );
      break;
    case Move:
      rv += QLatin1String( "moved" );
      break;
    case Remove:
      rv += QLatin1String( "removed" );
      break;
  }
  if ( parentDestCollection() >= 0 )
    rv += QString::fromLatin1( "to collection %1" ).arg( parentDestCollection() );
  return rv;
}

void NotificationMessage::appendAndCompress(NotificationMessage::List & list, const NotificationMessage & msg)
{
  for ( NotificationMessage::List::Iterator it = list.begin(); it != list.end(); ) {
    if ( msg.d->compareWithoutOp( *((*it).d) ) ) {
      if ( msg.operation() == (*it).operation() || msg.operation() == Modify ) {
        return;
      }
      if ( msg.operation() == Remove && (*it).operation() == Modify ) {
        it = list.erase( it );
      } else
        ++it;
    } else
      ++it;
  }
  list << msg;
}

QDBusArgument & operator <<(QDBusArgument & arg, const NotificationMessage & msg)
{
  arg.beginStructure();
  arg << msg.sessionId();
  arg << msg.type();
  arg << msg.operation();
  arg << msg.uid();
  arg << msg.remoteId();
  arg << msg.resource();
  arg << msg.parentCollection();
  arg << msg.parentDestCollection();
  arg << msg.mimeType();
  arg << msg.itemParts();
  arg.endStructure();
  return arg;
}

const QDBusArgument & operator >>(const QDBusArgument & arg, NotificationMessage & msg)
{
  arg.beginStructure();
  QByteArray b;
  arg >> b;
  msg.setSessionId( b );
  int i;
  arg >> i;
  msg.setType( static_cast<NotificationMessage::Type>( i ) );
  arg >> i;
  msg.setOperation( static_cast<NotificationMessage::Operation>( i ) );
  NotificationMessage::Id id;
  arg >> id;
  msg.setUid( id );
  QString s;
  arg >> s;
  msg.setRemoteId( s );
  arg >> b;
  msg.setResource( b );
  arg >> id;
  msg.setParentCollection( id );
  arg >> id;
  msg.setParentDestCollection( id );
  arg >> s;
  msg.setMimeType( s );
  QStringList l;
  arg >> l;
  msg.setItemParts( l );
  arg.endStructure();
  return arg;
}

uint qHash(const Akonadi::NotificationMessage & msg)
{
  return qHash( msg.uid() + (msg.type() << 31) + (msg.operation() << 28) );
}
<commit_msg>handle InvalidType and InvalidOp cases to disable compile warnings.<commit_after>/*
    Copyright (c) 2007 Volker Krause <vkrause@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This library 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 Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#include "notificationmessage_p.h"

#include <QDBusMetaType>
#include <QDebug>
#include <QHash>

using namespace Akonadi;

class NotificationMessage::Private : public QSharedData
{
  public:
    Private() : QSharedData(),
      type( NotificationMessage::InvalidType ),
      operation( NotificationMessage::InvalidOp ),
      uid( -1 ),
      parentCollection( -1 ),
      parentDestCollection( -1 )
    {}

    Private( const Private &other ) : QSharedData( other )
    {
      sessionId = other.sessionId;
      type = other.type;
      operation = other.operation;
      uid = other.uid;
      remoteId = other.remoteId;
      resource = other.resource;
      parentCollection = other.parentCollection;
      parentDestCollection = other.parentDestCollection;
      mimeType = other.mimeType;
      parts = other.parts;
    }

    bool compareWithoutOp( const Private &other ) const
    {
      return sessionId == other.sessionId
          && type == other.type
          && uid == other.uid
          && remoteId == other.remoteId
          && resource == other.resource
          && parentCollection == other.parentCollection
          && parentDestCollection == other.parentDestCollection
          && mimeType == other.mimeType
          && parts == other.parts;
    }

    bool operator==(const Private &other ) const
    {
      return operation == other.operation && compareWithoutOp( other );
    }

    QByteArray sessionId;
    NotificationMessage::Type type;
    NotificationMessage::Operation operation;
    Id uid;
    QString remoteId;
    QByteArray resource;
    Id parentCollection;
    Id parentDestCollection;
    QString mimeType;
    QStringList parts;
};

NotificationMessage::NotificationMessage() :
    d( new Private )
{
}

NotificationMessage::NotificationMessage(const NotificationMessage & other) :
    d( other.d )
{
}

NotificationMessage::~ NotificationMessage()
{
}

NotificationMessage & NotificationMessage::operator =(const NotificationMessage & other)
{
  if ( this != &other )
    d = other.d;
  return *this;
}

bool NotificationMessage::operator ==(const NotificationMessage & other) const
{
  return d == other.d;
}

void NotificationMessage::registerDBusTypes()
{
  qDBusRegisterMetaType<Akonadi::NotificationMessage>();
  qDBusRegisterMetaType<Akonadi::NotificationMessage::List>();
}

QByteArray NotificationMessage::sessionId() const
{
  return d->sessionId;
}

void NotificationMessage::setSessionId( const QByteArray &sessionId )
{
  d->sessionId = sessionId;
}

NotificationMessage::Type NotificationMessage::type() const
{
  return d->type;
}

void NotificationMessage::setType(Type type)
{
  d->type = type;
}

NotificationMessage::Operation NotificationMessage::operation() const
{
  return d->operation;
}

void NotificationMessage::setOperation(Operation op)
{
  d->operation = op;
}

NotificationMessage::Id NotificationMessage::uid() const
{
  return d->uid;
}

void NotificationMessage::setUid(Id uid)
{
  d->uid = uid;
}

QString NotificationMessage::remoteId() const
{
  return d->remoteId;
}

void NotificationMessage::setRemoteId(const QString & rid)
{
  d->remoteId = rid;
}

QByteArray NotificationMessage::resource() const
{
  return d->resource;
}

void NotificationMessage::setResource(const QByteArray & res)
{
  d->resource = res;
}

NotificationMessage::Id NotificationMessage::parentCollection() const
{
  return d->parentCollection;
}

NotificationMessage::Id NotificationMessage::parentDestCollection() const
{
  return d->parentDestCollection;
}

void NotificationMessage::setParentCollection(Id parent)
{
  d->parentCollection = parent;
}

void NotificationMessage::setParentDestCollection( Id parent )
{
  d->parentDestCollection = parent;
}

QString NotificationMessage::mimeType() const
{
  return d->mimeType;
}

void NotificationMessage::setMimeType(const QString & mimeType)
{
  d->mimeType = mimeType;
}

QStringList NotificationMessage::itemParts() const
{
  return d->parts;
}

void NotificationMessage::setItemParts(const QStringList & parts)
{
  d->parts = parts;
}

QString NotificationMessage::toString() const
{
  QString rv;
  switch ( type() ) {
    case Item:
      rv += QLatin1String( "Item " );
      break;
    case Collection:
      rv += QLatin1String( "Collection " );
      break;
    case InvalidType: // TODO: an error?
      break;
  }
  rv += QString::fromLatin1( "(%1, %2) " ).arg( uid() ).arg( remoteId() );
  if ( parentDestCollection() >= 0 )
    rv += QString::fromLatin1( "from " );
  else
    rv += QString::fromLatin1( "in " );
  if ( parentCollection() >= 0 )
    rv += QString::fromLatin1( "collection %1 " ).arg( parentCollection() );
  switch ( operation() ) {
    case Add:
      rv += QLatin1String( "added" );
      break;
    case Modify:
      rv += QLatin1String( "modified" );
      break;
    case Move:
      rv += QLatin1String( "moved" );
      break;
    case Remove:
      rv += QLatin1String( "removed" );
      break;
    case InvalidOp: // TODO: an error?
      break;
  }
  if ( parentDestCollection() >= 0 )
    rv += QString::fromLatin1( "to collection %1" ).arg( parentDestCollection() );
  return rv;
}

void NotificationMessage::appendAndCompress(NotificationMessage::List & list, const NotificationMessage & msg)
{
  for ( NotificationMessage::List::Iterator it = list.begin(); it != list.end(); ) {
    if ( msg.d->compareWithoutOp( *((*it).d) ) ) {
      if ( msg.operation() == (*it).operation() || msg.operation() == Modify ) {
        return;
      }
      if ( msg.operation() == Remove && (*it).operation() == Modify ) {
        it = list.erase( it );
      } else
        ++it;
    } else
      ++it;
  }
  list << msg;
}

QDBusArgument & operator <<(QDBusArgument & arg, const NotificationMessage & msg)
{
  arg.beginStructure();
  arg << msg.sessionId();
  arg << msg.type();
  arg << msg.operation();
  arg << msg.uid();
  arg << msg.remoteId();
  arg << msg.resource();
  arg << msg.parentCollection();
  arg << msg.parentDestCollection();
  arg << msg.mimeType();
  arg << msg.itemParts();
  arg.endStructure();
  return arg;
}

const QDBusArgument & operator >>(const QDBusArgument & arg, NotificationMessage & msg)
{
  arg.beginStructure();
  QByteArray b;
  arg >> b;
  msg.setSessionId( b );
  int i;
  arg >> i;
  msg.setType( static_cast<NotificationMessage::Type>( i ) );
  arg >> i;
  msg.setOperation( static_cast<NotificationMessage::Operation>( i ) );
  NotificationMessage::Id id;
  arg >> id;
  msg.setUid( id );
  QString s;
  arg >> s;
  msg.setRemoteId( s );
  arg >> b;
  msg.setResource( b );
  arg >> id;
  msg.setParentCollection( id );
  arg >> id;
  msg.setParentDestCollection( id );
  arg >> s;
  msg.setMimeType( s );
  QStringList l;
  arg >> l;
  msg.setItemParts( l );
  arg.endStructure();
  return arg;
}

uint qHash(const Akonadi::NotificationMessage & msg)
{
  return qHash( msg.uid() + (msg.type() << 31) + (msg.operation() << 28) );
}
<|endoftext|>


<commit_before>

#include "samson/common/coding.h"           // KVFILE_NUM_HASHGROUPS
#include "samson/common/MessagesOperations.h"
#include "samson/common/SamsonSetup.h"      // samson::SamsonSetup

#include "StreamManager.h"          // samson::stream::StreamManager
#include "BlockBreakQueueTask.h"    // samson::stream::BlockBreakQueueTask
#include "Block.h"                  // samson::stream::Block
#include "BlockList.h"              // samson::stream::BlockList
#include "Queue.h"                  // OwnInterface

size_t next_pow_2( size_t value )
{
    if( value < 2)
        return 1;

    int p = 1;
    while ( true )
    {
	   if( value == pow(2.0 , p))
           return pow( 2.0 , p);

        if( value < pow( 2.0 , p ) )
            return pow( 2.0 , p );
        p++;
    }

    LM_X(1,("Internal error"));
    return 1;

}

namespace samson {
    namespace stream
    {

        void BlockIdList::addIds( BlockList *list )
        {
            au::list< Block >::iterator block_it;
            for ( block_it = list->blocks.begin() ; block_it != list->blocks.end() ; block_it++)
            {
                Block* block = *block_it;
                size_t block_id = block->getId();
                addId( block_id );
            }

        }
        void BlockIdList::removeIds( BlockList *list )
        {
            au::list< Block >::iterator block_it;
            for ( block_it = list->blocks.begin() ; block_it != list->blocks.end() ; block_it++)
            {
                Block* block = *block_it;
                size_t block_id = block->getId();
                removeId( block_id );
            }
        }

        void BlockIdList::addId( size_t id )
        {
            block_ids.insert( id );
        }
        void BlockIdList::removeId( size_t id )
        {
            block_ids.erase( id );
        }

        size_t BlockIdList::num_ids()
        {
            return block_ids.size();
        }

        bool BlockIdList::containsBlockId( size_t id )
        {
            return ( block_ids.find( id ) != block_ids.end() );
        }

#pragma mark Queue

        Queue::Queue( std::string _name , StreamManager* _streamManager  )
        {
            // Keep the name
            name = _name;

            // Still pending of the block
            format = KVFormat("*","*");

            // Create a list for blocks pending to be broken...
            list = new BlockList( "queue_" + name );

            // Pointer to StreamManager
            streamManager = _streamManager;

            // Default number of divisions
            num_divisions = 1;

        }

        Queue::~Queue()
        {
            delete list;
        }

        void Queue::push( BlockList *list )
        {

            BlockInfo block_info = list->getBlockInfo();
            rate_kvs.push( block_info.info.kvs );
            rate_size.push( block_info.info.size );

            au::list< Block >::iterator b;
            for (b = list->blocks.begin() ; b != list->blocks.end() ; b++ )
                push( *b );
        }

        void Queue::push( Block *block )
        {

            if( format == KVFormat("*","*") )
                format = block->header->getKVFormat();  // Get the format of the first one...
            else
            {
                if( format != block->header->getKVFormat() )
                {
                    LM_W(("Trying to push a block with format %s to queue %s with format %s. Block rejected", block->header->getKVFormat().str().c_str() , name.c_str() , format.str().c_str() ));
                    return;
                }
            }

            // Add to the list for this queue
            list->add( block );

        }

        void Queue::getInfo( std::ostringstream& output)
        {
            au::xml_open(output, "queue");

            au::xml_simple(output, "name", name );

            // Information about the format
            format.getInfo(output);

            // Block list information
            list->getInfo( output );

            // Informat description of queue status
            std::ostringstream status;

            au::xml_simple(output, "num_divisions", num_divisions );

            if( lock_block_ids.num_ids() > 0)
                status << au::str("[ Locked %d/%d blocks ] " , lock_block_ids.num_ids() , list->getNumBlocks());

            if( status.str() == "" )
                status << "ready";

            au::xml_simple( output , "status" , status.str() );

            // Information about content
            BlockInfo block_info;
            update( block_info );
            block_info.getInfo(output);

            au::xml_simple( output , "environment" , environment.getEnvironmentDescription() );

            // Information about simple rate
            au::xml_single_element( output , "rate_kvs" , &rate_kvs );
            au::xml_single_element( output , "rate_size" , &rate_size );

            au::xml_close(output, "queue");
        }

        void Queue::update( BlockInfo& block_info )
        {
            list->update( block_info );

        }

        void Queue::setProperty( std::string property , std::string value )
        {
            environment.set( property , value );
        }

        void Queue::replaceAndUnlock( BlockList *from , BlockList *to )
        {
            replace( from , to );
            unlock(from);
        }

        void Queue::replace( BlockList *from , BlockList *to )
        {
            // Replace a list of blocks by another list
            list->replace( from , to );
        }

        void Queue::removeAndUnlock( BlockList *_list )
        {
            list->remove( _list );
            unlock( _list );
        }

        void Queue::remove ( BlockList *_list )
        {
            list->remove( _list );
        }

        void Queue::unlock ( BlockList *list )
        {
            // Remove this ids from any possible concept
            lock_block_ids.removeIds( list );
        }

        bool Queue::lock ( BlockList *list )
        {
            if( !canBelock( list ) )
                return false;

            // Add the block sto the id
            lock_block_ids.addIds( list );
            return true;
        }

        bool Queue::canBelock ( BlockList *list )
        {
            au::list< Block >::iterator block_it;
            for ( block_it = list->blocks.begin() ; block_it != list->blocks.end() ; block_it++ )
            {
                Block* block = *block_it;
                if( lock_block_ids.containsBlockId( block->getId() ) )
                    return false;
            }

            return true;
        }

        void Queue::getBlocksForKVRange( KVRange range , BlockList *outputBlockList )
        {
            au::list< Block >::iterator block_it;
            for ( block_it = list->blocks.begin() ; block_it != list->blocks.end() ; block_it++ )
            {
                Block *block = *block_it;
                KVRange block_range = block->getKVRange();

                if( block_range.overlap( range ) )
                    outputBlockList->add( block );
            }
        }

        bool Queue::getAndLockBlocksForKVRange( KVRange range , BlockList *outputBlockList )
        {
            if( !canLockBlocksForKVRange(range) )
                return false;

            au::list< Block >::iterator block_it;
            for ( block_it = list->blocks.begin() ; block_it != list->blocks.end() ; block_it++ )
            {
                Block *block = *block_it;
                size_t block_id = block->getId();
                KVRange block_range = block->getKVRange();

                if( block_range.overlap( range ) )
                {
                    lock_block_ids.addId( block_id );
                    outputBlockList->add( block );
                }
            }
            return true;
        }

        bool Queue::canLockBlocksForKVRange( KVRange range )
        {
            au::list< Block >::iterator block_it;
            for ( block_it = list->blocks.begin() ; block_it != list->blocks.end() ; block_it++ )
            {
                Block *block = *block_it;
                size_t block_id = block->getId();
                KVRange block_range = block->getKVRange();

                if( block_range.overlap( range ) )
                    if( lock_block_ids.containsBlockId(block_id) )
                        return false;

            }
            return true;
        }

        void Queue::review()
        {
            au::ExecesiveTimeAlarm alarm("Queue::review");

            // Review the size contained in this queue if there is a limit defined....

            size_t max_size = environment.getSizeT( "max_size" , 0 );

            if( max_size > 0 )
            {

                BlockList tmp_block_list;   // Temporal list to put extracted blocks...
                while( list->getBlockInfo().size > max_size )
                    tmp_block_list.extractBlockFrom( list );
            }

            //LM_M(("Intern review queue %s" , name.c_str() ));

            // Schedule new Block Break operations if necessary
            if( format == KVFormat("txt","txt") )
			{
                //LM_M(("Queue %s nor revised since format %s= txt" , name.c_str() , format.str().c_str() ));
                return;  // No necessary operations for txt elements
			}

            // Set the minimum number of divisions ( when possible )
            // Only in state queues when trying to run update-state operations
            // setMinimumNumDivisions();

            // Not break blocks any more

            /*
            while( true )
            {
                //LM_M(("Queue %s: Num divisions %d.... %lu blocks" , name.c_str() , num_divisions , list->blocks.size() ));

                size_t max_size = SamsonSetup::shared()->getUInt64("stream.max_operation_input_size");

                BlockList inputBlockList("candidates_block_division");
                getBlocksToBreak( &inputBlockList , max_size );

                if( inputBlockList.isEmpty() )
                    break;

                // Schedule a block break operation
                size_t id = streamManager->queueTaskManager.getNewId();

                BlockBreakQueueTask *task = new BlockBreakQueueTask( id , name , num_divisions );
                BlockList *input = task->getBlockList("input_0");
                input->copyFrom( &inputBlockList , 0 );

                task->setWorkingSize();

                streamManager->queueTaskManager.add( task );

                LM_T(LmtBlockManager,("Running a block-break operation for queue %s %s" , name.c_str() , input->strBlockIds().c_str() ));
            }
            */
            /*
            // Compact if the over-headed is too high for a particular division
            //LM_TODO(("To be completed..."));
            if ( num_divisions > 1 )
            {
                for ( int n = 0 ; n < num_divisions ; n++)
                {
                    // Create a list with all the blocks exclusive for this division
                    BlockList *tmp = new BlockList("compactation_for_queue");

                    KVRange range = rangeForDivision(n, num_divisions);
                    au::list< Block >::iterator block_it;
                    for ( block_it = list->blocks.begin() ; block_it != list->blocks.end() ; block_it++)
                    {
                        Block *block = *block_it;
                        if ( range.includes( block->getKVRange() ) )
                            tmp->add( block );
                    }

                    // If overhead is too large, compactation is required
                    BlockInfo block_info = tmp->getBlockInfo();

                    //LM_M(("Queue %s: division %d/%d %d blocks with %f overhead", name.c_str() , n , num_divisions , block_info.num_blocks , block_info.getOverhead() ));

                    if ( block_info.getOverhead() > 0.2 )
                    {
                        // Run a compact operation over this set
                        // Future work...
                    }

                    delete tmp;

                }

            }
             */

        }

        // Get some blocks that need to be broken to meet a particular number of divisions ( not locked )
        void Queue::getBlocksToBreak( BlockList *outputBlockList  , size_t max_size )
        {

            size_t total_size = 0 ;
            int num_blocks = 0;

            au::list< Block >::iterator b;
            for (b = list->blocks.begin() ;  b != list->blocks.end() ; b++)
            {
                Block *block = *b;
                size_t block_id = block->getId();
                KVRange block_range = block->getKVRange();

                if( !lock_block_ids.containsBlockId( block_id ) )
                {
                    if( !block_range.isValidForNumDivisions( num_divisions ) )
                    {
                        total_size += block->getSize();
                        if( num_blocks  > 0 )
                            if (( max_size > 0) && ( total_size > max_size ))
                                return;
                        LM_T(LmtBlockManager,("Adds block to be partitioned id=%lu, num_divisions:%d, total_size:%lu, max_size:%lu" , block->getId(), num_divisions, total_size, max_size ));
                        lock_block_ids.addId( block->getId() );

                        outputBlockList->add( *b );
                        num_blocks++;
                    }

                }
            }
        }

        bool Queue::isReadyForDivisions( )
        {
            // Check the queue is ready for the number of divisions ( all the block break operations have finished )

            au::list< Block >::iterator block_it;
            for ( block_it = list->blocks.begin() ; block_it != list->blocks.end() ; block_it++ )
            {
                Block *block = *block_it;
                KVRange block_range = block->getKVRange();

                if( !block_range.isValidForNumDivisions( num_divisions ) )
                    return false;
            }

            return true;

        }

        void Queue::fill( samson::network::CollectionRecord* record , VisualitzationOptions options )
        {

            // Get block information for this queue
            BlockInfo blockInfo;
            update( blockInfo );

            // Last component of name
            /*
            std::string last_component_name = name;
            size_t pos = name.find_last_of("/");
            if( pos != std::string::npos )
                last_component_name = name.substr( pos+1 );
             */

            add( record , "name" , name , "left,different" );
            add( record , "#kvs" , blockInfo.info.kvs , "f=uint64,sum" );
            add( record , "size" , blockInfo.info.size , "f=uint64,sum" );

            if( ( options == normal ) || (options == all ) )
            {
                add( record , "key" , format.keyFormat  , "different");
                add( record , "value" , format.valueFormat , "different" );
            }

            if( ( options == verbose ) || (options == all ) )
            {
                add( record , "#kvs/s"  , (size_t)rate_kvs.getRate() , "f=uint64,sum" );
                add( record , "Bytes/s" , (size_t)rate_size.getRate() , "f=uint64,sum" );
            }

            if( ( options == verbose2 ) || (options == all ) )
            {
                add( record , "#Blocs"     , blockInfo.num_blocks , "f=uint64,sum" );
                add( record , "Size"       , blockInfo.size , "f=uint64,sum" );
                add( record , "on Memory"  , blockInfo.size_on_memory , "f=uint64,sum" );
                add( record , "on Disk"    , blockInfo.size_on_disk , "f=uint64,sum" );
                add( record , "Locked"     , blockInfo.size_locked , "f=uint64,sum" );
                add( record , "Time from"  , (size_t)blockInfo.min_time , "f=time,different" );
                add( record , "Time to"    , (size_t)blockInfo.max_time , "f=time,different" );
            }

        }

    }
}
<commit_msg>SAMSON-433 Adjust time span of rate in queues<commit_after>

#include "samson/common/coding.h"           // KVFILE_NUM_HASHGROUPS
#include "samson/common/MessagesOperations.h"
#include "samson/common/SamsonSetup.h"      // samson::SamsonSetup

#include "StreamManager.h"          // samson::stream::StreamManager
#include "BlockBreakQueueTask.h"    // samson::stream::BlockBreakQueueTask
#include "Block.h"                  // samson::stream::Block
#include "BlockList.h"              // samson::stream::BlockList
#include "Queue.h"                  // OwnInterface

size_t next_pow_2( size_t value )
{
    if( value < 2)
        return 1;

    int p = 1;
    while ( true )
    {
	   if( value == pow(2.0 , p))
           return pow( 2.0 , p);

        if( value < pow( 2.0 , p ) )
            return pow( 2.0 , p );
        p++;
    }

    LM_X(1,("Internal error"));
    return 1;

}

namespace samson {
    namespace stream
    {

        void BlockIdList::addIds( BlockList *list )
        {
            au::list< Block >::iterator block_it;
            for ( block_it = list->blocks.begin() ; block_it != list->blocks.end() ; block_it++)
            {
                Block* block = *block_it;
                size_t block_id = block->getId();
                addId( block_id );
            }

        }
        void BlockIdList::removeIds( BlockList *list )
        {
            au::list< Block >::iterator block_it;
            for ( block_it = list->blocks.begin() ; block_it != list->blocks.end() ; block_it++)
            {
                Block* block = *block_it;
                size_t block_id = block->getId();
                removeId( block_id );
            }
        }

        void BlockIdList::addId( size_t id )
        {
            block_ids.insert( id );
        }
        void BlockIdList::removeId( size_t id )
        {
            block_ids.erase( id );
        }

        size_t BlockIdList::num_ids()
        {
            return block_ids.size();
        }

        bool BlockIdList::containsBlockId( size_t id )
        {
            return ( block_ids.find( id ) != block_ids.end() );
        }

#pragma mark Queue

        Queue::Queue( std::string _name , StreamManager* _streamManager  )
        {
            // Keep the name
            name = _name;

            // Still pending of the block
            format = KVFormat("*","*");

            // Create a list for blocks pending to be broken...
            list = new BlockList( "queue_" + name );

            // Pointer to StreamManager
            streamManager = _streamManager;

            // Default number of divisions
            num_divisions = 1;

            rate_kvs.setTimeLength( 60 );
            rate_size.setTimeLength( 60 );

        }

        Queue::~Queue()
        {
            delete list;
        }

        void Queue::push( BlockList *list )
        {

            BlockInfo block_info = list->getBlockInfo();
            rate_kvs.push( block_info.info.kvs );
            rate_size.push( block_info.info.size );

            au::list< Block >::iterator b;
            for (b = list->blocks.begin() ; b != list->blocks.end() ; b++ )
                push( *b );
        }

        void Queue::push( Block *block )
        {

            if( format == KVFormat("*","*") )
                format = block->header->getKVFormat();  // Get the format of the first one...
            else
            {
                if( format != block->header->getKVFormat() )
                {
                    LM_W(("Trying to push a block with format %s to queue %s with format %s. Block rejected", block->header->getKVFormat().str().c_str() , name.c_str() , format.str().c_str() ));
                    return;
                }
            }

            // Add to the list for this queue
            list->add( block );

        }

        void Queue::getInfo( std::ostringstream& output)
        {
            au::xml_open(output, "queue");

            au::xml_simple(output, "name", name );

            // Information about the format
            format.getInfo(output);

            // Block list information
            list->getInfo( output );

            // Informat description of queue status
            std::ostringstream status;

            au::xml_simple(output, "num_divisions", num_divisions );

            if( lock_block_ids.num_ids() > 0)
                status << au::str("[ Locked %d/%d blocks ] " , lock_block_ids.num_ids() , list->getNumBlocks());

            if( status.str() == "" )
                status << "ready";

            au::xml_simple( output , "status" , status.str() );

            // Information about content
            BlockInfo block_info;
            update( block_info );
            block_info.getInfo(output);

            au::xml_simple( output , "environment" , environment.getEnvironmentDescription() );

            // Information about simple rate
            au::xml_single_element( output , "rate_kvs" , &rate_kvs );
            au::xml_single_element( output , "rate_size" , &rate_size );

            au::xml_close(output, "queue");
        }

        void Queue::update( BlockInfo& block_info )
        {
            list->update( block_info );

        }

        void Queue::setProperty( std::string property , std::string value )
        {
            environment.set( property , value );
        }

        void Queue::replaceAndUnlock( BlockList *from , BlockList *to )
        {
            replace( from , to );
            unlock(from);
        }

        void Queue::replace( BlockList *from , BlockList *to )
        {
            // Replace a list of blocks by another list
            list->replace( from , to );
        }

        void Queue::removeAndUnlock( BlockList *_list )
        {
            list->remove( _list );
            unlock( _list );
        }

        void Queue::remove ( BlockList *_list )
        {
            list->remove( _list );
        }

        void Queue::unlock ( BlockList *list )
        {
            // Remove this ids from any possible concept
            lock_block_ids.removeIds( list );
        }

        bool Queue::lock ( BlockList *list )
        {
            if( !canBelock( list ) )
                return false;

            // Add the block sto the id
            lock_block_ids.addIds( list );
            return true;
        }

        bool Queue::canBelock ( BlockList *list )
        {
            au::list< Block >::iterator block_it;
            for ( block_it = list->blocks.begin() ; block_it != list->blocks.end() ; block_it++ )
            {
                Block* block = *block_it;
                if( lock_block_ids.containsBlockId( block->getId() ) )
                    return false;
            }

            return true;
        }

        void Queue::getBlocksForKVRange( KVRange range , BlockList *outputBlockList )
        {
            au::list< Block >::iterator block_it;
            for ( block_it = list->blocks.begin() ; block_it != list->blocks.end() ; block_it++ )
            {
                Block *block = *block_it;
                KVRange block_range = block->getKVRange();

                if( block_range.overlap( range ) )
                    outputBlockList->add( block );
            }
        }

        bool Queue::getAndLockBlocksForKVRange( KVRange range , BlockList *outputBlockList )
        {
            if( !canLockBlocksForKVRange(range) )
                return false;

            au::list< Block >::iterator block_it;
            for ( block_it = list->blocks.begin() ; block_it != list->blocks.end() ; block_it++ )
            {
                Block *block = *block_it;
                size_t block_id = block->getId();
                KVRange block_range = block->getKVRange();

                if( block_range.overlap( range ) )
                {
                    lock_block_ids.addId( block_id );
                    outputBlockList->add( block );
                }
            }
            return true;
        }

        bool Queue::canLockBlocksForKVRange( KVRange range )
        {
            au::list< Block >::iterator block_it;
            for ( block_it = list->blocks.begin() ; block_it != list->blocks.end() ; block_it++ )
            {
                Block *block = *block_it;
                size_t block_id = block->getId();
                KVRange block_range = block->getKVRange();

                if( block_range.overlap( range ) )
                    if( lock_block_ids.containsBlockId(block_id) )
                        return false;

            }
            return true;
        }

        void Queue::review()
        {
            au::ExecesiveTimeAlarm alarm("Queue::review");

            // Review the size contained in this queue if there is a limit defined....

            size_t max_size = environment.getSizeT( "max_size" , 0 );

            if( max_size > 0 )
            {

                BlockList tmp_block_list;   // Temporal list to put extracted blocks...
                while( list->getBlockInfo().size > max_size )
                    tmp_block_list.extractBlockFrom( list );
            }

            //LM_M(("Intern review queue %s" , name.c_str() ));

            // Schedule new Block Break operations if necessary
            if( format == KVFormat("txt","txt") )
			{
                //LM_M(("Queue %s nor revised since format %s= txt" , name.c_str() , format.str().c_str() ));
                return;  // No necessary operations for txt elements
			}

            // Set the minimum number of divisions ( when possible )
            // Only in state queues when trying to run update-state operations
            // setMinimumNumDivisions();

            // Not break blocks any more

            /*
            while( true )
            {
                //LM_M(("Queue %s: Num divisions %d.... %lu blocks" , name.c_str() , num_divisions , list->blocks.size() ));

                size_t max_size = SamsonSetup::shared()->getUInt64("stream.max_operation_input_size");

                BlockList inputBlockList("candidates_block_division");
                getBlocksToBreak( &inputBlockList , max_size );

                if( inputBlockList.isEmpty() )
                    break;

                // Schedule a block break operation
                size_t id = streamManager->queueTaskManager.getNewId();

                BlockBreakQueueTask *task = new BlockBreakQueueTask( id , name , num_divisions );
                BlockList *input = task->getBlockList("input_0");
                input->copyFrom( &inputBlockList , 0 );

                task->setWorkingSize();

                streamManager->queueTaskManager.add( task );

                LM_T(LmtBlockManager,("Running a block-break operation for queue %s %s" , name.c_str() , input->strBlockIds().c_str() ));
            }
            */
            /*
            // Compact if the over-headed is too high for a particular division
            //LM_TODO(("To be completed..."));
            if ( num_divisions > 1 )
            {
                for ( int n = 0 ; n < num_divisions ; n++)
                {
                    // Create a list with all the blocks exclusive for this division
                    BlockList *tmp = new BlockList("compactation_for_queue");

                    KVRange range = rangeForDivision(n, num_divisions);
                    au::list< Block >::iterator block_it;
                    for ( block_it = list->blocks.begin() ; block_it != list->blocks.end() ; block_it++)
                    {
                        Block *block = *block_it;
                        if ( range.includes( block->getKVRange() ) )
                            tmp->add( block );
                    }

                    // If overhead is too large, compactation is required
                    BlockInfo block_info = tmp->getBlockInfo();

                    //LM_M(("Queue %s: division %d/%d %d blocks with %f overhead", name.c_str() , n , num_divisions , block_info.num_blocks , block_info.getOverhead() ));

                    if ( block_info.getOverhead() > 0.2 )
                    {
                        // Run a compact operation over this set
                        // Future work...
                    }

                    delete tmp;

                }

            }
             */

        }

        // Get some blocks that need to be broken to meet a particular number of divisions ( not locked )
        void Queue::getBlocksToBreak( BlockList *outputBlockList  , size_t max_size )
        {

            size_t total_size = 0 ;
            int num_blocks = 0;

            au::list< Block >::iterator b;
            for (b = list->blocks.begin() ;  b != list->blocks.end() ; b++)
            {
                Block *block = *b;
                size_t block_id = block->getId();
                KVRange block_range = block->getKVRange();

                if( !lock_block_ids.containsBlockId( block_id ) )
                {
                    if( !block_range.isValidForNumDivisions( num_divisions ) )
                    {
                        total_size += block->getSize();
                        if( num_blocks  > 0 )
                            if (( max_size > 0) && ( total_size > max_size ))
                                return;
                        LM_T(LmtBlockManager,("Adds block to be partitioned id=%lu, num_divisions:%d, total_size:%lu, max_size:%lu" , block->getId(), num_divisions, total_size, max_size ));
                        lock_block_ids.addId( block->getId() );

                        outputBlockList->add( *b );
                        num_blocks++;
                    }

                }
            }
        }

        bool Queue::isReadyForDivisions( )
        {
            // Check the queue is ready for the number of divisions ( all the block break operations have finished )

            au::list< Block >::iterator block_it;
            for ( block_it = list->blocks.begin() ; block_it != list->blocks.end() ; block_it++ )
            {
                Block *block = *block_it;
                KVRange block_range = block->getKVRange();

                if( !block_range.isValidForNumDivisions( num_divisions ) )
                    return false;
            }

            return true;

        }

        void Queue::fill( samson::network::CollectionRecord* record , VisualitzationOptions options )
        {

            // Get block information for this queue
            BlockInfo blockInfo;
            update( blockInfo );

            // Last component of name
            /*
            std::string last_component_name = name;
            size_t pos = name.find_last_of("/");
            if( pos != std::string::npos )
                last_component_name = name.substr( pos+1 );
             */

            add( record , "name" , name , "left,different" );
            add( record , "#kvs" , blockInfo.info.kvs , "f=uint64,sum" );
            add( record , "size" , blockInfo.info.size , "f=uint64,sum" );

            if( ( options == normal ) || (options == all ) )
            {
                add( record , "key" , format.keyFormat  , "different");
                add( record , "value" , format.valueFormat , "different" );
            }

            if( ( options == verbose ) || (options == all ) )
            {
                add( record , "#kvs/s"  , (size_t)rate_kvs.getRate() , "f=uint64,sum" );
                add( record , "Bytes/s" , (size_t)rate_size.getRate() , "f=uint64,sum" );
            }

            if( ( options == verbose2 ) || (options == all ) )
            {
                add( record , "#Blocs"     , blockInfo.num_blocks , "f=uint64,sum" );
                add( record , "Size"       , blockInfo.size , "f=uint64,sum" );
                add( record , "on Memory"  , blockInfo.size_on_memory , "f=uint64,sum" );
                add( record , "on Disk"    , blockInfo.size_on_disk , "f=uint64,sum" );
                add( record , "Locked"     , blockInfo.size_locked , "f=uint64,sum" );
                add( record , "Time from"  , (size_t)blockInfo.min_time , "f=time,different" );
                add( record , "Time to"    , (size_t)blockInfo.max_time , "f=time,different" );
            }

        }

    }
}
<|endoftext|>


<commit_before>/*
 * (C) Copyright 2015 ETH Zurich Systems Group (http://www.systems.ethz.ch/) and others.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Contributors:
 *     Markus Pilman <mpilman@inf.ethz.ch>
 *     Simon Loesing <sloesing@inf.ethz.ch>
 *     Thomas Etter <etterth@gmail.com>
 *     Kevin Bocksrocker <kevin.bocksrocker@gmail.com>
 *     Lucas Braun <braunl@inf.ethz.ch>
 */
#include "Transactions.hpp"
#include <telldb/Exceptions.hpp>

using namespace tell::db;

namespace tpcc {

OrderStatusResult Transactions::orderStatus(Transaction& tx, const OrderStatusIn& in) {
    OrderStatusResult result;
    try {
        auto oTableF = tx.openTable("order");
        auto olTableF = tx.openTable("order-line");
        auto cTableF = tx.openTable("customer");
        auto cTable = cTableF.get();
        auto oTable = oTableF.get();
        auto olTable = olTableF.get();
        // get Customer
        CustomerKey cKey{0, 0, 0};
        auto customerF = getCustomer(tx, in.selectByLastName, in.c_last, in.w_id, in.d_id, cTable, cKey);
        // get newest order
        auto iter = tx.reverse_lower_bound(oTable, "order_idx", {
                Field::create(in.w_id)
                , Field::create(in.d_id)
                , Field::create(cKey.c_id)
                , Field::create(int32_t(0))
                });
        OrderKey oKey{iter.value()};
        auto orderF = tx.get(oTable, iter.value());
        auto order = orderF.get();
        auto customer = customerF.get();
        auto ol_cnt = boost::any_cast<int16_t>(order.at("o_ol_cnt").value());
        // To get the order lines, we could use an index - but this is not necessary,
        // since we can generate all primary keys instead
        OrderlineKey olKey{in.w_id, in.d_id, oKey.o_id, int16_t(1)};
        std::vector<Future<Tuple>> reqs;
        reqs.reserve(ol_cnt);
        for (decltype(ol_cnt) i = 1; i <= ol_cnt; ++i) {
            olKey.ol_number = i;
            reqs.emplace_back(tx.get(olTable, olKey.key()));
        }
        for (auto& f : reqs) {
            f.get();
        }
        tx.commit();
        result.success = true;
    } catch (std::exception& ex) {
        result.success = false;
        result.error = ex.what();
    }
    return result;
}

} // namespace tpcc

<commit_msg>Fix reverse lower bound<commit_after>/*
 * (C) Copyright 2015 ETH Zurich Systems Group (http://www.systems.ethz.ch/) and others.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Contributors:
 *     Markus Pilman <mpilman@inf.ethz.ch>
 *     Simon Loesing <sloesing@inf.ethz.ch>
 *     Thomas Etter <etterth@gmail.com>
 *     Kevin Bocksrocker <kevin.bocksrocker@gmail.com>
 *     Lucas Braun <braunl@inf.ethz.ch>
 */
#include "Transactions.hpp"
#include <telldb/Exceptions.hpp>

using namespace tell::db;

namespace tpcc {

OrderStatusResult Transactions::orderStatus(Transaction& tx, const OrderStatusIn& in) {
    OrderStatusResult result;
    try {
        auto oTableF = tx.openTable("order");
        auto olTableF = tx.openTable("order-line");
        auto cTableF = tx.openTable("customer");
        auto cTable = cTableF.get();
        auto oTable = oTableF.get();
        auto olTable = olTableF.get();
        // get Customer
        CustomerKey cKey{0, 0, 0};
        auto customerF = getCustomer(tx, in.selectByLastName, in.c_last, in.w_id, in.d_id, cTable, cKey);
        // get newest order
        auto iter = tx.reverse_lower_bound(oTable, "order_idx", {
                Field::create(in.w_id)
                , Field::create(in.d_id)
                , Field::create(cKey.c_id)
                , Field::create(std::numeric_limits<int32_t>::max())
                });
        OrderKey oKey{iter.value()};
        auto orderF = tx.get(oTable, iter.value());
        auto order = orderF.get();
        auto customer = customerF.get();
        auto ol_cnt = boost::any_cast<int16_t>(order.at("o_ol_cnt").value());
        // To get the order lines, we could use an index - but this is not necessary,
        // since we can generate all primary keys instead
        OrderlineKey olKey{in.w_id, in.d_id, oKey.o_id, int16_t(1)};
        std::vector<Future<Tuple>> reqs;
        reqs.reserve(ol_cnt);
        for (decltype(ol_cnt) i = 1; i <= ol_cnt; ++i) {
            olKey.ol_number = i;
            reqs.emplace_back(tx.get(olTable, olKey.key()));
        }
        for (auto& f : reqs) {
            f.get();
        }
        tx.commit();
        result.success = true;
    } catch (std::exception& ex) {
        result.success = false;
        result.error = ex.what();
    }
    return result;
}

} // namespace tpcc

<|endoftext|>


<commit_before>#pragma once

#include <cstring>
#include <cstdio>
#include <string>
#include <iostream>
#include <map>

namespace minibson {

    // Basic types

    enum node_type {
        double_node = 0x01,
        string_node = 0x02,
        document_node = 0x03,
        binary_node = 0x05,
        boolean_node = 0x08,
        null_node = 0x0A,
        int32_node = 0x10,
        int64_node = 0x12,
        unknown_node = 0xFF
    };

    template<typename T> struct type_converter { };

    class node {
        public:
            virtual ~node() { }
            virtual void serialize(void* const buffer, const size_t count) const = 0;
            virtual size_t get_serialized_size() const = 0;
            virtual unsigned char get_node_code() const { return 0; }
            virtual node* copy() const = 0;
            virtual void dump(std::ostream&) const = 0;
            virtual void dump(std::ostream& stream, int level) const { dump(stream); }
            static node* create(node_type type, const void* const buffer, const size_t count);
    };

    // Value types

    class null : public node {
        public:
            null() { }

            null(const void* const buffer, const size_t count) { }

            void serialize(void* const buffer, const size_t count) const { }

            size_t get_serialized_size() const {
                return 0;
            }

            unsigned char get_node_code() const {
                return null_node;
            }

            node* copy() const {
                return new null();
            }

            void dump(std::ostream& stream) const { stream << "null"; };
    };

    template<typename T, node_type N>
        class scalar : public node {
            private:
                T value;
            public:
                scalar(const T value) : value(value) { }

                scalar(const void* const buffer, const size_t count) {
                    value = *reinterpret_cast<const T*>(buffer);
                };

                void serialize(void* const buffer, const size_t count) const {
                    *reinterpret_cast<T*>(buffer) = value;
                }

                size_t get_serialized_size() const {
                    return sizeof(T);
                }

                unsigned char get_node_code() const {
                    return N;
                }

                node* copy() const {
                    return new scalar<T, N>(value);
                }

                void dump(std::ostream& stream) const { stream << value; };

                const T& get_value() const { return value; }
        };

    class int32 : public scalar<int, int32_node> {
        public:
            int32(const int value) : scalar<int, int32_node>(value) { }

            int32(const void* const buffer, const size_t count) : scalar<int, int32_node>(buffer, count) { };
    };

    template<> struct type_converter<int> { enum { node_type_code = int32_node }; typedef int32 node_class; };

    class int64 : public scalar<long long int, int64_node> {
        public:
            int64(const long long int value) : scalar<long long int, int64_node>(value) { }

            int64(const void* const buffer, const size_t count) : scalar<long long int, int64_node>(buffer, count) { };
    };

    template<> struct type_converter<long long int> { enum { node_type_code = int64_node }; typedef int64 node_class; };

    class Double : public scalar<double, double_node> {
        public:
            Double(const double value) : scalar<double, double_node>(value) { }

            Double(const void* const buffer, const size_t count) : scalar<double, double_node>(buffer, count) { };
    };

    template<> struct type_converter<double> { enum { node_type_code = double_node }; typedef Double node_class; };

    class string : public node {
        private:
            std::string value;
        public:
            string(const std::string& value) : value(value) { }

            string(const void* const buffer, const size_t count) {
                value.assign(reinterpret_cast<const char*>(buffer) + sizeof(unsigned int), *reinterpret_cast<const unsigned int*>(buffer) - 1);
            };

            void serialize(void* const buffer, const size_t count) const {
                *reinterpret_cast<unsigned int*>(buffer) = value.length() + 1;
                std::memcpy(reinterpret_cast<char*>(buffer) + sizeof(unsigned int), value.c_str(), value.length());
                *(reinterpret_cast<char*>(buffer) + count - 1) = '\0';
            }

            size_t get_serialized_size() const {
                return sizeof(unsigned int) + value.length() + 1;
            }

            unsigned char get_node_code() const {
                return string_node;
            }

            node* copy() const {
                return new string(value);
            }

            void dump(std::ostream& stream) const { stream << "\"" << value << "\""; };

            const std::string& get_value() const { return value; }
    };

    template<> struct type_converter<std::string> { enum { node_type_code = string_node }; typedef string node_class; };

    class boolean : public node {
        private:
            bool value;
        public:
            boolean(const bool value) : value(value) { }

            boolean(const void* const buffer, const size_t count) {
                switch (*reinterpret_cast<const unsigned char*>(buffer)) {
                    case 1: value = true; break;
                    default: value = false; break;
                }
            };

            void serialize(void* const buffer, const size_t count) const {
                *reinterpret_cast<unsigned char*>(buffer) = value ? true : false;
            }

            size_t get_serialized_size() const {
                return 1;
            }

            unsigned char get_node_code() const {
                return boolean_node;
            }

            node* copy() const {
                return new boolean(value);
            }

            void dump(std::ostream& stream) const { stream << (value ? "true" : "false"); };

            const bool& get_value() const { return value; }
    };

    template<> struct type_converter<bool> { enum { node_type_code = boolean_node }; typedef boolean node_class; };

    class binary : public node {
        public:
            struct buffer {
                buffer(const buffer& other) : owned(true) {
                    length = other.length;
                    data = new unsigned char[length];
                    std::memcpy(data, other.data, length);
                }

                buffer(void* data, size_t length) : data(data), length(length), owned(false) { }

                ~buffer() {
                    if (owned)
                        delete[] reinterpret_cast<unsigned char*>(data);
                }

                void dump(std::ostream& stream) const { stream << "<binary: " << length << " bytes>"; };

                void* data;
                size_t length;
                bool owned;
            };

        private:
            buffer value;

        public:
            binary(const buffer& buffer) : value(buffer) { }

            binary(const void* const buffer, const size_t count, const bool create = false) : value(NULL, 0) {
                const unsigned char* byte_buffer = reinterpret_cast<const unsigned char*>(buffer);

                if (create) {
                    value.length = count;
                    value.data = new unsigned char[value.length];
                    std::memcpy(value.data, byte_buffer, value.length);
                }
                else {
                    value.length = *reinterpret_cast<const size_t*>(byte_buffer);
                    value.data = new unsigned char[value.length];
                    std::memcpy(value.data, byte_buffer + 5, value.length);
                }

                value.owned = true;
            };

            void serialize(void* const buffer, const size_t count) const {
                unsigned char* byte_buffer = reinterpret_cast<unsigned char*>(buffer);

                *reinterpret_cast<size_t*>(byte_buffer) = value.length;
                std::memcpy(byte_buffer + 5, value.data, value.length);
            }

            size_t get_serialized_size() const {
                return 5 + value.length;
            }

            unsigned char get_node_code() const {
                return binary_node;
            }

            node* copy() const {
                return new binary(value.data, value.length, true);
            }

            void dump(std::ostream& stream) const { value.dump(stream); };

            const buffer get_value() const { return value; }
    };

    template<> struct type_converter< binary::buffer > { enum { node_type_code = binary_node }; typedef binary node_class; };

    // Composite types

    class element_list : protected std::map<std::string, node*>, public node {
        public:
            typedef std::map<std::string, node*>::const_iterator const_iterator;

            element_list() { }

            element_list(const element_list& other) {
                for (const_iterator i = other.begin(); i != other.end(); i++)
                    (*this)[i->first] = i->second->copy();
            }

            element_list(const void* const buffer, const size_t count) {
                const unsigned char* byte_buffer = reinterpret_cast<const unsigned char*>(buffer);
                size_t position = 0;

                while (position < count) {
                    node_type type = static_cast<node_type>(byte_buffer[position++]);
                    std::string name(reinterpret_cast<const char*>(byte_buffer + position));
                    node* node = NULL;

                    position += name.length() + 1;
                    node = node::create(type, byte_buffer + position, count - position);

                    if (node != NULL) {
                        position += node->get_serialized_size();
                        (*this)[name] = node;
                    }
                    else
                        break;
                }
            }

            void serialize(void* const buffer, const size_t count) const {
                unsigned char* byte_buffer = reinterpret_cast<unsigned char*>(buffer);
                int position = 0;

                for (const_iterator i = begin(); i != end(); i++) {
                    // Header
                    byte_buffer[position] = i->second->get_node_code();
                    position++;
                    // Key
                    std::strcpy(reinterpret_cast<char*>(byte_buffer + position), i->first.c_str());
                    position += i->first.length() + 1;
                    // Value
                    i->second->serialize(byte_buffer + position, count - position);
                    position += i->second->get_serialized_size();
                }
            }

            size_t get_serialized_size() const {
                size_t result = 0;

                for (const_iterator i = begin(); i != end(); i++)
                    result += 1 + i->first.length() + 1 + i->second->get_serialized_size();

                return result;
            }

            node* copy() const {
                return new element_list(*this);
            }

            void dump(std::ostream& stream) const {
                stream << "{ ";

                for (const_iterator i = begin(); i != end(); i++) {
                    stream << "\"" << i->first << "\": ";
                    i->second->dump(stream);

                    if (++i != end())
                        stream << ", ";
                    --i;
                }

                stream << " }";
            }

            void dump(std::ostream& stream, const int level) const {
                stream << "{ ";

                for (const_iterator i = begin(); i != end(); i++) {
                    stream << std::endl;

                    for (int j = 0; j < level + 1; j++)
                        stream << "\t";

                    stream << "\"" << i->first << "\": ";
                    i->second->dump(stream, level + 1);

                    if (++i != end())
                        stream << ", ";
                    --i;
                }

                stream << std::endl;

                for (int j = 0; j < level; j++)
                    stream << "\t";

                stream << "}";
            }

            const_iterator begin() const {
                return std::map<std::string, node*>::begin();
            }

            const_iterator end() const {
                return std::map<std::string, node*>::end();
            }

            bool contains(const std::string& key) const {
                return (std::map<std::string, node*>::find(key) != end());
            }

            template<typename T>
            bool contains(const std::string& key) const {
                const_iterator position = std::map<std::string, node*>::find(key);
                return (position != end()) && (position->second->get_node_code() == type_converter<T>::node_type_code);
            }

            ~element_list() {
                for (const_iterator i = begin(); i != end(); i++)
                    delete i->second;
            }

    };

    class document : public element_list {
        public:
            document() { }

            document(const void* const buffer, const size_t count) : element_list(reinterpret_cast<const unsigned char*>(buffer) + 4, *reinterpret_cast<const size_t*>(buffer) - 4 - 1) { }

            void serialize(void* const buffer, const size_t count) const {
                size_t serialized_size = get_serialized_size();

                if (count >= serialized_size) {
                    unsigned char* byte_buffer = reinterpret_cast<unsigned char*>(buffer);

                    *reinterpret_cast<int*>(buffer) = serialized_size;
                    element_list::serialize(byte_buffer + 4, count - 4 - 1);
                    byte_buffer[4 + element_list::get_serialized_size()] = 0;
                }
            }

            size_t get_serialized_size() const {
                return 4 + element_list::get_serialized_size() + 1;
            }

            unsigned char get_node_code() const {
                return document_node;
            }

            node* copy() const {
                return new document(*this);
            }

            template<typename result_type>
            const result_type get(const std::string& key, const result_type& _default) const {
                const node_type node_type_code = static_cast<node_type>(type_converter<result_type>::node_type_code);
                typedef typename type_converter<result_type>::node_class node_class;

                if ((find(key) != end()) && (at(key)->get_node_code() == node_type_code))
                    return reinterpret_cast<const node_class*>(at(key))->get_value();
                else
                    return _default;
            }

            const document& get(const std::string& key, const document& _default) const {
                if ((find(key) != end()) && (at(key)->get_node_code() == document_node))
                    return *reinterpret_cast<const document*>(at(key));
                else
                    return _default;
            }

            const std::string get(const std::string& key, const char* _default) const {
                if ((find(key) != end()) && (at(key)->get_node_code() == string_node))
                    return reinterpret_cast<const string*>(at(key))->get_value();
                else
                    return std::string(_default);
            }

            template<typename value_type>
            document& set(const std::string& key, const value_type& value) {
                typedef typename type_converter<value_type>::node_class node_class;

                if (find(key) != end())
                    delete (*this)[key];

                (*this)[key] = new node_class(value);
                return (*this);
            }

            document& set(const std::string& key, const char* value) {
                if (find(key) != end())
                    delete (*this)[key];

                (*this)[key] = new string(value);
                return (*this);
            }

            document& set(const std::string& key, const document& value) {
                if (find(key) != end())
                    delete (*this)[key];

                (*this)[key] = value.copy();
                return (*this);
            }

            document& set(const std::string& key) {
                if (find(key) != end())
                    delete (*this)[key];

                (*this)[key] = new null();
                return (*this);
            }
    };

    template<> struct type_converter< document > { enum { node_type_code = document_node }; typedef document node_class; };

    inline node* node::create(node_type type, const void * const buffer, const size_t count) {
        switch (type) {
            case null_node: return new null();
            case int32_node: return new int32(buffer, count);
            case int64_node: return new int64(buffer, count);
            case double_node: return new Double(buffer, count);
            case document_node: return new document(buffer, count);
            case string_node: return new string(buffer, count);
            case binary_node: return new binary(buffer, count);
            case boolean_node: return new boolean(buffer, count);
            default: return NULL;
        }
    }
}
<commit_msg>Fix usage of size_t in fixed-width serialized fields.<commit_after>#pragma once

#include <cstring>
#include <cstdio>
#include <string>
#include <iostream>
#include <map>

namespace minibson {

    // Basic types

    enum node_type {
        double_node = 0x01,
        string_node = 0x02,
        document_node = 0x03,
        binary_node = 0x05,
        boolean_node = 0x08,
        null_node = 0x0A,
        int32_node = 0x10,
        int64_node = 0x12,
        unknown_node = 0xFF
    };

    template<typename T> struct type_converter { };

    class node {
        public:
            virtual ~node() { }
            virtual void serialize(void* const buffer, const size_t count) const = 0;
            virtual size_t get_serialized_size() const = 0;
            virtual unsigned char get_node_code() const { return 0; }
            virtual node* copy() const = 0;
            virtual void dump(std::ostream&) const = 0;
            virtual void dump(std::ostream& stream, int level) const { dump(stream); }
            static node* create(node_type type, const void* const buffer, const size_t count);
    };

    // Value types

    class null : public node {
        public:
            null() { }

            null(const void* const buffer, const size_t count) { }

            void serialize(void* const buffer, const size_t count) const { }

            size_t get_serialized_size() const {
                return 0;
            }

            unsigned char get_node_code() const {
                return null_node;
            }

            node* copy() const {
                return new null();
            }

            void dump(std::ostream& stream) const { stream << "null"; };
    };

    template<typename T, node_type N>
        class scalar : public node {
            private:
                T value;
            public:
                scalar(const T value) : value(value) { }

                scalar(const void* const buffer, const size_t count) {
                    value = *reinterpret_cast<const T*>(buffer);
                };

                void serialize(void* const buffer, const size_t count) const {
                    *reinterpret_cast<T*>(buffer) = value;
                }

                size_t get_serialized_size() const {
                    return sizeof(T);
                }

                unsigned char get_node_code() const {
                    return N;
                }

                node* copy() const {
                    return new scalar<T, N>(value);
                }

                void dump(std::ostream& stream) const { stream << value; };

                const T& get_value() const { return value; }
        };

    class int32 : public scalar<int, int32_node> {
        public:
            int32(const int value) : scalar<int, int32_node>(value) { }

            int32(const void* const buffer, const size_t count) : scalar<int, int32_node>(buffer, count) { };
    };

    template<> struct type_converter<int> { enum { node_type_code = int32_node }; typedef int32 node_class; };

    class int64 : public scalar<long long int, int64_node> {
        public:
            int64(const long long int value) : scalar<long long int, int64_node>(value) { }

            int64(const void* const buffer, const size_t count) : scalar<long long int, int64_node>(buffer, count) { };
    };

    template<> struct type_converter<long long int> { enum { node_type_code = int64_node }; typedef int64 node_class; };

    class Double : public scalar<double, double_node> {
        public:
            Double(const double value) : scalar<double, double_node>(value) { }

            Double(const void* const buffer, const size_t count) : scalar<double, double_node>(buffer, count) { };
    };

    template<> struct type_converter<double> { enum { node_type_code = double_node }; typedef Double node_class; };

    class string : public node {
        private:
            std::string value;
        public:
            string(const std::string& value) : value(value) { }

            string(const void* const buffer, const size_t count) {
                value.assign(reinterpret_cast<const char*>(buffer) + sizeof(unsigned int), *reinterpret_cast<const unsigned int*>(buffer) - 1);
            };

            void serialize(void* const buffer, const size_t count) const {
                *reinterpret_cast<unsigned int*>(buffer) = value.length() + 1;
                std::memcpy(reinterpret_cast<char*>(buffer) + sizeof(unsigned int), value.c_str(), value.length());
                *(reinterpret_cast<char*>(buffer) + count - 1) = '\0';
            }

            size_t get_serialized_size() const {
                return sizeof(unsigned int) + value.length() + 1;
            }

            unsigned char get_node_code() const {
                return string_node;
            }

            node* copy() const {
                return new string(value);
            }

            void dump(std::ostream& stream) const { stream << "\"" << value << "\""; };

            const std::string& get_value() const { return value; }
    };

    template<> struct type_converter<std::string> { enum { node_type_code = string_node }; typedef string node_class; };

    class boolean : public node {
        private:
            bool value;
        public:
            boolean(const bool value) : value(value) { }

            boolean(const void* const buffer, const size_t count) {
                switch (*reinterpret_cast<const unsigned char*>(buffer)) {
                    case 1: value = true; break;
                    default: value = false; break;
                }
            };

            void serialize(void* const buffer, const size_t count) const {
                *reinterpret_cast<unsigned char*>(buffer) = value ? true : false;
            }

            size_t get_serialized_size() const {
                return 1;
            }

            unsigned char get_node_code() const {
                return boolean_node;
            }

            node* copy() const {
                return new boolean(value);
            }

            void dump(std::ostream& stream) const { stream << (value ? "true" : "false"); };

            const bool& get_value() const { return value; }
    };

    template<> struct type_converter<bool> { enum { node_type_code = boolean_node }; typedef boolean node_class; };

    class binary : public node {
        public:
            struct buffer {
                buffer(const buffer& other) : owned(true) {
                    length = other.length;
                    data = new unsigned char[length];
                    std::memcpy(data, other.data, length);
                }

                buffer(void* data, size_t length) : data(data), length(length), owned(false) { }

                ~buffer() {
                    if (owned)
                        delete[] reinterpret_cast<unsigned char*>(data);
                }

                void dump(std::ostream& stream) const { stream << "<binary: " << length << " bytes>"; };

                void* data;
                size_t length;
                bool owned;
            };

        private:
            buffer value;

        public:
            binary(const buffer& buffer) : value(buffer) { }

            binary(const void* const buffer, const size_t count, const bool create = false) : value(NULL, 0) {
                const unsigned char* byte_buffer = reinterpret_cast<const unsigned char*>(buffer);

                if (create) {
                    value.length = count;
                    value.data = new unsigned char[value.length];
                    std::memcpy(value.data, byte_buffer, value.length);
                }
                else {
                    value.length = *reinterpret_cast<const int*>(byte_buffer);
                    value.data = new unsigned char[value.length];
                    std::memcpy(value.data, byte_buffer + 5, value.length);
                }

                value.owned = true;
            };

            void serialize(void* const buffer, const size_t count) const {
                unsigned char* byte_buffer = reinterpret_cast<unsigned char*>(buffer);

                *reinterpret_cast<int*>(byte_buffer) = value.length;
                std::memcpy(byte_buffer + 5, value.data, value.length);
            }

            size_t get_serialized_size() const {
                return 5 + value.length;
            }

            unsigned char get_node_code() const {
                return binary_node;
            }

            node* copy() const {
                return new binary(value.data, value.length, true);
            }

            void dump(std::ostream& stream) const { value.dump(stream); };

            const buffer get_value() const { return value; }
    };

    template<> struct type_converter< binary::buffer > { enum { node_type_code = binary_node }; typedef binary node_class; };

    // Composite types

    class element_list : protected std::map<std::string, node*>, public node {
        public:
            typedef std::map<std::string, node*>::const_iterator const_iterator;

            element_list() { }

            element_list(const element_list& other) {
                for (const_iterator i = other.begin(); i != other.end(); i++)
                    (*this)[i->first] = i->second->copy();
            }

            element_list(const void* const buffer, const size_t count) {
                const unsigned char* byte_buffer = reinterpret_cast<const unsigned char*>(buffer);
                size_t position = 0;

                while (position < count) {
                    node_type type = static_cast<node_type>(byte_buffer[position++]);
                    std::string name(reinterpret_cast<const char*>(byte_buffer + position));
                    node* node = NULL;

                    position += name.length() + 1;
                    node = node::create(type, byte_buffer + position, count - position);

                    if (node != NULL) {
                        position += node->get_serialized_size();
                        (*this)[name] = node;
                    }
                    else
                        break;
                }
            }

            void serialize(void* const buffer, const size_t count) const {
                unsigned char* byte_buffer = reinterpret_cast<unsigned char*>(buffer);
                int position = 0;

                for (const_iterator i = begin(); i != end(); i++) {
                    // Header
                    byte_buffer[position] = i->second->get_node_code();
                    position++;
                    // Key
                    std::strcpy(reinterpret_cast<char*>(byte_buffer + position), i->first.c_str());
                    position += i->first.length() + 1;
                    // Value
                    i->second->serialize(byte_buffer + position, count - position);
                    position += i->second->get_serialized_size();
                }
            }

            size_t get_serialized_size() const {
                size_t result = 0;

                for (const_iterator i = begin(); i != end(); i++)
                    result += 1 + i->first.length() + 1 + i->second->get_serialized_size();

                return result;
            }

            node* copy() const {
                return new element_list(*this);
            }

            void dump(std::ostream& stream) const {
                stream << "{ ";

                for (const_iterator i = begin(); i != end(); i++) {
                    stream << "\"" << i->first << "\": ";
                    i->second->dump(stream);

                    if (++i != end())
                        stream << ", ";
                    --i;
                }

                stream << " }";
            }

            void dump(std::ostream& stream, const int level) const {
                stream << "{ ";

                for (const_iterator i = begin(); i != end(); i++) {
                    stream << std::endl;

                    for (int j = 0; j < level + 1; j++)
                        stream << "\t";

                    stream << "\"" << i->first << "\": ";
                    i->second->dump(stream, level + 1);

                    if (++i != end())
                        stream << ", ";
                    --i;
                }

                stream << std::endl;

                for (int j = 0; j < level; j++)
                    stream << "\t";

                stream << "}";
            }

            const_iterator begin() const {
                return std::map<std::string, node*>::begin();
            }

            const_iterator end() const {
                return std::map<std::string, node*>::end();
            }

            bool contains(const std::string& key) const {
                return (std::map<std::string, node*>::find(key) != end());
            }

            template<typename T>
            bool contains(const std::string& key) const {
                const_iterator position = std::map<std::string, node*>::find(key);
                return (position != end()) && (position->second->get_node_code() == type_converter<T>::node_type_code);
            }

            ~element_list() {
                for (const_iterator i = begin(); i != end(); i++)
                    delete i->second;
            }

    };

    class document : public element_list {
        public:
            document() { }

            document(const void* const buffer, const size_t count) : element_list(reinterpret_cast<const unsigned char*>(buffer) + 4, *reinterpret_cast<const int*>(buffer) - 4 - 1) { }

            void serialize(void* const buffer, const size_t count) const {
                size_t serialized_size = get_serialized_size();

                if (count >= serialized_size) {
                    unsigned char* byte_buffer = reinterpret_cast<unsigned char*>(buffer);

                    *reinterpret_cast<int*>(buffer) = serialized_size;
                    element_list::serialize(byte_buffer + 4, count - 4 - 1);
                    byte_buffer[4 + element_list::get_serialized_size()] = 0;
                }
            }

            size_t get_serialized_size() const {
                return 4 + element_list::get_serialized_size() + 1;
            }

            unsigned char get_node_code() const {
                return document_node;
            }

            node* copy() const {
                return new document(*this);
            }

            template<typename result_type>
            const result_type get(const std::string& key, const result_type& _default) const {
                const node_type node_type_code = static_cast<node_type>(type_converter<result_type>::node_type_code);
                typedef typename type_converter<result_type>::node_class node_class;

                if ((find(key) != end()) && (at(key)->get_node_code() == node_type_code))
                    return reinterpret_cast<const node_class*>(at(key))->get_value();
                else
                    return _default;
            }

            const document& get(const std::string& key, const document& _default) const {
                if ((find(key) != end()) && (at(key)->get_node_code() == document_node))
                    return *reinterpret_cast<const document*>(at(key));
                else
                    return _default;
            }

            const std::string get(const std::string& key, const char* _default) const {
                if ((find(key) != end()) && (at(key)->get_node_code() == string_node))
                    return reinterpret_cast<const string*>(at(key))->get_value();
                else
                    return std::string(_default);
            }

            template<typename value_type>
            document& set(const std::string& key, const value_type& value) {
                typedef typename type_converter<value_type>::node_class node_class;

                if (find(key) != end())
                    delete (*this)[key];

                (*this)[key] = new node_class(value);
                return (*this);
            }

            document& set(const std::string& key, const char* value) {
                if (find(key) != end())
                    delete (*this)[key];

                (*this)[key] = new string(value);
                return (*this);
            }

            document& set(const std::string& key, const document& value) {
                if (find(key) != end())
                    delete (*this)[key];

                (*this)[key] = value.copy();
                return (*this);
            }

            document& set(const std::string& key) {
                if (find(key) != end())
                    delete (*this)[key];

                (*this)[key] = new null();
                return (*this);
            }
    };

    template<> struct type_converter< document > { enum { node_type_code = document_node }; typedef document node_class; };

    inline node* node::create(node_type type, const void * const buffer, const size_t count) {
        switch (type) {
            case null_node: return new null();
            case int32_node: return new int32(buffer, count);
            case int64_node: return new int64(buffer, count);
            case double_node: return new Double(buffer, count);
            case document_node: return new document(buffer, count);
            case string_node: return new string(buffer, count);
            case binary_node: return new binary(buffer, count);
            case boolean_node: return new boolean(buffer, count);
            default: return NULL;
        }
    }
}
<|endoftext|>


<commit_before>#pragma once

#include <string>
#include <memory>

namespace ncv
{
        ///
        /// the clonable interface to be used with a manager:
        ///      ::make(const tstring&)         - create a new object (with the given configuration)
        ///      ::clone()                      - create a copy of the current object
        ///      ::configuration()              - parametrization
        ///      ::description()                - short description (configuration included)
        ///
        template
        <
                typename tobject,
                typename tstring = std::string
        >
        class clonable_t
        {
        public:

                typedef tobject                         object_t;
                typedef tstring                         string_t;
                typedef std::shared_ptr<tobject>        robject_t;

                ///
                /// \brief constructor
                ///
                clonable_t(const tstring& configuration)
                        :       m_configuration(configuration)
                {
                }

                ///
                /// \brief create an object clone
                ///
                virtual robject_t make(const tstring& configuration) const = 0;
                virtual robject_t clone() const = 0;

                ///
                /// \brief describe the object
                ///
                tstring configuration() const { return m_configuration; }
                virtual tstring description() const = 0;

        protected:

                // attributes
                tstring         m_configuration;
        };

        #define NANOCV_MAKE_CLONABLE(base_class, description_text) \
                virtual robject_t make(const string_t& configuration) const override \
                { \
                        return robject_t(new base_class(configuration)); \
                } \
                virtual robject_t clone() const override \
                { \
                        return robject_t(new base_class(*this)); \
                } \
                virtual string_t description() const override \
                { \
                        return description_text; \
                }
}
<commit_msg>style<commit_after>#pragma once

#include <string>
#include <memory>

namespace ncv
{
        ///
        /// the clonable interface to be used with a manager:
        ///      ::make(const tstring&)         - create a new object (with the given configuration)
        ///      ::clone()                      - create a copy of the current object
        ///      ::configuration()              - parametrization
        ///      ::description()                - short description (configuration included)
        ///
        template
        <
                typename tobject,
                typename tstring = std::string
        >
        class clonable_t
        {
        public:

                typedef tobject                         object_t;
                typedef tstring                         string_t;
                typedef std::shared_ptr<tobject>        robject_t;

                ///
                /// \brief constructor
                ///
                clonable_t(const tstring& configuration)
                        :       m_configuration(configuration)
                {
                }

                ///
                /// \brief create an object clone
                ///
                virtual robject_t make(const tstring& configuration) const = 0;
                virtual robject_t clone() const = 0;

                ///
                /// \brief describe the object
                ///
                tstring configuration() const { return m_configuration; }
                virtual tstring description() const = 0;

        protected:

                // attributes
                tstring         m_configuration;
        };

        #define NANOCV_MAKE_CLONABLE(base_class, description_text) \
                virtual robject_t make(const string_t& configuration) const override \
                { \
                        return std::make_shared<base_class>(configuration); \
                } \
                virtual robject_t clone() const override \
                { \
                        return std::make_shared<base_class>(*this); \
                } \
                virtual string_t description() const override \
                { \
                        return description_text; \
                }
}
<|endoftext|>


<commit_before>#include <patlms/type/time.h>

#include <patlms/type/exception/detail/wrong_time_value_exception.h>
#include <patlms/type/exception/detail/time_parse_exception.h>

#include <regex>
#include <iostream>
namespace type
{

const Time Time::Create(int hour, int minute, int second) {
  Time t;
  t.Set(hour, minute, second);

  return t;
}

const Time Time::Create(const std::string &time) {
  int hour = 0, minute = 0, second = 0;
  std::regex pattern("^\\s*([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})\\s*$");

  std::cmatch cm;
  if (std::regex_match(time.c_str(), cm, pattern)) {
    hour = stoi(cm[1]);
    minute = stoi(cm[2]);
    second = stoi(cm[3]);
  }
  else
    throw exception::detail::TimeParseException();

  return Time::Create(hour, minute, second);
}

void Time::Set(int hour, int minute, int second) {
  CheckTime(hour, minute, second);

  hour_ = hour;
  minute_ = minute;
  second_ = second;
}

const std::string Time::ToString() const {
  auto helper = [](int i) {
    return (i < 10 ? "0" : "") +std::to_string(i);
  };

  const std::string time_string = helper(hour_) + ":" + helper(minute_) + ":" + helper(second_);

  return time_string;
}

bool Time::operator==(const Time &t2) const {
  return (GetHour() == t2.GetHour()) &&
      (GetMinute() == t2.GetMinute()) &&
      (GetSecond() == t2.GetSecond());
}

bool Time::operator<(const Time &t2) const {
  if ((GetHour() == t2.GetHour()) &&
      (GetMinute() == t2.GetMinute()) &&
      (GetSecond() < t2.GetSecond()))
    return true;
  else if ((GetHour() == t2.GetHour()) &&
      (GetMinute() < t2.GetMinute()))
    return true;
  else if ((GetHour() < t2.GetHour()))
    return true;

  return false;
}

Time Time::operator-(long seconds) const {
  int hour = 0, minute = 0, second = 0;
  long time_in_seconds = GetHour() * 60 * 60 + GetMinute() * 60 + GetSecond() - seconds;

  if (time_in_seconds > 0) {
    hour = time_in_seconds / (60 * 60);
    time_in_seconds = time_in_seconds - hour * (60 * 60);

    minute = time_in_seconds / 60;
    time_in_seconds = time_in_seconds - minute * 60;

    second = time_in_seconds;
  }

  return Time::Create(hour, minute, second);
}

Time Time::operator+(long seconds) const {
  int hour = 23, minute = 59, second = 59;

  if (seconds < 23 * 60 * 60 + 59 * 60 + 59) {
    long time_in_seconds = GetHour() * 60 * 60 + GetMinute() * 60 + GetSecond() + seconds;

    if (time_in_seconds < 23 * 60 * 60 + 59 * 60 + 59) {
      hour = time_in_seconds / (60 * 60);
      time_in_seconds = time_in_seconds - hour * (60 * 60);

      minute = time_in_seconds / 60;
      time_in_seconds = time_in_seconds - minute * 60;

      second = time_in_seconds;
    }
  }

  return Time::Create(hour, minute, second);
}

void Time::CheckTime(int hour, int minute, int second) {
  if ((hour < 0 || hour > 24) ||
      (minute < 0 || minute > 59) ||
      (second < 0 || second > 59)) {
    throw exception::detail::WrongTimeValueException();
  }
}

std::ostream& operator<<(std::ostream& os, const type::Time &time) {
  os << time.GetHour() << ":" << time.GetMinute() << ":" << time.GetSecond();
  return os;
}

}
<commit_msg>Fix Time hour range<commit_after>#include <patlms/type/time.h>

#include <patlms/type/exception/detail/wrong_time_value_exception.h>
#include <patlms/type/exception/detail/time_parse_exception.h>

#include <regex>
#include <iostream>
namespace type
{

const Time Time::Create(int hour, int minute, int second) {
  Time t;
  t.Set(hour, minute, second);

  return t;
}

const Time Time::Create(const std::string &time) {
  int hour = 0, minute = 0, second = 0;
  std::regex pattern("^\\s*([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})\\s*$");

  std::cmatch cm;
  if (std::regex_match(time.c_str(), cm, pattern)) {
    hour = stoi(cm[1]);
    minute = stoi(cm[2]);
    second = stoi(cm[3]);
  }
  else
    throw exception::detail::TimeParseException();

  return Time::Create(hour, minute, second);
}

void Time::Set(int hour, int minute, int second) {
  CheckTime(hour, minute, second);

  hour_ = hour;
  minute_ = minute;
  second_ = second;
}

const std::string Time::ToString() const {
  auto helper = [](int i) {
    return (i < 10 ? "0" : "") +std::to_string(i);
  };

  const std::string time_string = helper(hour_) + ":" + helper(minute_) + ":" + helper(second_);

  return time_string;
}

bool Time::operator==(const Time &t2) const {
  return (GetHour() == t2.GetHour()) &&
      (GetMinute() == t2.GetMinute()) &&
      (GetSecond() == t2.GetSecond());
}

bool Time::operator<(const Time &t2) const {
  if ((GetHour() == t2.GetHour()) &&
      (GetMinute() == t2.GetMinute()) &&
      (GetSecond() < t2.GetSecond()))
    return true;
  else if ((GetHour() == t2.GetHour()) &&
      (GetMinute() < t2.GetMinute()))
    return true;
  else if ((GetHour() < t2.GetHour()))
    return true;

  return false;
}

Time Time::operator-(long seconds) const {
  int hour = 0, minute = 0, second = 0;
  long time_in_seconds = GetHour() * 60 * 60 + GetMinute() * 60 + GetSecond() - seconds;

  if (time_in_seconds > 0) {
    hour = time_in_seconds / (60 * 60);
    time_in_seconds = time_in_seconds - hour * (60 * 60);

    minute = time_in_seconds / 60;
    time_in_seconds = time_in_seconds - minute * 60;

    second = time_in_seconds;
  }

  return Time::Create(hour, minute, second);
}

Time Time::operator+(long seconds) const {
  int hour = 23, minute = 59, second = 59;

  if (seconds < 23 * 60 * 60 + 59 * 60 + 59) {
    long time_in_seconds = GetHour() * 60 * 60 + GetMinute() * 60 + GetSecond() + seconds;

    if (time_in_seconds < 23 * 60 * 60 + 59 * 60 + 59) {
      hour = time_in_seconds / (60 * 60);
      time_in_seconds = time_in_seconds - hour * (60 * 60);

      minute = time_in_seconds / 60;
      time_in_seconds = time_in_seconds - minute * 60;

      second = time_in_seconds;
    }
  }

  return Time::Create(hour, minute, second);
}

void Time::CheckTime(int hour, int minute, int second) {
  if ((hour < 0 || hour > 23) ||
      (minute < 0 || minute > 59) ||
      (second < 0 || second > 59)) {
    throw exception::detail::WrongTimeValueException();
  }
}

std::ostream& operator<<(std::ostream& os, const type::Time &time) {
  os << time.GetHour() << ":" << time.GetMinute() << ":" << time.GetSecond();
  return os;
}

}
<|endoftext|>