<commit_before>#include "log.h"
#include <QDebug>
#include <QRegExp>
#include <QList>
#include <QPair>
#include <QDateTime>
#include <QFileInfo>
//#include <QtConcurrent>
#include <QScrollBar>
#include <QTextCodec>

const QRegExp dateRegex("\\d\\d:\\d\\d:\\d\\d");

LinePositionList allLinePos(const QByteArray&bts){

    int count=0;
    auto size=bts.size();
    for(int i=0;i<size;++i){
        if(bts[i]=='\n'){
            count++;
        }
    }
    LinePositionList result(count);
    int start=0;
    int index=0;
    for(int i=0;i<size;++i){
        if(bts[i]=='\n'){
            LinePosition lp;
            lp.first=start;
            lp.second=i;
            lp.index=index++;
            result[lp.index]=lp;
            start=i+1;
        }
    }
    return result;
}

Log* Log::openFile(const QString&fname, const HighlightPatterns *global_highlight, const QString& default_encoding,QObject *parent){
    qDebug()<<"openFile"<<fname;
    QFileInfo fileInfo(fname);
    auto ll=new Log(fileInfo, fname, global_highlight, default_encoding, parent);
    return ll;
}

void Log::loadFile(){
    qDebug()<<"loadFile "<<m_fname;
    auto curDT=QDateTime::currentDateTimeUtc();
    QFile inputFile(m_fname);
    if (inputFile.open(QIODevice::ReadOnly))
    {
        m_bts=std::move(inputFile.readAll());
        m_lines=allLinePos(m_bts);

        inputFile.close();
    }else{
        throw std::logic_error("file not exists!");
    }
    qDebug()<<"elapsed time:"<< curDT.secsTo(QDateTime::currentDateTimeUtc());
    m_load_complete=true;
}

Log::Log(const QFileInfo& fileInfo,
         const QString&filename,
         const HighlightPatterns *global_highlight,
         const QString&default_encoding,
         QObject *parent):QAbstractItemModel(parent){
    m_default_encoding=default_encoding;
    m_fileInfo=fileInfo;
    m_lastModifed=m_fileInfo.lastModified();
    m_name=m_fileInfo.fileName();
    m_fname=filename;
    m_global_highlight=global_highlight;
    m_load_complete=false;
    m_codec = QTextCodec::codecForName( m_default_encoding.toStdString().c_str() );
    if(m_codec==nullptr){
        throw std::logic_error("m_codec==nullptr");
    }
    loadFile();
    auto idx=createIndex(-1,-1,nullptr);
    while(canFetchMore(idx)){
        fetchMore(idx);
    }
    qDebug()<<"loaded "<<m_name<<" lines:"<<m_lines.size();
}

QString Log::name()const{
    return m_name;
}

QString Log::filename()const{
    return m_fname;
}

void Log::update(){
    qDebug()<<"update "<<m_name<<"=>"<<m_fname;
    QFileInfo fileInfo(m_fname);

    //    if(fileInfo.lastModified()<=m_lastModifed){
    //        qDebug()<<"nothing to read: curDt:"<<fileInfo.lastModified()<<" myDt:"<<m_fileInfo.lastModified();
    //        return;
    //    }
    m_lastModifed=fileInfo.lastModified();

    qDebug()<<"loadFile "<<m_fname;
    auto curDT=QDateTime::currentDateTimeUtc();
    QFile inputFile(m_fname);
    if (inputFile.open(QIODevice::ReadOnly))
    {
        auto bts=inputFile.readAll();
        auto lines=allLinePos(bts);
        auto diff=lines.size()-m_lines.size();
        if(diff>0){
            //m_load_complete=false;
            //this->beginResetModel();
            m_bts=std::move(bts);

            m_lines=std::move(lines);

            m_load_complete=true;
            //this->endResetModel();

            emit countChanged(m_lines.size());
            emit linesChanged();

           int loaded=0;
            std::map<int, CachedString> local_res;
            for(size_t i=0;i<diff;++i){
                CachedString cs;
                cs.originValue=makeString(m_cache.size()+i);
                cs.Value=cs.originValue;
                local_res.insert(std::make_pair(m_cache.size()+i, cs));
                loaded++;
            }
            beginInsertRows(createIndex(0,0,nullptr), m_cache.size(), m_cache.size()+loaded-1);
            for(auto&kv:local_res){
                m_cache.insert(std::make_pair(kv.first, kv.second));
            }
            endInsertRows();
            emit m_lv_object->scrollToBottom();
        }

        inputFile.close();
    }else{
        throw std::logic_error("file not exists!");
    }

    qDebug()<<"update elapsed time:"<< curDT.secsTo(QDateTime::currentDateTimeUtc());
}

std::shared_ptr<QString> Log::makeString(int row, bool isPlain)const{
    auto line_pos=m_lines[row];
    int start=line_pos.first;
    int i=line_pos.second;

    int stringSize=int(i-start+1);
    QByteArray localStr(stringSize, ' ');

    int insertPos=0;
    for(int pos=start;pos<i;++pos){
        localStr[insertPos++]=m_bts[pos];
    }

    std::shared_ptr<QString> result=std::make_shared<QString>(m_codec->toUnicode(localStr));

    if(!isPlain)
    {
        if(m_global_highlight==nullptr){
            throw std::logic_error("m_global_highlight==nullptr");
        }
        result->replace('<', "<");
        result->replace('>', ">");
        for(auto it=m_global_highlight->begin();it!=m_global_highlight->end();++it){
            heighlightStr(result.get(), *it);
        }
        result->replace(' '," "); //html eats white spaces
    }

    return result;
}

int Log::rowCount(const QModelIndex & parent) const {
    Q_UNUSED(parent);
    if(!m_load_complete){
        return 0;
    }
   //return m_lines.size();
    return m_cache.size();
}

QVariant Log::data(const QModelIndex & index, int role) const {

    const QString emptyString="EmptyString";
    if(!m_load_complete ){
        return emptyString;
    }

    if (index.row() < 0 || index.row() >= int(m_lines.size()))
        return QVariant();
    if (role == Qt::DisplayRole || role == Qt::EditRole){
        auto it=m_cache.find(index.row());
        if(it!=m_cache.end()){
            return *it->second.Value;
        }
    }
    return QVariant();
}

QString Log::plainText(const QModelIndex & index)const{
    if (index.row() < 0 || index.row() >= int(m_lines.size()))
        return QString("error");
    return *makeString(index.row(), true);
}

bool Log::canFetchMore(const QModelIndex &index) const {
    if (m_lines.size()==m_cache.size()){
        qDebug()<<"canFetchMore "<<index.row()<<"isvalid:"<<index.isValid()<<"false";
        return false;
    }else{
        qDebug()<<"canFetchMore "<<index.row()<<"true";
        return true;
    }
}

void Log::fetchMore(const QModelIndex &index) {
    qDebug()<<"fetchMore"<<index.row();

    const int loadStep=1000;
    int loaded=0;
    std::map<int, CachedString> local_res;
    for(int i=0;i<loadStep;++i){
        if((m_cache.size()+local_res.size())==m_lines.size()){
            break;
        }
        CachedString cs;
        cs.originValue=makeString(m_cache.size()+i);
        cs.Value=cs.originValue;
        local_res.insert(std::make_pair(m_cache.size()+i, cs));
        loaded++;
    }
    beginInsertRows(index, m_cache.size(), m_cache.size()+loaded);
    for(auto&kv:local_res){
        m_cache.insert(std::make_pair(kv.first, kv.second));
    }
    endInsertRows();

}

void Log::clearHightlight(){
    //    m_load_complete=false;
    //    this->beginResetModel();
    //    QtConcurrent::blockingMap(m_buffer,[](CachedString&cs){
    //        cs.Value=cs.originValue;
    //    });
    //    for(int k=0;k<m_buffer.size();++k){
    //        auto mi=this->createIndex(k,0);
    //        dataChanged(mi, mi);
    //    }
    //    m_load_complete=true;
    //    this->endResetModel();
}

bool Log::heighlightStr(QString* str,const HighlightPattern&pattern){
    if(pattern.pattern.size()==0){
        return false;
    }
    bool result=false;

    QRegExp re(pattern.pattern);
    if(re.indexIn(*str)!= -1){
        auto ct=re.capturedTexts();
        for(auto&&captured_str:ct){
            str->replace(re,""+captured_str+"");
        }
        result=true;
    }

    return result;
}

void Log::updateHeighlights(QVector<CachedString>::iterator /*begin*/, QVector<CachedString>::iterator /*end*/,const QString&pattern){
    if(pattern.size()==0){
        return;
    }
    auto curDT=QDateTime::currentDateTimeUtc();

    //    QtConcurrent::blockingMap(begin, end,[this,&pattern](CachedString&cs){
    //        QString str(*cs.Value);
    //        auto is_updated=heighlightStr(&str, pattern);
    //        if(is_updated){
    //            cs.Value=std::make_shared<QString>(str);
    //        }
    //    });
    //    for(int k=0;k<m_buffer.size();++k){
    //        auto mi=this->createIndex(k,0);
    //        dataChanged(mi, mi);
    //    }
    qDebug()<<m_fname<<"updateHeighlights elapsed time:"<< curDT.secsTo(QDateTime::currentDateTimeUtc());
}

void Log::updateHeighlights(const QString&/*pattern*/){
    //updateHeighlights(m_buffer.begin(), m_buffer.end(), pattern);
}

void Log::localHightlightPattern(const QString&pattern){
    if(pattern.size()==0){
        return;
    }
    updateHeighlights(pattern);
}

void Log::setListVoxObject(QListView *object){
    m_lv_object=object;
}

QPair<int, QString> Log::findFrom(const QString&pattern,int index, SearchDirection direction){
    //TODO make thread safety. m_cache can be brokent, when timer is active
    if(size_t(index)==m_cache.size() || index<0){
        return QPair<int,QString>(index, QString());
    }

    QRegExp re(pattern.toUpper());

    int i=direction==SearchDirection::Down?index+1:index-1;

    while(true){
        QString str=plainText(createIndex(int(i),0,nullptr)).toUpper();
        if(re.indexIn(str)!=-1){
            return QPair<int,QString>(i, str);
        }
        if(direction==SearchDirection::Down){
            i++;
            if(size_t(i)==m_cache.size()){
                break;
            }
        }else{
            i--;
            if(i<0){
                break;
            }
        }
    }
    return QPair<int,QString>(index, "");
}
<commit_msg>html codes.<commit_after>#include "log.h"
#include <QDebug>
#include <QRegExp>
#include <QList>
#include <QPair>
#include <QDateTime>
#include <QFileInfo>
//#include <QtConcurrent>
#include <QScrollBar>
#include <QTextCodec>

const QRegExp dateRegex("\\d\\d:\\d\\d:\\d\\d");

LinePositionList allLinePos(const QByteArray&bts){

    int count=0;
    auto size=bts.size();
    for(int i=0;i<size;++i){
        if(bts[i]=='\n'){
            count++;
        }
    }
    LinePositionList result(count);
    int start=0;
    int index=0;
    for(int i=0;i<size;++i){
        if(bts[i]=='\n'){
            LinePosition lp;
            lp.first=start;
            lp.second=i;
            lp.index=index++;
            result[lp.index]=lp;
            start=i+1;
        }
    }
    return result;
}

Log* Log::openFile(const QString&fname, const HighlightPatterns *global_highlight, const QString& default_encoding,QObject *parent){
    qDebug()<<"openFile"<<fname;
    QFileInfo fileInfo(fname);
    auto ll=new Log(fileInfo, fname, global_highlight, default_encoding, parent);
    return ll;
}

void Log::loadFile(){
    qDebug()<<"loadFile "<<m_fname;
    auto curDT=QDateTime::currentDateTimeUtc();
    QFile inputFile(m_fname);
    if (inputFile.open(QIODevice::ReadOnly))
    {
        m_bts=std::move(inputFile.readAll());
        m_lines=allLinePos(m_bts);

        inputFile.close();
    }else{
        throw std::logic_error("file not exists!");
    }
    qDebug()<<"elapsed time:"<< curDT.secsTo(QDateTime::currentDateTimeUtc());
    m_load_complete=true;
}

Log::Log(const QFileInfo& fileInfo,
         const QString&filename,
         const HighlightPatterns *global_highlight,
         const QString&default_encoding,
         QObject *parent):QAbstractItemModel(parent){
    m_default_encoding=default_encoding;
    m_fileInfo=fileInfo;
    m_lastModifed=m_fileInfo.lastModified();
    m_name=m_fileInfo.fileName();
    m_fname=filename;
    m_global_highlight=global_highlight;
    m_load_complete=false;
    m_codec = QTextCodec::codecForName( m_default_encoding.toStdString().c_str() );
    if(m_codec==nullptr){
        throw std::logic_error("m_codec==nullptr");
    }
    loadFile();
    auto idx=createIndex(-1,-1,nullptr);
    while(canFetchMore(idx)){
        fetchMore(idx);
    }
    qDebug()<<"loaded "<<m_name<<" lines:"<<m_lines.size();
}

QString Log::name()const{
    return m_name;
}

QString Log::filename()const{
    return m_fname;
}

void Log::update(){
    qDebug()<<"update "<<m_name<<"=>"<<m_fname;
    QFileInfo fileInfo(m_fname);

    //    if(fileInfo.lastModified()<=m_lastModifed){
    //        qDebug()<<"nothing to read: curDt:"<<fileInfo.lastModified()<<" myDt:"<<m_fileInfo.lastModified();
    //        return;
    //    }
    m_lastModifed=fileInfo.lastModified();

    qDebug()<<"loadFile "<<m_fname;
    auto curDT=QDateTime::currentDateTimeUtc();
    QFile inputFile(m_fname);
    if (inputFile.open(QIODevice::ReadOnly))
    {
        auto bts=inputFile.readAll();
        auto lines=allLinePos(bts);
        auto diff=lines.size()-m_lines.size();
        if(diff>0){
            //m_load_complete=false;
            //this->beginResetModel();
            m_bts=std::move(bts);

            m_lines=std::move(lines);

            m_load_complete=true;
            //this->endResetModel();

            emit countChanged(m_lines.size());
            emit linesChanged();

           int loaded=0;
            std::map<int, CachedString> local_res;
            for(size_t i=0;i<diff;++i){
                CachedString cs;
                cs.originValue=makeString(m_cache.size()+i);
                cs.Value=cs.originValue;
                local_res.insert(std::make_pair(m_cache.size()+i, cs));
                loaded++;
            }
            beginInsertRows(createIndex(0,0,nullptr), m_cache.size(), m_cache.size()+loaded-1);
            for(auto&kv:local_res){
                m_cache.insert(std::make_pair(kv.first, kv.second));
            }
            endInsertRows();
            emit m_lv_object->scrollToBottom();
        }

        inputFile.close();
    }else{
        throw std::logic_error("file not exists!");
    }

    qDebug()<<"update elapsed time:"<< curDT.secsTo(QDateTime::currentDateTimeUtc());
}

std::shared_ptr<QString> Log::makeString(int row, bool isPlain)const{
    auto line_pos=m_lines[row];
    int start=line_pos.first;
    int i=line_pos.second;

    int stringSize=int(i-start+1);
    QByteArray localStr(stringSize, ' ');

    int insertPos=0;
    for(int pos=start;pos<i;++pos){
        localStr[insertPos++]=m_bts[pos];
    }

    std::shared_ptr<QString> result=std::make_shared<QString>(m_codec->toUnicode(localStr));

    if(!isPlain)
    {
        if(m_global_highlight==nullptr){
            throw std::logic_error("m_global_highlight==nullptr");
        }
        result->replace('<', "<");
        result->replace('>', ">");
        for(auto it=m_global_highlight->begin();it!=m_global_highlight->end();++it){
            heighlightStr(result.get(), *it);
        }
        result->replace(' '," "); //html eats white spaces
    }

    return result;
}

int Log::rowCount(const QModelIndex & parent) const {
    Q_UNUSED(parent);
    if(!m_load_complete){
        return 0;
    }
   //return m_lines.size();
    return m_cache.size();
}

QVariant Log::data(const QModelIndex & index, int role) const {

    const QString emptyString="EmptyString";
    if(!m_load_complete ){
        return emptyString;
    }

    if (index.row() < 0 || index.row() >= int(m_lines.size()))
        return QVariant();
    if (role == Qt::DisplayRole || role == Qt::EditRole){
        auto it=m_cache.find(index.row());
        if(it!=m_cache.end()){
            return *it->second.Value;
        }
    }
    return QVariant();
}

QString Log::plainText(const QModelIndex & index)const{
    if (index.row() < 0 || index.row() >= int(m_lines.size()))
        return QString("error");
    return *makeString(index.row(), true);
}

bool Log::canFetchMore(const QModelIndex &index) const {
    if (m_lines.size()==m_cache.size()){
        qDebug()<<"canFetchMore "<<index.row()<<"isvalid:"<<index.isValid()<<"false";
        return false;
    }else{
        qDebug()<<"canFetchMore "<<index.row()<<"true";
        return true;
    }
}

void Log::fetchMore(const QModelIndex &index) {
    qDebug()<<"fetchMore"<<index.row();

    const int loadStep=1000;
    int loaded=0;
    std::map<int, CachedString> local_res;
    for(int i=0;i<loadStep;++i){
        if((m_cache.size()+local_res.size())==m_lines.size()){
            break;
        }
        CachedString cs;
        cs.originValue=makeString(m_cache.size()+i);
        cs.Value=cs.originValue;
        local_res.insert(std::make_pair(m_cache.size()+i, cs));
        loaded++;
    }
    beginInsertRows(index, m_cache.size(), m_cache.size()+loaded);
    for(auto&kv:local_res){
        m_cache.insert(std::make_pair(kv.first, kv.second));
    }
    endInsertRows();

}

void Log::clearHightlight(){
    //    m_load_complete=false;
    //    this->beginResetModel();
    //    QtConcurrent::blockingMap(m_buffer,[](CachedString&cs){
    //        cs.Value=cs.originValue;
    //    });
    //    for(int k=0;k<m_buffer.size();++k){
    //        auto mi=this->createIndex(k,0);
    //        dataChanged(mi, mi);
    //    }
    //    m_load_complete=true;
    //    this->endResetModel();
}

bool Log::heighlightStr(QString* str,const HighlightPattern&pattern){
    if(pattern.pattern.size()==0){
        return false;
    }
    bool result=false;

    QRegExp re(pattern.pattern);
    if(re.indexIn(*str)!= -1){
        auto ct=re.capturedTexts();
        for(auto&&captured_str:ct){
            str->replace(re,""+captured_str+"");
        }
        result=true;
    }

    return result;
}

void Log::updateHeighlights(QVector<CachedString>::iterator /*begin*/, QVector<CachedString>::iterator /*end*/,const QString&pattern){
    if(pattern.size()==0){
        return;
    }
    auto curDT=QDateTime::currentDateTimeUtc();

    //    QtConcurrent::blockingMap(begin, end,[this,&pattern](CachedString&cs){
    //        QString str(*cs.Value);
    //        auto is_updated=heighlightStr(&str, pattern);
    //        if(is_updated){
    //            cs.Value=std::make_shared<QString>(str);
    //        }
    //    });
    //    for(int k=0;k<m_buffer.size();++k){
    //        auto mi=this->createIndex(k,0);
    //        dataChanged(mi, mi);
    //    }
    qDebug()<<m_fname<<"updateHeighlights elapsed time:"<< curDT.secsTo(QDateTime::currentDateTimeUtc());
}

void Log::updateHeighlights(const QString&/*pattern*/){
    //updateHeighlights(m_buffer.begin(), m_buffer.end(), pattern);
}

void Log::localHightlightPattern(const QString&pattern){
    if(pattern.size()==0){
        return;
    }
    updateHeighlights(pattern);
}

void Log::setListVoxObject(QListView *object){
    m_lv_object=object;
}

QPair<int, QString> Log::findFrom(const QString&pattern,int index, SearchDirection direction){
    //TODO make thread safety. m_cache can be brokent, when timer is active
    if(size_t(index)==m_cache.size() || index<0){
        return QPair<int,QString>(index, QString());
    }

    QRegExp re(pattern.toUpper());

    int i=direction==SearchDirection::Down?index+1:index-1;

    while(true){
        QString str=plainText(createIndex(int(i),0,nullptr)).toUpper();
        if(re.indexIn(str)!=-1){
            return QPair<int,QString>(i, str);
        }
        if(direction==SearchDirection::Down){
            i++;
            if(size_t(i)==m_cache.size()){
                break;
            }
        }else{
            i--;
            if(i<0){
                break;
            }
        }
    }
    return QPair<int,QString>(index, "");
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <chainparams.h>
#include <index/txindex.h>
#include <interfaces/chain.h>
#include <script/standard.h>
#include <test/util/setup_common.h>
#include <util/time.h>
#include <validation.h>

#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE(txindex_tests)

BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
{
    TxIndex txindex(interfaces::MakeChain(m_node), 1 << 20, true);

    CTransactionRef tx_disk;
    uint256 block_hash;

    // Transaction should not be found in the index before it is started.
    for (const auto& txn : m_coinbase_txns) {
        BOOST_CHECK(!txindex.FindTx(txn->GetHash(), block_hash, tx_disk));
    }

    // BlockUntilSyncedToCurrentChain should return false before txindex is started.
    BOOST_CHECK(!txindex.BlockUntilSyncedToCurrentChain());

    BOOST_REQUIRE(txindex.Start());

    // Allow tx index to catch up with the block index.
    constexpr int64_t timeout_ms = 10 * 1000;
    int64_t time_start = GetTimeMillis();
    while (!txindex.BlockUntilSyncedToCurrentChain()) {
        BOOST_REQUIRE(time_start + timeout_ms > GetTimeMillis());
        UninterruptibleSleep(std::chrono::milliseconds{100});
    }

    // Check that txindex excludes genesis block transactions.
    const CBlock& genesis_block = Params().GenesisBlock();
    for (const auto& txn : genesis_block.vtx) {
        BOOST_CHECK(!txindex.FindTx(txn->GetHash(), block_hash, tx_disk));
    }

    // Check that txindex has all txs that were in the chain before it started.
    for (const auto& txn : m_coinbase_txns) {
        if (!txindex.FindTx(txn->GetHash(), block_hash, tx_disk)) {
            BOOST_ERROR("FindTx failed");
        } else if (tx_disk->GetHash() != txn->GetHash()) {
            BOOST_ERROR("Read incorrect tx");
        }
    }

    // Check that new transactions in new blocks make it into the index.
    for (int i = 0; i < 10; i++) {
        CScript coinbase_script_pub_key = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey()));
        std::vector<CMutableTransaction> no_txns;
        const CBlock& block = CreateAndProcessBlock(no_txns, coinbase_script_pub_key);
        const CTransaction& txn = *block.vtx[0];

        BOOST_CHECK(txindex.BlockUntilSyncedToCurrentChain());
        if (!txindex.FindTx(txn.GetHash(), block_hash, tx_disk)) {
            BOOST_ERROR("FindTx failed");
        } else if (tx_disk->GetHash() != txn.GetHash()) {
            BOOST_ERROR("Read incorrect tx");
        }
    }

    // shutdown sequence (c.f. Shutdown() in init.cpp)
    txindex.Stop();

    // Let scheduler events finish running to avoid accessing any memory related to txindex after it is destructed
    SyncWithValidationInterfaceQueue();
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>test: move SyncWithValidationInterfaceQueue() before Stop() in txindex_tests<commit_after>// Copyright (c) 2017-2021 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <chainparams.h>
#include <index/txindex.h>
#include <interfaces/chain.h>
#include <script/standard.h>
#include <test/util/setup_common.h>
#include <util/time.h>
#include <validation.h>

#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_SUITE(txindex_tests)

BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
{
    TxIndex txindex(interfaces::MakeChain(m_node), 1 << 20, true);

    CTransactionRef tx_disk;
    uint256 block_hash;

    // Transaction should not be found in the index before it is started.
    for (const auto& txn : m_coinbase_txns) {
        BOOST_CHECK(!txindex.FindTx(txn->GetHash(), block_hash, tx_disk));
    }

    // BlockUntilSyncedToCurrentChain should return false before txindex is started.
    BOOST_CHECK(!txindex.BlockUntilSyncedToCurrentChain());

    BOOST_REQUIRE(txindex.Start());

    // Allow tx index to catch up with the block index.
    constexpr int64_t timeout_ms = 10 * 1000;
    int64_t time_start = GetTimeMillis();
    while (!txindex.BlockUntilSyncedToCurrentChain()) {
        BOOST_REQUIRE(time_start + timeout_ms > GetTimeMillis());
        UninterruptibleSleep(std::chrono::milliseconds{100});
    }

    // Check that txindex excludes genesis block transactions.
    const CBlock& genesis_block = Params().GenesisBlock();
    for (const auto& txn : genesis_block.vtx) {
        BOOST_CHECK(!txindex.FindTx(txn->GetHash(), block_hash, tx_disk));
    }

    // Check that txindex has all txs that were in the chain before it started.
    for (const auto& txn : m_coinbase_txns) {
        if (!txindex.FindTx(txn->GetHash(), block_hash, tx_disk)) {
            BOOST_ERROR("FindTx failed");
        } else if (tx_disk->GetHash() != txn->GetHash()) {
            BOOST_ERROR("Read incorrect tx");
        }
    }

    // Check that new transactions in new blocks make it into the index.
    for (int i = 0; i < 10; i++) {
        CScript coinbase_script_pub_key = GetScriptForDestination(PKHash(coinbaseKey.GetPubKey()));
        std::vector<CMutableTransaction> no_txns;
        const CBlock& block = CreateAndProcessBlock(no_txns, coinbase_script_pub_key);
        const CTransaction& txn = *block.vtx[0];

        BOOST_CHECK(txindex.BlockUntilSyncedToCurrentChain());
        if (!txindex.FindTx(txn.GetHash(), block_hash, tx_disk)) {
            BOOST_ERROR("FindTx failed");
        } else if (tx_disk->GetHash() != txn.GetHash()) {
            BOOST_ERROR("Read incorrect tx");
        }
    }

    // It is not safe to stop and destroy the index until it finishes handling
    // the last BlockConnected notification. The BlockUntilSyncedToCurrentChain()
    // call above is sufficient to ensure this, but the
    // SyncWithValidationInterfaceQueue() call below is also needed to ensure
    // TSAN always sees the test thread waiting for the notification thread, and
    // avoid potential false positive reports.
    SyncWithValidationInterfaceQueue();

    // shutdown sequence (c.f. Shutdown() in init.cpp)
    txindex.Stop();
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>//Code for COP 3503 Computer Programming for CS Majors II Lab/HW - Andrew Silver Problem 1. Code compiles. with g++ -std=c++0x -o p1 p1.cpp on Ubuntu 12.04 and with current stuff on Mac OS X. Implementation of RLE encoding for the Lab 3 for COP3503. Version 6.0 - includes working implementation of new-style encoding for COP 3503 HW 6. 1 + 1 = 2 ---> 11 + 11 = 12. Single digits get 1s before, and the no digit check was commented out.

//for more information, look up variations of the run-length encoding algorithm. for hello world, it prints he2lo world. for 1111, it prints 41, etc.

#include <iostream>

bool makestring(char* p1){
  bool result = false; //result of this function
  while (*p1){ //as long as the cstring is not at the delimiting whitespace. If the number 0 is in the cstring, this loop will stop evaluating and the else st
    if (!(*p1 - '0' < 10 && *p1 - '0' >= 0)){ //casts the element to an int. If it was a character, then the output would be not between 1 and 9, and this would execute (since it is ! ). If it was an int, then the output would be nonzero (the value of the int) and because of the ! this following code would not evaluate.
      result = true; //no number found, so good to go
    }
    else { //if there is a number in the list.
      result = false;
      break; //ends the for loop, a number was found
    }
    ++p1; //go to the next address to check
  } //ends while loop

  return result; //if there is a 0 digit in the cstring that is not the whitespace, then it will obviously return false, since a number exists, and it does not need to cycle through any more positions.
}

//this function takes a pointer to element at index 0 of an array (a cstring). It will cycle through and determine the length.
unsigned int lengthstring(char* p2){
  unsigned int length = 0; //the length of the cstring that will be determined.

  while (*p2){ //as long as the value at the address the pointer points to is not the delimiter 0. i.e., as long as the pointer does not point to the end of the array. Note that this does not include the delimiting 0 at the end in the calculation, as expected by the sample output. This could be added by just setting length to 1 at the start.
    ++length; //adds 1 to the length
    ++p2; //goes to the next address in the array
  }
  // std::cout << length; this part prints 5 if hello is passed in
  return length;

}

//function takes a cstring and replaces matching characters with the number of times they match
char* matchingstring(char* p3){
  int looptimes = 0; //the number of times the loop has occured through the values
  unsigned int length = 0; //length of the inputted cstring, which will be called from the function lengthstring
  char counting = '1'; //conversion for counter to a char to be stored
  int counter = 1; //the counter to track how many times the same element appears, starts at 1.
  char* repeat = p3; //tracker pointer to store the character that repeats, I don't want to increment the original array, copies address of p3 into repeat
  length = lengthstring(p3); //gets the length of the inputted string and stores it in counter
  char* output = new char[length](); //creates memory for pointer to the first element of a new array and default initializes the values to 0.
  char* array = output; //gets the value of the array, i.e., the address of the first element
  while (*p3){ //while not at the end of the array, i.e. the delimiter
    if ((*(p3 + 1) == *p3)){ //if the next element in the array is equal to the current
      while (*(p3 + 1) == *repeat && counter != 11){ //runs until the next element in the array is different than the current element and the numbers for counter are between 1 and 10
        ++counter; //increase the counter to determine the number of repeats
        ++p3; //moves p3 forward in the array to keep checking for more repeats
        // this evaluates std::cout << "yea this works" << std::endl;
      }
      if (counter >= 11){ //if the counter is greater than 10, then add a 0 for the first ten and keep going
        *array = '0';
        ++array;
        *array = *p3;
      }
      else if (counter == 10){ //if the counter is equal to 10, change it to 0
        *array = '0';
      }
      else {
        counting = (counter + '0'); //converts the int counter to a character
        *array = counting; //the element in the array gets the number of repeats
      }
      ++array; //go to the next index
      *array = *repeat; //the element in the array gets the repeated char
    }
    else if ( ((*p3 - '0' >= 0) && (*p3 - '0' < 10)) && ( ( (((*p3 - '0')/10 == 0 ) && (looptimes != 1) && (*(p3 + 1) == ' ' || *(p3 + 1) == '\0') )) || ( (*(p3 + 1) == ' ') && (*(p3 - 1) == ' ')) || ( (*(p3 +1) == '\0') && (*(p3 - 1) == ' ')))  ) { //additional implementation to RLE encoding. If there is a digit by itself, a 1 comes before it. The ' ' statements don't seem to work in the beginning of the pointer, so I created a "looptimes" variable that increments each time p3 goes to the next index. This means that this condition will always be false and I wouldn't have random '1's everywhere.
      *array = '1'; //1 digit found
      ++array;
      *array = *p3;
      ++p3; //goes to next index in P3
      *repeat = *p3; //resets repeat to current element at p3
      ++array; //goes to the next index position for the array
    }
    else { //base case, if no matches are found, i.e. if the next element is not equal to the current
      *array = *p3;
      ++p3; //go to the next index in p3
      *repeat = *p3; //resets repeat to the current element at p3
      ++array; //goes to next index position for the array
    }
    counter = 1; // reset counter to 1
    looptimes = 1; //once past the first element of the cstring, no longer run the first if condition
  }
  *array = '\0'; //adds the delimiting character to the end, making this a cstring
  return output; //returns a pointer to the first element of a cstring. Since the array was default initialized to 0, the last element will be '0'.
}

//the starting point of the program
int main(){

  int const buffer_size = 256; //create a buffer size
  char buffer[ buffer_size ]; //make a buffer

  // old version with no digits std::cout << "Type a sentence that does not contain any digits and press [RETURN], please." << std::endl;

  std::cout << "Type a sentence and press [RETURN], please." << std::endl;
  std::cin.getline( buffer, buffer_size ); //grab the input from the shell

  while (lengthstring(buffer)) //as long as pointer length does not equal 0, i.e. the null string
  {

    unsigned int originallength = lengthstring(buffer); //length of the original cstring, originally checklength
    unsigned int RLElength = 0; //length of the new cstring, which will be checked later

    /*  if(makestring(test) == false){ //calls the makestring method on the pointer, if the user enters a number, keep prompting. not used in new-style version
        std::cout << "Yeaaa bro don't give me numbers. That's not cool. Only use characters." << std::endl;
        std::cout << "Type a sentence that does not contain any digits and press [RETURN], please." << std::endl;
        std::cin.getline( buffer, buffer_size );

        } */

    //  else{ //if makestring(test) is true, i.e., there are no numbers in the cstring, removed in new style version
    char* RLE = matchingstring(buffer); //grabs a pointer to the first element of the RLE encoded version of the array, originally pointer
    RLElength = lengthstring(RLE); //checks the length of RLE version
    while (*RLE){ //while not at a delimeter
      std::cout << *RLE;
      ++RLE; //go to the next index position
    }
    std::cout << "" <<std::endl; //prints a newline
    if(originallength >= RLElength){ //if the RLE compressed version is shorter than the original
      std::cout << "The RLE version is " << (originallength - RLElength) << " shorter than the original" << std::endl;
    }
    else { //when using new style RLE compression, the RLElength could actually be longer.
      std::cout << "The RLE version is " << (RLElength - originallength) << " longer than the original" << std::endl;
    }
    if (lengthstring(buffer)){
      delete []RLE; //deletes the memory allocated for the encoded array
    }
    //std::cout << "Type a sentence that does not contain any digits and press [RETURN], please." << std::endl; NOT USED IN RLE NEW STYLE ENCODING
    std::cout << "Type a sentence and press [RETURN], please." <<std::endl;
    std::cin.getline( buffer, buffer_size );
  }
  //} closes else statement, removed in new style version
  return 0;
}
<commit_msg>got rid of extraneous () noted by CLang warning<commit_after>//Code for COP 3503 Computer Programming for CS Majors II Lab/HW - Andrew Silver Problem 1. Code compiles. with g++ -std=c++0x -o p1 p1.cpp on Ubuntu 12.04 and with current stuff on Mac OS X. Implementation of RLE encoding for the Lab 3 for COP3503. Version 6.0 - includes working implementation of new-style encoding for COP 3503 HW 6. 1 + 1 = 2 ---> 11 + 11 = 12. Single digits get 1s before, and the no digit check was commented out.

//for more information, look up variations of the run-length encoding algorithm. for hello world, it prints he2lo world. for 1111, it prints 41, etc.

#include <iostream>

bool makestring(char* p1){
  bool result = false; //result of this function
  while (*p1){ //as long as the cstring is not at the delimiting whitespace. If the number 0 is in the cstring, this loop will stop evaluating and the else st
    if (!(*p1 - '0' < 10 && *p1 - '0' >= 0)){ //casts the element to an int. If it was a character, then the output would be not between 1 and 9, and this would execute (since it is ! ). If it was an int, then the output would be nonzero (the value of the int) and because of the ! this following code would not evaluate.
      result = true; //no number found, so good to go
    }
    else { //if there is a number in the list.
      result = false;
      break; //ends the for loop, a number was found
    }
    ++p1; //go to the next address to check
  } //ends while loop

  return result; //if there is a 0 digit in the cstring that is not the whitespace, then it will obviously return false, since a number exists, and it does not need to cycle through any more positions.
}

//this function takes a pointer to element at index 0 of an array (a cstring). It will cycle through and determine the length.
unsigned int lengthstring(char* p2){
  unsigned int length = 0; //the length of the cstring that will be determined.

  while (*p2){ //as long as the value at the address the pointer points to is not the delimiter 0. i.e., as long as the pointer does not point to the end of the array. Note that this does not include the delimiting 0 at the end in the calculation, as expected by the sample output. This could be added by just setting length to 1 at the start.
    ++length; //adds 1 to the length
    ++p2; //goes to the next address in the array
  }
  // std::cout << length; this part prints 5 if hello is passed in
  return length;

}

//function takes a cstring and replaces matching characters with the number of times they match
char* matchingstring(char* p3){
  int looptimes = 0; //the number of times the loop has occured through the values
  unsigned int length = 0; //length of the inputted cstring, which will be called from the function lengthstring
  char counting = '1'; //conversion for counter to a char to be stored
  int counter = 1; //the counter to track how many times the same element appears, starts at 1.
  char* repeat = p3; //tracker pointer to store the character that repeats, I don't want to increment the original array, copies address of p3 into repeat
  length = lengthstring(p3); //gets the length of the inputted string and stores it in counter
  char* output = new char[length](); //creates memory for pointer to the first element of a new array and default initializes the values to 0.
  char* array = output; //gets the value of the array, i.e., the address of the first element
  while (*p3){ //while not at the end of the array, i.e. the delimiter
    if (*(p3 + 1) == *p3){ //if the next element in the array is equal to the current
      while (*(p3 + 1) == *repeat && counter != 11){ //runs until the next element in the array is different than the current element and the numbers for counter are between 1 and 10
        ++counter; //increase the counter to determine the number of repeats
        ++p3; //moves p3 forward in the array to keep checking for more repeats
        // this evaluates std::cout << "yea this works" << std::endl;
      }
      if (counter >= 11){ //if the counter is greater than 10, then add a 0 for the first ten and keep going
        *array = '0';
        ++array;
        *array = *p3;
      }
      else if (counter == 10){ //if the counter is equal to 10, change it to 0
        *array = '0';
      }
      else {
        counting = (counter + '0'); //converts the int counter to a character
        *array = counting; //the element in the array gets the number of repeats
      }
      ++array; //go to the next index
      *array = *repeat; //the element in the array gets the repeated char
    }
    else if ( ((*p3 - '0' >= 0) && (*p3 - '0' < 10)) && ( ( (((*p3 - '0')/10 == 0 ) && (looptimes != 1) && (*(p3 + 1) == ' ' || *(p3 + 1) == '\0') )) || ( (*(p3 + 1) == ' ') && (*(p3 - 1) == ' ')) || ( (*(p3 +1) == '\0') && (*(p3 - 1) == ' ')))  ) { //additional implementation to RLE encoding. If there is a digit by itself, a 1 comes before it. The ' ' statements don't seem to work in the beginning of the pointer, so I created a "looptimes" variable that increments each time p3 goes to the next index. This means that this condition will always be false and I wouldn't have random '1's everywhere.
      *array = '1'; //1 digit found
      ++array;
      *array = *p3;
      ++p3; //goes to next index in P3
      *repeat = *p3; //resets repeat to current element at p3
      ++array; //goes to the next index position for the array
    }
    else { //base case, if no matches are found, i.e. if the next element is not equal to the current
      *array = *p3;
      ++p3; //go to the next index in p3
      *repeat = *p3; //resets repeat to the current element at p3
      ++array; //goes to next index position for the array
    }
    counter = 1; // reset counter to 1
    looptimes = 1; //once past the first element of the cstring, no longer run the first if condition
  }
  *array = '\0'; //adds the delimiting character to the end, making this a cstring
  return output; //returns a pointer to the first element of a cstring. Since the array was default initialized to 0, the last element will be '0'.
}

//the starting point of the program
int main(){

  int const buffer_size = 256; //create a buffer size
  char buffer[ buffer_size ]; //make a buffer

  // old version with no digits std::cout << "Type a sentence that does not contain any digits and press [RETURN], please." << std::endl;

  std::cout << "Type a sentence and press [RETURN], please." << std::endl;
  std::cin.getline( buffer, buffer_size ); //grab the input from the shell

  while (lengthstring(buffer)) //as long as pointer length does not equal 0, i.e. the null string
  {

    unsigned int originallength = lengthstring(buffer); //length of the original cstring, originally checklength
    unsigned int RLElength = 0; //length of the new cstring, which will be checked later

    /*  if(makestring(test) == false){ //calls the makestring method on the pointer, if the user enters a number, keep prompting. not used in new-style version
        std::cout << "Yeaaa bro don't give me numbers. That's not cool. Only use characters." << std::endl;
        std::cout << "Type a sentence that does not contain any digits and press [RETURN], please." << std::endl;
        std::cin.getline( buffer, buffer_size );

        } */

    //  else{ //if makestring(test) is true, i.e., there are no numbers in the cstring, removed in new style version
    char* RLE = matchingstring(buffer); //grabs a pointer to the first element of the RLE encoded version of the array, originally pointer
    RLElength = lengthstring(RLE); //checks the length of RLE version
    while (*RLE){ //while not at a delimeter
      std::cout << *RLE;
      ++RLE; //go to the next index position
    }
    std::cout << "" <<std::endl; //prints a newline
    if(originallength >= RLElength){ //if the RLE compressed version is shorter than the original
      std::cout << "The RLE version is " << (originallength - RLElength) << " shorter than the original" << std::endl;
    }
    else { //when using new style RLE compression, the RLElength could actually be longer.
      std::cout << "The RLE version is " << (RLElength - originallength) << " longer than the original" << std::endl;
    }
    if (lengthstring(buffer)){
      delete []RLE; //deletes the memory allocated for the encoded array
    }
    //std::cout << "Type a sentence that does not contain any digits and press [RETURN], please." << std::endl; NOT USED IN RLE NEW STYLE ENCODING
    std::cout << "Type a sentence and press [RETURN], please." <<std::endl;
    std::cin.getline( buffer, buffer_size );
  }
  //} closes else statement, removed in new style version
  return 0;
}
<|endoftext|>


<commit_before>#include <lv.h>

using namespace std;

// A test unary functor
class Unary : public lv::UnaryFunctor
{
public:
    Unary() { mDim = 1; };
protected:
    void vector(var iVar, var& oVar) const;
};

void Unary::vector(var iVar, var& oVar) const
{
    for (int i=0; i<iVar.size(); i++)
        oVar[i] = iVar[iVar.size()-1-i];
    cout << "Unary: I: " << iVar.shape() << " " << iVar << endl;
    cout << "Unary: O: " << oVar.shape() << " " << oVar << endl;
}

// A test N-ary functor
class Nary : public lv::NaryFunctor
{
public:
    Nary() { mDim = 1; };
protected:
    void vector(var iVar, var& oVar) const;
};

void Nary::vector(var iVar, var& oVar) const
{
    for (int i=0; i<iVar[0].size(); i++)
        oVar[i] = iVar[0][iVar.size()-1-i];
    cout << "Nary[0]: " << iVar[0].shape() << " " << iVar[0] << endl;
    cout << "Nary[1]: " << iVar[1].shape() << " " << iVar[1] << endl;
    cout << "Nary[2]: " << iVar[2].shape() << " " << iVar[2] << endl;
    cout << "Nary: O: " << oVar.shape() << " " << oVar << endl;
}

int main(int argc, char** argv)
{
    // BLAS
    var bt;
    bt = 1.0f, 1.2f, 0.8f, -2.0f;
    cout << "dim: " << bt.dim() << " shape: " << bt.shape() << endl;
    cout << "shape(0): " << bt.shape(0)
         << " shape(-1): " << bt.shape(-1) << endl;
    cout << bt << "  sums to " << lv::sum(bt)  << endl;
    cout << bt << " asums to " << lv::asum(bt) << endl;

    // Broadcasting scalars
    var t1 = lv::irange(16.0f).view({4, 4});
    t1(1,2) = 2.3f;
    t1 += 1;
    cout << "t1: " << t1 << endl;
    cout << "t1*0.5: " << t1 * 0.5 << endl;
    t1 *= 1.5;
    cout << "t1: " << t1 << endl;
    t1 += t1;
    cout << "t1: " << t1 << endl;
    t1 -= t1 - 1;
    cout << "t1: " << t1 << endl;

    // Sub-views
    var r12 = lv::irange(0.1, 12.1);
    cout << "r12: " << r12 << endl;
    var sv = r12.view({4}, 4);
    cout << "sv: " << sv << endl;
    cout << "sv(0): " << sv(0) << endl;
    cout << "sv[0]: " << sv[0] << endl;
    cout << "sv.size(): " << sv.size() << endl;
    sv += 1;
    cout << "r12: " << r12 << endl;
    var rv;
    rv = -1.0, -2.0, -3.0, -4.0;
    cout << "rv: " << rv << endl;
    sv.offset(8);
    sv = rv;
    cout << "r12: " << r12 << endl;

    // Broadcasting tensors
    var r6 = lv::irange(6.0).view({3,2});
    var r2;
    r2 = 1.0, 2.0;
    cout << "r2: " << r2 << endl;
    cout << "r6: " << r6 << endl;
    r6 += r2;
    cout << "r6: " << r6 << endl;
    r6 *= r2;
    cout << "r6: " << r6 << endl;
    cout << "r6*r6: " << r6 * r6 << endl;

    // View of a view
    var r3 = r6.view({2}, 0);
    var r4 = sv.view({2}, 0);
    cout << "r3: " << r3 << endl;
    cout << "r4: " << r4 << endl;

    // Functors
    cout << "Size: " << sizeof(lv::Pow) << endl;
    cout << "Pow: " << lv::pow(3.0, 2) << endl;
    cout << "Pow: " << lv::pow(r6, 2) << endl;
    cout << "Tan: " << lv::tan(r6) << endl;

    // Transpose
    cout << "oTranspose:\n" << lv::transpose(r6) << endl << r6 << endl;
    cout << "iTranspose:\n" << r6.transpose() << endl << r6 << endl;

    // Dot
    var rd;
    rd = 2.0, 2.0, 2.0;
    var rd6 = lv::dot(r6, rd);
    cout << "Dot: " << rd6 << endl;

    // DFT
    var td = lv::view({2, 10});
    var fd;
    for (int i=0; i<10; i++)
    {
        td(0, i) = sinf(i);
        td(1, i) = cosf(i);
    }
    cout << "Time: " << td << endl;
    lv::DFT dft(10);
    fd = dft(td);
    cout << "Freq: " << fd << endl;

    // Check the complex operators
    cout << "Real: " << lv::real(fd) << endl;
    cout << "Imag: " << lv::imag(fd) << endl;
    cout << "Arg: " << lv::arg(fd) << endl;
    cout << "Abs: " << lv::abs(fd) << endl;
    cout << "Norm: " << lv::norm(fd) << endl;

    // Real output writing to complex storage
    var cd = var(12, lv::cfloat(0.0f,0.0f)).view({2,6});
    cout << "NormC: "<< lv::norm(fd, cd) << endl;

    var im = lv::iamax(fd);
    cout << "IAMax: " << im << endl;

    // Functor view broadcast
    Unary u;
    cout << u(r6) << endl;

    // N-ary functor
    var v1, v2, v3;
    v1 =
        0.0, 1.2, 1.4,
        1.0, 1.2, 1.4,
        2.0, 1.2, 1.4,
        3.0, 1.2, 1.4;
    v1 = v1.view({4,3});
    v2 =
        0.0, 2.2,
        1.0, 2.2,
        2.0, 2.2,
        3.0, 2.2;
    v2 = v2.view({4,2});
    v3 = 1.0, 2.2, 3.3, 4.4;
    Nary nary;
    var vN;
    vN.push(v1);
    vN.push(v2);
    vN.push(v3);
    cout << "vN: " << vN << endl;
    nary(vN);

    // Polynomial stuff
    var xpoly({1.0f, 0.0f, 0.0f, -1.0f});
    var xroot = lv::roots(xpoly);
    cout << "Roots of x^3-1=0: " << xroot << endl;
    xpoly = lv::poly(xroot);
    cout << "Poly is: " << xpoly << endl;

    // Sort
    var fsrt({1.0, -1.0, 2.1, -2.1, 3.0});
    cout << "Usrt is: " << fsrt << endl;
    cout << "Sort is: " << lv::sort(fsrt, fsrt) << endl;
    var csrt("Super duper strING");
    cout << "Usrt is: " << csrt << endl;
    cout << "Sort is: " << lv::sort(csrt, csrt) << endl;

    // Done
    return 0;
}
<commit_msg>Add a test for IDFT.  Still need to compare implementations.<commit_after>#include <lv.h>

using namespace std;

// A test unary functor
class Unary : public lv::UnaryFunctor
{
public:
    Unary() { mDim = 1; };
protected:
    void vector(var iVar, var& oVar) const;
};

void Unary::vector(var iVar, var& oVar) const
{
    for (int i=0; i<iVar.size(); i++)
        oVar[i] = iVar[iVar.size()-1-i];
    cout << "Unary: I: " << iVar.shape() << " " << iVar << endl;
    cout << "Unary: O: " << oVar.shape() << " " << oVar << endl;
}

// A test N-ary functor
class Nary : public lv::NaryFunctor
{
public:
    Nary() { mDim = 1; };
protected:
    void vector(var iVar, var& oVar) const;
};

void Nary::vector(var iVar, var& oVar) const
{
    for (int i=0; i<iVar[0].size(); i++)
        oVar[i] = iVar[0][iVar.size()-1-i];
    cout << "Nary[0]: " << iVar[0].shape() << " " << iVar[0] << endl;
    cout << "Nary[1]: " << iVar[1].shape() << " " << iVar[1] << endl;
    cout << "Nary[2]: " << iVar[2].shape() << " " << iVar[2] << endl;
    cout << "Nary: O: " << oVar.shape() << " " << oVar << endl;
}

int main(int argc, char** argv)
{
    // BLAS
    var bt;
    bt = 1.0f, 1.2f, 0.8f, -2.0f;
    cout << "dim: " << bt.dim() << " shape: " << bt.shape() << endl;
    cout << "shape(0): " << bt.shape(0)
         << " shape(-1): " << bt.shape(-1) << endl;
    cout << bt << "  sums to " << lv::sum(bt)  << endl;
    cout << bt << " asums to " << lv::asum(bt) << endl;

    // Broadcasting scalars
    var t1 = lv::irange(16.0f).view({4, 4});
    t1(1,2) = 2.3f;
    t1 += 1;
    cout << "t1: " << t1 << endl;
    cout << "t1*0.5: " << t1 * 0.5 << endl;
    t1 *= 1.5;
    cout << "t1: " << t1 << endl;
    t1 += t1;
    cout << "t1: " << t1 << endl;
    t1 -= t1 - 1;
    cout << "t1: " << t1 << endl;

    // Sub-views
    var r12 = lv::irange(0.1, 12.1);
    cout << "r12: " << r12 << endl;
    var sv = r12.view({4}, 4);
    cout << "sv: " << sv << endl;
    cout << "sv(0): " << sv(0) << endl;
    cout << "sv[0]: " << sv[0] << endl;
    cout << "sv.size(): " << sv.size() << endl;
    sv += 1;
    cout << "r12: " << r12 << endl;
    var rv;
    rv = -1.0, -2.0, -3.0, -4.0;
    cout << "rv: " << rv << endl;
    sv.offset(8);
    sv = rv;
    cout << "r12: " << r12 << endl;

    // Broadcasting tensors
    var r6 = lv::irange(6.0).view({3,2});
    var r2;
    r2 = 1.0, 2.0;
    cout << "r2: " << r2 << endl;
    cout << "r6: " << r6 << endl;
    r6 += r2;
    cout << "r6: " << r6 << endl;
    r6 *= r2;
    cout << "r6: " << r6 << endl;
    cout << "r6*r6: " << r6 * r6 << endl;

    // View of a view
    var r3 = r6.view({2}, 0);
    var r4 = sv.view({2}, 0);
    cout << "r3: " << r3 << endl;
    cout << "r4: " << r4 << endl;

    // Functors
    cout << "Size: " << sizeof(lv::Pow) << endl;
    cout << "Pow: " << lv::pow(3.0, 2) << endl;
    cout << "Pow: " << lv::pow(r6, 2) << endl;
    cout << "Tan: " << lv::tan(r6) << endl;

    // Transpose
    cout << "oTranspose:\n" << lv::transpose(r6) << endl << r6 << endl;
    cout << "iTranspose:\n" << r6.transpose() << endl << r6 << endl;

    // Dot
    var rd;
    rd = 2.0, 2.0, 2.0;
    var rd6 = lv::dot(r6, rd);
    cout << "Dot: " << rd6 << endl;

    // DFT
    var td = lv::view({2, 10});
    var fd;
    for (int i=0; i<10; i++)
    {
        td(0, i) = sinf(i);
        td(1, i) = cosf(i);
    }
    cout << "Time: " << td << endl;
    lv::DFT dft(10);
    fd = dft(td);
    cout << "Freq: " << fd << endl;
    lv::DFT idft(10, true);
    var ifd = idft(fd);
    cout << "IFreq: " << ifd << endl;

    // Check the complex operators
    cout << "Real: " << lv::real(fd) << endl;
    cout << "Imag: " << lv::imag(fd) << endl;
    cout << "Arg: " << lv::arg(fd) << endl;
    cout << "Abs: " << lv::abs(fd) << endl;
    cout << "Norm: " << lv::norm(fd) << endl;

    // Real output writing to complex storage
    var cd = var(12, lv::cfloat(0.0f,0.0f)).view({2,6});
    cout << "NormC: "<< lv::norm(fd, cd) << endl;

    var im = lv::iamax(fd);
    cout << "IAMax: " << im << endl;

    // Functor view broadcast
    Unary u;
    cout << u(r6) << endl;

    // N-ary functor
    var v1, v2, v3;
    v1 =
        0.0, 1.2, 1.4,
        1.0, 1.2, 1.4,
        2.0, 1.2, 1.4,
        3.0, 1.2, 1.4;
    v1 = v1.view({4,3});
    v2 =
        0.0, 2.2,
        1.0, 2.2,
        2.0, 2.2,
        3.0, 2.2;
    v2 = v2.view({4,2});
    v3 = 1.0, 2.2, 3.3, 4.4;
    Nary nary;
    var vN;
    vN.push(v1);
    vN.push(v2);
    vN.push(v3);
    cout << "vN: " << vN << endl;
    nary(vN);

    // Polynomial stuff
    var xpoly({1.0f, 0.0f, 0.0f, -1.0f});
    var xroot = lv::roots(xpoly);
    cout << "Roots of x^3-1=0: " << xroot << endl;
    xpoly = lv::poly(xroot);
    cout << "Poly is: " << xpoly << endl;

    // Sort
    var fsrt({1.0, -1.0, 2.1, -2.1, 3.0});
    cout << "Usrt is: " << fsrt << endl;
    cout << "Sort is: " << lv::sort(fsrt, fsrt) << endl;
    var csrt("Super duper strING");
    cout << "Usrt is: " << csrt << endl;
    cout << "Sort is: " << lv::sort(csrt, csrt) << endl;

    // Done
    return 0;
}
<|endoftext|>


<commit_before>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "SimpleFluidPropertiesTest.h"
#include "SinglePhaseFluidPropertiesTestUtils.h"

/**
 * Test that the fluid name is correctly returned
 */
TEST_F(SimpleFluidPropertiesTest, fluidName) { EXPECT_EQ(_fp->fluidName(), "simple_fluid"); }

/**
 * Test that the default molar mass is correctly returned
 */
TEST_F(SimpleFluidPropertiesTest, molarMass)
{
  ABS_TEST(_fp->molarMass(), 1.8e-2, REL_TOL_SAVED_VALUE);
}

/**
 * Verify calculation of the fluid properties
 */
TEST_F(SimpleFluidPropertiesTest, properties)
{
  const Real thermal_exp = 2.14E-4;
  const Real cv = 4186.0;
  const Real cp = 4194.0;
  const Real bulk_modulus = 2.0E9;
  const Real thermal_cond = 0.6;
  const Real entropy = 300.0;
  const Real visc = 1.0E-3;
  const Real density0 = 1000.0;
  const Real pp_coef = 0.0;

  const Real tol = REL_TOL_CONSISTENCY;

  Real p = 8.56E7;
  Real T = 200.0;
  Real e = 8.372E5;
  Real v = 0.001;

  ABS_TEST(_fp->beta_from_p_T(p, T), thermal_exp, tol);
  ABS_TEST(_fp->cp_from_p_T(p, T), cp, tol);
  ABS_TEST(_fp->cv_from_p_T(p, T), cv, tol);
  ABS_TEST(_fp->c_from_p_T(p, T), std::sqrt(bulk_modulus / _fp->rho_from_p_T(p, T)), tol);
  ABS_TEST(_fp->k_from_p_T(p, T), thermal_cond, tol);
  ABS_TEST(_fp->k_from_p_T(p, T), thermal_cond, tol);
  ABS_TEST(_fp->s_from_p_T(p, T), entropy, tol);
  ABS_TEST(_fp->rho_from_p_T(p, T), density0 * std::exp(p / bulk_modulus - thermal_exp * T), tol);
  ABS_TEST(_fp->e_from_p_T(p, T), cv * T, tol);
  ABS_TEST(_fp->mu_from_p_T(p, T), visc, tol);
  ABS_TEST(_fp->mu_from_p_T(p, T), visc, tol);
  ABS_TEST(_fp->h_from_p_T(p, T), cv * T + p / _fp->rho_from_p_T(p, T), tol);
  ABS_TEST(_fp2->h_from_p_T(p, T), cv * T + p * pp_coef / _fp2->rho_from_p_T(p, T), tol);
  ABS_TEST(_fp->cp_from_v_e(v, e), cp, tol);
  ABS_TEST(_fp->cv_from_v_e(v, e), cv, tol);
  ABS_TEST(
      _fp->c_from_v_e(v, e),
      std::sqrt(bulk_modulus / _fp->rho_from_p_T(_fp->p_from_v_e(v, e), _fp->T_from_v_e(v, e))),
      tol);
  ABS_TEST(_fp->k_from_v_e(v, e), thermal_cond, tol);
  ABS_TEST(_fp->s_from_v_e(v, e), entropy, tol);
  ABS_TEST(_fp->T_from_v_e(v, e), T, tol);
  ABS_TEST(_fp->p_from_v_e(v, e),
           bulk_modulus * (thermal_exp * _fp->T_from_v_e(v, e) + std::log(1 / (v * density0))),
           tol);
  ABS_TEST(_fp->mu_from_v_e(v, e), visc, tol);

  p = 1.06841E9;
  T = 300.0;
  e = 1.2558E6;
  v = 6.25E-4;

  ABS_TEST(_fp->beta_from_p_T(p, T), thermal_exp, tol);
  ABS_TEST(_fp->cp_from_p_T(p, T), cp, tol);
  ABS_TEST(_fp->cv_from_p_T(p, T), cv, tol);
  ABS_TEST(_fp->c_from_p_T(p, T), std::sqrt(bulk_modulus / _fp->rho_from_p_T(p, T)), tol);
  ABS_TEST(_fp->k_from_p_T(p, T), thermal_cond, tol);
  ABS_TEST(_fp->k_from_p_T(p, T), thermal_cond, tol);
  ABS_TEST(_fp->s_from_p_T(p, T), entropy, tol);
  ABS_TEST(_fp->rho_from_p_T(p, T), density0 * std::exp(p / bulk_modulus - thermal_exp * T), tol);
  ABS_TEST(_fp->e_from_p_T(p, T), cv * T, tol);
  ABS_TEST(_fp->mu_from_p_T(p, T), visc, tol);
  ABS_TEST(_fp->mu_from_p_T(p, T), visc, tol);
  ABS_TEST(_fp->h_from_p_T(p, T), cv * T + p / _fp->rho_from_p_T(p, T), tol);
  ABS_TEST(_fp2->h_from_p_T(p, T), cv * T + p * pp_coef / _fp2->rho_from_p_T(p, T), tol);
  ABS_TEST(_fp->cp_from_v_e(v, e), cp, tol);
  ABS_TEST(_fp->cv_from_v_e(v, e), cv, tol);
  ABS_TEST(
      _fp->c_from_v_e(v, e),
      std::sqrt(bulk_modulus / _fp->rho_from_p_T(_fp->p_from_v_e(v, e), _fp->T_from_v_e(v, e))),
      tol);
  ABS_TEST(_fp->k_from_v_e(v, e), thermal_cond, tol);
  ABS_TEST(_fp->s_from_v_e(v, e), entropy, tol);
  ABS_TEST(_fp->T_from_v_e(v, e), T, tol);
  ABS_TEST(_fp->p_from_v_e(v, e),
           bulk_modulus * (thermal_exp * _fp->T_from_v_e(v, e) + std::log(1 / (v * density0))),
           tol);
  ABS_TEST(_fp->mu_from_v_e(v, e), visc, tol);
}

/**
 * Verify calculation of the derivatives by comparing with finite
 * differences
 */
TEST_F(SimpleFluidPropertiesTest, derivatives)
{
  const Real tol = REL_TOL_DERIVATIVE;

  Real p = 1.0E7;
  Real T = 10.0;
  Real e = 8.372E5;
  Real v = 1.25E-3;

  DERIV_TEST(_fp->rho_from_p_T, p, T, tol);
  DERIV_TEST(_fp->mu_from_p_T, p, T, tol);
  DERIV_TEST(_fp->e_from_p_T, p, T, tol);
  DERIV_TEST(_fp->h_from_p_T, p, T, tol);
  DERIV_TEST(_fp->k_from_p_T, p, T, tol);
  DERIV_TEST(_fp->cp_from_p_T, p, T, tol);
  DERIV_TEST(_fp->cv_from_p_T, p, T, tol);
  DERIV_TEST(_fp->c_from_p_T, p, T, tol);
  DERIV_TEST(_fp->s_from_p_T, p, T, tol);
  DERIV_TEST(_fp->cp_from_v_e, v, e, tol);
  DERIV_TEST(_fp->cv_from_v_e, v, e, tol);
  DERIV_TEST(_fp->c_from_v_e, v, e, tol);
  DERIV_TEST(_fp->k_from_v_e, v, e, tol);
  DERIV_TEST(_fp->s_from_v_e, v, e, tol);
  DERIV_TEST(_fp->T_from_v_e, v, e, tol);
  DERIV_TEST(_fp->p_from_v_e, v, e, tol);
  DERIV_TEST(_fp->mu_from_v_e, v, e, tol);

  p = 5.0E7;
  T = 90.0;
  e = 1.6744E6;
  v = 6.25E-4;

  DERIV_TEST(_fp->rho_from_p_T, p, T, tol);
  DERIV_TEST(_fp->mu_from_p_T, p, T, tol);
  DERIV_TEST(_fp->e_from_p_T, p, T, tol);
  DERIV_TEST(_fp->h_from_p_T, p, T, tol);
  DERIV_TEST(_fp->k_from_p_T, p, T, tol);
  DERIV_TEST(_fp->cp_from_p_T, p, T, tol);
  DERIV_TEST(_fp->cv_from_p_T, p, T, tol);
  DERIV_TEST(_fp->c_from_p_T, p, T, tol);
  DERIV_TEST(_fp->s_from_p_T, p, T, tol);
  DERIV_TEST(_fp->cp_from_v_e, v, e, tol);
  DERIV_TEST(_fp->cv_from_v_e, v, e, tol);
  DERIV_TEST(_fp->c_from_v_e, v, e, tol);
  DERIV_TEST(_fp->k_from_v_e, v, e, tol);
  DERIV_TEST(_fp->s_from_v_e, v, e, tol);
  DERIV_TEST(_fp->T_from_v_e, v, e, tol);
  DERIV_TEST(_fp->p_from_v_e, v, e, tol);
  DERIV_TEST(_fp->mu_from_v_e, v, e, tol);
}

/**
 * Verify that the methods that return multiple properties in one call return identical
 * values as the individual methods
 */
TEST_F(SimpleFluidPropertiesTest, combined)
{
  const Real p = 1.0e6;
  const Real T = 300.0;
  const Real tol = REL_TOL_CONSISTENCY;

  // Single property methods
  Real rho, drho_dp, drho_dT;
  _fp->rho_from_p_T(p, T, rho, drho_dp, drho_dT);
  Real mu, dmu_dp, dmu_dT;
  _fp->mu_from_p_T(p, T, mu, dmu_dp, dmu_dT);
  Real e, de_dp, de_dT;
  _fp->e_from_p_T(p, T, e, de_dp, de_dT);

  // Combined property methods
  Real rho2, drho2_dp, drho2_dT, mu2, dmu2_dp, dmu2_dT, e2, de2_dp, de2_dT;
  _fp->rho_mu_from_p_T(p, T, rho2, mu2);

  ABS_TEST(rho, rho2, tol);
  ABS_TEST(mu, mu2, tol);

  _fp->rho_mu_from_p_T(p, T, rho2, drho2_dp, drho2_dT, mu2, dmu2_dp, dmu2_dT);
  ABS_TEST(rho, rho2, tol);
  ABS_TEST(drho_dp, drho2_dp, tol);
  ABS_TEST(drho_dT, drho2_dT, tol);
  ABS_TEST(mu, mu2, tol);
  ABS_TEST(dmu_dp, dmu2_dp, tol);
  ABS_TEST(dmu_dT, dmu2_dT, tol);

  _fp->rho_e_from_p_T(p, T, rho2, drho2_dp, drho2_dT, e2, de2_dp, de2_dT);
  ABS_TEST(rho, rho2, tol);
  ABS_TEST(drho_dp, drho2_dp, tol);
  ABS_TEST(drho_dT, drho2_dT, tol);
  ABS_TEST(e, e2, tol);
  ABS_TEST(de_dp, de2_dp, tol);
  ABS_TEST(de_dT, de2_dT, tol);
}
<commit_msg>Add unit test for SimpleFluidProps, refs #22439<commit_after>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "SimpleFluidPropertiesTest.h"
#include "SinglePhaseFluidPropertiesTestUtils.h"

/**
 * Test that the fluid name is correctly returned
 */
TEST_F(SimpleFluidPropertiesTest, fluidName) { EXPECT_EQ(_fp->fluidName(), "simple_fluid"); }

/**
 * Test that the default molar mass is correctly returned
 */
TEST_F(SimpleFluidPropertiesTest, molarMass)
{
  ABS_TEST(_fp->molarMass(), 1.8e-2, REL_TOL_SAVED_VALUE);
}

/**
 * Verify calculation of the fluid properties
 */
TEST_F(SimpleFluidPropertiesTest, properties)
{
  const Real thermal_exp = 2.14E-4;
  const Real cv = 4186.0;
  const Real cp = 4194.0;
  const Real bulk_modulus = 2.0E9;
  const Real thermal_cond = 0.6;
  const Real entropy = 300.0;
  const Real visc = 1.0E-3;
  const Real density0 = 1000.0;
  const Real pp_coef = 0.0;

  const Real tol = REL_TOL_CONSISTENCY;
  const Real large_tol = 10 * tol;

  Real p = 8.56E7;
  Real T = 200.0;
  Real e = 8.372E5;
  Real v = 0.001;

  ABS_TEST(_fp->beta_from_p_T(p, T), thermal_exp, tol);
  ABS_TEST(_fp->cp_from_p_T(p, T), cp, tol);
  ABS_TEST(_fp->cv_from_p_T(p, T), cv, tol);
  ABS_TEST(_fp->c_from_p_T(p, T), std::sqrt(bulk_modulus / _fp->rho_from_p_T(p, T)), tol);
  ABS_TEST(_fp->k_from_p_T(p, T), thermal_cond, tol);
  ABS_TEST(_fp->k_from_p_T(p, T), thermal_cond, tol);
  ABS_TEST(_fp->s_from_p_T(p, T), entropy, tol);
  ABS_TEST(_fp->rho_from_p_T(p, T), density0 * std::exp(p / bulk_modulus - thermal_exp * T), tol);
  ABS_TEST(_fp->e_from_p_T(p, T), cv * T, tol);
  ABS_TEST(_fp->e_from_p_rho(p, 1. / v), cv * T, tol);
  ABS_TEST(_fp->mu_from_p_T(p, T), visc, tol);
  ABS_TEST(_fp->mu_from_p_T(p, T), visc, tol);
  ABS_TEST(_fp->h_from_p_T(p, T), cv * T + p / _fp->rho_from_p_T(p, T), tol);
  ABS_TEST(_fp2->h_from_p_T(p, T), cv * T + p * pp_coef / _fp2->rho_from_p_T(p, T), tol);
  ABS_TEST(_fp->cp_from_v_e(v, e), cp, tol);
  ABS_TEST(_fp->cv_from_v_e(v, e), cv, tol);
  ABS_TEST(
      _fp->c_from_v_e(v, e),
      std::sqrt(bulk_modulus / _fp->rho_from_p_T(_fp->p_from_v_e(v, e), _fp->T_from_v_e(v, e))),
      tol);
  ABS_TEST(_fp->k_from_v_e(v, e), thermal_cond, tol);
  ABS_TEST(_fp->s_from_v_e(v, e), entropy, tol);
  ABS_TEST(_fp->T_from_v_e(v, e), T, tol);
  ABS_TEST(_fp->T_from_p_h(p, _fp->h_from_p_T(p, T)), T, tol);
  ABS_TEST(_fp->T_from_p_rho(p, 1. / v), T, tol);
  ABS_TEST(_fp->p_from_v_e(v, e),
           bulk_modulus * (thermal_exp * _fp->T_from_v_e(v, e) + std::log(1 / (v * density0))),
           tol);
  ABS_TEST(_fp->mu_from_v_e(v, e), visc, tol);

  p = 1.06841E9;
  T = 300.0;
  e = 1.2558E6;
  v = 6.249991432791718E-4;

  ABS_TEST(_fp->beta_from_p_T(p, T), thermal_exp, tol);
  ABS_TEST(_fp->cp_from_p_T(p, T), cp, tol);
  ABS_TEST(_fp->cv_from_p_T(p, T), cv, tol);
  ABS_TEST(_fp->c_from_p_T(p, T), std::sqrt(bulk_modulus / _fp->rho_from_p_T(p, T)), tol);
  ABS_TEST(_fp->k_from_p_T(p, T), thermal_cond, tol);
  ABS_TEST(_fp->k_from_p_T(p, T), thermal_cond, tol);
  ABS_TEST(_fp->s_from_p_T(p, T), entropy, tol);
  ABS_TEST(_fp->rho_from_p_T(p, T), density0 * std::exp(p / bulk_modulus - thermal_exp * T), tol);
  ABS_TEST(_fp->e_from_p_T(p, T), cv * T, tol);
  ABS_TEST(_fp->e_from_p_rho(p, 1. / v), cv * T, large_tol);
  ABS_TEST(_fp->mu_from_p_T(p, T), visc, tol);
  ABS_TEST(_fp->mu_from_p_T(p, T), visc, tol);
  ABS_TEST(_fp->h_from_p_T(p, T), cv * T + p / _fp->rho_from_p_T(p, T), tol);
  ABS_TEST(_fp2->h_from_p_T(p, T), cv * T + p * pp_coef / _fp2->rho_from_p_T(p, T), tol);
  ABS_TEST(_fp->cp_from_v_e(v, e), cp, tol);
  ABS_TEST(_fp->cv_from_v_e(v, e), cv, tol);
  ABS_TEST(
      _fp->c_from_v_e(v, e),
      std::sqrt(bulk_modulus / _fp->rho_from_p_T(_fp->p_from_v_e(v, e), _fp->T_from_v_e(v, e))),
      tol);
  ABS_TEST(_fp->k_from_v_e(v, e), thermal_cond, tol);
  ABS_TEST(_fp->s_from_v_e(v, e), entropy, tol);
  ABS_TEST(_fp->T_from_v_e(v, e), T, tol);
  ABS_TEST(_fp->T_from_p_h(p, _fp->h_from_p_T(p, T)), T, tol);
  ABS_TEST(_fp->T_from_p_rho(p, 1. / v), T, tol);
  ABS_TEST(_fp->p_from_v_e(v, e),
           bulk_modulus * (thermal_exp * _fp->T_from_v_e(v, e) + std::log(1 / (v * density0))),
           tol);
  ABS_TEST(_fp->mu_from_v_e(v, e), visc, tol);
}

/**
 * Verify calculation of the derivatives by comparing with finite
 * differences
 */
TEST_F(SimpleFluidPropertiesTest, derivatives)
{
  const Real tol = REL_TOL_DERIVATIVE;

  Real p = 1.0E7;
  Real T = 10.0;
  Real e = 8.372E5;
  Real v = 1.25E-3;

  DERIV_TEST(_fp->rho_from_p_T, p, T, tol);
  DERIV_TEST(_fp->mu_from_p_T, p, T, tol);
  DERIV_TEST(_fp->e_from_p_T, p, T, tol);
  DERIV_TEST(_fp->e_from_p_rho, p, 1. / v, tol);
  DERIV_TEST(_fp->h_from_p_T, p, T, tol);
  DERIV_TEST(_fp->k_from_p_T, p, T, tol);
  DERIV_TEST(_fp->cp_from_p_T, p, T, tol);
  DERIV_TEST(_fp->cv_from_p_T, p, T, tol);
  DERIV_TEST(_fp->c_from_p_T, p, T, tol);
  DERIV_TEST(_fp->s_from_p_T, p, T, tol);
  DERIV_TEST(_fp->cp_from_v_e, v, e, tol);
  DERIV_TEST(_fp->cv_from_v_e, v, e, tol);
  DERIV_TEST(_fp->c_from_v_e, v, e, tol);
  DERIV_TEST(_fp->k_from_v_e, v, e, tol);
  DERIV_TEST(_fp->s_from_v_e, v, e, tol);
  DERIV_TEST(_fp->T_from_v_e, v, e, tol);
  DERIV_TEST(_fp->T_from_p_rho, p, 1. / v, tol);
  DERIV_TEST(_fp->p_from_v_e, v, e, tol);
  DERIV_TEST(_fp->mu_from_v_e, v, e, tol);

  p = 5.0E7;
  T = 90.0;
  e = 1.6744E6;
  v = 6.25E-4;

  DERIV_TEST(_fp->rho_from_p_T, p, T, tol);
  DERIV_TEST(_fp->mu_from_p_T, p, T, tol);
  DERIV_TEST(_fp->e_from_p_T, p, T, tol);
  DERIV_TEST(_fp->e_from_p_rho, p, 1. / v, tol);
  DERIV_TEST(_fp->h_from_p_T, p, T, tol);
  DERIV_TEST(_fp->k_from_p_T, p, T, tol);
  DERIV_TEST(_fp->cp_from_p_T, p, T, tol);
  DERIV_TEST(_fp->cv_from_p_T, p, T, tol);
  DERIV_TEST(_fp->c_from_p_T, p, T, tol);
  DERIV_TEST(_fp->s_from_p_T, p, T, tol);
  DERIV_TEST(_fp->cp_from_v_e, v, e, tol);
  DERIV_TEST(_fp->cv_from_v_e, v, e, tol);
  DERIV_TEST(_fp->c_from_v_e, v, e, tol);
  DERIV_TEST(_fp->k_from_v_e, v, e, tol);
  DERIV_TEST(_fp->s_from_v_e, v, e, tol);
  DERIV_TEST(_fp->T_from_v_e, v, e, tol);
  DERIV_TEST(_fp->T_from_p_rho, p, 1. / v, tol);
  DERIV_TEST(_fp->p_from_v_e, v, e, tol);
  DERIV_TEST(_fp->mu_from_v_e, v, e, tol);
}

/**
 * Verify that the methods that return multiple properties in one call return identical
 * values as the individual methods
 */
TEST_F(SimpleFluidPropertiesTest, combined)
{
  const Real p = 1.0e6;
  const Real T = 300.0;
  const Real tol = REL_TOL_CONSISTENCY;

  // Single property methods
  Real rho, drho_dp, drho_dT;
  _fp->rho_from_p_T(p, T, rho, drho_dp, drho_dT);
  Real mu, dmu_dp, dmu_dT;
  _fp->mu_from_p_T(p, T, mu, dmu_dp, dmu_dT);
  Real e, de_dp, de_dT;
  _fp->e_from_p_T(p, T, e, de_dp, de_dT);

  // Combined property methods
  Real rho2, drho2_dp, drho2_dT, mu2, dmu2_dp, dmu2_dT, e2, de2_dp, de2_dT;
  _fp->rho_mu_from_p_T(p, T, rho2, mu2);

  ABS_TEST(rho, rho2, tol);
  ABS_TEST(mu, mu2, tol);

  _fp->rho_mu_from_p_T(p, T, rho2, drho2_dp, drho2_dT, mu2, dmu2_dp, dmu2_dT);
  ABS_TEST(rho, rho2, tol);
  ABS_TEST(drho_dp, drho2_dp, tol);
  ABS_TEST(drho_dT, drho2_dT, tol);
  ABS_TEST(mu, mu2, tol);
  ABS_TEST(dmu_dp, dmu2_dp, tol);
  ABS_TEST(dmu_dT, dmu2_dT, tol);

  _fp->rho_e_from_p_T(p, T, rho2, drho2_dp, drho2_dT, e2, de2_dp, de2_dT);
  ABS_TEST(rho, rho2, tol);
  ABS_TEST(drho_dp, drho2_dp, tol);
  ABS_TEST(drho_dT, drho2_dT, tol);
  ABS_TEST(e, e2, tol);
  ABS_TEST(de_dp, de2_dp, tol);
  ABS_TEST(de_dT, de2_dT, tol);
}
<|endoftext|>


<commit_before>#include "condor_common.h"

#include <algorithm>
#include "ranger.h"

///// ranger insert/erase/find implementation /////

ranger::iterator ranger::insert(ranger::range r)
{
    // lower_bound here will coalesce an adjacent disjoint range;
    // can use upper_bound instead to avoid this and leave them fractured
    iterator it_start = lower_bound(r._start);
    iterator it = it_start;
    while (it != end() && it->_start <= r._end)  // '<' for no coalesce
        ++it;

    iterator it_end = it;
    if (it_start == it_end)
        return forest.insert(it_end, r);

    if (it_start->contains(r))
        return it_start;

    iterator it_back = --it;
    range rr_new = { std::min(it_start->_start, r._start),
                     std::max(it_back->_end, r._end) };

    // avoid erase+insert if only expanding a range
    if (it_start == it_back) {
        it_start->_start = rr_new._start;
        it_start->_end = rr_new._end;
        return it_start;
    }

    iterator hint = forest.erase(it_start, it_end);

    return forest.insert(hint, rr_new);
}

ranger::iterator ranger::erase(ranger::range r)
{
    iterator it_start = upper_bound(r._start);
    iterator it = it_start;
    while (it != end() && it->_start < r._end)
        ++it;

    iterator it_end = it;
    if (it_start == it_end)
        return it_start;

    iterator it_back = --it;
    range rr_back  = *it_back;

    if (it_start->_start < r._start) {
        it_start->_end = r._start;
        ++it_start;
    }

    if (r._end < rr_back._end) {
        if (it_start == it_end) {
            return forest.insert(it_end, range(r._end, rr_back._end));
        } else {
            it_back->_start = r._end;
            --it_end;
        }
    }

    return it_start == it_end ? it_end : forest.erase(it_start, it_end);
}

std::pair<ranger::iterator, bool>
ranger::find(element_type x) const
{
    iterator it = upper_bound(x);
    return {it, it != end() && it->_start <= x};
}

bool ranger::contains(element_type x) const
{
    return find(x).second;
}

ranger::ranger(const std::initializer_list<ranger::range> &il)
{
    for (const range &rr : il)
        insert(rr);
}

// specialize lower_bound / upper_bound based on forest type
static inline std::set<ranger::range>::const_iterator
lower_bounder(const std::set<ranger::range> &f, ranger::range rr)
{
    return f.lower_bound(rr);
}

static inline std::set<ranger::range>::const_iterator
upper_bounder(const std::set<ranger::range> &f, ranger::range rr)
{
    return f.upper_bound(rr);
}

static inline std::vector<ranger::range>::const_iterator
lower_bounder(const std::vector<ranger::range> &f, ranger::range rr)
{
    return std::lower_bound(f.begin(), f.end(), rr);
}

static inline std::vector<ranger::range>::const_iterator
upper_bounder(const std::vector<ranger::range> &f, ranger::range rr)
{
    return std::upper_bound(f.begin(), f.end(), rr);
}

ranger::iterator ranger::lower_bound(element_type x) const
{
    return lower_bounder(forest, x);
}

ranger::iterator ranger::upper_bound(element_type x) const
{
    return upper_bounder(forest, x);
}

///// ranger::elements::iterator implementation /////

/* This allows:
 *
 *      for (int i : myranger.get_elements())
 *          process_int(i);
 *
 *
 * Instead of the still-straightforward:
 *
 *      for (auto &rr : myranger)
 *          for (int i : rr)
 *              process_int(i);
 */

void ranger::elements::iterator::mk_valid()
{
    if (!rit_valid) {
        rit = sit->begin();
        rit_valid = true;
    }
}

ranger::element_type ranger::elements::iterator::operator*()
{
    mk_valid();
    return *rit;
}

ranger::elements::iterator &ranger::elements::iterator::operator++()
{
    mk_valid();
    if (++rit == sit->end()) {
        ++sit;
        rit_valid = false;
    }
    return *this;
}

ranger::elements::iterator &ranger::elements::iterator::operator--()
{
    mk_valid();
    if (rit == sit->begin()) {
        --sit;
        rit = sit->end();
        --rit;
    }
    return *this;
}

bool ranger::elements::iterator::operator==(iterator &it)
{
    if (sit != it.sit)
        return false;
    if (!rit_valid && !it.rit_valid)
        return true;
    // at this point neither sit nor it.sit points to the end() of its set,
    // thus it's OK to call mk_valid() on each, which may dereference *sit
    mk_valid();
    it.mk_valid();
    return rit == it.rit;
}

bool ranger::elements::iterator::operator!=(iterator &it)
{
    return !(*this == it);
}

///// ranger persist/load implementation /////

#include <stdlib.h> // strtol
#include <stdio.h>  // sprintf
#include <string>

/*  persist / load ranger objects
 *
 *  The serialized format is one or more sub-ranges, separated by semicolons,
 *  where each sub-range is either N-M (for inclusive N..M) or N for a single
 *  integer.  Eg, "2", "5-10", "4;7;10-20;44;50-60"
 */

static
void persist_range_single(std::string &s, const ranger::range &rr)
{
    char buf[64];
    int n;
    if (rr._start == rr._end - 1)
        n = sprintf(buf, "%d;", rr._start);
    else
        n = sprintf(buf, "%d-%d;", rr._start, rr._end - 1);
    s.append(buf, n);
}

void persist(std::string &s, const ranger &r)
{
    s.clear();
    if (r.empty())
        return;

    for (auto &rr : r)
        persist_range_single(s, rr);

    s.erase(s.size() - 1);
}

void persist_range(std::string &s, const ranger &r, const ranger::range &rr)
{
    s.clear();
    if (r.empty())
        return;

    auto rit = r.find(rr._start).first;
    for (; rit != r.end() && rit->_start < rr._end; ++rit) {
        ranger::range rr_new = { std::max(rit->_start, rr._start),
                                 std::min(rit->_end,   rr._end) };
        persist_range_single(s, rr_new);
    }

    s.erase(s.size() - 1);
}

void persist_slice(std::string &s, const ranger &r, int start, int back)
{
    persist_range(s, r, {start, back+1});
}

// return 0 on success, (-1 - (position in string)) on parse failure
int load(ranger &r, const char *s)
{
    const char *sstart = s;
    while (*s) {
        char *sp;
        int start = strtol(s, &sp, 10);
        int back;
        if (s == sp)
            // no int parsed is ok as long as we're at the end
            return *s ? -1 - int(s - sstart) : 0;
        s = sp;
        if (*sp == '-') {
            s++;
            back = strtol(s, &sp, 10);
            if (s == sp)
                // a number should have followed '-'
                return -1 - int(s - sstart);
            s = sp;
        } else {
            back = start;
        }
        if (*s == ';')
            s++;
        else if (*s)
            // expected either ';' or end of string
            return -1 - int(s - sstart);
        r.insert({start, back + 1});
    }
    return 0;
}

<commit_msg>an alternate optimization for ranger::erase<commit_after>#include "condor_common.h"

#include <algorithm>
#include "ranger.h"

///// ranger insert/erase/find implementation /////

ranger::iterator ranger::insert(ranger::range r)
{
    // lower_bound here will coalesce an adjacent disjoint range;
    // can use upper_bound instead to avoid this and leave them fractured
    iterator it_start = lower_bound(r._start);
    iterator it = it_start;
    while (it != end() && it->_start <= r._end)  // '<' for no coalesce
        ++it;

    iterator it_end = it;
    if (it_start == it_end)
        return forest.insert(it_end, r);

    if (it_start->contains(r))
        return it_start;

    iterator it_back = --it;
    range rr_new = { std::min(it_start->_start, r._start),
                     std::max(it_back->_end, r._end) };

    // avoid erase+insert if only expanding a range
    if (it_start == it_back) {
        it_start->_start = rr_new._start;
        it_start->_end = rr_new._end;
        return it_start;
    }

    iterator hint = forest.erase(it_start, it_end);

    return forest.insert(hint, rr_new);
}

ranger::iterator ranger::erase(ranger::range r)
{
    iterator it_start = upper_bound(r._start);
    iterator it = it_start;
    while (it != end() && it->_start < r._end)
        ++it;

    iterator it_end = it;
    if (it_start == it_end)
        return it_start;

    iterator it_back = --it;
    range rr_back = *it_back;

    if (it_start->_start < r._start && r._end < it_start->_end) {
        // split a single range
        it_start->_end = r._start;
        return forest.insert(it_end, range(r._end, rr_back._end));
    }

    if (it_start->_start < r._start) {
        it_start->_end = r._start;
        ++it_start;
    }

    if (r._end < rr_back._end) {
        it_back->_start = r._end;
        --it_end;
    }

    return it_start == it_end ? it_end : forest.erase(it_start, it_end);
}

std::pair<ranger::iterator, bool>
ranger::find(element_type x) const
{
    iterator it = upper_bound(x);
    return {it, it != end() && it->_start <= x};
}

bool ranger::contains(element_type x) const
{
    return find(x).second;
}

ranger::ranger(const std::initializer_list<ranger::range> &il)
{
    for (const range &rr : il)
        insert(rr);
}

// specialize lower_bound / upper_bound based on forest type
static inline std::set<ranger::range>::const_iterator
lower_bounder(const std::set<ranger::range> &f, ranger::range rr)
{
    return f.lower_bound(rr);
}

static inline std::set<ranger::range>::const_iterator
upper_bounder(const std::set<ranger::range> &f, ranger::range rr)
{
    return f.upper_bound(rr);
}

static inline std::vector<ranger::range>::const_iterator
lower_bounder(const std::vector<ranger::range> &f, ranger::range rr)
{
    return std::lower_bound(f.begin(), f.end(), rr);
}

static inline std::vector<ranger::range>::const_iterator
upper_bounder(const std::vector<ranger::range> &f, ranger::range rr)
{
    return std::upper_bound(f.begin(), f.end(), rr);
}

ranger::iterator ranger::lower_bound(element_type x) const
{
    return lower_bounder(forest, x);
}

ranger::iterator ranger::upper_bound(element_type x) const
{
    return upper_bounder(forest, x);
}

///// ranger::elements::iterator implementation /////

/* This allows:
 *
 *      for (int i : myranger.get_elements())
 *          process_int(i);
 *
 *
 * Instead of the still-straightforward:
 *
 *      for (auto &rr : myranger)
 *          for (int i : rr)
 *              process_int(i);
 */

void ranger::elements::iterator::mk_valid()
{
    if (!rit_valid) {
        rit = sit->begin();
        rit_valid = true;
    }
}

ranger::element_type ranger::elements::iterator::operator*()
{
    mk_valid();
    return *rit;
}

ranger::elements::iterator &ranger::elements::iterator::operator++()
{
    mk_valid();
    if (++rit == sit->end()) {
        ++sit;
        rit_valid = false;
    }
    return *this;
}

ranger::elements::iterator &ranger::elements::iterator::operator--()
{
    mk_valid();
    if (rit == sit->begin()) {
        --sit;
        rit = sit->end();
        --rit;
    }
    return *this;
}

bool ranger::elements::iterator::operator==(iterator &it)
{
    if (sit != it.sit)
        return false;
    if (!rit_valid && !it.rit_valid)
        return true;
    // at this point neither sit nor it.sit points to the end() of its set,
    // thus it's OK to call mk_valid() on each, which may dereference *sit
    mk_valid();
    it.mk_valid();
    return rit == it.rit;
}

bool ranger::elements::iterator::operator!=(iterator &it)
{
    return !(*this == it);
}

///// ranger persist/load implementation /////

#include <stdlib.h> // strtol
#include <stdio.h>  // sprintf
#include <string>

/*  persist / load ranger objects
 *
 *  The serialized format is one or more sub-ranges, separated by semicolons,
 *  where each sub-range is either N-M (for inclusive N..M) or N for a single
 *  integer.  Eg, "2", "5-10", "4;7;10-20;44;50-60"
 */

static
void persist_range_single(std::string &s, const ranger::range &rr)
{
    char buf[64];
    int n;
    if (rr._start == rr._end - 1)
        n = sprintf(buf, "%d;", rr._start);
    else
        n = sprintf(buf, "%d-%d;", rr._start, rr._end - 1);
    s.append(buf, n);
}

void persist(std::string &s, const ranger &r)
{
    s.clear();
    if (r.empty())
        return;

    for (auto &rr : r)
        persist_range_single(s, rr);

    s.erase(s.size() - 1);
}

void persist_range(std::string &s, const ranger &r, const ranger::range &rr)
{
    s.clear();
    if (r.empty())
        return;

    auto rit = r.find(rr._start).first;
    for (; rit != r.end() && rit->_start < rr._end; ++rit) {
        ranger::range rr_new = { std::max(rit->_start, rr._start),
                                 std::min(rit->_end,   rr._end) };
        persist_range_single(s, rr_new);
    }

    s.erase(s.size() - 1);
}

void persist_slice(std::string &s, const ranger &r, int start, int back)
{
    persist_range(s, r, {start, back+1});
}

// return 0 on success, (-1 - (position in string)) on parse failure
int load(ranger &r, const char *s)
{
    const char *sstart = s;
    while (*s) {
        char *sp;
        int start = strtol(s, &sp, 10);
        int back;
        if (s == sp)
            // no int parsed is ok as long as we're at the end
            return *s ? -1 - int(s - sstart) : 0;
        s = sp;
        if (*sp == '-') {
            s++;
            back = strtol(s, &sp, 10);
            if (s == sp)
                // a number should have followed '-'
                return -1 - int(s - sstart);
            s = sp;
        } else {
            back = start;
        }
        if (*s == ';')
            s++;
        else if (*s)
            // expected either ';' or end of string
            return -1 - int(s - sstart);
        r.insert({start, back + 1});
    }
    return 0;
}

<|endoftext|>