<commit_before>/*
// $Id$
// Fennel is a library of data storage and processing components.
// Copyright (C) 2005-2005 The Eigenbase Project
// Copyright (C) 2003-2005 Disruptive Tech
// Copyright (C) 2005-2005 LucidEra, Inc.
// Portions Copyright (C) 1999-2005 John V. Sichi
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version approved by The Eigenbase Project.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "fennel/common/CommonPreamble.h"
#include "fennel/farrago/CmdInterpreter.h"
#include "fennel/farrago/JavaTraceTarget.h"
#include "fennel/exec/ExecStreamGraphEmbryo.h"
#include "fennel/farrago/ExecStreamBuilder.h"
#include "fennel/cache/CacheParams.h"
#include "fennel/common/ConfigMap.h"
#include "fennel/common/FennelExcn.h"
#include "fennel/btree/BTreeBuilder.h"
#include "fennel/db/Database.h"
#include "fennel/db/CheckpointThread.h"
#include "fennel/txn/LogicalTxn.h"
#include "fennel/txn/LogicalTxnLog.h"
#include "fennel/tuple/StoredTypeDescriptorFactory.h"
#include "fennel/segment/SegmentFactory.h"
#include "fennel/exec/DfsTreeExecStreamScheduler.h"
#include "fennel/exec/ExecStreamGraph.h"
#include "fennel/farrago/ExecStreamFactory.h"
#include "fennel/ftrs/FtrsTableWriterFactory.h"

FENNEL_BEGIN_CPPFILE("$Id$");

int64_t CmdInterpreter::executeCommand(
    ProxyCmd &cmd)
{
    resultHandle = 0;
    // dispatch based on polymorphic command type
    FemVisitor::visitTbl.accept(*this,cmd);
    return resultHandle;
}

CmdInterpreter::DbHandle *CmdInterpreter::getDbHandle(
    SharedProxyDbHandle pHandle)
{
    return reinterpret_cast<DbHandle *>(pHandle->getLongHandle());
}

CmdInterpreter::TxnHandle *CmdInterpreter::getTxnHandle(
    SharedProxyTxnHandle pHandle)
{
    return reinterpret_cast<TxnHandle *>(pHandle->getLongHandle());
}

CmdInterpreter::StreamGraphHandle *CmdInterpreter::getStreamGraphHandle(
    SharedProxyStreamGraphHandle pHandle)
{
    return reinterpret_cast<StreamGraphHandle *>(pHandle->getLongHandle());
}

SavepointId CmdInterpreter::getSavepointId(SharedProxySvptHandle pHandle)
{
    return SavepointId(pHandle->getLongHandle());
}

void CmdInterpreter::setDbHandle(
    SharedProxyDbHandle,DbHandle *pHandle)
{
    resultHandle = reinterpret_cast<int64_t>(pHandle);
}

void CmdInterpreter::setTxnHandle(
    SharedProxyTxnHandle,TxnHandle *pHandle)
{
    resultHandle = reinterpret_cast<int64_t>(pHandle);
}

void CmdInterpreter::setStreamGraphHandle(
    SharedProxyStreamGraphHandle,StreamGraphHandle *pHandle)
{
    resultHandle = reinterpret_cast<int64_t>(pHandle);
}

void CmdInterpreter::setExecStreamHandle(
    SharedProxyStreamHandle,ExecStream *pStream)
{
    resultHandle = reinterpret_cast<int64_t>(pStream);
}

void CmdInterpreter::setSvptHandle(
    SharedProxySvptHandle,SavepointId svptId)
{
    resultHandle = opaqueToInt(svptId);
}

CmdInterpreter::DbHandle* CmdInterpreter::newDbHandle()
{
    return new DbHandle();
}

CmdInterpreter::TxnHandle* CmdInterpreter::newTxnHandle()
{
    return new TxnHandle();
}

CmdInterpreter::DbHandle::~DbHandle()
{
    statsTimer.stop();

    // close database before trace
    pDb->close();
    --JniUtil::handleCount;
}

CmdInterpreter::TxnHandle::~TxnHandle()
{
    --JniUtil::handleCount;
}

CmdInterpreter::StreamGraphHandle::~StreamGraphHandle()
{
    if (javaRuntimeContext) {
        JniEnvAutoRef pEnv;
        pEnv->DeleteGlobalRef(javaRuntimeContext);
    }
    --JniUtil::handleCount;
}

void CmdInterpreter::visit(ProxyCmdOpenDatabase &cmd)
{
    ConfigMap configMap;

    SharedProxyDatabaseParam pParam = cmd.getParams();
    for (; pParam; ++pParam) {
        configMap.setStringParam(pParam->getName(),pParam->getValue());
    }

    CacheParams cacheParams;
    cacheParams.readConfig(configMap);
    SharedCache pCache = Cache::newCache(cacheParams);

    DeviceMode openMode = cmd.isCreateDatabase()
        ? DeviceMode::createNew
        : DeviceMode::load;

    jobject javaTrace = getObjectFromLong(cmd.getJavaTraceHandle());

    std::auto_ptr<DbHandle> pDbHandle(newDbHandle());
    ++JniUtil::handleCount;
    pDbHandle->pTraceTarget.reset(new JavaTraceTarget(javaTrace));

    SharedDatabase pDb = Database::newDatabase(
        pCache,
        configMap,
        openMode,
        pDbHandle->pTraceTarget.get());

    pDbHandle->pDb = pDb;

    pDbHandle->statsTimer.addSource(pDb);
    pDbHandle->statsTimer.start();

    if (pDb->isRecoveryRequired()) {
        SegmentAccessor scratchAccessor =
            pDb->getSegmentFactory()->newScratchSegment(pDb->getCache());
        FtrsTableWriterFactory recoveryFactory(
            pDb,
            pDb->getCache(),
            pDb->getTypeFactory(),
            scratchAccessor);
        pDb->recover(recoveryFactory);
    }
    setDbHandle(cmd.getResultHandle(),pDbHandle.release());
}

void CmdInterpreter::visit(ProxyCmdCloseDatabase &cmd)
{
    DbHandle *pDbHandle = getDbHandle(cmd.getDbHandle());
    deleteAndNullify(pDbHandle);
}

void CmdInterpreter::visit(ProxyCmdCheckpoint &cmd)
{
    DbHandle *pDbHandle = getDbHandle(cmd.getDbHandle());

    pDbHandle->pDb->requestCheckpoint(
        cmd.isFuzzy() ? CHECKPOINT_FLUSH_FUZZY : CHECKPOINT_FLUSH_ALL,
        cmd.isAsync());
}

void CmdInterpreter::getBTreeForIndexCmd(
    ProxyIndexCmd &cmd,PageId rootPageId,BTreeDescriptor &treeDescriptor)
{
    SharedDatabase pDatabase = getDbHandle(cmd.getDbHandle())->pDb;

    readTupleDescriptor(
        treeDescriptor.tupleDescriptor,
        *(cmd.getTupleDesc()),pDatabase->getTypeFactory());

    CmdInterpreter::readTupleProjection(
        treeDescriptor.keyProjection,cmd.getKeyProj());

    treeDescriptor.pageOwnerId = PageOwnerId(cmd.getIndexId());
    treeDescriptor.segmentId = SegmentId(cmd.getSegmentId());
    treeDescriptor.segmentAccessor.pSegment =
        pDatabase->getSegmentById(treeDescriptor.segmentId);
    treeDescriptor.segmentAccessor.pCacheAccessor = pDatabase->getCache();
    treeDescriptor.rootPageId = rootPageId;
}

void CmdInterpreter::visit(ProxyCmdCreateIndex &cmd)
{
    // block checkpoints
    SharedDatabase pDb = getDbHandle(cmd.getDbHandle())->pDb;
    SXMutexSharedGuard actionMutexGuard(
        pDb->getCheckpointThread()->getActionMutex());

    BTreeDescriptor treeDescriptor;
    getBTreeForIndexCmd(cmd,NULL_PAGE_ID,treeDescriptor);
    BTreeBuilder builder(treeDescriptor);
    builder.createEmptyRoot();
    resultHandle = opaqueToInt(builder.getRootPageId());
}

void CmdInterpreter::visit(ProxyCmdTruncateIndex &cmd)
{
    // block checkpoints
    SharedDatabase pDb = getDbHandle(cmd.getDbHandle())->pDb;
    SXMutexSharedGuard actionMutexGuard(
        pDb->getCheckpointThread()->getActionMutex());

    BTreeDescriptor treeDescriptor;
    getBTreeForIndexCmd(cmd,PageId(cmd.getRootPageId()),treeDescriptor);
    BTreeBuilder builder(treeDescriptor);
    builder.truncate(false);
}

void CmdInterpreter::visit(ProxyCmdDropIndex &cmd)
{
    // block checkpoints
    SharedDatabase pDb = getDbHandle(cmd.getDbHandle())->pDb;
    SXMutexSharedGuard actionMutexGuard(
        pDb->getCheckpointThread()->getActionMutex());

    BTreeDescriptor treeDescriptor;
    getBTreeForIndexCmd(cmd,PageId(cmd.getRootPageId()),treeDescriptor);
    BTreeBuilder builder(treeDescriptor);
    builder.truncate(true);
}

void CmdInterpreter::visit(ProxyCmdBeginTxn &cmd)
{
    // block checkpoints
    SharedDatabase pDb = getDbHandle(cmd.getDbHandle())->pDb;
    SXMutexSharedGuard actionMutexGuard(
        pDb->getCheckpointThread()->getActionMutex());

    std::auto_ptr<TxnHandle> pTxnHandle(newTxnHandle());
    ++JniUtil::handleCount;
    pTxnHandle->pDb = pDb;
    // TODO:  CacheAccessor factory
    pTxnHandle->pTxn = pDb->getTxnLog()->newLogicalTxn(pDb->getCache());

    // NOTE:  use a null scratchAccessor; individual ExecStreamGraphs
    // will have their own
    SegmentAccessor scratchAccessor;

    pTxnHandle->pFtrsTableWriterFactory = SharedFtrsTableWriterFactory(
        new FtrsTableWriterFactory(
            pDb,
            pDb->getCache(),
            pDb->getTypeFactory(),
            scratchAccessor));
    setTxnHandle(cmd.getResultHandle(),pTxnHandle.release());
}

void CmdInterpreter::visit(ProxyCmdSavepoint &cmd)
{
    TxnHandle *pTxnHandle = getTxnHandle(cmd.getTxnHandle());

    // block checkpoints
    SXMutexSharedGuard actionMutexGuard(
        pTxnHandle->pDb->getCheckpointThread()->getActionMutex());

    setSvptHandle(
        cmd.getResultHandle(),
        pTxnHandle->pTxn->createSavepoint());
}

void CmdInterpreter::visit(ProxyCmdCommit &cmd)
{
    TxnHandle *pTxnHandle = getTxnHandle(cmd.getTxnHandle());

    // block checkpoints
    SXMutexSharedGuard actionMutexGuard(
        pTxnHandle->pDb->getCheckpointThread()->getActionMutex());

    if (cmd.getSvptHandle()) {
        SavepointId svptId = getSavepointId(cmd.getSvptHandle());
        pTxnHandle->pTxn->commitSavepoint(svptId);
    } else {
        pTxnHandle->pTxn->commit();
        deleteAndNullify(pTxnHandle);
    }
}

void CmdInterpreter::visit(ProxyCmdRollback &cmd)
{
    TxnHandle *pTxnHandle = getTxnHandle(cmd.getTxnHandle());

    // block checkpoints
    SXMutexSharedGuard actionMutexGuard(
        pTxnHandle->pDb->getCheckpointThread()->getActionMutex());

    if (cmd.getSvptHandle()) {
        SavepointId svptId = getSavepointId(cmd.getSvptHandle());
        pTxnHandle->pTxn->rollback(&svptId);
    } else {
        pTxnHandle->pTxn->rollback();
        deleteAndNullify(pTxnHandle);
    }
}

void CmdInterpreter::visit(ProxyCmdCreateExecutionStreamGraph &cmd)
{
    TxnHandle *pTxnHandle = getTxnHandle(cmd.getTxnHandle());
    SharedExecStreamGraph pGraph =
        ExecStreamGraph::newExecStreamGraph();
    pGraph->setTxn(pTxnHandle->pTxn);
    std::auto_ptr<StreamGraphHandle> pStreamGraphHandle(
        new StreamGraphHandle());
    ++JniUtil::handleCount;
    pStreamGraphHandle->pTxnHandle = pTxnHandle;
    pStreamGraphHandle->pExecStreamGraph = pGraph;
    pStreamGraphHandle->pExecStreamFactory.reset(
        new ExecStreamFactory(
            pTxnHandle->pDb,
            pTxnHandle->pFtrsTableWriterFactory,
            pStreamGraphHandle.get()));
    setStreamGraphHandle(
        cmd.getResultHandle(),
        pStreamGraphHandle.release());
}

void CmdInterpreter::visit(ProxyCmdPrepareExecutionStreamGraph &cmd)
{
    StreamGraphHandle *pStreamGraphHandle = getStreamGraphHandle(
        cmd.getStreamGraphHandle());
    TxnHandle *pTxnHandle = pStreamGraphHandle->pTxnHandle;
    // NOTE:  sequence is important here
    SharedExecStreamScheduler pScheduler(
        new DfsTreeExecStreamScheduler(
            &(pTxnHandle->pDb->getTraceTarget()),
            "xo.scheduler"));
    ExecStreamGraphEmbryo graphEmbryo(
        pStreamGraphHandle->pExecStreamGraph,
        pScheduler,
        pTxnHandle->pDb->getCache(),
        pTxnHandle->pDb->getSegmentFactory(),
        pStreamGraphHandle->pExecStreamFactory->shouldEnforceCacheQuotas());
    pStreamGraphHandle->pExecStreamFactory->setGraphEmbryo(graphEmbryo);
    ExecStreamBuilder streamBuilder(
        graphEmbryo,
        *(pStreamGraphHandle->pExecStreamFactory));
    streamBuilder.buildStreamGraph(cmd, true);
    pStreamGraphHandle->pExecStreamFactory.reset();
    pStreamGraphHandle->pScheduler = pScheduler;
}

void CmdInterpreter::visit(ProxyCmdCreateStreamHandle &cmd)
{
    StreamGraphHandle *pStreamGraphHandle = getStreamGraphHandle(
        cmd.getStreamGraphHandle());
    SharedExecStream pStream =
        pStreamGraphHandle->pExecStreamGraph->findLastStream(
            cmd.getStreamName(), 0);
    setExecStreamHandle(
        cmd.getResultHandle(),
        pStream.get());
}

PageId CmdInterpreter::StreamGraphHandle::getRoot(PageOwnerId pageOwnerId)
{
    JniEnvAutoRef pEnv;
    jlong x = opaqueToInt(pageOwnerId);
    x = pEnv->CallLongMethod(
        javaRuntimeContext,JniUtil::methGetIndexRoot,x);
    return PageId(x);
}

void CmdInterpreter::readTupleDescriptor(
    TupleDescriptor &tupleDesc,
    ProxyTupleDescriptor &javaTupleDesc,
    StoredTypeDescriptorFactory const &typeFactory)
{
    tupleDesc.clear();
    SharedProxyTupleAttrDescriptor pAttr = javaTupleDesc.getAttrDescriptor();
    for (; pAttr; ++pAttr) {
        StoredTypeDescriptor const &typeDescriptor =
            typeFactory.newDataType(pAttr->getTypeOrdinal());
        tupleDesc.push_back(
            TupleAttributeDescriptor(
                typeDescriptor,pAttr->isNullable(),pAttr->getByteLength()));
    }
}

void CmdInterpreter::readTupleProjection(
    TupleProjection &tupleProj,
    SharedProxyTupleProjection pJavaTupleProj)
{
    tupleProj.clear();
    SharedProxyTupleAttrProjection pAttr = pJavaTupleProj->getAttrProjection();
    for (; pAttr; ++pAttr) {
        tupleProj.push_back(pAttr->getAttributeIndex());
    }
}

FENNEL_END_CPPFILE("$Id$");

// End CmdInterpreter.cpp
<commit_msg>FARRAGO:  initialize javaRuntimeContext just in case; should be in a constructor instead<commit_after>/*
// $Id$
// Fennel is a library of data storage and processing components.
// Copyright (C) 2005-2005 The Eigenbase Project
// Copyright (C) 2003-2005 Disruptive Tech
// Copyright (C) 2005-2005 LucidEra, Inc.
// Portions Copyright (C) 1999-2005 John V. Sichi
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version approved by The Eigenbase Project.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "fennel/common/CommonPreamble.h"
#include "fennel/farrago/CmdInterpreter.h"
#include "fennel/farrago/JavaTraceTarget.h"
#include "fennel/exec/ExecStreamGraphEmbryo.h"
#include "fennel/farrago/ExecStreamBuilder.h"
#include "fennel/cache/CacheParams.h"
#include "fennel/common/ConfigMap.h"
#include "fennel/common/FennelExcn.h"
#include "fennel/btree/BTreeBuilder.h"
#include "fennel/db/Database.h"
#include "fennel/db/CheckpointThread.h"
#include "fennel/txn/LogicalTxn.h"
#include "fennel/txn/LogicalTxnLog.h"
#include "fennel/tuple/StoredTypeDescriptorFactory.h"
#include "fennel/segment/SegmentFactory.h"
#include "fennel/exec/DfsTreeExecStreamScheduler.h"
#include "fennel/exec/ExecStreamGraph.h"
#include "fennel/farrago/ExecStreamFactory.h"
#include "fennel/ftrs/FtrsTableWriterFactory.h"

FENNEL_BEGIN_CPPFILE("$Id$");

int64_t CmdInterpreter::executeCommand(
    ProxyCmd &cmd)
{
    resultHandle = 0;
    // dispatch based on polymorphic command type
    FemVisitor::visitTbl.accept(*this,cmd);
    return resultHandle;
}

CmdInterpreter::DbHandle *CmdInterpreter::getDbHandle(
    SharedProxyDbHandle pHandle)
{
    return reinterpret_cast<DbHandle *>(pHandle->getLongHandle());
}

CmdInterpreter::TxnHandle *CmdInterpreter::getTxnHandle(
    SharedProxyTxnHandle pHandle)
{
    return reinterpret_cast<TxnHandle *>(pHandle->getLongHandle());
}

CmdInterpreter::StreamGraphHandle *CmdInterpreter::getStreamGraphHandle(
    SharedProxyStreamGraphHandle pHandle)
{
    return reinterpret_cast<StreamGraphHandle *>(pHandle->getLongHandle());
}

SavepointId CmdInterpreter::getSavepointId(SharedProxySvptHandle pHandle)
{
    return SavepointId(pHandle->getLongHandle());
}

void CmdInterpreter::setDbHandle(
    SharedProxyDbHandle,DbHandle *pHandle)
{
    resultHandle = reinterpret_cast<int64_t>(pHandle);
}

void CmdInterpreter::setTxnHandle(
    SharedProxyTxnHandle,TxnHandle *pHandle)
{
    resultHandle = reinterpret_cast<int64_t>(pHandle);
}

void CmdInterpreter::setStreamGraphHandle(
    SharedProxyStreamGraphHandle,StreamGraphHandle *pHandle)
{
    resultHandle = reinterpret_cast<int64_t>(pHandle);
}

void CmdInterpreter::setExecStreamHandle(
    SharedProxyStreamHandle,ExecStream *pStream)
{
    resultHandle = reinterpret_cast<int64_t>(pStream);
}

void CmdInterpreter::setSvptHandle(
    SharedProxySvptHandle,SavepointId svptId)
{
    resultHandle = opaqueToInt(svptId);
}

CmdInterpreter::DbHandle* CmdInterpreter::newDbHandle()
{
    return new DbHandle();
}

CmdInterpreter::TxnHandle* CmdInterpreter::newTxnHandle()
{
    return new TxnHandle();
}

CmdInterpreter::DbHandle::~DbHandle()
{
    statsTimer.stop();

    // close database before trace
    pDb->close();
    --JniUtil::handleCount;
}

CmdInterpreter::TxnHandle::~TxnHandle()
{
    --JniUtil::handleCount;
}

CmdInterpreter::StreamGraphHandle::~StreamGraphHandle()
{
    if (javaRuntimeContext) {
        JniEnvAutoRef pEnv;
        pEnv->DeleteGlobalRef(javaRuntimeContext);
    }
    --JniUtil::handleCount;
}

void CmdInterpreter::visit(ProxyCmdOpenDatabase &cmd)
{
    ConfigMap configMap;

    SharedProxyDatabaseParam pParam = cmd.getParams();
    for (; pParam; ++pParam) {
        configMap.setStringParam(pParam->getName(),pParam->getValue());
    }

    CacheParams cacheParams;
    cacheParams.readConfig(configMap);
    SharedCache pCache = Cache::newCache(cacheParams);

    DeviceMode openMode = cmd.isCreateDatabase()
        ? DeviceMode::createNew
        : DeviceMode::load;

    jobject javaTrace = getObjectFromLong(cmd.getJavaTraceHandle());

    std::auto_ptr<DbHandle> pDbHandle(newDbHandle());
    ++JniUtil::handleCount;
    pDbHandle->pTraceTarget.reset(new JavaTraceTarget(javaTrace));

    SharedDatabase pDb = Database::newDatabase(
        pCache,
        configMap,
        openMode,
        pDbHandle->pTraceTarget.get());

    pDbHandle->pDb = pDb;

    pDbHandle->statsTimer.addSource(pDb);
    pDbHandle->statsTimer.start();

    if (pDb->isRecoveryRequired()) {
        SegmentAccessor scratchAccessor =
            pDb->getSegmentFactory()->newScratchSegment(pDb->getCache());
        FtrsTableWriterFactory recoveryFactory(
            pDb,
            pDb->getCache(),
            pDb->getTypeFactory(),
            scratchAccessor);
        pDb->recover(recoveryFactory);
    }
    setDbHandle(cmd.getResultHandle(),pDbHandle.release());
}

void CmdInterpreter::visit(ProxyCmdCloseDatabase &cmd)
{
    DbHandle *pDbHandle = getDbHandle(cmd.getDbHandle());
    deleteAndNullify(pDbHandle);
}

void CmdInterpreter::visit(ProxyCmdCheckpoint &cmd)
{
    DbHandle *pDbHandle = getDbHandle(cmd.getDbHandle());

    pDbHandle->pDb->requestCheckpoint(
        cmd.isFuzzy() ? CHECKPOINT_FLUSH_FUZZY : CHECKPOINT_FLUSH_ALL,
        cmd.isAsync());
}

void CmdInterpreter::getBTreeForIndexCmd(
    ProxyIndexCmd &cmd,PageId rootPageId,BTreeDescriptor &treeDescriptor)
{
    SharedDatabase pDatabase = getDbHandle(cmd.getDbHandle())->pDb;

    readTupleDescriptor(
        treeDescriptor.tupleDescriptor,
        *(cmd.getTupleDesc()),pDatabase->getTypeFactory());

    CmdInterpreter::readTupleProjection(
        treeDescriptor.keyProjection,cmd.getKeyProj());

    treeDescriptor.pageOwnerId = PageOwnerId(cmd.getIndexId());
    treeDescriptor.segmentId = SegmentId(cmd.getSegmentId());
    treeDescriptor.segmentAccessor.pSegment =
        pDatabase->getSegmentById(treeDescriptor.segmentId);
    treeDescriptor.segmentAccessor.pCacheAccessor = pDatabase->getCache();
    treeDescriptor.rootPageId = rootPageId;
}

void CmdInterpreter::visit(ProxyCmdCreateIndex &cmd)
{
    // block checkpoints
    SharedDatabase pDb = getDbHandle(cmd.getDbHandle())->pDb;
    SXMutexSharedGuard actionMutexGuard(
        pDb->getCheckpointThread()->getActionMutex());

    BTreeDescriptor treeDescriptor;
    getBTreeForIndexCmd(cmd,NULL_PAGE_ID,treeDescriptor);
    BTreeBuilder builder(treeDescriptor);
    builder.createEmptyRoot();
    resultHandle = opaqueToInt(builder.getRootPageId());
}

void CmdInterpreter::visit(ProxyCmdTruncateIndex &cmd)
{
    // block checkpoints
    SharedDatabase pDb = getDbHandle(cmd.getDbHandle())->pDb;
    SXMutexSharedGuard actionMutexGuard(
        pDb->getCheckpointThread()->getActionMutex());

    BTreeDescriptor treeDescriptor;
    getBTreeForIndexCmd(cmd,PageId(cmd.getRootPageId()),treeDescriptor);
    BTreeBuilder builder(treeDescriptor);
    builder.truncate(false);
}

void CmdInterpreter::visit(ProxyCmdDropIndex &cmd)
{
    // block checkpoints
    SharedDatabase pDb = getDbHandle(cmd.getDbHandle())->pDb;
    SXMutexSharedGuard actionMutexGuard(
        pDb->getCheckpointThread()->getActionMutex());

    BTreeDescriptor treeDescriptor;
    getBTreeForIndexCmd(cmd,PageId(cmd.getRootPageId()),treeDescriptor);
    BTreeBuilder builder(treeDescriptor);
    builder.truncate(true);
}

void CmdInterpreter::visit(ProxyCmdBeginTxn &cmd)
{
    // block checkpoints
    SharedDatabase pDb = getDbHandle(cmd.getDbHandle())->pDb;
    SXMutexSharedGuard actionMutexGuard(
        pDb->getCheckpointThread()->getActionMutex());

    std::auto_ptr<TxnHandle> pTxnHandle(newTxnHandle());
    ++JniUtil::handleCount;
    pTxnHandle->pDb = pDb;
    // TODO:  CacheAccessor factory
    pTxnHandle->pTxn = pDb->getTxnLog()->newLogicalTxn(pDb->getCache());

    // NOTE:  use a null scratchAccessor; individual ExecStreamGraphs
    // will have their own
    SegmentAccessor scratchAccessor;

    pTxnHandle->pFtrsTableWriterFactory = SharedFtrsTableWriterFactory(
        new FtrsTableWriterFactory(
            pDb,
            pDb->getCache(),
            pDb->getTypeFactory(),
            scratchAccessor));
    setTxnHandle(cmd.getResultHandle(),pTxnHandle.release());
}

void CmdInterpreter::visit(ProxyCmdSavepoint &cmd)
{
    TxnHandle *pTxnHandle = getTxnHandle(cmd.getTxnHandle());

    // block checkpoints
    SXMutexSharedGuard actionMutexGuard(
        pTxnHandle->pDb->getCheckpointThread()->getActionMutex());

    setSvptHandle(
        cmd.getResultHandle(),
        pTxnHandle->pTxn->createSavepoint());
}

void CmdInterpreter::visit(ProxyCmdCommit &cmd)
{
    TxnHandle *pTxnHandle = getTxnHandle(cmd.getTxnHandle());

    // block checkpoints
    SXMutexSharedGuard actionMutexGuard(
        pTxnHandle->pDb->getCheckpointThread()->getActionMutex());

    if (cmd.getSvptHandle()) {
        SavepointId svptId = getSavepointId(cmd.getSvptHandle());
        pTxnHandle->pTxn->commitSavepoint(svptId);
    } else {
        pTxnHandle->pTxn->commit();
        deleteAndNullify(pTxnHandle);
    }
}

void CmdInterpreter::visit(ProxyCmdRollback &cmd)
{
    TxnHandle *pTxnHandle = getTxnHandle(cmd.getTxnHandle());

    // block checkpoints
    SXMutexSharedGuard actionMutexGuard(
        pTxnHandle->pDb->getCheckpointThread()->getActionMutex());

    if (cmd.getSvptHandle()) {
        SavepointId svptId = getSavepointId(cmd.getSvptHandle());
        pTxnHandle->pTxn->rollback(&svptId);
    } else {
        pTxnHandle->pTxn->rollback();
        deleteAndNullify(pTxnHandle);
    }
}

void CmdInterpreter::visit(ProxyCmdCreateExecutionStreamGraph &cmd)
{
    TxnHandle *pTxnHandle = getTxnHandle(cmd.getTxnHandle());
    SharedExecStreamGraph pGraph =
        ExecStreamGraph::newExecStreamGraph();
    pGraph->setTxn(pTxnHandle->pTxn);
    std::auto_ptr<StreamGraphHandle> pStreamGraphHandle(
        new StreamGraphHandle());
    ++JniUtil::handleCount;
    pStreamGraphHandle->javaRuntimeContext = NULL;
    pStreamGraphHandle->pTxnHandle = pTxnHandle;
    pStreamGraphHandle->pExecStreamGraph = pGraph;
    pStreamGraphHandle->pExecStreamFactory.reset(
        new ExecStreamFactory(
            pTxnHandle->pDb,
            pTxnHandle->pFtrsTableWriterFactory,
            pStreamGraphHandle.get()));
    setStreamGraphHandle(
        cmd.getResultHandle(),
        pStreamGraphHandle.release());
}

void CmdInterpreter::visit(ProxyCmdPrepareExecutionStreamGraph &cmd)
{
    StreamGraphHandle *pStreamGraphHandle = getStreamGraphHandle(
        cmd.getStreamGraphHandle());
    TxnHandle *pTxnHandle = pStreamGraphHandle->pTxnHandle;
    // NOTE:  sequence is important here
    SharedExecStreamScheduler pScheduler(
        new DfsTreeExecStreamScheduler(
            &(pTxnHandle->pDb->getTraceTarget()),
            "xo.scheduler"));
    ExecStreamGraphEmbryo graphEmbryo(
        pStreamGraphHandle->pExecStreamGraph,
        pScheduler,
        pTxnHandle->pDb->getCache(),
        pTxnHandle->pDb->getSegmentFactory(),
        pStreamGraphHandle->pExecStreamFactory->shouldEnforceCacheQuotas());
    pStreamGraphHandle->pExecStreamFactory->setGraphEmbryo(graphEmbryo);
    ExecStreamBuilder streamBuilder(
        graphEmbryo,
        *(pStreamGraphHandle->pExecStreamFactory));
    streamBuilder.buildStreamGraph(cmd, true);
    pStreamGraphHandle->pExecStreamFactory.reset();
    pStreamGraphHandle->pScheduler = pScheduler;
}

void CmdInterpreter::visit(ProxyCmdCreateStreamHandle &cmd)
{
    StreamGraphHandle *pStreamGraphHandle = getStreamGraphHandle(
        cmd.getStreamGraphHandle());
    SharedExecStream pStream =
        pStreamGraphHandle->pExecStreamGraph->findLastStream(
            cmd.getStreamName(), 0);
    setExecStreamHandle(
        cmd.getResultHandle(),
        pStream.get());
}

PageId CmdInterpreter::StreamGraphHandle::getRoot(PageOwnerId pageOwnerId)
{
    JniEnvAutoRef pEnv;
    jlong x = opaqueToInt(pageOwnerId);
    x = pEnv->CallLongMethod(
        javaRuntimeContext,JniUtil::methGetIndexRoot,x);
    return PageId(x);
}

void CmdInterpreter::readTupleDescriptor(
    TupleDescriptor &tupleDesc,
    ProxyTupleDescriptor &javaTupleDesc,
    StoredTypeDescriptorFactory const &typeFactory)
{
    tupleDesc.clear();
    SharedProxyTupleAttrDescriptor pAttr = javaTupleDesc.getAttrDescriptor();
    for (; pAttr; ++pAttr) {
        StoredTypeDescriptor const &typeDescriptor =
            typeFactory.newDataType(pAttr->getTypeOrdinal());
        tupleDesc.push_back(
            TupleAttributeDescriptor(
                typeDescriptor,pAttr->isNullable(),pAttr->getByteLength()));
    }
}

void CmdInterpreter::readTupleProjection(
    TupleProjection &tupleProj,
    SharedProxyTupleProjection pJavaTupleProj)
{
    tupleProj.clear();
    SharedProxyTupleAttrProjection pAttr = pJavaTupleProj->getAttrProjection();
    for (; pAttr; ++pAttr) {
        tupleProj.push_back(pAttr->getAttributeIndex());
    }
}

FENNEL_END_CPPFILE("$Id$");

// End CmdInterpreter.cpp
<|endoftext|>


<commit_before>/*
 * Advent of Code 2016
 * Day 3 (part 2)
 *
 * Command: clang++ --std=c++14 day03b.cpp
 *
 */

#include <cmath>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <boost/foreach.hpp>
#include <boost/tokenizer.hpp>

const int MAX_LINE_LENGTH = 2000;

class Triangle {
	public:
		Triangle(int, int, int);
		Triangle(std::string, std::string, std::string);
		int a;
		int b;
		int c;
		bool valid();
};

Triangle::Triangle(int a, int b, int c) {
	this->a = a;
	this->b = b;
	this->c = c;
}

Triangle::Triangle(std::string a, std::string b, std::string c) {
	this->a = atoi(a.c_str());
	this->b = atoi(b.c_str());
	this->c = atoi(c.c_str());
}

bool Triangle::valid() {
	return ((this->a + this->b > this->c) && (this->a + this->c > this->b) && (this->b + this->c > this->a));
}

void split(const std::string &s, char delim, std::vector<std::string> &elems) {
	std::stringstream ss;
	ss.str(s);
	std::string item;
	while (std::getline(ss, item, delim)) {
		elems.push_back(item);
	}
}

std::vector<std::string> split(const std::string &s, char delim) {
	std::vector<std::string> elems;
	split(s, delim, elems);
	return elems;
}

int main(void) {
	// Open the input file
	std::ifstream fin("input03.txt");
	if (!fin) {
		std::cerr << "Error reading input file input03.txt" << std::endl;
		return -1;
	}

	std::vector<Triangle> candidates;

	// Read the input
	std::vector<std::string> input;
	std::vector<std::string> partsA, partsB, partsC;
	int parts = 0;
	char cInput[MAX_LINE_LENGTH];
	while (fin.getline(cInput, MAX_LINE_LENGTH)) {
		using namespace std;
		using namespace boost;

		vector<string> bits;
		string input(cInput);
		tokenizer<> tokenizer(input);

		for (auto token : tokenizer) {
			bits.push_back(token);
		}

		partsA.push_back(bits.at(0));
		partsB.push_back(bits.at(1));
		partsC.push_back(bits.at(2));
		parts++;

		if (parts == 3) {
			Triangle t1(partsA.at(0), partsA.at(1), partsA.at(2));
			Triangle t2(partsB.at(0), partsB.at(1), partsB.at(2));
			Triangle t3(partsC.at(0), partsC.at(1), partsC.at(2));

			/*
			vector<vector<string>> theParts;
			theParts.push_back(partsA); theParts.push_back(partsB); theParts.push_back(partsC);
			for (auto v : theParts) {
				cout << "{ ";
				for (auto p : v) {
					cout << p << " ";
				}
				cout << "}" << endl;
			}
			*/

			partsA.clear();
			partsB.clear();
			partsC.clear();

			candidates.push_back(t1);
			candidates.push_back(t2);
			candidates.push_back(t3);
			parts = 0;
		}
	}
	fin.close();

	// Solve the problem
	int triangles = 0; int other = 0;
	for (auto t : candidates) {
		if (t.valid()) {
			triangles++;
		} else {
			other++;
		}
	}

	std::cout << "Triangles: " << triangles << std::endl << "Non-triangles: " << other << std::endl;

	return 0;
}

<commit_msg>Cleanup<commit_after>/*
 * Advent of Code 2016
 * Day 3 (part 2)
 *
 * Command: clang++ --std=c++14 day03b.cpp
 *
 */

#include <cmath>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <boost/foreach.hpp>
#include <boost/tokenizer.hpp>

const int MAX_LINE_LENGTH = 2000;

class Triangle {
	public:
		Triangle(int, int, int);
		Triangle(std::string, std::string, std::string);
		int a;
		int b;
		int c;
		bool valid();
};

Triangle::Triangle(int a, int b, int c) {
	this->a = a;
	this->b = b;
	this->c = c;
}

Triangle::Triangle(std::string a, std::string b, std::string c) {
	this->a = atoi(a.c_str());
	this->b = atoi(b.c_str());
	this->c = atoi(c.c_str());
}

bool Triangle::valid() {
	return ((this->a + this->b > this->c) && (this->a + this->c > this->b) && (this->b + this->c > this->a));
}

void split(const std::string &s, char delim, std::vector<std::string> &elems) {
	std::stringstream ss;
	ss.str(s);
	std::string item;
	while (std::getline(ss, item, delim)) {
		elems.push_back(item);
	}
}

std::vector<std::string> split(const std::string &s, char delim) {
	std::vector<std::string> elems;
	split(s, delim, elems);
	return elems;
}

int main(void) {
	// Open the input file
	std::ifstream fin("input03.txt");
	if (!fin) {
		std::cerr << "Error reading input file input03.txt" << std::endl;
		return -1;
	}

	std::vector<Triangle> candidates;

	// Read the input
	std::vector<std::string> input;
	std::vector<std::string> partsA, partsB, partsC;
	int parts = 0;
	char cInput[MAX_LINE_LENGTH];
	while (fin.getline(cInput, MAX_LINE_LENGTH)) {
		using namespace std;
		using namespace boost;

		vector<string> bits;
		string input(cInput);
		tokenizer<> tokenizer(input);

		for (auto token : tokenizer) {
			bits.push_back(token);
		}

		partsA.push_back(bits.at(0));
		partsB.push_back(bits.at(1));
		partsC.push_back(bits.at(2));
		parts++;

		if (parts == 3) {
			Triangle t1(partsA.at(0), partsA.at(1), partsA.at(2));
			Triangle t2(partsB.at(0), partsB.at(1), partsB.at(2));
			Triangle t3(partsC.at(0), partsC.at(1), partsC.at(2));

			partsA.clear();
			partsB.clear();
			partsC.clear();

			candidates.push_back(t1);
			candidates.push_back(t2);
			candidates.push_back(t3);
			parts = 0;
		}
	}
	fin.close();

	// Solve the problem
	int triangles = 0; int other = 0;
	for (auto t : candidates) {
		if (t.valid()) {
			triangles++;
		} else {
			other++;
		}
	}

	std::cout << "Triangles: " << triangles << std::endl << "Non-triangles: " << other << std::endl;

	return 0;
}

<|endoftext|>


<commit_before>// ========================================================================== //
// This file is part of Sara, a basic set of libraries in C++ for computer
// vision.
//
// Copyright (C) 2018 David Ok <david.ok8@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================== //

#include <DO/Sara/Core/MultiArray/InfiniteMultiArrayView.hpp>
#include <DO/Sara/Core/Timer.hpp>
#include <DO/Sara/Graphics.hpp>
#include <DO/Sara/ImageIO.hpp>

using namespace std;
using namespace DO::Sara;

GRAPHICS_MAIN()
{
  auto image = Image<float>{};
  imread(image, "/home/david/GitHub/DO-CV/sara/data/sunflowerField.jpg");

  auto kernel = Image<float>{10, 10};
  kernel.matrix() = MatrixXf::Ones(10, 10) / 100.f;

  create_window(image.sizes());
  display(image);
  get_key();
  close_window();

  return EXIT_SUCCESS;
}
<commit_msg>MAINT: sketch API.<commit_after>// ========================================================================== //
// This file is part of Sara, a basic set of libraries in C++ for computer
// vision.
//
// Copyright (C) 2018 David Ok <david.ok8@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================== //

#include <DO/Sara/Core/MultiArray/InfiniteMultiArrayView.hpp>
#include <DO/Sara/Core/Timer.hpp>
#include <DO/Sara/Graphics.hpp>
#include <DO/Sara/ImageIO.hpp>

#include <DO/Sara/Core/Tensor.hpp>
#include <DO/Sara/ImageProcessing/GemmBasedConvolution.hpp>

using namespace std;
using namespace DO::Sara;

GRAPHICS_MAIN()
{
  auto image = Image<float>{};
  imread(image, "/home/david/GitHub/DO-CV/sara/data/sunflowerField.jpg");

  auto kernel = Image<float>{10, 10};
  kernel.matrix() = MatrixXf::Ones(10, 10) / 100.f;

  auto y = Image<float>{image.sizes()};
  gemm_convolve(tensor_view(y), tensor_view(image), tensor_view(kernel));

  create_window(image.sizes());
  display(image);
  get_key();
  close_window();

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//    * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//    * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "net/disk_cache/disk_cache_test_util.h"

#include "base/file_util.h"
#include "base/path_service.h"
#include "base/scoped_handle.h"
#include "net/disk_cache/backend_impl.h"

std::string GenerateKey(bool same_length) {
  char key[200];
  CacheTestFillBuffer(key, sizeof(key), same_length);

  key[199] = '\0';
  return std::string(key);
}

void CacheTestFillBuffer(char* buffer, size_t len, bool no_nulls) {
  static bool called = false;
  if (!called) {
    called = true;
    int seed = static_cast<int>(Time::Now().ToInternalValue());
    srand(seed);
  }

  for (size_t i = 0; i < len; i++) {
    buffer[i] = static_cast<char>(rand());
    if (!buffer[i] && no_nulls)
      buffer[i] = 'g';
  }
  if (len && !buffer[0])
    buffer[0] = 'g';
}

std::wstring GetCachePath() {
  std::wstring path;
  PathService::Get(base::DIR_TEMP, &path);
  file_util::AppendToPath(&path, L"cache_test");
  if (!file_util::PathExists(path))
    file_util::CreateDirectory(path);

  return path;
}

bool CreateCacheTestFile(const wchar_t* name) {
  ScopedHandle file(CreateFile(name, GENERIC_READ | GENERIC_WRITE,
                                FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                                CREATE_ALWAYS, 0, NULL));
  if (!file.IsValid())
    return false;

  SetFilePointer(file, 4 * 1024 * 1024, 0, FILE_BEGIN);
  SetEndOfFile(file);
  return true;
}

bool DeleteCache(const wchar_t* path) {
  std::wstring my_path(path);
  file_util::AppendToPath(&my_path, L"*.*");
  return file_util::Delete(my_path, false);
}

bool CheckCacheIntegrity(const std::wstring& path) {
  scoped_ptr<disk_cache::BackendImpl> cache(new disk_cache::BackendImpl(path));
  if (!cache.get())
    return false;
  if (!cache->Init())
    return false;
  return cache->SelfCheck() >= 0;
}

// -----------------------------------------------------------------------

int g_cache_tests_max_id = 0;
volatile int g_cache_tests_received = 0;
volatile bool g_cache_tests_error = 0;

// On the actual callback, increase the number of tests received and check for
// errors (an unexpected test received)
void CallbackTest::RunWithParams(const Tuple1<int>& params) {
  if (id_ > g_cache_tests_max_id) {
    NOTREACHED();
    g_cache_tests_error = true;
  } else if (reuse_) {
    DCHECK(1 == reuse_);
    if (2 == reuse_)
      g_cache_tests_error = true;
    reuse_++;
  }

  g_cache_tests_received++;
}

// -----------------------------------------------------------------------

// Quits the message loop when all callbacks are called or we've been waiting
// too long for them (2 secs without a callback).
void TimerTask::Run() {
  if (g_cache_tests_received > num_callbacks_) {
    NOTREACHED();
  } else if (g_cache_tests_received == num_callbacks_) {
    completed_ = true;
    MessageLoop::current()->Quit();
  } else {
    // Not finished yet. See if we have to abort.
    if (last_ == g_cache_tests_received)
      num_iterations_++;
    else
      last_ = g_cache_tests_received;
    if (40 == num_iterations_)
      MessageLoop::current()->Quit();
  }
}

// -----------------------------------------------------------------------

MessageLoopHelper::MessageLoopHelper() {
  message_loop_ = MessageLoop::current();
  // Create a recurrent timer of 50 mS.
  timer_ = message_loop_->timer_manager()->StartTimer(50, &timer_task_, true);
}

MessageLoopHelper::~MessageLoopHelper() {
  message_loop_->timer_manager()->StopTimer(timer_);
  delete timer_;
}

bool MessageLoopHelper::WaitUntilCacheIoFinished(int num_callbacks) {
  if (num_callbacks == g_cache_tests_received)
    return true;

  timer_task_.ExpectCallbacks(num_callbacks);
  message_loop_->Run();
  return timer_task_.GetSate();
}

<commit_msg>Make the disk cache unit tests use some common code from the disk cache.<commit_after>// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//    * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//    * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "net/disk_cache/disk_cache_test_util.h"

#include "base/file_util.h"
#include "base/path_service.h"
#include "net/disk_cache/backend_impl.h"
#include "net/disk_cache/cache_util.h"
#include "net/disk_cache/file.h"

std::string GenerateKey(bool same_length) {
  char key[200];
  CacheTestFillBuffer(key, sizeof(key), same_length);

  key[199] = '\0';
  return std::string(key);
}

void CacheTestFillBuffer(char* buffer, size_t len, bool no_nulls) {
  static bool called = false;
  if (!called) {
    called = true;
    int seed = static_cast<int>(Time::Now().ToInternalValue());
    srand(seed);
  }

  for (size_t i = 0; i < len; i++) {
    buffer[i] = static_cast<char>(rand());
    if (!buffer[i] && no_nulls)
      buffer[i] = 'g';
  }
  if (len && !buffer[0])
    buffer[0] = 'g';
}

std::wstring GetCachePath() {
  std::wstring path;
  PathService::Get(base::DIR_TEMP, &path);
  file_util::AppendToPath(&path, L"cache_test");
  if (!file_util::PathExists(path))
    file_util::CreateDirectory(path);

  return path;
}

bool CreateCacheTestFile(const wchar_t* name) {
  using namespace disk_cache;
  int flags = OS_FILE_CREATE_ALWAYS | OS_FILE_READ | OS_FILE_WRITE |
              OS_FILE_SHARE_READ | OS_FILE_SHARE_WRITE;

  scoped_refptr<File> file(new File(CreateOSFile(name, flags, NULL)));
  if (!file->IsValid())
    return false;

  file->SetLength(4 * 1024 * 1024);
  return true;
}

bool DeleteCache(const wchar_t* path) {
  disk_cache::DeleteCache(path, false);
  return true;
}

bool CheckCacheIntegrity(const std::wstring& path) {
  scoped_ptr<disk_cache::BackendImpl> cache(new disk_cache::BackendImpl(path));
  if (!cache.get())
    return false;
  if (!cache->Init())
    return false;
  return cache->SelfCheck() >= 0;
}

// -----------------------------------------------------------------------

int g_cache_tests_max_id = 0;
volatile int g_cache_tests_received = 0;
volatile bool g_cache_tests_error = 0;

// On the actual callback, increase the number of tests received and check for
// errors (an unexpected test received)
void CallbackTest::RunWithParams(const Tuple1<int>& params) {
  if (id_ > g_cache_tests_max_id) {
    NOTREACHED();
    g_cache_tests_error = true;
  } else if (reuse_) {
    DCHECK(1 == reuse_);
    if (2 == reuse_)
      g_cache_tests_error = true;
    reuse_++;
  }

  g_cache_tests_received++;
}

// -----------------------------------------------------------------------

// Quits the message loop when all callbacks are called or we've been waiting
// too long for them (2 secs without a callback).
void TimerTask::Run() {
  if (g_cache_tests_received > num_callbacks_) {
    NOTREACHED();
  } else if (g_cache_tests_received == num_callbacks_) {
    completed_ = true;
    MessageLoop::current()->Quit();
  } else {
    // Not finished yet. See if we have to abort.
    if (last_ == g_cache_tests_received)
      num_iterations_++;
    else
      last_ = g_cache_tests_received;
    if (40 == num_iterations_)
      MessageLoop::current()->Quit();
  }
}

// -----------------------------------------------------------------------

MessageLoopHelper::MessageLoopHelper() {
  message_loop_ = MessageLoop::current();
  // Create a recurrent timer of 50 mS.
  timer_ = message_loop_->timer_manager()->StartTimer(50, &timer_task_, true);
}

MessageLoopHelper::~MessageLoopHelper() {
  message_loop_->timer_manager()->StopTimer(timer_);
  delete timer_;
}

bool MessageLoopHelper::WaitUntilCacheIoFinished(int num_callbacks) {
  if (num_callbacks == g_cache_tests_received)
    return true;

  timer_task_.ExpectCallbacks(num_callbacks);
  message_loop_->Run();
  return timer_task_.GetSate();
}

<|endoftext|>


<commit_before><commit_msg>reload_config does log levels now too.<commit_after><|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// Reaper
///
/// Copyright (c) 2015-2019 Thibault Schueller
/// This file is distributed under the MIT License
////////////////////////////////////////////////////////////////////////////////

#include "RenderDoc.h"

#if defined(REAPER_USE_RENDERDOC)

#    include "common/DebugLog.h"
#    include "common/ReaperRoot.h"

#    include "core/DynamicLibrary.h"
#    include "core/Profile.h"

#    if defined(REAPER_PLATFORM_LINUX) || defined(REAPER_PLATFORM_MACOSX)
#        include <renderdoc.h>
#    elif defined(REAPER_PLATFORM_WINDOWS)
#        include <renderdoc_app.h>
#    endif

namespace Reaper::RenderDoc
{
namespace
{
    constexpr RENDERDOC_Version RenderDocVersion = eRENDERDOC_API_Version_1_4_0;
    using RenderDocAPI = RENDERDOC_API_1_4_0;

    LibHandle     g_renderDocLib = nullptr;
    RenderDocAPI* g_renderDocAPI = nullptr;
} // namespace

void start_integration(ReaperRoot& root)
{
    REAPER_PROFILE_SCOPE("RenderDoc", MP_GREEN1);

    log_info(root, "renderdoc: starting integration");

    Assert(g_renderDocLib == nullptr);

    log_info(root, "renderdoc: loading {}", REAPER_RENDERDOC_LIB_NAME);
    // FIXME Documentation recommends RTLD_NOW | RTLD_NOLOAD on linux
    g_renderDocLib = dynlib::load(REAPER_RENDERDOC_LIB_NAME);

    pRENDERDOC_GetAPI pfn_RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)dynlib::getSymbol(g_renderDocLib, "RENDERDOC_GetAPI");

    Assert(pfn_RENDERDOC_GetAPI(RenderDocVersion, (void**)&g_renderDocAPI) == 1);

    int major, minor, patch;
    g_renderDocAPI->GetAPIVersion(&major, &minor, &patch);
    log_info(root, "renderdoc: API version {}.{}.{}", major, minor, patch);

    Assert(g_renderDocAPI->SetCaptureOptionU32(eRENDERDOC_Option_DebugOutputMute, 0) == 1);
    log_info(root, "renderdoc: disable debug output muting");
}

void stop_integration(ReaperRoot& root)
{
    REAPER_PROFILE_SCOPE("RenderDoc", MP_GREEN1);

    log_info(root, "renderdoc: stopping integration");

    Assert(g_renderDocLib != nullptr);

    // We are not supposed to unload RenderDoc lib manually ever.
    // See also: https://github.com/bkaradzic/bgfx/issues/1192
    // log_info(root, "renderdoc: unloading {}", REAPER_RENDERDOC_LIB_NAME);
    // dynlib::close(g_renderDocLib);
    // g_renderDocLib = nullptr;
}
} // namespace Reaper::RenderDoc

#else

namespace Reaper::RenderDoc
{
void start_integration(ReaperRoot& /*root*/)
{
    AssertUnreachable();
}

void stop_integration(ReaperRoot& /*root*/)
{
    AssertUnreachable();
}
} // namespace Reaper::RenderDoc

#endif
<commit_msg>renderdoc: let renderdoc mute validation ouput.<commit_after>////////////////////////////////////////////////////////////////////////////////
/// Reaper
///
/// Copyright (c) 2015-2019 Thibault Schueller
/// This file is distributed under the MIT License
////////////////////////////////////////////////////////////////////////////////

#include "RenderDoc.h"

#if defined(REAPER_USE_RENDERDOC)

#    include "common/DebugLog.h"
#    include "common/ReaperRoot.h"

#    include "core/DynamicLibrary.h"
#    include "core/Profile.h"

#    if defined(REAPER_PLATFORM_LINUX) || defined(REAPER_PLATFORM_MACOSX)
#        include <renderdoc.h>
#    elif defined(REAPER_PLATFORM_WINDOWS)
#        include <renderdoc_app.h>
#    endif

namespace Reaper::RenderDoc
{
namespace
{
    constexpr RENDERDOC_Version RenderDocVersion = eRENDERDOC_API_Version_1_4_0;
    using RenderDocAPI = RENDERDOC_API_1_4_0;

    LibHandle     g_renderDocLib = nullptr;
    RenderDocAPI* g_renderDocAPI = nullptr;
} // namespace

void start_integration(ReaperRoot& root)
{
    REAPER_PROFILE_SCOPE("RenderDoc", MP_GREEN1);

    log_info(root, "renderdoc: starting integration");

    Assert(g_renderDocLib == nullptr);

    log_info(root, "renderdoc: loading {}", REAPER_RENDERDOC_LIB_NAME);
    // FIXME Documentation recommends RTLD_NOW | RTLD_NOLOAD on linux
    g_renderDocLib = dynlib::load(REAPER_RENDERDOC_LIB_NAME);

    pRENDERDOC_GetAPI pfn_RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)dynlib::getSymbol(g_renderDocLib, "RENDERDOC_GetAPI");

    Assert(pfn_RENDERDOC_GetAPI(RenderDocVersion, (void**)&g_renderDocAPI) == 1);

    int major, minor, patch;
    g_renderDocAPI->GetAPIVersion(&major, &minor, &patch);
    log_info(root, "renderdoc: API version {}.{}.{}", major, minor, patch);
}

void stop_integration(ReaperRoot& root)
{
    REAPER_PROFILE_SCOPE("RenderDoc", MP_GREEN1);

    log_info(root, "renderdoc: stopping integration");

    Assert(g_renderDocLib != nullptr);

    // We are not supposed to unload RenderDoc lib manually ever.
    // See also: https://github.com/bkaradzic/bgfx/issues/1192
    // log_info(root, "renderdoc: unloading {}", REAPER_RENDERDOC_LIB_NAME);
    // dynlib::close(g_renderDocLib);
    // g_renderDocLib = nullptr;
}
} // namespace Reaper::RenderDoc

#else

namespace Reaper::RenderDoc
{
void start_integration(ReaperRoot& /*root*/)
{
    AssertUnreachable();
}

void stop_integration(ReaperRoot& /*root*/)
{
    AssertUnreachable();
}
} // namespace Reaper::RenderDoc

#endif
<|endoftext|>


<commit_before>#include "MainVisitor.hpp"

#include <iostream>
#include <chrono>
#include "Event.hpp"
#include "typedefs.hpp"

#include "MainModule.hpp"

#include "events/Terminate.hpp"
#include "events/CmdResponseReceived.hpp"
#include "events/WebClientRequestReceived.hpp"
#include "../../utils/Machine.hpp"

#include "../../network/websocket/typedefs.hpp"
#include "../../network/websocket/events/MessageSendRequest.hpp"
#include "../../network/websocket/events/MessageSendRequest.hpp"
#include "../../network/websocket/events/MessageBroadcastRequest.hpp"

namespace events = tin::controllers::main::events;
namespace main = tin::controllers::main;
using nlohmann::json;

tin::controllers::main::MainVisitor::MainVisitor(tin::controllers::main::MainModule& controller):
controller(controller)
{}

void tin::controllers::main::MainVisitor::visit(events::Terminate &evt)
{
    this->controller.terminate();
}

void tin::controllers::main::MainVisitor::visit(events::CmdResponseReceived &evt)
{
    std::cout << "[Supervisor] [MainCtrl] Received response: " << evt.jsonPtr->dump() << std::endl;
    std::cout << "                        Source: " << evt.ip << ":" << evt.port << std::endl;

    auto it = std::make_pair(evt.ip, evt.port);
    std::map<std::pair<std::string, unsigned int>, int>::iterator ipPortIdMapIt;
    std::map<int, utils::Machine>::iterator idMachineMapIt;
    ipPortIdMapIt = controller.ipPortIdMap.find(it);
    idMachineMapIt = controller.idMachineMap.find(ipPortIdMapIt->second);
    utils::Machine& m = idMachineMapIt->second;

    json& temp = *(evt.jsonPtr);

    if (temp.find("error") != temp.end() && temp["error"].is_string())
    {
        if(temp.find("notConnected") != temp.end())
        {
            bool error = temp["error"]["notConnected"];
            if(error == true)
    	       m.status = "offline";
        }
        std::cout << "[Supervisor][MainCtrl] Error received" << std::endl;
        return;
    }

    if(temp.find("cmd") != temp.end() && temp["cmd"].is_string())
    {
        const std::string cmd = temp["cmd"];

        if (cmd == "sync")
        {
            auto ms = std::chrono::duration_cast<std::chrono::seconds>(
                        std::chrono::system_clock::now().time_since_epoch());
            m.lastSynchronization = ms.count();
        }

        else if (cmd == "ping")
        {
            if(temp.find("response") != temp.end())
            {
                const std::string response = temp["error"]["response"];
                if(response == "sniffing")
                    m.status.assign("sniffing");
                if(response == "stand-by")
                    m.status.assign("stand-by");
            }

        }

        else if (cmd == "change_filter")
        {
        	const std::string expr = temp["expression"];
        	m.filter = expr;
        	m.status = "sniffing";
        }
    }

}

void tin::controllers::main::MainVisitor::visit(events::WebClientRequestReceived &evt)
{
    std::cout << "[Supervisor] WebClient Request Received, processing" << std::endl;

    json& temp = *(evt.jsonPtr);

    if(temp.find("route") == temp.end() || temp.find("type") == temp.end() ||
        !temp["route"].is_string() || !temp["type"].is_string())
        {
            std::cout << "[Supervisor] Bad WebClient request" << std::endl;
            return;
        }

    std::string route = temp["route"];
    std::string type = temp["type"];

    if (route == "machines" && type == "GET")
    {
        json jsonObj;
        jsonObj["data"] = {
                { "machines", {} }
            };

            for(auto& it: this->controller.idMachineMap)
            {
                jsonObj["data"]["machines"][jsonObj["data"]["machines"].size()] = {
                    { "id", it.second.id},
                    { "name", it.second.name },
                    { "ip", it.second.ip },
                    { "port", it.second.port },
                    { "status", it.second.status },
                    { "lastSync", it.second.lastSynchronization }
                    };
            }
    }

    else if(route == "machines" && type == "POST")
    {
        if(temp.find("data") == temp.end())
        {
            std::cout << "[Supervisor] No data in POST" << std::endl;
            return;
        }

        const std::string ip = temp["data"]["ip"];
        const std::string name = temp["data"]["name"];
        unsigned port = temp["data"]["port"];

        utils::Machine m = utils::Machine(ip, name, port);

        this->controller.ipPortIdMap.insert(
            std::pair<std::pair<std::string, unsigned int>, int>
             (std::make_pair(ip, port), m.id));
        this->controller.idMachineMap.insert(std::pair<int, utils::Machine>(m.id, m));

    }

}<commit_msg>handling webclient request event<commit_after>#include "MainVisitor.hpp"

#include <iostream>
#include <chrono>
#include "Event.hpp"
#include "typedefs.hpp"

#include "MainModule.hpp"

#include "events/Terminate.hpp"
#include "events/CmdResponseReceived.hpp"
#include "events/WebClientRequestReceived.hpp"
#include "../../utils/Machine.hpp"

#include "../../network/websocket/typedefs.hpp"
#include "../../network/websocket/events/MessageSendRequest.hpp"
#include "../../network/websocket/events/MessageSendRequest.hpp"
#include "../../network/websocket/events/MessageBroadcastRequest.hpp"

namespace events = tin::controllers::main::events;
namespace main = tin::controllers::main;
using nlohmann::json;

tin::controllers::main::MainVisitor::MainVisitor(tin::controllers::main::MainModule& controller):
controller(controller)
{}

void tin::controllers::main::MainVisitor::visit(events::Terminate &evt)
{
    this->controller.terminate();
}

void tin::controllers::main::MainVisitor::visit(events::CmdResponseReceived &evt)
{
    std::cout << "[Supervisor] [MainCtrl] Received response: " << evt.jsonPtr->dump() << std::endl;
    std::cout << "                        Source: " << evt.ip << ":" << evt.port << std::endl;

    auto it = std::make_pair(evt.ip, evt.port);
    std::map<std::pair<std::string, unsigned int>, int>::iterator ipPortIdMapIt;
    std::map<int, utils::Machine>::iterator idMachineMapIt;
    ipPortIdMapIt = controller.ipPortIdMap.find(it);
    idMachineMapIt = controller.idMachineMap.find(ipPortIdMapIt->second);
    utils::Machine& m = idMachineMapIt->second;

    json& temp = *(evt.jsonPtr);

    if (temp.find("error") != temp.end() && temp["error"].is_string())
    {
        if(temp.find("notConnected") != temp.end())
        {
            bool error = temp["error"]["notConnected"];
            if(error == true)
    	       m.status = "offline";
        }
        std::cout << "[Supervisor][MainCtrl] Error received" << std::endl;
        return;
    }

    if(temp.find("cmd") != temp.end() && temp["cmd"].is_string())
    {
        const std::string cmd = temp["cmd"];

        if (cmd == "sync")
        {
            auto ms = std::chrono::duration_cast<std::chrono::seconds>(
                        std::chrono::system_clock::now().time_since_epoch());
            m.lastSynchronization = ms.count();
        }

        else if (cmd == "ping")
        {
            if(temp.find("response") != temp.end())
            {
                const std::string response = temp["error"]["response"];
                if(response == "sniffing")
                    m.status.assign("sniffing");
                if(response == "stand-by")
                    m.status.assign("stand-by");
            }

        }

        else if (cmd == "change_filter")
        {
        	const std::string expr = temp["expression"];
        	m.filter = expr;
        	m.status = "sniffing";
        }
    }

}

void tin::controllers::main::MainVisitor::visit(events::WebClientRequestReceived &evt)
{
    std::cout << "[Supervisor] WebClient Request Received, processing" << std::endl;

    json& temp = *(evt.jsonPtr);

    if(temp.find("route") == temp.end() || temp.find("type") == temp.end() ||
        !temp["route"].is_string() || !temp["type"].is_string())
        {
            std::cout << "[Supervisor] Bad WebClient request" << std::endl;
            return;
        }

    std::string route = temp["route"];
    std::string type = temp["type"];

    if (route == "machines" && type == "GET")
    {
        json jsonObj;
        jsonObj["data"] = {
                { "machines", {} }
            };

            for(auto& it: this->controller.idMachineMap)
            {
                jsonObj["data"]["machines"][jsonObj["data"]["machines"].size()] = {
                    { "id", it.second.id},
                    { "name", it.second.name },
                    { "ip", it.second.ip },
                    { "port", it.second.port },
                    { "status", it.second.status },
                    { "lastSync", it.second.lastSynchronization }
                    };
            }
    }

    if(route == "machines" && type == "POST")
    {
        if(temp.find("data") == temp.end())
        {
            std::cout << "[Supervisor] No data in POST" << std::endl;
            return;
        }

        const std::string ip = temp["data"]["ip"];
        const std::string name = temp["data"]["name"];
        unsigned port = temp["data"]["port"];

        utils::Machine m = utils::Machine(ip, name, port);

        this->controller.ipPortIdMap.insert(
            std::pair<std::pair<std::string, unsigned int>, int>
             (std::make_pair(ip, port), m.id));
        this->controller.idMachineMap.insert(std::pair<int, utils::Machine>(m.id, m));

    }

    if (route.substr(0, 8) == "machine/")
        {
            auto routeRest = route.substr(8);
            auto action = std::string("");
            if (routeRest.find("/") != std::string::npos)
            {
                action = routeRest.substr(routeRest.find("/") + 1);
                routeRest = routeRest.substr(0, routeRest.find("/"));
            }

            try
            {
               int machineID = static_cast<int>(std::stoul(routeRest));

               utils::Machine& machine = this->controller.idMachineMap.at(machineID);

                if (action == "" && type == "GET")
                {
                    temp["data"] = {
                        { "id", machineID },
                        { "name", machine.name },
                        { "ip", machine.ip },
                        { "port", machine.port },
                        { "status", machine.status },
                        { "lastSync", machine.lastSynchronization }};

                }
                else if (action == "" && type == "PATCH")
                {

                    std::string name = temp["data"]["name"];
                    std::string ip = temp["data"]["ip"];
                    unsigned int port = temp["data"]["port"];

                    machine.name = name;
                    machine.ip = ip;
                    machine.port = port;

                    temp["data"] = {{ "success", true }};
                }
                else if (action == "" && type == "DELETE")
                {

                    temp["data"] = {{ "success", true }};
                }
                else if (action == "sync" && type == "POST")
                {
                    auto ms = std::chrono::duration_cast<std::chrono::seconds>(
                        std::chrono::system_clock::now().time_since_epoch()
                    );

                    machine.lastSynchronization = ms.count();

                    temp["data"] = {{ "success", true }};
                }
                else if (action == "toggle-sniffer" && type == "POST")
                {

                    if (machine.status == "sniffing")
                    {
                        machine.status = "stand-by";
                        temp["data"] = {{ "success", true }};
                    }
                    else if (machine.status == "stand-by")
                    {
                        machine.status = "sniffing";
                        temp["data"] = {{ "success", true }};
                    }
                    else
                    {
                        temp["error"] = {{ "invalid", { {"status", machine.status} } }};
                    }
                }
                else
                {
                    temp["error"] = {{ "invalid", { {"action", action} } }};
                }
            }
            catch (std::invalid_argument& e)
            {
                temp["error"] = {{ "invalid", { {"routeID", true} } }};
            }
        }

}<|endoftext|>


<commit_before>/*
 * This file is part of qasmtools.
 *
 * Copyright (c) 2019 - 2021 softwareQ Inc. All rights reserved.
 *
 * MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Adapted from Bruno Schmitt's Tweedledee library
 */

/**
 * \file qasmtools/parser/lexer.hpp
 * \brief Lexical analysis
 */

#pragma once

#include "token.hpp"

#include <cctype>
#include <memory>

namespace qasmtools {
namespace parser {

/**
 * \class qasmtools::parser::Lexer
 * \brief openPARSER lexer class
 *
 * The Lexer reads from (a shared_ptr to) an istream object given during
 * initialization. Rather than lex the entire buffer at once, tokens are
 * lexed and returned on-demand
 */
class Lexer {
  public:
    Lexer(const Lexer&) = delete;
    Lexer& operator=(const Lexer&) = delete;

    Lexer(std::shared_ptr<std::istream> buffer, const std::string& fname = "")
        : pos_(fname, 1, 1), buf_(buffer) {}

    /**
     * \brief Lex and return the next token
     *
     * \note Advances the buffer to the position after the consumed token
     *
     * \return The token that was lexed
     */
    Token next_token() { return lex(); }

  private:
    Position pos_; ///< current position in the source stream
    std::shared_ptr<std::istream> buf_; ///< stream buffer being lexed

    /**
     * \brief Skips the specified number of characters
     *
     * \param n The number of characters to skip ahead (optional, default is 1)
     */
    void skip_char(int n = 1) {
        buf_->ignore(n);
        pos_.advance_column(n);
    }

    /**
     * \brief Skips over whitespace
     *
     * \return True if and only if whitespace was actually consumed
     */
    bool skip_whitespace() {
        int consumed = 0;

        while (buf_->peek() == ' ' || buf_->peek() == '\t') {
            buf_->ignore();
            ++consumed;
        }

        pos_.advance_column(consumed);
        if (consumed != 0)
            return true;
        else
            return false;
    }

    /**
     * \brief Skips the rest of the line
     */
    void skip_line_comment() {
        int consumed = 0;

        char c = buf_->peek();
        while (c != 0 && c != '\n' && c != '\r' && c != EOF) {
            buf_->ignore();
            ++consumed;
            c = buf_->peek();
        }

        pos_.advance_column(consumed);
    }

    /**
     * \brief Lex a numeric constant
     *
     * \note [0-9]+(.[0-9]*)([eE][+-][0-9]+)?
     *
     * \param tok_start The position of the beginning of the token
     * \return An integer or real type token
     */
    Token lex_numeric_constant(Position tok_start) {
        std::string str;
        str.reserve(64); // Reserve space to avoid reallocation
        bool integral = true;

        while (std::isdigit(buf_->peek())) {
            str.push_back(buf_->peek());
            skip_char();
        }

        // lex decimal
        if (buf_->peek() == '.') {
            integral = false;
            str.push_back(buf_->peek());
            skip_char();

            while (std::isdigit(buf_->peek())) {
                str.push_back(buf_->peek());
                skip_char();
            }
        }

        // lex exponent
        if (buf_->peek() == 'e' || buf_->peek() == 'E') {
            integral = false;
            str.push_back(buf_->peek());
            skip_char();

            if (buf_->peek() == '-' || buf_->peek() == '+') {
                str.push_back(buf_->peek());
                skip_char();
            }

            while (std::isdigit(buf_->peek())) {
                str.push_back(buf_->peek());
                skip_char();
            }
        }

        if (integral) {
            return Token(tok_start, Token::Kind::nninteger, str,
                         std::stoi(str));
        } else {
            return Token(tok_start, Token::Kind::real, str, std::stof(str));
        }
    }

    /**
     * \brief Lex an identifier
     *
     * \note [A-Za-z][_A-Za-z0-9]*
     *
     * \param tok_start The position of the beginning of the token
     * \return An identifier type token
     */
    Token lex_identifier(Position tok_start) {
        std::string str;
        str.reserve(64); // Reserve space to avoid reallocation

        while (std::isalpha(buf_->peek()) || std::isdigit(buf_->peek()) ||
               buf_->peek() == '_') {
            str.push_back(buf_->peek());
            skip_char();
        }

        // Check if the identifier is a known keyword
        auto keyword = keywords.find(str);
        if (keyword != keywords.end()) {
            return Token(tok_start, keyword->second, str);
        }

        return Token(tok_start, Token::Kind::identifier, str, str);
    }

    /**
     * \brief Lex a string literal
     *
     * \note "[.]*"
     *
     * \param tok_start The position of the beginning of the token
     * \return A string type token
     */
    Token lex_string(Position tok_start) {
        std::string str;
        str.reserve(64); // Reserve space to avoid reallocation

        while (buf_->peek() != '"' && buf_->peek() != '\n' &&
               buf_->peek() != '\r') {
            str.push_back(buf_->peek());
            skip_char();
        }

        if (buf_->peek() != '"') {
            std::cerr << "Lexical error at " << tok_start << ": unmatched \"\n";
            return Token(tok_start, Token::Kind::error, str);
        }

        skip_char();
        return Token(tok_start, Token::Kind::string, str, str);
    }

    /**
     * \brief Lex a token
     *
     * \note See arXiv:1707.03429 for the full grammar
     *
     * \return The lexed token
     */
    Token lex() {
        Position tok_start = pos_;
        skip_whitespace();

        switch (buf_->peek()) {
            case EOF:
                skip_char();
                return Token(tok_start, Token::Kind::eof, "");

            case '\r':
                skip_char();
                if (buf_->peek() != '\n') {
                    buf_->ignore();
                    pos_.advance_line();
                    return lex();
                }
                // FALLTHROUGH
            case '\n':
                buf_->ignore();
                pos_.advance_line();
                return lex();

            case '/':
                skip_char();
                if (buf_->peek() == '/') {
                    skip_line_comment();
                    return lex();
                }
                return Token(tok_start, Token::Kind::slash, "/");

                // clang-format off
            case '0': case '1': case '2': case '3': case '4':
            case '5': case '6': case '7': case '8': case '9':
            case '.':
                return lex_numeric_constant(tok_start);
                // clang-format on

            case 'C':
                skip_char();
                if (buf_->peek() == 'X') {
                    skip_char();
                    return Token(tok_start, Token::Kind::kw_cx, "CX");
                }

                skip_char();
                std::cerr
                    << "Lexical error at " << tok_start
                    << ": identifiers must start with lowercase letters\n";
                return Token(tok_start, Token::Kind::error,
                             std::string({'C', (char) buf_->get()}));

            case 'U':
                skip_char();
                return Token(tok_start, Token::Kind::kw_u, "U");

                // clang-format off
            case 'O':
            case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
            case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
            case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
            case 'v': case 'w': case 'x': case 'y': case 'z':
                return lex_identifier(tok_start);
                // clang-format on

            case '[':
                skip_char();
                return Token(tok_start, Token::Kind::l_square, "[");

            case ']':
                skip_char();
                return Token(tok_start, Token::Kind::r_square, "]");

            case '(':
                skip_char();
                return Token(tok_start, Token::Kind::l_paren, "(");

            case ')':
                skip_char();
                return Token(tok_start, Token::Kind::r_paren, ")");

            case '{':
                skip_char();
                return Token(tok_start, Token::Kind::l_brace, "{");

            case '}':
                skip_char();
                return Token(tok_start, Token::Kind::r_brace, "}");

            case '*':
                skip_char();
                return Token(tok_start, Token::Kind::star, "*");

            case '+':
                skip_char();
                return Token(tok_start, Token::Kind::plus, "+");

            case '-':
                skip_char();

                if (buf_->peek() == '>') {
                    skip_char();
                    return Token(tok_start, Token::Kind::arrow, "->");
                }

                return Token(tok_start, Token::Kind::minus, "-");

            case '^':
                skip_char();
                return Token(tok_start, Token::Kind::caret, "^");

            case ';':
                skip_char();
                return Token(tok_start, Token::Kind::semicolon, ";");

            case '=':
                skip_char();
                if (buf_->peek() == '=') {
                    skip_char();
                    return Token(tok_start, Token::Kind::equalequal, "==");
                }

                skip_char();
                std::cerr << "Lexical error at " << tok_start
                          << ": expected \"=\" after \"=\"\n";
                return Token(tok_start, Token::Kind::error,
                             std::string({'=', (char) buf_->get()}));

            case ',':
                skip_char();
                return Token(tok_start, Token::Kind::comma, ";");

            case '"':
                skip_char();
                return lex_string(tok_start);

            default:
                skip_char();
                return Token(tok_start, Token::Kind::error,
                             std::string({(char) buf_->get()}));
        }
    }
};

} // namespace parser
} // namespace qasmtools
<commit_msg>Fixed bug in lexer.hpp<commit_after>/*
 * This file is part of qasmtools.
 *
 * Copyright (c) 2019 - 2021 softwareQ Inc. All rights reserved.
 *
 * MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Adapted from Bruno Schmitt's Tweedledee library
 */

/**
 * \file qasmtools/parser/lexer.hpp
 * \brief Lexical analysis
 */

#pragma once

#include "token.hpp"

#include <cctype>
#include <memory>

namespace qasmtools {
namespace parser {

/**
 * \class qasmtools::parser::Lexer
 * \brief openPARSER lexer class
 *
 * The Lexer reads from (a shared_ptr to) an istream object given during
 * initialization. Rather than lex the entire buffer at once, tokens are
 * lexed and returned on-demand
 */
class Lexer {
  public:
    Lexer(const Lexer&) = delete;
    Lexer& operator=(const Lexer&) = delete;

    Lexer(std::shared_ptr<std::istream> buffer, const std::string& fname = "")
        : pos_(fname, 1, 1), buf_(buffer) {}

    /**
     * \brief Lex and return the next token
     *
     * \note Advances the buffer to the position after the consumed token
     *
     * \return The token that was lexed
     */
    Token next_token() { return lex(); }

  private:
    Position pos_; ///< current position in the source stream
    std::shared_ptr<std::istream> buf_; ///< stream buffer being lexed

    /**
     * \brief Skips the specified number of characters
     *
     * \param n The number of characters to skip ahead (optional, default is 1)
     */
    void skip_char(int n = 1) {
        buf_->ignore(n);
        pos_.advance_column(n);
    }

    /**
     * \brief Skips over whitespace
     *
     * \return True if and only if whitespace was actually consumed
     */
    bool skip_whitespace() {
        int consumed = 0;

        while (buf_->peek() == ' ' || buf_->peek() == '\t') {
            buf_->ignore();
            ++consumed;
        }

        pos_.advance_column(consumed);
        if (consumed != 0)
            return true;
        else
            return false;
    }

    /**
     * \brief Skips the rest of the line
     */
    void skip_line_comment() {
        int consumed = 0;

        int c = buf_->peek();
        while (c != 0 && c != '\n' && c != '\r' && c != EOF) {
            buf_->ignore();
            ++consumed;
            c = buf_->peek();
        }

        pos_.advance_column(consumed);
    }

    /**
     * \brief Lex a numeric constant
     *
     * \note [0-9]+(.[0-9]*)([eE][+-][0-9]+)?
     *
     * \param tok_start The position of the beginning of the token
     * \return An integer or real type token
     */
    Token lex_numeric_constant(Position tok_start) {
        std::string str;
        str.reserve(64); // Reserve space to avoid reallocation
        bool integral = true;

        while (std::isdigit(buf_->peek())) {
            str.push_back(buf_->peek());
            skip_char();
        }

        // lex decimal
        if (buf_->peek() == '.') {
            integral = false;
            str.push_back(buf_->peek());
            skip_char();

            while (std::isdigit(buf_->peek())) {
                str.push_back(buf_->peek());
                skip_char();
            }
        }

        // lex exponent
        if (buf_->peek() == 'e' || buf_->peek() == 'E') {
            integral = false;
            str.push_back(buf_->peek());
            skip_char();

            if (buf_->peek() == '-' || buf_->peek() == '+') {
                str.push_back(buf_->peek());
                skip_char();
            }

            while (std::isdigit(buf_->peek())) {
                str.push_back(buf_->peek());
                skip_char();
            }
        }

        if (integral) {
            return Token(tok_start, Token::Kind::nninteger, str,
                         std::stoi(str));
        } else {
            return Token(tok_start, Token::Kind::real, str, std::stof(str));
        }
    }

    /**
     * \brief Lex an identifier
     *
     * \note [A-Za-z][_A-Za-z0-9]*
     *
     * \param tok_start The position of the beginning of the token
     * \return An identifier type token
     */
    Token lex_identifier(Position tok_start) {
        std::string str;
        str.reserve(64); // Reserve space to avoid reallocation

        while (std::isalpha(buf_->peek()) || std::isdigit(buf_->peek()) ||
               buf_->peek() == '_') {
            str.push_back(buf_->peek());
            skip_char();
        }

        // Check if the identifier is a known keyword
        auto keyword = keywords.find(str);
        if (keyword != keywords.end()) {
            return Token(tok_start, keyword->second, str);
        }

        return Token(tok_start, Token::Kind::identifier, str, str);
    }

    /**
     * \brief Lex a string literal
     *
     * \note "[.]*"
     *
     * \param tok_start The position of the beginning of the token
     * \return A string type token
     */
    Token lex_string(Position tok_start) {
        std::string str;
        str.reserve(64); // Reserve space to avoid reallocation

        while (buf_->peek() != '"' && buf_->peek() != '\n' &&
               buf_->peek() != '\r') {
            str.push_back(buf_->peek());
            skip_char();
        }

        if (buf_->peek() != '"') {
            std::cerr << "Lexical error at " << tok_start << ": unmatched \"\n";
            return Token(tok_start, Token::Kind::error, str);
        }

        skip_char();
        return Token(tok_start, Token::Kind::string, str, str);
    }

    /**
     * \brief Lex a token
     *
     * \note See arXiv:1707.03429 for the full grammar
     *
     * \return The lexed token
     */
    Token lex() {
        Position tok_start = pos_;
        skip_whitespace();

        switch (buf_->peek()) {
            case EOF:
                skip_char();
                return Token(tok_start, Token::Kind::eof, "");

            case '\r':
                skip_char();
                if (buf_->peek() != '\n') {
                    buf_->ignore();
                    pos_.advance_line();
                    return lex();
                }
                // FALLTHROUGH
            case '\n':
                buf_->ignore();
                pos_.advance_line();
                return lex();

            case '/':
                skip_char();
                if (buf_->peek() == '/') {
                    skip_line_comment();
                    return lex();
                }
                return Token(tok_start, Token::Kind::slash, "/");

                // clang-format off
            case '0': case '1': case '2': case '3': case '4':
            case '5': case '6': case '7': case '8': case '9':
            case '.':
                return lex_numeric_constant(tok_start);
                // clang-format on

            case 'C':
                skip_char();
                if (buf_->peek() == 'X') {
                    skip_char();
                    return Token(tok_start, Token::Kind::kw_cx, "CX");
                }

                skip_char();
                std::cerr
                    << "Lexical error at " << tok_start
                    << ": identifiers must start with lowercase letters\n";
                return Token(tok_start, Token::Kind::error,
                             std::string({'C', (char) buf_->get()}));

            case 'U':
                skip_char();
                return Token(tok_start, Token::Kind::kw_u, "U");

                // clang-format off
            case 'O':
            case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
            case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
            case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
            case 'v': case 'w': case 'x': case 'y': case 'z':
                return lex_identifier(tok_start);
                // clang-format on

            case '[':
                skip_char();
                return Token(tok_start, Token::Kind::l_square, "[");

            case ']':
                skip_char();
                return Token(tok_start, Token::Kind::r_square, "]");

            case '(':
                skip_char();
                return Token(tok_start, Token::Kind::l_paren, "(");

            case ')':
                skip_char();
                return Token(tok_start, Token::Kind::r_paren, ")");

            case '{':
                skip_char();
                return Token(tok_start, Token::Kind::l_brace, "{");

            case '}':
                skip_char();
                return Token(tok_start, Token::Kind::r_brace, "}");

            case '*':
                skip_char();
                return Token(tok_start, Token::Kind::star, "*");

            case '+':
                skip_char();
                return Token(tok_start, Token::Kind::plus, "+");

            case '-':
                skip_char();

                if (buf_->peek() == '>') {
                    skip_char();
                    return Token(tok_start, Token::Kind::arrow, "->");
                }

                return Token(tok_start, Token::Kind::minus, "-");

            case '^':
                skip_char();
                return Token(tok_start, Token::Kind::caret, "^");

            case ';':
                skip_char();
                return Token(tok_start, Token::Kind::semicolon, ";");

            case '=':
                skip_char();
                if (buf_->peek() == '=') {
                    skip_char();
                    return Token(tok_start, Token::Kind::equalequal, "==");
                }

                skip_char();
                std::cerr << "Lexical error at " << tok_start
                          << ": expected \"=\" after \"=\"\n";
                return Token(tok_start, Token::Kind::error,
                             std::string({'=', (char) buf_->get()}));

            case ',':
                skip_char();
                return Token(tok_start, Token::Kind::comma, ";");

            case '"':
                skip_char();
                return lex_string(tok_start);

            default:
                skip_char();
                return Token(tok_start, Token::Kind::error,
                             std::string({(char) buf_->get()}));
        }
    }
};

} // namespace parser
} // namespace qasmtools
<|endoftext|>