<commit_before>// Copyright (C) 2016 xaizek <xaizek@openmailbox.org>
//
// This file is part of uncov.
//
// uncov is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// uncov 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with uncov.  If not, see <http://www.gnu.org/licenses/>.

#include <sys/ioctl.h>
#include <sys/wait.h>
#include <termios.h>

#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/optional.hpp>
#include <boost/scope_exit.hpp>

#include <iomanip>
#include <iostream>
#include <limits>
#include <sstream>
#include <string>
#include <vector>

#include "BuildHistory.hpp"
#include "FilePrinter.hpp"
#include "Repository.hpp"
#include "SubCommand.hpp"
#include "TablePrinter.hpp"
#include "decoration.hpp"

static void printBuild(const Build &build);
static void printFile(const Repository *repo, const Build &build,
                      const File &file, FilePrinter &printer);

class CovInfo
{
public:
    CovInfo() = default;
    template <typename T>
    explicit CovInfo(const T &coverable)
        : coveredCount(coverable.getCoveredCount()),
          uncoveredCount(coverable.getUncoveredCount())
    {
    }

public:
    void addCovered(int num)
    {
        coveredCount += num;
    }

    void addUncovered(int num)
    {
        uncoveredCount += num;
    }

    int getCoveredCount() const
    {
        return coveredCount;
    }

    int getUncoveredCount() const
    {
        return uncoveredCount;
    }

    std::string formatCoverageRate() const
    {
        if (getRelevantLines() == 0) {
            return "100";
        }

        auto rate = 100*coveredCount/static_cast<float>(getRelevantLines());

        std::ostringstream oss;
        oss << std::fixed << std::right
            << std::setprecision(2) << rate;
        return oss.str();
    }

    std::string formatLines(const std::string &separator) const
    {
        return std::to_string(coveredCount) + separator
             + std::to_string(getRelevantLines());
    }

private:
    int getRelevantLines() const
    {
        return coveredCount + uncoveredCount;
    }

private:
    int coveredCount = 0;
    int uncoveredCount = 0;
};

class RedirectToPager
{
    template <typename T>
    using stream_buffer = boost::iostreams::stream_buffer<T>;
    using file_descriptor_sink = boost::iostreams::file_descriptor_sink;

public:
    RedirectToPager()
    {
        int pipePair[2];
        if (pipe(pipePair) != 0) {
            throw std::runtime_error("Failed to create a pipe");
        }
        BOOST_SCOPE_EXIT_ALL(pipePair) { close(pipePair[0]); };

        pid = fork();
        if (pid == -1) {
            close(pipePair[1]);
            throw std::runtime_error("Fork has failed");
        }
        if (pid == 0) {
            close(pipePair[1]);
            if (dup2(pipePair[0], STDIN_FILENO) == -1) {
                _Exit(EXIT_FAILURE);
            }
            close(pipePair[0]);
            // XXX: hard-coded invocation of less.
            execlp("less", "less", "-R", static_cast<char *>(nullptr));
            _Exit(127);
        }

        out.open(file_descriptor_sink(pipePair[1],
                                      boost::iostreams::close_handle));
        rdbuf = std::cout.rdbuf(&out);
    }

    ~RedirectToPager()
    {
        std::cout.rdbuf(rdbuf);
        out.close();
        int wstatus;
        waitpid(pid, &wstatus, 0);
    }

private:
    stream_buffer<file_descriptor_sink> out;
    std::streambuf *rdbuf;
    pid_t pid;
};

/**
 * @brief Retrieves terminal width.
 *
 * @returns Actual terminal width, or maximum possible value for the type.
 */
static unsigned int
getTerminalWidth()
{
    winsize ws;
    if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) != 0) {
        return std::numeric_limits<unsigned int>::max();
    }

    return ws.ws_col;
}

class BuildsCmd : public AutoSubCommand<BuildsCmd>
{
public:
    BuildsCmd() : parent("builds")
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &/*args*/) override
    {
        // TODO: calculate and display change of coverage (both in percents and
        //       in covered/relevant lines).
        // TODO: by default limit number of builds to display to N (e.g., 10).

        // TODO: colorize percents?
        TablePrinter tablePrinter {
            { "Build", "Coverage", "Lines", "Branch", "Commit" },
            getTerminalWidth()
        };

        std::string sharp("#"), percent(" %"), sep(" / ");
        for (const Build &build : bh->getBuilds()) {
            CovInfo covInfo(build);

            tablePrinter.append({
                sharp + std::to_string(build.getId()),
                covInfo.formatCoverageRate() + percent,
                covInfo.formatLines(sep),
                build.getRefName(),
                build.getRef()
            });
        }

        tablePrinter.print(std::cout);
    }
};

class DirsCmd : public AutoSubCommand<DirsCmd>
{
public:
    DirsCmd() : parent("dirs", 1U)
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &args) override
    {
        namespace fs = boost::filesystem;

        const int buildId = std::stoi(args[0]);
        if (boost::optional<Build> build = bh->getBuild(buildId)) {
            std::map<std::string, CovInfo> dirs;
            for (const std::string &filePath : build->getPaths()) {
                fs::path dirPath = filePath;
                dirPath.remove_filename();

                File &file = *build->getFile(filePath);
                CovInfo &info = dirs[dirPath.string()];

                info.addCovered(file.getCoveredCount());
                info.addUncovered(file.getUncoveredCount());
            }

            // TODO: colorize percents?
            TablePrinter tablePrinter({ "-Directory", "Coverage", "#" },
                                      getTerminalWidth());

            std::string slash("/"), percent(" %"), sep(" / ");
            for (const auto &entry : dirs) {
                const CovInfo &covInfo = entry.second;
                tablePrinter.append({
                    entry.first + slash,
                    covInfo.formatCoverageRate() + percent,
                    covInfo.formatLines(sep)
                });
            }

            tablePrinter.print(std::cout);
        } else {
            std::cerr << "Can't find build #" << buildId << '\n';
            error();
        }
    }
};

class FilesCmd : public AutoSubCommand<FilesCmd>
{
public:
    FilesCmd() : parent("files", 1U)
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &args) override
    {
        const int buildId = std::stoi(args[0]);
        boost::optional<Build> build = bh->getBuild(buildId);
        if (!build) {
            std::cerr << "Can't find build #" << buildId << '\n';
            return error();
        }

        // TODO: colorize percents?
        TablePrinter tablePrinter({ "-File", "Coverage", "#" },
                                  getTerminalWidth());

        std::string percent(" %"), sep(" / ");
        for (const std::string &filePath : build->getPaths()) {
            CovInfo covInfo(*build->getFile(filePath));
            tablePrinter.append({
                filePath,
                covInfo.formatCoverageRate() + percent,
                covInfo.formatLines(sep)
            });
        }

        tablePrinter.print(std::cout);
    }
};

class GetCmd : public AutoSubCommand<GetCmd>
{
public:
    GetCmd() : parent("get", 2U)
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &args) override
    {
        const int buildId = std::stoi(args[0]);
        boost::optional<Build> build = bh->getBuild(buildId);
        if (!build) {
            std::cerr << "Can't find build #" << buildId << '\n';
            return error();
        }

        boost::optional<File &> file = build->getFile(args[1]);
        if (!file) {
            std::cerr << "Can't find file: " << args[1] << '\n';
            return error();
        }

        std::cout << build->getRef() << '\n';
        for (int hits : file->getCoverage()) {
            std::cout << hits << '\n';
        }
    }
};

class NewCmd : public AutoSubCommand<NewCmd>
{
public:
    NewCmd() : parent("new")
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &/*args*/) override
    {
        std::string ref, refName;
        std::cin >> ref >> refName;

        const std::unordered_map<std::string, std::string> files =
            repo->listFiles(ref);

        BuildData bd(std::move(ref), refName);

        for (std::string path, sha1Hash; std::cin >> path >> sha1Hash; ) {
            int nLines;
            std::cin >> nLines;

            std::vector<int> coverage;
            coverage.reserve(nLines);

            while (nLines-- > 0) {
                int i;
                std::cin >> i;
                coverage.push_back(i);
            }

            const auto file = files.find(path);
            if (file == files.cend()) {
                std::cerr << "Skipping file missing in " << refName << ": "
                          << path << '\n';
            } else if (!boost::iequals(file->second, sha1Hash)) {
                std::cerr << path << " file at " << refName
                          << " doesn't match reported SHA-1\n";
                error();
            } else {
                bd.addFile(File(std::move(path), std::move(coverage)));
            }
        }

        if (!isFailed()) {
            Build build = bh->addBuild(bd);
            printBuild(build);
            // TODO: display change of coverage since previous build.
        }
    }
};

class ShowCmd : public AutoSubCommand<ShowCmd>
{
public:
    ShowCmd() : parent("show", 1U, 2U)
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &args) override
    {
        // TODO: maybe allow passing in path to directory, which would cause
        //       printing all files in that sub-tree (or only directly in it?).

        const int buildId = std::stoi(args[0]);
        if (boost::optional<Build> build = bh->getBuild(buildId)) {
            FilePrinter printer;

            if (args.size() == 1U) {
                RedirectToPager redirectToPager;
                printBuild(*build);
                for (const std::string &path : build->getPaths()) {
                    printFile(repo, *build, *build->getFile(path), printer);
                }
            } else if (boost::optional<File &> file = build->getFile(args[1])) {
                RedirectToPager redirectToPager;
                printBuild(*build);
                printFile(repo, *build, *file, printer);
            } else {
                std::cerr << "Can't find file: " << args[1] << '\n';
                error();
            }
        } else {
            std::cerr << "Can't find build #" << buildId << '\n';
            error();
        }
    }
};

static void
printBuild(const Build &build)
{
    CovInfo covInfo(build);
    // TODO: colorize percents?
    std::cout << (decor::bold << "Build:") << " #" << build.getId() << ", "
              << covInfo.formatCoverageRate() << "% "
              << '(' << covInfo.formatLines("/") << "), "
              << build.getRefName() << " (" << build.getRef() << ")\n";
}

static void
printFile(const Repository *repo, const Build &build, const File &file,
          FilePrinter &printer)
{
    CovInfo covInfo(file);
    const std::string &path = file.getPath();
    const std::string &ref = build.getRef();
    std::cout << std::setfill('-') << std::setw(80) << "\n"
              << std::setfill(' ');
    // TODO: colorize percents?
    std::cout << (decor::bold << "File: ") << path << ", "
              << covInfo.formatCoverageRate() << "% "
              << '(' << covInfo.formatLines("/") << ")\n";
    std::cout << std::setfill('-') << std::setw(80) << "\n"
              << std::setfill(' ');
    printer.print(path, repo->readFile(ref, path), file.getCoverage());
}
<commit_msg>Rearrange print functions in SubCommands.cpp<commit_after>// Copyright (C) 2016 xaizek <xaizek@openmailbox.org>
//
// This file is part of uncov.
//
// uncov is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// uncov 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with uncov.  If not, see <http://www.gnu.org/licenses/>.

#include <sys/ioctl.h>
#include <sys/wait.h>
#include <termios.h>

#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/optional.hpp>
#include <boost/scope_exit.hpp>

#include <iomanip>
#include <iostream>
#include <limits>
#include <sstream>
#include <string>
#include <vector>

#include "BuildHistory.hpp"
#include "FilePrinter.hpp"
#include "Repository.hpp"
#include "SubCommand.hpp"
#include "TablePrinter.hpp"
#include "decoration.hpp"

static void printBuildHeader(const Build &build);
static void printFile(const Repository *repo, const Build &build,
                      const File &file, FilePrinter &printer);
static void printFileHeader(const File &file);
static void printLineSeparator();

class CovInfo
{
public:
    CovInfo() = default;
    template <typename T>
    explicit CovInfo(const T &coverable)
        : coveredCount(coverable.getCoveredCount()),
          uncoveredCount(coverable.getUncoveredCount())
    {
    }

public:
    void addCovered(int num)
    {
        coveredCount += num;
    }

    void addUncovered(int num)
    {
        uncoveredCount += num;
    }

    int getCoveredCount() const
    {
        return coveredCount;
    }

    int getUncoveredCount() const
    {
        return uncoveredCount;
    }

    std::string formatCoverageRate() const
    {
        if (getRelevantLines() == 0) {
            return "100";
        }

        auto rate = 100*coveredCount/static_cast<float>(getRelevantLines());

        std::ostringstream oss;
        oss << std::fixed << std::right
            << std::setprecision(2) << rate;
        return oss.str();
    }

    std::string formatLines(const std::string &separator) const
    {
        return std::to_string(coveredCount) + separator
             + std::to_string(getRelevantLines());
    }

private:
    int getRelevantLines() const
    {
        return coveredCount + uncoveredCount;
    }

private:
    int coveredCount = 0;
    int uncoveredCount = 0;
};

class RedirectToPager
{
    template <typename T>
    using stream_buffer = boost::iostreams::stream_buffer<T>;
    using file_descriptor_sink = boost::iostreams::file_descriptor_sink;

public:
    RedirectToPager()
    {
        int pipePair[2];
        if (pipe(pipePair) != 0) {
            throw std::runtime_error("Failed to create a pipe");
        }
        BOOST_SCOPE_EXIT_ALL(pipePair) { close(pipePair[0]); };

        pid = fork();
        if (pid == -1) {
            close(pipePair[1]);
            throw std::runtime_error("Fork has failed");
        }
        if (pid == 0) {
            close(pipePair[1]);
            if (dup2(pipePair[0], STDIN_FILENO) == -1) {
                _Exit(EXIT_FAILURE);
            }
            close(pipePair[0]);
            // XXX: hard-coded invocation of less.
            execlp("less", "less", "-R", static_cast<char *>(nullptr));
            _Exit(127);
        }

        out.open(file_descriptor_sink(pipePair[1],
                                      boost::iostreams::close_handle));
        rdbuf = std::cout.rdbuf(&out);
    }

    ~RedirectToPager()
    {
        std::cout.rdbuf(rdbuf);
        out.close();
        int wstatus;
        waitpid(pid, &wstatus, 0);
    }

private:
    stream_buffer<file_descriptor_sink> out;
    std::streambuf *rdbuf;
    pid_t pid;
};

/**
 * @brief Retrieves terminal width.
 *
 * @returns Actual terminal width, or maximum possible value for the type.
 */
static unsigned int
getTerminalWidth()
{
    winsize ws;
    if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) != 0) {
        return std::numeric_limits<unsigned int>::max();
    }

    return ws.ws_col;
}

class BuildsCmd : public AutoSubCommand<BuildsCmd>
{
public:
    BuildsCmd() : parent("builds")
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &/*args*/) override
    {
        // TODO: calculate and display change of coverage (both in percents and
        //       in covered/relevant lines).
        // TODO: by default limit number of builds to display to N (e.g., 10).

        // TODO: colorize percents?
        TablePrinter tablePrinter {
            { "Build", "Coverage", "Lines", "Branch", "Commit" },
            getTerminalWidth()
        };

        std::string sharp("#"), percent(" %"), sep(" / ");
        for (const Build &build : bh->getBuilds()) {
            CovInfo covInfo(build);

            tablePrinter.append({
                sharp + std::to_string(build.getId()),
                covInfo.formatCoverageRate() + percent,
                covInfo.formatLines(sep),
                build.getRefName(),
                build.getRef()
            });
        }

        tablePrinter.print(std::cout);
    }
};

class DirsCmd : public AutoSubCommand<DirsCmd>
{
public:
    DirsCmd() : parent("dirs", 1U)
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &args) override
    {
        namespace fs = boost::filesystem;

        const int buildId = std::stoi(args[0]);
        if (boost::optional<Build> build = bh->getBuild(buildId)) {
            std::map<std::string, CovInfo> dirs;
            for (const std::string &filePath : build->getPaths()) {
                fs::path dirPath = filePath;
                dirPath.remove_filename();

                File &file = *build->getFile(filePath);
                CovInfo &info = dirs[dirPath.string()];

                info.addCovered(file.getCoveredCount());
                info.addUncovered(file.getUncoveredCount());
            }

            // TODO: colorize percents?
            TablePrinter tablePrinter({ "-Directory", "Coverage", "#" },
                                      getTerminalWidth());

            std::string slash("/"), percent(" %"), sep(" / ");
            for (const auto &entry : dirs) {
                const CovInfo &covInfo = entry.second;
                tablePrinter.append({
                    entry.first + slash,
                    covInfo.formatCoverageRate() + percent,
                    covInfo.formatLines(sep)
                });
            }

            tablePrinter.print(std::cout);
        } else {
            std::cerr << "Can't find build #" << buildId << '\n';
            error();
        }
    }
};

class FilesCmd : public AutoSubCommand<FilesCmd>
{
public:
    FilesCmd() : parent("files", 1U)
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &args) override
    {
        const int buildId = std::stoi(args[0]);
        boost::optional<Build> build = bh->getBuild(buildId);
        if (!build) {
            std::cerr << "Can't find build #" << buildId << '\n';
            return error();
        }

        // TODO: colorize percents?
        TablePrinter tablePrinter({ "-File", "Coverage", "#" },
                                  getTerminalWidth());

        std::string percent(" %"), sep(" / ");
        for (const std::string &filePath : build->getPaths()) {
            CovInfo covInfo(*build->getFile(filePath));
            tablePrinter.append({
                filePath,
                covInfo.formatCoverageRate() + percent,
                covInfo.formatLines(sep)
            });
        }

        tablePrinter.print(std::cout);
    }
};

class GetCmd : public AutoSubCommand<GetCmd>
{
public:
    GetCmd() : parent("get", 2U)
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &args) override
    {
        const int buildId = std::stoi(args[0]);
        boost::optional<Build> build = bh->getBuild(buildId);
        if (!build) {
            std::cerr << "Can't find build #" << buildId << '\n';
            return error();
        }

        boost::optional<File &> file = build->getFile(args[1]);
        if (!file) {
            std::cerr << "Can't find file: " << args[1] << '\n';
            return error();
        }

        std::cout << build->getRef() << '\n';
        for (int hits : file->getCoverage()) {
            std::cout << hits << '\n';
        }
    }
};

class NewCmd : public AutoSubCommand<NewCmd>
{
public:
    NewCmd() : parent("new")
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &/*args*/) override
    {
        std::string ref, refName;
        std::cin >> ref >> refName;

        const std::unordered_map<std::string, std::string> files =
            repo->listFiles(ref);

        BuildData bd(std::move(ref), refName);

        for (std::string path, sha1Hash; std::cin >> path >> sha1Hash; ) {
            int nLines;
            std::cin >> nLines;

            std::vector<int> coverage;
            coverage.reserve(nLines);

            while (nLines-- > 0) {
                int i;
                std::cin >> i;
                coverage.push_back(i);
            }

            const auto file = files.find(path);
            if (file == files.cend()) {
                std::cerr << "Skipping file missing in " << refName << ": "
                          << path << '\n';
            } else if (!boost::iequals(file->second, sha1Hash)) {
                std::cerr << path << " file at " << refName
                          << " doesn't match reported SHA-1\n";
                error();
            } else {
                bd.addFile(File(std::move(path), std::move(coverage)));
            }
        }

        if (!isFailed()) {
            Build build = bh->addBuild(bd);
            printBuildHeader(build);
            // TODO: display change of coverage since previous build.
        }
    }
};

class ShowCmd : public AutoSubCommand<ShowCmd>
{
public:
    ShowCmd() : parent("show", 1U, 2U)
    {
    }

private:
    virtual void
    execImpl(const std::vector<std::string> &args) override
    {
        // TODO: maybe allow passing in path to directory, which would cause
        //       printing all files in that sub-tree (or only directly in it?).

        const int buildId = std::stoi(args[0]);
        if (boost::optional<Build> build = bh->getBuild(buildId)) {
            FilePrinter printer;

            if (args.size() == 1U) {
                RedirectToPager redirectToPager;
                printBuildHeader(*build);
                for (const std::string &path : build->getPaths()) {
                    printFile(repo, *build, *build->getFile(path), printer);
                }
            } else if (boost::optional<File &> file = build->getFile(args[1])) {
                RedirectToPager redirectToPager;
                printBuildHeader(*build);
                printFile(repo, *build, *file, printer);
            } else {
                std::cerr << "Can't find file: " << args[1] << '\n';
                error();
            }
        } else {
            std::cerr << "Can't find build #" << buildId << '\n';
            error();
        }
    }
};

static void
printBuildHeader(const Build &build)
{
    CovInfo covInfo(build);
    // TODO: colorize percents?
    std::cout << (decor::bold << "Build:") << " #" << build.getId() << ", "
              << covInfo.formatCoverageRate() << "% "
              << '(' << covInfo.formatLines("/") << "), "
              << build.getRefName() << " (" << build.getRef() << ")\n";
}

static void
printFile(const Repository *repo, const Build &build, const File &file,
          FilePrinter &printer)
{
    printLineSeparator();
    printFileHeader(file);
    printLineSeparator();

    const std::string &path = file.getPath();
    const std::string &ref = build.getRef();
    printer.print(path, repo->readFile(ref, path), file.getCoverage());
}

static void
printFileHeader(const File &file)
{
    CovInfo covInfo(file);
    // TODO: colorize percents?
    std::cout << (decor::bold << "File: ") << file.getPath() << ", "
              << covInfo.formatCoverageRate() << "% "
              << '(' << covInfo.formatLines("/") << ")\n";
}

static void
printLineSeparator()
{
    std::cout << std::setfill('-') << std::setw(80) << '\n'
              << std::setfill(' ');
}
<|endoftext|>


<commit_before>#ifndef COFFEE_MILL_SUPER_IMPOSE
#define COFFEE_MILL_SUPER_IMPOSE
#include "BestFitStructure.hpp"
#include "DCDReader.hpp"
#include "DCDWriter.hpp"
#include "PDBReader.hpp"
#include "PDBWriter.hpp"
#include <list>

namespace mill
{

template<typename vectorT>
int superimpose(const std::string& fname)
{
    if(fname.substr(fname.size() - 4, 4) == ".dcd")
    {// no input file. use all particles.
        const std::string outname =
            fname.substr(0, fname.size() - 4) + "_imposed.dcd";

        std::ofstream ofs(outname);
        if(not ofs.good())
            throw std::runtime_error("file open error: " + outname);

        DCDReader<vectorT> reader;
        DCDWriter<vectorT> writer;
        auto dcddata = reader.read(fname);
        writer.write_header(ofs, dcddata.header());

        BestFit<typename scalar_type_extractor<vectorT>::type, Matrix> bestfit;
        bestfit.set_reference(dcddata.traj().front());
        for(auto snap = dcddata.cbegin(); snap != dcddata.cend(); ++snap)
        {
            writer.write_snapshot(ofs, bestfit.fit(*snap));
        }
        ofs.close();
        return 0;
    }
    else
    {
        throw std::invalid_argument("unknown file in argument: " + fname);
    }
}

}// mill

#endif//COFFEE_MILL_SUPER_IMPOSE
<commit_msg>add reading-toml mode to SuperImpose<commit_after>#ifndef COFFEE_MILL_SUPER_IMPOSE
#define COFFEE_MILL_SUPER_IMPOSE
#include "BestFitStructure.hpp"
#include "DCDReader.hpp"
#include "DCDWriter.hpp"
#include "PDBReader.hpp"
#include "PDBWriter.hpp"
#include <list>

namespace mill
{

template<typename T>
std::vector<T>
remove_except_elements(const std::vector<T>& elements,
        const std::vector<std::vector<std::int_least64_t>>& exception)
{
    std::vector<T> retval;
    retval.reserve(elements.size());
    std::int_least64_t index = 0;
    for(auto iter = elements.cbegin(); iter != elements.cend(); ++iter)
    {
        ++index;
        bool remove = false;
        for(auto e = exception.cbegin(); e != exception.cend(); ++e)
        {
            if(e->front() <= index && index <= e->back())
            {
                remove = true;
                break;
            }
        }
        if(remove) continue;
        retval.push_back(*iter);
    }
    return retval;
}

template<typename vectorT>
int superimpose(const std::string& fname)
{
    if(fname.substr(fname.size() - 4, 4) == ".dcd")
    {// no input file. use all particles.
        const std::string outname =
            fname.substr(0, fname.size() - 4) + "_imposed.dcd";

        std::ofstream ofs(outname);
        if(not ofs.good())
            throw std::runtime_error("file open error: " + outname);

        DCDReader<vectorT> reader;
        DCDWriter<vectorT> writer;
        auto dcddata = reader.read(fname);
        writer.write_header(ofs, dcddata.header());

        BestFit<typename scalar_type_extractor<vectorT>::type, Matrix> bestfit;
        bestfit.set_reference(dcddata.traj().front());
        for(auto snap = dcddata.cbegin(); snap != dcddata.cend(); ++snap)
        {
            writer.write_snapshot(ofs, bestfit.fit(*snap));
        }
        ofs.close();
        return 0;
    }
    else if(fname.substr(fname.size() - 5, 5) == ".toml")
    {// remove some particles to fit.
        std::ifstream tomlfile(fname);
        if(not tomlfile.good())
            throw std::invalid_argument("file open error: " + fname);

        const toml::Data input = toml::parse(tomlfile);
        const std::string dcdname = toml::get<toml::String>(input.at("dcdfile"));
        const std::string outname = toml::get<toml::String>(input.at("output"));
        const std::vector<std::vector<std::int_least64_t>> except_particle =
            toml::get<toml::Array<toml::Array<toml::Integer>>>(input.at("except"));

        std::ofstream outfile(outname);
        if(not outfile.good())
            throw std::runtime_error("file open error: " + outname);

        DCDReader<vectorT> reader;
        DCDWriter<vectorT> writer;
        std::ifstream dcdfile(dcdname);
        auto dcddata = reader.read(dcdfile);
        writer.write_header(outfile, dcddata.header());

        auto initial = dcddata.traj().front();
        BestFit<typename scalar_type_extractor<vectorT>::type, Matrix> bestfit;
        bestfit.set_reference(remove_except_elements(initial, except_particle));
        for(auto snap = dcddata.cbegin(); snap != dcddata.cend(); ++snap)
        {
            const auto core = remove_except_elements(*snap, except_particle);
            const auto R = bestfit.rotational_matrix(core);
            const auto dx = bestfit.zeroing_vector(core);
            auto rotated = *snap;
            for(auto iter = rotated.begin(); iter != rotated.end(); ++iter)
                *iter -= dx;

            for(auto iter = rotated.begin(); iter != rotated.end(); ++iter)
            {
                auto tmp = R * (*iter);
                *iter = tmp;
            }
            writer.write_snapshot(outfile, rotated);
        }
        outfile.close();
        return 0;
    }
    else
    {
        throw std::invalid_argument("unknown file in argument: " + fname);
    }
}

}// mill

#endif//COFFEE_MILL_SUPER_IMPOSE
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "assert.hpp"
#include "SymbolTable.hpp"

using namespace eddic;

//Global symbol table
SymbolTable eddic::symbols;

SymbolTable::SymbolTable(){
    reset();
}

void SymbolTable::reset(){
    functions.clear();
    structs.clear();

    //Add the standard functions to the function table
    defineStandardFunctions();
}

FunctionMap::const_iterator SymbolTable::begin(){
    return functions.cbegin();
}

FunctionMap::const_iterator SymbolTable::end(){
    return functions.cend();
}

void SymbolTable::addFunction(std::shared_ptr<Function> function){
    functions[function->mangledName] = function;
}

std::shared_ptr<Function> SymbolTable::getFunction(const std::string& function){
    return functions[function];
}

bool SymbolTable::exists(const std::string& function){
    return functions.find(function) != functions.end();
}

void SymbolTable::add_struct(std::shared_ptr<Struct> struct_){
    structs[struct_->name] = struct_;
}

std::shared_ptr<Struct> SymbolTable::get_struct(const std::string& struct_){
    return structs[struct_];
}

int SymbolTable::member_offset(std::shared_ptr<Struct> struct_, const std::string& member){
    int offset = 0;

    for(auto& m : struct_->members){
        if(m.name == member){
            return offset;
        }

        offset -= size(m.type);
    }

    ASSERT_PATH_NOT_TAKEN("The member is not part of the struct");
}

int SymbolTable::member_offset_reverse(std::shared_ptr<Struct> struct_, const std::string& member){
    int offset = -size_of_struct(struct_->name) + 8;
    //member_offset(struct_, struct_->members.back().name);

    for(auto& m : struct_->members){
        if(m.name == member){
            return offset;
        }

        offset += size(m.type);
    }

    ASSERT_PATH_NOT_TAKEN("The member is not part of the struct");

}

int SymbolTable::size_of_struct(const std::string& struct_name){
    int struct_size = 0;

    auto struct_ = get_struct(struct_name);

    for(auto& m : struct_->members){
        struct_size += size(m.type);
    }

    return struct_size;
}

bool SymbolTable::struct_exists(const std::string& struct_){
    return structs.find(struct_) != structs.end();
}

void SymbolTable::addReference(const std::string& function){
    ++(functions[function]->references);
}

int SymbolTable::referenceCount(const std::string& function){
    return functions[function]->references;
}

void SymbolTable::addPrintFunction(const std::string& function, BaseType parameterType){
    auto printFunction = std::make_shared<Function>(newSimpleType(BaseType::VOID), "print");
    printFunction->mangledName = function;
    printFunction->parameters.push_back({"a", newSimpleType(parameterType)});
    addFunction(printFunction);
}

void SymbolTable::defineStandardFunctions(){
    //print string
    addPrintFunction("_F5printS", BaseType::STRING);
    addPrintFunction("_F7printlnS", BaseType::STRING);

    //print integer
    addPrintFunction("_F5printI", BaseType::INT);
    addPrintFunction("_F7printlnI", BaseType::INT);

    //print bool
    addPrintFunction("_F5printB", BaseType::BOOL);
    addPrintFunction("_F7printlnB", BaseType::BOOL);

    //print float
    addPrintFunction("_F5printF", BaseType::FLOAT);
    addPrintFunction("_F7printlnF", BaseType::FLOAT);

    //concat function
    auto concatFunction = std::make_shared<Function>(newSimpleType(BaseType::STRING), "concat");
    concatFunction->mangledName = "_F6concatSS";
    concatFunction->parameters.push_back({"a", newSimpleType(BaseType::STRING)});
    concatFunction->parameters.push_back({"b", newSimpleType(BaseType::STRING)});
    addFunction(concatFunction);

    //time function
    auto timeFunction = std::make_shared<Function>(newSimpleType(BaseType::VOID), "time");
    timeFunction->mangledName = "_F4timeAI";
    timeFunction->parameters.push_back({"a", newArrayType(BaseType::INT)});
    addFunction(timeFunction);

    //duration function
    auto durationFunction = std::make_shared<Function>(newSimpleType(BaseType::VOID), "duration");
    durationFunction->mangledName = "_F8durationAIAI";
    durationFunction->parameters.push_back({"a", newArrayType(BaseType::INT)});
    durationFunction->parameters.push_back({"b", newArrayType(BaseType::INT)});
    addFunction(durationFunction);
}
<commit_msg>Fix the offsets for member of structs for 32 bits<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "assert.hpp"
#include "SymbolTable.hpp"

using namespace eddic;

//Global symbol table
SymbolTable eddic::symbols;

SymbolTable::SymbolTable(){
    reset();
}

void SymbolTable::reset(){
    functions.clear();
    structs.clear();

    //Add the standard functions to the function table
    defineStandardFunctions();
}

FunctionMap::const_iterator SymbolTable::begin(){
    return functions.cbegin();
}

FunctionMap::const_iterator SymbolTable::end(){
    return functions.cend();
}

void SymbolTable::addFunction(std::shared_ptr<Function> function){
    functions[function->mangledName] = function;
}

std::shared_ptr<Function> SymbolTable::getFunction(const std::string& function){
    return functions[function];
}

bool SymbolTable::exists(const std::string& function){
    return functions.find(function) != functions.end();
}

void SymbolTable::add_struct(std::shared_ptr<Struct> struct_){
    structs[struct_->name] = struct_;
}

std::shared_ptr<Struct> SymbolTable::get_struct(const std::string& struct_){
    return structs[struct_];
}

int SymbolTable::member_offset(std::shared_ptr<Struct> struct_, const std::string& member){
    int offset = 0;

    for(auto& m : struct_->members){
        if(m.name == member){
            return offset;
        }

        offset -= size(m.type);
    }

    ASSERT_PATH_NOT_TAKEN("The member is not part of the struct");
}

int SymbolTable::member_offset_reverse(std::shared_ptr<Struct> struct_, const std::string& member){
    int offset = -size_of_struct(struct_->name) + size(BaseType::INT);
    //member_offset(struct_, struct_->members.back().name);

    for(auto& m : struct_->members){
        if(m.name == member){
            return offset;
        }

        offset += size(m.type);
    }

    ASSERT_PATH_NOT_TAKEN("The member is not part of the struct");

}

int SymbolTable::size_of_struct(const std::string& struct_name){
    int struct_size = 0;

    auto struct_ = get_struct(struct_name);

    for(auto& m : struct_->members){
        struct_size += size(m.type);
    }

    return struct_size;
}

bool SymbolTable::struct_exists(const std::string& struct_){
    return structs.find(struct_) != structs.end();
}

void SymbolTable::addReference(const std::string& function){
    ++(functions[function]->references);
}

int SymbolTable::referenceCount(const std::string& function){
    return functions[function]->references;
}

void SymbolTable::addPrintFunction(const std::string& function, BaseType parameterType){
    auto printFunction = std::make_shared<Function>(newSimpleType(BaseType::VOID), "print");
    printFunction->mangledName = function;
    printFunction->parameters.push_back({"a", newSimpleType(parameterType)});
    addFunction(printFunction);
}

void SymbolTable::defineStandardFunctions(){
    //print string
    addPrintFunction("_F5printS", BaseType::STRING);
    addPrintFunction("_F7printlnS", BaseType::STRING);

    //print integer
    addPrintFunction("_F5printI", BaseType::INT);
    addPrintFunction("_F7printlnI", BaseType::INT);

    //print bool
    addPrintFunction("_F5printB", BaseType::BOOL);
    addPrintFunction("_F7printlnB", BaseType::BOOL);

    //print float
    addPrintFunction("_F5printF", BaseType::FLOAT);
    addPrintFunction("_F7printlnF", BaseType::FLOAT);

    //concat function
    auto concatFunction = std::make_shared<Function>(newSimpleType(BaseType::STRING), "concat");
    concatFunction->mangledName = "_F6concatSS";
    concatFunction->parameters.push_back({"a", newSimpleType(BaseType::STRING)});
    concatFunction->parameters.push_back({"b", newSimpleType(BaseType::STRING)});
    addFunction(concatFunction);

    //time function
    auto timeFunction = std::make_shared<Function>(newSimpleType(BaseType::VOID), "time");
    timeFunction->mangledName = "_F4timeAI";
    timeFunction->parameters.push_back({"a", newArrayType(BaseType::INT)});
    addFunction(timeFunction);

    //duration function
    auto durationFunction = std::make_shared<Function>(newSimpleType(BaseType::VOID), "duration");
    durationFunction->mangledName = "_F8durationAIAI";
    durationFunction->parameters.push_back({"a", newArrayType(BaseType::INT)});
    durationFunction->parameters.push_back({"b", newArrayType(BaseType::INT)});
    addFunction(durationFunction);
}
<|endoftext|>


<commit_before>#include "client_mode.h"

void
translate_req_template(client* clnt, request_template& req_template)
{
	req_template.place_holder_vecptr.resize(req_template.place_holder_str.size());
	for (int i = 0; i < req_template.place_holder_str.size(); i++) {
		string type = req_template.place_holder_str[i];
		if (clnt->parser.type_to_idvec.find(type) != clnt->parser.type_to_idvec.end()) {
			// do nothing
		} else {
			request_or_reply type_request;
			assert(clnt->parser.find_type_of(type, type_request));
			request_or_reply reply;
			clnt->Send(type_request);
			reply = clnt->Recv();
			vector<int>* ptr = new vector<int>();
			*ptr = reply.result_table;
			clnt->parser.type_to_idvec[type] = ptr;
			cout << type << " has " << ptr->size() << " objects" << endl;
		}
		req_template.place_holder_vecptr[i] = clnt->parser.type_to_idvec[type];
	}
}

void
instantiate_request(client* clnt, request_template& req_template, request_or_reply& r)
{
	for (int i = 0; i < req_template.place_holder_position.size(); i++) {
		int pos = req_template.place_holder_position[i];
		vector<int>* vecptr = req_template.place_holder_vecptr[i];
		if (vecptr == NULL || vecptr->size() == 0) {
			assert(false);
		}
		r.cmd_chains[pos] = (*vecptr)[clnt->cfg->get_random() % (vecptr->size())];
	}
	return ;
}

__thread int local_barrier_val = 1;
int global_barrier_val = 0;
void
ClientBarrier(struct thread_cfg *cfg)
{
	if (cfg->wid == 0) {
		MPI_Barrier(MPI_COMM_WORLD);
		__sync_fetch_and_add(&global_barrier_val, 1);
	}  else {
		__sync_fetch_and_add(&global_barrier_val, 1);
	}
	while (global_barrier_val < local_barrier_val * cfg->ncwkrs) {
		usleep(1);
	}
	local_barrier_val += 1;
}

void
single_execute(client* clnt, string filename, int execute_count)
{
	int sum = 0;
	int result_count;
	request_or_reply request;
	bool success = clnt->parser.parse(filename, request);
	if (!success) {
		cout << "sparql parse error" << endl;
		return ;
	}
	request.silent = global_silent;
	request_or_reply reply;
	for (int i = 0; i < execute_count; i++) {
		uint64_t t1 = timer::get_usec();
		clnt->Send(request);
		reply = clnt->Recv();
		uint64_t t2 = timer::get_usec();
		sum += t2 - t1;
	}
	cout << "result size:" << reply.silent_row_num << endl;
	int row_to_print = min(reply.row_num(), (uint64_t)global_max_print_row);
	if (row_to_print > 0) {
		clnt->print_result(reply, row_to_print);
	}
	cout << "average latency " << sum / execute_count << " us" << endl;
};

void
print_help(void)
{
	cout << "  Commands" << endl;
	cout << "\thelp:          \tdisplay help infomation" << endl;
	cout << "\tquit:          \tquit from client" << endl;
	cout << "\treconfig:      \treload config file" << endl;
	cout << "\tswitch_single: \trun single query (e.g., query [count])" << endl;
	cout << "\tswitch_batch:  \trun concurrent queries (e.g., queries)" << endl;
	cout << "\tswitch_mix:    \trun concurrent & single queries)" << endl;

}

enum { SINGLE_MODE = 0, BATCH_MODE, MIX_MODE, N_MODES };

string mode_str[N_MODES] = {
	"single mode (i.e., query [count]):",
	"batch mode (i.e., queries):",
	"mix mode: (i.e., queries query [count]):"
};

void
interactive_shell(client *clnt)
{
	struct thread_cfg *cfg = clnt->cfg;

	// the master client worker (i.e., sid == 0 and wid == 0)
	if (cfg->sid == 0 && cfg->wid == 0) {
		cout << "input help to get more infomation about the shell" << endl;
		cout << mode_str[global_client_mode] << endl;
	}

	while (true) {
		ClientBarrier(clnt->cfg);

		string input_str;
		if (cfg->sid == 0 && cfg->wid == 0) {
			//cout<<mode_str[global_client_mode]<<endl;
			cout << "> ";
			std::getline(std::cin, input_str);

			// send commands to all client workers
			for (int i = 0; i < cfg->nsrvs; i++) {
				for (int j = 0; j < cfg->ncwkrs; j++) {
					if (i == 0 && j == 0)
						continue;
					cfg->node->Send(i, j, input_str);
				}
			}
		} else {
			// recieve commands
			input_str = cfg->node->Recv();
		}

		//handle commands
		if (input_str == "help") {
			// TODO: support separate client workers
			if (cfg->sid == 0 && cfg->wid == 0)
				print_help();
		} else if (input_str == "quit") {
			if (cfg->wid == 0)
				exit(0);
		} else if (input_str == "reconfig") {
			if (cfg->wid == 0)
				reload_cfg();
		} else if (input_str == "switch_single") {
			if (cfg->wid == 0) {
				global_client_mode = SINGLE_MODE;
				if (cfg->sid == 0)
					cout << mode_str[global_client_mode] << endl;
			}
		} else if (input_str == "switch_batch") {
			if (cfg->wid == 0) {
				global_client_mode = BATCH_MODE;
				if (cfg->sid == 0)
					cout << mode_str[global_client_mode] << endl;
			}
		} else if (input_str == "switch_mix") {
			if (cfg->wid == 0) {
				global_client_mode = MIX_MODE;
				if (cfg->sid == 0)
					cout << mode_str[global_client_mode] << endl;
			}
		} else { //handle queries here
			if (global_client_mode == SINGLE_MODE) {
				if (cfg->sid == 0 && cfg->wid == 0) {
					// run single-command using the master client
					istringstream iss(input_str);
					string fname;
					int cnt = 1;

					iss >> fname >> cnt;
					if (cnt < 1) cnt = 1;

					single_execute(clnt, fname, cnt);
				}
			} else if (global_client_mode == BATCH_MODE) {
				batch_logger logger;

				// ISSUE: client vs. server
				// run batch-command on all clients
				istringstream iss(input_str);
				string fname;

				iss >> fname;

				logger.init();
				nonblocking_execute(clnt, fname, logger);
				//batch_execute(clnt,filename,logger);
				logger.finish();

				ClientBarrier(clnt->cfg);
				//MPI_Barrier(MPI_COMM_WORLD);

				// print results of batch command
				if (cfg->sid == 0 && cfg->wid == 0) {
					// collect logs from other clients
					for (int i = 0; i < cfg->nsrvs * cfg->ncwkrs - 1; i++) {
						batch_logger log = RecvObject<batch_logger>(clnt->cfg);
						logger.merge(log);
					}
					logger.print();
				} else {
					// transport logs to the master client
					SendObject<batch_logger>(clnt->cfg, 0, 0, logger);
				}
			} else if (global_client_mode == MIX_MODE) {
				batch_logger logger;

				istringstream iss(input_str);
				string b_fname;
				string s_fname;
				int cnt = 1;

				iss >> b_fname >> s_fname >> cnt;
				if (cnt < 1) cnt = 1;

				if (cfg->sid == 0 && cfg->wid == 0) {
					// dedicate the master client to run single-command
					single_execute(clnt, s_fname, cnt);
				} else {
					// run batch-command on other clients
					logger.init();
					nonblocking_execute(clnt, b_fname, logger);
					//batch_execute(clnt,batchfile,logger);
					logger.finish();
				}
				ClientBarrier(clnt->cfg);
				//MPI_Barrier(MPI_COMM_WORLD);

				if (cfg->sid == 0 && cfg->wid == 0) {
					// collect logs from other clients
					for (int i = 0; i < cfg->nsrvs * cfg->ncwkrs - 1 ; i++) {
						batch_logger log = RecvObject<batch_logger>(clnt->cfg);
						logger.merge(log);
					}
					logger.print();
				} else {
					// transport logs to the master client
					SendObject<batch_logger>(clnt->cfg, 0, 0, logger);
				}
			}
		}
	}
}

void
batch_execute(client* clnt, string mix_config, batch_logger& logger)
{
	ifstream configfile(mix_config);
	if (!configfile) {
		cout << "File " << mix_config << " not exist" << endl;
		return ;
	}

	int total_query_type;
	int total_request;
	int sleep_round = 1;
	configfile >> total_query_type >> total_request >> sleep_round;
	vector<int > distribution;
	vector<request_template > vec_template;
	vector<request_or_reply > vec_req;
	vec_template.resize(total_query_type);
	vec_req.resize(total_query_type);
	for (int i = 0; i < total_query_type; i++) {
		string filename;
		configfile >> filename;
		int current_dist;
		configfile >> current_dist;
		distribution.push_back(current_dist);
		bool success = clnt->parser.parse_template(filename, vec_template[i]);
		translate_req_template(clnt, vec_template[i]);
		vec_req[i].cmd_chains = vec_template[i].cmd_chains;
		if (!success) {
			cout << "sparql parse error" << endl;
			return ;
		}
		vec_req[i].silent = global_silent;
	}
	uint64_t start_time = timer::get_usec();
	for (int i = 0; i < global_batch_factor; i++) {
		int idx = mymath::get_distribution(clnt->cfg->get_random(), distribution);
		instantiate_request(clnt, vec_template[idx], vec_req[idx]);
		clnt->GetId(vec_req[idx]);
		logger.start_record(vec_req[idx].parent_id, idx);
		clnt->Send(vec_req[idx]);
	}
	for (int i = 0; i < total_request; i++) {
		request_or_reply reply = clnt->Recv();
		logger.end_record(reply.parent_id);
		int idx = mymath::get_distribution(clnt->cfg->get_random(), distribution);
		instantiate_request(clnt, vec_template[idx], vec_req[idx]);
		clnt->GetId(vec_req[idx]);
		logger.start_record(vec_req[idx].parent_id, idx);
		clnt->Send(vec_req[idx]);
	}
	for (int i = 0; i < global_batch_factor; i++) {
		request_or_reply reply = clnt->Recv();
		logger.end_record(reply.parent_id);
	}
	uint64_t end_time = timer::get_usec();
	cout << 1000.0 * (total_request + global_batch_factor) / (end_time - start_time) << " Kops" << endl;
};

void
nonblocking_execute(client* clnt, string mix_config, batch_logger& logger)
{
	ifstream configfile(mix_config);
	if (!configfile) {
		cout << "File " << mix_config << " not exist" << endl;
		return ;
	}

	int total_query_type;
	int total_request;
	int sleep_round = 1;
	configfile >> total_query_type >> total_request >> sleep_round;

	vector<int > distribution;
	vector<request_template > vec_template;
	vector<request_or_reply > vec_req;

	vec_template.resize(total_query_type);
	vec_req.resize(total_query_type);
	for (int i = 0; i < total_query_type; i++) {
		string filename;
		configfile >> filename;
		int current_dist;
		configfile >> current_dist;
		distribution.push_back(current_dist);
		bool success = clnt->parser.parse_template(filename, vec_template[i]);
		translate_req_template(clnt, vec_template[i]);
		vec_req[i].cmd_chains = vec_template[i].cmd_chains;
		if (!success) {
			cout << "sparql parse error" << endl;
			return ;
		}
		vec_req[i].silent = global_silent;
	}

	int send_request = 0;
	int recv_request = 0;
	while (recv_request != total_request) {
		for (int t = 0; t < 10; t++) {
			if (send_request < total_request) {
				send_request++;
				int idx = mymath::get_distribution(clnt->cfg->get_random(), distribution);
				instantiate_request(clnt, vec_template[idx], vec_req[idx]);
				clnt->GetId(vec_req[idx]);
				logger.start_record(vec_req[idx].parent_id, idx);
				clnt->Send(vec_req[idx]);
			}
		}

		for (int i = 0; i < sleep_round; i++) {
			timer::cpu_relax(100);
			request_or_reply reply;
			bool success = TryRecvR(clnt->cfg, reply);
			while (success) {
				recv_request++;
				logger.end_record(reply.parent_id);
				success = TryRecvR(clnt->cfg, reply);
			}
		}
	}
};
<commit_msg>client barrier<commit_after>#include "client_mode.h"

void
translate_req_template(client* clnt, request_template& req_template)
{
	req_template.place_holder_vecptr.resize(req_template.place_holder_str.size());
	for (int i = 0; i < req_template.place_holder_str.size(); i++) {
		string type = req_template.place_holder_str[i];
		if (clnt->parser.type_to_idvec.find(type) != clnt->parser.type_to_idvec.end()) {
			// do nothing
		} else {
			request_or_reply type_request;
			assert(clnt->parser.find_type_of(type, type_request));
			request_or_reply reply;
			clnt->Send(type_request);
			reply = clnt->Recv();
			vector<int>* ptr = new vector<int>();
			*ptr = reply.result_table;
			clnt->parser.type_to_idvec[type] = ptr;
			cout << type << " has " << ptr->size() << " objects" << endl;
		}
		req_template.place_holder_vecptr[i] = clnt->parser.type_to_idvec[type];
	}
}

void
instantiate_request(client* clnt, request_template& req_template, request_or_reply& r)
{
	for (int i = 0; i < req_template.place_holder_position.size(); i++) {
		int pos = req_template.place_holder_position[i];
		vector<int>* vecptr = req_template.place_holder_vecptr[i];
		if (vecptr == NULL || vecptr->size() == 0) {
			assert(false);
		}
		r.cmd_chains[pos] = (*vecptr)[clnt->cfg->get_random() % (vecptr->size())];
	}
}

void
client_barrier(struct thread_cfg *cfg)
{
	static int _curr = 0;
	static __thread int _next = 1;

	// inter-node barrier
	if (cfg->wid == 0)
		MPI_Barrier(MPI_COMM_WORLD);

	// intra-node barrier
	__sync_fetch_and_add(&_curr, 1);
	while (_curr < _next)
		usleep(1); // wait
	_next += cfg->ncwkrs; // next barrier
}

void
single_execute(client* clnt, string filename, int execute_count)
{
	int sum = 0;
	int result_count;
	request_or_reply request;
	bool success = clnt->parser.parse(filename, request);
	if (!success) {
		cout << "sparql parse error" << endl;
		return ;
	}
	request.silent = global_silent;
	request_or_reply reply;
	for (int i = 0; i < execute_count; i++) {
		uint64_t t1 = timer::get_usec();
		clnt->Send(request);
		reply = clnt->Recv();
		uint64_t t2 = timer::get_usec();
		sum += t2 - t1;
	}
	cout << "result size:" << reply.silent_row_num << endl;
	int row_to_print = min(reply.row_num(), (uint64_t)global_max_print_row);
	if (row_to_print > 0) {
		clnt->print_result(reply, row_to_print);
	}
	cout << "average latency " << sum / execute_count << " us" << endl;
}

void
print_help(void)
{
	cout << "  Commands" << endl;
	cout << "\thelp:          \tdisplay help infomation" << endl;
	cout << "\tquit:          \tquit from client" << endl;
	cout << "\treconfig:      \treload config file" << endl;
	cout << "\tswitch_single: \trun single query (e.g., query [count])" << endl;
	cout << "\tswitch_batch:  \trun concurrent queries (e.g., queries)" << endl;
	cout << "\tswitch_mix:    \trun concurrent & single queries)" << endl;

}

enum { SINGLE_MODE = 0, BATCH_MODE, MIX_MODE, N_MODES };

string mode_str[N_MODES] = {
	"single mode (i.e., query [count]):",
	"batch mode (i.e., queries):",
	"mix mode: (i.e., queries query [count]):"
};

void
interactive_shell(client *clnt)
{
	struct thread_cfg *cfg = clnt->cfg;

	// the master client worker (i.e., sid == 0 and wid == 0)
	if (cfg->sid == 0 && cfg->wid == 0) {
		cout << "input help to get more infomation about the shell" << endl;
		cout << mode_str[global_client_mode] << endl;
	}

	while (true) {
		client_barrier(clnt->cfg);

		string input_str;
		if (cfg->sid == 0 && cfg->wid == 0) {
			cout << "> ";
			std::getline(std::cin, input_str);

			// send commands to all client workers
			for (int i = 0; i < cfg->nsrvs; i++) {
				for (int j = 0; j < cfg->ncwkrs; j++) {
					if (i == 0 && j == 0)
						continue;
					cfg->node->Send(i, j, input_str);
				}
			}
		} else {
			// recieve commands
			input_str = cfg->node->Recv();
		}

		//handle commands
		if (input_str == "help") {
			// TODO: support separate client workers
			if (cfg->sid == 0 && cfg->wid == 0)
				print_help();
		} else if (input_str == "quit") {
			if (cfg->wid == 0)
				exit(0);
		} else if (input_str == "reconfig") {
			if (cfg->wid == 0)
				reload_cfg();
		} else if (input_str == "switch_single") {
			if (cfg->wid == 0) {
				global_client_mode = SINGLE_MODE;
				if (cfg->sid == 0)
					cout << mode_str[global_client_mode] << endl;
			}
		} else if (input_str == "switch_batch") {
			if (cfg->wid == 0) {
				global_client_mode = BATCH_MODE;
				if (cfg->sid == 0)
					cout << mode_str[global_client_mode] << endl;
			}
		} else if (input_str == "switch_mix") {
			if (cfg->wid == 0) {
				global_client_mode = MIX_MODE;
				if (cfg->sid == 0)
					cout << mode_str[global_client_mode] << endl;
			}
		} else { //handle queries here
			if (global_client_mode == SINGLE_MODE) {
				if (cfg->sid == 0 && cfg->wid == 0) {
					// run single-command using the master client
					istringstream iss(input_str);
					string fname;
					int cnt = 1;

					iss >> fname >> cnt;
					if (cnt < 1) cnt = 1;

					single_execute(clnt, fname, cnt);
				}
			} else if (global_client_mode == BATCH_MODE) {
				batch_logger logger;

				// ISSUE: client vs. server
				// run batch-command on all clients
				istringstream iss(input_str);
				string fname;

				iss >> fname;

				logger.init();
				nonblocking_execute(clnt, fname, logger);
				//batch_execute(clnt,filename,logger);
				logger.finish();

				client_barrier(clnt->cfg);
				//MPI_Barrier(MPI_COMM_WORLD);

				// print results of batch command
				if (cfg->sid == 0 && cfg->wid == 0) {
					// collect logs from other clients
					for (int i = 0; i < cfg->nsrvs * cfg->ncwkrs - 1; i++) {
						batch_logger log = RecvObject<batch_logger>(clnt->cfg);
						logger.merge(log);
					}
					logger.print();
				} else {
					// transport logs to the master client
					SendObject<batch_logger>(clnt->cfg, 0, 0, logger);
				}
			} else if (global_client_mode == MIX_MODE) {
				batch_logger logger;

				istringstream iss(input_str);
				string b_fname;
				string s_fname;
				int cnt = 1;

				iss >> b_fname >> s_fname >> cnt;
				if (cnt < 1) cnt = 1;

				if (cfg->sid == 0 && cfg->wid == 0) {
					// dedicate the master client to run single-command
					single_execute(clnt, s_fname, cnt);
				} else {
					// run batch-command on other clients
					logger.init();
					nonblocking_execute(clnt, b_fname, logger);
					//batch_execute(clnt,batchfile,logger);
					logger.finish();
				}
				client_barrier(clnt->cfg);
				//MPI_Barrier(MPI_COMM_WORLD);

				if (cfg->sid == 0 && cfg->wid == 0) {
					// collect logs from other clients
					for (int i = 0; i < cfg->nsrvs * cfg->ncwkrs - 1 ; i++) {
						batch_logger log = RecvObject<batch_logger>(clnt->cfg);
						logger.merge(log);
					}
					logger.print();
				} else {
					// transport logs to the master client
					SendObject<batch_logger>(clnt->cfg, 0, 0, logger);
				}
			}
		}
	}
}

void
batch_execute(client* clnt, string mix_config, batch_logger& logger)
{
	ifstream configfile(mix_config);
	if (!configfile) {
		cout << "File " << mix_config << " not exist" << endl;
		return ;
	}

	int total_query_type;
	int total_request;
	int sleep_round = 1;
	configfile >> total_query_type >> total_request >> sleep_round;
	vector<int > distribution;
	vector<request_template > vec_template;
	vector<request_or_reply > vec_req;
	vec_template.resize(total_query_type);
	vec_req.resize(total_query_type);
	for (int i = 0; i < total_query_type; i++) {
		string filename;
		configfile >> filename;
		int current_dist;
		configfile >> current_dist;
		distribution.push_back(current_dist);
		bool success = clnt->parser.parse_template(filename, vec_template[i]);
		translate_req_template(clnt, vec_template[i]);
		vec_req[i].cmd_chains = vec_template[i].cmd_chains;
		if (!success) {
			cout << "sparql parse error" << endl;
			return ;
		}
		vec_req[i].silent = global_silent;
	}
	uint64_t start_time = timer::get_usec();
	for (int i = 0; i < global_batch_factor; i++) {
		int idx = mymath::get_distribution(clnt->cfg->get_random(), distribution);
		instantiate_request(clnt, vec_template[idx], vec_req[idx]);
		clnt->GetId(vec_req[idx]);
		logger.start_record(vec_req[idx].parent_id, idx);
		clnt->Send(vec_req[idx]);
	}
	for (int i = 0; i < total_request; i++) {
		request_or_reply reply = clnt->Recv();
		logger.end_record(reply.parent_id);
		int idx = mymath::get_distribution(clnt->cfg->get_random(), distribution);
		instantiate_request(clnt, vec_template[idx], vec_req[idx]);
		clnt->GetId(vec_req[idx]);
		logger.start_record(vec_req[idx].parent_id, idx);
		clnt->Send(vec_req[idx]);
	}
	for (int i = 0; i < global_batch_factor; i++) {
		request_or_reply reply = clnt->Recv();
		logger.end_record(reply.parent_id);
	}
	uint64_t end_time = timer::get_usec();
	cout << 1000.0 * (total_request + global_batch_factor) / (end_time - start_time) << " Kops" << endl;
};

void
nonblocking_execute(client* clnt, string mix_config, batch_logger& logger)
{
	ifstream configfile(mix_config);
	if (!configfile) {
		cout << "File " << mix_config << " not exist" << endl;
		return ;
	}

	int total_query_type;
	int total_request;
	int sleep_round = 1;
	configfile >> total_query_type >> total_request >> sleep_round;

	vector<int > distribution;
	vector<request_template > vec_template;
	vector<request_or_reply > vec_req;

	vec_template.resize(total_query_type);
	vec_req.resize(total_query_type);
	for (int i = 0; i < total_query_type; i++) {
		string filename;
		configfile >> filename;
		int current_dist;
		configfile >> current_dist;
		distribution.push_back(current_dist);
		bool success = clnt->parser.parse_template(filename, vec_template[i]);
		translate_req_template(clnt, vec_template[i]);
		vec_req[i].cmd_chains = vec_template[i].cmd_chains;
		if (!success) {
			cout << "sparql parse error" << endl;
			return ;
		}
		vec_req[i].silent = global_silent;
	}

	int send_request = 0;
	int recv_request = 0;
	while (recv_request != total_request) {
		for (int t = 0; t < 10; t++) {
			if (send_request < total_request) {
				send_request++;
				int idx = mymath::get_distribution(clnt->cfg->get_random(), distribution);
				instantiate_request(clnt, vec_template[idx], vec_req[idx]);
				clnt->GetId(vec_req[idx]);
				logger.start_record(vec_req[idx].parent_id, idx);
				clnt->Send(vec_req[idx]);
			}
		}

		for (int i = 0; i < sleep_round; i++) {
			timer::cpu_relax(100);
			request_or_reply reply;
			bool success = TryRecvR(clnt->cfg, reply);
			while (success) {
				recv_request++;
				logger.end_record(reply.parent_id);
				success = TryRecvR(clnt->cfg, reply);
			}
		}
	}
};
<|endoftext|>


<commit_before>//
// BatchEncoder (Audio Conversion GUI)
// Copyright (C) 2005-2017 Wiesław Šoltés <wieslaw.soltes@gmail.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 2 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//

#include "StdAfx.h"
#include "BatchEncoder.h"
#include "UnicodeUtf8.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// UNICODE to UTF8

//
// use free(...) to release memory (returned buffer pointer) and avoid memory leaks
//
// WideCharToMultiByte()
//
unsigned char *MakeUtf8String(const wchar_t *unicode)
{
    int size = 0, index = 0, out_index = 0;
    unsigned char *out;
    unsigned short c;

    c = unicode[index++];
    while (c)
    {
        if (c < 0x0080)
            size += 1;
        else if (c < 0x0800)
            size += 2;
        else
            size += 3;

        c = unicode[index++];
    }

    out = (unsigned char*)malloc(size + 1);
    if (out == NULL)
        return NULL;
    index = 0;

    c = unicode[index++];
    while (c)
    {
        if (c < 0x080)
        {
            out[out_index++] = (unsigned char)c;
        }
        else if (c < 0x800)
        {
            out[out_index++] = 0xc0 | (c >> 6);
            out[out_index++] = 0x80 | (c & 0x3f);
        }
        else
        {
            out[out_index++] = 0xe0 | (c >> 12);
            out[out_index++] = 0x80 | ((c >> 6) & 0x3f);
            out[out_index++] = 0x80 | (c & 0x3f);
        }
        c = unicode[index++];
    }

    out[out_index] = 0x00;
    return out;
}

// UTF8 to UNICODE

//
// use free(...) to release memory (returned buffer pointer) and avoid memory leaks
//
// MultiByteToWideChar(CP_UTF8)
//
wchar_t *MakeUnicodeString(const unsigned char *utf8)
{
    int size = 0, index = 0, out_index = 0;
    wchar_t *out;
    unsigned char c;

    c = utf8[index++];
    while (c)
    {
        if ((c & 0x80) == 0)
            index += 0;
        else if ((c & 0xe0) == 0xe0)
            index += 2;
        else
            index += 1;

        size += 1;
        c = utf8[index++];
    }

    out = (wchar_t *)malloc((size + 1) * sizeof(wchar_t));
    if (out == NULL)
        return NULL;
    index = 0;

    c = utf8[index++];
    while (c)
    {
        if ((c & 0x80) == 0)
        {
            out[out_index++] = c;
        }
        else if ((c & 0xe0) == 0xe0)
        {
            out[out_index] = (c & 0x1F) << 12;
            c = utf8[index++];
            out[out_index] |= (c & 0x3F) << 6;
            c = utf8[index++];
            out[out_index++] |= (c & 0x3F);
        }
        else
        {
            out[out_index] = (c & 0x3F) << 6;
            c = utf8[index++];
            out[out_index++] |= (c & 0x3F);
        }
        c = utf8[index++];
    }

    out[out_index] = 0;
    return out;
}

// ANSI (char) to UNICODE

//
// use free(...) to release 'to' buffer after using it
//
int UnicodeEncode(const char *from, wchar_t **to)
{
    wchar_t *unicode;
    int wchars, err;

    wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, (int)strlen(from), NULL, 0);
    if (wchars == 0)
        return -1;

    unicode = (wchar_t *)calloc(wchars + 1, sizeof(unsigned short));
    if (unicode == NULL)
        return -1;

    err = ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, (int)strlen(from), unicode, wchars);
    if (err != wchars)
    {
        *to = NULL;
        free(unicode);
        return -1;
    }

    *to = unicode;
    return 0;
}

// UNICODE to ANSI (char)

//
// use free(...) to release 'to' buffer after using it
//
int UnicodeDecode(const wchar_t *from, char **to)
{
    int chars, err;

    chars = ::WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, from, -1, NULL, 0, NULL, NULL);
    if (chars == 0)
        return -1;

    *to = (char *)calloc(chars + 1, sizeof(unsigned char));
    if (*to == NULL)
        return -1;

    err = ::WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, from, -1, *to, chars, NULL, NULL);
    if (err != chars)
    {
        free(*to);
        *to = NULL;
        return -1;
    }

    return 0;
}

//
// use free(...) to release 'to' buffer after using it
//
int Utf8Encode(const char *from, char **to)
{
    wchar_t *unicode;
    int wchars, err;

    wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, (int)strlen(from), NULL, 0);
    if (wchars == 0)
        return -1;

    unicode = (wchar_t *)calloc(wchars + 1, sizeof(unsigned short));
    if (unicode == NULL)
        return -1;

    err = ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, (int)strlen(from), unicode, wchars);
    if (err != wchars)
    {
        free(unicode);
        return -1;
    }

    *to = (char *)MakeUtf8String(unicode);
    free(unicode);
    return 0;
}

//
// use free(...) to release 'to' buffer after using it
//
int Utf8Decode(const char *from, char **to)
{
    wchar_t *unicode;
    int chars, err;

    unicode = MakeUnicodeString((unsigned char *)from);
    if (unicode == NULL)
        return -1;

    chars = ::WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, -1, NULL, 0, NULL, NULL);
    if (chars == 0)
    {
        free(unicode);
        return -1;
    }

    *to = (char *)calloc(chars + 1, sizeof(unsigned char));
    if (*to == NULL)
    {
        free(unicode);
        return -1;
    }

    err = ::WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, -1, *to, chars, NULL, NULL);
    if (err != chars)
    {
        free(unicode);
        free(*to);
        *to = NULL;
        return -1;
    }

    free(unicode);
    return 0;
}
<commit_msg>Update UnicodeUtf8.cpp<commit_after>// Copyright (c) Wiesław Šoltés. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include "StdAfx.h"
#include "BatchEncoder.h"
#include "UnicodeUtf8.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// UNICODE to UTF8

//
// use free(...) to release memory (returned buffer pointer) and avoid memory leaks
//
// WideCharToMultiByte()
//
unsigned char *MakeUtf8String(const wchar_t *unicode)
{
    int size = 0, index = 0, out_index = 0;
    unsigned char *out;
    unsigned short c;

    c = unicode[index++];
    while (c)
    {
        if (c < 0x0080)
            size += 1;
        else if (c < 0x0800)
            size += 2;
        else
            size += 3;

        c = unicode[index++];
    }

    out = (unsigned char*)malloc(size + 1);
    if (out == NULL)
        return NULL;
    index = 0;

    c = unicode[index++];
    while (c)
    {
        if (c < 0x080)
        {
            out[out_index++] = (unsigned char)c;
        }
        else if (c < 0x800)
        {
            out[out_index++] = 0xc0 | (c >> 6);
            out[out_index++] = 0x80 | (c & 0x3f);
        }
        else
        {
            out[out_index++] = 0xe0 | (c >> 12);
            out[out_index++] = 0x80 | ((c >> 6) & 0x3f);
            out[out_index++] = 0x80 | (c & 0x3f);
        }
        c = unicode[index++];
    }

    out[out_index] = 0x00;
    return out;
}

// UTF8 to UNICODE

//
// use free(...) to release memory (returned buffer pointer) and avoid memory leaks
//
// MultiByteToWideChar(CP_UTF8)
//
wchar_t *MakeUnicodeString(const unsigned char *utf8)
{
    int size = 0, index = 0, out_index = 0;
    wchar_t *out;
    unsigned char c;

    c = utf8[index++];
    while (c)
    {
        if ((c & 0x80) == 0)
            index += 0;
        else if ((c & 0xe0) == 0xe0)
            index += 2;
        else
            index += 1;

        size += 1;
        c = utf8[index++];
    }

    out = (wchar_t *)malloc((size + 1) * sizeof(wchar_t));
    if (out == NULL)
        return NULL;
    index = 0;

    c = utf8[index++];
    while (c)
    {
        if ((c & 0x80) == 0)
        {
            out[out_index++] = c;
        }
        else if ((c & 0xe0) == 0xe0)
        {
            out[out_index] = (c & 0x1F) << 12;
            c = utf8[index++];
            out[out_index] |= (c & 0x3F) << 6;
            c = utf8[index++];
            out[out_index++] |= (c & 0x3F);
        }
        else
        {
            out[out_index] = (c & 0x3F) << 6;
            c = utf8[index++];
            out[out_index++] |= (c & 0x3F);
        }
        c = utf8[index++];
    }

    out[out_index] = 0;
    return out;
}

// ANSI (char) to UNICODE

//
// use free(...) to release 'to' buffer after using it
//
int UnicodeEncode(const char *from, wchar_t **to)
{
    wchar_t *unicode;
    int wchars, err;

    wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, (int)strlen(from), NULL, 0);
    if (wchars == 0)
        return -1;

    unicode = (wchar_t *)calloc(wchars + 1, sizeof(unsigned short));
    if (unicode == NULL)
        return -1;

    err = ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, (int)strlen(from), unicode, wchars);
    if (err != wchars)
    {
        *to = NULL;
        free(unicode);
        return -1;
    }

    *to = unicode;
    return 0;
}

// UNICODE to ANSI (char)

//
// use free(...) to release 'to' buffer after using it
//
int UnicodeDecode(const wchar_t *from, char **to)
{
    int chars, err;

    chars = ::WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, from, -1, NULL, 0, NULL, NULL);
    if (chars == 0)
        return -1;

    *to = (char *)calloc(chars + 1, sizeof(unsigned char));
    if (*to == NULL)
        return -1;

    err = ::WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, from, -1, *to, chars, NULL, NULL);
    if (err != chars)
    {
        free(*to);
        *to = NULL;
        return -1;
    }

    return 0;
}

//
// use free(...) to release 'to' buffer after using it
//
int Utf8Encode(const char *from, char **to)
{
    wchar_t *unicode;
    int wchars, err;

    wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, (int)strlen(from), NULL, 0);
    if (wchars == 0)
        return -1;

    unicode = (wchar_t *)calloc(wchars + 1, sizeof(unsigned short));
    if (unicode == NULL)
        return -1;

    err = ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, (int)strlen(from), unicode, wchars);
    if (err != wchars)
    {
        free(unicode);
        return -1;
    }

    *to = (char *)MakeUtf8String(unicode);
    free(unicode);
    return 0;
}

//
// use free(...) to release 'to' buffer after using it
//
int Utf8Decode(const char *from, char **to)
{
    wchar_t *unicode;
    int chars, err;

    unicode = MakeUnicodeString((unsigned char *)from);
    if (unicode == NULL)
        return -1;

    chars = ::WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, -1, NULL, 0, NULL, NULL);
    if (chars == 0)
    {
        free(unicode);
        return -1;
    }

    *to = (char *)calloc(chars + 1, sizeof(unsigned char));
    if (*to == NULL)
    {
        free(unicode);
        return -1;
    }

    err = ::WideCharToMultiByte(GetConsoleCP(), WC_COMPOSITECHECK, unicode, -1, *to, chars, NULL, NULL);
    if (err != chars)
    {
        free(unicode);
        free(*to);
        *to = NULL;
        return -1;
    }

    free(unicode);
    return 0;
}
<|endoftext|>


<commit_before>#ifndef _H_XML_NODE
#define _H_XML_NODE

#include <iostream>
#include <list>
#include <string>

namespace Xml
{

    /**
     * Defines the abstract class of a node for interface purpose
     */
    class Node
    {
    public:

        /*
         * Gets all children nodes
         *
         * @return A list of all children nodes (obviously...)
         */
        virtual
        std::list<Node *>
        childrenNodes() = 0;

        virtual
        std::list<Node const *> const
        childrenNodes() const = 0;

        /*
         * Implements standart stream operator
         */
        virtual
        std::ostream &
        operator >> (std::ostream & stream) const = 0;

        /*
         * Destructor
         */
        virtual
        ~Node()
        {

        }

    };

    /*
     * Defines a sexier standart stream operator
     */
    inline
    std::ostream &
    operator << (std::ostream & stream, Node const & node)
    {
        node >> stream;
        return stream;
    }

}

#endif //_H_XML_NODE
<commit_msg>Implements Xml::Node::exportToStream()<commit_after>#ifndef _H_XML_NODE
#define _H_XML_NODE

#include <iostream>
#include <list>
#include <string>

namespace Xml
{

    /**
     * Defines the abstract class of a node for interface purpose
     */
    class Node
    {
    public:

        /**
         * Implements standart stream operator
         */
        inline
        std::ostream &
        operator >> (std::ostream & stream) const
        {
            exportToStream(stream, "");
            return stream;
        }

        /**
         * Destructor
         */
        virtual
        ~Node()
        {

        }

    protected:

        /**
         * Exports to a <stream> with a given <indent>
         *
         * @param <stream> is the stream to export to
         * @param <indent> is the the indentation prefix
         */
        virtual
        void
        exportToStream(std::ostream & stream, std::string const & indent) const = 0;

        /**
         * Gets the content text if is a Xml::Text
         */
        virtual
        std::string
        contentText() const
        {
            return "";
        }

    };

    /**
     * Defines a sexier standart stream operator
     */
    inline
    std::ostream &
    operator << (std::ostream & stream, Node const & node)
    {
        node >> stream;
        return stream;
    }

}

#endif //_H_XML_NODE
<|endoftext|>


<commit_before>#include <ace-c/Lexer.hpp>
#include <ace-c/Operator.hpp>
#include <ace-c/CompilerError.hpp>
#include <ace-c/Keywords.hpp>

#include <array>
#include <sstream>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <iostream>

using namespace utf;

Lexer::Lexer(const SourceStream &source_stream, TokenStream *token_stream,
    CompilationUnit *compilation_unit)
    : m_source_stream(source_stream),
      m_token_stream(token_stream),
      m_compilation_unit(compilation_unit)
{
    m_source_location.SetFileName(m_source_stream.GetFile()->GetFilePath());
}

Lexer::Lexer(const Lexer &other)
    : m_source_stream(other.m_source_stream),
      m_token_stream(other.m_token_stream),
      m_compilation_unit(other.m_compilation_unit),
      m_source_location(other.m_source_location)
{
}

void Lexer::Analyze()
{
    // skip initial whitespace
    SkipWhitespace();

    while (m_source_stream.HasNext() && m_source_stream.Peek() != '\0') {
        Token token = NextToken();
        if (!token.Empty()) {
            m_token_stream->Push(token);
        }

        // SkipWhitespace() returns true if there was a newline
        const SourceLocation location = m_source_location;
        if (SkipWhitespace()) {
            // add the `newline` statement terminator if not a continuation token
            if (token && token.GetTokenClass() != TK_NEWLINE && !token.IsContinuationToken()) {
                // skip whitespace before next token
                SkipWhitespace();

                // check if next token is connected
                if (m_source_stream.HasNext() && m_source_stream.Peek() != '\0') {
                    auto peek = m_source_stream.Peek();
                    if (peek == '{' || peek == '.') {
                        // do not add newline
                        continue;
                    }
                }

                // add newline
                m_token_stream->Push(Token(TK_NEWLINE, "newline", location));
            }
        }
    }
}

Token Lexer::NextToken()
{
    SourceLocation location = m_source_location;

    std::array<u32char, 3> ch;
    int total_pos_change = 0;
    for (int i = 0; i < 3; i++) {
        int pos_change = 0;
        ch[i] = m_source_stream.Next(pos_change);
        total_pos_change += pos_change;
    }
    // go back to previous position
    m_source_stream.GoBack(total_pos_change);

    if (ch[0] == '\"' || ch[0] == '\'') {
        return ReadStringLiteral();
    } else if (ch[0] == '0' && (ch[1] == 'x' || ch[1] == 'X')) {
        return ReadHexNumberLiteral();
    } else if (utf32_isdigit(ch[0]) || (ch[0] == '.' && utf32_isdigit(ch[1]))) {
        return ReadNumberLiteral();
    } else if (ch[0] == '/' && ch[1] == '/') {
        return ReadLineComment();
    } else if (ch[0] == '/' && ch[1] == '*') {
        return ReadBlockComment();
        /*if (ch[2] == '*') {
            return ReadDocumentation();
        } else {
            return ReadBlockComment();
        }*/
    } else if (ch[0] == '_' || utf32_isalpha(ch[0])) {
        return ReadIdentifier();
    } else if (ch[0] == '-' && ch[1] == '>') {
        for (int i = 0; i < 2; i++) {
            int pos_change = 0;
            m_source_stream.Next(pos_change);
            m_source_location.GetColumn() += pos_change;
        }
        return Token(TK_RIGHT_ARROW, "->", location);
    } else if (ch[0] == '+' || ch[0] == '-' ||
               ch[0] == '*' || ch[0] == '/' ||
               ch[0] == '%' || ch[0] == '^' ||
               ch[0] == '&' || ch[0] == '|' ||
               ch[0] == '<' || ch[0] == '>' ||
               ch[0] == '=' || ch[0] == '!') {
        return ReadOperator();
    } else if (ch[0] == ',') {
        int pos_change = 0;
        m_source_stream.Next(pos_change);
        m_source_location.GetColumn() += pos_change;
        return Token(TK_COMMA, ",", location);
    } else if (ch[0] == ';') {
        int pos_change = 0;
        m_source_stream.Next(pos_change);
        m_source_location.GetColumn() += pos_change;
        return Token(TK_SEMICOLON, ";", location);
    } else if (ch[0] == ':') {
        if (ch[1] == ':') {
            for (int i = 0; i < 2; i++) {
                int pos_change = 0;
                m_source_stream.Next(pos_change);
                m_source_location.GetColumn() += pos_change;
            }
            return Token(TK_DOUBLE_COLON, "::", location);
        } else {
            int pos_change = 0;
            m_source_stream.Next(pos_change);
            m_source_location.GetColumn() += pos_change;
            return Token(TK_COLON, ":", location);
        }
    } else if (ch[0] == '.') {
        if (ch[1] == '.' && ch[2] == '.') {
            for (int i = 0; i < 3; i++) {
                int pos_change = 0;
                m_source_stream.Next(pos_change);
                m_source_location.GetColumn() += pos_change;
            }
            return Token(TK_ELLIPSIS, "...", location);
        } else {
            int pos_change = 0;
            m_source_stream.Next(pos_change);
            m_source_location.GetColumn() += pos_change;
            return Token(TK_DOT, ".", location);
        }
    } else if (ch[0] == '(') {
        int pos_change = 0;
        m_source_stream.Next(pos_change);
        m_source_location.GetColumn() += pos_change;
        return Token(TK_OPEN_PARENTH, "(", location);
    } else if (ch[0] == ')') {
        int pos_change = 0;
        m_source_stream.Next(pos_change);
        m_source_location.GetColumn() += pos_change;
        return Token(TK_CLOSE_PARENTH, ")", location);
    } else if (ch[0] == '[') {
        int pos_change = 0;
        m_source_stream.Next(pos_change);
        m_source_location.GetColumn() += pos_change;
        return Token(TK_OPEN_BRACKET, "[", location);
    } else if (ch[0] == ']') {
        int pos_change = 0;
        m_source_stream.Next(pos_change);
        m_source_location.GetColumn() += pos_change;
        return Token(TK_CLOSE_BRACKET, "]", location);
    } else if (ch[0] == '{') {
        int pos_change = 0;
        m_source_stream.Next(pos_change);
        m_source_location.GetColumn() += pos_change;
        return Token(TK_OPEN_BRACE, "{", location);
    } else if (ch[0] == '}') {
        int pos_change = 0;
        m_source_stream.Next(pos_change);
        m_source_location.GetColumn() += pos_change;
        return Token(TK_CLOSE_BRACE, "}", location);
    } else {
        int pos_change = 0;
        utf::u32char bad_token = m_source_stream.Next(pos_change);

        char bad_token_str[sizeof(bad_token)] = { '\0' };
        utf::char32to8(bad_token, bad_token_str);

        CompilerError error(Level_fatal, Msg_unexpected_token,
            location, std::string(bad_token_str));

        m_compilation_unit->GetErrorList().AddError(error);
        m_source_location.GetColumn() += pos_change;

        return Token::EMPTY;
    }
}

u32char Lexer::ReadEscapeCode()
{
    // location of the start of the escape code
    SourceLocation location = m_source_location;

    if (HasNext()) {
        int pos_change = 0;
        u32char esc = m_source_stream.Next(pos_change);
        m_source_location.GetColumn() += pos_change;

        // TODO: add support for unicode escapes
        switch (esc) {
        case 't': return '\t';
        case 'b': return '\b';
        case 'n': return '\n';
        case 'r': return '\r';
        case 'f': return '\f';
        case '\'':
        case '\"':
        case '\\':
            // return the escape itself
            return esc;
        default:
            m_compilation_unit->GetErrorList().AddError(
                CompilerError(Level_fatal, Msg_unrecognized_escape_sequence,
                    location, std::string("\\") + utf::get_bytes(esc)));
        }
    }

    return 0;
}

Token Lexer::ReadStringLiteral()
{
    // the location for the start of the string
    SourceLocation location = m_source_location;

    std::string value;
    int pos_change = 0;

    u32char delim = m_source_stream.Next(pos_change);
    m_source_location.GetColumn() += pos_change;

    // the character as utf-32
    u32char ch = m_source_stream.Next(pos_change);

    while (true) {
        m_source_location.GetColumn() += pos_change;

        if (ch == delim) {
            // end of string
            break;
        } else if (ch == (u32char)'\n' || !HasNext()) {
            // unterminated string literal
            m_compilation_unit->GetErrorList().AddError(
                CompilerError(Level_fatal, Msg_unterminated_string_literal,
                    location));

            if (ch == (u32char)'\n') {
                // increment line and reset column
                m_source_location.GetColumn() = 0;
                m_source_location.GetLine()++;
            }

            break;
        }

        // determine whether to read an escape sequence
        if (ch == (u32char)'\\') {
            u32char esc = ReadEscapeCode();
            // append the bytes
            value.append(utf::get_bytes(esc));
        } else {
            // Append the character itself
            value.append(utf::get_bytes(ch));
        }

        ch = m_source_stream.Next(pos_change);
    }

    return Token(TK_STRING, value, location);
}

Token Lexer::ReadNumberLiteral()
{
    SourceLocation location = m_source_location;

    // store the value in a string
    std::string value;

    // assume integer to start
    TokenClass token_class = TK_INTEGER;

    // allows support for floats starting with '.'
    if (m_source_stream.Peek() == '.') {
        token_class = TK_FLOAT;
        value = "0.";
        int pos_change = 0;
        m_source_stream.Next(pos_change);
        m_source_location.GetColumn() += pos_change;
    }

    u32char ch = m_source_stream.Peek();
    while (m_source_stream.HasNext() && utf32_isdigit(ch)) {
        int pos_change = 0;
        u32char next_ch = m_source_stream.Next(pos_change);
        value.append(utf::get_bytes(next_ch));
        m_source_location.GetColumn() += pos_change;

        if (token_class != TK_FLOAT) {
            if (m_source_stream.HasNext()) {
                // the character as a utf-32 character
                u32char ch = m_source_stream.Peek();
                if (ch == (u32char)'.') {
                    // read next to check if after is a digit
                    int pos_change = 0;
                    m_source_stream.Next(pos_change);

                    u32char next = m_source_stream.Peek();
                    if (!utf::utf32_isalpha(next) && next != (u32char)'_') {
                        // type is a float because of '.' and not an identifier after
                        token_class = TK_FLOAT;
                        value.append(utf::get_bytes(ch));
                        m_source_location.GetColumn() += pos_change;
                    } else {
                        // not a float literal, so go back on the '.'
                        m_source_stream.GoBack(pos_change);
                    }
                }
            }
        }
        ch = m_source_stream.Peek();
    }

    return Token(token_class, value, location);
}

Token Lexer::ReadHexNumberLiteral()
{
    // location of the start of the hex number
    SourceLocation location = m_source_location;

    // store the value in a string
    std::string value;

    // read the "0x"
    for (int i = 0; i < 2; i++) {
        int pos_change = 0;
        u32char next_ch = m_source_stream.Next(pos_change);
        value.append(utf::get_bytes(next_ch));
        m_source_location.GetColumn() += pos_change;
    }

    u32char ch = (u32char)('\0');
    do {
        int pos_change = 0;
        u32char next_ch = m_source_stream.Next(pos_change);
        value.append(utf::get_bytes(next_ch));
        m_source_location.GetColumn() += pos_change;
        ch = m_source_stream.Peek();
    } while (std::isxdigit(ch));

    long num = std::strtol(value.c_str(), 0, 16);
    std::stringstream ss;
    ss << num;

    return Token(TK_INTEGER, ss.str(), location);
}

Token Lexer::ReadLineComment()
{
    SourceLocation location = m_source_location;

    // read '//'
    for (int i = 0; i < 2; i++) {
        int pos_change = 0;
        m_source_stream.Next(pos_change);
        m_source_location.GetColumn() += pos_change;
    }

    // read until newline or EOF is reached
    while (m_source_stream.HasNext() && m_source_stream.Peek() != (u32char)'\n') {
        int pos_change = 0;
        m_source_stream.Next(pos_change);
        m_source_location.GetColumn() += pos_change;
    }

    return Token::EMPTY;
}

Token Lexer::ReadBlockComment()
{
    SourceLocation location = m_source_location;

    // read '/*'
    for (int i = 0; i < 2; i++) {
        int pos_change = 0;
        m_source_stream.Next(pos_change);
        m_source_location.GetColumn() += pos_change;
    }

    u32char previous = 0;
    while (HasNext()) {
        if (m_source_stream.Peek() == (u32char)'/' && previous == (u32char)'*') {
            int pos_change = 0;
            m_source_stream.Next(pos_change);
            m_source_location.GetColumn() += pos_change;
            break;
        } else if (m_source_stream.Peek() == (u32char)'\n') {
            // just reset column and increment line
            m_source_location.GetColumn() = 0;
            m_source_location.GetLine()++;
        }
        int pos_change = 0;
        previous = m_source_stream.Next(pos_change);
        m_source_location.GetColumn() += pos_change;
    }

    return Token::EMPTY;
}

Token Lexer::ReadDocumentation()
{
    SourceLocation location = m_source_location;

    std::string value;

    // read '/**'
    for (int i = 0; i < 3; i++) {
        int pos_change = 0;
        m_source_stream.Next(pos_change);
        m_source_location.GetColumn() += pos_change;
    }

    u32char previous = 0;
    while (HasNext()) {
        if (m_source_stream.Peek() == (u32char)'/' && previous == (u32char)'*') {
            int pos_change = 0;
            m_source_stream.Next(pos_change);
            m_source_location.GetColumn() += pos_change;
            break;
        } else {
            char ch[4] = {'\0'};
            utf::char32to8(m_source_stream.Peek(), ch);
            // append value
            value += ch;

            if (m_source_stream.Peek() == (u32char)'\n') {
                // just reset column and increment line
                m_source_location.GetColumn() = 0;
                m_source_location.GetLine()++;
            }
        }
        int pos_change = 0;
        previous = m_source_stream.Next(pos_change);
        m_source_location.GetColumn() += pos_change;
    }

    return Token::EMPTY;
}

Token Lexer::ReadOperator()
{
    // location of the start of the hex number
    SourceLocation location = m_source_location;

    std::array<u32char, 2> ch;
    int total_pos_change = 0;
    for (int i = 0; i < 2; i++) {
        int pos_change = 0;
        ch[i] = m_source_stream.Next(pos_change);
        total_pos_change += pos_change;
    }
    // go back
    m_source_stream.GoBack(total_pos_change);

    std::string op_1 = utf::get_bytes(ch[0]);
    std::string op_2 = op_1 + utf::get_bytes(ch[1]);

    if (Operator::IsOperator(op_2)) {
        int pos_change_1 = 0, pos_change_2 = 0;
        m_source_stream.Next(pos_change_1);
        m_source_stream.Next(pos_change_2);
        m_source_location.GetColumn() += (pos_change_1 + pos_change_2);
        return Token(TK_OPERATOR, op_2, location);
    } else if (Operator::IsOperator(op_1)) {
        int pos_change = 0;
        m_source_stream.Next(pos_change);
        m_source_location.GetColumn() += pos_change;
        return Token(TK_OPERATOR, op_1, location);
    }

    return Token::EMPTY;
}

Token Lexer::ReadIdentifier()
{
    SourceLocation location = m_source_location;

    // store the name in this string
    std::string value;

    // the character as a utf-32 character
    u32char ch = m_source_stream.Peek();

    while (utf32_isdigit(ch) || ch == (u32char)('_') || utf32_isalpha(ch)) {
        int pos_change = 0;
        ch = m_source_stream.Next(pos_change);
        m_source_location.GetColumn() += pos_change;
        // append the raw bytes
        value.append(utf::get_bytes(ch));
        // set ch to be the next character in the buffer
        ch = m_source_stream.Peek();
    }

    return Token(Keyword::IsKeyword(value) ? TK_KEYWORD : TK_IDENT, value, location);
}

bool Lexer::HasNext()
{
    if (!m_source_stream.HasNext()) {
        m_compilation_unit->GetErrorList().AddError(
            CompilerError(Level_fatal, Msg_unexpected_eof, m_source_location));
        return false;
    }

    return true;
}

bool Lexer::SkipWhitespace()
{
    bool had_newline = false;

    while (m_source_stream.HasNext() && utf32_isspace(m_source_stream.Peek())) {
        int pos_change = 0;
        if (m_source_stream.Next(pos_change) == (u32char)'\n') {
            m_source_location.GetLine()++;
            m_source_location.GetColumn() = 0;
            had_newline = true;
        } else {
            m_source_location.GetColumn() += pos_change;
        }
    }

    return had_newline;
}
<commit_msg>Delete lexer.cpp<commit_after><|endoftext|>