<commit_before>/*
 * Copyright 2014 The Imaging Source Europe GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "UsbCamera.h"
#include <stdexcept>

namespace tis
{

// lookup table for all supported camera types
static const camera_type camera_type_list[] =
{
    {
        UNKNOWN, 0, 0, ""
    },
    /* registration of USB2 cameras with jumper attached */
    { USB2, 0xeb1a,        0x2760, "Empia"       },
    { USB3, TIS_VENDOR_ID, 0x8666, "DFK AFU 130" },
    { USB2, TIS_VENDOR_ID, 0x8202, "DFK 22xUC02" },
    { USB2, TIS_VENDOR_ID, 0x8302, "DFK 22xUC02 UVC"},
    { USB2, TIS_VENDOR_ID, 0x8203, "DFK 61xUC02"},
    { USB2, TIS_VENDOR_ID, 0x8204, "DFK 41xUC02"},
    { USB2, TIS_VENDOR_ID, 0x8205, "DFx 51xUC02"},
    { USB2, TIS_VENDOR_ID, 0x8206, "DFx 41xUC02"},
    { USB2, TIS_VENDOR_ID, 0x8207, "DFK 72xUC02"},
    { USB2, TIS_VENDOR_ID, 0x8307, "DFK 72xUC02 UVC"},
    { USB2, TIS_VENDOR_ID, 0x8208, "DFK 42xUC02"},
    { USB2, TIS_VENDOR_ID, 0x8308, "DFK 42xUC02 UVC"},

    // { DBG_TEXT("BF-532"), DBG_TEXT("Dxx AU/BU"), eUSBCAM, 0x8101, &CTIS_AU_Camera_create },
    // { DBG_TEXT("BF-532"), DBG_TEXT("DxK 51xU03"), eEUVCCAM, 0x8102, &create_cam_ccd_51 },
    // { DBG_TEXT("MT9V023"), DBG_TEXT("DxK 21AUC02"), eEUVCCAM, 0x8201, &CDevice_MT9V023_create },
    // { DBG_TEXT("MT9V023"), DBG_TEXT("DxK 21AUC02"), eEUVCCAM, 0x8202, &CDevice_MT9V023_create },

    { USB3, 0x04b4,        0x00f3, "Westbridge" },
    { USB3, TIS_VENDOR_ID, 0x8401, "DMK 23U618" },
    { USB3, TIS_VENDOR_ID, 0x8402, "DMK 23U445" },
    { USB3, TIS_VENDOR_ID, 0x8403, "DMK 23U274" },
    { USB3, TIS_VENDOR_ID, 0x8404, "DMK 23UV024"},
    { USB3, TIS_VENDOR_ID, 0x8405, "DMK 23UM021"},
    { USB3, TIS_VENDOR_ID, 0x8406, "DMK 23UP031"},
    { USB3, TIS_VENDOR_ID, 0x8411, "DFK 23U618" },
    { USB3, TIS_VENDOR_ID, 0x8412, "DFK 23U445" },
    { USB3, TIS_VENDOR_ID, 0x8413, "DFK 23U274" },
    { USB3, TIS_VENDOR_ID, 0x8414, "DFK 23UV024"},
    { USB3, TIS_VENDOR_ID, 0x8415, "DFK 23UM021"},
    { USB3, TIS_VENDOR_ID, 0x8416, "DFK 23UP031"},
    { USB3, TIS_VENDOR_ID, 0x8426, "DMK 23UP031-AF"},
    { USB3, TIS_VENDOR_ID, 0x8436, "DFK 23UP031-AF"}
};

const camera_type find_camera_type (const unsigned int& idVendor, const unsigned int& idProduct)
{
    for (auto& c : camera_type_list)
    {
        if (idProduct == c.idProduct && idProduct == c.idProduct)
        {
            return c;
        }
    }

    // type not known assure we still can handle the device
    // as long as it is one of ours

    if ((idProduct & (0x8400)) == (0x8400))
    {
        return {USB3, idVendor, idProduct, "Unknown USB3 Camera"};
    }

    if ((idProduct & (0x8200)) == (0x8200) || (idProduct & (0x8300)) == (0x8300))
    {
        return {USB2, idVendor, idProduct, "Unknown USB2 Camera"};
    }

    return camera_type_list[0];

}

UsbCamera::UsbCamera (std::shared_ptr<UsbSession> session, device_info dev, unsigned int _interface):
    usb_session(session),
    dev(dev),
    interface(_interface)
{
    try
    {
        this->dev_handle = libusb_open_device_with_vid_pid(usb_session->get_session(), dev.idVendor, dev.idProduct);

        if (this->dev_handle == NULL)
        {
            throw std::runtime_error("Unable to attain device handle.");
        }

        claim_interface();
    }
    catch (std::runtime_error& err)
    {
        throw;
    }
}

UsbCamera::~UsbCamera ()
{
    release_interface();
    libusb_close(this->dev_handle);
}

device_info UsbCamera::get_device_info ()
{
    return dev;
}

camera_type UsbCamera::get_camera_type ()
{
    return find_camera_type (this->dev.idVendor, this->dev.idProduct);
}

void UsbCamera::claim_interface ()
{
    if (libusb_kernel_driver_active(this->dev_handle, this->interface) == 1)
    {
        if (libusb_detach_kernel_driver(dev_handle, interface) != 0)
        {
            throw std::runtime_error("Unable to detach kernel driver.");
        }
    }

    int r = libusb_claim_interface(this->dev_handle, this->interface);
    if (r < 0)
    {
        throw std::runtime_error("Unable to claim interface.");
    }
}

void UsbCamera::release_interface ()
{
    int r = libusb_release_interface(this->dev_handle, this->interface);
    if (r != 0)
    {
        throw std::runtime_error("Unable to release intreface.");
    }
    libusb_attach_kernel_driver(this->dev_handle, this->interface);
}

}; /* namespace tis */
<commit_msg>Fixed faulty vendor check<commit_after>/*
 * Copyright 2014 The Imaging Source Europe GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "UsbCamera.h"
#include <stdexcept>

namespace tis
{

// lookup table for all supported camera types
static const camera_type camera_type_list[] =
{
    {
        UNKNOWN, 0, 0, ""
    },
    /* registration of USB2 cameras with jumper attached */
    { USB2, 0xeb1a,        0x2760, "Empia"       },
    { USB3, TIS_VENDOR_ID, 0x8666, "DFK AFU 130" },
    { USB2, TIS_VENDOR_ID, 0x8202, "DFK 22xUC02" },
    { USB2, TIS_VENDOR_ID, 0x8302, "DFK 22xUC02 UVC"},
    { USB2, TIS_VENDOR_ID, 0x8203, "DFK 61xUC02"},
    { USB2, TIS_VENDOR_ID, 0x8204, "DFK 41xUC02"},
    { USB2, TIS_VENDOR_ID, 0x8205, "DFx 51xUC02"},
    { USB2, TIS_VENDOR_ID, 0x8206, "DFx 41xUC02"},
    { USB2, TIS_VENDOR_ID, 0x8207, "DFK 72xUC02"},
    { USB2, TIS_VENDOR_ID, 0x8307, "DFK 72xUC02 UVC"},
    { USB2, TIS_VENDOR_ID, 0x8208, "DFK 42xUC02"},
    { USB2, TIS_VENDOR_ID, 0x8308, "DFK 42xUC02 UVC"},

    // { DBG_TEXT("BF-532"), DBG_TEXT("Dxx AU/BU"), eUSBCAM, 0x8101, &CTIS_AU_Camera_create },
    // { DBG_TEXT("BF-532"), DBG_TEXT("DxK 51xU03"), eEUVCCAM, 0x8102, &create_cam_ccd_51 },
    // { DBG_TEXT("MT9V023"), DBG_TEXT("DxK 21AUC02"), eEUVCCAM, 0x8201, &CDevice_MT9V023_create },
    // { DBG_TEXT("MT9V023"), DBG_TEXT("DxK 21AUC02"), eEUVCCAM, 0x8202, &CDevice_MT9V023_create },

    { USB3, 0x04b4,        0x00f3, "Westbridge" },
    { USB3, TIS_VENDOR_ID, 0x8401, "DMK 23U618" },
    { USB3, TIS_VENDOR_ID, 0x8402, "DMK 23U445" },
    { USB3, TIS_VENDOR_ID, 0x8403, "DMK 23U274" },
    { USB3, TIS_VENDOR_ID, 0x8404, "DMK 23UV024"},
    { USB3, TIS_VENDOR_ID, 0x8405, "DMK 23UM021"},
    { USB3, TIS_VENDOR_ID, 0x8406, "DMK 23UP031"},
    { USB3, TIS_VENDOR_ID, 0x8411, "DFK 23U618" },
    { USB3, TIS_VENDOR_ID, 0x8412, "DFK 23U445" },
    { USB3, TIS_VENDOR_ID, 0x8413, "DFK 23U274" },
    { USB3, TIS_VENDOR_ID, 0x8414, "DFK 23UV024"},
    { USB3, TIS_VENDOR_ID, 0x8415, "DFK 23UM021"},
    { USB3, TIS_VENDOR_ID, 0x8416, "DFK 23UP031"},
    { USB3, TIS_VENDOR_ID, 0x8426, "DMK 23UP031-AF"},
    { USB3, TIS_VENDOR_ID, 0x8436, "DFK 23UP031-AF"}
};

const camera_type find_camera_type (const unsigned int& idVendor, const unsigned int& idProduct)
{
    for (auto& c : camera_type_list)
    {
        if (idVendor == c.idVendor && idProduct == c.idProduct)
        {
            return c;
        }
    }

    // type not known assure we still can handle the device
    // as long as it is one of ours

    if ((idProduct & (0x8400)) == (0x8400))
    {
        return {USB3, idVendor, idProduct, "Unknown USB3 Camera"};
    }

    if ((idProduct & (0x8200)) == (0x8200) || (idProduct & (0x8300)) == (0x8300))
    {
        return {USB2, idVendor, idProduct, "Unknown USB2 Camera"};
    }

    return camera_type_list[0];

}

UsbCamera::UsbCamera (std::shared_ptr<UsbSession> session, device_info dev, unsigned int _interface):
    usb_session(session),
    dev(dev),
    interface(_interface)
{
    try
    {
        this->dev_handle = libusb_open_device_with_vid_pid(usb_session->get_session(), dev.idVendor, dev.idProduct);

        if (this->dev_handle == NULL)
        {
            throw std::runtime_error("Unable to attain device handle.");
        }

        claim_interface();
    }
    catch (std::runtime_error& err)
    {
        throw;
    }
}

UsbCamera::~UsbCamera ()
{
    release_interface();
    libusb_close(this->dev_handle);
}

device_info UsbCamera::get_device_info ()
{
    return dev;
}

camera_type UsbCamera::get_camera_type ()
{
    return find_camera_type (this->dev.idVendor, this->dev.idProduct);
}

void UsbCamera::claim_interface ()
{
    if (libusb_kernel_driver_active(this->dev_handle, this->interface) == 1)
    {
        if (libusb_detach_kernel_driver(dev_handle, interface) != 0)
        {
            throw std::runtime_error("Unable to detach kernel driver.");
        }
    }

    int r = libusb_claim_interface(this->dev_handle, this->interface);
    if (r < 0)
    {
        throw std::runtime_error("Unable to claim interface.");
    }
}

void UsbCamera::release_interface ()
{
    int r = libusb_release_interface(this->dev_handle, this->interface);
    if (r != 0)
    {
        throw std::runtime_error("Unable to release intreface.");
    }
    libusb_attach_kernel_driver(this->dev_handle, this->interface);
}

}; /* namespace tis */
<|endoftext|>


<commit_before>// Copyright (C) 2018 xaizek <xaizek@posteo.net>
//
// This file is part of uncov.
//
// uncov is free software: you can redistribute it and/or modify
// it under the terms of version 3 of the GNU Affero General Public License as
// published by the Free Software Foundation.
//
// 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 "GcovImporter.hpp"

#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

#include <cassert>

#include <fstream>
#include <istream>
#include <regex>
#include <set>
#include <sstream>
#include <stdexcept>
#include <string>
#include <tuple>
#include <unordered_set>
#include <utility>
#include <vector>

#include "utils/fs.hpp"
#include "utils/md5.hpp"
#include "utils/strings.hpp"
#include "BuildHistory.hpp"
#include "integration.hpp"

namespace fs = boost::filesystem;
namespace pt = boost::property_tree;

// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89961 for information about
// what's wrong with some versions of `gcov` and why binning is needed.

//! `gcov` option to generate coverage in JSON format.
static const char GcovJsonFormat[] = "--json-format";
//! `gcov` option to generate coverage in plain text format.
static const char GcovIntermediateFormat[] = "--intermediate-format";

//! First version of `gcov` which has broken `--preserve-paths` option.
static int FirstBrokenGcovVersion = 8;

namespace {
    /**
     * @brief A set of files that should be passed to `gcov` at the same time.
     */
    class Bin {
    public:
        /**
         * @brief Constructs an empty set.
         *
         * @param deduplicateNames Whether to avoid adding name-duplicates.
         */
        Bin(bool deduplicateNames = true) : deduplicateNames(deduplicateNames)
        { }

    public:
        /**
         * @brief Tries to add a file to this bin.
         *
         * @param path Absolute path to the file.
         *
         * @returns `true` if the path was added.
         */
        bool add(const fs::path &path)
        {
            assert(path.is_absolute() && "Paths should be absolute.");

            if (deduplicateNames &&
                !names.emplace(path.filename().string()).second) {
                return false;
            }

            paths.emplace_back(path.string());
            return true;
        }

        /**
         * @brief Retrieves list of paths of this bin.
         *
         * @returns The list.
         */
        const std::vector<std::string> & getPaths() const
        { return paths; }

    private:
        //! Whether no two files should have the same name.
        bool deduplicateNames;
        //! Names of files in this bin if `deduplicateNames` is set.
        std::unordered_set<std::string> names;
        //! Files of this bin.
        std::vector<std::string> paths;
    };
}

GcovInfo::GcovInfo()
    : employBinning(true), jsonFormat(false), intermediateFormat(false)
{
    const std::regex optionRegex("--[-a-z]+");
    const std::regex versionRegex("gcov \\(GCC\\) (.*)");

    std::smatch match;

    const std::string help = readProc({ "gcov", "--help" });
    auto from = help.cbegin();
    auto to = help.cend();
    while (std::regex_search(from, to, match, optionRegex)) {
        const std::string str = match.str();
        if (str == GcovJsonFormat) {
            jsonFormat = true;
        } else if (str == GcovIntermediateFormat) {
            intermediateFormat = true;
        }

        from += match.position() + match.length();
    }

    const std::string version = readProc({ "gcov", "--version" });
    if (std::regex_search(version, match, versionRegex)) {
        const int majorVersion = std::stoi(match[1]);
        employBinning = (majorVersion >= FirstBrokenGcovVersion);
    }
}

GcovInfo::GcovInfo(bool employBinning, bool jsonFormat,
                   bool intermediateFormat)
    : employBinning(employBinning), jsonFormat(jsonFormat),
      intermediateFormat(intermediateFormat)
{ }

std::function<GcovImporter::runner_f>
GcovImporter::setRunner(std::function<runner_f> runner)
{
    std::function<runner_f> previous = std::move(getRunner());
    getRunner() = std::move(runner);
    return previous;
}

GcovImporter::GcovImporter(const std::string &root,
                           const std::string &covoutRoot,
                           const std::vector<std::string> &exclude,
                           const std::string &prefix,
                           GcovInfo gcovInfo)
    : gcovInfo(gcovInfo), rootDir(normalizePath(fs::absolute(root))),
      prefix(prefix)
{
    for (const std::string &p : exclude) {
        skipPaths.insert(normalizePath(fs::absolute(p, root)));
    }

    std::unordered_set<std::string> extensions = {
        ".h", ".hh", ".hpp", ".hxx",
        ".c", ".cc", ".cpp", ".cxx",
        ".m", ".mm",
    };
    std::unordered_set<std::string> skipDirs = {
        ".git", ".hg", ".svn", // Various version control systems.
        ".deps"                // Dependency tracking of automake.
    };

    if (!gcovInfo.hasJsonFormat() && !gcovInfo.hasIntermediateFormat()) {
        throw std::runtime_error("Failed to detect machine format of gcov");
    }

    std::vector<fs::path> gcnoFiles;
    for (fs::recursive_directory_iterator it(fs::absolute(covoutRoot)), end;
         it != end; ++it) {
        fs::path path = it->path();
        if (fs::is_directory(path)) {
            if (skipDirs.count(path.filename().string())) {
                it.no_push();
                continue;
            }
        } else if (fs::is_regular(path)) {
            // We are looking for *.gcno and not *.gcda, because they are
            // generated even for files that weren't executed (e.g.,
            // `main.cpp`).
            if (path.extension() == ".gcno") {
                gcnoFiles.push_back(path);
            }
        }
    }

    importFiles(std::move(gcnoFiles));

    for (fs::recursive_directory_iterator it(rootDir), end; it != end; ++it) {
        fs::path path = it->path();
        if (fs::is_directory(path)) {
            if (skipDirs.count(path.filename().string())) {
                it.no_push();
            } else if (skipPaths.count(normalizePath(fs::absolute(path)))) {
                it.no_push();
            }
        } else if (extensions.count(path.extension().string())) {
            std::string filePath = makeRelativePath(rootDir, path).string();
            if (mapping.find(filePath) == mapping.end()) {
                std::string contents = readFile(path.string());
                std::string hash = md5(contents);

                int nLines = std::count(contents.cbegin(), contents.cend(),
                                        '\n');

                files.emplace_back(filePath, std::move(hash),
                                   std::vector<int>(nLines, -1));
            }
        }
    }

    for (auto &e : mapping) {
        std::string contents = readFile(root + '/' + e.first);
        std::string hash = md5(contents);

        std::vector<std::string> lines = split(contents, '\n');
        e.second.resize(lines.size(), -1);

        unsigned int i = 0U;
        for (std::string &line : lines) {
            boost::trim_if(line, boost::is_any_of("\r\n \t"));
            if (line == "}" || line == "};") {
                e.second[i] = -1;
            }
            ++i;
        }

        files.emplace_back(e.first, std::move(hash), std::move(e.second));
    }

    mapping.clear();
}

std::vector<File> &&
GcovImporter::getFiles() &&
{
    return std::move(files);
}

void
GcovImporter::importFiles(std::vector<fs::path> gcnoFiles)
{
    importAsFiles(std::move(gcnoFiles));
}

void
GcovImporter::importAsFiles(std::vector<fs::path> gcnoFiles)
{
    std::vector<Bin> bins;

    if (gcovInfo.needsBinning()) {
        // We want to execute the runner for tests even if there are no input
        // files.
        bins.emplace_back();

        for (const fs::path &gcnoFile : gcnoFiles) {
            bool added = false;

            for (Bin &bin : bins) {
                if (bin.add(gcnoFile)) {
                    added = true;
                    break;
                }
            }

            if (!added) {
                bins.emplace_back();
                bins.back().add(gcnoFile);
            }
        }
    } else {
        bins.emplace_back(/*deduplicateNames=*/false);
        Bin &bin = bins.back();
        for (const fs::path &gcnoFile : gcnoFiles) {
            bin.add(gcnoFile);
        }
    }

    std::string gcovOption;
    std::string gcovFileExt;
    if (gcovInfo.hasJsonFormat()) {
        gcovOption = GcovJsonFormat;
        gcovFileExt = ".gcov.json.gz";
    } else {
        gcovOption = GcovIntermediateFormat;
        gcovFileExt = ".gcov";
    }

    for (const Bin &bin : bins) {
        const std::vector<std::string> &paths = bin.getPaths();

        std::vector<std::string> cmd = {
            "gcov", "--preserve-paths", gcovOption, "--"
        };
        cmd.insert(cmd.cend(), paths.cbegin(), paths.cend());

        TempDir tempDir("gcovi");
        std::string tempDirPath = tempDir;
        getRunner()(std::move(cmd), tempDirPath);

        for (fs::recursive_directory_iterator it(tempDirPath), end;
             it != end; ++it) {
            fs::path path = it->path();
            if (fs::is_regular(path) &&
                boost::ends_with(path.filename().string(), gcovFileExt)) {
                if (gcovInfo.hasJsonFormat()) {
                    parseGcovJsonGz(path.string());
                } else {
                    parseGcov(path.string());
                }
            }
        }
    }
}

void
GcovImporter::parseGcovJsonGz(const std::string &path)
{
    namespace io = boost::iostreams;

    std::ifstream file(path, std::ios_base::in | std::ios_base::binary);

    io::filtering_istreambuf in;
    in.push(io::gzip_decompressor());
    in.push(file);

    std::istream is(&in);
    parseGcovJson(is);
}

void
GcovImporter::parseGcovJson(std::istream &stream)
{
    pt::ptree props;
    pt::read_json(stream, props);

    const std::string cwd = props.get<std::string>("current_working_directory");

    for (auto &file : props.get_child("files")) {
        fs::path path = file.second.get<std::string>("file");
        if (!path.is_absolute()) {
            path = cwd / path;
        }

        const std::string sourcePath = resolveSourcePath(path);
        if (sourcePath.empty()) {
            continue;
        }

        std::vector<int> &coverage = mapping[sourcePath];
        for (auto &line : file.second.get_child("lines")) {
            updateCoverage(coverage,
                           line.second.get<unsigned int>("line_number"),
                           line.second.get<int>("count"));
        }
    }
}

void
GcovImporter::parseGcov(const std::string &path)
{
    std::vector<int> *coverage = nullptr;
    std::ifstream in(path);
    for (std::string line; in >> line; ) {
        std::string type, value;
        std::tie(type, value) = splitAt(line, ':');
        if (type == "file") {
            const std::string sourcePath = resolveSourcePath(value);
            coverage = (sourcePath.empty() ? nullptr : &mapping[sourcePath]);
        } else if (coverage != nullptr && type == "lcount") {
            std::vector<std::string> fields = split(value, ',');
            if (fields.size() < 2U) {
                throw std::runtime_error("Not enough fields in lcount: " +
                                         value);
            }

            unsigned int lineNo = std::stoi(fields[0]);
            int count = std::stoi(fields[1]);
            updateCoverage(*coverage, lineNo, count);
        }
    }
}

std::string
GcovImporter::resolveSourcePath(fs::path unresolved)
{
    if (!unresolved.is_absolute()) {
        unresolved = prefix / unresolved;
    }

    fs::path sourcePath = normalizePath(fs::absolute(unresolved,
                                                     rootDir));
    if (!pathIsInSubtree(rootDir, sourcePath) || isExcluded(sourcePath)) {
        return std::string();
    }

    return makeRelativePath(rootDir, sourcePath).string();
}

void
GcovImporter::updateCoverage(std::vector<int> &coverage, unsigned int lineNo,
                             int count)
{
    if (coverage.size() < lineNo) {
        coverage.resize(lineNo, -1);
    }

    int &entry = coverage[lineNo - 1U];
    entry = (entry == -1 ? count : entry + count);
}

bool
GcovImporter::isExcluded(boost::filesystem::path path) const
{
    for (const fs::path &skipPath : skipPaths) {
        if (pathIsInSubtree(skipPath, path)) {
            return true;
        }
    }
    return false;
}

std::function<GcovImporter::runner_f> &
GcovImporter::getRunner()
{
    static std::function<runner_f> runner;
    return runner;
}
<commit_msg>One more use of fs namespace alias in GcovImporter<commit_after>// Copyright (C) 2018 xaizek <xaizek@posteo.net>
//
// This file is part of uncov.
//
// uncov is free software: you can redistribute it and/or modify
// it under the terms of version 3 of the GNU Affero General Public License as
// published by the Free Software Foundation.
//
// 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 "GcovImporter.hpp"

#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

#include <cassert>

#include <fstream>
#include <istream>
#include <regex>
#include <set>
#include <sstream>
#include <stdexcept>
#include <string>
#include <tuple>
#include <unordered_set>
#include <utility>
#include <vector>

#include "utils/fs.hpp"
#include "utils/md5.hpp"
#include "utils/strings.hpp"
#include "BuildHistory.hpp"
#include "integration.hpp"

namespace fs = boost::filesystem;
namespace pt = boost::property_tree;

// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89961 for information about
// what's wrong with some versions of `gcov` and why binning is needed.

//! `gcov` option to generate coverage in JSON format.
static const char GcovJsonFormat[] = "--json-format";
//! `gcov` option to generate coverage in plain text format.
static const char GcovIntermediateFormat[] = "--intermediate-format";

//! First version of `gcov` which has broken `--preserve-paths` option.
static int FirstBrokenGcovVersion = 8;

namespace {
    /**
     * @brief A set of files that should be passed to `gcov` at the same time.
     */
    class Bin {
    public:
        /**
         * @brief Constructs an empty set.
         *
         * @param deduplicateNames Whether to avoid adding name-duplicates.
         */
        Bin(bool deduplicateNames = true) : deduplicateNames(deduplicateNames)
        { }

    public:
        /**
         * @brief Tries to add a file to this bin.
         *
         * @param path Absolute path to the file.
         *
         * @returns `true` if the path was added.
         */
        bool add(const fs::path &path)
        {
            assert(path.is_absolute() && "Paths should be absolute.");

            if (deduplicateNames &&
                !names.emplace(path.filename().string()).second) {
                return false;
            }

            paths.emplace_back(path.string());
            return true;
        }

        /**
         * @brief Retrieves list of paths of this bin.
         *
         * @returns The list.
         */
        const std::vector<std::string> & getPaths() const
        { return paths; }

    private:
        //! Whether no two files should have the same name.
        bool deduplicateNames;
        //! Names of files in this bin if `deduplicateNames` is set.
        std::unordered_set<std::string> names;
        //! Files of this bin.
        std::vector<std::string> paths;
    };
}

GcovInfo::GcovInfo()
    : employBinning(true), jsonFormat(false), intermediateFormat(false)
{
    const std::regex optionRegex("--[-a-z]+");
    const std::regex versionRegex("gcov \\(GCC\\) (.*)");

    std::smatch match;

    const std::string help = readProc({ "gcov", "--help" });
    auto from = help.cbegin();
    auto to = help.cend();
    while (std::regex_search(from, to, match, optionRegex)) {
        const std::string str = match.str();
        if (str == GcovJsonFormat) {
            jsonFormat = true;
        } else if (str == GcovIntermediateFormat) {
            intermediateFormat = true;
        }

        from += match.position() + match.length();
    }

    const std::string version = readProc({ "gcov", "--version" });
    if (std::regex_search(version, match, versionRegex)) {
        const int majorVersion = std::stoi(match[1]);
        employBinning = (majorVersion >= FirstBrokenGcovVersion);
    }
}

GcovInfo::GcovInfo(bool employBinning, bool jsonFormat,
                   bool intermediateFormat)
    : employBinning(employBinning), jsonFormat(jsonFormat),
      intermediateFormat(intermediateFormat)
{ }

std::function<GcovImporter::runner_f>
GcovImporter::setRunner(std::function<runner_f> runner)
{
    std::function<runner_f> previous = std::move(getRunner());
    getRunner() = std::move(runner);
    return previous;
}

GcovImporter::GcovImporter(const std::string &root,
                           const std::string &covoutRoot,
                           const std::vector<std::string> &exclude,
                           const std::string &prefix,
                           GcovInfo gcovInfo)
    : gcovInfo(gcovInfo), rootDir(normalizePath(fs::absolute(root))),
      prefix(prefix)
{
    for (const std::string &p : exclude) {
        skipPaths.insert(normalizePath(fs::absolute(p, root)));
    }

    std::unordered_set<std::string> extensions = {
        ".h", ".hh", ".hpp", ".hxx",
        ".c", ".cc", ".cpp", ".cxx",
        ".m", ".mm",
    };
    std::unordered_set<std::string> skipDirs = {
        ".git", ".hg", ".svn", // Various version control systems.
        ".deps"                // Dependency tracking of automake.
    };

    if (!gcovInfo.hasJsonFormat() && !gcovInfo.hasIntermediateFormat()) {
        throw std::runtime_error("Failed to detect machine format of gcov");
    }

    std::vector<fs::path> gcnoFiles;
    for (fs::recursive_directory_iterator it(fs::absolute(covoutRoot)), end;
         it != end; ++it) {
        fs::path path = it->path();
        if (fs::is_directory(path)) {
            if (skipDirs.count(path.filename().string())) {
                it.no_push();
                continue;
            }
        } else if (fs::is_regular(path)) {
            // We are looking for *.gcno and not *.gcda, because they are
            // generated even for files that weren't executed (e.g.,
            // `main.cpp`).
            if (path.extension() == ".gcno") {
                gcnoFiles.push_back(path);
            }
        }
    }

    importFiles(std::move(gcnoFiles));

    for (fs::recursive_directory_iterator it(rootDir), end; it != end; ++it) {
        fs::path path = it->path();
        if (fs::is_directory(path)) {
            if (skipDirs.count(path.filename().string())) {
                it.no_push();
            } else if (skipPaths.count(normalizePath(fs::absolute(path)))) {
                it.no_push();
            }
        } else if (extensions.count(path.extension().string())) {
            std::string filePath = makeRelativePath(rootDir, path).string();
            if (mapping.find(filePath) == mapping.end()) {
                std::string contents = readFile(path.string());
                std::string hash = md5(contents);

                int nLines = std::count(contents.cbegin(), contents.cend(),
                                        '\n');

                files.emplace_back(filePath, std::move(hash),
                                   std::vector<int>(nLines, -1));
            }
        }
    }

    for (auto &e : mapping) {
        std::string contents = readFile(root + '/' + e.first);
        std::string hash = md5(contents);

        std::vector<std::string> lines = split(contents, '\n');
        e.second.resize(lines.size(), -1);

        unsigned int i = 0U;
        for (std::string &line : lines) {
            boost::trim_if(line, boost::is_any_of("\r\n \t"));
            if (line == "}" || line == "};") {
                e.second[i] = -1;
            }
            ++i;
        }

        files.emplace_back(e.first, std::move(hash), std::move(e.second));
    }

    mapping.clear();
}

std::vector<File> &&
GcovImporter::getFiles() &&
{
    return std::move(files);
}

void
GcovImporter::importFiles(std::vector<fs::path> gcnoFiles)
{
    importAsFiles(std::move(gcnoFiles));
}

void
GcovImporter::importAsFiles(std::vector<fs::path> gcnoFiles)
{
    std::vector<Bin> bins;

    if (gcovInfo.needsBinning()) {
        // We want to execute the runner for tests even if there are no input
        // files.
        bins.emplace_back();

        for (const fs::path &gcnoFile : gcnoFiles) {
            bool added = false;

            for (Bin &bin : bins) {
                if (bin.add(gcnoFile)) {
                    added = true;
                    break;
                }
            }

            if (!added) {
                bins.emplace_back();
                bins.back().add(gcnoFile);
            }
        }
    } else {
        bins.emplace_back(/*deduplicateNames=*/false);
        Bin &bin = bins.back();
        for (const fs::path &gcnoFile : gcnoFiles) {
            bin.add(gcnoFile);
        }
    }

    std::string gcovOption;
    std::string gcovFileExt;
    if (gcovInfo.hasJsonFormat()) {
        gcovOption = GcovJsonFormat;
        gcovFileExt = ".gcov.json.gz";
    } else {
        gcovOption = GcovIntermediateFormat;
        gcovFileExt = ".gcov";
    }

    for (const Bin &bin : bins) {
        const std::vector<std::string> &paths = bin.getPaths();

        std::vector<std::string> cmd = {
            "gcov", "--preserve-paths", gcovOption, "--"
        };
        cmd.insert(cmd.cend(), paths.cbegin(), paths.cend());

        TempDir tempDir("gcovi");
        std::string tempDirPath = tempDir;
        getRunner()(std::move(cmd), tempDirPath);

        for (fs::recursive_directory_iterator it(tempDirPath), end;
             it != end; ++it) {
            fs::path path = it->path();
            if (fs::is_regular(path) &&
                boost::ends_with(path.filename().string(), gcovFileExt)) {
                if (gcovInfo.hasJsonFormat()) {
                    parseGcovJsonGz(path.string());
                } else {
                    parseGcov(path.string());
                }
            }
        }
    }
}

void
GcovImporter::parseGcovJsonGz(const std::string &path)
{
    namespace io = boost::iostreams;

    std::ifstream file(path, std::ios_base::in | std::ios_base::binary);

    io::filtering_istreambuf in;
    in.push(io::gzip_decompressor());
    in.push(file);

    std::istream is(&in);
    parseGcovJson(is);
}

void
GcovImporter::parseGcovJson(std::istream &stream)
{
    pt::ptree props;
    pt::read_json(stream, props);

    const std::string cwd = props.get<std::string>("current_working_directory");

    for (auto &file : props.get_child("files")) {
        fs::path path = file.second.get<std::string>("file");
        if (!path.is_absolute()) {
            path = cwd / path;
        }

        const std::string sourcePath = resolveSourcePath(path);
        if (sourcePath.empty()) {
            continue;
        }

        std::vector<int> &coverage = mapping[sourcePath];
        for (auto &line : file.second.get_child("lines")) {
            updateCoverage(coverage,
                           line.second.get<unsigned int>("line_number"),
                           line.second.get<int>("count"));
        }
    }
}

void
GcovImporter::parseGcov(const std::string &path)
{
    std::vector<int> *coverage = nullptr;
    std::ifstream in(path);
    for (std::string line; in >> line; ) {
        std::string type, value;
        std::tie(type, value) = splitAt(line, ':');
        if (type == "file") {
            const std::string sourcePath = resolveSourcePath(value);
            coverage = (sourcePath.empty() ? nullptr : &mapping[sourcePath]);
        } else if (coverage != nullptr && type == "lcount") {
            std::vector<std::string> fields = split(value, ',');
            if (fields.size() < 2U) {
                throw std::runtime_error("Not enough fields in lcount: " +
                                         value);
            }

            unsigned int lineNo = std::stoi(fields[0]);
            int count = std::stoi(fields[1]);
            updateCoverage(*coverage, lineNo, count);
        }
    }
}

std::string
GcovImporter::resolveSourcePath(fs::path unresolved)
{
    if (!unresolved.is_absolute()) {
        unresolved = prefix / unresolved;
    }

    fs::path sourcePath = normalizePath(fs::absolute(unresolved,
                                                     rootDir));
    if (!pathIsInSubtree(rootDir, sourcePath) || isExcluded(sourcePath)) {
        return std::string();
    }

    return makeRelativePath(rootDir, sourcePath).string();
}

void
GcovImporter::updateCoverage(std::vector<int> &coverage, unsigned int lineNo,
                             int count)
{
    if (coverage.size() < lineNo) {
        coverage.resize(lineNo, -1);
    }

    int &entry = coverage[lineNo - 1U];
    entry = (entry == -1 ? count : entry + count);
}

bool
GcovImporter::isExcluded(fs::path path) const
{
    for (const fs::path &skipPath : skipPaths) {
        if (pathIsInSubtree(skipPath, path)) {
            return true;
        }
    }
    return false;
}

std::function<GcovImporter::runner_f> &
GcovImporter::getRunner()
{
    static std::function<runner_f> runner;
    return runner;
}
<|endoftext|>


<commit_before>#include "Genes/Genome.h"

#include <string>
#include <array>
#include <iostream>
#include <algorithm>
#include <numeric>

#include "Game/Color.h"
#include "Game/Clock.h"
#include "Game/Board.h"

#include "Utility/Random.h"
#include "Utility/String.h"
#include "Utility/Exceptions.h"

#include "Genes/Gene.h"
#include "Genes/Total_Force_Gene.h"
#include "Genes/Freedom_To_Move_Gene.h"
#include "Genes/Pawn_Advancement_Gene.h"
#include "Genes/Passed_Pawn_Gene.h"
#include "Genes/Opponent_Pieces_Targeted_Gene.h"
#include "Genes/Sphere_of_Influence_Gene.h"
#include "Genes/Look_Ahead_Gene.h"
#include "Genes/King_Confinement_Gene.h"
#include "Genes/King_Protection_Gene.h"
#include "Genes/Castling_Possible_Gene.h"
#include "Genes/Piece_Strength_Gene.h"
#include "Genes/Stacked_Pawns_Gene.h"
#include "Genes/Pawn_Islands_Gene.h"
#include "Genes/Checkmate_Material_Gene.h"
#include "Genes/Pawn_Structure_Gene.h"

namespace
{
    const auto search_method_names =
        []()
        {
            std::array<std::string, 2> names;
            names[static_cast<int>(Search_Method::MINIMAX)] = "Minimax";
            names[static_cast<int>(Search_Method::ITERATIVE_DEEPENING)] = "Iterative Deepening";
            return names;
        }();

        int next_id = 0;
}

Genome::Genome() noexcept :
    id_number(next_id++),
    genome{
        std::make_unique<Piece_Strength_Gene>(),
        std::make_unique<Look_Ahead_Gene>(),
        std::make_unique<Total_Force_Gene>(nullptr),
        std::make_unique<Freedom_To_Move_Gene>(),
        std::make_unique<Pawn_Advancement_Gene>(),
        std::make_unique<Passed_Pawn_Gene>(),
        std::make_unique<Opponent_Pieces_Targeted_Gene>(nullptr),
        std::make_unique<Sphere_of_Influence_Gene>(),
        std::make_unique<King_Confinement_Gene>(),
        std::make_unique<King_Protection_Gene>(),
        std::make_unique<Castling_Possible_Gene>(),
        std::make_unique<Stacked_Pawns_Gene>(),
        std::make_unique<Pawn_Islands_Gene>(),
        std::make_unique<Checkmate_Material_Gene>(),
        std::make_unique<Pawn_Structure_Gene>()
    }
{
    renormalize_priorities();
    reset_piece_strength_gene();

    assert(gene_reference<Piece_Strength_Gene>().name() == "Piece Strength Gene");
    assert(gene_reference<Look_Ahead_Gene>().name() == "Look Ahead Gene");
}

Genome::Genome(const Genome& other) noexcept : id_number(other.id()), searching_method(other.search_method())
{
    std::transform(other.genome.begin(), other.genome.end(),
                   genome.begin(),
                   [](const auto& gene)
                   {
                       return gene->duplicate();
                   });
    reset_piece_strength_gene();
}

Genome::Genome(std::istream& is, int id_in) : Genome()
{
    id_number = id_in;
    --next_id;

    if( ! is)
    {
        throw Genome_Creation_Error("Could not read: ");
    }

    for(std::string line; std::getline(is, line);)
    {
        line = String::strip_comments(line, "#");
        if(!String::starts_with(line, "ID"))
        {
            continue;
        }

        const auto param_value = String::split(line, ":", 1);
        if(param_value.size() != 2 || String::trim_outer_whitespace(param_value[0]) != "ID")
        {
            continue;
        }

        if(id_number == String::to_number<int>(param_value[1]))
        {
            auto add_details = [this](const auto& e)
            {
                return "Error in creating Genome #" + std::to_string(id()) + "\n" + e.what() + "\nFile: ";
            };

            try
            {
                read_from(is);
            }
            catch(const Missing_Genome_Data& e)
            {
                throw Missing_Genome_Data(add_details(e));
            }
            catch(const Duplicate_Genome_Data& e)
            {
                throw Duplicate_Genome_Data(add_details(e));
            }
            catch(const Genome_Creation_Error& e)
            {
                throw Genome_Creation_Error(add_details(e));
            }

            next_id = std::max(next_id, id() + 1);
            return;
        }
    }

    throw Genome_Creation_Error("Could not locate ID " + std::to_string(id_number) + " inside file ");
}

void Genome::reset_piece_strength_gene() noexcept
{
    auto piece_strength_gene = &gene_reference<Piece_Strength_Gene>();
    for(auto& gene : genome)
    {
        gene->reset_piece_strength_gene(piece_strength_gene);
    }
}

void Genome::renormalize_priorities() noexcept
{
    for(auto stage : {Game_Stage::OPENING, Game_Stage::ENDGAME})
    {
        const auto norm =
            std::accumulate(genome.begin(), genome.end(), 0.0,
                            [stage](auto sum, const auto& gene)
                            {
                                return sum + (gene->has_priority() ? std::abs(gene->priority(stage)) : 0.0);
                            });
        if(norm > 0.0)
        {
            for(auto& gene : genome)
            {
                gene->scale_priority(stage, 1.0/norm);
            }
        }
    }
}

Genome& Genome::operator=(const Genome& other) noexcept
{
    id_number = other.id();
    std::transform(other.genome.begin(), other.genome.end(),
                   genome.begin(),
                   [](const auto& gene)
                   {
                       return gene->duplicate();
                   });
    reset_piece_strength_gene();
    searching_method = other.search_method();
    return *this;
}

Genome::Genome(const Genome& A, const Genome& B) noexcept : id_number(next_id++)
{
    std::transform(A.genome.begin(), A.genome.end(), B.genome.begin(),
                   genome.begin(),
                   [](const auto& gene_a, const auto& gene_b)
                   {
                       return (Random::coin_flip() ? gene_a : gene_b)->duplicate();
                   });

    reset_piece_strength_gene();
    renormalize_priorities();

    searching_method = Random::coin_flip() ? A.search_method() : B.search_method();
}

void Genome::read_from(std::istream& is)
{
    for(std::string line; std::getline(is, line);)
    {
        line = String::strip_comments(line, "#");

        if(line.empty())
        {
            continue;
        }

        if(line == "END")
        {
            renormalize_priorities();
            return;
        }

        const auto line_split = String::split(line, ":", 1);
        if(line_split.size() != 2)
        {
            throw Genome_Creation_Error("No colon in parameter line: " + line);
        }

        if(String::trim_outer_whitespace(line_split[0]) == "Name")
        {
            const auto gene_name = String::remove_extra_whitespace(line_split[1]);
            const auto found_gene = std::find_if(genome.begin(), genome.end(),
                                                 [&gene_name](const auto& gene)
                                                 {
                                                     return gene->name() == gene_name;
                                                 });
            if(found_gene != genome.end())
            {
                (*found_gene)->read_from(is);
            }
            else
            {
                throw Genome_Creation_Error("Unrecognized gene name: " + gene_name + "\nin line: " + line);
            }
        }
        else if(String::trim_outer_whitespace(line_split[0]) == "Search Method")
        {
            const auto search_method_name_input = String::trim_outer_whitespace(line_split[1]);
            if(search_method_name_input == search_method_name(Search_Method::MINIMAX))
            {
                searching_method = Search_Method::MINIMAX;
            }
            else if(search_method_name_input == search_method_name(Search_Method::ITERATIVE_DEEPENING))
            {
                searching_method = Search_Method::ITERATIVE_DEEPENING;
            }
            else
            {
                throw Genome_Creation_Error("Unrecognized search method: " + line);
            }
        }
        else
        {
            throw Genome_Creation_Error("Bad line in genome file (expected Name): " + line);
        }
    }

    throw Genome_Creation_Error("Reached end of file before END of genome.");
}

double Genome::score_board(const Board& board, const Piece_Color perspective, size_t depth) const noexcept
{
    const auto progress_in_game = game_progress(board);
    return std::accumulate(genome.begin(), genome.end(), 0.0,
                           [&](auto sum, const auto& gene)
                           {
                               return sum + gene->evaluate(board, perspective, depth, progress_in_game);
                           });
}

double Genome::evaluate(const Board& board, const Piece_Color perspective, size_t depth) const noexcept
{
    return score_board(board, perspective, depth) - score_board(board, opposite(perspective), depth);
}

void Genome::mutate(const size_t mutation_count) noexcept
{
    for(size_t i = 0; i < mutation_count; ++i)
    {
        mutate();
    }
}

void Genome::mutate() noexcept
{
    // Create copies of genes equal in number to the number of mutatable components.
    std::vector<Gene*> genes;
    for(const auto& gene : genome)
    {
        genes.insert(genes.end(), gene->mutatable_components(), gene.get());
    }

    // Pick randomly from the list so every component has an equal chance for mutation.
    Random::random_element(genes)->mutate();
    renormalize_priorities();

    if(Random::success_probability(1, 1000))
    {
        searching_method = searching_method == Search_Method::MINIMAX ?
                           Search_Method::ITERATIVE_DEEPENING :
                           Search_Method::MINIMAX;
    }
}

int Genome::id() const noexcept
{
    return id_number;
}

std::string Genome::name() const noexcept
{
    return "Genetic Chess #" + std::to_string(id());
}

std::string Genome::author() const noexcept
{
    return "Mark Harrison";
}

void Genome::print(std::ostream& os) const noexcept
{
    os << "ID: " << id() << '\n';
    os << "Search Method: " << search_method_name() << "\n\n";
    for(const auto& gene : genome)
    {
        gene->print(os);
    }
    os << "END\n" << std::endl;
}

Clock::seconds Genome::time_to_examine(const Board& board, const Clock& clock) const noexcept
{
    return gene_reference<Look_Ahead_Gene>().time_to_examine(board, clock);
}

double Genome::speculation_time_factor(const double game_progress) const noexcept
{
    return gene_reference<Look_Ahead_Gene>().speculation_time_factor(game_progress);
}

double Genome::branching_factor(const double game_progress) const noexcept
{
    return gene_reference<Look_Ahead_Gene>().branching_factor(game_progress);
}

double Genome::expected_number_of_moves_left(const Board& board) const noexcept
{
    return gene_reference<Look_Ahead_Gene>().expected_moves_left(board);
}

double Genome::game_progress(const Board& board) const noexcept
{
    return gene_reference<Piece_Strength_Gene>().game_progress(board);
}

Search_Method Genome::search_method() const noexcept
{
    return searching_method;
}

std::string Genome::search_method_name() const noexcept
{
    return search_method_name(search_method());
}

std::string Genome::search_method_name(const Search_Method search_method) noexcept
{
    return search_method_names[static_cast<int>(search_method)];
}

const std::array<double, 6>& Genome::piece_values() const noexcept
{
    return gene_reference<Piece_Strength_Gene>().piece_values();
}
<commit_msg>Fix misleading spacing<commit_after>#include "Genes/Genome.h"

#include <string>
#include <array>
#include <iostream>
#include <algorithm>
#include <numeric>

#include "Game/Color.h"
#include "Game/Clock.h"
#include "Game/Board.h"

#include "Utility/Random.h"
#include "Utility/String.h"
#include "Utility/Exceptions.h"

#include "Genes/Gene.h"
#include "Genes/Total_Force_Gene.h"
#include "Genes/Freedom_To_Move_Gene.h"
#include "Genes/Pawn_Advancement_Gene.h"
#include "Genes/Passed_Pawn_Gene.h"
#include "Genes/Opponent_Pieces_Targeted_Gene.h"
#include "Genes/Sphere_of_Influence_Gene.h"
#include "Genes/Look_Ahead_Gene.h"
#include "Genes/King_Confinement_Gene.h"
#include "Genes/King_Protection_Gene.h"
#include "Genes/Castling_Possible_Gene.h"
#include "Genes/Piece_Strength_Gene.h"
#include "Genes/Stacked_Pawns_Gene.h"
#include "Genes/Pawn_Islands_Gene.h"
#include "Genes/Checkmate_Material_Gene.h"
#include "Genes/Pawn_Structure_Gene.h"

namespace
{
    const auto search_method_names =
        []()
        {
            std::array<std::string, 2> names;
            names[static_cast<int>(Search_Method::MINIMAX)] = "Minimax";
            names[static_cast<int>(Search_Method::ITERATIVE_DEEPENING)] = "Iterative Deepening";
            return names;
        }();

    int next_id = 0;
}

Genome::Genome() noexcept :
    id_number(next_id++),
    genome{
        std::make_unique<Piece_Strength_Gene>(),
        std::make_unique<Look_Ahead_Gene>(),
        std::make_unique<Total_Force_Gene>(nullptr),
        std::make_unique<Freedom_To_Move_Gene>(),
        std::make_unique<Pawn_Advancement_Gene>(),
        std::make_unique<Passed_Pawn_Gene>(),
        std::make_unique<Opponent_Pieces_Targeted_Gene>(nullptr),
        std::make_unique<Sphere_of_Influence_Gene>(),
        std::make_unique<King_Confinement_Gene>(),
        std::make_unique<King_Protection_Gene>(),
        std::make_unique<Castling_Possible_Gene>(),
        std::make_unique<Stacked_Pawns_Gene>(),
        std::make_unique<Pawn_Islands_Gene>(),
        std::make_unique<Checkmate_Material_Gene>(),
        std::make_unique<Pawn_Structure_Gene>()
    }
{
    renormalize_priorities();
    reset_piece_strength_gene();

    assert(gene_reference<Piece_Strength_Gene>().name() == "Piece Strength Gene");
    assert(gene_reference<Look_Ahead_Gene>().name() == "Look Ahead Gene");
}

Genome::Genome(const Genome& other) noexcept : id_number(other.id()), searching_method(other.search_method())
{
    std::transform(other.genome.begin(), other.genome.end(),
                   genome.begin(),
                   [](const auto& gene)
                   {
                       return gene->duplicate();
                   });
    reset_piece_strength_gene();
}

Genome::Genome(std::istream& is, int id_in) : Genome()
{
    id_number = id_in;
    --next_id;

    if( ! is)
    {
        throw Genome_Creation_Error("Could not read: ");
    }

    for(std::string line; std::getline(is, line);)
    {
        line = String::strip_comments(line, "#");
        if(!String::starts_with(line, "ID"))
        {
            continue;
        }

        const auto param_value = String::split(line, ":", 1);
        if(param_value.size() != 2 || String::trim_outer_whitespace(param_value[0]) != "ID")
        {
            continue;
        }

        if(id_number == String::to_number<int>(param_value[1]))
        {
            auto add_details = [this](const auto& e)
            {
                return "Error in creating Genome #" + std::to_string(id()) + "\n" + e.what() + "\nFile: ";
            };

            try
            {
                read_from(is);
            }
            catch(const Missing_Genome_Data& e)
            {
                throw Missing_Genome_Data(add_details(e));
            }
            catch(const Duplicate_Genome_Data& e)
            {
                throw Duplicate_Genome_Data(add_details(e));
            }
            catch(const Genome_Creation_Error& e)
            {
                throw Genome_Creation_Error(add_details(e));
            }

            next_id = std::max(next_id, id() + 1);
            return;
        }
    }

    throw Genome_Creation_Error("Could not locate ID " + std::to_string(id_number) + " inside file ");
}

void Genome::reset_piece_strength_gene() noexcept
{
    auto piece_strength_gene = &gene_reference<Piece_Strength_Gene>();
    for(auto& gene : genome)
    {
        gene->reset_piece_strength_gene(piece_strength_gene);
    }
}

void Genome::renormalize_priorities() noexcept
{
    for(auto stage : {Game_Stage::OPENING, Game_Stage::ENDGAME})
    {
        const auto norm =
            std::accumulate(genome.begin(), genome.end(), 0.0,
                            [stage](auto sum, const auto& gene)
                            {
                                return sum + (gene->has_priority() ? std::abs(gene->priority(stage)) : 0.0);
                            });
        if(norm > 0.0)
        {
            for(auto& gene : genome)
            {
                gene->scale_priority(stage, 1.0/norm);
            }
        }
    }
}

Genome& Genome::operator=(const Genome& other) noexcept
{
    id_number = other.id();
    std::transform(other.genome.begin(), other.genome.end(),
                   genome.begin(),
                   [](const auto& gene)
                   {
                       return gene->duplicate();
                   });
    reset_piece_strength_gene();
    searching_method = other.search_method();
    return *this;
}

Genome::Genome(const Genome& A, const Genome& B) noexcept : id_number(next_id++)
{
    std::transform(A.genome.begin(), A.genome.end(), B.genome.begin(),
                   genome.begin(),
                   [](const auto& gene_a, const auto& gene_b)
                   {
                       return (Random::coin_flip() ? gene_a : gene_b)->duplicate();
                   });

    reset_piece_strength_gene();
    renormalize_priorities();

    searching_method = Random::coin_flip() ? A.search_method() : B.search_method();
}

void Genome::read_from(std::istream& is)
{
    for(std::string line; std::getline(is, line);)
    {
        line = String::strip_comments(line, "#");

        if(line.empty())
        {
            continue;
        }

        if(line == "END")
        {
            renormalize_priorities();
            return;
        }

        const auto line_split = String::split(line, ":", 1);
        if(line_split.size() != 2)
        {
            throw Genome_Creation_Error("No colon in parameter line: " + line);
        }

        if(String::trim_outer_whitespace(line_split[0]) == "Name")
        {
            const auto gene_name = String::remove_extra_whitespace(line_split[1]);
            const auto found_gene = std::find_if(genome.begin(), genome.end(),
                                                 [&gene_name](const auto& gene)
                                                 {
                                                     return gene->name() == gene_name;
                                                 });
            if(found_gene != genome.end())
            {
                (*found_gene)->read_from(is);
            }
            else
            {
                throw Genome_Creation_Error("Unrecognized gene name: " + gene_name + "\nin line: " + line);
            }
        }
        else if(String::trim_outer_whitespace(line_split[0]) == "Search Method")
        {
            const auto search_method_name_input = String::trim_outer_whitespace(line_split[1]);
            if(search_method_name_input == search_method_name(Search_Method::MINIMAX))
            {
                searching_method = Search_Method::MINIMAX;
            }
            else if(search_method_name_input == search_method_name(Search_Method::ITERATIVE_DEEPENING))
            {
                searching_method = Search_Method::ITERATIVE_DEEPENING;
            }
            else
            {
                throw Genome_Creation_Error("Unrecognized search method: " + line);
            }
        }
        else
        {
            throw Genome_Creation_Error("Bad line in genome file (expected Name): " + line);
        }
    }

    throw Genome_Creation_Error("Reached end of file before END of genome.");
}

double Genome::score_board(const Board& board, const Piece_Color perspective, size_t depth) const noexcept
{
    const auto progress_in_game = game_progress(board);
    return std::accumulate(genome.begin(), genome.end(), 0.0,
                           [&](auto sum, const auto& gene)
                           {
                               return sum + gene->evaluate(board, perspective, depth, progress_in_game);
                           });
}

double Genome::evaluate(const Board& board, const Piece_Color perspective, size_t depth) const noexcept
{
    return score_board(board, perspective, depth) - score_board(board, opposite(perspective), depth);
}

void Genome::mutate(const size_t mutation_count) noexcept
{
    for(size_t i = 0; i < mutation_count; ++i)
    {
        mutate();
    }
}

void Genome::mutate() noexcept
{
    // Create copies of genes equal in number to the number of mutatable components.
    std::vector<Gene*> genes;
    for(const auto& gene : genome)
    {
        genes.insert(genes.end(), gene->mutatable_components(), gene.get());
    }

    // Pick randomly from the list so every component has an equal chance for mutation.
    Random::random_element(genes)->mutate();
    renormalize_priorities();

    if(Random::success_probability(1, 1000))
    {
        searching_method = searching_method == Search_Method::MINIMAX ?
                           Search_Method::ITERATIVE_DEEPENING :
                           Search_Method::MINIMAX;
    }
}

int Genome::id() const noexcept
{
    return id_number;
}

std::string Genome::name() const noexcept
{
    return "Genetic Chess #" + std::to_string(id());
}

std::string Genome::author() const noexcept
{
    return "Mark Harrison";
}

void Genome::print(std::ostream& os) const noexcept
{
    os << "ID: " << id() << '\n';
    os << "Search Method: " << search_method_name() << "\n\n";
    for(const auto& gene : genome)
    {
        gene->print(os);
    }
    os << "END\n" << std::endl;
}

Clock::seconds Genome::time_to_examine(const Board& board, const Clock& clock) const noexcept
{
    return gene_reference<Look_Ahead_Gene>().time_to_examine(board, clock);
}

double Genome::speculation_time_factor(const double game_progress) const noexcept
{
    return gene_reference<Look_Ahead_Gene>().speculation_time_factor(game_progress);
}

double Genome::branching_factor(const double game_progress) const noexcept
{
    return gene_reference<Look_Ahead_Gene>().branching_factor(game_progress);
}

double Genome::expected_number_of_moves_left(const Board& board) const noexcept
{
    return gene_reference<Look_Ahead_Gene>().expected_moves_left(board);
}

double Genome::game_progress(const Board& board) const noexcept
{
    return gene_reference<Piece_Strength_Gene>().game_progress(board);
}

Search_Method Genome::search_method() const noexcept
{
    return searching_method;
}

std::string Genome::search_method_name() const noexcept
{
    return search_method_name(search_method());
}

std::string Genome::search_method_name(const Search_Method search_method) noexcept
{
    return search_method_names[static_cast<int>(search_method)];
}

const std::array<double, 6>& Genome::piece_values() const noexcept
{
    return gene_reference<Piece_Strength_Gene>().piece_values();
}
<|endoftext|>


<commit_before>#include "Matrix.h"
#include <math.h>
#include <string.h>

Matrix::Matrix()
{
	/* load identity */
	contents[0] = contents[5] = contents[10] = contents[15] = 1.0f;
	contents[1] = contents[2] = contents[3] =
	contents[4] = contents[6] = contents[7] =
	contents[8] = contents[9] = contents[11] =
	contents[12] = contents[13] = contents[14] = 0.0f;
}

Matrix::Matrix(GLfloat *_contents)
{
	memcpy(contents, _contents, sizeof(GLfloat)*16);
}

Matrix Matrix::getRightOrthogonalInverse()
{
	/* invert matrix and multiply by that - good for positioning cameras */
	GLfloat inverse[16];

	/* transpose 3x3 */
	inverse[0] = contents[0]; inverse[1] = contents[4]; inverse[2] = contents[8];
	inverse[4] = contents[1]; inverse[5] = contents[5]; inverse[6] = contents[9];
	inverse[8] = contents[2]; inverse[9] = contents[6]; inverse[10] = contents[10];

	/* bottom = 0, 0, 0, 1 */
	inverse[3] = inverse[7] = inverse[11] = 0.0f; inverse[15] = 1.0f;

	/* figure out translation ... */
	inverse[12] = -(inverse[0] * contents[12] + inverse[4] * contents[13] + inverse[8] * contents[14]);
	inverse[13] = -(inverse[1] * contents[12] + inverse[5] * contents[13] + inverse[9] * contents[14]);
	inverse[14] = -(inverse[2] * contents[12] + inverse[6] * contents[13] + inverse[10] * contents[14]);

	return Matrix(inverse);
}

Matrix Matrix::rotationMatrix(GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
{
	/* compose rotation matrix, exactly as per glRotatef */
	GLfloat cosine, sine;

	angle = (GLfloat)((angle * M_PI) / 180.0f);
	cosine = cosf(angle);
	sine = sinf(angle);

	float length = x*x + y*y + z*z;
	if(length > 1.01f || length < 0.99f)
	{
		float multiplier = 1.0f / sqrtf(length);
		x *= multiplier; y *= multiplier; z *= multiplier;
	}

	GLfloat contents[16];
	contents[0] = (x*x*(1 - cosine)) + cosine;
	contents[1] = (y*x*(1 - cosine)) + z*sine;
	contents[2] = (x*z*(1 - cosine)) - y*sine;
	contents[3] = 0.0f;

	contents[4] = (x*y*(1 - cosine)) - z*sine;
	contents[5] = (y*y*(1 - cosine)) + cosine;
	contents[6] = (y*z*(1 - cosine)) + x*sine;
	contents[7] = 0.0f;

	contents[8] = (x*z*(1 - cosine)) + y*sine;
	contents[9] = (y*z*(1 - cosine)) - x*sine;
	contents[10] = (z*z*(1 - cosine)) + cosine;
	contents[11] = 0.0f;

	contents[12] = 0.0f;
	contents[13] = 0.0f;
	contents[14] = 0.0f;
	contents[15] = 1.0f;

	return Matrix(contents);
}

Matrix Matrix::translationMatrix(GLfloat x, GLfloat y, GLfloat z)
{
	GLfloat contents[16];

	// the main diagonal is all 1s
	contents[0] = contents[5] = contents[10] = contents[15] = 1.0f;

	// the translation vector goes in the rightmost column
	contents[12] = x;
	contents[13] = y;
	contents[14] = z;

	// the rest are 0s
	contents[1] = contents[2] = contents[3] =
	contents[4] = contents[6] = contents[7] =
	contents[8] = contents[9] = contents[11] = 0.0f;

	return Matrix(contents);
}

Matrix Matrix::projectionMatrix(GLfloat yFieldOfView, GLfloat aspectRatio, GLfloat zNear, GLfloat zFar)
{
	/* compose projection matrix, exactly as per gluPerspective */
	yFieldOfView = (GLfloat)((yFieldOfView * M_PI) / 180.0f);
	GLfloat cotangent = 1.0f / tanf(yFieldOfView * 0.5f);

	GLfloat contents[16];

	contents[0] = cotangent / aspectRatio;
	contents[1] = contents[2] = contents[3] = 0.0f;

	contents[4] = 0.0f;
	contents[5] = cotangent;
	contents[6] = contents[7] = 0.0f;

	contents[8] = contents[9] = 0.0f;
	contents[10] = (zFar + zNear) / (zNear - zFar);
	contents[11] = -1.0f;

	contents[12] = contents[13] = 0.0f;
	contents[14] = (2.0f * zFar * zNear) / (zNear - zFar);
	contents[15] = 0.0f;

	return Matrix(contents);
}

Matrix operator *(Matrix &left, Matrix &right)
{
	GLfloat result[16];

	/* do multiplication */
	result[0] = left.contents[0] * right.contents[0] +	left.contents[4] * right.contents[1] +	left.contents[8] * right.contents[2];
	result[4] = left.contents[0] * right.contents[4] +	left.contents[4] * right.contents[5] +	left.contents[8] * right.contents[6];
	result[8] = left.contents[0] * right.contents[8] +	left.contents[4] * right.contents[9] +	left.contents[8] * right.contents[10];

	result[1] = left.contents[1] * right.contents[0] +	left.contents[5] * right.contents[1] +	left.contents[9] * right.contents[2];
	result[5] = left.contents[1] * right.contents[4] +	left.contents[5] * right.contents[5] +	left.contents[9] * right.contents[6];
	result[9] = left.contents[1] * right.contents[8] +	left.contents[5] * right.contents[9] +	left.contents[9] * right.contents[10];

	result[2] = left.contents[2] * right.contents[0] +	left.contents[6] * right.contents[1] +	left.contents[10] * right.contents[2];
	result[6] = left.contents[2] * right.contents[4] +	left.contents[6] * right.contents[5] +	left.contents[10] * right.contents[6];
	result[10] = left.contents[2] * right.contents[8] +	left.contents[6] * right.contents[9] +	left.contents[10] * right.contents[10];

	result[3] = result[7] = result[11] =
	result[12] = result[13] = result[14] = 0.0f;
	result[15] = 1.0f;

	return Matrix(result);
}
<commit_msg>Fixed: this class is no longer restricted to right orthogonal matrices, so the multiply has to be the full thing.<commit_after>#include "Matrix.h"
#include <math.h>
#include <string.h>

Matrix::Matrix()
{
	/* load identity */
	contents[0] = contents[5] = contents[10] = contents[15] = 1.0f;
	contents[1] = contents[2] = contents[3] =
	contents[4] = contents[6] = contents[7] =
	contents[8] = contents[9] = contents[11] =
	contents[12] = contents[13] = contents[14] = 0.0f;
}

Matrix::Matrix(GLfloat *_contents)
{
	memcpy(contents, _contents, sizeof(GLfloat)*16);
}

Matrix Matrix::getRightOrthogonalInverse()
{
	/* invert matrix and multiply by that - good for positioning cameras */
	GLfloat inverse[16];

	/* transpose 3x3 */
	inverse[0] = contents[0]; inverse[1] = contents[4]; inverse[2] = contents[8];
	inverse[4] = contents[1]; inverse[5] = contents[5]; inverse[6] = contents[9];
	inverse[8] = contents[2]; inverse[9] = contents[6]; inverse[10] = contents[10];

	/* bottom = 0, 0, 0, 1 */
	inverse[3] = inverse[7] = inverse[11] = 0.0f; inverse[15] = 1.0f;

	/* figure out translation ... */
	inverse[12] = -(inverse[0] * contents[12] + inverse[4] * contents[13] + inverse[8] * contents[14]);
	inverse[13] = -(inverse[1] * contents[12] + inverse[5] * contents[13] + inverse[9] * contents[14]);
	inverse[14] = -(inverse[2] * contents[12] + inverse[6] * contents[13] + inverse[10] * contents[14]);

	return Matrix(inverse);
}

Matrix Matrix::rotationMatrix(GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
{
	/* compose rotation matrix, exactly as per glRotatef */
	GLfloat cosine, sine;

	angle = (GLfloat)((angle * M_PI) / 180.0f);
	cosine = cosf(angle);
	sine = sinf(angle);

	float length = x*x + y*y + z*z;
	if(length > 1.01f || length < 0.99f)
	{
		float multiplier = 1.0f / sqrtf(length);
		x *= multiplier; y *= multiplier; z *= multiplier;
	}

	GLfloat contents[16];
	contents[0] = (x*x*(1 - cosine)) + cosine;
	contents[1] = (y*x*(1 - cosine)) + z*sine;
	contents[2] = (x*z*(1 - cosine)) - y*sine;
	contents[3] = 0.0f;

	contents[4] = (x*y*(1 - cosine)) - z*sine;
	contents[5] = (y*y*(1 - cosine)) + cosine;
	contents[6] = (y*z*(1 - cosine)) + x*sine;
	contents[7] = 0.0f;

	contents[8] = (x*z*(1 - cosine)) + y*sine;
	contents[9] = (y*z*(1 - cosine)) - x*sine;
	contents[10] = (z*z*(1 - cosine)) + cosine;
	contents[11] = 0.0f;

	contents[12] = 0.0f;
	contents[13] = 0.0f;
	contents[14] = 0.0f;
	contents[15] = 1.0f;

	return Matrix(contents);
}

Matrix Matrix::translationMatrix(GLfloat x, GLfloat y, GLfloat z)
{
	GLfloat contents[16];

	// the main diagonal is all 1s
	contents[0] = contents[5] = contents[10] = contents[15] = 1.0f;

	// the translation vector goes in the rightmost column
	contents[12] = x;
	contents[13] = y;
	contents[14] = z;

	// the rest are 0s
	contents[1] = contents[2] = contents[3] =
	contents[4] = contents[6] = contents[7] =
	contents[8] = contents[9] = contents[11] = 0.0f;

	return Matrix(contents);
}

Matrix Matrix::projectionMatrix(GLfloat yFieldOfView, GLfloat aspectRatio, GLfloat zNear, GLfloat zFar)
{
	/* compose projection matrix, exactly as per gluPerspective */
	yFieldOfView = (GLfloat)((yFieldOfView * M_PI) / 180.0f);
	GLfloat cotangent = 1.0f / tanf(yFieldOfView * 0.5f);

	GLfloat contents[16];

	contents[0] = cotangent / aspectRatio;
	contents[1] = contents[2] = contents[3] = 0.0f;

	contents[4] = 0.0f;
	contents[5] = cotangent;
	contents[6] = contents[7] = 0.0f;

	contents[8] = contents[9] = 0.0f;
	contents[10] = (zFar + zNear) / (zNear - zFar);
	contents[11] = -1.0f;

	contents[12] = contents[13] = 0.0f;
	contents[14] = (2.0f * zFar * zNear) / (zNear - zFar);
	contents[15] = 0.0f;

	return Matrix(contents);
}

Matrix operator *(Matrix &left, Matrix &right)
{
	GLfloat result[16];

	/* do multiplication */
	result[0]	= left.contents[0] * right.contents[0]	+	left.contents[4] * right.contents[1]	+	left.contents[8] * right.contents[2]	+	left.contents[12] * right.contents[3];
	result[4]	= left.contents[0] * right.contents[4]	+	left.contents[4] * right.contents[5]	+	left.contents[8] * right.contents[6]	+	left.contents[12] * right.contents[7];
	result[8]	= left.contents[0] * right.contents[8]	+	left.contents[4] * right.contents[9]	+	left.contents[8] * right.contents[10]	+	left.contents[12] * right.contents[11];
	result[12]	= left.contents[0] * right.contents[12]	+	left.contents[4] * right.contents[13]	+	left.contents[8] * right.contents[14]	+	left.contents[12] * right.contents[15];

	result[1]	= left.contents[1] * right.contents[0]	+	left.contents[5] * right.contents[1]	+	left.contents[9] * right.contents[2]	+	left.contents[13] * right.contents[3];
	result[5]	= left.contents[1] * right.contents[4]	+	left.contents[5] * right.contents[5]	+	left.contents[9] * right.contents[6]	+	left.contents[13] * right.contents[7];
	result[9]	= left.contents[1] * right.contents[8]	+	left.contents[5] * right.contents[9]	+	left.contents[9] * right.contents[10]	+	left.contents[13] * right.contents[11];
	result[13]	= left.contents[1] * right.contents[12]	+	left.contents[5] * right.contents[13]	+	left.contents[9] * right.contents[14]	+	left.contents[13] * right.contents[15];

	result[2]	= left.contents[2] * right.contents[0]	+	left.contents[6] * right.contents[1]	+	left.contents[10] * right.contents[2]	+	left.contents[14] * right.contents[3];
	result[6]	= left.contents[2] * right.contents[4]	+	left.contents[6] * right.contents[5]	+	left.contents[10] * right.contents[6]	+	left.contents[14] * right.contents[7];
	result[10]	= left.contents[2] * right.contents[8]	+	left.contents[6] * right.contents[9]	+	left.contents[10] * right.contents[10]	+	left.contents[14] * right.contents[11];
	result[14]	= left.contents[2] * right.contents[12]	+	left.contents[6] * right.contents[13]	+	left.contents[10] * right.contents[14]	+	left.contents[14] * right.contents[15];

	result[3]	= left.contents[3] * right.contents[0]	+	left.contents[7] * right.contents[1]	+	left.contents[11] * right.contents[2]	+	left.contents[15] * right.contents[3];
	result[7]	= left.contents[3] * right.contents[4]	+	left.contents[7] * right.contents[5]	+	left.contents[11] * right.contents[6]	+	left.contents[15] * right.contents[7];
	result[11]	= left.contents[3] * right.contents[8]	+	left.contents[7] * right.contents[9]	+	left.contents[11] * right.contents[10]	+	left.contents[15] * right.contents[11];
	result[15]	= left.contents[3] * right.contents[12]	+	left.contents[7] * right.contents[13]	+	left.contents[11] * right.contents[14]	+	left.contents[15] * right.contents[15];

	return Matrix(result);
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <typeinfo>
#include <ctype.h>

enum TokenType{
  TOKEN_BRACKET_OPEN,
  TOKEN_BRACKET_CLOSE,
  TOKEN_SYMBOL,
  TOKEN_STRING,
  TOKEN_NIL,
};

class Token {
public:
  TokenType type;
  std::string value;

  Token(TokenType atype) : type(atype), value(std::string()) {
  }

  Token(TokenType atype, std::string avalue) : type(atype), value(avalue) {
  }
};

namespace Lisp {
  class Expression {
  public:
    virtual ~Expression() {}

    virtual std::string lisp_str() = 0;
  };

  class CallFunction : public Expression {
  public:
    std::string name;
    std::vector<Expression*> args;

    CallFunction(std::string aname, std::vector<Expression*> &aargs) : name(aname), args(aargs) {}
    ~CallFunction() {
      for(size_t i = 0 ; i < args.size() ; i++) {
        delete args[i];
      }
    }

    std::string lisp_str() {
      std::stringstream ss;
      ss << "(" << name << " ";
      for(Expression* arg : args) {
        ss << arg->lisp_str() << " ";
      }
      ss << ")";
      return ss.str();
    }
  };

  class String : public Expression {
  public:
    std::string value;

    String(std::string &avalue) : value(avalue) {}

    std::string lisp_str() { return '"' + value + '"'; }
  };

  // TODO: RubyみたくExpression*に埋め込みたい
  class Nil : public Expression {
  public:
    Nil() {}

    std::string lisp_str() { return "nil"; }
  };
}

bool is_symbol(char c) {
  return isalnum(c) && isalpha(c);
}

int main() {
  using namespace std;

  string code;
  //code.reserve(1024);
  vector<Token*> tokens;
  vector<Lisp::Expression*> exprs;

  char ch;
  while((ch = cin.get()) != std::char_traits<char>::eof()) {
    code.push_back(ch);
  }

  for(size_t i = 0 ; i < code.size() - 1 ; i++) { //TODO: -1を修正(EOFっぽい?)
    char ch = code[i];
    if(ch == '(')
      tokens.push_back(new Token(TOKEN_BRACKET_OPEN));
    else if(ch == ')')
      tokens.push_back(new Token(TOKEN_BRACKET_CLOSE));
    else if(ch == '"') { // string
      i++;

      size_t token_len = 0;
      while(code[i + token_len] != '"') {
        token_len++;
        if(i + token_len >= code.size()) {
          //TODO: raise an error
        }
      }
      tokens.push_back(new Token(TOKEN_STRING, code.substr(i, token_len)));
      i += token_len;
    }
    else if(ch == ' ' || ch == '\n')
      ;//skip
    else { // symbol
      size_t token_len = 0;
      while(is_symbol(code[i + token_len])) {
        token_len++;
        if(i + token_len >= code.size()) {
          //TODO: raise an error
        }
      }

      string token_val = code.substr(i, token_len);
      TokenType token_type;
      if(token_val == "nil")
        token_type = TOKEN_NIL;
      else
        token_type = TOKEN_SYMBOL;

      if(token_type == TOKEN_SYMBOL)
        tokens.push_back(new Token(TOKEN_SYMBOL, token_val));
      else
        tokens.push_back(new Token(token_type));

      i += token_len - 1;
    }
  }

  for(auto token : tokens) {
    cout << "token type: " << token->type << ", value: " << token->value << endl;
  }

  // parse
  for(size_t i = 0 ; i < tokens.size() ; i++) {
    Token* token = tokens[i];
    switch(token->type) {
      case TOKEN_BRACKET_OPEN: {
        string name;
        vector<Lisp::Expression*> args;

        i++;
        if(tokens[i]->type != TOKEN_STRING) {
          //TODO: raise an error
        }
        name = tokens[i]->value;

        i++;
        for(; tokens[i]->type != TOKEN_BRACKET_CLOSE ; i++) {
          switch(tokens[i]->type) {
            case TOKEN_STRING:
              args.push_back(new Lisp::String(tokens[i]->value));
              break;
            case TOKEN_NIL:
              args.push_back(new Lisp::Nil());
              break;
            default: ;
          }
        }

        exprs.push_back(new Lisp::CallFunction(name, args));

        break;
      }
      default:
        break;
    }
  }

  // evaluate
  for(size_t i = 0 ; i < exprs.size() ; i++) {
    auto expr = exprs[i];

    const type_info& id = typeid(*expr);
    if(id == typeid(Lisp::CallFunction)) {
      auto call_fun = (Lisp::CallFunction*)expr;
      auto name = call_fun->name;
      if(name == "print") {
        for(auto arg : call_fun->args) {
          cout << ((Lisp::String*)arg)->value;
        }
        exprs[i] = new Lisp::Nil;
      }
      else if(name == "inspect") {
        cout << call_fun->args[0]->lisp_str() << endl;
        exprs[i] = new Lisp::Nil;
      }
    }
  }

  // destruction
  for(size_t i = 0 ; i < tokens.size() ; i++) {
    delete tokens[i];
  }

  for(size_t i = 0 ; i < exprs.size() ; i++) {
    delete exprs[i];
  }

  return 0;
}
<commit_msg>Listを追加<commit_after>#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <typeinfo>
#include <ctype.h>

enum TokenType{
  TOKEN_BRACKET_OPEN,
  TOKEN_BRACKET_CLOSE,
  TOKEN_SYMBOL,
  TOKEN_STRING,
  TOKEN_NIL,
};

class Token {
public:
  TokenType type;
  std::string value;

  Token(TokenType atype) : type(atype), value(std::string()) {
  }

  Token(TokenType atype, std::string avalue) : type(atype), value(avalue) {
  }
};

namespace Lisp {
  class Expression {
  public:
    virtual ~Expression() {}

    virtual std::string lisp_str() = 0;
  };

  class CallFunction : public Expression {
  public:
    std::string name;
    std::vector<Expression*> args;

    CallFunction(std::string aname, std::vector<Expression*> &aargs) : name(aname), args(aargs) {}
    ~CallFunction() {
      for(size_t i = 0 ; i < args.size() ; i++) {
        delete args[i];
      }
    }

    std::string lisp_str() {
      std::stringstream ss;
      ss << "(" << name << " ";
      for(Expression* arg : args) {
        ss << arg->lisp_str() << " ";
      }
      ss << ")";
      return ss.str();
    }
  };

  class String : public Expression {
  public:
    std::string value;

    String(std::string &avalue) : value(avalue) {}

    std::string lisp_str() { return '"' + value + '"'; }
  };

  class List : public Expression {
  public:
    std::vector<Expression*> values;

    List(std::vector<Expression*> &avalues) : values(avalues) {}

    std::string lisp_str() {
      std::stringstream ss;
      ss << "(";
      for(Expression* value : values) {
        ss << value->lisp_str() << " ";
      }
      ss << ")";
      return ss.str();
    }
  };

  // TODO: RubyみたくExpression*に埋め込みたい
  class Nil : public Expression {
  public:
    Nil() {}

    std::string lisp_str() { return "nil"; }
  };
}

bool is_symbol(char c) {
  return isalnum(c) && isalpha(c);
}

int main() {
  using namespace std;

  string code;
  //code.reserve(1024);
  vector<Token*> tokens;
  vector<Lisp::Expression*> exprs;

  char ch;
  while((ch = cin.get()) != std::char_traits<char>::eof()) {
    code.push_back(ch);
  }

  for(size_t i = 0 ; i < code.size() - 1 ; i++) { //TODO: -1を修正(EOFっぽい?)
    char ch = code[i];
    if(ch == '(')
      tokens.push_back(new Token(TOKEN_BRACKET_OPEN));
    else if(ch == ')')
      tokens.push_back(new Token(TOKEN_BRACKET_CLOSE));
    else if(ch == '"') { // string
      i++;

      size_t token_len = 0;
      while(code[i + token_len] != '"') {
        token_len++;
        if(i + token_len >= code.size()) {
          //TODO: raise an error
        }
      }
      tokens.push_back(new Token(TOKEN_STRING, code.substr(i, token_len)));
      i += token_len;
    }
    else if(ch == ' ' || ch == '\n')
      ;//skip
    else { // symbol
      size_t token_len = 0;
      while(is_symbol(code[i + token_len])) {
        token_len++;
        if(i + token_len >= code.size()) {
          //TODO: raise an error
        }
      }

      string token_val = code.substr(i, token_len);
      TokenType token_type;
      if(token_val == "nil")
        token_type = TOKEN_NIL;
      else
        token_type = TOKEN_SYMBOL;

      if(token_type == TOKEN_SYMBOL)
        tokens.push_back(new Token(TOKEN_SYMBOL, token_val));
      else
        tokens.push_back(new Token(token_type));

      i += token_len - 1;
    }
  }

  for(auto token : tokens) {
    cout << "token type: " << token->type << ", value: " << token->value << endl;
  }

  // parse
  for(size_t i = 0 ; i < tokens.size() ; i++) {
    Token* token = tokens[i];
    switch(token->type) {
      case TOKEN_BRACKET_OPEN: {
        string name;
        vector<Lisp::Expression*> args;

        i++;
        if(tokens[i]->type != TOKEN_STRING) {
          //TODO: raise an error
        }
        name = tokens[i]->value;

        i++;
        for(; tokens[i]->type != TOKEN_BRACKET_CLOSE ; i++) {
          switch(tokens[i]->type) {
            case TOKEN_STRING:
              args.push_back(new Lisp::String(tokens[i]->value));
              break;
            case TOKEN_NIL:
              args.push_back(new Lisp::Nil());
              break;
            default: ;
          }
        }

        exprs.push_back(new Lisp::CallFunction(name, args));

        break;
      }
      default:
        break;
    }
  }

  // evaluate
  for(size_t i = 0 ; i < exprs.size() ; i++) {
    auto expr = exprs[i];

    const type_info& id = typeid(*expr);
    if(id == typeid(Lisp::CallFunction)) {
      auto call_fun = (Lisp::CallFunction*)expr;
      auto name = call_fun->name;
      if(name == "print") {
        for(auto arg : call_fun->args) {
          cout << ((Lisp::String*)arg)->value;
        }
        exprs[i] = new Lisp::Nil;
      }
      else if(name == "inspect") {
        cout << call_fun->args[0]->lisp_str() << endl;
        exprs[i] = new Lisp::Nil;
      }
    }
  }

  // destruction
  for(size_t i = 0 ; i < tokens.size() ; i++) {
    delete tokens[i];
  }

  for(size_t i = 0 ; i < exprs.size() ; i++) {
    delete exprs[i];
  }

  return 0;
}
<|endoftext|>


<commit_before>a4edc28f-2747-11e6-b293-e0f84713e7b8<commit_msg>Fixed that one bug<commit_after>a501e46e-2747-11e6-a586-e0f84713e7b8<|endoftext|>


<commit_before>#include "html5viewer/html5viewer.h"
#include "clientwrapper.hpp"
#include "utilities.hpp"

#include <boost/thread.hpp>
#include <fc/filesystem.hpp>
#include <bts/blockchain/config.hpp>
#include <signal.h>

#include <QApplication>
#include <QSettings>
#include <QPixmap>
#include <QErrorMessage>
#include <QSplashScreen>
#include <QDir>
#include <QWebSettings>
#include <QWebPage>
#include <QWebFrame>
#include <QJsonDocument>
#include <QGraphicsWebView>
#include <QClipboard>

#include <boost/program_options.hpp>

#include <bts/client/client.hpp>
#include <bts/net/upnp.hpp>
#include <bts/blockchain/chain_database.hpp>
#include <bts/rpc/rpc_server.hpp>
#include <bts/cli/cli.hpp>
#include <bts/utilities/git_revision.hpp>
#include <fc/filesystem.hpp>
#include <fc/thread/thread.hpp>
#include <fc/log/file_appender.hpp>
#include <fc/log/logger_config.hpp>
#include <fc/io/json.hpp>
#include <fc/reflect/variant.hpp>
#include <fc/git_revision.hpp>
#include <fc/io/json.hpp>
#include <fc/log/logger_config.hpp>

#include <boost/iostreams/tee.hpp>
#include <boost/iostreams/stream.hpp>
#include <fstream>

#include <QResource>
#include <iostream>
#include <iomanip>

#ifdef NDEBUG
#include "config_prod.hpp"
#else
#include "config_dev.hpp"
#endif

int main( int argc, char** argv )
{
   QCoreApplication::setOrganizationName( "BitShares" );
   QCoreApplication::setOrganizationDomain( "bitshares.org" );
   QCoreApplication::setApplicationName( BTS_BLOCKCHAIN_NAME );
   QApplication app(argc, argv);

   QPixmap pixmap(":/images/splash_screen.png");
   QSplashScreen splash(pixmap);
      splash.showMessage(QObject::tr("Loading configuration..."),
                         Qt::AlignCenter | Qt::AlignBottom, Qt::white);
   splash.show();

   try {
    ClientWrapper client;
    client.connect(&client, &ClientWrapper::error, [&](QString errorString) {
        splash.showMessage(errorString, Qt::AlignCenter | Qt::AlignBottom, Qt::white);
        fc::usleep( fc::seconds(3) );
        exit(-1);
    });
    client.initialize();

    qApp->processEvents();

    Html5Viewer viewer;
    QWebSettings::globalSettings()->setAttribute( QWebSettings::PluginsEnabled, false );
    viewer.webView()->page()->settings()->setAttribute( QWebSettings::PluginsEnabled, false );
    viewer.setOrientation(Html5Viewer::ScreenOrientationAuto);
    viewer.resize(1200,800);
    viewer.webView()->setAcceptHoverEvents(true);
    viewer.webView()->page()->mainFrame()->addToJavaScriptWindowObject("bitshares", &client);
    viewer.webView()->page()->mainFrame()->addToJavaScriptWindowObject("utilities", new Utilities, QWebFrame::ScriptOwnership);
    viewer.show();

    viewer.loadUrl(client.http_url());

    splash.finish(&viewer);

    return app.exec();
   }
   catch ( const fc::exception& e)
   {
      elog( "${e}", ("e",e.to_detail_string() ) );
      QErrorMessage::qtHandler()->showMessage( e.to_string().c_str() );
   }
}
<commit_msg>Remove unnecessary #include<commit_after>#include "html5viewer/html5viewer.h"
#include "clientwrapper.hpp"
#include "utilities.hpp"

#include <boost/thread.hpp>
#include <fc/filesystem.hpp>
#include <bts/blockchain/config.hpp>
#include <signal.h>

#include <QApplication>
#include <QSettings>
#include <QPixmap>
#include <QErrorMessage>
#include <QSplashScreen>
#include <QDir>
#include <QWebSettings>
#include <QWebPage>
#include <QWebFrame>
#include <QJsonDocument>
#include <QGraphicsWebView>

#include <boost/program_options.hpp>

#include <bts/client/client.hpp>
#include <bts/net/upnp.hpp>
#include <bts/blockchain/chain_database.hpp>
#include <bts/rpc/rpc_server.hpp>
#include <bts/cli/cli.hpp>
#include <bts/utilities/git_revision.hpp>
#include <fc/filesystem.hpp>
#include <fc/thread/thread.hpp>
#include <fc/log/file_appender.hpp>
#include <fc/log/logger_config.hpp>
#include <fc/io/json.hpp>
#include <fc/reflect/variant.hpp>
#include <fc/git_revision.hpp>
#include <fc/io/json.hpp>
#include <fc/log/logger_config.hpp>

#include <boost/iostreams/tee.hpp>
#include <boost/iostreams/stream.hpp>
#include <fstream>

#include <QResource>
#include <iostream>
#include <iomanip>

#ifdef NDEBUG
#include "config_prod.hpp"
#else
#include "config_dev.hpp"
#endif

int main( int argc, char** argv )
{
   QCoreApplication::setOrganizationName( "BitShares" );
   QCoreApplication::setOrganizationDomain( "bitshares.org" );
   QCoreApplication::setApplicationName( BTS_BLOCKCHAIN_NAME );
   QApplication app(argc, argv);

   QPixmap pixmap(":/images/splash_screen.png");
   QSplashScreen splash(pixmap);
      splash.showMessage(QObject::tr("Loading configuration..."),
                         Qt::AlignCenter | Qt::AlignBottom, Qt::white);
   splash.show();

   try {
    ClientWrapper client;
    client.connect(&client, &ClientWrapper::error, [&](QString errorString) {
        splash.showMessage(errorString, Qt::AlignCenter | Qt::AlignBottom, Qt::white);
        fc::usleep( fc::seconds(3) );
        exit(-1);
    });
    client.initialize();

    qApp->processEvents();

    Html5Viewer viewer;
    QWebSettings::globalSettings()->setAttribute( QWebSettings::PluginsEnabled, false );
    viewer.webView()->page()->settings()->setAttribute( QWebSettings::PluginsEnabled, false );
    viewer.setOrientation(Html5Viewer::ScreenOrientationAuto);
    viewer.resize(1200,800);
    viewer.webView()->setAcceptHoverEvents(true);
    viewer.webView()->page()->mainFrame()->addToJavaScriptWindowObject("bitshares", &client);
    viewer.webView()->page()->mainFrame()->addToJavaScriptWindowObject("utilities", new Utilities, QWebFrame::ScriptOwnership);
    viewer.show();

    viewer.loadUrl(client.http_url());

    splash.finish(&viewer);

    return app.exec();
   }
   catch ( const fc::exception& e)
   {
      elog( "${e}", ("e",e.to_detail_string() ) );
      QErrorMessage::qtHandler()->showMessage( e.to_string().c_str() );
   }
}
<|endoftext|>


<commit_before>6f71a4c7-ad5c-11e7-86e4-ac87a332f658<commit_msg>bug fix<commit_after>6fe33de8-ad5c-11e7-93ec-ac87a332f658<|endoftext|>


<commit_before>d48d8b38-4b02-11e5-bbc4-28cfe9171a43<commit_msg>almost working<commit_after>d49d5e8c-4b02-11e5-8fbd-28cfe9171a43<|endoftext|>


<commit_before>#include <SFML/Window.hpp>
#include <GL/glew.h>
#include <iostream>

void loadShader(GLuint &program)
{
	GLint compile_ok = GL_FALSE, link_ok = GL_FALSE;

	// Vertex
	GLuint vs = glCreateShader(GL_VERTEX_SHADER);
	const char *vs_source =
		"#version 120\n"
		"attribute vec2 coord2d;                  "
		"void main(void) {                        "
		"  gl_Position = vec4(coord2d, 0.0, 1.0); "
		"}";
	glShaderSource(vs, 1, &vs_source, NULL);
	glCompileShader(vs);
	glGetShaderiv(vs, GL_COMPILE_STATUS, &compile_ok);
	if (!compile_ok)
		throw std::runtime_error("Error in vertex shader");

	// Fragment
	GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
	const char *fs_source =
		"#version 120\n"
		"void main(void) {        "
		"  gl_FragColor[0] = 0.3; "
		"  gl_FragColor[1] = 1.0; "
		"  gl_FragColor[2] = 0.3; "
		"}";
	glShaderSource(fs, 1, &fs_source, NULL);
	glCompileShader(fs);
	glGetShaderiv(fs, GL_COMPILE_STATUS, &compile_ok);
	if (!compile_ok)
		throw std::runtime_error("Error in fragment shader");

	program = glCreateProgram();
	glAttachShader(program, vs);
	glAttachShader(program, fs);
	glLinkProgram(program);
	glGetProgramiv(program, GL_LINK_STATUS, &link_ok);
	if (!link_ok)
		throw std::runtime_error("Error in glLinkProgram");

	const char* attribute_name = "coord2d";
}

int main()
{
	GLuint program;
	GLuint vbo_triangle;
	GLint attribute_coord2d;

	sf::Window window(sf::VideoMode(800,600),"NetroTD",sf::Style::Default);

	// Load glew
	GLenum glew_status = glewInit();
	if (glew_status != GLEW_OK)
		throw std::runtime_error("Glewinit");

	// Load Shader
	loadShader(program);

	attribute_coord2d = glGetAttribLocation(program, "coord2d");
	if (attribute_coord2d == -1)
		throw std::runtime_error("Could not bind attribute");

	//Buffer
	glGenBuffers(1, &vbo_triangle);
	glBindBuffer(GL_ARRAY_BUFFER, vbo_triangle);
	static const GLfloat triangle_vertices[] =
	{
		0.0,	0.8,
		-0.8,	-0.8,
		0.8, 	-0.8,
	};
	glBufferData(GL_ARRAY_BUFFER, sizeof(triangle_vertices), triangle_vertices, GL_STATIC_DRAW);
	glVertexAttribPointer(attribute_coord2d, 2, GL_FLOAT, GL_FALSE, 0, 0);

	// Some useful info
	std::cout << "OpenGL version: " << glGetString(GL_VERSION) << std::endl;
    std::cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
    std::cout << "Vendor: " << glGetString(GL_VENDOR) << std::endl;
    std::cout << "Renderer: " << glGetString(GL_RENDERER) << std::endl;

	while (true)
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
			{
				glDeleteProgram(program);
				return EXIT_SUCCESS;
			}

            else if (event.type == sf::Event::Resized)
                glViewport(0, 0, event.size.width, event.size.height);
        }

		// Clear
		glClearColor(0, 0, 0, 1);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

		glUseProgram(program);
		glBindBuffer(GL_ARRAY_BUFFER, vbo_triangle);
		glEnableVertexAttribArray(attribute_coord2d);

		// Draw
		glDrawArrays(GL_TRIANGLES, 0, 6);

		glDisableVertexAttribArray(attribute_coord2d);
		glUseProgram(0);

		// Refresh window
        window.display();
    }
}
<commit_msg>Attemp to render rungholt sceen.. does not crash but I get black screen<commit_after>#include <SFML/Window.hpp>
#include <GL/glew.h>
#include <iostream>
#include <string>
#include <vector>

#define TINYOBJLOADER_IMPLEMENTATION
#include "tiny_obj_loader.h"

void loadShader(GLuint &program)
{
    GLint compile_ok = GL_FALSE, link_ok = GL_FALSE;

    // Vertex
    GLuint vs = glCreateShader(GL_VERTEX_SHADER);
    const char *vs_source =
        "#version 120\n"
        "attribute vec2 coord2d;                  "
        "void main(void) {                        "
        "  gl_Position = vec4(coord2d, 0.0, 1.0); "
        "}";
    glShaderSource(vs, 1, &vs_source, NULL);
    glCompileShader(vs);
    glGetShaderiv(vs, GL_COMPILE_STATUS, &compile_ok);
    if (!compile_ok)
        throw std::runtime_error("Error in vertex shader");

    // Fragment
    GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
    const char *fs_source =
        "#version 120\n"
        "void main(void) {        "
        "  gl_FragColor[0] = 0.3; "
        "  gl_FragColor[1] = 1.0; "
        "  gl_FragColor[2] = 0.3; "
        "}";
    glShaderSource(fs, 1, &fs_source, NULL);
    glCompileShader(fs);
    glGetShaderiv(fs, GL_COMPILE_STATUS, &compile_ok);
    if (!compile_ok)
        throw std::runtime_error("Error in fragment shader");

    program = glCreateProgram();
    glAttachShader(program, vs);
    glAttachShader(program, fs);
    glLinkProgram(program);
    glGetProgramiv(program, GL_LINK_STATUS, &link_ok);
    if (!link_ok)
        throw std::runtime_error("Error in glLinkProgram");

    const char* attribute_name = "coord2d";
}

int main()
{

    /*
    //Buffer
    glGenBuffers(1, &vbo_triangle);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_triangle);
    static const GLfloat triangle_vertices[] =
    {
    0.0,	0.8,
    -0.8,	-0.8,
    0.8, 	-0.8,
    };
    glBufferData(GL_ARRAY_BUFFER, sizeof(triangle_vertices), triangle_vertices, GL_STATIC_DRAW);
    glVertexAttribPointer(attribute_coord2d, 2, GL_FLOAT, GL_FALSE, 0, 0);

    // Some useful info
    std::cout << "OpenGL version: " << glGetString(GL_VERSION) << std::endl;
    std::cout << "GLSL version: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
    std::cout << "Vendor: " << glGetString(GL_VENDOR) << std::endl;
    std::cout << "Renderer: " << glGetString(GL_RENDERER) << std::endl;

*/

    std::string inputfile = "models/rungholt/rungholt.obj";
    std::vector<tinyobj::shape_t> shapes;
    std::vector<tinyobj::material_t> materials;

    std::string err;
    bool ret = tinyobj::LoadObj(shapes, materials, err, inputfile.c_str(),"models/rungholt/materials/");

    if (!err.empty()) { // `err` may contain warning message.
        std::cerr << err << std::endl;
    }

    if (!ret) {
        exit(1);
    }

    std::cout << "# of shapes    : " << shapes.size() << std::endl;
    std::cout << "# of materials : " << materials.size() << std::endl;

    for (size_t i = 0; i < shapes.size(); i++)
    {
        printf("shape[%ld].name = %s\n",
                i, shapes[i].name.c_str());
        printf("Size of shape[%ld].indices: %ld\n",
                i, shapes[i].mesh.indices.size());
        printf("Size of shape[%ld].material_ids: %ld\n",
                i, shapes[i].mesh.material_ids.size());

        assert((shapes[i].mesh.indices.size() % 3) == 0);

        for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++)
        {
            printf("  idx[%ld] = %d, %d, %d. mat_id = %d\n",
                    f, shapes[i].mesh.indices[3*f+0],
                    shapes[i].mesh.indices[3*f+1],
                    shapes[i].mesh.indices[3*f+2],
                    shapes[i].mesh.material_ids[f]);
        }

        printf("shape[%ld].vertices: %ld\n",
                i, shapes[i].mesh.positions.size());

        assert((shapes[i].mesh.positions.size() % 3) == 0);

        for (size_t v = 0; v < shapes[i].mesh.positions.size() / 3; v++)
        {
            printf("  v[%ld] = (%f, %f, %f)\n", v,
                    shapes[i].mesh.positions[3*v+0],
                    shapes[i].mesh.positions[3*v+1],
                    shapes[i].mesh.positions[3*v+2]);
        }
    }

    for (size_t i = 0; i < materials.size(); i++) {
        printf("material[%ld].name = %s\n", i, materials[i].name.c_str());
        printf("  material.Ka = (%f, %f ,%f)\n", materials[i].ambient[0], materials[i].ambient[1], materials[i].ambient[2]);
        printf("  material.Kd = (%f, %f ,%f)\n", materials[i].diffuse[0], materials[i].diffuse[1], materials[i].diffuse[2]);
        printf("  material.Ks = (%f, %f ,%f)\n", materials[i].specular[0], materials[i].specular[1], materials[i].specular[2]);
        printf("  material.Tr = (%f, %f ,%f)\n", materials[i].transmittance[0], materials[i].transmittance[1], materials[i].transmittance[2]);
        printf("  material.Ke = (%f, %f ,%f)\n", materials[i].emission[0], materials[i].emission[1], materials[i].emission[2]);
        printf("  material.Ns = %f\n", materials[i].shininess);
        printf("  material.Ni = %f\n", materials[i].ior);
        printf("  material.dissolve = %f\n", materials[i].dissolve);
        printf("  material.illum = %d\n", materials[i].illum);
        printf("  material.map_Ka = %s\n", materials[i].ambient_texname.c_str());
        printf("  material.map_Kd = %s\n", materials[i].diffuse_texname.c_str());
        printf("  material.map_Ks = %s\n", materials[i].specular_texname.c_str());
        printf("  material.map_Ns = %s\n", materials[i].specular_highlight_texname.c_str());
        std::map<std::string, std::string>::const_iterator it(materials[i].unknown_parameter.begin());
        std::map<std::string, std::string>::const_iterator itEnd(materials[i].unknown_parameter.end());
        for (; it != itEnd; it++) {
            printf("  material.%s = %s\n", it->first.c_str(), it->second.c_str());
        }
        printf("\n");
    }

    GLuint program;
    GLuint vbo_triangle;
    GLint attribute_coord2d;
    GLuint vaoIds[shapes.size()];
    GLuint vboIds[shapes.size()];
    sf::Window window(sf::VideoMode(800,600),"NetroTD",sf::Style::Default);

    // Load glew
    GLenum glew_status = glewInit();
    if (glew_status != GLEW_OK)
        throw std::runtime_error("Glewinit");

    // Load Shader
    loadShader(program);

    attribute_coord2d = glGetAttribLocation(program, "coord2d");
    if (attribute_coord2d == -1)
        throw std::runtime_error("Could not bind attribute");

    for(int i = 0; i < shapes.size(); ++i)
    {
        glGenVertexArrays(1,&vaoIds[i]);
        glBindVertexArray(vaoIds[i]);

        glGenBuffers(1,&vboIds[i]);
        glBindBuffer(GL_ARRAY_BUFFER,vboIds[i]);
        glBufferData(GL_ARRAY_BUFFER,shapes[i].mesh.num_vertices.size() * sizeof(shapes[i].mesh.num_vertices[0]),&shapes[i].mesh.num_vertices[0], GL_STATIC_DRAW);
    }
    while (true)
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
            {
                glDeleteProgram(program);
                return EXIT_SUCCESS;
            }

            else if (event.type == sf::Event::Resized)
                glViewport(0, 0, event.size.width, event.size.height);
        }

        // Clear
        glClearColor(0, 0, 0, 1);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glUseProgram(program);

        //glColor3f(0,1,0);
        for(int i = 0; i < shapes.size();++i)
        {
            glBindBuffer(GL_ARRAY_BUFFER, vboIds[i]);
            //glEnableVertexAttribArray(attribute_coord2d);

            // Draw
            glDrawArrays(GL_TRIANGLES, 0, shapes[i].mesh.num_vertices.size());
        }
        glBindVertexArray(0);
        //glDisableVertexAttribArray(attribute_coord2d);
        glUseProgram(0);

        // Refresh window
        window.display();
    }

}
<|endoftext|>