<commit_before>///
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2004-2007 Torsten Rahn  <tackat@kde.org>
// Copyright 2007      Inge Wallin   <ingwa@kde.org>
// Copyright 2007      Thomas Zander <zander@kde.org>
// Copyright 2010      Bastian Holst <bastianholst@gmx.de>
//

// Self
#include "NavigationWidget.h"

// Marble
#include "MarbleDebug.h"
#include "MarbleModel.h"
#include "MarbleWidget.h"
#include "MarbleRunnerManager.h"
#include "MarblePlacemarkModel.h"
#include "GeoSceneDocument.h"
#include "GeoSceneHead.h"

// Qt
#include <QtCore/QTime>
#include <QtCore/QTimer>
#include <QtGui/QSortFilterProxyModel>

using namespace Marble;

#include "ui_NavigationWidget.h"

namespace Marble
{

class NavigationWidgetPrivate
{
 public:
    Ui::NavigationWidget    m_navigationUi;
    MarbleWidget           *m_widget;
    QSortFilterProxyModel  *m_sortproxy;
    QString                 m_searchTerm;
    bool                    m_searchTriggered;
    MarbleRunnerManager    *m_runnerManager;
};

NavigationWidget::NavigationWidget( QWidget *parent, Qt::WindowFlags f )
    : QWidget( parent, f ),
      d( new NavigationWidgetPrivate() )
{
    d->m_searchTerm.clear();
    d->m_searchTriggered = false;
    d->m_widget = 0;

    d->m_navigationUi.setupUi( this );

    d->m_sortproxy = new QSortFilterProxyModel( this );
    d->m_navigationUi.locationListView->setModel( d->m_sortproxy );

    connect( d->m_navigationUi.goHomeButton,     SIGNAL( clicked() ),
             this,                               SIGNAL( goHome() ) );
    connect( d->m_navigationUi.zoomSlider,       SIGNAL( valueChanged( int ) ),
             this,                               SIGNAL( zoomChanged( int ) ) );
    connect( d->m_navigationUi.zoomInButton,     SIGNAL( clicked() ),
             this,                               SIGNAL( zoomIn() ) );
    connect( d->m_navigationUi.zoomOutButton,    SIGNAL( clicked() ),
             this,                               SIGNAL( zoomOut() ) );

    connect( d->m_navigationUi.zoomSlider,       SIGNAL( valueChanged( int ) ),
             this,                               SLOT( updateButtons( int ) ) );

    connect( d->m_navigationUi.moveLeftButton,   SIGNAL( clicked() ),
             this,                               SIGNAL( moveLeft() ) );
    connect( d->m_navigationUi.moveRightButton,  SIGNAL( clicked() ),
             this,                               SIGNAL( moveRight() ) );
    connect( d->m_navigationUi.moveUpButton,     SIGNAL( clicked() ),
             this,                               SIGNAL( moveUp() ) );
    connect( d->m_navigationUi.moveDownButton,   SIGNAL( clicked() ),
             this,                               SIGNAL( moveDown() ) );

    connect( d->m_navigationUi.locationListView, SIGNAL( activated( const QModelIndex& ) ),
             this,                               SLOT( mapCenterOnSignal( const QModelIndex& ) ) );

    connect( d->m_navigationUi.searchLineEdit,   SIGNAL( textChanged( const QString& ) ),
             this,                               SLOT( searchLineChanged( const QString& ) ) );
    connect( d->m_navigationUi.searchLineEdit,   SIGNAL( returnPressed() ),
             this,                               SLOT( searchReturnPressed() ) );

    connect( d->m_navigationUi.zoomSlider,       SIGNAL( sliderPressed() ),
             this,                               SLOT( adjustForAnimation() ) );
    connect( d->m_navigationUi.zoomSlider,       SIGNAL( sliderReleased() ),
             this,                               SLOT( adjustForStill() ) );
}

NavigationWidget::~NavigationWidget()
{
    delete d;
}

void NavigationWidget::setMarbleWidget( MarbleWidget *widget )
{
    d->m_runnerManager = new MarbleRunnerManager( widget->model()->pluginManager(), this );
    connect( d->m_runnerManager, SIGNAL( searchResultChanged(  QAbstractItemModel* ) ),
             this,               SLOT( setLocations( QAbstractItemModel* ) ) );

    d->m_widget = widget;
    d->m_runnerManager->setModel( widget->model() );

    // Make us aware of all the Placemarks in the MarbleModel so that
    // we can search them.
    setLocations( d->m_widget->placemarkModel() );

//    FIXME: Why does this fail: "selection model works on a different model than the view..." ?
//    d->m_navigationUi.locationListView->setSelectionModel( d->m_widget->placemarkSelectionModel() );

    // Connect necessary signals.
    connect( this, SIGNAL( goHome() ),         d->m_widget, SLOT( goHome() ) );
    connect( this, SIGNAL( zoomChanged(int) ), d->m_widget, SLOT( zoomView( int ) ) );
    connect( this, SIGNAL( zoomIn() ),         d->m_widget, SLOT( zoomIn() ) );
    connect( this, SIGNAL( zoomOut() ),        d->m_widget, SLOT( zoomOut() ) );

    connect( this, SIGNAL( moveLeft() ),  d->m_widget, SLOT( moveLeft() ) );
    connect( this, SIGNAL( moveRight() ), d->m_widget, SLOT( moveRight() ) );
    connect( this, SIGNAL( moveUp() ),    d->m_widget, SLOT( moveUp() ) );
    connect( this, SIGNAL( moveDown() ),  d->m_widget, SLOT( moveDown() ) );

    connect( d->m_widget, SIGNAL( zoomChanged( int ) ),
             this,        SLOT( changeZoom( int ) ) );

    connect( d->m_widget, SIGNAL( themeChanged( QString ) ),
             this,        SLOT( selectTheme( QString ) ) );
}

void NavigationWidget::changeZoom( int zoom )
{
    // There exists a circular signal/slot connection between MarbleWidget and this widget's
    // zoom slider. MarbleWidget prevents recursion, but it still loops one time unless
    // blocked here. Note that it would be possible to only connect the sliders
    // sliderMoved signal instead of its valueChanged signal above to break up the loop.
    // This however means that the slider cannot be operated with the mouse wheel, as this
    // does not emit the sliderMoved signal for some reason. Therefore the signal is blocked
    // below before calling setValue on the slider to avoid that it calls back to MarbleWidget,
    // and then un-blocked again to make user interaction possible.

    d->m_navigationUi.zoomSlider->blockSignals( true );

    d->m_navigationUi.zoomSlider->setValue( zoom );
    d->m_navigationUi.zoomSlider->setMinimum( minimumZoom() );
    // As we have disabled all zoomSlider Signals, we have to update our buttons seperately.
    updateButtons( zoom );

    d->m_navigationUi.zoomSlider->blockSignals( false );
}

void NavigationWidget::searchLineChanged( const QString &search )
{
    d->m_searchTerm = search;
    // if search line is empty, restore original geonames
    if ( d->m_searchTerm.isEmpty() )
        setLocations( d->m_widget->placemarkModel() );
    if ( d->m_searchTriggered )
        return;
    d->m_searchTriggered = true;
    QTimer::singleShot( 0, this, SLOT( search() ) );
}

void NavigationWidget::searchReturnPressed()
{
    // do nothing if search term empty
    if ( !d->m_searchTerm.isEmpty() ) {
        d->m_runnerManager->findPlacemarks( d->m_searchTerm );
    }
}

void NavigationWidget::search()
{
    d->m_searchTriggered = false;
    int  currentSelected = d->m_navigationUi.locationListView->currentIndex().row();
    d->m_navigationUi.locationListView->selectItem( d->m_searchTerm );
    if ( currentSelected != d->m_navigationUi.locationListView->currentIndex().row() )
        d->m_navigationUi.locationListView->activate();
}

void NavigationWidget::setLocations(QAbstractItemModel* locations)
{
    QTime t;
    t.start();
    d->m_sortproxy->setSourceModel( locations );
    d->m_sortproxy->setSortLocaleAware( true );
    d->m_sortproxy->setDynamicSortFilter( true );
    d->m_sortproxy->sort( 0 );
    d->m_widget->placemarkSelectionModel()->clear();
    mDebug() << "NavigationWidget (sort): Time elapsed:"<< t.elapsed() << " ms";
}

void NavigationWidget::selectTheme( const QString &theme )
{
    Q_UNUSED( theme )

    if( !d->m_widget )
        return;

    d->m_navigationUi.zoomSlider->setMaximum( d->m_widget->maximumZoom() );
    updateButtons( d->m_navigationUi.zoomSlider->value() );
}

void NavigationWidget::updateButtons( int value )
{
    if ( value <= d->m_navigationUi.zoomSlider->minimum() ) {
        d->m_navigationUi.zoomInButton->setEnabled( true );
        d->m_navigationUi.zoomOutButton->setEnabled( false );
    } else if ( value >= d->m_navigationUi.zoomSlider->maximum() ) {
        d->m_navigationUi.zoomInButton->setEnabled( false );
        d->m_navigationUi.zoomOutButton->setEnabled( true );
    } else {
        d->m_navigationUi.zoomInButton->setEnabled( true );
        d->m_navigationUi.zoomOutButton->setEnabled( true );
    }
}

void NavigationWidget::mapCenterOnSignal( const QModelIndex &index )
{
    if( !index.isValid() ) {
        return;
    }
    GeoDataObject *object
            = qVariantValue<GeoDataObject*>( index.model()->data(index, MarblePlacemarkModel::ObjectPointerRole ) );
    if ( dynamic_cast<GeoDataPlacemark*>(object) )
    {
        GeoDataCoordinates coord = ( dynamic_cast<GeoDataPlacemark*>( object ) )->coordinate();
        d->m_widget->centerOn( coord, true );
        d->m_widget->placemarkSelectionModel()->select( d->m_sortproxy->mapToSource( index ), QItemSelectionModel::ClearAndSelect );
    }
}

void NavigationWidget::adjustForAnimation()
{
    // TODO: use signals here as well
    if ( !d->m_widget )
        return;

    d->m_widget->setViewContext( Animation );
}

void NavigationWidget::adjustForStill()
{
    // TODO: use signals here as well
    if ( !d->m_widget )
        return;

    d->m_widget->setViewContext( Still );
}

void NavigationWidget::resizeEvent ( QResizeEvent * )
{
    if ( height() < 500 ) {
        if ( !d->m_navigationUi.zoomSlider->isHidden() ) {
            setUpdatesEnabled(false);
            d->m_navigationUi.zoomSlider->hide();
            d->m_navigationUi.m_pSpacerFrame->setSizePolicy( QSizePolicy::Preferred,
                                                             QSizePolicy::Expanding );
            setUpdatesEnabled(true);
        }
    } else {
        if ( d->m_navigationUi.zoomSlider->isHidden() ) {
            setUpdatesEnabled(false);
            d->m_navigationUi.zoomSlider->show();
            d->m_navigationUi.m_pSpacerFrame->setSizePolicy( QSizePolicy::Preferred,
                                                       QSizePolicy::Fixed );
            setUpdatesEnabled(true);
        }
    }
}

void NavigationWidget::setWorkOffline(bool offline)
{
    d->m_runnerManager->setWorkOffline( offline );
}

int NavigationWidget::minimumZoom() const
{
    return d->m_widget->minimumZoom();
}

}

#include "NavigationWidget.moc"
<commit_msg>Delay by 500ms before jumping after a search text is input<commit_after>///
// This file is part of the Marble Virtual Globe.
//
// This program is free software licensed under the GNU LGPL. You can
// find a copy of this license in LICENSE.txt in the top directory of
// the source code.
//
// Copyright 2004-2007 Torsten Rahn  <tackat@kde.org>
// Copyright 2007      Inge Wallin   <ingwa@kde.org>
// Copyright 2007      Thomas Zander <zander@kde.org>
// Copyright 2010      Bastian Holst <bastianholst@gmx.de>
//

// Self
#include "NavigationWidget.h"

// Marble
#include "MarbleDebug.h"
#include "MarbleModel.h"
#include "MarbleWidget.h"
#include "MarbleRunnerManager.h"
#include "MarblePlacemarkModel.h"
#include "GeoSceneDocument.h"
#include "GeoSceneHead.h"

// Qt
#include <QtCore/QTime>
#include <QtCore/QTimer>
#include <QtGui/QSortFilterProxyModel>

using namespace Marble;

#include "ui_NavigationWidget.h"

namespace Marble
{

class NavigationWidgetPrivate
{
 public:
    Ui::NavigationWidget    m_navigationUi;
    MarbleWidget           *m_widget;
    QSortFilterProxyModel  *m_sortproxy;
    QString                 m_searchTerm;
    MarbleRunnerManager    *m_runnerManager;
    QTimer                  m_deferSearch;
};

NavigationWidget::NavigationWidget( QWidget *parent, Qt::WindowFlags f )
    : QWidget( parent, f ),
      d( new NavigationWidgetPrivate() )
{
    d->m_searchTerm.clear();
    d->m_widget = 0;

    d->m_navigationUi.setupUi( this );

    d->m_sortproxy = new QSortFilterProxyModel( this );
    d->m_navigationUi.locationListView->setModel( d->m_sortproxy );
    d->m_deferSearch.setSingleShot( true );
    connect ( &d->m_deferSearch, SIGNAL( timeout() ),
              this, SLOT( search()) );

    connect( d->m_navigationUi.goHomeButton,     SIGNAL( clicked() ),
             this,                               SIGNAL( goHome() ) );
    connect( d->m_navigationUi.zoomSlider,       SIGNAL( valueChanged( int ) ),
             this,                               SIGNAL( zoomChanged( int ) ) );
    connect( d->m_navigationUi.zoomInButton,     SIGNAL( clicked() ),
             this,                               SIGNAL( zoomIn() ) );
    connect( d->m_navigationUi.zoomOutButton,    SIGNAL( clicked() ),
             this,                               SIGNAL( zoomOut() ) );

    connect( d->m_navigationUi.zoomSlider,       SIGNAL( valueChanged( int ) ),
             this,                               SLOT( updateButtons( int ) ) );

    connect( d->m_navigationUi.moveLeftButton,   SIGNAL( clicked() ),
             this,                               SIGNAL( moveLeft() ) );
    connect( d->m_navigationUi.moveRightButton,  SIGNAL( clicked() ),
             this,                               SIGNAL( moveRight() ) );
    connect( d->m_navigationUi.moveUpButton,     SIGNAL( clicked() ),
             this,                               SIGNAL( moveUp() ) );
    connect( d->m_navigationUi.moveDownButton,   SIGNAL( clicked() ),
             this,                               SIGNAL( moveDown() ) );

    connect( d->m_navigationUi.locationListView, SIGNAL( activated( const QModelIndex& ) ),
             this,                               SLOT( mapCenterOnSignal( const QModelIndex& ) ) );

    connect( d->m_navigationUi.searchLineEdit,   SIGNAL( textChanged( const QString& ) ),
             this,                               SLOT( searchLineChanged( const QString& ) ) );
    connect( d->m_navigationUi.searchLineEdit,   SIGNAL( returnPressed() ),
             this,                               SLOT( searchReturnPressed() ) );

    connect( d->m_navigationUi.zoomSlider,       SIGNAL( sliderPressed() ),
             this,                               SLOT( adjustForAnimation() ) );
    connect( d->m_navigationUi.zoomSlider,       SIGNAL( sliderReleased() ),
             this,                               SLOT( adjustForStill() ) );
}

NavigationWidget::~NavigationWidget()
{
    delete d;
}

void NavigationWidget::setMarbleWidget( MarbleWidget *widget )
{
    d->m_runnerManager = new MarbleRunnerManager( widget->model()->pluginManager(), this );
    connect( d->m_runnerManager, SIGNAL( searchResultChanged(  QAbstractItemModel* ) ),
             this,               SLOT( setLocations( QAbstractItemModel* ) ) );

    d->m_widget = widget;
    d->m_runnerManager->setModel( widget->model() );

    // Make us aware of all the Placemarks in the MarbleModel so that
    // we can search them.
    setLocations( d->m_widget->placemarkModel() );

//    FIXME: Why does this fail: "selection model works on a different model than the view..." ?
//    d->m_navigationUi.locationListView->setSelectionModel( d->m_widget->placemarkSelectionModel() );

    // Connect necessary signals.
    connect( this, SIGNAL( goHome() ),         d->m_widget, SLOT( goHome() ) );
    connect( this, SIGNAL( zoomChanged(int) ), d->m_widget, SLOT( zoomView( int ) ) );
    connect( this, SIGNAL( zoomIn() ),         d->m_widget, SLOT( zoomIn() ) );
    connect( this, SIGNAL( zoomOut() ),        d->m_widget, SLOT( zoomOut() ) );

    connect( this, SIGNAL( moveLeft() ),  d->m_widget, SLOT( moveLeft() ) );
    connect( this, SIGNAL( moveRight() ), d->m_widget, SLOT( moveRight() ) );
    connect( this, SIGNAL( moveUp() ),    d->m_widget, SLOT( moveUp() ) );
    connect( this, SIGNAL( moveDown() ),  d->m_widget, SLOT( moveDown() ) );

    connect( d->m_widget, SIGNAL( zoomChanged( int ) ),
             this,        SLOT( changeZoom( int ) ) );

    connect( d->m_widget, SIGNAL( themeChanged( QString ) ),
             this,        SLOT( selectTheme( QString ) ) );
}

void NavigationWidget::changeZoom( int zoom )
{
    // There exists a circular signal/slot connection between MarbleWidget and this widget's
    // zoom slider. MarbleWidget prevents recursion, but it still loops one time unless
    // blocked here. Note that it would be possible to only connect the sliders
    // sliderMoved signal instead of its valueChanged signal above to break up the loop.
    // This however means that the slider cannot be operated with the mouse wheel, as this
    // does not emit the sliderMoved signal for some reason. Therefore the signal is blocked
    // below before calling setValue on the slider to avoid that it calls back to MarbleWidget,
    // and then un-blocked again to make user interaction possible.

    d->m_navigationUi.zoomSlider->blockSignals( true );

    d->m_navigationUi.zoomSlider->setValue( zoom );
    d->m_navigationUi.zoomSlider->setMinimum( minimumZoom() );
    // As we have disabled all zoomSlider Signals, we have to update our buttons seperately.
    updateButtons( zoom );

    d->m_navigationUi.zoomSlider->blockSignals( false );
}

void NavigationWidget::searchLineChanged( const QString &search )
{
    d->m_searchTerm = search;
    // if search line is empty, restore original geonames
    if ( d->m_searchTerm.isEmpty() )
        setLocations( d->m_widget->placemarkModel() );
    d->m_deferSearch.start( 500 );
}

void NavigationWidget::searchReturnPressed()
{
    // do nothing if search term empty
    if ( !d->m_searchTerm.isEmpty() ) {
        d->m_runnerManager->findPlacemarks( d->m_searchTerm );
    }
}

void NavigationWidget::search()
{
    d->m_deferSearch.stop();
    int  currentSelected = d->m_navigationUi.locationListView->currentIndex().row();
    d->m_navigationUi.locationListView->selectItem( d->m_searchTerm );
    if ( currentSelected != d->m_navigationUi.locationListView->currentIndex().row() )
        d->m_navigationUi.locationListView->activate();
}

void NavigationWidget::setLocations(QAbstractItemModel* locations)
{
    QTime t;
    t.start();
    d->m_sortproxy->setSourceModel( locations );
    d->m_sortproxy->setSortLocaleAware( true );
    d->m_sortproxy->setDynamicSortFilter( true );
    d->m_sortproxy->sort( 0 );
    d->m_widget->placemarkSelectionModel()->clear();
    mDebug() << "NavigationWidget (sort): Time elapsed:"<< t.elapsed() << " ms";
}

void NavigationWidget::selectTheme( const QString &theme )
{
    Q_UNUSED( theme )

    if( !d->m_widget )
        return;

    d->m_navigationUi.zoomSlider->setMaximum( d->m_widget->maximumZoom() );
    updateButtons( d->m_navigationUi.zoomSlider->value() );
}

void NavigationWidget::updateButtons( int value )
{
    if ( value <= d->m_navigationUi.zoomSlider->minimum() ) {
        d->m_navigationUi.zoomInButton->setEnabled( true );
        d->m_navigationUi.zoomOutButton->setEnabled( false );
    } else if ( value >= d->m_navigationUi.zoomSlider->maximum() ) {
        d->m_navigationUi.zoomInButton->setEnabled( false );
        d->m_navigationUi.zoomOutButton->setEnabled( true );
    } else {
        d->m_navigationUi.zoomInButton->setEnabled( true );
        d->m_navigationUi.zoomOutButton->setEnabled( true );
    }
}

void NavigationWidget::mapCenterOnSignal( const QModelIndex &index )
{
    if( !index.isValid() ) {
        return;
    }
    GeoDataObject *object
            = qVariantValue<GeoDataObject*>( index.model()->data(index, MarblePlacemarkModel::ObjectPointerRole ) );
    if ( dynamic_cast<GeoDataPlacemark*>(object) )
    {
        GeoDataCoordinates coord = ( dynamic_cast<GeoDataPlacemark*>( object ) )->coordinate();
        d->m_widget->centerOn( coord, true );
        d->m_widget->placemarkSelectionModel()->select( d->m_sortproxy->mapToSource( index ), QItemSelectionModel::ClearAndSelect );
    }
}

void NavigationWidget::adjustForAnimation()
{
    // TODO: use signals here as well
    if ( !d->m_widget )
        return;

    d->m_widget->setViewContext( Animation );
}

void NavigationWidget::adjustForStill()
{
    // TODO: use signals here as well
    if ( !d->m_widget )
        return;

    d->m_widget->setViewContext( Still );
}

void NavigationWidget::resizeEvent ( QResizeEvent * )
{
    if ( height() < 500 ) {
        if ( !d->m_navigationUi.zoomSlider->isHidden() ) {
            setUpdatesEnabled(false);
            d->m_navigationUi.zoomSlider->hide();
            d->m_navigationUi.m_pSpacerFrame->setSizePolicy( QSizePolicy::Preferred,
                                                             QSizePolicy::Expanding );
            setUpdatesEnabled(true);
        }
    } else {
        if ( d->m_navigationUi.zoomSlider->isHidden() ) {
            setUpdatesEnabled(false);
            d->m_navigationUi.zoomSlider->show();
            d->m_navigationUi.m_pSpacerFrame->setSizePolicy( QSizePolicy::Preferred,
                                                       QSizePolicy::Fixed );
            setUpdatesEnabled(true);
        }
    }
}

void NavigationWidget::setWorkOffline(bool offline)
{
    d->m_runnerManager->setWorkOffline( offline );
}

int NavigationWidget::minimumZoom() const
{
    return d->m_widget->minimumZoom();
}

}

#include "NavigationWidget.moc"
<|endoftext|>


<commit_before>// Copyright (c) 2015-2017 Matthew Sitton <matthewsitton@gmail.com>
// See LICENSE in the project root for license information.

#pragma once
#include <memory>
#include <algorithm>

namespace ORCore
{
    struct BufferInfo
    {
        int channels;
        int frames;
    };

    // TODO - Actually move away from unique_ptr here to raw new/delete if needed because we need
    // to be able to pass in direct device pointers and such which would be bad if we tried to
    // free them. new/delete will only be called when the constructor with only size is passed in.
    // TODO - put channel # and number of frames in here.
    class Buffer
    {
    public:
        Buffer();
        Buffer(BufferInfo info);
        Buffer(float* buffer, BufferInfo info);
        Buffer(const Buffer& other);
        Buffer(Buffer&& other);
        ~Buffer();

        Buffer& operator=(const Buffer& other);
        Buffer& operator=(Buffer&& other);

        operator float*();

        void clone_type(const Buffer& other);

        BufferInfo get_info();
        int size();
        void clear();

    private:
        float* m_buffer;
        bool m_allocated;
        BufferInfo m_info;
        int m_size;
    };
}<commit_msg>Remove outdated todo's in audio buffer.<commit_after>// Copyright (c) 2015-2017 Matthew Sitton <matthewsitton@gmail.com>
// See LICENSE in the project root for license information.

#pragma once
#include <memory>
#include <algorithm>

namespace ORCore
{
    struct BufferInfo
    {
        int channels;
        int frames;
    };

    class Buffer
    {
    public:
        Buffer();
        Buffer(BufferInfo info);
        Buffer(float* buffer, BufferInfo info);
        Buffer(const Buffer& other);
        Buffer(Buffer&& other);
        ~Buffer();

        Buffer& operator=(const Buffer& other);
        Buffer& operator=(Buffer&& other);

        operator float*();

        void clone_type(const Buffer& other);

        BufferInfo get_info();
        int size();
        void clear();

    private:
        float* m_buffer;
        bool m_allocated;
        BufferInfo m_info;
        int m_size;
    };
}<|endoftext|>


<commit_before>#ifndef KEYCODE_HPP
#define KEYCODE_HPP

namespace org_pqrs_KeyRemap4MacBook {
  // ======================================================================
  class EventType {
  public:
    EventType(unsigned int v = 0) : value_(v) {}
    unsigned int get(void) const { return value_; }
    bool operator==(const EventType& other) const { return value_ == other.get(); }
    bool operator!=(const EventType& other) const { return ! (*this == other); }

#include "keycode/output/include.EventType.hpp"

  private:
    unsigned int value_;
  };

  // ======================================================================
  class KeyboardType {
  public:
    KeyboardType(unsigned int v = 0) : value_(v) {}
    unsigned int get(void) const { return value_; }
    bool operator==(const KeyboardType& other) const { return value_ == other.get(); }
    bool operator!=(const KeyboardType& other) const { return ! (*this == other); }

    bool isInternalKeyboard(void) const;

#include "keycode/output/include.KeyboardType.hpp"

  private:
    unsigned int value_;
  };

  // ======================================================================
  class KeyCode;
  class Flags;

  class ModifierFlag {
  public:
    unsigned int get(void) const { return value_; }
    bool operator==(const ModifierFlag& other) const { return value_ == other.get(); }
    bool operator!=(const ModifierFlag& other) const { return ! (*this == other); }

    unsigned int operator~(void) const { return ~value_; }

    const KeyCode& getKeyCode(void) const;

#include "keycode/output/include.ModifierFlag.hpp"

  private:
    ModifierFlag(unsigned int v) : value_(v) {}
    unsigned int value_;
  };
  namespace ModifierFlagList {
    const ModifierFlag list[] = {
      ModifierFlag::CAPSLOCK,
      ModifierFlag::SHIFT_L,
      ModifierFlag::SHIFT_R,
      ModifierFlag::CONTROL_L,
      ModifierFlag::CONTROL_R,
      ModifierFlag::OPTION_L,
      ModifierFlag::OPTION_R,
      ModifierFlag::COMMAND_L,
      ModifierFlag::COMMAND_R,
      ModifierFlag::FN,
    };
    const int listsize = sizeof(list) / sizeof(list[0]);
  };
  class Flags {
  public:
    Flags(unsigned int v = 0) : value_(v) {}
    Flags(const ModifierFlag& v) : value_(v.get()) {}
    unsigned int get(void) const { return value_; }
    bool operator==(const Flags& other) const { return value_ == other.get(); }
    bool operator!=(const Flags& other) const { return ! (*this == other); }

    Flags operator|(const Flags& other) const { return value_ | other.get(); }
    Flags operator&(const Flags& other) const { return value_ & other.get(); }

    Flags& add(const Flags& flags) { value_ |= flags.get(); return *this; }
    Flags& stripFN(void)     { value_ &= ~ModifierFlag::FN;     return *this; }
    Flags& stripCURSOR(void) { value_ &= ~ModifierFlag::CURSOR; return *this; }
    Flags& stripKEYPAD(void) { value_ &= ~ModifierFlag::KEYPAD; return *this; }
    Flags& stripNONE(void)   { value_ &= ~ModifierFlag::NONE;   return *this; }

    bool isOn(const ModifierFlag& flag) const {
      return (value_ & flag.get()) == flag.get();
    }
    bool isOn(const Flags& flags) const {
      if (flags.isOn(ModifierFlag::NONE)) {
        return (value_ | ModifierFlag::NONE.get()) == flags.get();
      } else {
        return (value_ & flags.get()) == flags.get();
      }
    }

  private:
    unsigned int value_;
  };
  inline Flags operator|(const ModifierFlag& lhs, const ModifierFlag& rhs) { return lhs.get() | rhs.get(); }

  // ======================================================================
  class KeyCode {
  public:
    KeyCode(unsigned int v = 0) : value_(v) {}
    unsigned int get(void) const { return value_; }
    bool operator==(const KeyCode& other) const { return value_ == other.get(); }
    bool operator!=(const KeyCode& other) const { return ! (*this == other); }

    bool operator> (const KeyCode& other) const { return value_ > other.get(); }
    bool operator>=(const KeyCode& other) const { return value_ >= other.get(); }

    void normalizeKey(Flags & flags, const KeyboardType &keyboardType);
    void reverseNormalizeKey(Flags & flags, const KeyboardType &keyboardType);

    ModifierFlag getModifierFlag(void) const;
    bool isModifier(void) const { return getModifierFlag() != ModifierFlag::NONE; }

#include "keycode/output/include.KeyCode.hpp"

  private:
    unsigned int value_;
  };

  // ======================================================================
  class ConsumerKeyCode {
  public:
    ConsumerKeyCode(unsigned int v = 0) : value_(v) {}
    unsigned int get(void) const { return value_; }
    bool operator==(const ConsumerKeyCode& other) const { return value_ == other.get(); }
    bool operator!=(const ConsumerKeyCode& other) const { return ! (*this == other); }

    bool operator> (const ConsumerKeyCode& other) const { return value_ > other.get(); }
    bool operator>=(const ConsumerKeyCode& other) const { return value_ >= other.get(); }

#include "keycode/output/include.ConsumerKeyCode.hpp"

  private:
    unsigned int value_;
  };

  // ======================================================================
  class Buttons;

  class PointingButton {
  public:
    unsigned int get(void) const { return value_; }
    bool operator==(const PointingButton& other) const { return value_ == other.get(); }
    bool operator!=(const PointingButton& other) const { return ! (*this == other); }

    unsigned int operator~(void) const { return ~value_; }

#include "keycode/output/include.PointingButton.hpp"

  private:
    PointingButton(unsigned int v) : value_(v) {}
    unsigned int value_;
  };
  class Buttons {
  public:
    Buttons(unsigned int v = 0) : value_(v) {}
    Buttons(const PointingButton& v) : value_(v.get()) {}
    unsigned int get(void) const { return value_; }
    bool operator==(const Buttons& other) const { return value_ == other.get(); }
    bool operator!=(const Buttons& other) const { return ! (*this == other); }

    unsigned int operator~(void) const { return ~value_; }
    Buttons operator|(const Buttons& other) const { return value_ | other.get(); }

    Buttons& add(const Buttons& button) { value_ |= button.get(); return *this; }
    Buttons& remove(const Buttons& button) { value_ &= ~button; return *this; }

    bool isNONE(void) const { return value_ == 0; }
    bool isOn(const Buttons& buttons) const {
      return (value_ & buttons.get()) == buttons.get();
    }

  private:
    unsigned int value_;
  };
  inline Buttons operator|(const PointingButton& lhs, const PointingButton& rhs) { return lhs.get() | rhs.get(); }
}

#endif
<commit_msg>update keycode.hpp @ kext<commit_after>#ifndef KEYCODE_HPP
#define KEYCODE_HPP

namespace org_pqrs_KeyRemap4MacBook {
  // ======================================================================
  class EventType {
  public:
    EventType(unsigned int v = 0) : value_(v) {}
    unsigned int get(void) const { return value_; }
    bool operator==(const EventType& other) const { return value_ == other.get(); }
    bool operator!=(const EventType& other) const { return ! (*this == other); }

#include "keycode/output/include.EventType.hpp"

  private:
    unsigned int value_;
  };

  // ======================================================================
  class KeyboardType {
  public:
    KeyboardType(unsigned int v = 0) : value_(v) {}
    unsigned int get(void) const { return value_; }
    bool operator==(const KeyboardType& other) const { return value_ == other.get(); }
    bool operator!=(const KeyboardType& other) const { return ! (*this == other); }

    bool isInternalKeyboard(void) const;

#include "keycode/output/include.KeyboardType.hpp"

  private:
    unsigned int value_;
  };

  // ======================================================================
  class KeyCode;
  class Flags;

  class ModifierFlag {
  public:
    unsigned int get(void) const { return value_; }
    bool operator==(const ModifierFlag& other) const { return value_ == other.get(); }
    bool operator!=(const ModifierFlag& other) const { return ! (*this == other); }

    unsigned int operator~(void) const { return ~value_; }

    const KeyCode& getKeyCode(void) const;

#include "keycode/output/include.ModifierFlag.hpp"

  private:
    ModifierFlag(unsigned int v) : value_(v) {}
    unsigned int value_;
  };
  class Flags {
  public:
    Flags(unsigned int v = 0) : value_(v) {}
    Flags(const ModifierFlag& v) : value_(v.get()) {}
    unsigned int get(void) const { return value_; }
    bool operator==(const Flags& other) const { return value_ == other.get(); }
    bool operator!=(const Flags& other) const { return ! (*this == other); }

    Flags operator|(const Flags& other) const { return value_ | other.get(); }
    Flags operator&(const Flags& other) const { return value_ & other.get(); }

    Flags& add(const Flags& flags) { value_ |= flags.get(); return *this; }
    Flags& stripFN(void)     { value_ &= ~ModifierFlag::FN;     return *this; }
    Flags& stripCURSOR(void) { value_ &= ~ModifierFlag::CURSOR; return *this; }
    Flags& stripKEYPAD(void) { value_ &= ~ModifierFlag::KEYPAD; return *this; }
    Flags& stripNONE(void)   { value_ &= ~ModifierFlag::NONE;   return *this; }

    bool isOn(const ModifierFlag& flag) const {
      return (value_ & flag.get()) == flag.get();
    }
    bool isOn(const Flags& flags) const {
      if (flags.isOn(ModifierFlag::NONE)) {
        return (value_ | ModifierFlag::NONE.get()) == flags.get();
      } else {
        return (value_ & flags.get()) == flags.get();
      }
    }

  private:
    unsigned int value_;
  };
  inline Flags operator|(const ModifierFlag& lhs, const ModifierFlag& rhs) { return lhs.get() | rhs.get(); }

  // ======================================================================
  class KeyCode {
  public:
    KeyCode(unsigned int v = 0) : value_(v) {}
    unsigned int get(void) const { return value_; }
    bool operator==(const KeyCode& other) const { return value_ == other.get(); }
    bool operator!=(const KeyCode& other) const { return ! (*this == other); }

    bool operator> (const KeyCode& other) const { return value_ > other.get(); }
    bool operator>=(const KeyCode& other) const { return value_ >= other.get(); }

    void normalizeKey(Flags & flags, const KeyboardType &keyboardType);
    void reverseNormalizeKey(Flags & flags, const KeyboardType &keyboardType);

    ModifierFlag getModifierFlag(void) const;
    bool isModifier(void) const { return getModifierFlag() != ModifierFlag::NONE; }

#include "keycode/output/include.KeyCode.hpp"

  private:
    unsigned int value_;
  };

  // ======================================================================
  class ConsumerKeyCode {
  public:
    ConsumerKeyCode(unsigned int v = 0) : value_(v) {}
    unsigned int get(void) const { return value_; }
    bool operator==(const ConsumerKeyCode& other) const { return value_ == other.get(); }
    bool operator!=(const ConsumerKeyCode& other) const { return ! (*this == other); }

    bool operator> (const ConsumerKeyCode& other) const { return value_ > other.get(); }
    bool operator>=(const ConsumerKeyCode& other) const { return value_ >= other.get(); }

#include "keycode/output/include.ConsumerKeyCode.hpp"

  private:
    unsigned int value_;
  };

  // ======================================================================
  class Buttons;

  class PointingButton {
  public:
    unsigned int get(void) const { return value_; }
    bool operator==(const PointingButton& other) const { return value_ == other.get(); }
    bool operator!=(const PointingButton& other) const { return ! (*this == other); }

    unsigned int operator~(void) const { return ~value_; }

#include "keycode/output/include.PointingButton.hpp"

  private:
    PointingButton(unsigned int v) : value_(v) {}
    unsigned int value_;
  };
  class Buttons {
  public:
    Buttons(unsigned int v = 0) : value_(v) {}
    Buttons(const PointingButton& v) : value_(v.get()) {}
    unsigned int get(void) const { return value_; }
    bool operator==(const Buttons& other) const { return value_ == other.get(); }
    bool operator!=(const Buttons& other) const { return ! (*this == other); }

    unsigned int operator~(void) const { return ~value_; }
    Buttons operator|(const Buttons& other) const { return value_ | other.get(); }

    Buttons& add(const Buttons& button) { value_ |= button.get(); return *this; }
    Buttons& remove(const Buttons& button) { value_ &= ~button; return *this; }

    bool isNONE(void) const { return value_ == 0; }
    bool isOn(const Buttons& buttons) const {
      return (value_ & buttons.get()) == buttons.get();
    }

  private:
    unsigned int value_;
  };
  inline Buttons operator|(const PointingButton& lhs, const PointingButton& rhs) { return lhs.get() | rhs.get(); }
}

#endif
<|endoftext|>


<commit_before>/*
  Judy Arrays allow for fast and memory efficient access to in-memory hash tables.
  Instantiation is slow, but continued use shows speed increases over native v8::Array implementation.
  Some code cleanup was done to allow for clean compilation with g++ or clang++.

  © 2011-2013 by Jerry Sievert
*/

#include <memory.h>
#include <stdio.h>

#include "judy64nb.h"
#include "judynode.h"

struct store {
  unsigned long length;
  uchar *ptr;
  int type;
};

#define FROM_BUFFER 0
#define FROM_STRING 1
#define MAX_JUDY_SIZE 1024

void *jg_init(int size, int depth = 0) {
  if (!size) {
    size = MAX_JUDY_SIZE;
  } else if (size > MAX_JUDY_SIZE) {
    return NULL;
  }

  return judy_open(size, depth);
}

int jg_set(void *judy, uchar *key, uchar *value, unsigned long len, int type) {
  JudySlot *cell;

  cell = judy_cell((Judy *)judy, key, (size_t)strlen((const char *)key));
  if (cell && *cell) {
    struct store *data = (struct store *)*cell;
    if (data->ptr) {
      free((void *)data->ptr);
    }
    free((void *)data);
  }
  if (cell) {
    struct store *data = (struct store *)malloc(sizeof(struct store));
    data->ptr = (uchar *)malloc(len);
    data->length = len;
    data->type = type;

    memcpy(data->ptr, value, len);

    *cell = (JudySlot)data;
    return 1;
  }

  return 0;
}

uchar *jg_get(void *judy, uchar *key, unsigned long *len, int *type) {
  JudySlot *cell;

  cell = judy_slot((Judy *)judy, key, (size_t)strlen((const char *)key));

  if (cell) {
    struct store *data = (struct store *)*cell;

    *len = data->length;
    *type = data->type;
    uchar *value = (uchar *)data->ptr;

    return value;
  }
  return NULL;
}

void jg_delete(void *judy, uchar *key) {
  JudySlot *cell;

  cell = judy_slot((Judy *)judy, key, (size_t)strlen((const char *)key));

  if (cell) {
    struct store *data = (struct store *)*cell;
    if (data) {
      if (data->ptr) {
        free((void *)data->ptr);
      }
      free((void *)data);
    }

    judy_del((Judy *)judy);
  }
}

Nan::Persistent<Function> constructor;

NAN_MODULE_INIT(JudyNode::Init) {
  Local<FunctionTemplate> tpl =
    Nan::New<FunctionTemplate>(JudyNode::New);
  tpl->SetClassName(Nan::New("Judy").ToLocalChecked());
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  Nan::SetPrototypeMethod(tpl, "get", JudyNode::Get);
  Nan::SetPrototypeMethod(tpl, "set", JudyNode::Set);
  Nan::SetPrototypeMethod(tpl, "delete", JudyNode::Delete);
  // Nan::SetPrototypeMethod(tpl, "rm", JudyNode::Delete);
  // Nan::SetPrototypeMethod(tpl, "del", JudyNode::Delete);
  Nan::SetPrototypeMethod(tpl, "keys", JudyNode::Keys);

  constructor.Reset(Nan::GetFunction(tpl).ToLocalChecked());
  Nan::Set(target, Nan::New("JudyNode").ToLocalChecked(),
           Nan::GetFunction(tpl).ToLocalChecked());
}

NODE_MODULE(JudyNode, JudyNode::Init)

// JudyNode::JudyNode() {};

/*
JudyNode::~JudyNode() {
    if (this->container == NULL) {
        return;
    }
    JudySlot *cell = (JudySlot *)judy_strt((Judy *)this->container, NULL, 0);
    while (cell) {
        free((void *)*cell);
        judy_del((Judy *)this->container);
        cell = judy_nxt((Judy *)this->container);
    }
}
*/

NAN_METHOD(JudyNode::New) {
  if (info.IsConstructCall()) {
    JudyNode *self = new JudyNode();
    self->container = jg_init(1024, 0);
    if (self->container == NULL) {
      info.GetReturnValue().SetUndefined();
    }
    self->Wrap(info.This());
    info.GetReturnValue().Set(info.This());
  } else { // Turn it into a construct call.
    v8::Local<v8::Function> cons =  Nan::New<Function>(constructor);
    info.GetReturnValue().Set(cons->NewInstance());
  }
}

NAN_METHOD(JudyNode::Get) {
  JudyNode *self = Nan::ObjectWrap::Unwrap<JudyNode>(info.This());

  if (info.Length() < 1) {
    return info.GetReturnValue().SetUndefined();
  }

  Nan::Utf8String key(info[0]->ToString());

  unsigned long len;
  int type;
  uchar *get = jg_get(self->container, (uchar *)*key, &len, &type);
  if (get == NULL) {
    return info.GetReturnValue().SetUndefined();
  }

  if (type == FROM_BUFFER) {
    Local<Object> slowBuffer = Nan::NewBuffer(len).ToLocalChecked();
    memcpy(node::Buffer::Data(slowBuffer), get, len);
    // slowBuffer->CopyBuffer(get, len);

    Local<Object> globalObj = Nan::GetCurrentContext()->Global();
    Local<Function> bufferConstructor = Local<Function>::Cast(
                                          globalObj->Get(Nan::New("Buffer").ToLocalChecked()));
    Local<Value> constructorArgs[3] = {
      slowBuffer,
      Nan::New<Integer>((int32_t) len),
      Nan::New<Integer>(0)
    };
    Local<Object> actualBuffer =
      Nan::NewInstance(bufferConstructor, 3, constructorArgs).ToLocalChecked();

    info.GetReturnValue().Set(actualBuffer);
  }

  info.GetReturnValue().Set(Nan::New<String>((const char *)get, len).ToLocalChecked());
}

NAN_METHOD(JudyNode::Set) {
  JudyNode *self = Nan::ObjectWrap::Unwrap<JudyNode>(info.This());

  if (info.Length() < 2) {
    return info.GetReturnValue().SetUndefined();
  }
  Nan::Utf8String key(info[0]->ToString());

  if (Buffer::HasInstance(info[1])) {
    Handle<Object> buffer = info[1]->ToObject();
    jg_set(self->container, (uchar *)*key, (uchar *)Buffer::Data(buffer),
           Buffer::Length(buffer), FROM_BUFFER);
  } else {
    Nan::Utf8String data(info[1]->ToString());
    jg_set(self->container, (uchar *)*key, (uchar *)*data, data.length(),
           FROM_STRING);
  }

  return info.GetReturnValue().SetUndefined();
}

NAN_METHOD(JudyNode::Delete) {
  JudyNode *self = Nan::ObjectWrap::Unwrap<JudyNode>(info.This());

  if (info.Length() < 1) {
    return info.GetReturnValue().SetUndefined();
  }
  Nan::Utf8String key(info[0]->ToString());

  jg_delete(self->container, (uchar *)*key);
  return info.GetReturnValue().SetUndefined();
}

NAN_METHOD(JudyNode::Keys) {
  JudyNode *self = Nan::ObjectWrap::Unwrap<JudyNode>(info.This());

  uint32_t counter = 0;
  uchar buf[1024];
  JudySlot *cell = (JudySlot *)judy_strt((Judy *)self->container, NULL, 0);
  Local<Array> arr = Nan::New<Array>();

  while (cell) {
    judy_key((Judy *)self->container, buf, 1024);
    Local<String> val = Nan::New<String>((char *)buf).ToLocalChecked();
    Nan::Set(arr, counter, val);
    cell = judy_nxt((Judy *)self->container);
    counter++;
  }

  info.GetReturnValue().Set(arr);
}

<commit_msg>v8 using namespace, NaN optional<commit_after>/*
  Judy Arrays allow for fast and memory efficient access to in-memory hash tables.
  Instantiation is slow, but continued use shows speed increases over native v8::Array implementation.
  Some code cleanup was done to allow for clean compilation with g++ or clang++.

  © 2011-2013 by Jerry Sievert
*/

#include <memory.h>
#include <stdio.h>

#include "judy64nb.h"
#include "judynode.h"

struct store {
  unsigned long length;
  uchar *ptr;
  int type;
};

#define FROM_BUFFER 0
#define FROM_STRING 1
#define MAX_JUDY_SIZE 1024

void *jg_init(int size, int depth = 0) {
  if (!size) {
    size = MAX_JUDY_SIZE;
  } else if (size > MAX_JUDY_SIZE) {
    return NULL;
  }

  return judy_open(size, depth);
}

int jg_set(void *judy, uchar *key, uchar *value, unsigned long len, int type) {
  JudySlot *cell;

  cell = judy_cell((Judy *)judy, key, (size_t)strlen((const char *)key));
  if (cell && *cell) {
    struct store *data = (struct store *)*cell;
    if (data->ptr) {
      free((void *)data->ptr);
    }
    free((void *)data);
  }
  if (cell) {
    struct store *data = (struct store *)malloc(sizeof(struct store));
    data->ptr = (uchar *)malloc(len);
    data->length = len;
    data->type = type;

    memcpy(data->ptr, value, len);

    *cell = (JudySlot)data;
    return 1;
  }

  return 0;
}

uchar *jg_get(void *judy, uchar *key, unsigned long *len, int *type) {
  JudySlot *cell;

  cell = judy_slot((Judy *)judy, key, (size_t)strlen((const char *)key));

  if (cell) {
    struct store *data = (struct store *)*cell;

    *len = data->length;
    *type = data->type;
    uchar *value = (uchar *)data->ptr;

    return value;
  }
  return NULL;
}

void jg_delete(void *judy, uchar *key) {
  JudySlot *cell;

  cell = judy_slot((Judy *)judy, key, (size_t)strlen((const char *)key));

  if (cell) {
    struct store *data = (struct store *)*cell;
    if (data) {
      if (data->ptr) {
        free((void *)data->ptr);
      }
      free((void *)data);
    }

    judy_del((Judy *)judy);
  }
}

Nan::Persistent<Function> constructor;

NAN_MODULE_INIT(JudyNode::Init) {
  Local<FunctionTemplate> tpl =
    Nan::New<FunctionTemplate>(JudyNode::New);
  tpl->SetClassName(Nan::New("Judy").ToLocalChecked());
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  Nan::SetPrototypeMethod(tpl, "get", JudyNode::Get);
  Nan::SetPrototypeMethod(tpl, "set", JudyNode::Set);
  Nan::SetPrototypeMethod(tpl, "delete", JudyNode::Delete);
  // Nan::SetPrototypeMethod(tpl, "rm", JudyNode::Delete);
  // Nan::SetPrototypeMethod(tpl, "del", JudyNode::Delete);
  Nan::SetPrototypeMethod(tpl, "keys", JudyNode::Keys);

  constructor.Reset(Nan::GetFunction(tpl).ToLocalChecked());
  Nan::Set(target, Nan::New("JudyNode").ToLocalChecked(),
           Nan::GetFunction(tpl).ToLocalChecked());
}

NODE_MODULE(JudyNode, JudyNode::Init)

// JudyNode::JudyNode() {};

/*
JudyNode::~JudyNode() {
    if (this->container == NULL) {
        return;
    }
    JudySlot *cell = (JudySlot *)judy_strt((Judy *)this->container, NULL, 0);
    while (cell) {
        free((void *)*cell);
        judy_del((Judy *)this->container);
        cell = judy_nxt((Judy *)this->container);
    }
}
*/

NAN_METHOD(JudyNode::New) {
  if (info.IsConstructCall()) {
    JudyNode *self = new JudyNode();
    self->container = jg_init(1024, 0);
    if (self->container == NULL) {
      info.GetReturnValue().SetUndefined();
    }
    self->Wrap(info.This());
    info.GetReturnValue().Set(info.This());
  } else { // Turn it into a construct call.
    Local<Function> cons =  Nan::New<Function>(constructor);
    info.GetReturnValue().Set(cons->NewInstance());
  }
}

NAN_METHOD(JudyNode::Get) {
  JudyNode *self = Nan::ObjectWrap::Unwrap<JudyNode>(info.This());

  if (info.Length() < 1) {
    return info.GetReturnValue().SetUndefined();
  }

  Nan::Utf8String key(info[0]->ToString());

  unsigned long len;
  int type;
  uchar *get = jg_get(self->container, (uchar *)*key, &len, &type);
  if (get == NULL) {
    return info.GetReturnValue().SetUndefined();
  }

  if (type == FROM_BUFFER) {
    Local<Object> slowBuffer = Nan::NewBuffer(len).ToLocalChecked();
    memcpy(node::Buffer::Data(slowBuffer), get, len);
    // slowBuffer->CopyBuffer(get, len);

    Local<Object> globalObj = Nan::GetCurrentContext()->Global();
    Local<Function> bufferConstructor =
      Local<Function>::Cast(
        globalObj->Get(Nan::New("Buffer").ToLocalChecked())
      );
    Local<Value> constructorArgs[3] = {
      slowBuffer,
      Nan::New<Integer>((int32_t) len),
      Nan::New<Integer>(0)
    };
    Local<Object> actualBuffer =
      Nan::NewInstance(bufferConstructor, 3, constructorArgs).ToLocalChecked();

    info.GetReturnValue().Set(actualBuffer);
  }

  info.GetReturnValue().Set(Nan::New<String>((const char *)get, len).ToLocalChecked());
}

NAN_METHOD(JudyNode::Set) {
  JudyNode *self = Nan::ObjectWrap::Unwrap<JudyNode>(info.This());

  if (info.Length() < 2) {
    return info.GetReturnValue().SetUndefined();
  }
  Nan::Utf8String key(info[0]->ToString());

  if (Buffer::HasInstance(info[1])) {
    Handle<Object> buffer = info[1]->ToObject();
    jg_set(self->container, (uchar *)*key, (uchar *)Buffer::Data(buffer),
           Buffer::Length(buffer), FROM_BUFFER);
  } else {
    Nan::Utf8String data(info[1]->ToString());
    jg_set(self->container, (uchar *)*key, (uchar *)*data, data.length(),
           FROM_STRING);
  }

  return info.GetReturnValue().SetUndefined();
}

NAN_METHOD(JudyNode::Delete) {
  JudyNode *self = Nan::ObjectWrap::Unwrap<JudyNode>(info.This());

  if (info.Length() < 1) {
    return info.GetReturnValue().SetUndefined();
  }
  Nan::Utf8String key(info[0]->ToString());

  jg_delete(self->container, (uchar *)*key);
  return info.GetReturnValue().SetUndefined();
}

NAN_METHOD(JudyNode::Keys) {
  JudyNode *self = Nan::ObjectWrap::Unwrap<JudyNode>(info.This());

  uint32_t counter = 0;
  uchar buf[1024];
  JudySlot *cell = (JudySlot *)judy_strt((Judy *)self->container, NULL, 0);
  Local<Array> arr = Nan::New<Array>();

  while (cell) {
    judy_key((Judy *)self->container, buf, 1024);
    Local<String> val = Nan::New<String>((char *)buf).ToLocalChecked();
    Nan::Set(arr, counter, val);
    cell = judy_nxt((Judy *)self->container);
    counter++;
  }

  info.GetReturnValue().Set(arr);
}

<|endoftext|>


<commit_before>/*
 * Database.cpp
 *
 * Copyright (C) 2020 by RStudio, PBC
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/Database.hpp>

#include <shared_core/Error.hpp>

#include <soci/postgresql/soci-postgresql.h>
#include <soci/sqlite3/soci-sqlite3.h>

namespace rstudio {
namespace core {
namespace database {

class ConnectVisitor : public boost::static_visitor<Error>
{
public:
   ConnectVisitor(boost::shared_ptr<Connection>* pPtrConnection) :
      pPtrConnection_(pPtrConnection)
   {
   }

   Error operator()(const SqliteConnectionOptions& options) const
   {
      try
      {
         boost::shared_ptr<Connection> pConnection(new Connection(soci::sqlite3, "dbname=" + options.file));
         *pPtrConnection_ = pConnection;
         return Success();
      }
      catch(soci::soci_error& error)
      {
         return Error(boost::system::errc::protocol_error, error.get_error_message(), ERROR_LOCATION);
      }
   }

   Error operator()(const PostgresqlConnectionOptions& options) const
   {
      return Success();
   }

private:
   boost::shared_ptr<Connection>* pPtrConnection_;
};

Error connect(const ConnectionOptions& options,
              boost::shared_ptr<Connection>* pPtrConnection)
{
   return boost::apply_visitor(ConnectVisitor(pPtrConnection), options);
}

Query::Query(const std::string& sqlStatement,
             soci::session& session) :
   statement_(session)
{
   // it's possible that prepare can throw a database exception, but we
   // do not want to surface errors until execute() is called
   try
   {
      statement_.prepare(sqlStatement);
   }
   catch (soci::soci_error& error)
   {
      prepareError_ = error;
   }
}

Connection::Connection(const soci::backend_factory& factory,
                       const std::string& connectionStr) :
   session_(factory, connectionStr)
{
}

Query Connection::query(const std::string& sqlStatement)
{
   return Query(sqlStatement, session_);
}

Error Connection::execute(Query& query)
{
   if (query.prepareError_)
      return Error(boost::system::errc::protocol_error, ERROR_LOCATION);

   try
   {
      query.statement_.define_and_bind();
      query.statement_.execute(true);
      query.statement_.bind_clean_up();
   }
   catch (soci::soci_error&)
   {
      return Error(boost::system::errc::protocol_error, ERROR_LOCATION);
   }

   return Success();
}

} // namespace database
} // namespace core
} // namespace rstudio
<commit_msg>Added integration of soci errors with boost error codes<commit_after>/*
 * Database.cpp
 *
 * Copyright (C) 2020 by RStudio, PBC
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/Database.hpp>

#include <shared_core/Error.hpp>

#include <soci/postgresql/soci-postgresql.h>
#include <soci/sqlite3/soci-sqlite3.h>

// Database Boost Errors
// Declare soci errors as boost errors.
// =================================================================================================================
namespace RSTUDIO_BOOST_NAMESPACE {
namespace system {

template <>
struct is_error_code_enum<soci::soci_error::error_category>
{
   static const bool value = true;
};

} // namespace system
} // namespace boost

namespace rstudio {
namespace core {
namespace database {
   const boost::system::error_category& databaseErrorCategory();
}
}
}

namespace soci {

inline boost::system::error_code make_error_code(soci::soci_error::error_category e)
{
   return { e, rstudio::core::database::databaseErrorCategory() };
}

inline boost::system::error_condition make_error_condition(soci::soci_error::error_category e)
{
   return { e, rstudio::core::database::databaseErrorCategory() };
}

}

namespace rstudio {
namespace core {
namespace database {

class DatabaseErrorCategory : public boost::system::error_category
{
public:
   const char* name() const BOOST_NOEXCEPT override;

   std::string message(int ev) const override;
};

const boost::system::error_category& databaseErrorCategory()
{
   static DatabaseErrorCategory databaseErrorCategoryConst;
   return databaseErrorCategoryConst;
}

const char* DatabaseErrorCategory::name() const BOOST_NOEXCEPT
{
   return "database";
}

std::string DatabaseErrorCategory::message(int ev) const
{
   switch (ev)
   {
      case soci::soci_error::error_category::connection_error:
         return "Connection Error";
      case soci::soci_error::error_category::invalid_statement:
         return "Invalid Statement";
      case soci::soci_error::error_category::no_privilege:
         return "No Privilege";
      case soci::soci_error::error_category::no_data:
         return "No Data";
      case soci::soci_error::error_category::constraint_violation:
         return "Constraint Violation";
      case soci::soci_error::error_category::unknown_transaction_state:
         return "Unknown Transaction State";
      case soci::soci_error::error_category::system_error:
         return "System Error";
      case soci::soci_error::error_category::unknown:
      default:
         return "Unknown Error";
   }
}

#define DatabaseError(sociError) Error(sociError.get_error_category(), sociError.get_error_message(), ERROR_LOCATION);

// Database errors =================================================================================================

class ConnectVisitor : public boost::static_visitor<Error>
{
public:
   ConnectVisitor(boost::shared_ptr<Connection>* pPtrConnection) :
      pPtrConnection_(pPtrConnection)
   {
   }

   Error operator()(const SqliteConnectionOptions& options) const
   {
      try
      {
         boost::shared_ptr<Connection> pConnection(new Connection(soci::sqlite3, "dbname=" + options.file));
         *pPtrConnection_ = pConnection;
         return Success();
      }
      catch(soci::soci_error& error)
      {
         return DatabaseError(error);
      }
   }

   Error operator()(const PostgresqlConnectionOptions& options) const
   {
      return Success();
   }

private:
   boost::shared_ptr<Connection>* pPtrConnection_;
};

Error connect(const ConnectionOptions& options,
              boost::shared_ptr<Connection>* pPtrConnection)
{
   return boost::apply_visitor(ConnectVisitor(pPtrConnection), options);
}

Query::Query(const std::string& sqlStatement,
             soci::session& session) :
   statement_(session)
{
   // it's possible that prepare can throw a database exception, but we
   // do not want to surface errors until execute() is called
   try
   {
      statement_.prepare(sqlStatement);
   }
   catch (soci::soci_error& error)
   {
      prepareError_ = error;
   }
}

Connection::Connection(const soci::backend_factory& factory,
                       const std::string& connectionStr) :
   session_(factory, connectionStr)
{
}

Query Connection::query(const std::string& sqlStatement)
{
   return Query(sqlStatement, session_);
}

Error Connection::execute(Query& query)
{
   if (query.prepareError_)
      return DatabaseError(query.prepareError_.get());

   try
   {
      query.statement_.define_and_bind();
      query.statement_.execute(true);
      query.statement_.bind_clean_up();
   }
   catch (soci::soci_error& error)
   {
      return DatabaseError(error);
   }

   return Success();
}

} // namespace database
} // namespace core
} // namespace rstudio
<|endoftext|>


<commit_before>#include "cpu.h"

#include "../bitwise.h"
#include "../util/log.h"

#include <cstdlib>

[[noreturn]] inline void unimplemented_opcode() {
    log_error("Unimplemented opcode");
    std::exit(1);
}

/* ADC */
inline void CPU::_opcode_adc(u8 value) {
    u8 reg = a.value();
    u8 carry = flag_carry_value();

    u16 result16 = reg + value + carry;

    set_flag_zero(reg == 0);
    set_flag_subtract(false);
    set_flag_half_carry(((reg ^ value ^ result16) & 0x10) != 0);
    set_flag_carry((result16 & 0x100) != 0);

    u8 result = static_cast<u8>(result16);
    a.set(result);
}

void CPU::opcode_adc() {
    _opcode_adc(get_byte_from_pc());
}

void CPU::opcode_adc(const ByteRegister& reg) {
    _opcode_adc(reg.value());
}

void CPU::opcode_adc(const Address&& addr) {
    _opcode_adc(mmu.read(addr));
}

/* ADD */
inline void CPU::_opcode_add(u8 reg, u8 value) {
    u16 result16 = reg + value;

    set_flag_zero(a.value() == 0);
    set_flag_subtract(false);
    set_flag_half_carry(((reg ^ value ^ result16) & 0x10) != 0);
    set_flag_carry((result16 & 0x100) != 0);

    u8 result = static_cast<u8>(result16);
    a.set(result);
}

void CPU::opcode_add_a() {
    _opcode_add(a.value(), get_byte_from_pc());
}

void CPU::opcode_add_a(const ByteRegister& reg) {
    _opcode_add(a.value(), reg.value());
}

void CPU::opcode_add_a(const Address& addr) {
    _opcode_add(a.value(), mmu.read(addr));
}

void CPU::opcode_add_hl(const RegisterPair& reg_pair) {
    unimplemented_opcode();
}

void CPU::opcode_add_hl(const WordRegister& word_reg) {
    unimplemented_opcode();
}

void CPU::opcode_add_sp() {
    unimplemented_opcode();
}

void CPU::opcode_add_signed() {
    unimplemented_opcode();
}

/* AND */
void CPU::opcode_and() {
    unimplemented_opcode();
}

void CPU::opcode_and(ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_and(Address&& addr) {
    unimplemented_opcode();
}

/* BIT */
void CPU::_opcode_bit(const u8 bit, const u8 value) {
    set_flag_zero(!check_bit(value, bit));
    set_flag_subtract(false);
    set_flag_half_carry(true);
}

void CPU::opcode_bit(const u8 bit, ByteRegister& reg) {
    _opcode_bit(bit, reg.value());
}

void CPU::opcode_bit(const u8 bit, Address&& addr) {
    _opcode_bit(bit, mmu.read(addr));
}

/* CALL */
void CPU::opcode_call() {
    u16 address = get_word_from_pc();
    stack_push(pc);
    pc.set(address);
}

void CPU::opcode_call(Condition condition) {
    if (is_condition(condition)) {
        opcode_call();
    }
}

/* CCF */
void CPU::opcode_ccf() {
    unimplemented_opcode();
}

/* CP */
void CPU::opcode_cp() {
    unimplemented_opcode();
}

void CPU::opcode_cp(const ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_cp(const Address& addr) {
    unimplemented_opcode();
}

/* CPL */
void CPU::opcode_cpl() {
    unimplemented_opcode();
}

/* DAA */
void CPU::opcode_daa() {
    unimplemented_opcode();
}

/* DEC */
void CPU::opcode_dec(ByteRegister& reg) {
    reg.decrement();
}

void CPU::opcode_dec(RegisterPair& reg) {
    reg.decrement();
}

void CPU::opcode_dec(WordRegister& reg) {
    reg.decrement();
}

void CPU::opcode_dec(Address&& addr) {
    u8 value = mmu.read(addr);
    u8 result = static_cast<u8>(value - 1);
    mmu.write(addr, result);
}

/* DI */
void CPU::opcode_di() {
    // TODO: should this write a value into memory?
    interrupts_enabled = false;
}

/* EI */
void CPU::opcode_ei() {
    // TODO: should this write a value into memory?
    interrupts_enabled = true;
}

/* INC */
void CPU::opcode_inc(ByteRegister& reg) {
    reg.increment();
}

void CPU::opcode_inc(RegisterPair& reg) {
    reg.increment();
}

void CPU::opcode_inc(WordRegister& reg) {
    reg.increment();
}

void CPU::opcode_inc(Address&& addr) {
    u8 value = mmu.read(addr);
    u8 result = static_cast<u8>(value + 1);
    mmu.write(addr, result);
}

/* JP */
void CPU::opcode_jp() {
    unimplemented_opcode();
}

void CPU::opcode_jp(Condition condition) {
    unimplemented_opcode();
}

void CPU::opcode_jp(const Address& addr) {
    unimplemented_opcode();
}

/* JR */
void CPU::opcode_jr() {
    s8 n = get_signed_byte_from_pc();
    u16 old_pc = pc.value();

    u16 new_pc = static_cast<u16>(old_pc + n);
    pc.set(new_pc);
}

void CPU::opcode_jr(Condition condition) {
    if (is_condition(condition)) {
        opcode_jr();
    }
}

/* HALT */
void CPU::opcode_halt() {
    unimplemented_opcode();
}

/* LD */
void CPU::opcode_ld(ByteRegister& reg) {
    u8 n = get_byte_from_pc();
    reg.set(n);
}

void CPU::opcode_ld(ByteRegister& reg, const ByteRegister& byte_reg) {
    reg.set(byte_reg.value());
}

void CPU::opcode_ld(ByteRegister& reg, const Address& address) {
    reg.set(mmu.read(address));
}

void CPU::opcode_ld(RegisterPair& reg) {
    u16 nn = get_word_from_pc();
    reg.set(nn);
}

void CPU::opcode_ld(WordRegister& reg) {
    u16 nn = get_word_from_pc();
    reg.set(nn);
}

void CPU::opcode_ld(WordRegister& reg, const RegisterPair& reg_pair) {
    unimplemented_opcode();
}

void CPU::opcode_ld(const Address& address) {
    u8 n = get_byte_from_pc();
    mmu.write(address, n);
}

void CPU::opcode_ld(const Address& address, const ByteRegister& byte_reg) {
    mmu.write(address, byte_reg.value());
}

void CPU::opcode_ld(const Address& address, const WordRegister& word_reg) {
    mmu.write_word(address, word_reg.value());
}

void CPU::opcode_ld_to_addr(const ByteRegister &reg) {
    unimplemented_opcode();
}

/* LDD */
void CPU::opcode_ldd(ByteRegister& reg, const Address& address) {
    // TODO: clean up
    // two ways of doing ldd
    // address is always that of HL
    reg.set(mmu.read(address));
    hl.decrement();
}

void CPU::opcode_ldd(const Address& address, const ByteRegister& reg) {
    mmu.write(address, reg.value());
    hl.decrement();
}

/* LDH */
void CPU::opcode_ldh_into_a() {
    unimplemented_opcode();
}

void CPU::opcode_ldh_into_data() {
    u8 offset = get_byte_from_pc();
    auto address = Address(0xFF00 + offset);

    mmu.write(address, a.value());
}

void CPU::opcode_ldh_into_c() {
    u8 offset = c.value();
    auto address = Address(0xFF00 + offset);

    mmu.write(address, a.value());
}

/* LDHL */
void CPU::opcode_ldhl() {
    unimplemented_opcode();
}

/* LDI */
void CPU::opcode_ldi(ByteRegister& reg, const Address& address) {
    reg.set(mmu.read(address));
    hl.increment();
}

void CPU::opcode_ldi(const Address& address, const ByteRegister& reg) {
    mmu.write(address, reg.value());
    hl.increment();
}

/* NOP */
void CPU::opcode_nop() {
    unimplemented_opcode();
}

/* OR */
void CPU::opcode_or() {
    unimplemented_opcode();
}

void CPU::opcode_or(const ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_or(const Address& addr) {
    unimplemented_opcode();
}

/* POP */
void CPU::opcode_pop(const RegisterPair& reg) {
    stack_pop(reg);
}

/* PUSH */
void CPU::opcode_push(const RegisterPair& reg) {
    stack_push(reg);
}

/* RES */
void CPU::opcode_res(const int bit, ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_res(const int bit, Address&& addr) {
    unimplemented_opcode();
}

/* RET */
void CPU::opcode_ret() {
    unimplemented_opcode();
}

void CPU::opcode_ret(Condition condition) {
    unimplemented_opcode();
}

/* RETI */
void CPU::opcode_reti() {
    unimplemented_opcode();
}

/* RL */
void CPU::opcode_rl(ByteRegister& reg) {
    u8 carry = flag_carry_value();
    u8 value = reg.value();

    // TODO: in other emulators, flags are only reset if carry flag is not set
    reset_flags();

    bool will_carry = check_bit(value, 7);
    set_flag_carry(will_carry);

    u8 result = static_cast<u8>(value << 1);
    result |= carry;

    set_flag_zero(result == 0);

    reg.set(result);
}

void CPU::opcode_rl(Address&& addr) {
    u8 old_carry = flag_carry_value();
    u8 value = mmu.read(addr);

    // TODO: in other emulators, flags are only reset if carry flag is not set
    reset_flags();

    bool will_carry = check_bit(value, 7);
    set_flag_carry(will_carry);

    u8 result = static_cast<u8>(value << 1);
    result |= old_carry;

    set_flag_zero(result == 0);

    mmu.write(addr, result);
}

/* RLC */
void CPU::opcode_rlc(ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_rlc(Address&& addr) {
    unimplemented_opcode();
}

/* RR */
void CPU::opcode_rr(ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_rr(Address&& addr) {
    unimplemented_opcode();
}

/* RRC */
void CPU::opcode_rrc(ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_rrc(Address&& addr) {
    unimplemented_opcode();
}

/* RST */
// TODO: offset type
void CPU::opcode_rst(const u8 offset) {
    unimplemented_opcode();
}

/* SBC */
void CPU::opcode_sbc() {
    unimplemented_opcode();
}

void CPU::opcode_sbc(ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_sbc(Address&& addr) {
    unimplemented_opcode();
}

/* SCF */
void CPU::opcode_scf() {
    unimplemented_opcode();
}

/* SET */
void CPU::opcode_set(const int bit, ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_set(const int bit, Address&& addr) {
    unimplemented_opcode();
}

/* SLA */
void CPU::opcode_sla(ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_sla(Address&& addr) {
    unimplemented_opcode();
}

/* SRA */
void CPU::opcode_sra(ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_sra(Address&& addr) {
    unimplemented_opcode();
}

/* SRL */
void CPU::opcode_srl(ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_srl(Address&& addr) {
    unimplemented_opcode();
}

/* STOP */
void CPU::opcode_stop() {
    unimplemented_opcode();
}

/* SUB */
void CPU::opcode_sub() {
    unimplemented_opcode();
}

void CPU::opcode_sub(ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_sub(Address&& addr) {
    unimplemented_opcode();
}

/* SWAP */
void CPU::opcode_swap(ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_swap(Address&& addr) {
    unimplemented_opcode();
}

/* XOR */
void CPU::_opcode_xor(u8 value) {
    u8 reg = a.value();

    u8 result = reg ^ value;

    set_flag_zero(reg == 0);
    set_flag_subtract(false);
    set_flag_half_carry(false);
    set_flag_carry(false);

    a.set(result);
}

void CPU::opcode_xor() {
    _opcode_xor(get_byte_from_pc());
}

void CPU::opcode_xor(const ByteRegister& reg) {
    _opcode_xor(reg.value());
}

void CPU::opcode_xor(const Address& addr) {
    _opcode_xor(mmu.read(addr));
}
<commit_msg>Implement RET<commit_after>#include "cpu.h"

#include "../bitwise.h"
#include "../util/log.h"

#include <cstdlib>

[[noreturn]] inline void unimplemented_opcode() {
    log_error("Unimplemented opcode");
    std::exit(1);
}

/* ADC */
inline void CPU::_opcode_adc(u8 value) {
    u8 reg = a.value();
    u8 carry = flag_carry_value();

    u16 result16 = reg + value + carry;

    set_flag_zero(reg == 0);
    set_flag_subtract(false);
    set_flag_half_carry(((reg ^ value ^ result16) & 0x10) != 0);
    set_flag_carry((result16 & 0x100) != 0);

    u8 result = static_cast<u8>(result16);
    a.set(result);
}

void CPU::opcode_adc() {
    _opcode_adc(get_byte_from_pc());
}

void CPU::opcode_adc(const ByteRegister& reg) {
    _opcode_adc(reg.value());
}

void CPU::opcode_adc(const Address&& addr) {
    _opcode_adc(mmu.read(addr));
}

/* ADD */
inline void CPU::_opcode_add(u8 reg, u8 value) {
    u16 result16 = reg + value;

    set_flag_zero(a.value() == 0);
    set_flag_subtract(false);
    set_flag_half_carry(((reg ^ value ^ result16) & 0x10) != 0);
    set_flag_carry((result16 & 0x100) != 0);

    u8 result = static_cast<u8>(result16);
    a.set(result);
}

void CPU::opcode_add_a() {
    _opcode_add(a.value(), get_byte_from_pc());
}

void CPU::opcode_add_a(const ByteRegister& reg) {
    _opcode_add(a.value(), reg.value());
}

void CPU::opcode_add_a(const Address& addr) {
    _opcode_add(a.value(), mmu.read(addr));
}

void CPU::opcode_add_hl(const RegisterPair& reg_pair) {
    unimplemented_opcode();
}

void CPU::opcode_add_hl(const WordRegister& word_reg) {
    unimplemented_opcode();
}

void CPU::opcode_add_sp() {
    unimplemented_opcode();
}

void CPU::opcode_add_signed() {
    unimplemented_opcode();
}

/* AND */
void CPU::opcode_and() {
    unimplemented_opcode();
}

void CPU::opcode_and(ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_and(Address&& addr) {
    unimplemented_opcode();
}

/* BIT */
void CPU::_opcode_bit(const u8 bit, const u8 value) {
    set_flag_zero(!check_bit(value, bit));
    set_flag_subtract(false);
    set_flag_half_carry(true);
}

void CPU::opcode_bit(const u8 bit, ByteRegister& reg) {
    _opcode_bit(bit, reg.value());
}

void CPU::opcode_bit(const u8 bit, Address&& addr) {
    _opcode_bit(bit, mmu.read(addr));
}

/* CALL */
void CPU::opcode_call() {
    u16 address = get_word_from_pc();
    stack_push(pc);
    pc.set(address);
}

void CPU::opcode_call(Condition condition) {
    if (is_condition(condition)) {
        opcode_call();
    }
}

/* CCF */
void CPU::opcode_ccf() {
    unimplemented_opcode();
}

/* CP */
void CPU::opcode_cp() {
    unimplemented_opcode();
}

void CPU::opcode_cp(const ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_cp(const Address& addr) {
    unimplemented_opcode();
}

/* CPL */
void CPU::opcode_cpl() {
    unimplemented_opcode();
}

/* DAA */
void CPU::opcode_daa() {
    unimplemented_opcode();
}

/* DEC */
void CPU::opcode_dec(ByteRegister& reg) {
    reg.decrement();
}

void CPU::opcode_dec(RegisterPair& reg) {
    reg.decrement();
}

void CPU::opcode_dec(WordRegister& reg) {
    reg.decrement();
}

void CPU::opcode_dec(Address&& addr) {
    u8 value = mmu.read(addr);
    u8 result = static_cast<u8>(value - 1);
    mmu.write(addr, result);
}

/* DI */
void CPU::opcode_di() {
    // TODO: should this write a value into memory?
    interrupts_enabled = false;
}

/* EI */
void CPU::opcode_ei() {
    // TODO: should this write a value into memory?
    interrupts_enabled = true;
}

/* INC */
void CPU::opcode_inc(ByteRegister& reg) {
    reg.increment();
}

void CPU::opcode_inc(RegisterPair& reg) {
    reg.increment();
}

void CPU::opcode_inc(WordRegister& reg) {
    reg.increment();
}

void CPU::opcode_inc(Address&& addr) {
    u8 value = mmu.read(addr);
    u8 result = static_cast<u8>(value + 1);
    mmu.write(addr, result);
}

/* JP */
void CPU::opcode_jp() {
    unimplemented_opcode();
}

void CPU::opcode_jp(Condition condition) {
    unimplemented_opcode();
}

void CPU::opcode_jp(const Address& addr) {
    unimplemented_opcode();
}

/* JR */
void CPU::opcode_jr() {
    s8 n = get_signed_byte_from_pc();
    u16 old_pc = pc.value();

    u16 new_pc = static_cast<u16>(old_pc + n);
    pc.set(new_pc);
}

void CPU::opcode_jr(Condition condition) {
    if (is_condition(condition)) {
        opcode_jr();
    }
}

/* HALT */
void CPU::opcode_halt() {
    unimplemented_opcode();
}

/* LD */
void CPU::opcode_ld(ByteRegister& reg) {
    u8 n = get_byte_from_pc();
    reg.set(n);
}

void CPU::opcode_ld(ByteRegister& reg, const ByteRegister& byte_reg) {
    reg.set(byte_reg.value());
}

void CPU::opcode_ld(ByteRegister& reg, const Address& address) {
    reg.set(mmu.read(address));
}

void CPU::opcode_ld(RegisterPair& reg) {
    u16 nn = get_word_from_pc();
    reg.set(nn);
}

void CPU::opcode_ld(WordRegister& reg) {
    u16 nn = get_word_from_pc();
    reg.set(nn);
}

void CPU::opcode_ld(WordRegister& reg, const RegisterPair& reg_pair) {
    unimplemented_opcode();
}

void CPU::opcode_ld(const Address& address) {
    u8 n = get_byte_from_pc();
    mmu.write(address, n);
}

void CPU::opcode_ld(const Address& address, const ByteRegister& byte_reg) {
    mmu.write(address, byte_reg.value());
}

void CPU::opcode_ld(const Address& address, const WordRegister& word_reg) {
    mmu.write_word(address, word_reg.value());
}

void CPU::opcode_ld_to_addr(const ByteRegister &reg) {
    unimplemented_opcode();
}

/* LDD */
void CPU::opcode_ldd(ByteRegister& reg, const Address& address) {
    // TODO: clean up
    // two ways of doing ldd
    // address is always that of HL
    reg.set(mmu.read(address));
    hl.decrement();
}

void CPU::opcode_ldd(const Address& address, const ByteRegister& reg) {
    mmu.write(address, reg.value());
    hl.decrement();
}

/* LDH */
void CPU::opcode_ldh_into_a() {
    unimplemented_opcode();
}

void CPU::opcode_ldh_into_data() {
    u8 offset = get_byte_from_pc();
    auto address = Address(0xFF00 + offset);

    mmu.write(address, a.value());
}

void CPU::opcode_ldh_into_c() {
    u8 offset = c.value();
    auto address = Address(0xFF00 + offset);

    mmu.write(address, a.value());
}

/* LDHL */
void CPU::opcode_ldhl() {
    unimplemented_opcode();
}

/* LDI */
void CPU::opcode_ldi(ByteRegister& reg, const Address& address) {
    reg.set(mmu.read(address));
    hl.increment();
}

void CPU::opcode_ldi(const Address& address, const ByteRegister& reg) {
    mmu.write(address, reg.value());
    hl.increment();
}

/* NOP */
void CPU::opcode_nop() {
    unimplemented_opcode();
}

/* OR */
void CPU::opcode_or() {
    unimplemented_opcode();
}

void CPU::opcode_or(const ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_or(const Address& addr) {
    unimplemented_opcode();
}

/* POP */
void CPU::opcode_pop(const RegisterPair& reg) {
    stack_pop(reg);
}

/* PUSH */
void CPU::opcode_push(const RegisterPair& reg) {
    stack_push(reg);
}

/* RES */
void CPU::opcode_res(const int bit, ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_res(const int bit, Address&& addr) {
    unimplemented_opcode();
}

/* RET */
void CPU::opcode_ret() {
    stack_pop(pc);
}

void CPU::opcode_ret(Condition condition) {
    if (is_condition(condition)) {
        opcode_ret();
    }
}

/* RETI */
void CPU::opcode_reti() {
    unimplemented_opcode();
}

/* RL */
void CPU::opcode_rl(ByteRegister& reg) {
    u8 carry = flag_carry_value();
    u8 value = reg.value();

    // TODO: in other emulators, flags are only reset if carry flag is not set
    reset_flags();

    bool will_carry = check_bit(value, 7);
    set_flag_carry(will_carry);

    u8 result = static_cast<u8>(value << 1);
    result |= carry;

    set_flag_zero(result == 0);

    reg.set(result);
}

void CPU::opcode_rl(Address&& addr) {
    u8 old_carry = flag_carry_value();
    u8 value = mmu.read(addr);

    // TODO: in other emulators, flags are only reset if carry flag is not set
    reset_flags();

    bool will_carry = check_bit(value, 7);
    set_flag_carry(will_carry);

    u8 result = static_cast<u8>(value << 1);
    result |= old_carry;

    set_flag_zero(result == 0);

    mmu.write(addr, result);
}

/* RLC */
void CPU::opcode_rlc(ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_rlc(Address&& addr) {
    unimplemented_opcode();
}

/* RR */
void CPU::opcode_rr(ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_rr(Address&& addr) {
    unimplemented_opcode();
}

/* RRC */
void CPU::opcode_rrc(ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_rrc(Address&& addr) {
    unimplemented_opcode();
}

/* RST */
// TODO: offset type
void CPU::opcode_rst(const u8 offset) {
    unimplemented_opcode();
}

/* SBC */
void CPU::opcode_sbc() {
    unimplemented_opcode();
}

void CPU::opcode_sbc(ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_sbc(Address&& addr) {
    unimplemented_opcode();
}

/* SCF */
void CPU::opcode_scf() {
    unimplemented_opcode();
}

/* SET */
void CPU::opcode_set(const int bit, ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_set(const int bit, Address&& addr) {
    unimplemented_opcode();
}

/* SLA */
void CPU::opcode_sla(ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_sla(Address&& addr) {
    unimplemented_opcode();
}

/* SRA */
void CPU::opcode_sra(ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_sra(Address&& addr) {
    unimplemented_opcode();
}

/* SRL */
void CPU::opcode_srl(ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_srl(Address&& addr) {
    unimplemented_opcode();
}

/* STOP */
void CPU::opcode_stop() {
    unimplemented_opcode();
}

/* SUB */
void CPU::opcode_sub() {
    unimplemented_opcode();
}

void CPU::opcode_sub(ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_sub(Address&& addr) {
    unimplemented_opcode();
}

/* SWAP */
void CPU::opcode_swap(ByteRegister& reg) {
    unimplemented_opcode();
}

void CPU::opcode_swap(Address&& addr) {
    unimplemented_opcode();
}

/* XOR */
void CPU::_opcode_xor(u8 value) {
    u8 reg = a.value();

    u8 result = reg ^ value;

    set_flag_zero(reg == 0);
    set_flag_subtract(false);
    set_flag_half_carry(false);
    set_flag_carry(false);

    a.set(result);
}

void CPU::opcode_xor() {
    _opcode_xor(get_byte_from_pc());
}

void CPU::opcode_xor(const ByteRegister& reg) {
    _opcode_xor(reg.value());
}

void CPU::opcode_xor(const Address& addr) {
    _opcode_xor(mmu.read(addr));
}
<|endoftext|>


<commit_before>#include <string>
#include <functional>
#include <fstream>
#include <set>

#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>

#include <boost/optional.hpp>
#include <boost/filesystem.hpp>

#include <json/json.h>
#include "../common/json_help.hpp"

#include "raftrpc.hpp"
#include "raftstate.hpp"
#include "raftclient.hpp"

namespace raft
{
	namespace request
	{
		Update::Update(const std::string& from, const std::string& key,
			   const std::string& old_version, const std::string& new_version)
			:Request(from, key),
			old_version_(old_version),
			new_version_(new_version)
		{
		}

		Update::Update(const Json::Value& root)
			:Request(root)
		{
			std::string type = checked_from_json<std::string>(root, "type");

			if(type != "update")
				throw std::runtime_error("Raft request not update.");

			old_version_ = checked_from_json<std::string>(root, "old_version");
			new_version_ = checked_from_json<std::string>(root, "new_version");
		}

		Update::operator Json::Value() const
		{
			Json::Value root = Request::operator Json::Value();

			root["type"] = "update";
			root["old_version"] = old_version_;
			root["new_version"] = new_version_;

			return root;
		}

		std::string Update::old_version() const noexcept
		{
			return old_version_;
		}

		std::string Update::version() const noexcept
		{
			return new_version_;
		}

		std::string Update::new_version() const noexcept
		{
			return new_version_;
		}

		Delete::Delete(const std::string& from, const std::string& key,
				const std::string& version)
			:VersionRequest(from, key, version)
		{
		}

		Delete::Delete(const Json::Value& root)
			:VersionRequest(root)
		{
			std::string type = checked_from_json<std::string>(root, "type");

			if(type != "delete")
				throw std::runtime_error("Raft request not delete.");
		}

		Delete::operator Json::Value() const
		{
			Json::Value root = VersionRequest::operator Json::Value();

			root["type"] = "delete";

			return root;
		}

		Rename::Rename(const std::string& from, const std::string& key,
				const std::string& new_key, const std::string& version)
			:VersionRequest(from, key, version),
			new_key_(new_key)
		{
		}

		Rename::Rename(const Json::Value& root)
			:VersionRequest(root)
		{
			std::string type = checked_from_json<std::string>(root, "type");

			if(type != "rename")
				throw std::runtime_error("Raft request not rename.");

			new_key_ = checked_from_json<std::string>(root, "new_key");
		}

		Rename::operator Json::Value() const
		{
			Json::Value root = VersionRequest::operator Json::Value();

			root["type"] = "rename";
			root["new_key"] = new_key_;

			return root;
		}

		std::string Rename::new_key() const noexcept
		{
			return new_key_;
		}

		Add::Add(const std::string& from, const std::string& key,
				const std::string& version)
			:VersionRequest(from, key, version)
		{
		}

		Add::Add(const Json::Value& root)
			:VersionRequest(root)
		{
			std::string type = checked_from_json<std::string>(root, "type");

			if(type != "add")
				throw std::runtime_error("Raft request not add.");

		}

		Add::operator Json::Value() const
		{
			Json::Value root = VersionRequest::operator Json::Value();

			root["type"] = "add";
			root["version"] = version_;

			return root;
		}

	}
}

ClientHandlers::ClientHandlers(const send_request_type& send_request, const append_to_log_type& append_to_log,
		const leader_type& leader)
	:send_request_(send_request),
	append_to_log_(append_to_log),
	leader_(leader)
{
}

void ClientHandlers::send_request(const std::string& to, const Json::Value& request) const
{
	send_request_(to, request);
}

void ClientHandlers::append_to_log(const Json::Value& request) const
{
	append_to_log_(request);
}

boost::optional<std::string> ClientHandlers::leader() const
{
	return leader_();
}

RaftClient::RaftClient(const std::string& id, ClientHandlers& handlers)
	:id_(id),
	handlers_(handlers)
{
}

void RaftClient::commit_handler(const Json::Value& root)
{
	const std::string type = json_help::checked_from_json<std::string>(root, "type", "Bad commit RPC:");
	if(type == "update")
	{
		raft::request::Update entry(root);
		commit_if_valid(entry);
	}
	else if(type == "delete")
	{
		raft::request::Delete entry(root);
		auto commit_valid = valid(entry, version_map_);
		if(commit_valid == request_invalid && version_map_.count(entry.key()) == 1)
			throw std::runtime_error("Bad commit: conflicts");

		apply_to(entry, version_map_);
	}
	else if(type == "rename")
	{
		raft::request::Rename entry(root);
		commit_if_valid(entry);
	}
	else if(type == "add")
	{
		raft::request::Add entry(root);
		commit_if_valid(entry);
	}
	else throw std::runtime_error("Bad commit RPC: unknown type " + type);
}

bool RaftClient::exists(const std::string& key) const noexcept
{
	return version_map_.count(key) == 1;
}

std::tuple<std::string, std::string> RaftClient::operator [](const std::string& key) noexcept(false)
{
	return version_map_.at(key);
}

void RaftClient::apply_to(const raft::request::Update& update, version_map_type& version_map)
{
	version_map[update.key()] = std::make_tuple(update.new_version(), update.from());
}

void RaftClient::apply_to(const raft::request::Delete& update, version_map_type& version_map)
{
	version_map.erase(update.key());
}

void RaftClient::apply_to(const raft::request::Rename& update, version_map_type& version_map)
{
	version_map[update.new_key()] = std::make_tuple(std::get<0>(version_map[update.key()]),
			update.from());
	version_map.erase(update.key());
}

void RaftClient::apply_to(const raft::request::Add& update, version_map_type& version_map)
{
	version_map[update.key()] = std::make_tuple(update.version(), update.from());
}

bool RaftClient::check_conflict(const raft::request::Update& update) const
{
	if(pending_version_map_.count(update.key()))
		return std::get<0>(pending_version_map_.at(update.key())) != update.old_version();
	else if(version_map_.count(update.key()))
		return std::get<0>(version_map_.at(update.key())) != update.old_version();
	else
		return true;
}

bool RaftClient::check_conflict(const raft::request::Delete& del) const
{
	if(pending_version_map_.count(del.key()))
		return std::get<0>(pending_version_map_.at(del.key())) != del.version();
	else if(version_map_.count(del.key()))
		return std::get<0>(version_map_.at(del.key())) != del.version();

	return true;
}

bool RaftClient::check_conflict(const raft::request::Rename& rename) const
{
	if(!(pending_version_map_.count(rename.new_key()) == 1
		|| version_map_.count(rename.new_key()) == 1))
	{
		if(pending_version_map_.count(rename.key()))
			return std::get<0>(pending_version_map_.at(rename.key())) != rename.version();
		else if(version_map_.count(rename.key()))
			return std::get<0>(version_map_.at(rename.key())) != rename.version();
	}

	return true;
}

bool RaftClient::check_conflict(const raft::request::Add& add) const
{
	return version_map_.count(add.key()) == 1 || pending_version_map_.count(add.key()) == 1;
}

bool RaftClient::done(raft::request::Update::const_reference request, const version_map_type& version_map) const noexcept
{
	try
	{
		if(version_map.count(request.key()))
			return std::get<0>(version_map.at(request.key())) == request.new_version();
	}
	catch(std::exception& ex)
	{
		BOOST_LOG_TRIVIAL(warning) << "Unexpected exception in RaftClient::done(Update...). Ignoring. Details: "
			<< ex.what();
	}
	catch(...)
	{
		BOOST_LOG_TRIVIAL(warning) << "Unexpected exception in RaftClient::done(Update...). Ignoring.";
	}

	return false;
}

bool RaftClient::done(raft::request::Delete::const_reference request, const version_map_type& version_map) const noexcept
{
	//can't tell if the've been done
	return false;
}

bool RaftClient::done(raft::request::Rename::const_reference request, const version_map_type& version_map) const noexcept
{
	try
	{
		if(version_map.count(request.new_key()))
			return std::get<0>(version_map.at(request.new_key())) == request.version();
	}
	catch(std::exception& ex)
	{
		BOOST_LOG_TRIVIAL(warning) << "Unexpected exception in RaftClient::done(Rename...). Ignoring. Details: "
			<< ex.what();
	}
	catch(...)
	{
		BOOST_LOG_TRIVIAL(warning) << "Unexpected exception in RaftClient::done(Rename...). Ignoring.";
	}

	return false;
}

bool RaftClient::done(raft::request::Add::const_reference request, const version_map_type& version_map) const noexcept
{
	try
	{
		if(version_map.count(request.key()))
			return std::get<0>(version_map.at(request.key())) == request.version();
	}
	catch(std::exception& ex)
	{
		BOOST_LOG_TRIVIAL(warning) << "Unexpected exception in RaftClient::done(Add...). Ignoring. Details: "
			<< ex.what();
	}
	catch(...)
	{
		BOOST_LOG_TRIVIAL(warning) << "Unexpected exception in RaftClient::done(Add...). Ignoring.";
	}

	return false;
}
<commit_msg>Added logging to commit.<commit_after>#include <string>
#include <functional>
#include <fstream>
#include <set>

#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>

#include <boost/optional.hpp>
#include <boost/filesystem.hpp>

#include <json/json.h>
#include "../common/json_help.hpp"

#include "raftrpc.hpp"
#include "raftstate.hpp"
#include "raftclient.hpp"

namespace raft
{
	namespace request
	{
		Update::Update(const std::string& from, const std::string& key,
			   const std::string& old_version, const std::string& new_version)
			:Request(from, key),
			old_version_(old_version),
			new_version_(new_version)
		{
		}

		Update::Update(const Json::Value& root)
			:Request(root)
		{
			std::string type = checked_from_json<std::string>(root, "type");

			if(type != "update")
				throw std::runtime_error("Raft request not update.");

			old_version_ = checked_from_json<std::string>(root, "old_version");
			new_version_ = checked_from_json<std::string>(root, "new_version");
		}

		Update::operator Json::Value() const
		{
			Json::Value root = Request::operator Json::Value();

			root["type"] = "update";
			root["old_version"] = old_version_;
			root["new_version"] = new_version_;

			return root;
		}

		std::string Update::old_version() const noexcept
		{
			return old_version_;
		}

		std::string Update::version() const noexcept
		{
			return new_version_;
		}

		std::string Update::new_version() const noexcept
		{
			return new_version_;
		}

		Delete::Delete(const std::string& from, const std::string& key,
				const std::string& version)
			:VersionRequest(from, key, version)
		{
		}

		Delete::Delete(const Json::Value& root)
			:VersionRequest(root)
		{
			std::string type = checked_from_json<std::string>(root, "type");

			if(type != "delete")
				throw std::runtime_error("Raft request not delete.");
		}

		Delete::operator Json::Value() const
		{
			Json::Value root = VersionRequest::operator Json::Value();

			root["type"] = "delete";

			return root;
		}

		Rename::Rename(const std::string& from, const std::string& key,
				const std::string& new_key, const std::string& version)
			:VersionRequest(from, key, version),
			new_key_(new_key)
		{
		}

		Rename::Rename(const Json::Value& root)
			:VersionRequest(root)
		{
			std::string type = checked_from_json<std::string>(root, "type");

			if(type != "rename")
				throw std::runtime_error("Raft request not rename.");

			new_key_ = checked_from_json<std::string>(root, "new_key");
		}

		Rename::operator Json::Value() const
		{
			Json::Value root = VersionRequest::operator Json::Value();

			root["type"] = "rename";
			root["new_key"] = new_key_;

			return root;
		}

		std::string Rename::new_key() const noexcept
		{
			return new_key_;
		}

		Add::Add(const std::string& from, const std::string& key,
				const std::string& version)
			:VersionRequest(from, key, version)
		{
		}

		Add::Add(const Json::Value& root)
			:VersionRequest(root)
		{
			std::string type = checked_from_json<std::string>(root, "type");

			if(type != "add")
				throw std::runtime_error("Raft request not add.");

		}

		Add::operator Json::Value() const
		{
			Json::Value root = VersionRequest::operator Json::Value();

			root["type"] = "add";
			root["version"] = version_;

			return root;
		}

	}
}

ClientHandlers::ClientHandlers(const send_request_type& send_request, const append_to_log_type& append_to_log,
		const leader_type& leader)
	:send_request_(send_request),
	append_to_log_(append_to_log),
	leader_(leader)
{
}

void ClientHandlers::send_request(const std::string& to, const Json::Value& request) const
{
	send_request_(to, request);
}

void ClientHandlers::append_to_log(const Json::Value& request) const
{
	append_to_log_(request);
}

boost::optional<std::string> ClientHandlers::leader() const
{
	return leader_();
}

RaftClient::RaftClient(const std::string& id, ClientHandlers& handlers)
	:id_(id),
	handlers_(handlers)
{
}

void RaftClient::commit_handler(const Json::Value& root)
{
	const std::string type = json_help::checked_from_json<std::string>(root, "type", "Bad commit RPC:");
	if(type == "update")
	{
		raft::request::Update entry(root);

		BOOST_LOG_TRIVIAL(info) << "Committing update on key: " << entry.key()
			<< " version: " << entry.old_version() << " -> " << entry.new_version();

		commit_if_valid(entry);
	}
	else if(type == "delete")
	{
		raft::request::Delete entry(root);
		BOOST_LOG_TRIVIAL(info) << "Committing delete on key: " << entry.key()
			<< " version: " << entry.version();

		auto commit_valid = valid(entry, version_map_);
		if(commit_valid == request_invalid && version_map_.count(entry.key()) == 1)
			throw std::runtime_error("Bad commit: conflicts");

		apply_to(entry, version_map_);
	}
	else if(type == "rename")
	{
		raft::request::Rename entry(root);
		BOOST_LOG_TRIVIAL(info) << "Committing rename on key: " << entry.key()
			<< " -> " << entry.new_key() << " version: " << entry.version();

		commit_if_valid(entry);
	}
	else if(type == "add")
	{
		raft::request::Add entry(root);
		BOOST_LOG_TRIVIAL(info) << "Committing add on key: " << entry.key()
			<< " version: " << entry.version();

		commit_if_valid(entry);
	}
	else throw std::runtime_error("Bad commit RPC: unknown type " + type);
}

bool RaftClient::exists(const std::string& key) const noexcept
{
	return version_map_.count(key) == 1;
}

std::tuple<std::string, std::string> RaftClient::operator [](const std::string& key) noexcept(false)
{
	return version_map_.at(key);
}

void RaftClient::apply_to(const raft::request::Update& update, version_map_type& version_map)
{
	version_map[update.key()] = std::make_tuple(update.new_version(), update.from());
}

void RaftClient::apply_to(const raft::request::Delete& update, version_map_type& version_map)
{
	version_map.erase(update.key());
}

void RaftClient::apply_to(const raft::request::Rename& update, version_map_type& version_map)
{
	version_map[update.new_key()] = std::make_tuple(std::get<0>(version_map[update.key()]),
			update.from());
	version_map.erase(update.key());
}

void RaftClient::apply_to(const raft::request::Add& update, version_map_type& version_map)
{
	version_map[update.key()] = std::make_tuple(update.version(), update.from());
}

bool RaftClient::check_conflict(const raft::request::Update& update) const
{
	if(pending_version_map_.count(update.key()))
		return std::get<0>(pending_version_map_.at(update.key())) != update.old_version();
	else if(version_map_.count(update.key()))
		return std::get<0>(version_map_.at(update.key())) != update.old_version();
	else
		return true;
}

bool RaftClient::check_conflict(const raft::request::Delete& del) const
{
	if(pending_version_map_.count(del.key()))
		return std::get<0>(pending_version_map_.at(del.key())) != del.version();
	else if(version_map_.count(del.key()))
		return std::get<0>(version_map_.at(del.key())) != del.version();

	return true;
}

bool RaftClient::check_conflict(const raft::request::Rename& rename) const
{
	if(!(pending_version_map_.count(rename.new_key()) == 1
		|| version_map_.count(rename.new_key()) == 1))
	{
		if(pending_version_map_.count(rename.key()))
			return std::get<0>(pending_version_map_.at(rename.key())) != rename.version();
		else if(version_map_.count(rename.key()))
			return std::get<0>(version_map_.at(rename.key())) != rename.version();
	}

	return true;
}

bool RaftClient::check_conflict(const raft::request::Add& add) const
{
	return version_map_.count(add.key()) == 1 || pending_version_map_.count(add.key()) == 1;
}

bool RaftClient::done(raft::request::Update::const_reference request, const version_map_type& version_map) const noexcept
{
	try
	{
		if(version_map.count(request.key()))
			return std::get<0>(version_map.at(request.key())) == request.new_version();
	}
	catch(std::exception& ex)
	{
		BOOST_LOG_TRIVIAL(warning) << "Unexpected exception in RaftClient::done(Update...). Ignoring. Details: "
			<< ex.what();
	}
	catch(...)
	{
		BOOST_LOG_TRIVIAL(warning) << "Unexpected exception in RaftClient::done(Update...). Ignoring.";
	}

	return false;
}

bool RaftClient::done(raft::request::Delete::const_reference request, const version_map_type& version_map) const noexcept
{
	//can't tell if the've been done
	return false;
}

bool RaftClient::done(raft::request::Rename::const_reference request, const version_map_type& version_map) const noexcept
{
	try
	{
		if(version_map.count(request.new_key()))
			return std::get<0>(version_map.at(request.new_key())) == request.version();
	}
	catch(std::exception& ex)
	{
		BOOST_LOG_TRIVIAL(warning) << "Unexpected exception in RaftClient::done(Rename...). Ignoring. Details: "
			<< ex.what();
	}
	catch(...)
	{
		BOOST_LOG_TRIVIAL(warning) << "Unexpected exception in RaftClient::done(Rename...). Ignoring.";
	}

	return false;
}

bool RaftClient::done(raft::request::Add::const_reference request, const version_map_type& version_map) const noexcept
{
	try
	{
		if(version_map.count(request.key()))
			return std::get<0>(version_map.at(request.key())) == request.version();
	}
	catch(std::exception& ex)
	{
		BOOST_LOG_TRIVIAL(warning) << "Unexpected exception in RaftClient::done(Add...). Ignoring. Details: "
			<< ex.what();
	}
	catch(...)
	{
		BOOST_LOG_TRIVIAL(warning) << "Unexpected exception in RaftClient::done(Add...). Ignoring.";
	}

	return false;
}
<|endoftext|>