<commit_before>#define FTS_FUZZY_MATCH_IMPLEMENTATION
#include <QtWidgets>
#include "mainwindow.h"
#include <fts_fuzzy_match.h>
#include <glob.h>
#include <string>
#include <map>
#include <database.h>

Window::Window(QWidget *parent) : QMainWindow(parent)
{
    // Initalise database
    db.setDatabaseName("recipes.db");

    // Initialise widgets
    searchBox = new SearchBox();
    searchBox->setPlaceholderText("Search for recipes");
    searchBox->setClearButtonEnabled(true);
    recipeBox = new QComboBox();
    populateRecipeBox(recipeBox);
    createRecipeListWidget();
    numResults = new QLabel();
    recipeView = new QWebEngineView();

    // Set layout
    centralWidget = new QWidget();
    QGridLayout *sidebar = new QGridLayout();
    sidebar->addWidget(searchBox, 0, 0, 1, 2);
    sidebar->addWidget(numResults, 1, 0, 1, 1);
    sidebar->addWidget(recipeBox, 1, 1, 1, 1);
    sidebar->addWidget(recipeList, 2, 0, 1, 2);

    QHBoxLayout *mainLayout = new QHBoxLayout(centralWidget);
    mainLayout->addLayout(sidebar, 1);
    mainLayout->addWidget(recipeView, 3);

    centralWidget->setLayout(mainLayout);
    centralWidget->show();
    setCentralWidget(centralWidget);

    // Create menus
    optionsMenu = new QMenu("Options");
    updateDb = new QAction("Update database", this);
    connect(updateDb, &QAction::triggered, this, &Window::updateDatabase);
    cleanDb = new QAction("Clean database", this);
    connect(cleanDb, &QAction::triggered, this, &Window::cleanDatabase);
    optionsMenu->addAction(updateDb);
    optionsMenu->addAction(cleanDb);
    menuBar()->addMenu(optionsMenu);

    // Set window paramters
    setWindowTitle(tr("Find Recipes"));
    setMinimumSize(940, 400);

    // Set signals
    connect(recipeList, &QListWidget::itemClicked, this, &Window::openFile);
    connect(searchBox, SIGNAL(inputText(QString)), this, SLOT(updateRecipesDiplay(QString)));
    connect(searchBox, SIGNAL(returnPressed()), recipeList, SLOT(setFocus()));
    connect(recipeBox, SIGNAL(currentTextChanged(QString)), searchBox, SLOT(recipeFiterChanged(QString)));

    // Update on startup
    updateDatabase();
}

// Get list of files according to glob patternn
QStringList globVector(const std::string& pattern){
    glob_t glob_result;
    glob(pattern.c_str(),GLOB_TILDE,NULL,&glob_result);
    QStringList files;
    for(unsigned int i=0; i<glob_result.gl_pathc; ++i){
        files << QString(glob_result.gl_pathv[i]);
    }
    globfree(&glob_result);
    return files;
}

void SearchBox::recipeFiterChanged(QString newFilter){
    Q_UNUSED(newFilter);
    // When the recipe filter changes, emit this signal to call updateRecipeDisplay
    emit inputText(text());
}

void SearchBox::keyPressEvent(QKeyEvent *evt){
    QLineEdit::keyPressEvent(evt);
    setPlaceholderText("Search for recipes");
    // When the search changes, emit this signal to call updateRecipeDisplay
    emit inputText(text());
}

void Window::populateRecipeBox(QComboBox* box){
    // Open database
    db.open();
    // Prepare query
    QSqlQuery query = QSqlQuery();
    query.prepare("SELECT CATEGORY, COUNT(*) FROM RECIPES GROUP BY CATEGORY ORDER BY CATEGORY");
    query.setForwardOnly(true);
    query.exec();

    box->addItem("All Recipes");
    while(query.next()){
        box->addItem(query.value("CATEGORY").toString());
    }
    db.close();
}

void Window::updateRecipesDiplay(QString searchText){
    recipeList->clear();
    QList<QListWidgetItem*> recipes;

    if (searchText.isEmpty()) {
        recipes = getAllRecipes();
        for (int i=0; i<recipes.size(); ++i){
            recipeList->addItem(recipes[i]);
        }
        recipeList->sortItems();

    }else{
        recipes = getMatchingRecipes(searchText);
        for (int i=0; i<recipes.size(); ++i){
            recipeList->addItem(recipes[i]);
        }
    }

    recipeList->setDragEnabled(false);

    QString text = QString("%1 recipes").arg(recipes.size());
    if (recipes.size() == 1){
        text = "1 recipe";
    }
    numResults->setText(text);
}

QList<QListWidgetItem*> Window::getAllRecipes(){
    QList<QListWidgetItem*> recipes;

    // Open database and execute query
    db.open();
    // Prepare query based on filter
    QSqlQuery query = QSqlQuery();
    if(recipeBox->currentText() != "All Recipes"){
        QString category = recipeBox->currentText();
        query.prepare("SELECT TITLE, IMG_PATH, HTML_PATH FROM RECIPES WHERE CATEGORY = :category");
        query.bindValue(":category", category);
        query.setForwardOnly(true);
    }else{
        query.prepare("SELECT TITLE, IMG_PATH, HTML_PATH FROM RECIPES");
        query.setForwardOnly(true);
    }
    // Execute query
    query.exec();

    while(query.next()){
        // Extract info from query results
        QString title = query.value("TITLE").toString();
        QString img_path = query.value("IMG_PATH").toString();
        QString html_path = query.value("HTML_PATH").toString();

        // Create QListWidgetItems
        QListWidgetItem *recipe = new QListWidgetItem;
        recipe->setText(title);
        recipe->setData(Qt::UserRole, html_path);

        QImage *img = new QImage();
        bool loaded = img->load(img_path);
        if (loaded){
            recipe->setIcon(QPixmap::fromImage(*img));
        }else{
            // If image doesn't exist, use placeholder image
            bool loaded = img->load("./images/Placeholder.jpg");
            if (loaded){
                recipe->setIcon(QPixmap::fromImage(*img));
            }
        }
        recipes.append(recipe);
    }
    db.close();
    return recipes;
}

QList<QListWidgetItem*> Window::getMatchingRecipes(QString searchText){
    QList<QListWidgetItem*> recipes;

    // Get matching recipes and their scores. The QStringList contains title, img_path, file_path in order.
    std::map<double, QStringList> matchingRecipes = findMatches(searchText);
    // Build QListWidgetItems and add to QList
    // By default the map should be in ascending order, so use reverse iterator to get highest matches first
    for (auto iter = matchingRecipes.rbegin(); iter != matchingRecipes.rend(); ++iter){

        QString title = iter->second[0];
        QString img_path = iter->second[1];
        QString html_path = iter->second[2];

        QListWidgetItem *recipe = new QListWidgetItem;
        recipe->setText(title);
        recipe->setData(Qt::UserRole, html_path);

        QImage *img = new QImage();
        bool loaded = img->load(img_path);
        if (loaded){
            recipe->setIcon(QPixmap::fromImage(*img));
        }else{
            // If image doesn't exist, use placeholder image
            bool loaded = img->load("./images/Placeholder.jpg");
            if (loaded){
                recipe->setIcon(QPixmap::fromImage(*img));
            }
        }
        recipes.append(recipe);
    }

    return recipes;
}

std::map<double, QStringList> Window::findMatches(QString text)
{
    // Open database
    db.open();
    // Prepare query based on filter
    QSqlQuery query = QSqlQuery();
    if(recipeBox->currentText() != "All Recipes"){
        QString category = recipeBox->currentText();
        query.prepare("SELECT TITLE, IMG_PATH, HTML_PATH FROM RECIPES WHERE CATEGORY = :category");
        query.bindValue(":category", category);
        query.setForwardOnly(true);
    }else{
        query.prepare("SELECT TITLE, IMG_PATH, HTML_PATH FROM RECIPES");
        query.setForwardOnly(true);
    }
    // Execute query
    query.exec();

    // Get matching files and their scores
    std::map<double, QStringList> matchingFiles;
    std::string txtstr = text.toStdString();
    while(query.next()){
        int score;
        QString title = query.value("TITLE").toString();
        QString img_path = query.value("IMG_PATH").toString().replace("\'", "").replace(",", "");
        QString file_path = query.value("HTML_PATH").toString();

        std::string titlestr = title.toStdString();
        if (fts::fuzzy_match(txtstr.c_str(), titlestr.c_str(), score)){
            // If a map entry already has the current score, increase score by 0.01.
            double dbscore = (double)score;
            if (matchingFiles.count(dbscore) > 0){
                dbscore += 0.01;
            }
            matchingFiles[dbscore] = QStringList() << title << img_path << file_path;
        }
    }
    db.close();
    return matchingFiles;
}

void Window::createRecipeListWidget()
{
    recipeList = new QListWidget();
    recipeList->setViewMode(QListView::IconMode);
    recipeList->setGridSize(QSize(212, int(212/1.51)) );
    recipeList->setIconSize(QSize(199, int(199/1.78)) );
    recipeList->setWordWrap(true);
    recipeList->setTextElideMode(Qt::ElideNone);
    recipeList->horizontalScrollBar()->setEnabled(false);
    recipeList->horizontalScrollBar()->setVisible(false);
}

void Window::openFile(QListWidgetItem *recipe)
{
    // Read hidden data to find full file path
    QString path = recipe->data(Qt::UserRole).toString();
    QString url = "file://" + currentDir.absoluteFilePath(path);
    recipeView->load(url);
}

void Window::updateDatabase(){
    int num_updates = db_ops::update_database(&db);
    QString updated_text;
    if (num_updates == 0){
        updated_text = "Search for recipes";
    }else{
        updated_text = "Search for recipes - Updated!";
    }
    searchBox->setPlaceholderText(updated_text);
    // Repopulate list
    updateRecipesDiplay("");
}

void Window::cleanDatabase(){
    int num_removals = db_ops::clean_database(&db);
    QString cleaned_text;
    if (num_removals == 1){
        cleaned_text = QString("Search for recipes - Removed 1 recipe!");
    }else{
        cleaned_text = QString("Search for recipes - Removed %1 recipes!").arg(num_removals);
    }
    searchBox->setPlaceholderText(cleaned_text);
    // Repopulate list
    updateRecipesDiplay("");
}

void Window::resizeEvent(QResizeEvent *event){
    Q_UNUSED(event);
    int iconWidth, iconHeight, gridWidth, gridHeight;
    double gridRatio = 1.51;
    double iconRatio = 1.78;
    QSize recipeListSize = recipeList->size();

    // Set gridwith based on recipeList size and ensure it doesn't go below minimum value
    gridWidth = qMax(int(recipeListSize.width()) - 17.0, 212.0);
    // Calculate other parameters based on ratios of default values.
    gridHeight = int(gridWidth/gridRatio);
    iconWidth = gridWidth - 13;
    iconHeight = int(iconWidth/iconRatio);

    recipeList->setIconSize(QSize(iconWidth, iconHeight));
    recipeList->setGridSize(QSize(gridWidth, gridHeight));
    recipeList->setUniformItemSizes(true);
}

<commit_msg>Add recipe count to combobox for recipe categories<commit_after>#define FTS_FUZZY_MATCH_IMPLEMENTATION
#include <QtWidgets>
#include "mainwindow.h"
#include <fts_fuzzy_match.h>
#include <glob.h>
#include <string>
#include <map>
#include <database.h>

Window::Window(QWidget *parent) : QMainWindow(parent)
{
    // Initalise database
    db.setDatabaseName("recipes.db");

    // Initialise widgets
    searchBox = new SearchBox();
    searchBox->setPlaceholderText("Search for recipes");
    searchBox->setClearButtonEnabled(true);
    recipeBox = new QComboBox();
    populateRecipeBox(recipeBox);
    createRecipeListWidget();
    numResults = new QLabel();
    recipeView = new QWebEngineView();

    // Set layout
    centralWidget = new QWidget();
    QGridLayout *sidebar = new QGridLayout();
    sidebar->addWidget(searchBox, 0, 0, 1, 2);
    sidebar->addWidget(numResults, 1, 0, 1, 1);
    sidebar->addWidget(recipeBox, 1, 1, 1, 1);
    sidebar->addWidget(recipeList, 2, 0, 1, 2);

    QHBoxLayout *mainLayout = new QHBoxLayout(centralWidget);
    mainLayout->addLayout(sidebar, 1);
    mainLayout->addWidget(recipeView, 3);

    centralWidget->setLayout(mainLayout);
    centralWidget->show();
    setCentralWidget(centralWidget);

    // Create menus
    optionsMenu = new QMenu("Options");
    updateDb = new QAction("Update database", this);
    connect(updateDb, &QAction::triggered, this, &Window::updateDatabase);
    cleanDb = new QAction("Clean database", this);
    connect(cleanDb, &QAction::triggered, this, &Window::cleanDatabase);
    optionsMenu->addAction(updateDb);
    optionsMenu->addAction(cleanDb);
    menuBar()->addMenu(optionsMenu);

    // Set window paramters
    setWindowTitle(tr("Find Recipes"));
    setMinimumSize(940, 400);

    // Set signals
    connect(recipeList, &QListWidget::itemClicked, this, &Window::openFile);
    connect(searchBox, SIGNAL(inputText(QString)), this, SLOT(updateRecipesDiplay(QString)));
    connect(searchBox, SIGNAL(returnPressed()), recipeList, SLOT(setFocus()));
    connect(recipeBox, SIGNAL(currentTextChanged(QString)), searchBox, SLOT(recipeFiterChanged(QString)));

    // Update on startup
    updateDatabase();
}

// Get list of files according to glob patternn
QStringList globVector(const std::string& pattern){
    glob_t glob_result;
    glob(pattern.c_str(),GLOB_TILDE,NULL,&glob_result);
    QStringList files;
    for(unsigned int i=0; i<glob_result.gl_pathc; ++i){
        files << QString(glob_result.gl_pathv[i]);
    }
    globfree(&glob_result);
    return files;
}

void SearchBox::recipeFiterChanged(QString newFilter){
    Q_UNUSED(newFilter);
    // When the recipe filter changes, emit this signal to call updateRecipeDisplay
    emit inputText(text());
}

void SearchBox::keyPressEvent(QKeyEvent *evt){
    QLineEdit::keyPressEvent(evt);
    setPlaceholderText("Search for recipes");
    // When the search changes, emit this signal to call updateRecipeDisplay
    emit inputText(text());
}

void Window::populateRecipeBox(QComboBox* box){
    // Open database
    db.open();
    // Prepare query
    QSqlQuery query = QSqlQuery();
    query.prepare("SELECT CATEGORY, COUNT(*) FROM RECIPES GROUP BY CATEGORY ORDER BY CATEGORY");
    query.setForwardOnly(true);
    query.exec();

    box->addItem("All Recipes");
    while(query.next()){
        QString entry = query.value("CATEGORY").toString() + " [" + query.value(1).toString() + "]";
        box->addItem(entry);
    }
    db.close();
}

void Window::updateRecipesDiplay(QString searchText){
    recipeList->clear();
    QList<QListWidgetItem*> recipes;

    if (searchText.isEmpty()) {
        recipes = getAllRecipes();
        for (int i=0; i<recipes.size(); ++i){
            recipeList->addItem(recipes[i]);
        }
        recipeList->sortItems();

    }else{
        recipes = getMatchingRecipes(searchText);
        for (int i=0; i<recipes.size(); ++i){
            recipeList->addItem(recipes[i]);
        }
    }

    recipeList->setDragEnabled(false);

    QString text = QString("%1 recipes").arg(recipes.size());
    if (recipes.size() == 1){
        text = "1 recipe";
    }
    numResults->setText(text);
}

QList<QListWidgetItem*> Window::getAllRecipes(){
    QList<QListWidgetItem*> recipes;

    // Open database and execute query
    db.open();
    // Prepare query based on filter
    QSqlQuery query = QSqlQuery();
    if(recipeBox->currentText() != "All Recipes"){
        QString category = recipeBox->currentText().split(" [")[0];
        query.prepare("SELECT TITLE, IMG_PATH, HTML_PATH FROM RECIPES WHERE CATEGORY = :category");
        query.bindValue(":category", category);
        query.setForwardOnly(true);
    }else{
        query.prepare("SELECT TITLE, IMG_PATH, HTML_PATH FROM RECIPES");
        query.setForwardOnly(true);
    }
    // Execute query
    query.exec();

    while(query.next()){
        // Extract info from query results
        QString title = query.value("TITLE").toString();
        QString img_path = query.value("IMG_PATH").toString();
        QString html_path = query.value("HTML_PATH").toString();

        // Create QListWidgetItems
        QListWidgetItem *recipe = new QListWidgetItem;
        recipe->setText(title);
        recipe->setData(Qt::UserRole, html_path);

        QImage *img = new QImage();
        bool loaded = img->load(img_path);
        if (loaded){
            recipe->setIcon(QPixmap::fromImage(*img));
        }else{
            // If image doesn't exist, use placeholder image
            bool loaded = img->load("./images/Placeholder.jpg");
            if (loaded){
                recipe->setIcon(QPixmap::fromImage(*img));
            }
        }
        recipes.append(recipe);
    }
    db.close();
    return recipes;
}

QList<QListWidgetItem*> Window::getMatchingRecipes(QString searchText){
    QList<QListWidgetItem*> recipes;

    // Get matching recipes and their scores. The QStringList contains title, img_path, file_path in order.
    std::map<double, QStringList> matchingRecipes = findMatches(searchText);
    // Build QListWidgetItems and add to QList
    // By default the map should be in ascending order, so use reverse iterator to get highest matches first
    for (auto iter = matchingRecipes.rbegin(); iter != matchingRecipes.rend(); ++iter){

        QString title = iter->second[0];
        QString img_path = iter->second[1];
        QString html_path = iter->second[2];

        QListWidgetItem *recipe = new QListWidgetItem;
        recipe->setText(title);
        recipe->setData(Qt::UserRole, html_path);

        QImage *img = new QImage();
        bool loaded = img->load(img_path);
        if (loaded){
            recipe->setIcon(QPixmap::fromImage(*img));
        }else{
            // If image doesn't exist, use placeholder image
            bool loaded = img->load("./images/Placeholder.jpg");
            if (loaded){
                recipe->setIcon(QPixmap::fromImage(*img));
            }
        }
        recipes.append(recipe);
    }

    return recipes;
}

std::map<double, QStringList> Window::findMatches(QString text)
{
    // Open database
    db.open();
    // Prepare query based on filter
    QSqlQuery query = QSqlQuery();
    if(recipeBox->currentText() != "All Recipes"){
        QString category = recipeBox->currentText().split(" [")[0];
        query.prepare("SELECT TITLE, IMG_PATH, HTML_PATH FROM RECIPES WHERE CATEGORY = :category");
        query.bindValue(":category", category);
        query.setForwardOnly(true);
    }else{
        query.prepare("SELECT TITLE, IMG_PATH, HTML_PATH FROM RECIPES");
        query.setForwardOnly(true);
    }
    // Execute query
    query.exec();

    // Get matching files and their scores
    std::map<double, QStringList> matchingFiles;
    std::string txtstr = text.toStdString();
    while(query.next()){
        int score;
        QString title = query.value("TITLE").toString();
        QString img_path = query.value("IMG_PATH").toString().replace("\'", "").replace(",", "");
        QString file_path = query.value("HTML_PATH").toString();

        std::string titlestr = title.toStdString();
        if (fts::fuzzy_match(txtstr.c_str(), titlestr.c_str(), score)){
            // If a map entry already has the current score, increase score by 0.01.
            double dbscore = (double)score;
            if (matchingFiles.count(dbscore) > 0){
                dbscore += 0.01;
            }
            matchingFiles[dbscore] = QStringList() << title << img_path << file_path;
        }
    }
    db.close();
    return matchingFiles;
}

void Window::createRecipeListWidget()
{
    recipeList = new QListWidget();
    recipeList->setViewMode(QListView::IconMode);
    recipeList->setGridSize(QSize(212, int(212/1.51)) );
    recipeList->setIconSize(QSize(199, int(199/1.78)) );
    recipeList->setWordWrap(true);
    recipeList->setTextElideMode(Qt::ElideNone);
    recipeList->horizontalScrollBar()->setEnabled(false);
    recipeList->horizontalScrollBar()->setVisible(false);
}

void Window::openFile(QListWidgetItem *recipe)
{
    // Read hidden data to find full file path
    QString path = recipe->data(Qt::UserRole).toString();
    QString url = "file://" + currentDir.absoluteFilePath(path);
    recipeView->load(url);
}

void Window::updateDatabase(){
    int num_updates = db_ops::update_database(&db);
    QString updated_text;
    if (num_updates == 0){
        updated_text = "Search for recipes";
    }else{
        updated_text = "Search for recipes - Updated!";
    }
    searchBox->setPlaceholderText(updated_text);
    // Repopulate list
    updateRecipesDiplay("");
}

void Window::cleanDatabase(){
    int num_removals = db_ops::clean_database(&db);
    QString cleaned_text;
    if (num_removals == 1){
        cleaned_text = QString("Search for recipes - Removed 1 recipe!");
    }else{
        cleaned_text = QString("Search for recipes - Removed %1 recipes!").arg(num_removals);
    }
    searchBox->setPlaceholderText(cleaned_text);
    // Repopulate list
    updateRecipesDiplay("");
}

void Window::resizeEvent(QResizeEvent *event){
    Q_UNUSED(event);
    int iconWidth, iconHeight, gridWidth, gridHeight;
    double gridRatio = 1.51;
    double iconRatio = 1.78;
    QSize recipeListSize = recipeList->size();

    // Set gridwith based on recipeList size and ensure it doesn't go below minimum value
    gridWidth = qMax(int(recipeListSize.width()) - 17.0, 212.0);
    // Calculate other parameters based on ratios of default values.
    gridHeight = int(gridWidth/gridRatio);
    iconWidth = gridWidth - 13;
    iconHeight = int(iconWidth/iconRatio);

    recipeList->setIconSize(QSize(iconWidth, iconHeight));
    recipeList->setGridSize(QSize(gridWidth, gridHeight));
    recipeList->setUniformItemSizes(true);
}

<|endoftext|>


<commit_before>/**
 * \file
 * <!--
 * Copyright 2015 Develer S.r.l. (http://www.develer.com/)
 * -->
 *
 * \brief main cutecom-ng window
 *
 * \author Aurelien Rainone <aurelien@develer.org>
 */

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "connectdialog.h"
#include "sessionmanager.h"
#include "outputmanager.h"

#include <QTextEdit>
#include <QScrollBar>

const QString LINE_ENDING = "\r\n";

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(ui->connectButton, &QAbstractButton::clicked, this, &MainWindow::openConnectionDialog);

    // create session and output managers
    output_mgr = new OutputManager(this);
    session_mgr = new SessionManager(this);

    // handle new user input, and send it to the serial port via MainWindow::handleReturnPressed
    connect(ui->textInput, &QLineEdit::returnPressed, this, &MainWindow::handleReturnPressed);

    // let output manager handle new data coming from serial port
    connect(session_mgr, &SessionManager::dataReceived, output_mgr, &OutputManager::handleNewData);

    // get data formatted for display and show it in output view
    connect(output_mgr, &OutputManager::dataConverted, this, &MainWindow::addDataToView);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::openConnectionDialog()
{
    ConnectDialog dialog(this);

    connect(&dialog, &ConnectDialog::openDeviceClicked, session_mgr, &SessionManager::openSession);
    dialog.exec();
}

void MainWindow::handleReturnPressed()
{
    // if session is not open, this also keeps user input
    if (session_mgr->isSessionOpen())
    {
        QString line = ui->textInput->text() + LINE_ENDING;
        session_mgr->sendToSerial(line.toLocal8Bit());
        ui->textInput->clear();
    }
}

void MainWindow::addDataToView(const QString & textdata)
{
    // save current text selection
    QTextCursor cursor = ui->textOutput->textCursor();

    // insert data at end of 'edit' (but this clears any selection)
    ui->textOutput->moveCursor(QTextCursor::End);
    ui->textOutput->insertPlainText (textdata);

    // revert text selection
    ui->textOutput->setTextCursor(cursor);

    // push scroll to the bottom
    QScrollBar *vbar = ui->textOutput->verticalScrollBar();
    vbar->setValue(vbar->maximum());
}
<commit_msg>remove unused include, fix coding style<commit_after>/**
 * \file
 * <!--
 * Copyright 2015 Develer S.r.l. (http://www.develer.com/)
 * -->
 *
 * \brief main cutecom-ng window
 *
 * \author Aurelien Rainone <aurelien@develer.org>
 */

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "connectdialog.h"
#include "sessionmanager.h"
#include "outputmanager.h"

#include <QScrollBar>

const QString LINE_ENDING = "\r\n";

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(ui->connectButton, &QAbstractButton::clicked, this, &MainWindow::openConnectionDialog);

    // create session and output managers
    output_mgr = new OutputManager(this);
    session_mgr = new SessionManager(this);

    // handle new user input, and send it to the serial port via MainWindow::handleReturnPressed
    connect(ui->textInput, &QLineEdit::returnPressed, this, &MainWindow::handleReturnPressed);

    // let output manager handle new data coming from serial port
    connect(session_mgr, &SessionManager::dataReceived, output_mgr, &OutputManager::handleNewData);

    // get data formatted for display and show it in output view
    connect(output_mgr, &OutputManager::dataConverted, this, &MainWindow::addDataToView);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::openConnectionDialog()
{
    ConnectDialog dialog(this);

    connect(&dialog, &ConnectDialog::openDeviceClicked, session_mgr, &SessionManager::openSession);
    dialog.exec();
}

void MainWindow::handleReturnPressed()
{
    // if session is not open, this also keeps user input
    if (session_mgr->isSessionOpen())
    {
        QString line = ui->textInput->text() + LINE_ENDING;
        session_mgr->sendToSerial(line.toLocal8Bit());
        ui->textInput->clear();
    }
}

void MainWindow::addDataToView(const QString & textdata)
{
    // save current text selection
    QTextCursor cursor = ui->textOutput->textCursor();

    // insert data at end of 'edit' (but this clears any selection)
    ui->textOutput->moveCursor(QTextCursor::End);
    ui->textOutput->insertPlainText(textdata);

    // revert text selection
    ui->textOutput->setTextCursor(cursor);

    // push scroll to the bottom
    QScrollBar *vbar = ui->textOutput->verticalScrollBar();
    vbar->setValue(vbar->maximum());
}
<|endoftext|>


<commit_before>/**
 * Clever programming language
 * Copyright (c) 2011-2012 Clever Team
 *
 * 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.
 */

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include "core/cthread.h"
#include "core/value.h"
#include "types/function.h"
#include "core/pkgmanager.h"
#include "modules/std/io/io.h"

namespace clever { namespace packages { namespace std {

namespace io {

#define STDIO_DELIM "{}"
#define STDIO_MAXBUF 8096

// flush(void)
// Flushes output buffer (forcefully)
static CLEVER_FUNCTION(flush) {
	fflush(stdout);
}

// print(object a, [ ...])
// Prints the object values without trailing newline
static CLEVER_FUNCTION(print) {
	for (size_t i = 0, size = CLEVER_ARG_COUNT(); i < size; ++i) {
		CLEVER_ARG_DUMP(i);
	}
}

// println(object a, [ ...])
// Prints the object values with trailing newline
static CLEVER_FUNCTION(println) {
	for (size_t i = 0, size = CLEVER_ARG_COUNT(); i < size; ++i) {
		CLEVER_ARG_DUMP(i);
		::std::cout << '\n';
	}
}

// printf(string format, [...])
// Prints and formats a string to standard output without trailing newline
static CLEVER_FUNCTION(printf) {
	if (CLEVER_ARG_COUNT() > 0) {
		char* point = strtok((char*)CLEVER_ARG_PSTR(0), STDIO_DELIM);
		if (point) {
			do {
				unsigned int arg = atoi(point);
				if (arg) {
					if (args.size() > arg) {
						CLEVER_ARG_DUMP(arg);
					}
				} else {
					::std::cout << point;
				}
			} while((point = strtok(NULL, STDIO_DELIM)));
		}
	}
}

} // clever::packages::std::io

/// Initializes Standard module
CLEVER_MODULE_INIT(IOModule) {
	using namespace io;

	BEGIN_DECLARE_FUNCTION();
	addFunction(new Function("print", &CLEVER_FUNC_NAME(print)));
	addFunction(new Function("println", &CLEVER_FUNC_NAME(println)));
	addFunction(new Function("printf", &CLEVER_FUNC_NAME(printf)));
	addFunction(new Function("flush", &CLEVER_FUNC_NAME(flush)));
	END_DECLARE();
}

}}} // clever::packages::std
<commit_msg>-whitespace<commit_after>/**
 * Clever programming language
 * Copyright (c) 2011-2012 Clever Team
 *
 * 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.
 */

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include "core/cthread.h"
#include "core/value.h"
#include "types/function.h"
#include "core/pkgmanager.h"
#include "modules/std/io/io.h"

namespace clever { namespace packages { namespace std {

namespace io {

#define STDIO_DELIM "{}"
#define STDIO_MAXBUF 8096

// flush(void)
// Flushes output buffer (forcefully)
static CLEVER_FUNCTION(flush) {
	fflush(stdout);
}

// print(object a, [ ...])
// Prints the object values without trailing newline
static CLEVER_FUNCTION(print) {
	for (size_t i = 0, size = CLEVER_ARG_COUNT(); i < size; ++i) {
		CLEVER_ARG_DUMP(i);
	}
}

// println(object a, [ ...])
// Prints the object values with trailing newline
static CLEVER_FUNCTION(println) {
	for (size_t i = 0, size = CLEVER_ARG_COUNT(); i < size; ++i) {
		CLEVER_ARG_DUMP(i);
		::std::cout << '\n';
	}
}

// printf(string format, [...])
// Prints and formats a string to standard output without trailing newline
static CLEVER_FUNCTION(printf) {
	if (CLEVER_ARG_COUNT() > 0) {
		char* point = strtok((char*)CLEVER_ARG_PSTR(0), STDIO_DELIM);
		if (point) {
			do {
				unsigned int arg = atoi(point);
				if (arg) {
					if (args.size() > arg) {
						CLEVER_ARG_DUMP(arg);
					}
				} else {
					::std::cout << point;
				}
			} while((point = strtok(NULL, STDIO_DELIM)));
		}
	}
}

} // clever::packages::std::io

/// Initializes Standard module
CLEVER_MODULE_INIT(IOModule) {
	using namespace io;

	BEGIN_DECLARE_FUNCTION();
	addFunction(new Function("print", &CLEVER_FUNC_NAME(print)));
	addFunction(new Function("println", &CLEVER_FUNC_NAME(println)));
	addFunction(new Function("printf", &CLEVER_FUNC_NAME(printf)));
	addFunction(new Function("flush", &CLEVER_FUNC_NAME(flush)));
	END_DECLARE();
}

}}} // clever::packages::std
<|endoftext|>


<commit_before>/**
 * Clever programming language
 * Copyright (c) 2011-2012 Clever Team
 *
 * 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.
 */

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include "core/cthread.h"
#include "core/value.h"
#include "types/function.h"
#include "core/pkgmanager.h"
#include "modules/std/io/io.h"

namespace clever { namespace packages { namespace std {

namespace io {

#define STDIO_DELIM "{}"
#define STDIO_MAXBUF 8096

// flush(void)
// Flushes output buffer (forcefully)
static CLEVER_FUNCTION(flush) {
	fflush(stdout);
}

// print(object a, [ ...])
// Prints the object values without trailing newline
static CLEVER_FUNCTION(print) {
	for (size_t i = 0, size = CARG_COUNT(); i < size; ++i) {
		CARG_DUMP(i);
	}
}

// println(object a, [ ...])
// Prints the object values with trailing newline
static CLEVER_FUNCTION(println) {
	for (size_t i = 0, size = CARG_COUNT(); i < size; ++i) {
		CARG_DUMP(i);
		::std::cout << ::std::endl;
	}
}

// printf(string format, [...])
// Prints and formats a string to standard output without trailing newline
static CLEVER_FUNCTION(printf) {
	if (CARG_COUNT() > 0) {
		char* point = strtok(CARG_PSTR(0), STDIO_DELIM);
		if (point) {
			do {
				unsigned int arg = atoi(point);
				if (arg) {
					if (args.size() > arg) {
						CARG_DUMP(arg);
					}
				} else {
					::std::cout << point;
				}
			} while((point = strtok(NULL, STDIO_DELIM)));
		}
	}
}

} // clever::packages::std::io

/// Initializes Standard module
CLEVER_MODULE_INIT(IOModule) {
	using namespace io;

	BEGIN_DECLARE_FUNCTION();
	addFunction(new Function("print", &CLEVER_FUNC_NAME(print)));
	addFunction(new Function("println", &CLEVER_FUNC_NAME(println)));
	addFunction(new Function("printf", &CLEVER_FUNC_NAME(printf)));
	addFunction(new Function("flush", &CLEVER_FUNC_NAME(flush)));
	END_DECLARE();
}

}}} // clever::packages::std
<commit_msg>swapsies<commit_after>/**
 * Clever programming language
 * Copyright (c) 2011-2012 Clever Team
 *
 * 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.
 */

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include "core/cthread.h"
#include "core/value.h"
#include "types/function.h"
#include "core/pkgmanager.h"
#include "modules/std/io/io.h"

namespace clever { namespace packages { namespace std {

namespace io {

#define STDIO_DELIM "{}"
#define STDIO_MAXBUF 8096

// flush(void)
// Flushes output buffer (forcefully)
static CLEVER_FUNCTION(flush) {
	fflush(stdout);
}

// print(object a, [ ...])
// Prints the object values without trailing newline
static CLEVER_FUNCTION(print) {
	for (size_t i = 0, size = CARG_COUNT(); i < size; ++i) {
		CARG_DUMP(i);
	}
}

// println(object a, [ ...])
// Prints the object values with trailing newline
static CLEVER_FUNCTION(println) {
	for (size_t i = 0, size = CARG_COUNT(); i < size; ++i) {
		CARG_DUMP(i);
		::std::cout << '\n';
	}
}

// printf(string format, [...])
// Prints and formats a string to standard output without trailing newline
static CLEVER_FUNCTION(printf) {
	if (CARG_COUNT() > 0) {
		char* point = strtok(CARG_PSTR(0), STDIO_DELIM);
		if (point) {
			do {
				unsigned int arg = atoi(point);
				if (arg) {
					if (args.size() > arg) {
						CARG_DUMP(arg);
					}
				} else {
					::std::cout << point;
				}
			} while((point = strtok(NULL, STDIO_DELIM)));
		}
	}
}

} // clever::packages::std::io

/// Initializes Standard module
CLEVER_MODULE_INIT(IOModule) {
	using namespace io;

	BEGIN_DECLARE_FUNCTION();
	addFunction(new Function("print", &CLEVER_FUNC_NAME(print)));
	addFunction(new Function("println", &CLEVER_FUNC_NAME(println)));
	addFunction(new Function("printf", &CLEVER_FUNC_NAME(printf)));
	addFunction(new Function("flush", &CLEVER_FUNC_NAME(flush)));
	END_DECLARE();
}

}}} // clever::packages::std
<|endoftext|>


<commit_before>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "watchman/fs/Pipe.h"
#ifdef _WIN32
#include <event2/util.h> // @manual
#endif
#include <folly/Exception.h>
#include <folly/String.h>
#include <system_error>

namespace watchman {

Pipe::Pipe() {
#ifdef _WIN32
  HANDLE readPipe;
  HANDLE writePipe;
  auto sec = SECURITY_ATTRIBUTES();

  sec.nLength = sizeof(sec);
  sec.bInheritHandle = FALSE; // O_CLOEXEC equivalent
  constexpr DWORD kPipeSize = 64 * 1024;

  if (!CreatePipe(&readPipe, &writePipe, &sec, kPipeSize)) {
    throw std::system_error(
        GetLastError(), std::system_category(), "CreatePipe failed");
  }
  read = FileDescriptor(intptr_t(readPipe), FileDescriptor::FDType::Pipe);
  write = FileDescriptor(intptr_t(writePipe), FileDescriptor::FDType::Pipe);

#else
  int fds[2];
  int res;
#if HAVE_PIPE2
  res = pipe2(fds, O_NONBLOCK | O_CLOEXEC);
#else
  res = pipe(fds);
#endif

  if (res) {
    throw std::system_error(
        errno,
        std::system_category(),
        std::string("pipe error: ") + folly::errnoStr(errno));
  }
  read = FileDescriptor(fds[0], FileDescriptor::FDType::Pipe);
  write = FileDescriptor(fds[1], FileDescriptor::FDType::Pipe);

#if !HAVE_PIPE2
  read.setCloExec();
  read.setNonBlock();
  write.setCloExec();
  write.setNonBlock();
#endif
#endif
}

SocketPair::SocketPair() {
  FileDescriptor::system_handle_type pair[2];

#ifdef _WIN32
  // The win32 libevent implementation will attempt to use unix domain sockets
  // if available, but will fall back to using loopback TCP sockets.
  auto r = evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair);
#else
  auto r = ::socketpair(
      AF_UNIX,
#ifdef SOCK_NONBLOCK
      SOCK_NONBLOCK |
#endif
#ifdef SOCK_CLOEXEC
          SOCK_CLOEXEC |
#endif
          SOCK_STREAM,
      0,
      pair);
#endif
  folly::checkUnixError(r, "socketpair failed");

  read = FileDescriptor(pair[0], FileDescriptor::FDType::Socket);
  write = FileDescriptor(pair[1], FileDescriptor::FDType::Socket);

  read.setNonBlock();
  write.setNonBlock();
  read.setCloExec();
  write.setCloExec();
}
} // namespace watchman
<commit_msg>enable more tests on @mode/win<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "watchman/fs/Pipe.h"
#include <folly/Exception.h>
#include <folly/String.h>
#include <folly/portability/Event.h>
#include <system_error>

namespace watchman {

Pipe::Pipe() {
#ifdef _WIN32
  HANDLE readPipe;
  HANDLE writePipe;
  auto sec = SECURITY_ATTRIBUTES();

  sec.nLength = sizeof(sec);
  sec.bInheritHandle = FALSE; // O_CLOEXEC equivalent
  constexpr DWORD kPipeSize = 64 * 1024;

  if (!CreatePipe(&readPipe, &writePipe, &sec, kPipeSize)) {
    throw std::system_error(
        GetLastError(), std::system_category(), "CreatePipe failed");
  }
  read = FileDescriptor(intptr_t(readPipe), FileDescriptor::FDType::Pipe);
  write = FileDescriptor(intptr_t(writePipe), FileDescriptor::FDType::Pipe);

#else
  int fds[2];
  int res;
#if HAVE_PIPE2
  res = pipe2(fds, O_NONBLOCK | O_CLOEXEC);
#else
  res = pipe(fds);
#endif

  if (res) {
    throw std::system_error(
        errno,
        std::system_category(),
        std::string("pipe error: ") + folly::errnoStr(errno));
  }
  read = FileDescriptor(fds[0], FileDescriptor::FDType::Pipe);
  write = FileDescriptor(fds[1], FileDescriptor::FDType::Pipe);

#if !HAVE_PIPE2
  read.setCloExec();
  read.setNonBlock();
  write.setCloExec();
  write.setNonBlock();
#endif
#endif
}

SocketPair::SocketPair() {
  FileDescriptor::system_handle_type pair[2];

#ifdef _WIN32
  // The win32 libevent implementation will attempt to use unix domain sockets
  // if available, but will fall back to using loopback TCP sockets.
  auto r = evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, pair);
#else
  auto r = ::socketpair(
      AF_UNIX,
#ifdef SOCK_NONBLOCK
      SOCK_NONBLOCK |
#endif
#ifdef SOCK_CLOEXEC
          SOCK_CLOEXEC |
#endif
          SOCK_STREAM,
      0,
      pair);
#endif
  folly::checkUnixError(r, "socketpair failed");

  read = FileDescriptor(pair[0], FileDescriptor::FDType::Socket);
  write = FileDescriptor(pair[1], FileDescriptor::FDType::Socket);

  read.setNonBlock();
  write.setNonBlock();
  read.setCloExec();
  write.setCloExec();
}
} // namespace watchman
<|endoftext|>


<commit_before>/*****************************************************************************
 * Copyright (C) 2011-2015 Michael Ira Krufky
 *
 * Author: Michael Ira Krufky <mkrufky@linuxtv.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <stdio.h>
#include <sstream>
#include "array.h"
#include "value-macros.h"

using namespace valueobj;

namespace valueobj {

template <typename T>
const ValueBase* Array::push(T val)
{
	return push<T>(val, "");
}

template <typename T>
const ValueBase* Array::set(std::string key, T val)
{
	if (!key.length()) return NULL;
	const ValueBase* v = push<T>(val, key);
	if (v) updateIndex(key, v);
	return v;
}

template <typename T>
const ValueBase* Array::set(int key, T val)
{
	return set<T>(intToStr(key), val);
}

template <typename T>
const ValueBase* Array::pushByRef(T& val, std::string idx)
{
	Value<T> *v = new Value<T>(idx, val);
	vector.push_back(v);
	++(*v); // increment refcount
	return v;
}

template <typename T>
const ValueBase* Array::push(T val, std::string idx)
{
	return pushByRef<T>(val, idx);
}

template <typename T>
const T& Array::get(unsigned int &idx, T& def) const
{
	if (idx <= vector.size()) {
		Value<T> *val = (Value<T>*)vector[idx];
		if (val->checkType(typeid(T)))
			return val->get();
	}
	return def;
}
}

#define IMPL_ARRAY_TMPL(T) \
template const ValueBase* Array::push(T val); \
template const ValueBase* Array::set(std::string key, T val); \
template const ValueBase* Array::set(int key, T val); \
template const ValueBase* Array::pushByRef(T& val, std::string idx); \
template const ValueBase* Array::push(T val, std::string idx); \
template const T& Array::get(unsigned int &idx, T& def) const

#if 1 // we only need Array::push(unsigned int) but implementing them all for the sake of completeness
IMPL_ARRAY_TMPL(unsigned int);
#else
template const ValueBase* Array::push(unsigned int val);
#endif

#define DBG 0

static ReferencedValueUndefined& valueUndefined = ReferencedValueUndefined::instance();

Array::Array(std::string idx)
 : idxField(idx)
{
#if DBG
	fprintf(stderr, "%s\n", __func__);
#endif
}

Array::~Array()
{
#if DBG
	fprintf(stderr, "%s\n", __func__);
#endif
	clear();
}

Array::Array(const Array &obj)
{
	for (KeyValueVector::const_iterator it = obj.vector.begin(); it != obj.vector.end(); ++it) {
		ValueBase *v = *it;
		push(v);
		const std::string& n = v->getName();
		if (n.length()) updateIndex(n, v);
	}
#if DBG
	fprintf(stderr, "%s(copy) %lu\n", __func__, vector.size());
#endif
}

const std::string Array::toJson() const
{
	std::stringstream s;

	if (!vector.size()) return "[]";

	int count = 0;

	s << "[ ";

	for (KeyValueVector::const_iterator it = vector.begin(); it != vector.end(); ++it) {
		if (count) s << ", ";

		s << (*it)->toJson();

		count++;
	}
	s << " ]";

	return s.str();

}

size_t Array::size() const
{
	return vector.size();
}

const std::string &Array::getIndex() const
{
	return idxField;
}

const ValueBase* Array::get(unsigned int idx) const
{
	if (idx <= vector.size())
		return vector[idx];

	return &valueUndefined;
}

void Array::updateIndex(std::string key, const ValueBase *val)
{
	if (key.length()) indices[key] = val;
}

std::string &Array::assignIndex(Object &obj, std::string &index)
{
	if (idxField.length()) {
		const ValueBase *val = obj.get(idxField);
		index = (typeid(std::string) == val->getType()) ?
			obj.get<std::string>(idxField) : val->toJson();
	}

	return index;
}

const ValueBase* Array::getByName(std::string idx) const
{
	std::map<std::string, const ValueBase*>::const_iterator it = indices.find(idx);
	if (it == indices.end())
		return &valueUndefined;

	return it->second;
}

const ValueBase* Array::getByName(unsigned int idx) const
{
	return getByName(intToStr(idx));
}

void Array::clear()
{
	for (KeyValueVector::iterator it = vector.begin(); it != vector.end(); ++it)
	{
		// decrement refcount. if refcount becomes zero, delete
		if (0 == (--(**it)).getRefCnt()) delete *it;
	}
	vector.clear();
	indices.clear();
}

const std::string Array::intToStr(int i) const
{
	std::stringstream s;
	s << i;
	return s.str();
}

const ValueBase* Array::pushObject(Object &val, std::string idx)
{
	bool extractIndex = (!idx.length());

	if (extractIndex) assignIndex(val, idx);

	const ValueBase *v = pushByRef<Object>(val, idx);

	if (extractIndex) updateIndex(idx, v);

	return v;
}

#ifndef USING_INLINE_PUSH
const ValueBase *Array::push(char *val, std::string idx)
{
	return push<std::string>(std::string(val), idx);
}

const ValueBase *Array::push(const char *val, std::string idx)
{
	return push<std::string>(std::string(val), idx);
}

const ValueBase *Array::push(std::string &val, std::string idx)
{
	return pushByRef<std::string>(val, idx);
}

const ValueBase *Array::push(Array &val, std::string idx)
{
	return pushByRef<Array>(val, idx);
}

const ValueBase *Array::push(Array *val, std::string idx)
{
	return pushByRef<Array>(*val, idx);
}
#endif

const ValueBase* Array::push(Object &o)
{
	return pushObject(o, "");
}

const ValueBase *Array::push(Object *o)
{
	return push(*o);
}

const ValueBase* Array::push(ValueBase *val)
{
	vector.push_back(val);
	++(*val);
	return val;
}

DEFINE_DEFAULT_GETTERS(Array, unsigned int)
TO_JSON_TPL(Array, VALUE.toJson().c_str())
<commit_msg>value/array: implement array template for all types<commit_after>/*****************************************************************************
 * Copyright (C) 2011-2015 Michael Ira Krufky
 *
 * Author: Michael Ira Krufky <mkrufky@linuxtv.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <stdio.h>
#include <sstream>
#include "array.h"
#include "value-macros.h"

using namespace valueobj;

namespace valueobj {

template <typename T>
const ValueBase* Array::push(T val)
{
	return push<T>(val, "");
}

template <typename T>
const ValueBase* Array::set(std::string key, T val)
{
	if (!key.length()) return NULL;
	const ValueBase* v = push<T>(val, key);
	if (v) updateIndex(key, v);
	return v;
}

template <typename T>
const ValueBase* Array::set(int key, T val)
{
	return set<T>(intToStr(key), val);
}

template <typename T>
const ValueBase* Array::pushByRef(T& val, std::string idx)
{
	Value<T> *v = new Value<T>(idx, val);
	vector.push_back(v);
	++(*v); // increment refcount
	return v;
}

template <typename T>
const ValueBase* Array::push(T val, std::string idx)
{
	return pushByRef<T>(val, idx);
}

template <typename T>
const T& Array::get(unsigned int &idx, T& def) const
{
	if (idx <= vector.size()) {
		Value<T> *val = (Value<T>*)vector[idx];
		if (val->checkType(typeid(T)))
			return val->get();
	}
	return def;
}
}

#define IMPL_ARRAY_TMPL(T) \
template const ValueBase* Array::push(T val); \
template const ValueBase* Array::set(std::string key, T val); \
template const ValueBase* Array::set(int key, T val); \
template const ValueBase* Array::pushByRef(T& val, std::string idx); \
template const ValueBase* Array::push(T val, std::string idx); \
template const T& Array::get(unsigned int &idx, T& def) const

IMPL_ARRAY_TMPL(int);
IMPL_ARRAY_TMPL(long);
IMPL_ARRAY_TMPL(short);
IMPL_ARRAY_TMPL(char);
IMPL_ARRAY_TMPL(unsigned int);
IMPL_ARRAY_TMPL(unsigned long);
IMPL_ARRAY_TMPL(unsigned long long);
IMPL_ARRAY_TMPL(unsigned short);
IMPL_ARRAY_TMPL(unsigned char);
IMPL_ARRAY_TMPL(std::string);
IMPL_ARRAY_TMPL(bool);
IMPL_ARRAY_TMPL(double);
IMPL_ARRAY_TMPL(Array);
IMPL_ARRAY_TMPL(Object);

#define DBG 0

static ReferencedValueUndefined& valueUndefined = ReferencedValueUndefined::instance();

Array::Array(std::string idx)
 : idxField(idx)
{
#if DBG
	fprintf(stderr, "%s\n", __func__);
#endif
}

Array::~Array()
{
#if DBG
	fprintf(stderr, "%s\n", __func__);
#endif
	clear();
}

Array::Array(const Array &obj)
{
	for (KeyValueVector::const_iterator it = obj.vector.begin(); it != obj.vector.end(); ++it) {
		ValueBase *v = *it;
		push(v);
		const std::string& n = v->getName();
		if (n.length()) updateIndex(n, v);
	}
#if DBG
	fprintf(stderr, "%s(copy) %lu\n", __func__, vector.size());
#endif
}

const std::string Array::toJson() const
{
	std::stringstream s;

	if (!vector.size()) return "[]";

	int count = 0;

	s << "[ ";

	for (KeyValueVector::const_iterator it = vector.begin(); it != vector.end(); ++it) {
		if (count) s << ", ";

		s << (*it)->toJson();

		count++;
	}
	s << " ]";

	return s.str();

}

size_t Array::size() const
{
	return vector.size();
}

const std::string &Array::getIndex() const
{
	return idxField;
}

const ValueBase* Array::get(unsigned int idx) const
{
	if (idx <= vector.size())
		return vector[idx];

	return &valueUndefined;
}

void Array::updateIndex(std::string key, const ValueBase *val)
{
	if (key.length()) indices[key] = val;
}

std::string &Array::assignIndex(Object &obj, std::string &index)
{
	if (idxField.length()) {
		const ValueBase *val = obj.get(idxField);
		index = (typeid(std::string) == val->getType()) ?
			obj.get<std::string>(idxField) : val->toJson();
	}

	return index;
}

const ValueBase* Array::getByName(std::string idx) const
{
	std::map<std::string, const ValueBase*>::const_iterator it = indices.find(idx);
	if (it == indices.end())
		return &valueUndefined;

	return it->second;
}

const ValueBase* Array::getByName(unsigned int idx) const
{
	return getByName(intToStr(idx));
}

void Array::clear()
{
	for (KeyValueVector::iterator it = vector.begin(); it != vector.end(); ++it)
	{
		// decrement refcount. if refcount becomes zero, delete
		if (0 == (--(**it)).getRefCnt()) delete *it;
	}
	vector.clear();
	indices.clear();
}

const std::string Array::intToStr(int i) const
{
	std::stringstream s;
	s << i;
	return s.str();
}

const ValueBase* Array::pushObject(Object &val, std::string idx)
{
	bool extractIndex = (!idx.length());

	if (extractIndex) assignIndex(val, idx);

	const ValueBase *v = pushByRef<Object>(val, idx);

	if (extractIndex) updateIndex(idx, v);

	return v;
}

#ifndef USING_INLINE_PUSH
const ValueBase *Array::push(char *val, std::string idx)
{
	return push<std::string>(std::string(val), idx);
}

const ValueBase *Array::push(const char *val, std::string idx)
{
	return push<std::string>(std::string(val), idx);
}

const ValueBase *Array::push(std::string &val, std::string idx)
{
	return pushByRef<std::string>(val, idx);
}

const ValueBase *Array::push(Array &val, std::string idx)
{
	return pushByRef<Array>(val, idx);
}

const ValueBase *Array::push(Array *val, std::string idx)
{
	return pushByRef<Array>(*val, idx);
}
#endif

const ValueBase* Array::push(Object &o)
{
	return pushObject(o, "");
}

const ValueBase *Array::push(Object *o)
{
	return push(*o);
}

const ValueBase* Array::push(ValueBase *val)
{
	vector.push_back(val);
	++(*val);
	return val;
}

DEFINE_DEFAULT_GETTERS(Array, unsigned int)
TO_JSON_TPL(Array, VALUE.toJson().c_str())
<|endoftext|>


<commit_before>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Libmemcached library
 *
 *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
 *  Copyright (C) 2006-2009 Brian Aker 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.
 *
 *      * The names of its contributors may not 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 <libmemcached/common.h>

#include <libmemcached/options.hpp>
#include <libmemcached/virtual_bucket.h>

#if 0
static const memcached_st global_copy= {
  .state= {
    .is_purging= false, // .is_purging
    .is_processing_input= false, // is_processing_input
    .is_time_for_rebuild= false,
  },
  .flags= {
    .auto_eject_hosts= false,
    .binary_protocol= false,
    .buffer_requests= false,
    .hash_with_namespace= false,
    .no_block= false,
    .no_reply= false,
    .randomize_replica_read= false,
    .support_cas= false,
    .tcp_nodelay= false,
    .use_sort_hosts= false,
    .use_udp= false,
    .verify_key= false,
    .tcp_keepalive= false,
  },
};
#endif

static inline bool _memcached_init(memcached_st *self)
{
  self->state.is_purging= false;
  self->state.is_processing_input= false;
  self->state.is_time_for_rebuild= false;

  self->flags.auto_eject_hosts= false;
  self->flags.binary_protocol= false;
  self->flags.buffer_requests= false;
  self->flags.hash_with_namespace= false;
  self->flags.no_block= false;
  self->flags.no_reply= false;
  self->flags.randomize_replica_read= false;
  self->flags.support_cas= false;
  self->flags.tcp_nodelay= false;
  self->flags.use_sort_hosts= false;
  self->flags.use_udp= false;
  self->flags.verify_key= false;
  self->flags.tcp_keepalive= false;

  self->virtual_bucket= NULL;

  self->distribution= MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA_SPY;

  if (hashkit_create(&self->hashkit) == NULL)
  {
    return false;
  }

  self->server_info.version= 0;

  self->ketama.continuum= NULL;
  self->ketama.continuum_count= 0;
  self->ketama.continuum_points_counter= 0;
  self->ketama.next_distribution_rebuild= 0;
  self->ketama.weighted= false;

  self->number_of_hosts= 0;
  self->servers= NULL;
  self->last_disconnected_server= NULL;

  self->snd_timeout= 0;
  self->rcv_timeout= 0;
  self->server_failure_limit= MEMCACHED_SERVER_FAILURE_LIMIT;
  self->query_id= 1; // 0 is considered invalid

  /* TODO, Document why we picked these defaults */
  self->io_msg_watermark= 500;
  self->io_bytes_watermark= 65 * 1024;

  self->tcp_keepidle= 0;

  self->io_key_prefetch= 0;
  self->poll_timeout= MEMCACHED_DEFAULT_TIMEOUT;
  self->connect_timeout= MEMCACHED_DEFAULT_CONNECT_TIMEOUT;
  self->retry_timeout= MEMCACHED_SERVER_FAILURE_RETRY_TIMEOUT;

  self->send_size= -1;
  self->recv_size= -1;

  self->user_data= NULL;
  self->number_of_replicas= 0;

  self->allocators= memcached_allocators_return_default();

  self->on_clone= NULL;
  self->on_cleanup= NULL;
  self->get_key_failure= NULL;
  self->delete_trigger= NULL;
  self->callbacks= NULL;
  self->sasl.callbacks= NULL;
  self->sasl.is_allocated= false;

  self->error_messages= NULL;
  self->_namespace= NULL;
  self->configure.initial_pool_size= 1;
  self->configure.max_pool_size= 1;
  self->configure.version= -1;
  self->configure.filename= NULL;

  return true;
}

static void _free(memcached_st *ptr, bool release_st)
{
  /* If we have anything open, lets close it now */
  send_quit(ptr);
  memcached_server_list_free(memcached_server_list(ptr));
  memcached_result_free(&ptr->result);

  memcached_virtual_bucket_free(ptr);

  memcached_server_free(ptr->last_disconnected_server);

  if (ptr->on_cleanup)
  {
    ptr->on_cleanup(ptr);
  }

  libmemcached_free(ptr, ptr->ketama.continuum);

  memcached_array_free(ptr->_namespace);
  ptr->_namespace= NULL;

  memcached_error_free(*ptr);

  if (LIBMEMCACHED_WITH_SASL_SUPPORT and ptr->sasl.callbacks)
  {
    memcached_destroy_sasl_auth_data(ptr);
  }

  if (release_st)
  {
    memcached_array_free(ptr->configure.filename);
    ptr->configure.filename= NULL;
  }

  if (memcached_is_allocated(ptr) && release_st)
  {
    libmemcached_free(ptr, ptr);
  }
}

memcached_st *memcached_create(memcached_st *ptr)
{
  if (ptr)
  {
    ptr->options.is_allocated= false;
  }
  else
  {
    ptr= (memcached_st *)malloc(sizeof(memcached_st));

    if (ptr == NULL)
    {
      return NULL; /*  MEMCACHED_MEMORY_ALLOCATION_FAILURE */
    }

    ptr->options.is_allocated= true;
  }

#if 0
  memcached_set_purging(ptr, false);
  memcached_set_processing_input(ptr, false);
#endif

  if (_memcached_init(ptr) == false)
  {
    memcached_free(ptr);
    return NULL;
  }

  if (memcached_result_create(ptr, &ptr->result) == NULL)
  {
    memcached_free(ptr);
    return NULL;
  }

  WATCHPOINT_ASSERT_INITIALIZED(&ptr->result);

  return ptr;
}

memcached_st *memcached(const char *string, size_t length)
{
  memcached_st *self= memcached_create(NULL);
  if (self == NULL)
  {
    return NULL;
  }

  if (length == 0)
  {
    return self;
  }

  memcached_return_t rc= memcached_parse_configuration(self, string, length);
  if (memcached_success(rc) and memcached_parse_filename(self))
  {
    rc= memcached_parse_configure_file(*self, memcached_parse_filename(self), memcached_parse_filename_length(self));
  }

  if (memcached_failed(rc))
  {
    memcached_free(self);
    return NULL;
  }

  return self;
}

memcached_return_t memcached_reset(memcached_st *ptr)
{
  WATCHPOINT_ASSERT(ptr);
  if (not ptr)
  {
    return MEMCACHED_INVALID_ARGUMENTS;
  }

  bool stored_is_allocated= memcached_is_allocated(ptr);
  uint64_t query_id= ptr->query_id;
  _free(ptr, false);
  memcached_create(ptr);
  memcached_set_allocated(ptr, stored_is_allocated);
  ptr->query_id= query_id;

  if (ptr->configure.filename)
  {
    return memcached_parse_configure_file(*ptr, memcached_param_array(ptr->configure.filename));
  }

  return MEMCACHED_SUCCESS;
}

void memcached_servers_reset(memcached_st *self)
{
  if (self)
  {
    memcached_server_list_free(memcached_server_list(self));

    memcached_server_list_set(self, NULL);
    self->number_of_hosts= 0;
    memcached_server_free(self->last_disconnected_server);
    self->last_disconnected_server= NULL;
  }
}

void memcached_reset_last_disconnected_server(memcached_st *self)
{
  if (self)
  {
    memcached_server_free(self->last_disconnected_server);
    self->last_disconnected_server= NULL;
  }
}

void memcached_free(memcached_st *ptr)
{
  if (ptr)
  {
    _free(ptr, true);
  }
}

/*
  clone is the destination, while source is the structure to clone.
  If source is NULL the call is the same as if a memcached_create() was
  called.
*/
memcached_st *memcached_clone(memcached_st *clone, const memcached_st *source)
{
  if (source == NULL)
  {
    return memcached_create(clone);
  }

  if (clone and memcached_is_allocated(clone))
  {
    return NULL;
  }

  memcached_st *new_clone= memcached_create(clone);

  if (new_clone == NULL)
  {
    return NULL;
  }

  new_clone->flags= source->flags;
  new_clone->send_size= source->send_size;
  new_clone->recv_size= source->recv_size;
  new_clone->poll_timeout= source->poll_timeout;
  new_clone->connect_timeout= source->connect_timeout;
  new_clone->retry_timeout= source->retry_timeout;
  new_clone->distribution= source->distribution;

  if (hashkit_clone(&new_clone->hashkit, &source->hashkit) == NULL)
  {
    memcached_free(new_clone);
    return NULL;
  }

  new_clone->user_data= source->user_data;

  new_clone->snd_timeout= source->snd_timeout;
  new_clone->rcv_timeout= source->rcv_timeout;

  new_clone->on_clone= source->on_clone;
  new_clone->on_cleanup= source->on_cleanup;

  new_clone->allocators= source->allocators;

  new_clone->get_key_failure= source->get_key_failure;
  new_clone->delete_trigger= source->delete_trigger;
  new_clone->server_failure_limit= source->server_failure_limit;
  new_clone->io_msg_watermark= source->io_msg_watermark;
  new_clone->io_bytes_watermark= source->io_bytes_watermark;
  new_clone->io_key_prefetch= source->io_key_prefetch;
  new_clone->number_of_replicas= source->number_of_replicas;
  new_clone->tcp_keepidle= source->tcp_keepidle;

  if (memcached_server_count(source))
  {
    if (memcached_failed(memcached_push(new_clone, source)))
    {
      return NULL;
    }
  }

  new_clone->_namespace= memcached_array_clone(new_clone, source->_namespace);
  new_clone->configure.filename= memcached_array_clone(new_clone, source->_namespace);

  if (LIBMEMCACHED_WITH_SASL_SUPPORT and source->sasl.callbacks)
  {
    if (memcached_failed(memcached_clone_sasl(new_clone, source)))
    {
      memcached_free(new_clone);
      return NULL;
    }
  }

  if (memcached_failed(run_distribution(new_clone)))
  {
    memcached_free(new_clone);

    return NULL;
  }

  if (source->on_clone)
  {
    source->on_clone(new_clone, source);
  }

  return new_clone;
}

void *memcached_get_user_data(const memcached_st *ptr)
{
  return ptr->user_data;
}

void *memcached_set_user_data(memcached_st *ptr, void *data)
{
  void *ret= ptr->user_data;
  ptr->user_data= data;

  return ret;
}

memcached_return_t memcached_push(memcached_st *destination, const memcached_st *source)
{
  return memcached_server_push(destination, source->servers);
}

memcached_server_write_instance_st memcached_server_instance_fetch(memcached_st *ptr, uint32_t server_key)
{
  return &ptr->servers[server_key];
}

memcached_server_instance_st memcached_server_instance_by_position(const memcached_st *ptr, uint32_t server_key)
{
  return &ptr->servers[server_key];
}

uint64_t memcached_query_id(const memcached_st *self)
{
  if (not self)
    return 0;

  return self->query_id;
}
<commit_msg>Reverse patch<commit_after>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Libmemcached library
 *
 *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
 *  Copyright (C) 2006-2009 Brian Aker 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.
 *
 *      * The names of its contributors may not 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 <libmemcached/common.h>

#include <libmemcached/options.hpp>
#include <libmemcached/virtual_bucket.h>

#if 0
static const memcached_st global_copy= {
  .state= {
    .is_purging= false, // .is_purging
    .is_processing_input= false, // is_processing_input
    .is_time_for_rebuild= false,
  },
  .flags= {
    .auto_eject_hosts= false,
    .binary_protocol= false,
    .buffer_requests= false,
    .hash_with_namespace= false,
    .no_block= false,
    .no_reply= false,
    .randomize_replica_read= false,
    .support_cas= false,
    .tcp_nodelay= false,
    .use_sort_hosts= false,
    .use_udp= false,
    .verify_key= false,
    .tcp_keepalive= false,
  },
};
#endif

static inline bool _memcached_init(memcached_st *self)
{
  self->state.is_purging= false;
  self->state.is_processing_input= false;
  self->state.is_time_for_rebuild= false;

  self->flags.auto_eject_hosts= false;
  self->flags.binary_protocol= false;
  self->flags.buffer_requests= false;
  self->flags.hash_with_namespace= false;
  self->flags.no_block= false;
  self->flags.no_reply= false;
  self->flags.randomize_replica_read= false;
  self->flags.support_cas= false;
  self->flags.tcp_nodelay= false;
  self->flags.use_sort_hosts= false;
  self->flags.use_udp= false;
  self->flags.verify_key= false;
  self->flags.tcp_keepalive= false;

  self->virtual_bucket= NULL;

  self->distribution= MEMCACHED_DISTRIBUTION_MODULA;

  if (hashkit_create(&self->hashkit) == NULL)
  {
    return false;
  }

  self->server_info.version= 0;

  self->ketama.continuum= NULL;
  self->ketama.continuum_count= 0;
  self->ketama.continuum_points_counter= 0;
  self->ketama.next_distribution_rebuild= 0;
  self->ketama.weighted= false;

  self->number_of_hosts= 0;
  self->servers= NULL;
  self->last_disconnected_server= NULL;

  self->snd_timeout= 0;
  self->rcv_timeout= 0;
  self->server_failure_limit= MEMCACHED_SERVER_FAILURE_LIMIT;
  self->query_id= 1; // 0 is considered invalid

  /* TODO, Document why we picked these defaults */
  self->io_msg_watermark= 500;
  self->io_bytes_watermark= 65 * 1024;

  self->tcp_keepidle= 0;

  self->io_key_prefetch= 0;
  self->poll_timeout= MEMCACHED_DEFAULT_TIMEOUT;
  self->connect_timeout= MEMCACHED_DEFAULT_CONNECT_TIMEOUT;
  self->retry_timeout= MEMCACHED_SERVER_FAILURE_RETRY_TIMEOUT;

  self->send_size= -1;
  self->recv_size= -1;

  self->user_data= NULL;
  self->number_of_replicas= 0;

  self->allocators= memcached_allocators_return_default();

  self->on_clone= NULL;
  self->on_cleanup= NULL;
  self->get_key_failure= NULL;
  self->delete_trigger= NULL;
  self->callbacks= NULL;
  self->sasl.callbacks= NULL;
  self->sasl.is_allocated= false;

  self->error_messages= NULL;
  self->_namespace= NULL;
  self->configure.initial_pool_size= 1;
  self->configure.max_pool_size= 1;
  self->configure.version= -1;
  self->configure.filename= NULL;

  return true;
}

static void _free(memcached_st *ptr, bool release_st)
{
  /* If we have anything open, lets close it now */
  send_quit(ptr);
  memcached_server_list_free(memcached_server_list(ptr));
  memcached_result_free(&ptr->result);

  memcached_virtual_bucket_free(ptr);

  memcached_server_free(ptr->last_disconnected_server);

  if (ptr->on_cleanup)
  {
    ptr->on_cleanup(ptr);
  }

  libmemcached_free(ptr, ptr->ketama.continuum);

  memcached_array_free(ptr->_namespace);
  ptr->_namespace= NULL;

  memcached_error_free(*ptr);

  if (LIBMEMCACHED_WITH_SASL_SUPPORT and ptr->sasl.callbacks)
  {
    memcached_destroy_sasl_auth_data(ptr);
  }

  if (release_st)
  {
    memcached_array_free(ptr->configure.filename);
    ptr->configure.filename= NULL;
  }

  if (memcached_is_allocated(ptr) && release_st)
  {
    libmemcached_free(ptr, ptr);
  }
}

memcached_st *memcached_create(memcached_st *ptr)
{
  if (ptr)
  {
    ptr->options.is_allocated= false;
  }
  else
  {
    ptr= (memcached_st *)malloc(sizeof(memcached_st));

    if (ptr == NULL)
    {
      return NULL; /*  MEMCACHED_MEMORY_ALLOCATION_FAILURE */
    }

    ptr->options.is_allocated= true;
  }

#if 0
  memcached_set_purging(ptr, false);
  memcached_set_processing_input(ptr, false);
#endif

  if (_memcached_init(ptr) == false)
  {
    memcached_free(ptr);
    return NULL;
  }

  if (memcached_result_create(ptr, &ptr->result) == NULL)
  {
    memcached_free(ptr);
    return NULL;
  }

  WATCHPOINT_ASSERT_INITIALIZED(&ptr->result);

  return ptr;
}

memcached_st *memcached(const char *string, size_t length)
{
  memcached_st *self= memcached_create(NULL);
  if (self == NULL)
  {
    return NULL;
  }

  if (length == 0)
  {
    return self;
  }

  memcached_return_t rc= memcached_parse_configuration(self, string, length);
  if (memcached_success(rc) and memcached_parse_filename(self))
  {
    rc= memcached_parse_configure_file(*self, memcached_parse_filename(self), memcached_parse_filename_length(self));
  }

  if (memcached_failed(rc))
  {
    memcached_free(self);
    return NULL;
  }

  return self;
}

memcached_return_t memcached_reset(memcached_st *ptr)
{
  WATCHPOINT_ASSERT(ptr);
  if (not ptr)
  {
    return MEMCACHED_INVALID_ARGUMENTS;
  }

  bool stored_is_allocated= memcached_is_allocated(ptr);
  uint64_t query_id= ptr->query_id;
  _free(ptr, false);
  memcached_create(ptr);
  memcached_set_allocated(ptr, stored_is_allocated);
  ptr->query_id= query_id;

  if (ptr->configure.filename)
  {
    return memcached_parse_configure_file(*ptr, memcached_param_array(ptr->configure.filename));
  }

  return MEMCACHED_SUCCESS;
}

void memcached_servers_reset(memcached_st *self)
{
  if (self)
  {
    memcached_server_list_free(memcached_server_list(self));

    memcached_server_list_set(self, NULL);
    self->number_of_hosts= 0;
    memcached_server_free(self->last_disconnected_server);
    self->last_disconnected_server= NULL;
  }
}

void memcached_reset_last_disconnected_server(memcached_st *self)
{
  if (self)
  {
    memcached_server_free(self->last_disconnected_server);
    self->last_disconnected_server= NULL;
  }
}

void memcached_free(memcached_st *ptr)
{
  if (ptr)
  {
    _free(ptr, true);
  }
}

/*
  clone is the destination, while source is the structure to clone.
  If source is NULL the call is the same as if a memcached_create() was
  called.
*/
memcached_st *memcached_clone(memcached_st *clone, const memcached_st *source)
{
  if (source == NULL)
  {
    return memcached_create(clone);
  }

  if (clone and memcached_is_allocated(clone))
  {
    return NULL;
  }

  memcached_st *new_clone= memcached_create(clone);

  if (new_clone == NULL)
  {
    return NULL;
  }

  new_clone->flags= source->flags;
  new_clone->send_size= source->send_size;
  new_clone->recv_size= source->recv_size;
  new_clone->poll_timeout= source->poll_timeout;
  new_clone->connect_timeout= source->connect_timeout;
  new_clone->retry_timeout= source->retry_timeout;
  new_clone->distribution= source->distribution;

  if (hashkit_clone(&new_clone->hashkit, &source->hashkit) == NULL)
  {
    memcached_free(new_clone);
    return NULL;
  }

  new_clone->user_data= source->user_data;

  new_clone->snd_timeout= source->snd_timeout;
  new_clone->rcv_timeout= source->rcv_timeout;

  new_clone->on_clone= source->on_clone;
  new_clone->on_cleanup= source->on_cleanup;

  new_clone->allocators= source->allocators;

  new_clone->get_key_failure= source->get_key_failure;
  new_clone->delete_trigger= source->delete_trigger;
  new_clone->server_failure_limit= source->server_failure_limit;
  new_clone->io_msg_watermark= source->io_msg_watermark;
  new_clone->io_bytes_watermark= source->io_bytes_watermark;
  new_clone->io_key_prefetch= source->io_key_prefetch;
  new_clone->number_of_replicas= source->number_of_replicas;
  new_clone->tcp_keepidle= source->tcp_keepidle;

  if (memcached_server_count(source))
  {
    if (memcached_failed(memcached_push(new_clone, source)))
    {
      return NULL;
    }
  }

  new_clone->_namespace= memcached_array_clone(new_clone, source->_namespace);
  new_clone->configure.filename= memcached_array_clone(new_clone, source->_namespace);

  if (LIBMEMCACHED_WITH_SASL_SUPPORT and source->sasl.callbacks)
  {
    if (memcached_failed(memcached_clone_sasl(new_clone, source)))
    {
      memcached_free(new_clone);
      return NULL;
    }
  }

  if (memcached_failed(run_distribution(new_clone)))
  {
    memcached_free(new_clone);

    return NULL;
  }

  if (source->on_clone)
  {
    source->on_clone(new_clone, source);
  }

  return new_clone;
}

void *memcached_get_user_data(const memcached_st *ptr)
{
  return ptr->user_data;
}

void *memcached_set_user_data(memcached_st *ptr, void *data)
{
  void *ret= ptr->user_data;
  ptr->user_data= data;

  return ret;
}

memcached_return_t memcached_push(memcached_st *destination, const memcached_st *source)
{
  return memcached_server_push(destination, source->servers);
}

memcached_server_write_instance_st memcached_server_instance_fetch(memcached_st *ptr, uint32_t server_key)
{
  return &ptr->servers[server_key];
}

memcached_server_instance_st memcached_server_instance_by_position(const memcached_st *ptr, uint32_t server_key)
{
  return &ptr->servers[server_key];
}

uint64_t memcached_query_id(const memcached_st *self)
{
  if (not self)
    return 0;

  return self->query_id;
}
<|endoftext|>


<commit_before>#include "libpldm/base.h"

#include "base.hpp"

#include <array>
#include <cstring>
#include <map>
#include <stdexcept>
#include <vector>

#include "libpldm/bios.h"
#include "libpldm/platform.h"

namespace pldm
{

using Type = uint8_t;

namespace responder
{

using Cmd = std::vector<uint8_t>;

static const std::map<Type, Cmd> capabilities{
    {PLDM_BASE,
     {PLDM_GET_TID, PLDM_GET_PLDM_VERSION, PLDM_GET_PLDM_TYPES,
      PLDM_GET_PLDM_COMMANDS}},
    {PLDM_PLATFORM, {PLDM_SET_STATE_EFFECTER_STATES}},
    {PLDM_BIOS,
     {PLDM_GET_DATE_TIME, PLDM_GET_BIOS_TABLE,
      PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE}},
};

static const std::map<Type, ver32_t> versions{
    {PLDM_BASE, {0xF1, 0xF0, 0xF0, 0x00}},
    {PLDM_PLATFORM, {0xF1, 0xF1, 0xF1, 0x00}},
    {PLDM_BIOS, {0xF1, 0xF0, 0xF0, 0x00}},
    {PLDM_FRU, {0xF1, 0xF0, 0xF0, 0x00}},
};

namespace base
{

Response Handler::getPLDMTypes(const pldm_msg* request,
                               size_t /*payloadLength*/)
{
    // DSP0240 has this as a bitfield8[N], where N = 0 to 7
    std::array<bitfield8_t, 8> types{};
    for (const auto& type : capabilities)
    {
        auto index = type.first / 8;
        // <Type Number> = <Array Index> * 8 + <bit position>
        auto bit = type.first - (index * 8);
        types[index].byte |= 1 << bit;
    }

    Response response(sizeof(pldm_msg_hdr) + PLDM_GET_TYPES_RESP_BYTES, 0);
    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
    auto rc = encode_get_types_resp(request->hdr.instance_id, PLDM_SUCCESS,
                                    types.data(), responsePtr);
    if (rc != PLDM_SUCCESS)
    {
        return CmdHandler::ccOnlyResponse(request, rc);
    }

    return response;
}

Response Handler::getPLDMCommands(const pldm_msg* request, size_t payloadLength)
{
    ver32_t version{};
    Type type;

    Response response(sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_RESP_BYTES, 0);
    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());

    auto rc = decode_get_commands_req(request, payloadLength, &type, &version);

    if (rc != PLDM_SUCCESS)
    {
        return CmdHandler::ccOnlyResponse(request, rc);
    }

    // DSP0240 has this as a bitfield8[N], where N = 0 to 31
    std::array<bitfield8_t, 32> cmds{};
    if (capabilities.find(type) == capabilities.end())
    {
        return CmdHandler::ccOnlyResponse(request,
                                          PLDM_ERROR_INVALID_PLDM_TYPE);
    }

    for (const auto& cmd : capabilities.at(type))
    {
        auto index = cmd / 8;
        // <Type Number> = <Array Index> * 8 + <bit position>
        auto bit = cmd - (index * 8);
        cmds[index].byte |= 1 << bit;
    }

    rc = encode_get_commands_resp(request->hdr.instance_id, PLDM_SUCCESS,
                                  cmds.data(), responsePtr);
    if (rc != PLDM_SUCCESS)
    {
        return ccOnlyResponse(request, rc);
    }

    return response;
}

Response Handler::getPLDMVersion(const pldm_msg* request, size_t payloadLength)
{
    uint32_t transferHandle;
    Type type;
    uint8_t transferFlag;

    Response response(sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_RESP_BYTES, 0);
    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());

    uint8_t rc = decode_get_version_req(request, payloadLength, &transferHandle,
                                        &transferFlag, &type);

    if (rc != PLDM_SUCCESS)
    {
        return CmdHandler::ccOnlyResponse(request, rc);
    }

    ver32_t version{};
    auto search = versions.find(type);

    if (search == versions.end())
    {
        return CmdHandler::ccOnlyResponse(request,
                                          PLDM_ERROR_INVALID_PLDM_TYPE);
    }

    memcpy(&version, &(search->second), sizeof(version));
    rc = encode_get_version_resp(request->hdr.instance_id, PLDM_SUCCESS, 0,
                                 PLDM_START_AND_END, &version,
                                 sizeof(pldm_version), responsePtr);
    if (rc != PLDM_SUCCESS)
    {
        return ccOnlyResponse(request, rc);
    }

    return response;
}

Response Handler::getTID(const pldm_msg* request, size_t /*payloadLength*/)
{
    // assigned 1 to the bmc as the PLDM terminus
    uint8_t tid = 1;

    Response response(sizeof(pldm_msg_hdr) + PLDM_GET_TID_RESP_BYTES, 0);
    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
    auto rc = encode_get_tid_resp(request->hdr.instance_id, PLDM_SUCCESS, tid,
                                  responsePtr);
    if (rc != PLDM_SUCCESS)
    {
        return ccOnlyResponse(request, rc);
    }

    return response;
}

} // namespace base
} // namespace responder
} // namespace pldm
<commit_msg>Update the PLDM version for Platform Spec<commit_after>#include "libpldm/base.h"

#include "base.hpp"

#include <array>
#include <cstring>
#include <map>
#include <stdexcept>
#include <vector>

#include "libpldm/bios.h"
#include "libpldm/platform.h"

namespace pldm
{

using Type = uint8_t;

namespace responder
{

using Cmd = std::vector<uint8_t>;

static const std::map<Type, Cmd> capabilities{
    {PLDM_BASE,
     {PLDM_GET_TID, PLDM_GET_PLDM_VERSION, PLDM_GET_PLDM_TYPES,
      PLDM_GET_PLDM_COMMANDS}},
    {PLDM_PLATFORM, {PLDM_SET_STATE_EFFECTER_STATES}},
    {PLDM_BIOS,
     {PLDM_GET_DATE_TIME, PLDM_GET_BIOS_TABLE,
      PLDM_GET_BIOS_ATTRIBUTE_CURRENT_VALUE_BY_HANDLE}},
};

static const std::map<Type, ver32_t> versions{
    {PLDM_BASE, {0xF1, 0xF0, 0xF0, 0x00}},
    {PLDM_PLATFORM, {0xF1, 0xF2, 0xF0, 0x00}},
    {PLDM_BIOS, {0xF1, 0xF0, 0xF0, 0x00}},
    {PLDM_FRU, {0xF1, 0xF0, 0xF0, 0x00}},
};

namespace base
{

Response Handler::getPLDMTypes(const pldm_msg* request,
                               size_t /*payloadLength*/)
{
    // DSP0240 has this as a bitfield8[N], where N = 0 to 7
    std::array<bitfield8_t, 8> types{};
    for (const auto& type : capabilities)
    {
        auto index = type.first / 8;
        // <Type Number> = <Array Index> * 8 + <bit position>
        auto bit = type.first - (index * 8);
        types[index].byte |= 1 << bit;
    }

    Response response(sizeof(pldm_msg_hdr) + PLDM_GET_TYPES_RESP_BYTES, 0);
    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
    auto rc = encode_get_types_resp(request->hdr.instance_id, PLDM_SUCCESS,
                                    types.data(), responsePtr);
    if (rc != PLDM_SUCCESS)
    {
        return CmdHandler::ccOnlyResponse(request, rc);
    }

    return response;
}

Response Handler::getPLDMCommands(const pldm_msg* request, size_t payloadLength)
{
    ver32_t version{};
    Type type;

    Response response(sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_RESP_BYTES, 0);
    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());

    auto rc = decode_get_commands_req(request, payloadLength, &type, &version);

    if (rc != PLDM_SUCCESS)
    {
        return CmdHandler::ccOnlyResponse(request, rc);
    }

    // DSP0240 has this as a bitfield8[N], where N = 0 to 31
    std::array<bitfield8_t, 32> cmds{};
    if (capabilities.find(type) == capabilities.end())
    {
        return CmdHandler::ccOnlyResponse(request,
                                          PLDM_ERROR_INVALID_PLDM_TYPE);
    }

    for (const auto& cmd : capabilities.at(type))
    {
        auto index = cmd / 8;
        // <Type Number> = <Array Index> * 8 + <bit position>
        auto bit = cmd - (index * 8);
        cmds[index].byte |= 1 << bit;
    }

    rc = encode_get_commands_resp(request->hdr.instance_id, PLDM_SUCCESS,
                                  cmds.data(), responsePtr);
    if (rc != PLDM_SUCCESS)
    {
        return ccOnlyResponse(request, rc);
    }

    return response;
}

Response Handler::getPLDMVersion(const pldm_msg* request, size_t payloadLength)
{
    uint32_t transferHandle;
    Type type;
    uint8_t transferFlag;

    Response response(sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_RESP_BYTES, 0);
    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());

    uint8_t rc = decode_get_version_req(request, payloadLength, &transferHandle,
                                        &transferFlag, &type);

    if (rc != PLDM_SUCCESS)
    {
        return CmdHandler::ccOnlyResponse(request, rc);
    }

    ver32_t version{};
    auto search = versions.find(type);

    if (search == versions.end())
    {
        return CmdHandler::ccOnlyResponse(request,
                                          PLDM_ERROR_INVALID_PLDM_TYPE);
    }

    memcpy(&version, &(search->second), sizeof(version));
    rc = encode_get_version_resp(request->hdr.instance_id, PLDM_SUCCESS, 0,
                                 PLDM_START_AND_END, &version,
                                 sizeof(pldm_version), responsePtr);
    if (rc != PLDM_SUCCESS)
    {
        return ccOnlyResponse(request, rc);
    }

    return response;
}

Response Handler::getTID(const pldm_msg* request, size_t /*payloadLength*/)
{
    // assigned 1 to the bmc as the PLDM terminus
    uint8_t tid = 1;

    Response response(sizeof(pldm_msg_hdr) + PLDM_GET_TID_RESP_BYTES, 0);
    auto responsePtr = reinterpret_cast<pldm_msg*>(response.data());
    auto rc = encode_get_tid_resp(request->hdr.instance_id, PLDM_SUCCESS, tid,
                                  responsePtr);
    if (rc != PLDM_SUCCESS)
    {
        return ccOnlyResponse(request, rc);
    }

    return response;
}

} // namespace base
} // namespace responder
} // namespace pldm
<|endoftext|>


<commit_before>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#pragma once

#include <chrono>
#include <cstdint>
#include <string_view>

#include <caf/atom.hpp>
#include <caf/fwd.hpp>

namespace vast::defaults {

namespace command {

/// Path to persistent state.
constexpr std::string_view directory = "vast";

/// Hostname or IP address of a remote node.
constexpr std::string_view endpoint_host = "";

/// TCP port address of a remote node.
constexpr uint16_t endpoint_port = 42000;

/// Server ID for the consensus module.
constexpr std::string_view id = "";

/// Path for reading input events or `-` for reading from STDIN.
constexpr std::string_view read_path = "-";

/// Path to alternate schema.

/// Path for writing query results or `-` for writing to STDOUT.
constexpr std::string_view write_path = "-";

/// Inverse factor by which to delay packets. For example, if 5, then for two
/// packets spaced *t* seconds apart, the source will sleep for *t/5* seconds.
constexpr int64_t pseudo_realtime_factor = 0;

/// Number of bytes to keep per event.
constexpr size_t cutoff = std::numeric_limits<size_t>::max();

/// Flow table expiration interval.
constexpr size_t flow_expiry = 10;

/// Flush to disk after that many packets.
constexpr size_t flush_interval = 10000;

/// Maximum number of results.
constexpr size_t max_events = 0;

/// Maximum flow lifetime before eviction.
constexpr size_t max_flow_age = 60;

/// Number of concurrent flows to track.
constexpr size_t max_flows = 1 << 20;

/// Number of events generated by the test source.
constexpr size_t generated_events = 100;

/// The unique ID of this node.
constexpr std::string_view node_id = "node";

/// @returns the table slice type from `options` if available, otherwise the
///          type configured in the actor system, or ::system::table_slice_type
///          if no user-defined option is available.
caf::atom_value table_slice_type(caf::actor_system& sys,
                                 caf::settings& options);

} // namespace command

namespace system {

/// The default table slice type.
constexpr caf::atom_value table_slice_type = caf::atom("default");

/// Maximum size for sources that generate table slices.
constexpr size_t table_slice_size = 100;

/// Maximum number of events per INDEX partition.
constexpr size_t max_partition_size = 1 << 20;

/// Maximum number of in-memory INDEX partitions.
constexpr size_t max_in_mem_partitions = 10;

/// Number of immediately scheduled INDEX partitions.
constexpr size_t taste_partitions = 5;

/// Maximum number of concurrent INDEX queries.
constexpr size_t num_query_supervisors = 10;

/// Number of cached ARCHIVE segments.
constexpr size_t segments = 10;

/// Maximum size of ARCHIVE segments in MB.
constexpr size_t max_segment_size = 128;

/// Number of initial IDs to request in the IMPORTER.
constexpr size_t initially_requested_ids = 128;

/// Rate at which telemetry data is sent to the ACCOUNTANT.
constexpr std::chrono::milliseconds telemetry_rate = std::chrono::milliseconds{
  1000};

} // namespace system

} // namespace vast::defaults
<commit_msg>Integrate review suggestions<commit_after>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#pragma once

#include <chrono>
#include <cstdint>
#include <string_view>

#include <caf/atom.hpp>
#include <caf/fwd.hpp>

namespace vast::defaults {

namespace command {

/// Path to persistent state.
constexpr std::string_view directory = "vast";

/// Hostname or IP address of a remote node.
constexpr std::string_view endpoint_host = "";

/// TCP port address of a remote node.
constexpr uint16_t endpoint_port = 42000;

/// Server ID for the consensus module.
constexpr std::string_view id = "";

/// Path for reading input events or `-` for reading from STDIN.
constexpr std::string_view read_path = "-";

/// Path to alternate schema.

/// Path for writing query results or `-` for writing to STDOUT.
constexpr std::string_view write_path = "-";

/// Inverse factor by which to delay packets. For example, if 5, then for two
/// packets spaced *t* seconds apart, the source will sleep for *t/5* seconds.
constexpr int64_t pseudo_realtime_factor = 0;

/// Number of bytes to keep per event.
constexpr size_t cutoff = std::numeric_limits<size_t>::max();

/// Flow table expiration interval.
constexpr size_t flow_expiry = 10;

/// Flush to disk after that many packets.
constexpr size_t flush_interval = 10'000;

/// Maximum number of results.
constexpr size_t max_events = 0;

/// Maximum flow lifetime before eviction.
constexpr size_t max_flow_age = 60;

/// Number of concurrent flows to track.
constexpr size_t max_flows = 1'048'576; // 1_Mi

/// Number of events generated by the test source.
constexpr size_t generated_events = 100;

/// The unique ID of this node.
constexpr std::string_view node_id = "node";

/// @returns the table slice type from `options` if available, otherwise the
///          type configured in the actor system, or ::system::table_slice_type
///          if no user-defined option is available.
caf::atom_value table_slice_type(caf::actor_system& sys,
                                 caf::settings& options);

} // namespace command

namespace system {

/// The default table slice type.
constexpr caf::atom_value table_slice_type = caf::atom("default");

/// Maximum size for sources that generate table slices.
constexpr size_t table_slice_size = 100;

/// Maximum number of events per INDEX partition.
constexpr size_t max_partition_size = 1'048'576; // 1_Mi

/// Maximum number of in-memory INDEX partitions.
constexpr size_t max_in_mem_partitions = 10;

/// Number of immediately scheduled INDEX partitions.
constexpr size_t taste_partitions = 5;

/// Maximum number of concurrent INDEX queries.
constexpr size_t num_query_supervisors = 10;

/// Number of cached ARCHIVE segments.
constexpr size_t segments = 10;

/// Maximum size of ARCHIVE segments in MB.
constexpr size_t max_segment_size = 128;

/// Number of initial IDs to request in the IMPORTER.
constexpr size_t initially_requested_ids = 128;

/// Rate at which telemetry data is sent to the ACCOUNTANT.
constexpr std::chrono::milliseconds telemetry_rate = std::chrono::milliseconds{
  1000};

} // namespace system

} // namespace vast::defaults
<|endoftext|>