<commit_before>/*
 * Copyright 2011, 2012 Esrille Inc.
 *
 * 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.
 */

// A test harness for the implementation report of
//       the CSS2.1 Conformance Test Suite
// http://test.csswg.org/suites/css2.1/20110323/

#include <unistd.h>
#include <sys/wait.h>

#include <cstring>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

#include <boost/version.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>

enum {
    INTERACTIVE,
    HEADLESS,
    REPORT,
    UPDATE
};

int processOutput(std::istream& stream, std::string& result)
{
    std::string output;
    bool completed = false;
    while (std::getline(stream, output)) {
        if (!completed) {
            if (output == "## complete")
                completed = true;
            continue;
        }
        if (output == "##")
            break;
        result += output + '\n';
    }
    return 0;
}

int runTest(int argc, char* argv[], std::string userStyle, std::string testFonts, std::string url, std::string& result)
{
    int pipefd[2];
    pipe(pipefd);

    pid_t pid = fork();
    if (pid == -1) {
        std::cerr << "error: no more process to create\n";
        return -1;
    }
    if (pid == 0) {
        close(1);
        dup(pipefd[1]);
        close(pipefd[0]);
        int argi = argc - 1;
        if (!userStyle.empty())
            argv[argi++] = strdup(userStyle.c_str());
        if (testFonts == "on")
            argv[argi++] ="-testfonts";
        url = "http://localhost:8000/" + url;
        // url = "http://test.csswg.org/suites/css2.1/20110323/" + url;
        argv[argi++] = strdup(url.c_str());
        argv[argi] = 0;
        execvp(argv[0], argv);
        exit(EXIT_FAILURE);
    }
    close(pipefd[1]);

#if 104400 <= BOOST_VERSION
    boost::iostreams::stream<boost::iostreams::file_descriptor_source> stream(pipefd[0], boost::iostreams::close_handle);
#else
    boost::iostreams::stream<boost::iostreams::file_descriptor_source> stream(pipefd[0], true);
#endif
    processOutput(stream, result);
    return pid;
}

void killTest(int pid)
{
    int status;
    kill(pid, SIGTERM);
    if (wait(&status) == -1)
        std::cerr << "error: failed to wait for a test process to complete\n";
}

bool loadLog(const std::string& path, std::string& result, std::string& log)
{
    std::ifstream file(path.c_str());
    if (!file) {
        result = "?";
        return false;
    }
    std::string line;
    std::getline(file, line);
    size_t pos = line.find('\t');
    if (pos != std::string::npos)
        result = line.substr(pos + 1);
    else {
        result = "?";
        return false;
    }
    log.clear();
    while (std::getline(file, line))
        log += line + '\n';
    return true;
}

bool saveLog(const std::string& path, const std::string& url, const std::string& result, const std::string& log)
{
    std::ofstream file(path.c_str(), std::ios_base::out | std::ios_base::trunc);
    if (!file) {
        std::cerr << "error: failed to open the report file\n";
        return false;
    }
    file << "# " << url.c_str() << '\t' << result << '\n' << log;
    file.flush();
    file.close();
    return true;
}

int main(int argc, char* argv[])
{
    int mode = HEADLESS;

    int argi = 1;
    while (*argv[argi] == '-') {
        switch (argv[argi][1]) {
        case 'i':
            mode = INTERACTIVE;
            break;
        case 'r':
            mode = REPORT;
            break;
        case 'u':
            mode = UPDATE;
            break;
        default:
            break;
        }
        ++argi;
    }

    if (argc < argi + 2) {
        std::cout << "usage: " << argv[0] << " [-i] report.data command [argument ...]\n";
        return EXIT_FAILURE;
    }

    std::ifstream data(argv[argi]);
    if (!data) {
        std::cerr << "error: " << argv[argi] << ": no such file\n";
        return EXIT_FAILURE;
    }

    std::ofstream report("report.data", std::ios_base::out | std::ios_base::trunc);
    if (!report) {
        std::cerr << "error: failed to open the report file\n";
        return EXIT_FAILURE;
    }

    char* args[argc - argi + 3];
    for (int i = 2; i < argc; ++i)
        args[i - 2] = argv[i + argi - 1];
    args[argc - argi] = args[argc - argi + 1] = args[argc - argi + 2] = 0;

    std::string result;
    std::string url;
    std::string undo;
    std::string userStyle;
    std::string testFonts;
    bool redo = false;
    while (data) {
        if (result == "undo") {
            std::swap(url, undo);
            redo = true;
        } else if (redo) {
            std::swap(url, undo);
            redo = false;
        } else {
            std::string line;
            std::getline(data, line);
            if (line.empty() || line == "testname    result  comment") {
                report << line << '\n';
                continue;
            }
            if (line[0] == '#') {
                if (line.compare(1, 9, "userstyle") == 0) {
                    if (10 < line.length()) {
                        std::stringstream s(line.substr(10), std::stringstream::in);
                        s >> userStyle;
                    } else
                        userStyle.clear();
                } else if (line.compare(1, 9, "testfonts") == 0) {
                    if (10 < line.length()) {
                        std::stringstream s(line.substr(10), std::stringstream::in);
                        s >> testFonts;
                    } else
                        testFonts.clear();
                }
                report << line << '\n';
                continue;
            }
            undo = url;
            std::stringstream s(line, std::stringstream::in);
            s >> url;
        }
        if (url.empty())
            continue;

        std::string path(url);
        size_t pos = path.rfind('.');
        if (pos != std::string::npos) {
            path.erase(pos);
            path += ".log";
        }
        std::string evaluation;
        std::string log;
        loadLog(path, evaluation, log);

        pid_t pid = -1;
        std::string output;
        switch (mode) {
        case REPORT:
            break;
        case UPDATE:
            if (evaluation[0] == '?')
                break;
            // FALL THROUGH
        default:
            pid = runTest(argc - argi, args, userStyle, testFonts, url, output);
            break;
        }

        if (0 < pid && output.empty())
            result = "fatal";
        else if (mode == INTERACTIVE) {
            std::cout << "## complete\n" << output;
            std::cout << '[' << url << "] ";
            if (evaluation.empty() || evaluation[0] == '?')
                std::cout << "pass? ";
            else {
                std::cout << evaluation << "? ";
                if (evaluation != "pass")
                    std::cout << '\a';
            }
            std::getline(std::cin, result);
            if (result.empty()) {
                if (evaluation.empty() || evaluation[0] == '?')
                    result = "pass";
                else
                    result = evaluation;
            } else if (result == "p" || result == "\x1b")
                result = "pass";
            else if (result == "f")
                result = "fail";
            else if (result == "i")
                result = "invalid";
            else if (result == "k") // keep
                result = evaluation;
            else if (result == "n")
                result = "na";
            else if (result == "s")
                result = "skip";
            else if (result == "u")
                result = "uncertain";
            else if (result == "q" || result == "quit")
                break;
            else if (result == "z")
                result = "undo";
            if (result != "undo" && !saveLog(path, url, result, output)) {
                std::cerr << "error: failed to open the report file\n";
                return EXIT_FAILURE;
            }
        } else if (mode == HEADLESS) {
            if (evaluation != "?" && output != log)
                result = "uncertain";
            else
                result = evaluation;
        } else if (mode == REPORT) {
            result = evaluation;
        } else if (mode == UPDATE) {
            result = evaluation;
            if (result[0] != '?') {
                if (!saveLog(path, url, result, output)) {
                    std::cerr << "error: failed to open the report file\n";
                    return EXIT_FAILURE;
                }
            }
        }

        if (0 < pid)
            killTest(pid);

        if (result != "undo")
            report << url << '\t' << result << '\n';
        if (mode != INTERACTIVE && result[0] != '?')
            std::cout << url << '\t' << result << '\n';
    }
    report.close();
}
<commit_msg>(harness) : Terminate the test process if it does not complete in 10 seconds.<commit_after>/*
 * Copyright 2011, 2012 Esrille Inc.
 *
 * 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.
 */

// A test harness for the implementation report of
//       the CSS2.1 Conformance Test Suite
// http://test.csswg.org/suites/css2.1/20110323/

#include <unistd.h>
#include <sys/wait.h>

#include <cstring>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>

#include <boost/version.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>

enum {
    INTERACTIVE,
    HEADLESS,
    REPORT,
    UPDATE
};

int processOutput(std::istream& stream, std::string& result)
{
    std::string output;
    bool completed = false;
    while (std::getline(stream, output)) {
        if (!completed) {
            if (output == "## complete")
                completed = true;
            continue;
        }
        if (output == "##")
            break;
        result += output + '\n';
    }
    return 0;
}

int runTest(int argc, char* argv[], std::string userStyle, std::string testFonts, std::string url, std::string& result)
{
    int pipefd[2];
    pipe(pipefd);

    pid_t pid = fork();
    if (pid == -1) {
        std::cerr << "error: no more process to create\n";
        return -1;
    }
    if (pid == 0) {
        close(1);
        dup(pipefd[1]);
        close(pipefd[0]);
        int argi = argc - 1;
        if (!userStyle.empty())
            argv[argi++] = strdup(userStyle.c_str());
        if (testFonts == "on")
            argv[argi++] ="-testfonts";
        url = "http://localhost:8000/" + url;
        // url = "http://test.csswg.org/suites/css2.1/20110323/" + url;
        argv[argi++] = strdup(url.c_str());
        argv[argi] = 0;
        alarm(10);  // Terminate the process if it does not complete in 10 seconds.
        execvp(argv[0], argv);
        exit(EXIT_FAILURE);
    }
    close(pipefd[1]);

#if 104400 <= BOOST_VERSION
    boost::iostreams::stream<boost::iostreams::file_descriptor_source> stream(pipefd[0], boost::iostreams::close_handle);
#else
    boost::iostreams::stream<boost::iostreams::file_descriptor_source> stream(pipefd[0], true);
#endif
    processOutput(stream, result);
    return pid;
}

void killTest(int pid)
{
    int status;
    kill(pid, SIGTERM);
    if (wait(&status) == -1)
        std::cerr << "error: failed to wait for a test process to complete\n";
}

bool loadLog(const std::string& path, std::string& result, std::string& log)
{
    std::ifstream file(path.c_str());
    if (!file) {
        result = "?";
        return false;
    }
    std::string line;
    std::getline(file, line);
    size_t pos = line.find('\t');
    if (pos != std::string::npos)
        result = line.substr(pos + 1);
    else {
        result = "?";
        return false;
    }
    log.clear();
    while (std::getline(file, line))
        log += line + '\n';
    return true;
}

bool saveLog(const std::string& path, const std::string& url, const std::string& result, const std::string& log)
{
    std::ofstream file(path.c_str(), std::ios_base::out | std::ios_base::trunc);
    if (!file) {
        std::cerr << "error: failed to open the report file\n";
        return false;
    }
    file << "# " << url.c_str() << '\t' << result << '\n' << log;
    file.flush();
    file.close();
    return true;
}

int main(int argc, char* argv[])
{
    int mode = HEADLESS;

    int argi = 1;
    while (*argv[argi] == '-') {
        switch (argv[argi][1]) {
        case 'i':
            mode = INTERACTIVE;
            break;
        case 'r':
            mode = REPORT;
            break;
        case 'u':
            mode = UPDATE;
            break;
        default:
            break;
        }
        ++argi;
    }

    if (argc < argi + 2) {
        std::cout << "usage: " << argv[0] << " [-i] report.data command [argument ...]\n";
        return EXIT_FAILURE;
    }

    std::ifstream data(argv[argi]);
    if (!data) {
        std::cerr << "error: " << argv[argi] << ": no such file\n";
        return EXIT_FAILURE;
    }

    std::ofstream report("report.data", std::ios_base::out | std::ios_base::trunc);
    if (!report) {
        std::cerr << "error: failed to open the report file\n";
        return EXIT_FAILURE;
    }

    char* args[argc - argi + 3];
    for (int i = 2; i < argc; ++i)
        args[i - 2] = argv[i + argi - 1];
    args[argc - argi] = args[argc - argi + 1] = args[argc - argi + 2] = 0;

    std::string result;
    std::string url;
    std::string undo;
    std::string userStyle;
    std::string testFonts;
    bool redo = false;
    while (data) {
        if (result == "undo") {
            std::swap(url, undo);
            redo = true;
        } else if (redo) {
            std::swap(url, undo);
            redo = false;
        } else {
            std::string line;
            std::getline(data, line);
            if (line.empty() || line == "testname    result  comment") {
                report << line << '\n';
                continue;
            }
            if (line[0] == '#') {
                if (line.compare(1, 9, "userstyle") == 0) {
                    if (10 < line.length()) {
                        std::stringstream s(line.substr(10), std::stringstream::in);
                        s >> userStyle;
                    } else
                        userStyle.clear();
                } else if (line.compare(1, 9, "testfonts") == 0) {
                    if (10 < line.length()) {
                        std::stringstream s(line.substr(10), std::stringstream::in);
                        s >> testFonts;
                    } else
                        testFonts.clear();
                }
                report << line << '\n';
                continue;
            }
            undo = url;
            std::stringstream s(line, std::stringstream::in);
            s >> url;
        }
        if (url.empty())
            continue;

        std::string path(url);
        size_t pos = path.rfind('.');
        if (pos != std::string::npos) {
            path.erase(pos);
            path += ".log";
        }
        std::string evaluation;
        std::string log;
        loadLog(path, evaluation, log);

        pid_t pid = -1;
        std::string output;
        switch (mode) {
        case REPORT:
            break;
        case UPDATE:
            if (evaluation[0] == '?')
                break;
            // FALL THROUGH
        default:
            pid = runTest(argc - argi, args, userStyle, testFonts, url, output);
            break;
        }

        if (0 < pid && output.empty())
            result = "fatal";
        else if (mode == INTERACTIVE) {
            std::cout << "## complete\n" << output;
            std::cout << '[' << url << "] ";
            if (evaluation.empty() || evaluation[0] == '?')
                std::cout << "pass? ";
            else {
                std::cout << evaluation << "? ";
                if (evaluation != "pass")
                    std::cout << '\a';
            }
            std::getline(std::cin, result);
            if (result.empty()) {
                if (evaluation.empty() || evaluation[0] == '?')
                    result = "pass";
                else
                    result = evaluation;
            } else if (result == "p" || result == "\x1b")
                result = "pass";
            else if (result == "f")
                result = "fail";
            else if (result == "i")
                result = "invalid";
            else if (result == "k") // keep
                result = evaluation;
            else if (result == "n")
                result = "na";
            else if (result == "s")
                result = "skip";
            else if (result == "u")
                result = "uncertain";
            else if (result == "q" || result == "quit")
                break;
            else if (result == "z")
                result = "undo";
            if (result != "undo" && !saveLog(path, url, result, output)) {
                std::cerr << "error: failed to open the report file\n";
                return EXIT_FAILURE;
            }
        } else if (mode == HEADLESS) {
            if (evaluation != "?" && output != log)
                result = "uncertain";
            else
                result = evaluation;
        } else if (mode == REPORT) {
            result = evaluation;
        } else if (mode == UPDATE) {
            result = evaluation;
            if (result[0] != '?') {
                if (!saveLog(path, url, result, output)) {
                    std::cerr << "error: failed to open the report file\n";
                    return EXIT_FAILURE;
                }
            }
        }

        if (0 < pid)
            killTest(pid);

        if (result != "undo")
            report << url << '\t' << result << '\n';
        if (mode != INTERACTIVE && result[0] != '?')
            std::cout << url << '\t' << result << '\n';
    }
    report.close();
}
<|endoftext|>


<commit_before>/** @file
    @brief Implementation

    @date 2015

    @author
    Sensics, Inc.
    <http://sensics.com/osvr>
*/

// Copyright 2015 Sensics, Inc.
//
// 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.

// Internal Includes
#include <osvr/PluginHost/SearchPath.h>
#include <osvr/PluginHost/PathConfig.h>
#include "BinaryLocation.h"
#include <osvr/Util/Verbosity.h>

// Library/third-party includes
#include <boost/filesystem.hpp>
#include <boost/range/iterator_range.hpp>

// Standard includes
#include <vector>
#include <string>
#include <algorithm>

namespace osvr {
namespace pluginhost {

    using boost::filesystem::directory_iterator;
    using boost::make_iterator_range;
    namespace fs = boost::filesystem;

    SearchPath getPluginSearchPath() {
        auto exeLocation = fs::path{getBinaryLocation()};
#ifdef __ANDROID__
        OSVR_DEV_VERBOSE("Binary location: " << exeLocation);
#endif
        // Should be something like PREFIX/bin or PREFIX/bin/Release (depending
        // on if we're installed or in a build tree)
        auto binDir = exeLocation.parent_path();

#if defined(_MSC_VER) && defined(CMAKE_INTDIR)
        /// CMAKE_INTDIR is a string like "Debug", defined automatically if
        /// building in some multi-config generator mode of using the MSVC
        /// compiler (the IDE or MSBuild on a solution).
        /// Not defined in makefiles (nmake, jom, ninja), though, hence why we
        /// have to check both definitions.
        if (binDir.filename() == CMAKE_INTDIR) {
            binDir = binDir.parent_path();
        }
#endif

        // binDir now normalized to PREFIX/bin

        /// This will become our return value.
        SearchPath paths;

        // Lambda to add a path, if it's not already in the list.
        auto addUniquePath = [&paths](fs::path const &path) {
            OSVR_DEV_VERBOSE("Adding search path " << path);
            auto pathString = path.generic_string();
            if (std::find(begin(paths), end(paths), pathString) == end(paths)) {
                // if we didn't already add this path, add it now.
                paths.emplace_back(std::move(pathString));
            }
        };

#ifdef OSVR_PLUGINS_UNDER_BINDIR
        // If the plugin directory is a subdirectory of where the binaries are,
        // no need to go up a level before searching.
        addUniquePath(binDir / OSVR_PLUGIN_SUBDIR);
#endif

        // For each component of the compiled-in binary directory, we lop off a
        // component from the binary location we've detected, and add it to the
        // list of possible roots.
        auto root = binDir.parent_path();
        std::vector<fs::path> rootDirCandidates;
        {
            auto compiledBinDir = fs::path{OSVR_BINDIR};
            do {
                rootDirCandidates.push_back(root);
                root = root.parent_path();
                compiledBinDir = compiledBinDir.parent_path();
            } while (!compiledBinDir.empty() && !root.empty());
        }

#ifdef __ANDROID__
        // current working directory, if different from root
        auto currentWorkingDirectory = boost::filesystem::current_path();
        if (currentWorkingDirectory != root) {
            addUniquePath(currentWorkingDirectory / OSVR_PLUGIN_DIR);
        }
#endif

        for (auto const &possibleRoot : rootDirCandidates) {

#if defined(_MSC_VER) && defined(CMAKE_INTDIR)
            addUniquePath(possibleRoot / OSVR_PLUGIN_DIR / CMAKE_INTDIR);
#endif
            addUniquePath(possibleRoot / OSVR_PLUGIN_DIR);
        }

        /// @todo add user's home directory to search path

        return paths;
    }

    FileList getAllFilesWithExt(SearchPath const& dirPath, const std::string &ext) {
        FileList filesPaths;

        for (const auto &path : dirPath) {
            fs::path directoryPath(path);

            // Make sure that directory exists
            if (!fs::exists(directoryPath)) {
                continue;
            }

            // Get a list of files inside the dir that match the extension
            for (const auto &pathName : make_iterator_range(
                     directory_iterator(directoryPath), directory_iterator())) {
                if (!fs::is_regular_file(pathName) ||
                    pathName.path().extension() != ext) {
                    continue;
                }

                filesPaths.push_back(pathName.path().generic_string());
            }
        }

        return filesPaths;
    }

    std::string findPlugin(SearchPath const &searchPaths, const std::string &pluginName) {
        for (const auto &searchPath : searchPaths) {
            if (!fs::exists(searchPath)) {
                continue;
            }

            for (const auto &pluginPathName : make_iterator_range(
                     directory_iterator(searchPath), directory_iterator())) {
                /// Must be a regular file
                /// @todo does this mean symlinks get excluded?
                if (!fs::is_regular_file(pluginPathName)) {
                    continue;
                }

                const auto pluginCandidate = fs::path(pluginPathName);

                /// Needs right extension
                if (pluginCandidate.extension().generic_string() !=
                    OSVR_PLUGIN_EXTENSION) {
                    continue;
                }
                const auto pluginBaseName =
                    pluginCandidate.filename().stem().generic_string();
                /// If the name is right or has the manual load suffix, this is
                /// a good one.
                if ((pluginBaseName == pluginName) ||
                    (pluginBaseName ==
                     pluginName + OSVR_PLUGIN_IGNORE_SUFFIX)) {
                    return pluginPathName.path().generic_string();
                }
            }
        }

        return std::string();
    }

} // namespace pluginhost
} // namespace osvr
<commit_msg>Comment out a verbose message<commit_after>/** @file
    @brief Implementation

    @date 2015

    @author
    Sensics, Inc.
    <http://sensics.com/osvr>
*/

// Copyright 2015 Sensics, Inc.
//
// 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.

// Internal Includes
#include <osvr/PluginHost/SearchPath.h>
#include <osvr/PluginHost/PathConfig.h>
#include "BinaryLocation.h"
#include <osvr/Util/Verbosity.h>

// Library/third-party includes
#include <boost/filesystem.hpp>
#include <boost/range/iterator_range.hpp>

// Standard includes
#include <vector>
#include <string>
#include <algorithm>

namespace osvr {
namespace pluginhost {

    using boost::filesystem::directory_iterator;
    using boost::make_iterator_range;
    namespace fs = boost::filesystem;

    SearchPath getPluginSearchPath() {
        auto exeLocation = fs::path{getBinaryLocation()};
#ifdef __ANDROID__
        OSVR_DEV_VERBOSE("Binary location: " << exeLocation);
#endif
        // Should be something like PREFIX/bin or PREFIX/bin/Release (depending
        // on if we're installed or in a build tree)
        auto binDir = exeLocation.parent_path();

#if defined(_MSC_VER) && defined(CMAKE_INTDIR)
        /// CMAKE_INTDIR is a string like "Debug", defined automatically if
        /// building in some multi-config generator mode of using the MSVC
        /// compiler (the IDE or MSBuild on a solution).
        /// Not defined in makefiles (nmake, jom, ninja), though, hence why we
        /// have to check both definitions.
        if (binDir.filename() == CMAKE_INTDIR) {
            binDir = binDir.parent_path();
        }
#endif

        // binDir now normalized to PREFIX/bin

        /// This will become our return value.
        SearchPath paths;

        // Lambda to add a path, if it's not already in the list.
        auto addUniquePath = [&paths](fs::path const &path) {
            //OSVR_DEV_VERBOSE("Adding search path " << path);
            auto pathString = path.generic_string();
            if (std::find(begin(paths), end(paths), pathString) == end(paths)) {
                // if we didn't already add this path, add it now.
                paths.emplace_back(std::move(pathString));
            }
        };

#ifdef OSVR_PLUGINS_UNDER_BINDIR
        // If the plugin directory is a subdirectory of where the binaries are,
        // no need to go up a level before searching.
        addUniquePath(binDir / OSVR_PLUGIN_SUBDIR);
#endif

        // For each component of the compiled-in binary directory, we lop off a
        // component from the binary location we've detected, and add it to the
        // list of possible roots.
        auto root = binDir.parent_path();
        std::vector<fs::path> rootDirCandidates;
        {
            auto compiledBinDir = fs::path{OSVR_BINDIR};
            do {
                rootDirCandidates.push_back(root);
                root = root.parent_path();
                compiledBinDir = compiledBinDir.parent_path();
            } while (!compiledBinDir.empty() && !root.empty());
        }

#ifdef __ANDROID__
        // current working directory, if different from root
        auto currentWorkingDirectory = boost::filesystem::current_path();
        if (currentWorkingDirectory != root) {
            addUniquePath(currentWorkingDirectory / OSVR_PLUGIN_DIR);
        }
#endif

        for (auto const &possibleRoot : rootDirCandidates) {

#if defined(_MSC_VER) && defined(CMAKE_INTDIR)
            addUniquePath(possibleRoot / OSVR_PLUGIN_DIR / CMAKE_INTDIR);
#endif
            addUniquePath(possibleRoot / OSVR_PLUGIN_DIR);
        }

        /// @todo add user's home directory to search path

        return paths;
    }

    FileList getAllFilesWithExt(SearchPath const& dirPath, const std::string &ext) {
        FileList filesPaths;

        for (const auto &path : dirPath) {
            fs::path directoryPath(path);

            // Make sure that directory exists
            if (!fs::exists(directoryPath)) {
                continue;
            }

            // Get a list of files inside the dir that match the extension
            for (const auto &pathName : make_iterator_range(
                     directory_iterator(directoryPath), directory_iterator())) {
                if (!fs::is_regular_file(pathName) ||
                    pathName.path().extension() != ext) {
                    continue;
                }

                filesPaths.push_back(pathName.path().generic_string());
            }
        }

        return filesPaths;
    }

    std::string findPlugin(SearchPath const &searchPaths, const std::string &pluginName) {
        for (const auto &searchPath : searchPaths) {
            if (!fs::exists(searchPath)) {
                continue;
            }

            for (const auto &pluginPathName : make_iterator_range(
                     directory_iterator(searchPath), directory_iterator())) {
                /// Must be a regular file
                /// @todo does this mean symlinks get excluded?
                if (!fs::is_regular_file(pluginPathName)) {
                    continue;
                }

                const auto pluginCandidate = fs::path(pluginPathName);

                /// Needs right extension
                if (pluginCandidate.extension().generic_string() !=
                    OSVR_PLUGIN_EXTENSION) {
                    continue;
                }
                const auto pluginBaseName =
                    pluginCandidate.filename().stem().generic_string();
                /// If the name is right or has the manual load suffix, this is
                /// a good one.
                if ((pluginBaseName == pluginName) ||
                    (pluginBaseName ==
                     pluginName + OSVR_PLUGIN_IGNORE_SUFFIX)) {
                    return pluginPathName.path().generic_string();
                }
            }
        }

        return std::string();
    }

} // namespace pluginhost
} // namespace osvr
<|endoftext|>


<commit_before>// Copyright(c) 2016 Jounayd Id Salah
// Distributed under the MIT License (See accompanying file LICENSE.md file or copy at http://opensource.org/licenses/MIT).
#include "neural/pch.h"
#include "neural/process/training/coNeuralTrainingNet_f.h"
#include "neural/process/training/coNeuralTrainingNet.h"
#include "neural/process/training/coNeuralTrainingLayer.h"
#include "neural/process/training/coNeuralDataSet.h"
#include "neural/process/coNeuralLayer_f.h"
#include "neural/process/coNeuralNet_f.h"
#include "neural/process/coNeuralActivation_f.h"
#include "neural/network/coNeuralNet.h"
#include "neural/network/coNeuralLayer.h"
#include "lang/result/coResult_f.h"

void coComputeForwardPass(coNeuralTrainingNet& _trainingNet, const coArray<coFloat>& _targetInputs)
{
	coArray<coFloat> inputs = _targetInputs;
	for (coNeuralTrainingLayer* trainingLayer : _trainingNet.GetTrainingLayers())
	{
		coComputeOutputs(*trainingLayer->layer, inputs, trainingLayer->outputs);
		inputs = trainingLayer->outputs;
	}
}

void coComputeGradients(coNeuralTrainingNet& _trainingNet, const coArray<coFloat>& _targetOutputs)
{
	const coArray<coNeuralTrainingLayer*>& trainingLayers = _trainingNet.GetTrainingLayers();

	// Last layer
	{
		coNeuralTrainingLayer* trainingLayer = coBack(trainingLayers);
		const coUint nbOutputs = trainingLayer->outputs.count;
		coArray<coFloat>& gradients = trainingLayer->gradients;
		const coArray<coFloat>& values = trainingLayer->outputs;
		for (coUint i = 0; i < nbOutputs; ++i)
		{
			const coFloat value = values[i];
			const coFloat targetValue = _targetOutputs[i];
			const coFloat error = targetValue - value;
			gradients[i] = error * coComputeNeuralActivationDerivativeTransfer(value);
		}
	}

	// Rest of the layers
	for (coInt j = trainingLayers.count - 2; j >= 0; --j)
	{
		coNeuralTrainingLayer* curTrainingLayer = trainingLayers[j];
		coNeuralTrainingLayer* nextTrainingLayer = trainingLayers[j + 1];
		coArray<coFloat>& curGradients = curTrainingLayer->gradients;
		const coArray<coFloat>& nextGradients = nextTrainingLayer->gradients;
		const coArray<coFloat>& curOutputs = curTrainingLayer->outputs;

		const coNeuralLayer* curData = curTrainingLayer->layer;
		const coNeuralLayer* nextData = nextTrainingLayer->layer;
		const coArray<coFloat>& nextWeights = nextData->GetWeightBuffer();
		const coUint nbCurOutputs = curData->GetNbOutputs();
		const coUint nbNextOutputs = nextData->GetNbOutputs();
		for (coUint k = 0; k < nbCurOutputs; ++k)
		{
			coFloat sum = 0.0f;
			for (coUint l = 0; l < nbNextOutputs; ++l)
			{
				const coUint weightIndex = l * nbCurOutputs + k;
				sum += nextGradients.data[l] * nextWeights.data[weightIndex];
			}
			const coFloat output = curOutputs.data[k];
			curGradients.data[k] = sum * coComputeNeuralActivationDerivativeTransfer(output);
		}
	}
}

void coUpdateWeights(coNeuralTrainingNet& _trainingNet, coFloat _learnRate, coFloat _momentum, const coArray<coFloat>& _inputs)
{
	const coArray<coNeuralTrainingLayer*>& trainingLayers = _trainingNet.GetTrainingLayers();
	coArray<coFloat> layerInputs(_inputs);
	for (coNeuralTrainingLayer* trainingLayer : trainingLayers)
	{
		coNeuralLayer* data = trainingLayer->layer;
		const coUint nbInputs = data->GetNbInputs();
		const coUint nbOutputs = data->GetNbOutputs();
		coArray<coFloat>& biasBuffer = data->GetBiasBuffer();
		coArray<coFloat>& weightBuffer = data->GetWeightBuffer();
		coArray<coFloat>& biasDeltas = trainingLayer->biasDeltas;
		coArray<coFloat>& weightDeltas = trainingLayer->weightDeltas;
		const coArray<coFloat>& gradients = trainingLayer->gradients;

		const coFloat decay = 0.0f;//0.000001f;

		coUint weightIndex = 0;
		for (coUint k = 0; k < nbOutputs; ++k)
		{
			const coFloat gradient = gradients.data[k];

			// Biases
			{
				coFloat& curBias = biasBuffer.data[k];
				coFloat& curDelta = biasDeltas.data[k];
				curDelta = _learnRate * gradient + _momentum * curDelta - decay * curBias;
				curBias += curDelta;
			}

			// Weights
			for (coUint l = 0; l < nbInputs; ++l)
			{
				coFloat& curWeight = weightBuffer.data[weightIndex];
				coFloat& curDelta = weightDeltas.data[weightIndex];
				curDelta = _learnRate * gradient * layerInputs.data[l] + _momentum * curDelta - decay * curWeight;
				curWeight += curDelta;
				++weightIndex;
			}
		}

		layerInputs = trainingLayer->outputs;
	}
}

coFloat coComputeErrors(const coNeuralTrainingNet& _trainingNet, const coArray<coFloat>& _targetOutputs)
{
	coFloat error = 0.0f;
	const coArray<coNeuralTrainingLayer*>& trainingLayers = _trainingNet.GetTrainingLayers();
	coNeuralTrainingLayer* lastTrainingLayer = coBack(trainingLayers);
	const coArray<coFloat>& outputs = lastTrainingLayer->outputs;
	coASSERT(outputs.count == _targetOutputs.count);
	const coUint nbOutputs = lastTrainingLayer->outputs.count;
	for (coUint i = 0; i < nbOutputs; ++i)
	{
		error += coPow2(_targetOutputs[i] - outputs[i]);
	}
	return error;
}

coResult coTrain(coNeuralTrainingNet& _trainingNet, const coNeuralDataSet& _dataSet, coFloat _targetError, coUint _nbMaxEpochs)
{
	// References:
	// - "On Large-Batch Training for Deep Learning: Generalization Gap and Sharp Minima" (arXiv:1609.04836).

	coTRY(_targetError >= 0.0f, nullptr);

	const coFloat meanSquareErrorTarget = coPow2(_targetError);

	const coFloat learnRate = 0.4f;
	const coFloat momentum = 0.9f;

	//coTRY(learnRate < 1.0f, nullptr);

	coNeuralNet* net = _trainingNet.GetNet();
	coTRY(net, nullptr);

	const coUint nbNetInputs = net->GetNbInputs();
	const coUint nbNetOutputs = net->GetNbOutputs();

	coDynamicArray<coUint> sampleIndices;
	coResize(sampleIndices, _dataSet.nbSamples);
	for (coUint i = 0; i < sampleIndices.count; ++i)
		sampleIndices[i] = i;

	coUint32 seed = 77777777;

#ifdef coDEBUG
	coDynamicArray<coFloat> errors;
	coReserve(errors, _dataSet.nbSamples);
#endif

	// For each epoch
	coFloat err;
	coUint nbEpochs = 0;
	do
	{
		coShuffle(sampleIndices, seed);

		const coUint32 nbTrainingSamples = _dataSet.nbSamples * 60 / 100;
		const coUint32 nbValidationSamples = _dataSet.nbSamples - nbTrainingSamples;

		// For each sample
		for (coUint i = 0; i < nbTrainingSamples; ++i)
		{
			const coUint sampleIndex = sampleIndices[i];
			const coArray<coFloat> sampleInputs(_dataSet.inputs.data + sampleIndex * nbNetInputs, nbNetInputs);
			const coArray<coFloat> sampleOutputs(_dataSet.outputs.data + sampleIndex * nbNetOutputs, nbNetOutputs);
			coComputeForwardPass(_trainingNet, sampleInputs);
			coComputeGradients(_trainingNet, sampleOutputs);
			coUpdateWeights(_trainingNet, learnRate, momentum, sampleInputs);
		}

		// Error
		{
			err = 0.0f;
			for (coUint i = nbTrainingSamples; i < _dataSet.nbSamples; ++i)
			{
				const coUint sampleIndex = sampleIndices[i];
				const coArray<coFloat> sampleInputs(_dataSet.inputs.data + sampleIndex * nbNetInputs, nbNetInputs);
				const coArray<coFloat> sampleOutputs(_dataSet.outputs.data + sampleIndex * nbNetOutputs, nbNetOutputs);
				coComputeForwardPass(_trainingNet, sampleInputs);
				err += coComputeErrors(_trainingNet, sampleOutputs);
			}

			coASSERT(nbValidationSamples);
			err /= coFloat(nbValidationSamples);
			err *= 0.5f;

#ifdef coDEBUG
			coPushBack(errors, err);
#endif
		}

		++nbEpochs;
	} while (err > meanSquareErrorTarget && nbEpochs < _nbMaxEpochs);

	return true;
}
<commit_msg>sdfsdf<commit_after>// Copyright(c) 2016 Jounayd Id Salah
// Distributed under the MIT License (See accompanying file LICENSE.md file or copy at http://opensource.org/licenses/MIT).
#include "neural/pch.h"
#include "neural/process/training/coNeuralTrainingNet_f.h"
#include "neural/process/training/coNeuralTrainingNet.h"
#include "neural/process/training/coNeuralTrainingLayer.h"
#include "neural/process/training/coNeuralDataSet.h"
#include "neural/process/coNeuralLayer_f.h"
#include "neural/process/coNeuralNet_f.h"
#include "neural/process/coNeuralActivation_f.h"
#include "neural/network/coNeuralNet.h"
#include "neural/network/coNeuralLayer.h"
#include "lang/result/coResult_f.h"

void coComputeForwardPass(coNeuralTrainingNet& _trainingNet, const coArray<coFloat>& _targetInputs)
{
	coArray<coFloat> inputs = _targetInputs;
	for (coNeuralTrainingLayer* trainingLayer : _trainingNet.GetTrainingLayers())
	{
		coComputeOutputs(*trainingLayer->layer, inputs, trainingLayer->outputs);
		inputs = trainingLayer->outputs;
	}
}

void coComputeGradients(coNeuralTrainingNet& _trainingNet, const coArray<coFloat>& _targetOutputs)
{
	const coArray<coNeuralTrainingLayer*>& trainingLayers = _trainingNet.GetTrainingLayers();

	// Last layer
	{
		coNeuralTrainingLayer* trainingLayer = coBack(trainingLayers);
		const coUint nbOutputs = trainingLayer->outputs.count;
		coArray<coFloat>& gradients = trainingLayer->gradients;
		const coArray<coFloat>& values = trainingLayer->outputs;
		for (coUint i = 0; i < nbOutputs; ++i)
		{
			const coFloat value = values[i];
			const coFloat targetValue = _targetOutputs[i];
			const coFloat error = targetValue - value;
			gradients[i] = error * coComputeNeuralActivationDerivativeTransfer(value);
		}
	}

	// Rest of the layers
	for (coInt j = trainingLayers.count - 2; j >= 0; --j)
	{
		coNeuralTrainingLayer* curTrainingLayer = trainingLayers[j];
		coNeuralTrainingLayer* nextTrainingLayer = trainingLayers[j + 1];
		coArray<coFloat>& curGradients = curTrainingLayer->gradients;
		const coArray<coFloat>& nextGradients = nextTrainingLayer->gradients;
		const coArray<coFloat>& curOutputs = curTrainingLayer->outputs;

		const coNeuralLayer* curData = curTrainingLayer->layer;
		const coNeuralLayer* nextData = nextTrainingLayer->layer;
		const coArray<coFloat>& nextWeights = nextData->GetWeightBuffer();
		const coUint nbCurOutputs = curData->GetNbOutputs();
		const coUint nbNextOutputs = nextData->GetNbOutputs();
		for (coUint k = 0; k < nbCurOutputs; ++k)
		{
			coFloat sum = 0.0f;
			for (coUint l = 0; l < nbNextOutputs; ++l)
			{
				const coUint weightIndex = l * nbCurOutputs + k;
				sum += nextGradients.data[l] * nextWeights.data[weightIndex];
			}
			const coFloat output = curOutputs.data[k];
			curGradients.data[k] = sum * coComputeNeuralActivationDerivativeTransfer(output);
		}
	}
}

void coUpdateWeights(coNeuralTrainingNet& _trainingNet, coFloat _learnRate, coFloat _momentum, const coArray<coFloat>& _inputs)
{
	const coArray<coNeuralTrainingLayer*>& trainingLayers = _trainingNet.GetTrainingLayers();
	coArray<coFloat> layerInputs(_inputs);
	for (coNeuralTrainingLayer* trainingLayer : trainingLayers)
	{
		coNeuralLayer* data = trainingLayer->layer;
		const coUint nbInputs = data->GetNbInputs();
		const coUint nbOutputs = data->GetNbOutputs();
		coArray<coFloat>& biasBuffer = data->GetBiasBuffer();
		coArray<coFloat>& weightBuffer = data->GetWeightBuffer();
		coArray<coFloat>& biasDeltas = trainingLayer->biasDeltas;
		coArray<coFloat>& weightDeltas = trainingLayer->weightDeltas;
		const coArray<coFloat>& gradients = trainingLayer->gradients;

		const coFloat decay = 0.0f;//0.000001f;

		coUint weightIndex = 0;
		for (coUint k = 0; k < nbOutputs; ++k)
		{
			const coFloat gradient = gradients.data[k];

			// Biases
			{
				coFloat& curBias = biasBuffer.data[k];
				coFloat& curDelta = biasDeltas.data[k];
				curDelta = _learnRate * gradient + _momentum * curDelta - decay * curBias;
				curBias += curDelta;
			}

			// Weights
			for (coUint l = 0; l < nbInputs; ++l)
			{
				coFloat& curWeight = weightBuffer.data[weightIndex];
				coFloat& curDelta = weightDeltas.data[weightIndex];
				curDelta = _learnRate * gradient * layerInputs.data[l] + _momentum * curDelta - decay * curWeight;
				curWeight += curDelta;
				++weightIndex;
			}
		}

		layerInputs = trainingLayer->outputs;
	}
}

coFloat coComputeErrors(const coNeuralTrainingNet& _trainingNet, const coArray<coFloat>& _targetOutputs)
{
	coFloat error = 0.0f;
	const coArray<coNeuralTrainingLayer*>& trainingLayers = _trainingNet.GetTrainingLayers();
	coNeuralTrainingLayer* lastTrainingLayer = coBack(trainingLayers);
	const coArray<coFloat>& outputs = lastTrainingLayer->outputs;
	coASSERT(outputs.count == _targetOutputs.count);
	const coUint nbOutputs = lastTrainingLayer->outputs.count;
	for (coUint i = 0; i < nbOutputs; ++i)
	{
		error += coPow2(_targetOutputs[i] - outputs[i]);
	}
	return error;
}

coResult coTrain(coNeuralTrainingNet& _trainingNet, const coNeuralDataSet& _dataSet, coFloat _targetError, coUint _nbMaxEpochs)
{
	// References:
	// - "On Large-Batch Training for Deep Learning: Generalization Gap and Sharp Minima" (arXiv:1609.04836).

	coTRY(_targetError >= 0.0f, nullptr);

	const coFloat meanSquareErrorTarget = coPow2(_targetError);

	const coFloat learnRate = 0.3f;
	const coFloat momentum = 0.9f;
	const coFloat trainingSamplesRatio = 0.6f;

	//coTRY(learnRate < 1.0f, nullptr);

	coNeuralNet* net = _trainingNet.GetNet();
	coTRY(net, nullptr);

	const coUint nbNetInputs = net->GetNbInputs();
	const coUint nbNetOutputs = net->GetNbOutputs();

	coDynamicArray<coUint> sampleIndices;
	coResize(sampleIndices, _dataSet.nbSamples);
	for (coUint i = 0; i < sampleIndices.count; ++i)
		sampleIndices[i] = i;

	coUint32 seed = 77777777;

#ifdef coDEBUG
	coDynamicArray<coFloat> errors;
	coReserve(errors, _dataSet.nbSamples);
#endif

	// For each epoch
	coFloat err;
	coUint nbEpochs = 0;
	do
	{
		coShuffle(sampleIndices, seed);

		const coUint32 nbTrainingSamples = coUint32(trainingSamplesRatio * _dataSet.nbSamples);
		const coUint32 nbValidationSamples = _dataSet.nbSamples - nbTrainingSamples;

		// For each sample
		for (coUint i = 0; i < nbTrainingSamples; ++i)
		{
			const coUint sampleIndex = sampleIndices[i];
			const coArray<coFloat> sampleInputs(_dataSet.inputs.data + sampleIndex * nbNetInputs, nbNetInputs);
			const coArray<coFloat> sampleOutputs(_dataSet.outputs.data + sampleIndex * nbNetOutputs, nbNetOutputs);
			coComputeForwardPass(_trainingNet, sampleInputs);
			coComputeGradients(_trainingNet, sampleOutputs);
			coUpdateWeights(_trainingNet, learnRate, momentum, sampleInputs);
		}

		// Error
		{
			err = 0.0f;
			for (coUint i = nbTrainingSamples; i < _dataSet.nbSamples; ++i)
			{
				const coUint sampleIndex = sampleIndices[i];
				const coArray<coFloat> sampleInputs(_dataSet.inputs.data + sampleIndex * nbNetInputs, nbNetInputs);
				const coArray<coFloat> sampleOutputs(_dataSet.outputs.data + sampleIndex * nbNetOutputs, nbNetOutputs);
				coComputeForwardPass(_trainingNet, sampleInputs);
				err += coComputeErrors(_trainingNet, sampleOutputs);
			}

			coASSERT(nbValidationSamples);
			err /= coFloat(nbValidationSamples);
			err *= 0.5f;

#ifdef coDEBUG
			coPushBack(errors, err);
#endif
		}

		++nbEpochs;
	} while (err > meanSquareErrorTarget && nbEpochs < _nbMaxEpochs);

	return true;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <windows.h>
#include <string>
#include <fstream>
#include <conio.h>
#include <Shlwapi.h>
#include <stdlib.h>
#include <algorithm>
#include "General.h"
#include "../Progresscounter/Progress.h"
#include "Path.h"
#pragma comment(lib, "shlwapi.lib")

#ifdef DEBUG
	#define VERSION "1.33d"
#endif
#ifdef RELEASE
	#define VERSION "1.33r"
#endif

using namespace std;

void RestoreTree(string filePath);

int main()
{
	// Initializing console.
	string input = "";
	string command = "";
	PrepareConsole("Tree", VERSION, "Please name the file which should be source of the tree.\nType \"help\" for further information.");

	// Loop waits for correct input.
	while (true)
	{
		Color(INPUT_COLOR);
		cout << "Tree.exe> ";
		getline(cin, input, '\n');
		command = ToLower(GetWord(input, 1));
		Color(OUTPUT_COLOR);

		// Parsing.
		if (command == "exit" || command == "quit")
		{
			// Leaving program when "exit" or "quit" has been typed.
			return(EXIT_SUCCESS);
		}
		else if (command == "help")
		{
			// Shows a description of all available commands.
			cout << "   Available Commands:" << endl;
			cout << "   help\t\tShows this page" << endl;
			cout << "   info\t\tGeneral information" << endl;
			cout << "   clear/cls\tClears the Screen" << endl;
			cout << "   exit\t\tTerminates the program" << endl << endl;
			cout << "   Enter any other string to designate the file containing the tree." << endl;
			cout << "   The program will create the listed files and directories," << endl;
			cout << "   until you press 'q' or the file reaches its end." << endl << endl;
		}
		else if (command == "info")
		{
			// Shows general info about the software.
			cout << "   Tree Version " << VERSION << endl;
			cout << "   Compiled: " << __DATE__ << ", " << __TIME__ << endl;
			cout << "   (c) 2012 - 2015 Julian Heinzel" << endl << endl;
		}
		else if (command == "clear" || command == "cls")
		{
			// Resets the terminal.
			PrepareConsole("Tree", VERSION, "Please name the file which should be source of the tree.\nType \"help\" for further information.");
		}
		else if (!PathFileExists(input.c_str()))
		{
			// Printing an error, if no command and no valid path has been typed.
			cout << "   Did not find file \"" + input + "\"." << endl << endl;
		}
		else
		{
			RestoreTree(input);
		}
	}
	return(EXIT_SUCCESS);
}

// Restores the directory and file structure.
void RestoreTree(string filePath)
{
	string		line;
	ifstream	fileIn;
	Progress	progressBar;
	Path		path;

	// Counting the total number of lines in the specified textfile.
	int numberOfLines = 0;
	cout << "   File found, counting lines..." << endl;
	fileIn.open(filePath);
	while (getline(fileIn, line))
	{
		numberOfLines += 1;
	}
	progressBar.Reset(numberOfLines, 3);

	// Opening file and skipping the first three lines.
	cout << "   Processing " << numberOfLines << " lines of text." << endl << "   ";
	fileIn.close();
	fileIn.open(filePath);
	for (int i = 0; i < 3; i++) getline(fileIn, line);

	// Get the filename, replace '.' by '_', set the resulting string as root folder.
	string fileName = GetFileName(filePath);
	replace(fileName.begin(), fileName.end(), '.', '_');
	path.AddLevel(fileName);
	CreateDirectory(path.GetLevel(0).c_str(), 0);

	// Loops through every line in the file.
	while (getline(fileIn, line))
	{
		bool	readingName = false;
		int		level = 0;
		int		length = strlen(line.c_str());
		int		indention = 0;
		string	newName = "";

		// Update the terminal, quit on 'q' and 'e'
		progressBar.Increment();
		progressBar.Print();
		if (_kbhit())
		{
			char C = _getch();
			if (C == 'q' || C == 'e')
			{
				cout << endl << "   Program canceled. Processed "
					<< progressBar.GetCounter() << " of " << progressBar.GetMaxElements()
					<< " lines. (" << progressBar.GetString() << ")" << endl << endl;
				return;
			}
		}

		if (length == 0)
		{
			break;
		}

		// Extract directory/file name from line.
		for (int i = 0; i < length; i++)
		{
			char c = line[i];
			if ((c != ' ') && (c != '-') && (c != '\\') && (c != '|') && (c != '+') && (readingName == false))
			{
				readingName = true;
			}

			if (readingName == true)
			{
				newName += c;
			}
			else
			{
				indention++;
			}
		}
		level = (indention / 4);

		// If there is no valid file or directory name, the next line is beeing evaluated.
		if (newName == "")
		{
			continue;
		}

		// If there is a '+' or a '\' in the given line, the name will be interpreted as a directory.
		// The new path is saved and the directory created.
		path.RemoveLevels(level, path.Depth());
		path.AddLevel(newName);
		if ((line.find('+') != -1) || (line.find("\\") != -1))
		{
			CreateDirectory(path.GetPath().c_str(), 0);
		}
		else
		{
			// Otherwise a file is listed, which will then be created.
			ofstream fileOut;
			fileOut.open(path.GetPath());
			fileOut.close();
		}
	}

	if (progressBar.GetPercent() == 100)
	{
		// Info if the file has been successfully processed.
		cout << endl << "   Generated files from \"" + filePath + "\" succesfully." << endl << endl;
	}
}<commit_msg>Replaced annoying defines by const identifiers.<commit_after>#include <iostream>
#include <windows.h>
#include <string>
#include <fstream>
#include <conio.h>
#include <Shlwapi.h>
#include <stdlib.h>
#include <algorithm>
#include "General.h"
#include "../Progresscounter/Progress.h"
#include "Path.h"
#pragma comment(lib, "shlwapi.lib")

using namespace std;

const string version = "1.33";
void RestoreTree(string filePath);

int main()
{
	// Initializing console.
	string input = "";
	string command = "";
	PrepareConsole("Tree", version, "Please name the file which should be source of the tree.\nType \"help\" for further information.");

	// Loop waits for correct input.
	while (true)
	{
		Color(INPUT_COLOR);
		cout << "Tree.exe> ";
		getline(cin, input, '\n');
		command = ToLower(GetWord(input, 1));
		Color(OUTPUT_COLOR);

		// Parsing.
		if (command == "exit" || command == "quit")
		{
			// Leaving program when "exit" or "quit" has been typed.
			return(EXIT_SUCCESS);
		}
		else if (command == "help")
		{
			// Shows a description of all available commands.
			cout << "   Available Commands:" << endl;
			cout << "   help\t\tShows this page" << endl;
			cout << "   info\t\tGeneral information" << endl;
			cout << "   clear/cls\tClears the Screen" << endl;
			cout << "   exit\t\tTerminates the program" << endl << endl;
			cout << "   Enter any other string to designate the file containing the tree." << endl;
			cout << "   The program will create the listed files and directories," << endl;
			cout << "   until you press 'q' or the file reaches its end." << endl << endl;
		}
		else if (command == "info")
		{
			// Shows general info about the software.
			cout << "   Tree Version " << version << endl;
			cout << "   Compiled: " << __DATE__ << ", " << __TIME__ << endl;
			cout << "   (c) 2012 - 2015 Julian Heinzel" << endl << endl;
		}
		else if (command == "clear" || command == "cls")
		{
			// Resets the terminal.
			PrepareConsole("Tree", version, "Please name the file which should be source of the tree.\nType \"help\" for further information.");
		}
		else if (!PathFileExists(input.c_str()))
		{
			// Printing an error, if no command and no valid path has been typed.
			cout << "   Did not find file \"" + input + "\"." << endl << endl;
		}
		else
		{
			RestoreTree(input);
		}
	}
	return(EXIT_SUCCESS);
}

// Restores the directory and file structure.
void RestoreTree(string filePath)
{
	string		line;
	ifstream	fileIn;
	Progress	progressBar;
	Path		path;

	// Counting the total number of lines in the specified textfile.
	int numberOfLines = 0;
	cout << "   File found, counting lines..." << endl;
	fileIn.open(filePath);
	while (getline(fileIn, line))
	{
		numberOfLines += 1;
	}
	progressBar.Reset(numberOfLines, 3);

	// Opening file and skipping the first three lines.
	cout << "   Processing " << numberOfLines << " lines of text." << endl << "   ";
	fileIn.close();
	fileIn.open(filePath);
	for (int i = 0; i < 3; i++) getline(fileIn, line);

	// Get the filename, replace '.' by '_', set the resulting string as root folder.
	string fileName = GetFileName(filePath);
	replace(fileName.begin(), fileName.end(), '.', '_');
	path.AddLevel(fileName);
	CreateDirectory(path.GetLevel(0).c_str(), 0);

	// Loops through every line in the file.
	while (getline(fileIn, line))
	{
		bool	readingName = false;
		int		level = 0;
		int		length = strlen(line.c_str());
		int		indention = 0;
		string	newName = "";

		// Update the terminal, quit on 'q' and 'e'
		progressBar.Increment();
		progressBar.Print();
		if (_kbhit())
		{
			char C = _getch();
			if (C == 'q' || C == 'e')
			{
				cout << endl << "   Program canceled. Processed "
					<< progressBar.GetCounter() << " of " << progressBar.GetMaxElements()
					<< " lines. (" << progressBar.GetString() << ")" << endl << endl;
				return;
			}
		}

		if (length == 0)
		{
			break;
		}

		// Extract directory/file name from line.
		for (int i = 0; i < length; i++)
		{
			char c = line[i];
			if ((c != ' ') && (c != '-') && (c != '\\') && (c != '|') && (c != '+') && (readingName == false))
			{
				readingName = true;
			}

			if (readingName == true)
			{
				newName += c;
			}
			else
			{
				indention++;
			}
		}
		level = (indention / 4);

		// If there is no valid file or directory name, the next line is beeing evaluated.
		if (newName == "")
		{
			continue;
		}

		// If there is a '+' or a '\' in the given line, the name will be interpreted as a directory.
		// The new path is saved and the directory created.
		path.RemoveLevels(level, path.Depth());
		path.AddLevel(newName);
		if ((line.find('+') != -1) || (line.find("\\") != -1))
		{
			CreateDirectory(path.GetPath().c_str(), 0);
		}
		else
		{
			// Otherwise a file is listed, which will then be created.
			ofstream fileOut;
			fileOut.open(path.GetPath());
			fileOut.close();
		}
	}

	if (progressBar.GetPercent() == 100)
	{
		// Info if the file has been successfully processed.
		cout << endl << "   Generated files from \"" + filePath + "\" succesfully." << endl << endl;
	}
}<|endoftext|>


<commit_before>/*
Copyright (c) 2017 InversePalindrome
Memento Mori - Subject.hpp
InversePalindrome.com
*/

#pragma once

#include "Observer.hpp"

#include <vector>

class Subject
{
public:
	void addObserver(Observer& observer);
	void removeObserver(Observer& observer);

	void notifyObservers(const Message& message);

private:
	std::vector<Observer*> observers;
};
<commit_msg>Delete Subject.hpp<commit_after><|endoftext|>


<commit_before>#ifndef GCN_GUICHAN_HPP
#define GCN_GUICHAN_HPP

// #include "guichan/actionlistener.hpp"
#include <guichan/color.hpp>
// #include "guichan/container.hpp"
// #include "guichan/focushandler.hpp"
// #include "guichan/font.hpp"
#include <guichan/graphics.hpp>
//#include "guichan/gui.hpp"
#include <guichan/image.hpp>
// #include "guichan/imagemousetype.hpp"
#include "guichan/input.hpp"
#include "guichan/key.hpp"
#include "guichan/keyinput.hpp"
// #include "guichan/keylistener.hpp"
#include "guichan/mouseinput.hpp"
// #include "guichan/mouselistener.hpp"
// #include "guichan/mousetype.hpp"
#include <guichan/rectangle.hpp>
#include <guichan/cliprectangle.hpp>
//#include "guichan/widget.hpp"

#include <guichan/sdl/sdlgraphics.hpp>
#include <guichan/sdl/sdlimage.hpp>
#include <guichan/sdl/sdlinput.hpp>

#endif // end GCN_GUICHAN_HPP
<commit_msg>Removed everyting regarding graphics/input drivers.<commit_after>#ifndef GCN_GUICHAN_HPP
#define GCN_GUICHAN_HPP

// #include "guichan/actionlistener.hpp"
#include <guichan/color.hpp>
// #include "guichan/container.hpp"
// #include "guichan/focushandler.hpp"
// #include "guichan/font.hpp"
#include <guichan/graphics.hpp>
//#include "guichan/gui.hpp"
#include <guichan/image.hpp>
// #include "guichan/imagemousetype.hpp"
#include <guichan/input.hpp>
#include <guichan/key.hpp>
#include <guichan/keyinput.hpp>
// #include "guichan/keylistener.hpp"
#include <guichan/mouseinput.hpp>
// #include "guichan/mouselistener.hpp"
// #include "guichan/mousetype.hpp"
#include <guichan/rectangle.hpp>
#include <guichan/cliprectangle.hpp>
//#include "guichan/widget.hpp"

#endif // end GCN_GUICHAN_HPP
<|endoftext|>


<commit_before>/*
 * @Filename: helpers.hpp
 * @Author: Anurag Soni <anuragsoni.13@gmail.com>
 * @Description: Helper functions and meta information
 */
#pragma once
#include <algorithm>
#define AGENT_NAME "restless/0.2"
namespace
{
// Trim string from beginning
inline std::string &ltrim(std::string &s)
{
    s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
    return s;
}
// Trim string from the end
inline std::string &rtrim(std::string &s)
{
    s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
    return s;
}
// Trim string from both ends
inline std::string &trim(std::string &s)
{
    return ltrim(rtrim(s));
}

}<commit_msg>Add missing headers to the 'helpers.hpp'.<commit_after>/*
 * @Filename: helpers.hpp
 * @Author: Anurag Soni <anuragsoni.13@gmail.com>
 * @Description: Helper functions and meta information
 */
#pragma once
#include <algorithm>
#include <functional>
#include <cctype>
#define AGENT_NAME "restless/0.2"
namespace
{
// Trim string from beginning
inline std::string &ltrim(std::string &s)
{
    s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
    return s;
}
// Trim string from the end
inline std::string &rtrim(std::string &s)
{
    s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
    return s;
}
// Trim string from both ends
inline std::string &trim(std::string &s)
{
    return ltrim(rtrim(s));
}

}
<|endoftext|>


<commit_before>#pragma once

#include <unordered_map>
#include <memory>
#include <type_traits>
#include <tuple>

namespace kgr {

template<typename... Types>
struct Dependency {
	using DependenciesTypes = std::tuple<Types...>;
};

using NoDependencies = Dependency<>;

struct Single {
	using ParentTypes = std::tuple<>;
};

template<typename T>
struct Service;

template<typename... Types>
struct Overrides : Single {
	using ParentTypes = std::tuple<Types...>;
};

namespace detail {

enum class enabler {};

template <bool b, typename T>
using enable_if_t = typename std::enable_if<b, T>::type;

template<int ...>
struct seq {};

template<int n, int ...S>
struct seq_gen : seq_gen<n-1, n-1, S...> {};

template<int ...S>
struct seq_gen<0, S...> {
	using type = seq<S...>;
};

struct Holder {
	virtual ~Holder() = default;
};

template<typename T>
struct InstanceHolder final : Holder {
	explicit InstanceHolder(std::shared_ptr<T> instance) : _instance{std::move(instance)} {}

	std::shared_ptr<T> getInstance() const {
		return _instance;
	}

private:
	std::shared_ptr<T> _instance;
};

template<typename T, typename... Args>
struct CallbackHolder final : Holder {
	using callback_t = std::function<std::shared_ptr<T>(Args...)>;

	explicit CallbackHolder(callback_t callback) : _callback{std::move(callback)} {}

	std::shared_ptr<T> operator ()(Args... args) {
		return _callback(args...);
	}
private:
	callback_t _callback;
};

template<typename T, typename ...Args>
std::unique_ptr<T> make_unique( Args&& ...args )
{
    return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) );
}

template <typename T> void type_id() {}
using type_id_fn = void(*)();

} // namespace detail

class Container : public std::enable_shared_from_this<Container> {
	template<typename Condition, typename T = detail::enabler> using enable_if = detail::enable_if_t<Condition::value, T>;
	template<typename Condition, typename T = detail::enabler> using disable_if = detail::enable_if_t<!Condition::value, T>;
	template<typename T> using is_service_single = std::is_base_of<Single, Service<T>>;
	template<typename T> using is_abstract = std::is_abstract<T>;
	template<typename T> using is_base_of_container = std::is_base_of<Container, T>;
	template<typename T> using is_container = std::is_same<T, Container>;
	template<typename T> using dependency_types = typename Service<T>::DependenciesTypes;
	template<typename T> using parent_types = typename Service<T>::ParentTypes;
	template <typename Tuple> using tuple_seq = typename detail::seq_gen<std::tuple_size<Tuple>::value>::type;
	template<int S, typename T> using parent_element = typename std::tuple_element<S, parent_types<T>>::type;
	template<int S, typename Tuple> using tuple_element = typename std::tuple_element<S, Tuple>::type;
	using holder_ptr = std::unique_ptr<detail::Holder>;
	using holder_cont = std::unordered_map<detail::type_id_fn, holder_ptr>;
	constexpr static detail::enabler null = {};

public:
	Container(const Container &) = delete;
	Container(Container &&) = delete;
	Container& operator =(const Container &) = delete;
	Container& operator =(Container &&) = delete;
	virtual ~Container() = default;

	template <typename T, typename... Args,
		 enable_if<is_base_of_container<T>> = null>
	static std::shared_ptr<T> make_container(Args&&... args) {
		auto container = std::make_shared<T>(std::forward<Args>(args)...);
		static_cast<Container&>(*container).init();
		return container;
	}

	template<typename T>
	void instance(std::shared_ptr<T> service) {
		static_assert(is_service_single<T>::value, "instance only accept Single Service instance.");

		call_save_instance(std::move(service), tuple_seq<parent_types<T>>{});
	}

	template<typename T>
	void instance() {
		static_assert(is_service_single<T>::value, "instance only accept Single Service instance.");

		instance(make_service<T>());
	}

	template<typename T, disable_if<is_abstract<T>> = null, disable_if<is_base_of_container<T>> = null>
	std::shared_ptr<T> service() {
		return get_service<T>();
	}

	template<typename T, enable_if<is_container<T>> = null>
	std::shared_ptr<T> service() {
		return shared_from_this();
	}

	template<typename T, disable_if<is_container<T>> = null, enable_if<is_base_of_container<T>> = null>
	std::shared_ptr<T> service() {
		return std::dynamic_pointer_cast<T>(shared_from_this());
	}

	template<typename T, enable_if<is_abstract<T>> = null>
	std::shared_ptr<T> service() {
		auto it = _services.find(&detail::type_id<T>);

		if (it != _services.end()) {
			return static_cast<detail::InstanceHolder<T>&>(*it->second).getInstance();
		}

		return {};
	}

	template<typename T, typename U>
	void callback(U callback) {
		static_assert(!is_service_single<T>::value, "instance does not accept Single Service.");

		save_callback<T, dependency_types<T>>(tuple_seq<dependency_types<T>>{}, callback);
	}
protected:
	Container() = default;
	virtual void init(){}
private:
	template<typename T, enable_if<is_service_single<T>> = null>
	std::shared_ptr<T> get_service() {
		auto it = _services.find(&detail::type_id<T>);

		if (it == _services.end()) {
			auto service = make_service<T>();
			instance(service);

			return service;
		} else {
			return static_cast<detail::InstanceHolder<T>*>(it->second.get())->getInstance();
		}

		return {};
	}

	template<typename T, disable_if<is_service_single<T>> = null>
	std::shared_ptr<T> get_service() {
		return make_service<T>();
	}

	template<typename T, int ...S>
	void call_save_instance(std::shared_ptr<T> service, detail::seq<S...>) {
		save_instance<T, parent_element<S, T>...>(std::move(service));
	}

	template<typename Tuple, int ...S>
	std::tuple<std::shared_ptr<tuple_element<S, Tuple>>...> dependency(detail::seq<S...>) {
		return std::make_tuple(service<tuple_element<S, Tuple>>()...);
	}

	template<typename T, typename Tuple, int ...S>
	std::shared_ptr<T> callback_make_service(detail::seq<S...>, Tuple dependencies) const {
		auto it = _callbacks.find(&detail::type_id<T>);

		if (it != _callbacks.end()) {
			return static_cast<detail::CallbackHolder<T, tuple_element<S, Tuple>...>&>(*it->second)(std::get<S>(dependencies)...);
		}

		return {};
	}

	template<typename T, typename Tuple, int ...S>
	std::shared_ptr<T> make_service(detail::seq<S...> seq, Tuple dependencies) const {
		auto service = callback_make_service<T, Tuple>(seq, dependencies);

		if (service) {
			return service;
		}

		return std::make_shared<T>(std::get<S>(dependencies)...);
	}

	template <typename T>
	std::shared_ptr<T> make_service() {
		auto seq = tuple_seq<dependency_types<T>>{};
		return make_service<T>(seq, dependency<dependency_types<T>>(seq));
	}

	template<typename T, typename ...Others>
	detail::enable_if_t<(sizeof...(Others) > 0), void> save_instance(std::shared_ptr<T> service) {
		save_instance<T>(service);
		save_instance<Others...>(std::move(service));
	}

	template<typename T>
	void save_instance (std::shared_ptr<T> service) {
		_services[&detail::type_id<T>] = detail::make_unique<detail::InstanceHolder<T>>(std::move(service));
	}

	template<typename T, typename Tuple, int ...S, typename U>
	void save_callback (detail::seq<S...>, U callback) {
		_callbacks[&detail::type_id<T>] = detail::make_unique<detail::CallbackHolder<T, std::shared_ptr<tuple_element<S, Tuple>>...>>(callback);
	}

	holder_cont _callbacks;
	holder_cont _services;
};

template<typename T = Container, typename ...Args>
std::shared_ptr<T> make_container(Args&& ...args) {
	static_assert(std::is_base_of<Container, T>::value, "make_container only accept container types.");

	return Container::make_container<T>(std::forward<Args>(args)...);
}

}  // namespace kgr
<commit_msg>Work on returns<commit_after>#pragma once

#include <unordered_map>
#include <memory>
#include <type_traits>
#include <tuple>

namespace kgr {

template<typename... Types>
struct Dependency {
	using DependenciesTypes = std::tuple<Types...>;
};

using NoDependencies = Dependency<>;

struct Single {
	using ParentTypes = std::tuple<>;
};

template<typename T>
struct Service;

template<typename... Types>
struct Overrides : Single {
	using ParentTypes = std::tuple<Types...>;
};

namespace detail {

enum class enabler {};

template <bool b, typename T>
using enable_if_t = typename std::enable_if<b, T>::type;

template<int ...>
struct seq {};

template<int n, int ...S>
struct seq_gen : seq_gen<n-1, n-1, S...> {};

template<int ...S>
struct seq_gen<0, S...> {
	using type = seq<S...>;
};

struct Holder {
	virtual ~Holder() = default;
};

template<typename T>
struct InstanceHolder final : Holder {
	explicit InstanceHolder(std::shared_ptr<T> instance) : _instance{std::move(instance)} {}

	std::shared_ptr<T> getInstance() const {
		return _instance;
	}

private:
	std::shared_ptr<T> _instance;
};

template<typename T, typename... Args>
struct CallbackHolder final : Holder {
	using callback_t = std::function<std::shared_ptr<T>(Args...)>;

	explicit CallbackHolder(callback_t callback) : _callback{std::move(callback)} {}

	std::shared_ptr<T> operator ()(Args... args) {
		return _callback(args...);
	}
private:
	callback_t _callback;
};

template<typename T, typename ...Args>
std::unique_ptr<T> make_unique( Args&& ...args )
{
    return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) );
}

template <typename T> void type_id() {}
using type_id_fn = void(*)();

} // namespace detail

class Container : public std::enable_shared_from_this<Container> {
	template<typename Condition, typename T = detail::enabler> using enable_if = detail::enable_if_t<Condition::value, T>;
	template<typename Condition, typename T = detail::enabler> using disable_if = detail::enable_if_t<!Condition::value, T>;
	template<typename T> using is_service_single = std::is_base_of<Single, Service<T>>;
	template<typename T> using is_abstract = std::is_abstract<T>;
	template<typename T> using is_base_of_container = std::is_base_of<Container, T>;
	template<typename T> using is_container = std::is_same<T, Container>;
	template<typename T> using dependency_types = typename Service<T>::DependenciesTypes;
	template<typename T> using parent_types = typename Service<T>::ParentTypes;
	template <typename Tuple> using tuple_seq = typename detail::seq_gen<std::tuple_size<Tuple>::value>::type;
	template<int S, typename T> using parent_element = typename std::tuple_element<S, parent_types<T>>::type;
	template<int S, typename Tuple> using tuple_element = typename std::tuple_element<S, Tuple>::type;
	using holder_ptr = std::unique_ptr<detail::Holder>;
	using holder_cont = std::unordered_map<detail::type_id_fn, holder_ptr>;
	constexpr static detail::enabler null = {};

public:
	Container(const Container &) = delete;
	Container(Container &&) = delete;
	Container& operator =(const Container &) = delete;
	Container& operator =(Container &&) = delete;
	virtual ~Container() = default;

	template <typename T, typename... Args,
		 enable_if<is_base_of_container<T>> = null>
	static std::shared_ptr<T> make_container(Args&&... args) {
		auto container = std::make_shared<T>(std::forward<Args>(args)...);
		static_cast<Container&>(*container).init();
		return container;
	}

	template<typename T>
	void instance(std::shared_ptr<T> service) {
		static_assert(is_service_single<T>::value, "instance only accept Single Service instance.");

		call_save_instance(std::move(service), tuple_seq<parent_types<T>>{});
	}

	template<typename T>
	void instance() {
		static_assert(is_service_single<T>::value, "instance only accept Single Service instance.");

		instance(make_service<T>());
	}

	template<typename T, disable_if<is_abstract<T>> = null, disable_if<is_base_of_container<T>> = null>
	std::shared_ptr<T> service() {
		return get_service<T>();
	}

	template<typename T, enable_if<is_container<T>> = null>
	std::shared_ptr<T> service() {
		return shared_from_this();
	}

	template<typename T, disable_if<is_container<T>> = null, enable_if<is_base_of_container<T>> = null>
	std::shared_ptr<T> service() {
		return std::dynamic_pointer_cast<T>(shared_from_this());
	}

	template<typename T, enable_if<is_abstract<T>> = null>
	std::shared_ptr<T> service() {
		auto it = _services.find(&detail::type_id<T>);

		if (it != _services.end()) {
			return static_cast<detail::InstanceHolder<T>&>(*it->second).getInstance();
		}

		return {};
	}

	template<typename T, typename U>
	void callback(U callback) {
		static_assert(!is_service_single<T>::value, "instance does not accept Single Service.");

		save_callback<T, dependency_types<T>>(tuple_seq<dependency_types<T>>{}, callback);
	}
protected:
	Container() = default;
	virtual void init(){}
private:
	template<typename T, enable_if<is_service_single<T>> = null>
	std::shared_ptr<T> get_service() {
		auto it = _services.find(&detail::type_id<T>);

		if (it == _services.end()) {
			auto service = make_service<T>();
			instance(service);

			return service;
		}
		return static_cast<detail::InstanceHolder<T>*>(it->second.get())->getInstance();
	}

	template<typename T, disable_if<is_service_single<T>> = null>
	std::shared_ptr<T> get_service() {
		return make_service<T>();
	}

	template<typename T, int ...S>
	void call_save_instance(std::shared_ptr<T> service, detail::seq<S...>) {
		save_instance<T, parent_element<S, T>...>(std::move(service));
	}

	template<typename Tuple, int ...S>
	std::tuple<std::shared_ptr<tuple_element<S, Tuple>>...> dependency(detail::seq<S...>) {
		return std::make_tuple(service<tuple_element<S, Tuple>>()...);
	}

	template<typename T, typename Tuple, int ...S>
	std::shared_ptr<T> callback_make_service(detail::seq<S...>, Tuple dependencies) const {
		auto it = _callbacks.find(&detail::type_id<T>);

		if (it != _callbacks.end()) {
			return static_cast<detail::CallbackHolder<T, tuple_element<S, Tuple>...>&>(*it->second)(std::get<S>(dependencies)...);
		}

		return {};
	}

	template<typename T, typename Tuple, int ...S>
	std::shared_ptr<T> make_service(detail::seq<S...> seq, Tuple dependencies) const {
		auto service = callback_make_service<T, Tuple>(seq, dependencies);

		return service ? service : std::make_shared<T>(std::get<S>(dependencies)...);
	}

	template <typename T>
	std::shared_ptr<T> make_service() {
		auto seq = tuple_seq<dependency_types<T>>{};
		return make_service<T>(seq, dependency<dependency_types<T>>(seq));
	}

	template<typename T, typename ...Others>
	detail::enable_if_t<(sizeof...(Others) > 0), void> save_instance(std::shared_ptr<T> service) {
		save_instance<T>(service);
		save_instance<Others...>(std::move(service));
	}

	template<typename T>
	void save_instance (std::shared_ptr<T> service) {
		_services[&detail::type_id<T>] = detail::make_unique<detail::InstanceHolder<T>>(std::move(service));
	}

	template<typename T, typename Tuple, int ...S, typename U>
	void save_callback (detail::seq<S...>, U callback) {
		_callbacks[&detail::type_id<T>] = detail::make_unique<detail::CallbackHolder<T, std::shared_ptr<tuple_element<S, Tuple>>...>>(callback);
	}

	holder_cont _callbacks;
	holder_cont _services;
};

template<typename T = Container, typename ...Args>
std::shared_ptr<T> make_container(Args&& ...args) {
	static_assert(std::is_base_of<Container, T>::value, "make_container only accept container types.");

	return Container::make_container<T>(std::forward<Args>(args)...);
}

}  // namespace kgr
<|endoftext|>


<commit_before>#pragma once

#include <unordered_map>
#include <memory>
#include <type_traits>
#include <tuple>

namespace kgr {

template<typename... Types>
struct Dependency {
	using DependenciesTypes = std::tuple<Types...>;
};

using NoDependencies = Dependency<>;

struct Single {
	using ParentTypes = std::tuple<>;
};

template<typename T>
struct Service;

template<typename... Types>
struct Overrides : Single {
	using ParentTypes = std::tuple<Types...>;
};

namespace detail {

enum class enabler {};

template <bool B, typename T>
using enable_if_t = typename std::enable_if<B, T>::type;

template<int ...>
struct seq { };

template<int N, int ...S>
struct seq_gen : seq_gen<N-1, N-1, S...> { };

template<int ...S>
struct seq_gen<0, S...> {
	using type = seq<S...>;
};

struct Holder {};

template<typename T>
struct InstanceHolder final : Holder {
	explicit InstanceHolder(std::shared_ptr<T> instance) : _instance{std::move(instance)} {}

	std::shared_ptr<T> getInstance() const {
		return _instance;
	}

private:
	std::shared_ptr<T> _instance;
};

template<typename T, typename... Args>
struct CallbackHolder final : Holder {
	using callback_t = std::function<std::shared_ptr<T>(Args...)>;

	explicit CallbackHolder(callback_t callback) : _callback{std::move(callback)} {}

	std::shared_ptr<T> operator ()(Args... args) {
		return _callback(args...);
	}
private:
	callback_t _callback;
};

template<typename T, typename ...Args>
std::unique_ptr<T> make_unique( Args&& ...args )
{
    return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) );
}

template <typename T> void type_id() {}
using type_id_fn = void(*)();

} // namespace detail

class Container : public std::enable_shared_from_this<Container> {
	template<typename Condition, typename T = detail::enabler> using enable_if = detail::enable_if_t<Condition::value, T>;
	template<typename Condition, typename T = detail::enabler> using disable_if = detail::enable_if_t<!Condition::value, T>;
	template<typename T> using is_service_single = std::is_base_of<Single, Service<T>>;
	template<typename T> using is_abstract = std::is_abstract<T>;
	template<typename T> using is_base_of_container = std::is_base_of<Container, T>;
	template<typename T> using is_container = std::is_same<T, Container>;
	template<typename T> using dependency_types = typename Service<T>::DependenciesTypes;
	template<typename T> using parent_types = typename Service<T>::ParentTypes;
	template <typename Tuple> using tuple_seq = typename detail::seq_gen<std::tuple_size<Tuple>::value>::type;
	template<int S, typename T> using parent_element = typename std::tuple_element<S, parent_types<T>>::type;
	template<int S, typename Tuple> using tuple_element = typename std::tuple_element<S, Tuple>::type;
	using holder_ptr = std::unique_ptr<detail::Holder>;
	using holder_cont = std::unordered_map<detail::type_id_fn, holder_ptr>;
	constexpr static detail::enabler null = {};

public:
	Container() = default;
	Container(const Container &) = default;
	Container(Container &&) = default;
	Container& operator =(const Container &) = default;
	Container& operator =(Container &&) = default;
	~Container() = default;

	template<typename T>
	void instance(std::shared_ptr<T> service) {
		static_assert(is_service_single<T>::value, "instance only accept Single Service instance.");

		call_save_instance(std::move(service), tuple_seq<parent_types<T>>{});
	}

	template<typename T>
	void instance() {
		static_assert(is_service_single<T>::value, "instance only accept Single Service instance.");

		instance(make_service<T>());
	}

	template<typename T, disable_if<is_abstract<T>> = null, disable_if<is_base_of_container<T>> = null>
	std::shared_ptr<T> service() {
		return get_service<T>();
	}

	template<typename T, enable_if<is_container<T>> = null>
	std::shared_ptr<T> service() {
		return shared_from_this();
	}

	template<typename T, disable_if<is_container<T>> = null, enable_if<is_base_of_container<T>> = null>
	std::shared_ptr<T> service() {
		return std::dynamic_pointer_cast<T>(shared_from_this());
	}

	template<typename T, enable_if<is_abstract<T>> = null>
	std::shared_ptr<T> service() {
		auto it = _services.find(&detail::type_id<T>);

		if (it != _services.end()) {
			auto holder = static_cast<detail::InstanceHolder<T>*>(it->second.get());

			if (holder) {
				return holder->getInstance();
			}
		}
		return {};
	}

	template<typename T, typename U>
	void callback(U callback) {
		static_assert(!is_service_single<T>::value, "instance does not accept Single Service.");

		save_callback<T, dependency_types<T>>(tuple_seq<dependency_types<T>>{}, callback);
	}

	virtual void init(){}

private:
	template<typename T, enable_if<is_service_single<T>> = null>
	std::shared_ptr<T> get_service() {
		auto it = _services.find(&detail::type_id<T>);

		if (it == _services.end()) {
			auto service = make_service<T>();
			instance(service);

			return service;
		} else {
			auto holder = static_cast<detail::InstanceHolder<T>*>(it->second.get());

			if (holder) {
				return holder->getInstance();
			}
		}
		return {};
	}

	template<typename T, disable_if<is_service_single<T>> = null>
	std::shared_ptr<T> get_service() {
		return make_service<T>();
	}

	template<typename T, int ...S>
	void call_save_instance(std::shared_ptr<T> service, detail::seq<S...>) {
		save_instance<T, parent_element<S, T>...>(std::move(service));
	}

	template<typename Tuple, int ...S>
	std::tuple<std::shared_ptr<tuple_element<S, Tuple>>...> dependency(detail::seq<S...>) {
		return std::make_tuple(service<tuple_element<S, Tuple>>()...);
	}

	template<typename T, typename Tuple, int ...S>
	std::shared_ptr<T> callback_make_service(detail::seq<S...>, Tuple dependencies) const {
		auto it = _callbacks.find(&detail::type_id<T>);

		if (it != _callbacks.end()) {
			auto holder = static_cast<detail::CallbackHolder<T, tuple_element<S, Tuple>...>*>(it->second.get());
			if (holder) {
				return (*holder)(std::get<S>(dependencies)...);
			}
		}
		return {};
	}

	template<typename T, typename Tuple, int ...S>
	std::shared_ptr<T> make_service(detail::seq<S...> seq, Tuple dependencies) const {
		auto service = callback_make_service<T, Tuple>(seq, dependencies);

		if (service) {
			return service;
		}

		return std::make_shared<T>(std::get<S>(dependencies)...);
	}

	template <typename T>
	std::shared_ptr<T> make_service() {
		auto seq = tuple_seq<dependency_types<T>>{};
		return make_service<T>(seq, dependency<dependency_types<T>>(seq));
	}

	template<typename T, typename ...Others>
	detail::enable_if_t<(sizeof...(Others) > 0), void> save_instance(std::shared_ptr<T> service) {
		save_instance<T>(service);
		save_instance<Others...>(std::move(service));
	}

	template<typename T>
	void save_instance (std::shared_ptr<T> service) {
		_services[&detail::type_id<T>] = detail::make_unique<detail::InstanceHolder<T>>(std::move(service));
	}

	template<typename T, typename Tuple, int ...S, typename U>
	void save_callback (detail::seq<S...>, U callback) {
		_callbacks[&detail::type_id<T>] = detail::make_unique<detail::CallbackHolder<T, std::shared_ptr<tuple_element<S, Tuple>>...>>(callback);
	}

	holder_cont _callbacks;
	holder_cont _services;
};

template<typename T = Container, typename ...Args>
std::shared_ptr<T> make_container(Args&& ...args) {
	static_assert(std::is_base_of<Container, T>::value, "make_container only accept container types.");

	auto container = std::make_shared<T>(std::forward<Args>(args)...);
	container->init();

	return container;
}

}  // namespace kgr
<commit_msg>no need to check if null, the value cannot be null<commit_after>#pragma once

#include <unordered_map>
#include <memory>
#include <type_traits>
#include <tuple>

namespace kgr {

template<typename... Types>
struct Dependency {
	using DependenciesTypes = std::tuple<Types...>;
};

using NoDependencies = Dependency<>;

struct Single {
	using ParentTypes = std::tuple<>;
};

template<typename T>
struct Service;

template<typename... Types>
struct Overrides : Single {
	using ParentTypes = std::tuple<Types...>;
};

namespace detail {

enum class enabler {};

template <bool B, typename T>
using enable_if_t = typename std::enable_if<B, T>::type;

template<int ...>
struct seq { };

template<int N, int ...S>
struct seq_gen : seq_gen<N-1, N-1, S...> { };

template<int ...S>
struct seq_gen<0, S...> {
	using type = seq<S...>;
};

struct Holder {};

template<typename T>
struct InstanceHolder final : Holder {
	explicit InstanceHolder(std::shared_ptr<T> instance) : _instance{std::move(instance)} {}

	std::shared_ptr<T> getInstance() const {
		return _instance;
	}

private:
	std::shared_ptr<T> _instance;
};

template<typename T, typename... Args>
struct CallbackHolder final : Holder {
	using callback_t = std::function<std::shared_ptr<T>(Args...)>;

	explicit CallbackHolder(callback_t callback) : _callback{std::move(callback)} {}

	std::shared_ptr<T> operator ()(Args... args) {
		return _callback(args...);
	}
private:
	callback_t _callback;
};

template<typename T, typename ...Args>
std::unique_ptr<T> make_unique( Args&& ...args )
{
    return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) );
}

template <typename T> void type_id() {}
using type_id_fn = void(*)();

} // namespace detail

class Container : public std::enable_shared_from_this<Container> {
	template<typename Condition, typename T = detail::enabler> using enable_if = detail::enable_if_t<Condition::value, T>;
	template<typename Condition, typename T = detail::enabler> using disable_if = detail::enable_if_t<!Condition::value, T>;
	template<typename T> using is_service_single = std::is_base_of<Single, Service<T>>;
	template<typename T> using is_abstract = std::is_abstract<T>;
	template<typename T> using is_base_of_container = std::is_base_of<Container, T>;
	template<typename T> using is_container = std::is_same<T, Container>;
	template<typename T> using dependency_types = typename Service<T>::DependenciesTypes;
	template<typename T> using parent_types = typename Service<T>::ParentTypes;
	template <typename Tuple> using tuple_seq = typename detail::seq_gen<std::tuple_size<Tuple>::value>::type;
	template<int S, typename T> using parent_element = typename std::tuple_element<S, parent_types<T>>::type;
	template<int S, typename Tuple> using tuple_element = typename std::tuple_element<S, Tuple>::type;
	using holder_ptr = std::unique_ptr<detail::Holder>;
	using holder_cont = std::unordered_map<detail::type_id_fn, holder_ptr>;
	constexpr static detail::enabler null = {};

public:
	Container() = default;
	Container(const Container &) = default;
	Container(Container &&) = default;
	Container& operator =(const Container &) = default;
	Container& operator =(Container &&) = default;
	~Container() = default;

	template<typename T>
	void instance(std::shared_ptr<T> service) {
		static_assert(is_service_single<T>::value, "instance only accept Single Service instance.");

		call_save_instance(std::move(service), tuple_seq<parent_types<T>>{});
	}

	template<typename T>
	void instance() {
		static_assert(is_service_single<T>::value, "instance only accept Single Service instance.");

		instance(make_service<T>());
	}

	template<typename T, disable_if<is_abstract<T>> = null, disable_if<is_base_of_container<T>> = null>
	std::shared_ptr<T> service() {
		return get_service<T>();
	}

	template<typename T, enable_if<is_container<T>> = null>
	std::shared_ptr<T> service() {
		return shared_from_this();
	}

	template<typename T, disable_if<is_container<T>> = null, enable_if<is_base_of_container<T>> = null>
	std::shared_ptr<T> service() {
		return std::dynamic_pointer_cast<T>(shared_from_this());
	}

	template<typename T, enable_if<is_abstract<T>> = null>
	std::shared_ptr<T> service() {
		auto it = _services.find(&detail::type_id<T>);

		if (it != _services.end()) {
			return static_cast<detail::InstanceHolder<T>*>(it->second.get())->getInstance();
		}
		return {};
	}

	template<typename T, typename U>
	void callback(U callback) {
		static_assert(!is_service_single<T>::value, "instance does not accept Single Service.");

		save_callback<T, dependency_types<T>>(tuple_seq<dependency_types<T>>{}, callback);
	}

	virtual void init(){}

private:
	template<typename T, enable_if<is_service_single<T>> = null>
	std::shared_ptr<T> get_service() {
		auto it = _services.find(&detail::type_id<T>);

		if (it == _services.end()) {
			auto service = make_service<T>();
			instance(service);

			return service;
		} else {
			return static_cast<detail::InstanceHolder<T>*>(it->second.get())->getInstance();
		}

		return {};
	}

	template<typename T, disable_if<is_service_single<T>> = null>
	std::shared_ptr<T> get_service() {
		return make_service<T>();
	}

	template<typename T, int ...S>
	void call_save_instance(std::shared_ptr<T> service, detail::seq<S...>) {
		save_instance<T, parent_element<S, T>...>(std::move(service));
	}

	template<typename Tuple, int ...S>
	std::tuple<std::shared_ptr<tuple_element<S, Tuple>>...> dependency(detail::seq<S...>) {
		return std::make_tuple(service<tuple_element<S, Tuple>>()...);
	}

	template<typename T, typename Tuple, int ...S>
	std::shared_ptr<T> callback_make_service(detail::seq<S...>, Tuple dependencies) const {
		auto it = _callbacks.find(&detail::type_id<T>);

		if (it != _callbacks.end()) {
			return (*static_cast<detail::CallbackHolder<T, tuple_element<S, Tuple>...>*>(it->second.get()))(std::get<S>(dependencies)...);
		}

		return {};
	}

	template<typename T, typename Tuple, int ...S>
	std::shared_ptr<T> make_service(detail::seq<S...> seq, Tuple dependencies) const {
		auto service = callback_make_service<T, Tuple>(seq, dependencies);

		if (service) {
			return service;
		}

		return std::make_shared<T>(std::get<S>(dependencies)...);
	}

	template <typename T>
	std::shared_ptr<T> make_service() {
		auto seq = tuple_seq<dependency_types<T>>{};
		return make_service<T>(seq, dependency<dependency_types<T>>(seq));
	}

	template<typename T, typename ...Others>
	detail::enable_if_t<(sizeof...(Others) > 0), void> save_instance(std::shared_ptr<T> service) {
		save_instance<T>(service);
		save_instance<Others...>(std::move(service));
	}

	template<typename T>
	void save_instance (std::shared_ptr<T> service) {
		_services[&detail::type_id<T>] = detail::make_unique<detail::InstanceHolder<T>>(std::move(service));
	}

	template<typename T, typename Tuple, int ...S, typename U>
	void save_callback (detail::seq<S...>, U callback) {
		_callbacks[&detail::type_id<T>] = detail::make_unique<detail::CallbackHolder<T, std::shared_ptr<tuple_element<S, Tuple>>...>>(callback);
	}

	holder_cont _callbacks;
	holder_cont _services;
};

template<typename T = Container, typename ...Args>
std::shared_ptr<T> make_container(Args&& ...args) {
	static_assert(std::is_base_of<Container, T>::value, "make_container only accept container types.");

	auto container = std::make_shared<T>(std::forward<Args>(args)...);
	container->init();

	return container;
}

}  // namespace kgr
<|endoftext|>