<commit_before>/***************************************************************************
 *   Copyright (c) 2005 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
# include <qobject.h>
#endif

#include "Workbench.h"
#include <Gui/MenuManager.h>
#include <Gui/ToolBarManager.h>

using namespace PartGui;

#if 0 // needed for Qt's lupdate utility
    qApp->translate("Workbench", "&Part");
    qApp->translate("Workbench", "&Simple");
    qApp->translate("Workbench", "&Parametric");
    qApp->translate("Workbench", "Solids");
    qApp->translate("Workbench", "Part tools");
    qApp->translate("Workbench", "Boolean");
#endif

/// @namespace PartGui @class Workbench
TYPESYSTEM_SOURCE(PartGui::Workbench, Gui::StdWorkbench)

Workbench::Workbench()
{
}

Workbench::~Workbench()
{
}

Gui::MenuItem* Workbench::setupMenuBar() const
{
    Gui::MenuItem* root = StdWorkbench::setupMenuBar();
    Gui::MenuItem* item = root->findItem("&Windows");

    Gui::MenuItem* prim = new Gui::MenuItem;
    prim->setCommand("Primitives");
    *prim << "Part_Box" << "Part_Cylinder" << "Part_Sphere"
          << "Part_Cone" << "Part_Torus";

    Gui::MenuItem* bop = new Gui::MenuItem;
    bop->setCommand("Boolean");
    *bop << "Part_Boolean" << "Part_Cut" << "Part_Fuse" << "Part_Common";

    Gui::MenuItem* join = new Gui::MenuItem;
    join->setCommand("Join");
    *join << "Part_JoinConnect" << "Part_JoinEmbed" << "Part_JoinCutout";

    Gui::MenuItem* split = new Gui::MenuItem;
    split->setCommand("Split");
    *split << "Part_BooleanFragments" << "Part_Slice" << "Part_XOR";

    Gui::MenuItem* compound = new Gui::MenuItem;
    compound->setCommand("Compound");
    *compound << "Part_Compound" << "Part_CompoundFilter";

    Gui::MenuItem* part = new Gui::MenuItem;
    root->insertItem(item, part);
    part->setCommand("&Part");
    *part << "Part_Import" << "Part_Export" << "Separator";
    *part << prim << "Part_Primitives" << "Part_Builder" << "Separator"
          << "Part_ShapeFromMesh" << "Part_MakeSolid" << "Part_ReverseShape"
          << "Part_SimpleCopy" << "Part_RefineShape" << "Part_CheckGeometry"
          << "Separator" << bop << join << split << compound << "Separator"
          << "Part_CrossSections" << "Part_MakeFace" << "Part_Extrude"
          << "Part_Revolve" << "Part_Mirror" << "Part_Fillet" << "Part_Chamfer"
          << "Part_RuledSurface" << "Part_Loft" << "Part_Sweep"
          << "Part_Offset" << "Part_Offset2D" << "Part_Thickness" << "Separator" << "Part_EditAttachment";

    Gui::MenuItem* measure = new Gui::MenuItem;
    root->insertItem(item,measure);
    measure->setCommand("Measure");
    *measure << "Part_Measure_Linear" << "Part_Measure_Angular" << "Separator" << "Part_Measure_Clear_All" << "Part_Measure_Toggle_All" <<
      "Part_Measure_Toggle_3d" << "Part_Measure_Toggle_Delta";

    // leave this for 0.14 until #0000477 is fixed
#if 0
    Gui::MenuItem* view = root->findItem("&View");
    if (view) {
        Gui::MenuItem* appr = view->findItem("Std_RandomColor");
        appr = view->afterItem(appr);
        Gui::MenuItem* face = new Gui::MenuItem();
        face->setCommand("Part_ColorPerFace");
        view->insertItem(appr, face);
    }
#endif

    return root;
}

Gui::ToolBarItem* Workbench::setupToolBars() const
{
    Gui::ToolBarItem* root = StdWorkbench::setupToolBars();

    Gui::ToolBarItem* solids = new Gui::ToolBarItem(root);
    solids->setCommand("Solids");
    *solids << "Part_Box" << "Part_Cylinder" << "Part_Sphere" << "Part_Cone"
            << "Part_Torus" << "Part_Primitives" << "Part_Builder";

    Gui::ToolBarItem* tool = new Gui::ToolBarItem(root);
    tool->setCommand("Part tools");
    *tool << "Part_Extrude" << "Part_Revolve" << "Part_Mirror" << "Part_Fillet"
          << "Part_Chamfer" << "Part_RuledSurface" << "Part_Loft" << "Part_Sweep"
          << "Part_CompOffset" << "Part_Thickness";

    Gui::ToolBarItem* boolop = new Gui::ToolBarItem(root);
    boolop->setCommand("Boolean");
    *boolop << "Part_Boolean" << "Part_Cut" << "Part_Fuse" << "Part_Common"
            << "Part_CompJoinFeatures" << "Part_CompSplitFeatures" << "Part_CheckGeometry" << "Part_Section"
            << "Part_CrossSections";

    Gui::ToolBarItem* measure = new Gui::ToolBarItem(root);
    measure->setCommand("Measure");
    *measure << "Part_Measure_Linear" << "Part_Measure_Angular"  << "Separator" << "Part_Measure_Clear_All" << "Part_Measure_Toggle_All"
             << "Part_Measure_Toggle_3d" << "Part_Measure_Toggle_Delta";

    return root;
}

Gui::ToolBarItem* Workbench::setupCommandBars() const
{
    // Part tools
    Gui::ToolBarItem* root = new Gui::ToolBarItem;
    return root;
}
<commit_msg>fixes #0001955: Part Section not available in the Part menu<commit_after>/***************************************************************************
 *   Copyright (c) 2005 Werner Mayer <wmayer[at]users.sourceforge.net>     *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"

#ifndef _PreComp_
# include <qobject.h>
#endif

#include "Workbench.h"
#include <Gui/MenuManager.h>
#include <Gui/ToolBarManager.h>

using namespace PartGui;

#if 0 // needed for Qt's lupdate utility
    qApp->translate("Workbench", "&Part");
    qApp->translate("Workbench", "&Simple");
    qApp->translate("Workbench", "&Parametric");
    qApp->translate("Workbench", "Solids");
    qApp->translate("Workbench", "Part tools");
    qApp->translate("Workbench", "Boolean");
#endif

/// @namespace PartGui @class Workbench
TYPESYSTEM_SOURCE(PartGui::Workbench, Gui::StdWorkbench)

Workbench::Workbench()
{
}

Workbench::~Workbench()
{
}

Gui::MenuItem* Workbench::setupMenuBar() const
{
    Gui::MenuItem* root = StdWorkbench::setupMenuBar();
    Gui::MenuItem* item = root->findItem("&Windows");

    Gui::MenuItem* prim = new Gui::MenuItem;
    prim->setCommand("Primitives");
    *prim << "Part_Box"
          << "Part_Cylinder"
          << "Part_Sphere"
          << "Part_Cone"
          << "Part_Torus";

    Gui::MenuItem* bop = new Gui::MenuItem;
    bop->setCommand("Boolean");
    *bop << "Part_Boolean"
         << "Part_Cut"
         << "Part_Fuse"
         << "Part_Common";

    Gui::MenuItem* join = new Gui::MenuItem;
    join->setCommand("Join");
    *join << "Part_JoinConnect"
          << "Part_JoinEmbed"
          << "Part_JoinCutout";

    Gui::MenuItem* split = new Gui::MenuItem;
    split->setCommand("Split");
    *split << "Part_BooleanFragments"
           << "Part_Slice"
           << "Part_XOR";

    Gui::MenuItem* compound = new Gui::MenuItem;
    compound->setCommand("Compound");
    *compound << "Part_Compound"
              << "Part_CompoundFilter";

    Gui::MenuItem* part = new Gui::MenuItem;
    root->insertItem(item, part);
    part->setCommand("&Part");
    *part << "Part_Import"
          << "Part_Export"
          << "Separator";
    *part << prim
          << "Part_Primitives"
          << "Part_Builder"
          << "Separator"
          << "Part_ShapeFromMesh"
          << "Part_MakeSolid"
          << "Part_ReverseShape"
          << "Part_SimpleCopy"
          << "Part_RefineShape"
          << "Part_CheckGeometry"
          << "Separator"
          << bop << join << split << compound
          << "Separator"
          << "Part_Section"
          << "Part_CrossSections"
          << "Part_MakeFace"
          << "Part_Extrude"
          << "Part_Revolve"
          << "Part_Mirror"
          << "Part_Fillet"
          << "Part_Chamfer"
          << "Part_RuledSurface"
          << "Part_Loft"
          << "Part_Sweep"
          << "Part_Offset"
          << "Part_Offset2D"
          << "Part_Thickness"
          << "Separator"
          << "Part_EditAttachment";

    Gui::MenuItem* measure = new Gui::MenuItem;
    root->insertItem(item,measure);
    measure->setCommand("Measure");
    *measure << "Part_Measure_Linear"
             << "Part_Measure_Angular"
             << "Separator"
             << "Part_Measure_Clear_All"
             << "Part_Measure_Toggle_All"
             << "Part_Measure_Toggle_3d"
             << "Part_Measure_Toggle_Delta";

    // leave this for 0.14 until #0000477 is fixed
#if 0
    Gui::MenuItem* view = root->findItem("&View");
    if (view) {
        Gui::MenuItem* appr = view->findItem("Std_RandomColor");
        appr = view->afterItem(appr);
        Gui::MenuItem* face = new Gui::MenuItem();
        face->setCommand("Part_ColorPerFace");
        view->insertItem(appr, face);
    }
#endif

    return root;
}

Gui::ToolBarItem* Workbench::setupToolBars() const
{
    Gui::ToolBarItem* root = StdWorkbench::setupToolBars();

    Gui::ToolBarItem* solids = new Gui::ToolBarItem(root);
    solids->setCommand("Solids");
    *solids << "Part_Box"
            << "Part_Cylinder"
            << "Part_Sphere"
            << "Part_Cone"
            << "Part_Torus"
            << "Part_Primitives"
            << "Part_Builder";

    Gui::ToolBarItem* tool = new Gui::ToolBarItem(root);
    tool->setCommand("Part tools");
    *tool << "Part_Extrude"
          << "Part_Revolve"
          << "Part_Mirror"
          << "Part_Fillet"
          << "Part_Chamfer"
          << "Part_RuledSurface"
          << "Part_Loft"
          << "Part_Sweep"
          << "Part_CompOffset"
          << "Part_Thickness";

    Gui::ToolBarItem* boolop = new Gui::ToolBarItem(root);
    boolop->setCommand("Boolean");
    *boolop << "Part_Boolean"
            << "Part_Cut"
            << "Part_Fuse"
            << "Part_Common"
            << "Part_CompJoinFeatures"
            << "Part_CompSplitFeatures"
            << "Part_CheckGeometry"
            << "Part_Section"
            << "Part_CrossSections";

    Gui::ToolBarItem* measure = new Gui::ToolBarItem(root);
    measure->setCommand("Measure");
    *measure << "Part_Measure_Linear"
             << "Part_Measure_Angular"
             << "Separator"
             << "Part_Measure_Clear_All"
             << "Part_Measure_Toggle_All"
             << "Part_Measure_Toggle_3d"
             << "Part_Measure_Toggle_Delta";

    return root;
}

Gui::ToolBarItem* Workbench::setupCommandBars() const
{
    // Part tools
    Gui::ToolBarItem* root = new Gui::ToolBarItem;
    return root;
}
<|endoftext|>


<commit_before>/** @file
    @brief Implementation

    @date 2016

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

// Copyright 2016 Razer 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 "FindDriver.h"

// Library/third-party includes
#include <boost/iostreams/stream.hpp>
#include <boost/process.hpp>
#include <json/reader.h>
#include <json/value.h>
#include <osvr/Util/Finally.h>
#include <osvr/Util/PlatformConfig.h>

// Standard includes
#include <iostream>
#include <limits.h>
#include <vector>

#if _MSC_VER >= 1800
#include <filesystem>
#else
#include <boost/filesystem.hpp>
#endif

#if defined(OSVR_WINDOWS)
#include <shlobj.h>
#endif

#undef VIVELOADER_VERBOSE

using osvr::util::finally;

namespace osvr {
namespace vive {
#if defined(OSVR_WINDOWS)
    static const auto PLATFORM_DIRNAME_BASE = "win";
    static const auto DRIVER_EXTENSION = ".dll";
    static const auto TOOL_EXTENSION = ".exe";
    static const auto PATH_SEP = "\\";
#elif defined(OSVR_MACOSX)
    /// @todo Note that there are no 64-bit steamvr runtimes or drivers on OS X
    static const auto PLATFORM_DIRNAME_BASE = "osx";
    static const auto DRIVER_EXTENSION = ".dylib";
    static const auto TOOL_EXTENSION = "";
    static const auto PATH_SEP = "/";
#elif defined(OSVR_LINUX)
    static const auto PLATFORM_DIRNAME_BASE = "linux";
    static const auto DRIVER_EXTENSION = ".so";
    static const auto TOOL_EXTENSION = "";
    static const auto PATH_SEP = "/";
#else
#error "Sorry, Valve does not produce a SteamVR runtime for your platform."
#endif

#if defined(OSVR_USING_FILESYSTEM_TR2)
    using std::tr2::sys::path;
    using std::tr2::sys::wpath;
    using std::tr2::sys::exists;
#elif defined(OSVR_USING_BOOST_FILESYSTEM)
    using boost::filesystem::path;
    using boost::filesystem::exists;
#endif

    inline std::string getPlatformDirname() {
        return PLATFORM_DIRNAME_BASE +
               std::to_string(sizeof(void *) * CHAR_BIT);

    inline void parsePathConfigFile(std::istream &is, Json::Value &ret) {
        Json::Reader reader;
        if (!reader.parse(is, ret)) {
            std::cerr << "Error parsing file containing path configuration - "
                         "have you run SteamVR yet?"
                      << std::endl;
            std::cerr << reader.getFormattedErrorMessages() << std::endl;
        }
    }
#if defined(OSVR_WINDOWS)

    inline Json::Value getPathConfig() {
        PWSTR outString = nullptr;
        Json::Value ret;
        // It's OK to use Vista+ stuff here, since openvr_api.dll uses Vista+
        // stuff too.
        auto hr =
            SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &outString);
        if (!SUCCEEDED(hr)) {
            std::cerr << "Could not get local app data directory!" << std::endl;
            return ret;
        }
        // Free the string returned when we're all done.
        auto freeString = [&] { CoTaskMemFree(outString); };
        // Build the path to the file.
        auto vrPaths =
            wpath(outString) / wpath(L"openvr") / wpath(L"openvrpaths.vrpath");
        std::ifstream is(vrPaths.string());
        if (!is) {
            std::wcerr << L"Could not open file containing path configuration "
                          L"- have you run SteamVR yet? "
                       << vrPaths << L"\n";
            return ret;
        }
        parsePathConfigFile(is, ret);
        return ret;
    }
#elif defined(OSVR_MACOSX)
    inline Json::Value getPathConfig() {
#error "implementation not complete"
    }
#elif defined(OSVR_LINUX)

    inline Json::Value getPathConfig() {
#error "implementation not complete"
    }
#endif

#if 0
#if defined(OSVR_WINDOWS)
    inline std::vector<std::string> getSteamVRRoots() {
        /// @todo make this better - there's Windows API for that.
        return std::vector<std::string>{
            std::string{"C:\\Program Files\\Steam\\steamapps\\common\\SteamVR"},
            std::string{
                "C:\\Program Files (x86)\\Steam\\steamapps\\common\\SteamVR"}};
    }
#elif defined(OSVR_MACOSX)
    inline std::vector<std::string> getSteamVRRoots() {
#error "implementation not complete"
    }
#elif defined(OSVR_LINUX)

    inline std::vector<std::string> getSteamVRRoots() {
#error "implementation not complete"
    }
#endif
#endif

    inline std::vector<std::string> getSteamVRRoots(Json::Value const &json) {
        std::vector<std::string> ret;
        auto &runtimes = json["runtime"];
        if (!runtimes.isArray()) {
            return ret;
        }
        for (auto &runtime : runtimes) {
            ret.emplace_back(runtime.asString());
        }
        return ret;
    }
    inline std::vector<std::string> getSteamVRRoots() {
        return getSteamVRRoots(getPathConfig());
    }

    inline void computeDriverRootAndFilePath(DriverLocationInfo &info,
                                             std::string const &driver) {
        auto p = path{info.steamVrRoot};
        p /= "drivers";
        p /= driver;
        p /= "bin";
        p /= getPlatformDirname();
        info.driverRoot = p.string();
        p /= ("driver_" + driver + DRIVER_EXTENSION);
        info.driverFile = p.string();
    }

    DriverLocationInfo findDriver(std::string const &driver) {

        DriverLocationInfo info;

        for (auto &root : getSteamVRRoots()) {
            info.steamVrRoot = root;
            info.driverName = driver;

            computeDriverRootAndFilePath(info, driver);
#ifdef VIVELOADER_VERBOSE
            std::cout << "Will try to load driver from:\n"
                      << info.driverFile << std::endl;
            if (exists(path{info.driverRoot})) {
                std::cout << "Driver root exists" << std::endl;
            }
            if (exists(path{info.driverFile})) {
                std::cout << "Driver file exists" << std::endl;
            }
#endif
            if (exists(path{info.driverRoot}) &&
                exists(path{info.driverFile})) {
                info.found = true;
                return info;
            }
        }
        info = DriverLocationInfo{};
        return info;
    }

    std::string getToolLocation(std::string const &toolName,
                                std::string const &steamVrRoot) {
        std::vector<std::string> searchPath;
        if (!steamVrRoot.empty()) {
            searchPath = {steamVrRoot};
        } else {
            searchPath = getSteamVRRoots();
        }

        for (auto &root : searchPath) {
            auto p = path{root};
            p /= "bin";
            p /= getPlatformDirname();
            p /= (toolName + TOOL_EXTENSION);
            if (exists(p)) {
                return p.string();
            }
        }
        return std::string{};
    }
    ConfigDirs findConfigDirs(std::string const & /*steamVrRoot*/,
                              std::string const &driver) {
        ConfigDirs ret;
        auto json = getPathConfig();
        auto const &configLocations = json["config"];
        if (!configLocations.isArray()) {
            return ret;
        }
        for (auto &configDir : configLocations) {
            auto configPath = path{configDir.asString()};
            if (!exists(configPath)) {
                continue;
            }
            ret.rootConfigDir = configPath.string();
            ret.driverConfigDir = (configPath / path{driver}).string();
            ret.valid = true;
            return ret;
        }
        ret = ConfigDirs{};
        return ret;
    }
#if 0
    ConfigDirs findConfigDirs(std::string const &steamVrRoot,
                              std::string const &driver) {
        static const auto LINE_PREFIX = "Config path = ";
        ConfigDirs ret;
        bool foundLine = false;
        auto vrpathregFile =
            osvr::vive::getToolLocation("vrpathreg", steamVrRoot);
        if (vrpathregFile.empty()) {
            return ret;
        }
        std::string pathLine;
        {
            using namespace boost::process;
            using namespace boost::process::initializers;
            using namespace boost::iostreams;
            auto p = create_pipe();
            file_descriptor_sink sink(p.sink, close_handle);
            auto c = execute(run_exe(vrpathregFile),
#ifdef _WIN32

                             show_window(SW_HIDE),
#endif
                             bind_stdout(sink), bind_stderr(sink));

            file_descriptor_source source(p.source, close_handle);
            stream<file_descriptor_source> is(source);

            for (int i = 0; i < 4; ++i) {
                std::getline(is, pathLine);
                if (pathLine.find(LINE_PREFIX) != std::string::npos) {
                    foundLine = true;
                    break;
                }
            }
            wait_for_exit(c);
        }
        if (!foundLine) {
            return ret;
        }
        while (!pathLine.empty() &&
               (pathLine.back() == '\r' || pathLine.back() == '\n')) {
            pathLine.pop_back();
        }

#ifdef VIVELOADER_VERBOSE
        std::cout << "Path line is: " << pathLine << std::endl;
#endif
        auto prefixLoc = pathLine.find(LINE_PREFIX);
        auto sub = pathLine.substr(std::string(LINE_PREFIX).size() + prefixLoc);
#ifdef VIVELOADER_VERBOSE
        std::cout << "substring is: " << sub << std::endl;
#endif
        ret.rootConfigDir = sub;
        ret.driverConfigDir = sub + PATH_SEP + driver;

        if (exists(path{ret.rootConfigDir})) {
#ifdef VIVELOADER_VERBOSE
            std::cout << "root config dir exists" << std::endl;
#endif
            ret.valid = true;
        }

        return ret;
    }
#endif

} // namespace vive
} // namespace osvr
<commit_msg>Remove boost::process-using code from FindDriver<commit_after>/** @file
    @brief Implementation

    @date 2016

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

// Copyright 2016 Razer 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 "FindDriver.h"

// Library/third-party includes
#include <boost/iostreams/stream.hpp>
#include <json/reader.h>
#include <json/value.h>
#include <osvr/Util/Finally.h>
#include <osvr/Util/PlatformConfig.h>

// Standard includes
#include <iostream>
#include <limits.h>
#include <vector>

#if _MSC_VER >= 1800
#include <filesystem>
#else
#include <boost/filesystem.hpp>
#endif

#if defined(OSVR_WINDOWS)
#include <shlobj.h>
#endif

#undef VIVELOADER_VERBOSE

using osvr::util::finally;

namespace osvr {
namespace vive {
#if defined(OSVR_WINDOWS)
    static const auto PLATFORM_DIRNAME_BASE = "win";
    static const auto DRIVER_EXTENSION = ".dll";
    static const auto TOOL_EXTENSION = ".exe";
    static const auto PATH_SEP = "\\";
#elif defined(OSVR_MACOSX)
    /// @todo Note that there are no 64-bit steamvr runtimes or drivers on OS X
    static const auto PLATFORM_DIRNAME_BASE = "osx";
    static const auto DRIVER_EXTENSION = ".dylib";
    static const auto TOOL_EXTENSION = "";
    static const auto PATH_SEP = "/";
#elif defined(OSVR_LINUX)
    static const auto PLATFORM_DIRNAME_BASE = "linux";
    static const auto DRIVER_EXTENSION = ".so";
    static const auto TOOL_EXTENSION = "";
    static const auto PATH_SEP = "/";
#else
#error "Sorry, Valve does not produce a SteamVR runtime for your platform."
#endif

#if defined(OSVR_USING_FILESYSTEM_TR2)
    using std::tr2::sys::path;
    using std::tr2::sys::wpath;
    using std::tr2::sys::exists;
#elif defined(OSVR_USING_BOOST_FILESYSTEM)
    using boost::filesystem::path;
    using boost::filesystem::exists;
#endif

#ifdef OSVR_MACOSX
    inline std::string getPlatformBitSuffix() {
        // they use universal binaries but stick them in "32"
        return "32";
    }
#else
    inline std::string getPlatformBitSuffix() {
        return std::to_string(sizeof(void *) * CHAR_BIT);
    }
#endif

    inline std::string getPlatformDirname() {
        return PLATFORM_DIRNAME_BASE + getPlatformBitSuffix();
    }

    inline void parsePathConfigFile(std::istream &is, Json::Value &ret) {
        Json::Reader reader;
        if (!reader.parse(is, ret)) {
            std::cerr << "Error parsing file containing path configuration - "
                         "have you run SteamVR yet?"
                      << std::endl;
            std::cerr << reader.getFormattedErrorMessages() << std::endl;
        }
    }
#if defined(OSVR_WINDOWS)

    inline Json::Value getPathConfig() {
        PWSTR outString = nullptr;
        Json::Value ret;
        // It's OK to use Vista+ stuff here, since openvr_api.dll uses Vista+
        // stuff too.
        auto hr =
            SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &outString);
        if (!SUCCEEDED(hr)) {
            std::cerr << "Could not get local app data directory!" << std::endl;
            return ret;
        }
        // Free the string returned when we're all done.
        auto freeString = [&] { CoTaskMemFree(outString); };
        // Build the path to the file.
        auto vrPaths =
            wpath(outString) / wpath(L"openvr") / wpath(L"openvrpaths.vrpath");
        std::ifstream is(vrPaths.string());
        if (!is) {
            std::wcerr << L"Could not open file containing path configuration "
                          L"- have you run SteamVR yet? "
                       << vrPaths << L"\n";
            return ret;
        }
        parsePathConfigFile(is, ret);
        return ret;
    }
#elif defined(OSVR_MACOSX)
    inline Json::Value getPathConfig() {
#error "implementation not complete"
    }
#elif defined(OSVR_LINUX)

    inline Json::Value getPathConfig() {
#error "implementation not complete"
    }
#endif

#if 0
#if defined(OSVR_WINDOWS)
    inline std::vector<std::string> getSteamVRRoots() {
        /// @todo make this better - there's Windows API for that.
        return std::vector<std::string>{
            std::string{"C:\\Program Files\\Steam\\steamapps\\common\\SteamVR"},
            std::string{
                "C:\\Program Files (x86)\\Steam\\steamapps\\common\\SteamVR"}};
    }
#elif defined(OSVR_MACOSX)
    inline std::vector<std::string> getSteamVRRoots() {
#error "implementation not complete"
    }
#elif defined(OSVR_LINUX)

    inline std::vector<std::string> getSteamVRRoots() {
#error "implementation not complete"
    }
#endif
#endif

    inline std::vector<std::string> getSteamVRRoots(Json::Value const &json) {
        std::vector<std::string> ret;
        auto &runtimes = json["runtime"];
        if (!runtimes.isArray()) {
            return ret;
        }
        for (auto &runtime : runtimes) {
            ret.emplace_back(runtime.asString());
        }
        return ret;
    }
    inline std::vector<std::string> getSteamVRRoots() {
        return getSteamVRRoots(getPathConfig());
    }

    inline void computeDriverRootAndFilePath(DriverLocationInfo &info,
                                             std::string const &driver) {
        auto p = path{info.steamVrRoot};
        p /= "drivers";
        p /= driver;
        p /= "bin";
        p /= getPlatformDirname();
        info.driverRoot = p.string();
        p /= ("driver_" + driver + DRIVER_EXTENSION);
        info.driverFile = p.string();
    }

    DriverLocationInfo findDriver(std::string const &driver) {

        DriverLocationInfo info;

        for (auto &root : getSteamVRRoots()) {
            info.steamVrRoot = root;
            info.driverName = driver;

            computeDriverRootAndFilePath(info, driver);
#ifdef VIVELOADER_VERBOSE
            std::cout << "Will try to load driver from:\n"
                      << info.driverFile << std::endl;
            if (exists(path{info.driverRoot})) {
                std::cout << "Driver root exists" << std::endl;
            }
            if (exists(path{info.driverFile})) {
                std::cout << "Driver file exists" << std::endl;
            }
#endif
            if (exists(path{info.driverRoot}) &&
                exists(path{info.driverFile})) {
                info.found = true;
                return info;
            }
        }
        info = DriverLocationInfo{};
        return info;
    }

    std::string getToolLocation(std::string const &toolName,
                                std::string const &steamVrRoot) {
        std::vector<std::string> searchPath;
        if (!steamVrRoot.empty()) {
            searchPath = {steamVrRoot};
        } else {
            searchPath = getSteamVRRoots();
        }

        for (auto &root : searchPath) {
            auto p = path{root};
            p /= "bin";
            p /= getPlatformDirname();
            p /= (toolName + TOOL_EXTENSION);
            if (exists(p)) {
                return p.string();
            }
        }
        return std::string{};
    }

    ConfigDirs findConfigDirs(std::string const & /*steamVrRoot*/,
                              std::string const &driver) {
        ConfigDirs ret;
        auto json = getPathConfig();
        auto const &configLocations = json["config"];
        if (!configLocations.isArray()) {
            return ret;
        }
        for (auto &configDir : configLocations) {
            auto configPath = path{configDir.asString()};
            if (!exists(configPath)) {
                continue;
            }
            ret.rootConfigDir = configPath.string();
            ret.driverConfigDir = (configPath / path{driver}).string();
            ret.valid = true;
            return ret;
        }
        ret = ConfigDirs{};
        return ret;
    }

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


<commit_before>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, development version     *
*                (c) 2006-2016 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This program is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU General Public License as published by the Free  *
* Software Foundation; either version 2 of the License, or (at your option)   *
* any later version.                                                          *
*                                                                             *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    *
* more details.                                                               *
*                                                                             *
* You should have received a copy of the GNU General Public License along     *
* with this program; if not, write to the Free Software Foundation, Inc., 51  *
* Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.                   *
*******************************************************************************
*                            SOFA :: Applications                             *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#include <sofa/helper/io/ImagePNG.h>
#include <sofa/helper/system/FileRepository.h>

#include <gtest/gtest.h>

namespace sofa {

class ImagePNG_test : public ::testing::Test
{
protected:
    ImagePNG_test() {}

    void SetUp()
    {
        sofa::helper::system::DataRepository.addFirstPath(FRAMEWORK_TEST_RESOURCES_DIR);
    }
    void TearDown()
    {
        sofa::helper::system::DataRepository.removePath(FRAMEWORK_TEST_RESOURCES_DIR);
    }

    struct ImagePNGTestData
    {
        std::string filename;
        unsigned int width;
        unsigned int height;
        const unsigned char* data;

        ImagePNGTestData(const std::string& filename, unsigned int width, unsigned int height
            , unsigned int bpp, const unsigned char* data)
            : filename(filename), width(width), height(height), data(data)
        {

        }

        void testBench()
        {
            sofa::helper::io::ImagePNG img;

            EXPECT_TRUE(img.load(filename));
            EXPECT_EQ(width, img.getWidth());
            EXPECT_EQ(height, img.getHeight());
            EXPECT_EQ(width*height, img.getPixelCount());

            const unsigned char* testdata = img.getPixels();

            EXPECT_TRUE(0 == std::memcmp(data, testdata, sizeof(data)));
        }
    };

};

TEST_F(ImagePNG_test, ImagePNG_NoFile)
{
    sofa::helper::io::ImagePNG imgNoFile;
    EXPECT_FALSE(imgNoFile.load("image/randomnamewhichdoesnotexist.png"));
}

TEST_F(ImagePNG_test, ImagePNG_NoImg)
{
    sofa::helper::io::ImagePNG imgNoImage;
    EXPECT_FALSE(imgNoImage.load("image/imagetest_noimage.png"));
}

TEST_F(ImagePNG_test, ImagePNG_BlackWhite)
{
    unsigned int width = 800;
    unsigned int height = 600;
    unsigned int bpp = 3;
    unsigned int totalsize = width*height*bpp;

    unsigned char* imgdata = new unsigned char[totalsize];
    //half image (800x300) is black the other one is white
    std::fill(imgdata, imgdata + (800*300*3), 0);
    std::fill(imgdata + (800 * 300 * 3), imgdata + (800 * 600 * 3), 255);

    ImagePNGTestData imgBW("image/imagetest_blackwhite.png", width, height, bpp, imgdata);
    imgBW.testBench();
}

}// namespace sofa
<commit_msg>[SofaKernel] Framework_test: fixing ImagePNG_test<commit_after>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, development version     *
*                (c) 2006-2016 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This program is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU General Public License as published by the Free  *
* Software Foundation; either version 2 of the License, or (at your option)   *
* any later version.                                                          *
*                                                                             *
* This program is distributed in the hope that it will be useful, but WITHOUT *
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    *
* more details.                                                               *
*                                                                             *
* You should have received a copy of the GNU General Public License along     *
* with this program; if not, write to the Free Software Foundation, Inc., 51  *
* Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.                   *
*******************************************************************************
*                            SOFA :: Applications                             *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/
#include <sofa/helper/io/ImagePNG.h>
#include <sofa/helper/system/FileRepository.h>
#include <cstring>

#include <gtest/gtest.h>

namespace sofa {

class ImagePNG_test : public ::testing::Test
{
protected:
    ImagePNG_test() {}

    void SetUp()
    {
        sofa::helper::system::DataRepository.addFirstPath(FRAMEWORK_TEST_RESOURCES_DIR);
    }
    void TearDown()
    {
        sofa::helper::system::DataRepository.removePath(FRAMEWORK_TEST_RESOURCES_DIR);
    }

    struct ImagePNGTestData
    {
        std::string filename;
        unsigned int width;
        unsigned int height;
        unsigned int bpp;
        const unsigned char* data;

        ImagePNGTestData(const std::string& filename, unsigned int width, unsigned int height
            , unsigned int bpp, const unsigned char* data)
            : filename(filename), width(width), height(height), bpp(bpp), data(data)
        {

        }

        void testBench()
        {
            sofa::helper::io::ImagePNG img;

            EXPECT_TRUE(img.load(filename));
            EXPECT_EQ(width, img.getWidth());
            EXPECT_EQ(height, img.getHeight());
            EXPECT_EQ(width*height, img.getPixelCount());
            EXPECT_EQ(bpp, img.getBytesPerPixel());

            const unsigned char* testdata = img.getPixels();

            EXPECT_TRUE(0 == std::memcmp(data, testdata, width*height*bpp));
        }
    };

};

TEST_F(ImagePNG_test, ImagePNG_NoFile)
{
    sofa::helper::io::ImagePNG imgNoFile;
    EXPECT_FALSE(imgNoFile.load("image/randomnamewhichdoesnotexist.png"));
}

TEST_F(ImagePNG_test, ImagePNG_NoImg)
{
    sofa::helper::io::ImagePNG imgNoImage;
    EXPECT_FALSE(imgNoImage.load("image/imagetest_noimage.png"));
}

TEST_F(ImagePNG_test, ImagePNG_BlackWhite)
{
    unsigned int width = 800;
    unsigned int height = 600;
    unsigned int bpp = 3;
    unsigned int totalsize = width*height*bpp;

    unsigned char* imgdata = new unsigned char[totalsize];
    //half image (800x300) is black the other one is white
    std::fill(imgdata, imgdata + (800*300*3), 0);
    std::fill(imgdata + (800 * 300 * 3), imgdata + (800 * 600 * 3), 255);

    ImagePNGTestData imgBW("image/imagetest_blackwhite.png", width, height, bpp, imgdata);
    imgBW.testBench();
}

}// namespace sofa
<|endoftext|>


<commit_before>/*****************************************************************************/
/**
 *  @file   NormalizedDeviceCoordinate.cpp
 *  @author Naohisa Sakamoto
 */
/*----------------------------------------------------------------------------
 *
 *  Copyright (c) Visualization Laboratory, Kyoto University.
 *  All rights reserved.
 *  See http://www.viz.media.kyoto-u.ac.jp/kvs/copyright/ for details.
 *
 *  $Id$
 */
/*****************************************************************************/
#include "NormalizedDeviceCoordinate.h"
#include "WindowCoordinate.h"
#include "CameraCoordinate.h"
#include <kvs/Camera>

namespace kvs
{

/*===========================================================================*/
/**
 *  @brief  Constructs a new NormalizedDeviceCoordinate class.
 *  @param  position [in] position in normalized device coordinates
 */
/*===========================================================================*/
NormalizedDeviceCoordinate::NormalizedDeviceCoordinate( const kvs::Vec3& position ):
    m_position( position )
{
}

/*===========================================================================*/
/**
 *  @brief  Transforms normalized device coordinates to world coordinates.
 *  @param  x [in] x coordinate value of left corner of the viewport
 *  @param  y [in] y coordinate value of left corner of the viewport
 *  @param  width [in] width of the viewport
 *  @param  height [in] height of the viewport
 *  @return world coordinates
 */
/*===========================================================================*/
const WindowCoordinate NormalizedDeviceCoordinate::toWindowCoordinate(
    const int x,
    const int y,
    const size_t width,
    const size_t height ) const
{
    const float px = ( m_position[0] + 1.0f ) * width * 0.5f + x;
    const float py = ( m_position[1] + 1.0f ) * height * 0.5f + y;
    const float pz = WindowCoordinate::CalculateDepth( ( m_position[2] + 1.0f ) / 2.0f );
    const kvs::Vec3 position( px, py, pz );
    return WindowCoordinate( position, x, y, width, height );
}

/*===========================================================================*/
/**
 *  @brief  Transforms normalized device coordinates to camera coordinates.
 *  @param  camera [in] pointer to a camera defines camera coordinates
 *  @return camera coordinates
 */
/*===========================================================================*/
const CameraCoordinate NormalizedDeviceCoordinate::toCameraCoordinate( const kvs::Camera* camera ) const
{
    const kvs::Xform xform( camera->projectionMatrix() * camera->viewingMatrix() );
    const kvs::Vec3 position = xform.inverse().project( m_position );
    return CameraCoordinate( position, camera );
}

} // end of namespace kvs
<commit_msg>Fixed a problem.<commit_after>/*****************************************************************************/
/**
 *  @file   NormalizedDeviceCoordinate.cpp
 *  @author Naohisa Sakamoto
 */
/*----------------------------------------------------------------------------
 *
 *  Copyright (c) Visualization Laboratory, Kyoto University.
 *  All rights reserved.
 *  See http://www.viz.media.kyoto-u.ac.jp/kvs/copyright/ for details.
 *
 *  $Id$
 */
/*****************************************************************************/
#include "NormalizedDeviceCoordinate.h"
#include "WindowCoordinate.h"
#include "CameraCoordinate.h"
#include <kvs/Camera>

namespace kvs
{

/*===========================================================================*/
/**
 *  @brief  Constructs a new NormalizedDeviceCoordinate class.
 *  @param  position [in] position in normalized device coordinates
 */
/*===========================================================================*/
NormalizedDeviceCoordinate::NormalizedDeviceCoordinate( const kvs::Vec3& position ):
    m_position( position )
{
}

/*===========================================================================*/
/**
 *  @brief  Transforms normalized device coordinates to world coordinates.
 *  @param  x [in] x coordinate value of left corner of the viewport
 *  @param  y [in] y coordinate value of left corner of the viewport
 *  @param  width [in] width of the viewport
 *  @param  height [in] height of the viewport
 *  @return world coordinates
 */
/*===========================================================================*/
const WindowCoordinate NormalizedDeviceCoordinate::toWindowCoordinate(
    const int x,
    const int y,
    const size_t width,
    const size_t height ) const
{
    const float px = ( m_position[0] + 1.0f ) * width * 0.5f + x;
    const float py = ( m_position[1] + 1.0f ) * height * 0.5f + y;
    const float pz = WindowCoordinate::CalculateDepth( ( m_position[2] + 1.0f ) / 2.0f );
    const kvs::Vec3 position( px, py, pz );
    return WindowCoordinate( position, x, y, width, height );
}

/*===========================================================================*/
/**
 *  @brief  Transforms normalized device coordinates to camera coordinates.
 *  @param  camera [in] pointer to a camera defines camera coordinates
 *  @return camera coordinates
 */
/*===========================================================================*/
const CameraCoordinate NormalizedDeviceCoordinate::toCameraCoordinate( const kvs::Camera* camera ) const
{
    const kvs::Xform xform( camera->projectionMatrix() );
    const kvs::Vec3 position = xform.inverse().project( m_position );
    return CameraCoordinate( position, camera );
}

} // end of namespace kvs
<|endoftext|>


<commit_before>#include <catch.hpp>

#include <lua.hpp>
#include <luwra.hpp>

#include <cstring>
#include <string>
#include <utility>
#include <type_traits>

template <typename I>
struct NumericTest {
	static
	void test(lua_State* state) {
		const I max_value = std::numeric_limits<I>::max();
		const I min_value = std::numeric_limits<I>::lowest();
		const I avg_value = (max_value + min_value) / 2;

		// Largest value
		CHECK(luwra::push(state, max_value) == 1);
		CHECK(luwra::read<I>(state, -1) == max_value);

		// Lowest value
		CHECK(luwra::push(state, min_value) == 1);
		CHECK(luwra::read<I>(state, -1) == min_value);

		// Average value
		CHECK(luwra::push(state, avg_value) == 1);
		CHECK(luwra::read<I>(state, -1) == avg_value);
	}
};

struct TautologyTest {
	static
	void test(lua_State*) {}
};

template <typename B, typename I>
using SelectNumericTest =
	typename std::conditional<
		luwra::internal::NumericContainedValueBase<I, B>::qualifies,
		NumericTest<I>,
		TautologyTest
	>::type;

TEST_CASE("types_numeric") {
	lua_State* state = luaL_newstate();

	// Integer-based types
	SelectNumericTest<lua_Integer, signed char>::test(state);
	SelectNumericTest<lua_Integer, unsigned char>::test(state);
	SelectNumericTest<lua_Integer, signed short>::test(state);
	SelectNumericTest<lua_Integer, unsigned short>::test(state);
	SelectNumericTest<lua_Integer, signed int>::test(state);
	SelectNumericTest<lua_Integer, unsigned int>::test(state);
	SelectNumericTest<lua_Integer, signed long int>::test(state);
	SelectNumericTest<lua_Integer, unsigned long int>::test(state);
	SelectNumericTest<lua_Integer, signed long long int>::test(state);
	SelectNumericTest<lua_Integer, unsigned long long int>::test(state);

	// Number-based types
	SelectNumericTest<lua_Number, float>::test(state);
	SelectNumericTest<lua_Number, double>::test(state);
	SelectNumericTest<lua_Number, long double>::test(state);

	lua_close(state);
}

TEST_CASE("types_string") {
	lua_State* state = luaL_newstate();

	const char* test_cstr = "Luwra Test String";
	std::string test_str(test_cstr);

	// Safety first
	REQUIRE(test_str == test_cstr);

	// Push both strings
	REQUIRE(luwra::push(state, test_cstr) == 1);
	REQUIRE(luwra::push(state, test_str) == 1);

	// They must be equal to Lua
	REQUIRE(luwra::equal(state, -1, -2));

	// Extraction as C string must not change the string's value
	const char* l_cstr1 = luwra::read<const char*>(state, -1);
	const char* l_cstr2 = luwra::read<const char*>(state, -2);

	REQUIRE(std::strcmp(test_cstr,        l_cstr1) == 0);
	REQUIRE(std::strcmp(test_cstr,        l_cstr2) == 0);
	REQUIRE(std::strcmp(test_str.c_str(), l_cstr1) == 0);
	REQUIRE(std::strcmp(test_str.c_str(), l_cstr2) == 0);
	REQUIRE(std::strcmp(l_cstr1,          l_cstr2) == 0);

	// Extraction as C++ string must not change the string's value
	std::string l_str1 = luwra::read<std::string>(state, -1);
	std::string l_str2 = luwra::read<std::string>(state, -2);

	REQUIRE(l_str1   == test_cstr);
	REQUIRE(l_str2   == test_cstr);
	REQUIRE(test_str == l_str1);
	REQUIRE(test_str == l_str2);
	REQUIRE(l_str1   == l_str2);

	lua_close(state);
}

TEST_CASE("types_tuple") {
	lua_State* state = luaL_newstate();

	int a = 13;
	std::string b("Hello");
	float c = 0.37;

	// Push normal tuple
	auto tuple = std::make_tuple(a, b, c);
	REQUIRE(luwra::push(state, tuple) == 3);

	// Push nested tuple
	auto tuple_nested = std::make_tuple(a, b, c, tuple);
	REQUIRE(luwra::push(state, tuple_nested) == 6);

	lua_close(state);
}

TEST_CASE("types_bool") {
	lua_State* state = luaL_newstate();

	bool value = true;

	REQUIRE(luwra::push(state, value) == 1);
	REQUIRE(luwra::read<bool>(state, -1) == value);

	lua_close(state);
}
<commit_msg>What are parentheses?<commit_after>#include <catch.hpp>

#include <lua.hpp>
#include <luwra.hpp>

#include <cstring>
#include <string>
#include <utility>
#include <type_traits>

template <typename I>
struct NumericTest {
	static
	void test(lua_State* state) {
		const I max_value = std::numeric_limits<I>::max();
		const I min_value = std::numeric_limits<I>::lowest();
		const I avg_value = (max_value + min_value) / 2;

		// Largest value
		CHECK((luwra::push(state, max_value) == 1));
		CHECK((luwra::read<I>(state, -1) == max_value));

		// Lowest value
		CHECK((luwra::push(state, min_value) == 1));
		CHECK((luwra::read<I>(state, -1) == min_value));

		// Average value
		CHECK((luwra::push(state, avg_value) == 1));
		CHECK((luwra::read<I>(state, -1) == avg_value));
	}
};

struct TautologyTest {
	static
	void test(lua_State*) {}
};

template <typename B, typename I>
using SelectNumericTest =
	typename std::conditional<
		luwra::internal::NumericContainedValueBase<I, B>::qualifies,
		NumericTest<I>,
		TautologyTest
	>::type;

TEST_CASE("types_numeric") {
	lua_State* state = luaL_newstate();

	// Integer-based types
	SelectNumericTest<lua_Integer, signed char>::test(state);
	SelectNumericTest<lua_Integer, unsigned char>::test(state);
	SelectNumericTest<lua_Integer, signed short>::test(state);
	SelectNumericTest<lua_Integer, unsigned short>::test(state);
	SelectNumericTest<lua_Integer, signed int>::test(state);
	SelectNumericTest<lua_Integer, unsigned int>::test(state);
	SelectNumericTest<lua_Integer, signed long int>::test(state);
	SelectNumericTest<lua_Integer, unsigned long int>::test(state);
	SelectNumericTest<lua_Integer, signed long long int>::test(state);
	SelectNumericTest<lua_Integer, unsigned long long int>::test(state);

	// Number-based types
	SelectNumericTest<lua_Number, float>::test(state);
	SelectNumericTest<lua_Number, double>::test(state);
	SelectNumericTest<lua_Number, long double>::test(state);

	lua_close(state);
}

TEST_CASE("types_string") {
	lua_State* state = luaL_newstate();

	const char* test_cstr = "Luwra Test String";
	std::string test_str(test_cstr);

	// Safety first
	REQUIRE(test_str == test_cstr);

	// Push both strings
	REQUIRE(luwra::push(state, test_cstr) == 1);
	REQUIRE(luwra::push(state, test_str) == 1);

	// They must be equal to Lua
	REQUIRE(luwra::equal(state, -1, -2));

	// Extraction as C string must not change the string's value
	const char* l_cstr1 = luwra::read<const char*>(state, -1);
	const char* l_cstr2 = luwra::read<const char*>(state, -2);

	REQUIRE(std::strcmp(test_cstr,        l_cstr1) == 0);
	REQUIRE(std::strcmp(test_cstr,        l_cstr2) == 0);
	REQUIRE(std::strcmp(test_str.c_str(), l_cstr1) == 0);
	REQUIRE(std::strcmp(test_str.c_str(), l_cstr2) == 0);
	REQUIRE(std::strcmp(l_cstr1,          l_cstr2) == 0);

	// Extraction as C++ string must not change the string's value
	std::string l_str1 = luwra::read<std::string>(state, -1);
	std::string l_str2 = luwra::read<std::string>(state, -2);

	REQUIRE(l_str1   == test_cstr);
	REQUIRE(l_str2   == test_cstr);
	REQUIRE(test_str == l_str1);
	REQUIRE(test_str == l_str2);
	REQUIRE(l_str1   == l_str2);

	lua_close(state);
}

TEST_CASE("types_tuple") {
	lua_State* state = luaL_newstate();

	int a = 13;
	std::string b("Hello");
	float c = 0.37;

	// Push normal tuple
	auto tuple = std::make_tuple(a, b, c);
	REQUIRE(luwra::push(state, tuple) == 3);

	// Push nested tuple
	auto tuple_nested = std::make_tuple(a, b, c, tuple);
	REQUIRE(luwra::push(state, tuple_nested) == 6);

	lua_close(state);
}

TEST_CASE("types_bool") {
	lua_State* state = luaL_newstate();

	bool value = true;

	REQUIRE(luwra::push(state, value) == 1);
	REQUIRE(luwra::read<bool>(state, -1) == value);

	lua_close(state);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 Mohammad Mehdi Saboorian
 *
 * This is part of moor, a wrapper for libarchive
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include "archive_writer.hpp"
#include "memory_writer_callback.hpp"

#include <archive.h>
#include <archive_entry.h>

#include <fstream>
#include <stdexcept>
#include <system_error>

#include <sys/types.h>
#include <sys/stat.h>

using namespace moor;

namespace
{
  class ScopedReadDisk
  {
  private:
    archive* m_archive;

  public:
    ScopedReadDisk()
      : m_archive(archive_read_disk_new())
    {
        if (!m_archive)
        {
            throw std::bad_alloc();
        }
    }

    ~ScopedReadDisk()
    {
      archive_read_close(m_archive);
      archive_read_free(m_archive);
    }

    operator archive*()
    {
      return m_archive;
    }

    operator const archive*() const
    {
      return m_archive;
    }
  };
}

void ArchiveWriter::checkError(const int err_code,
                               const bool close_before_throw)
{
  int archiveErrno = 0;
  const char* errStr = nullptr;
  if (err_code == ARCHIVE_FATAL)
  {
      archiveErrno = archive_errno(m_archive);
      errStr = archive_error_string(m_archive);
      if (close_before_throw)
      {
          close();
      }
  }

  if (err_code != ARCHIVE_OK && err_code != ARCHIVE_WARN)
  {
    throw std::system_error(archiveErrno,
                            std::generic_category(),
                            errStr ? errStr : "");
  }
}

ArchiveWriter::ArchiveWriter(const std::string& archive_file_name_,
                             const Format& format_,
                             const Filter& filter_)
  : Archive(archive_write_new(), archive_file_name_),
    m_entry(archive_entry_new()),
    m_format(format_),
    m_filter(filter_),
    m_open(true)
{
  // Set archive format
  checkError(archive_write_set_format(m_archive, (int) m_format), true);

  // Set archive compression
  checkError(archive_write_add_filter(m_archive, (int) m_filter), true);
  checkError(archive_write_open_filename(m_archive, cfilename()), true);
}

ArchiveWriter::ArchiveWriter(std::vector<unsigned char>& out_buffer_,
                             const Format& format_,
                             const Filter& filter_)
  : Archive(archive_write_new()),
    m_entry(archive_entry_new()),
    m_format(format_),
    m_filter(filter_),
    m_open(true)
{
  // Set archive format
  checkError(archive_write_set_format(m_archive, static_cast<int>(m_format)), true);

  // Set archive filter
  checkError(archive_write_add_filter(m_archive, static_cast<int>(m_filter)), true);
  checkError(write_open_memory(m_archive, &out_buffer_), true);
}

ArchiveWriter::ArchiveWriter(unsigned char* out_buffer_,
                             size_t* size_,
                             const Format& format_,
                             const Filter& filter_)
  : Archive(archive_write_new()),
    m_entry(archive_entry_new()),
    m_format(format_),
    m_filter(filter_),
    m_open(true)
{
  // Set archive format
  checkError(archive_write_set_format(m_archive, static_cast<int>(m_format)), true);

  // Set archive filter
  checkError(archive_write_add_filter(m_archive, static_cast<int>(m_filter)), true);
  checkError(archive_write_open_memory(m_archive, out_buffer_, *size_, size_), true);
}

ArchiveWriter::~ArchiveWriter()
{
  close();
}

void ArchiveWriter::addHeader(const std::string& entry_name_,
                              const FileType entry_type_,
                              const long long size_,
                              const int permission_)
{
  m_entry = archive_entry_clear(m_entry);
  archive_entry_set_pathname(m_entry, entry_name_.c_str());
  archive_entry_set_perm(m_entry, permission_);
  archive_entry_set_filetype(m_entry, static_cast<int>(entry_type_));
  archive_entry_set_size(m_entry, size_);
  checkError(archive_write_header(m_archive, m_entry));
}

void ArchiveWriter::addHeader(const std::string& filePath, const struct stat* statBuf)
{
  ScopedReadDisk a;

  m_entry = archive_entry_clear(m_entry);
  archive_entry_set_pathname(m_entry, filePath.c_str());
  checkError(archive_read_disk_entry_from_file(a, m_entry, -1, statBuf));
  checkError(archive_write_header(m_archive, m_entry));
}

void ArchiveWriter::addContent(const char b)
{
  archive_write_data(m_archive, &b, 1);
}

void ArchiveWriter::addContent(const void* data, const unsigned long long size)
{
  archive_write_data(m_archive, data, size);
}

void ArchiveWriter::addFinish()
{
  archive_write_finish_entry(m_archive);
}

void ArchiveWriter::addFile(const std::string& file_path)
{
  struct stat file_stat;
  if (stat(file_path.c_str(), &file_stat) < 0)
  {
      throw std::system_error(std::error_code(errno, std::generic_category()));
  }

  addHeader(file_path, &file_stat);

  if (!S_ISREG(file_stat.st_mode))
  {
    throw std::system_error(std::make_error_code(std::errc::not_supported));
  }

  std::fstream entry_file(file_path, std::ios::in);
  char buf[8192];
  while (entry_file.good())
  {
    entry_file.read(buf, sizeof(buf));
    archive_write_data(m_archive, buf, static_cast<size_t>(entry_file.gcount()));
  }
  entry_file.close();

  addFinish();
}

void ArchiveWriter::addFile(const std::string& entry_name,
                            const void* data,
                            unsigned long long size)
{
  addHeader(entry_name, FileType::Regular, size);
  addContent(data, size);
  addFinish();
}

void ArchiveWriter::addDirectory(const std::string& directory_name)
{
  addHeader(directory_name, FileType::Directory, 0777);
  addFinish();
}

void ArchiveWriter::close()
{
  if (m_open)
  {
    m_open = false;

    if (m_archive)
    {
      archive_write_close(m_archive);
      archive_write_free(m_archive);
    }

    if (m_entry)
    {
      archive_entry_free(m_entry);
    }
  }
}
<commit_msg>Less C-style casts<commit_after>/*
 * Copyright (c) 2013 Mohammad Mehdi Saboorian
 *
 * This is part of moor, a wrapper for libarchive
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include "archive_writer.hpp"
#include "memory_writer_callback.hpp"

#include <archive.h>
#include <archive_entry.h>

#include <fstream>
#include <stdexcept>
#include <system_error>

#include <sys/types.h>
#include <sys/stat.h>

using namespace moor;

namespace
{
  class ScopedReadDisk
  {
  private:
    archive* m_archive;

  public:
    ScopedReadDisk()
      : m_archive(archive_read_disk_new())
    {
        if (!m_archive)
        {
            throw std::bad_alloc();
        }
    }

    ~ScopedReadDisk()
    {
      archive_read_close(m_archive);
      archive_read_free(m_archive);
    }

    operator archive*()
    {
      return m_archive;
    }

    operator const archive*() const
    {
      return m_archive;
    }
  };
}

void ArchiveWriter::checkError(const int err_code,
                               const bool close_before_throw)
{
  int archiveErrno = 0;
  const char* errStr = nullptr;
  if (err_code == ARCHIVE_FATAL)
  {
      archiveErrno = archive_errno(m_archive);
      errStr = archive_error_string(m_archive);
      if (close_before_throw)
      {
          close();
      }
  }

  if (err_code != ARCHIVE_OK && err_code != ARCHIVE_WARN)
  {
    throw std::system_error(archiveErrno,
                            std::generic_category(),
                            errStr ? errStr : "");
  }
}

ArchiveWriter::ArchiveWriter(const std::string& archive_file_name_,
                             const Format& format_,
                             const Filter& filter_)
  : Archive(archive_write_new(), archive_file_name_),
    m_entry(archive_entry_new()),
    m_format(format_),
    m_filter(filter_),
    m_open(true)
{
  // Set archive format
  checkError(archive_write_set_format(m_archive, static_cast<int>(m_format)), true);

  // Set archive compression
  checkError(archive_write_add_filter(m_archive, static_cast<int>(m_filter)), true);
  checkError(archive_write_open_filename(m_archive, cfilename()), true);
}

ArchiveWriter::ArchiveWriter(std::vector<unsigned char>& out_buffer_,
                             const Format& format_,
                             const Filter& filter_)
  : Archive(archive_write_new()),
    m_entry(archive_entry_new()),
    m_format(format_),
    m_filter(filter_),
    m_open(true)
{
  // Set archive format
  checkError(archive_write_set_format(m_archive, static_cast<int>(m_format)), true);

  // Set archive filter
  checkError(archive_write_add_filter(m_archive, static_cast<int>(m_filter)), true);
  checkError(write_open_memory(m_archive, &out_buffer_), true);
}

ArchiveWriter::ArchiveWriter(unsigned char* out_buffer_,
                             size_t* size_,
                             const Format& format_,
                             const Filter& filter_)
  : Archive(archive_write_new()),
    m_entry(archive_entry_new()),
    m_format(format_),
    m_filter(filter_),
    m_open(true)
{
  // Set archive format
  checkError(archive_write_set_format(m_archive, static_cast<int>(m_format)), true);

  // Set archive filter
  checkError(archive_write_add_filter(m_archive, static_cast<int>(m_filter)), true);
  checkError(archive_write_open_memory(m_archive, out_buffer_, *size_, size_), true);
}

ArchiveWriter::~ArchiveWriter()
{
  close();
}

void ArchiveWriter::addHeader(const std::string& entry_name_,
                              const FileType entry_type_,
                              const long long size_,
                              const int permission_)
{
  m_entry = archive_entry_clear(m_entry);
  archive_entry_set_pathname(m_entry, entry_name_.c_str());
  archive_entry_set_perm(m_entry, permission_);
  archive_entry_set_filetype(m_entry, static_cast<int>(entry_type_));
  archive_entry_set_size(m_entry, size_);
  checkError(archive_write_header(m_archive, m_entry));
}

void ArchiveWriter::addHeader(const std::string& filePath, const struct stat* statBuf)
{
  ScopedReadDisk a;

  m_entry = archive_entry_clear(m_entry);
  archive_entry_set_pathname(m_entry, filePath.c_str());
  checkError(archive_read_disk_entry_from_file(a, m_entry, -1, statBuf));
  checkError(archive_write_header(m_archive, m_entry));
}

void ArchiveWriter::addContent(const char b)
{
  archive_write_data(m_archive, &b, 1);
}

void ArchiveWriter::addContent(const void* data, const unsigned long long size)
{
  archive_write_data(m_archive, data, size);
}

void ArchiveWriter::addFinish()
{
  archive_write_finish_entry(m_archive);
}

void ArchiveWriter::addFile(const std::string& file_path)
{
  struct stat file_stat;
  if (stat(file_path.c_str(), &file_stat) < 0)
  {
      throw std::system_error(std::error_code(errno, std::generic_category()));
  }

  addHeader(file_path, &file_stat);

  if (!S_ISREG(file_stat.st_mode))
  {
    throw std::system_error(std::make_error_code(std::errc::not_supported));
  }

  std::fstream entry_file(file_path, std::ios::in);
  char buf[8192];
  while (entry_file.good())
  {
    entry_file.read(buf, sizeof(buf));
    archive_write_data(m_archive, buf, static_cast<size_t>(entry_file.gcount()));
  }
  entry_file.close();

  addFinish();
}

void ArchiveWriter::addFile(const std::string& entry_name,
                            const void* data,
                            unsigned long long size)
{
  addHeader(entry_name, FileType::Regular, size);
  addContent(data, size);
  addFinish();
}

void ArchiveWriter::addDirectory(const std::string& directory_name)
{
  addHeader(directory_name, FileType::Directory, 0777);
  addFinish();
}

void ArchiveWriter::close()
{
  if (m_open)
  {
    m_open = false;

    if (m_archive)
    {
      archive_write_close(m_archive);
      archive_write_free(m_archive);
    }

    if (m_entry)
    {
      archive_entry_free(m_entry);
    }
  }
}
<|endoftext|>


<commit_before>#include "catch.hpp"

#include <lua.hpp>
#include <luwra.hpp>

#include <cstring>
#include <string>
#include <utility>
#include <type_traits>

template <typename I>
struct NumericTest {
	static
	void test(lua_State* state) {
		const I max_value = std::numeric_limits<I>::max();
		const I min_value = std::numeric_limits<I>::lowest();
		const I avg_value = (max_value + min_value) / 2;

		// Largest value
		REQUIRE(luwra::Value<I>::push(state, max_value) == 1);
		REQUIRE(luwra::Value<I>::read(state, -1) == max_value);
		lua_pop(state, 1);

		// Lowest value
		REQUIRE(luwra::Value<I>::push(state, min_value) == 1);
		REQUIRE(luwra::Value<I>::read(state, -1) == min_value);
		lua_pop(state, 1);

		// Average value
		REQUIRE(luwra::Value<I>::push(state, avg_value) == 1);
		REQUIRE(luwra::Value<I>::read(state, -1) == avg_value);
		lua_pop(state, 1);
	}
};

struct TautologyTest {
	static
	void test(lua_State*) {}
};

template <typename B, typename I>
using SelectNumericTest =
	typename std::conditional<
		luwra::internal::NumericContainedValueBase<I, B>::qualifies,
		NumericTest<I>,
		TautologyTest
	>::type;

TEST_CASE("Test Value specialization for numeric C types", "types_numeric") {
	lua_State* state = luaL_newstate();

	// Integer-based types
	SelectNumericTest<lua_Integer, signed short>::test(state);
	SelectNumericTest<lua_Integer, unsigned short>::test(state);
	SelectNumericTest<lua_Integer, signed int>::test(state);
	SelectNumericTest<lua_Integer, unsigned int>::test(state);
	SelectNumericTest<lua_Integer, signed long int>::test(state);
	SelectNumericTest<lua_Integer, unsigned long int>::test(state);
	SelectNumericTest<lua_Integer, signed long long int>::test(state);
	SelectNumericTest<lua_Integer, unsigned long long int>::test(state);

	// Number-based types
	SelectNumericTest<lua_Number, float>::test(state);
	SelectNumericTest<lua_Number, double>::test(state);
	SelectNumericTest<lua_Number, long double>::test(state);

	lua_close(state);
}

TEST_CASE("Test Value specialization for string types", "types_string") {
	lua_State* state = luaL_newstate();

	const char* test_cstr = "Luwra Test String";
	std::string test_str(test_cstr);

	// Safety first
	REQUIRE(test_str == test_cstr);

	// Push both strings
	REQUIRE(luwra::Value<const char*>::push(state, test_cstr) == 1);
	REQUIRE(luwra::Value<std::string>::push(state, test_str) == 1);

	// They must be equal to Lua
	REQUIRE(lua_compare(state, -1, -2, LUA_OPEQ));

	// Extraction as C string must not change the string's value
	const char* l_cstr1 = luwra::Value<const char*>::read(state, -1);
	const char* l_cstr2 = luwra::Value<const char*>::read(state, -2);

	REQUIRE(std::strcmp(test_cstr, l_cstr1) == 0);
	REQUIRE(std::strcmp(test_cstr, l_cstr2) == 0);
	REQUIRE(std::strcmp(test_str.c_str(), l_cstr1) == 0);
	REQUIRE(std::strcmp(test_str.c_str(), l_cstr2) == 0);
	REQUIRE(std::strcmp(l_cstr1, l_cstr2) == 0);

	// Extraction as C++ string must not change the string's value
	std::string l_str1 = luwra::Value<std::string>::read(state, -1);
	std::string l_str2 = luwra::Value<std::string>::read(state, -2);

	REQUIRE(l_str1 == test_cstr);
	REQUIRE(l_str2 == test_cstr);
	REQUIRE(test_str == l_str1);
	REQUIRE(test_str == l_str2);
	REQUIRE(l_str1 == l_str2);

	lua_pop(state, 2);
	lua_close(state);
}
<commit_msg>Add tuple test<commit_after>#include "catch.hpp"

#include <lua.hpp>
#include <luwra.hpp>

#include <cstring>
#include <string>
#include <utility>
#include <type_traits>

template <typename I>
struct NumericTest {
	static
	void test(lua_State* state) {
		const I max_value = std::numeric_limits<I>::max();
		const I min_value = std::numeric_limits<I>::lowest();
		const I avg_value = (max_value + min_value) / 2;

		// Largest value
		REQUIRE(luwra::Value<I>::push(state, max_value) == 1);
		REQUIRE(luwra::Value<I>::read(state, -1) == max_value);

		// Lowest value
		REQUIRE(luwra::Value<I>::push(state, min_value) == 1);
		REQUIRE(luwra::Value<I>::read(state, -1) == min_value);

		// Average value
		REQUIRE(luwra::Value<I>::push(state, avg_value) == 1);
		REQUIRE(luwra::Value<I>::read(state, -1) == avg_value);
	}
};

struct TautologyTest {
	static
	void test(lua_State*) {}
};

template <typename B, typename I>
using SelectNumericTest =
	typename std::conditional<
		luwra::internal::NumericContainedValueBase<I, B>::qualifies,
		NumericTest<I>,
		TautologyTest
	>::type;

TEST_CASE("Test Value specialization for numeric C types", "types_numeric") {
	lua_State* state = luaL_newstate();

	// Integer-based types
	SelectNumericTest<lua_Integer, signed short>::test(state);
	SelectNumericTest<lua_Integer, unsigned short>::test(state);
	SelectNumericTest<lua_Integer, signed int>::test(state);
	SelectNumericTest<lua_Integer, unsigned int>::test(state);
	SelectNumericTest<lua_Integer, signed long int>::test(state);
	SelectNumericTest<lua_Integer, unsigned long int>::test(state);
	SelectNumericTest<lua_Integer, signed long long int>::test(state);
	SelectNumericTest<lua_Integer, unsigned long long int>::test(state);

	// Number-based types
	SelectNumericTest<lua_Number, float>::test(state);
	SelectNumericTest<lua_Number, double>::test(state);
	SelectNumericTest<lua_Number, long double>::test(state);

	lua_close(state);
}

TEST_CASE("Test Value specialization for string types", "types_string") {
	lua_State* state = luaL_newstate();

	const char* test_cstr = "Luwra Test String";
	std::string test_str(test_cstr);

	// Safety first
	REQUIRE(test_str == test_cstr);

	// Push both strings
	REQUIRE(luwra::Value<const char*>::push(state, test_cstr) == 1);
	REQUIRE(luwra::Value<std::string>::push(state, test_str) == 1);

	// They must be equal to Lua
	REQUIRE(lua_compare(state, -1, -2, LUA_OPEQ));

	// Extraction as C string must not change the string's value
	const char* l_cstr1 = luwra::Value<const char*>::read(state, -1);
	const char* l_cstr2 = luwra::Value<const char*>::read(state, -2);

	REQUIRE(std::strcmp(test_cstr,        l_cstr1) == 0);
	REQUIRE(std::strcmp(test_cstr,        l_cstr2) == 0);
	REQUIRE(std::strcmp(test_str.c_str(), l_cstr1) == 0);
	REQUIRE(std::strcmp(test_str.c_str(), l_cstr2) == 0);
	REQUIRE(std::strcmp(l_cstr1,          l_cstr2) == 0);

	// Extraction as C++ string must not change the string's value
	std::string l_str1 = luwra::Value<std::string>::read(state, -1);
	std::string l_str2 = luwra::Value<std::string>::read(state, -2);

	REQUIRE(l_str1   == test_cstr);
	REQUIRE(l_str2   == test_cstr);
	REQUIRE(test_str == l_str1);
	REQUIRE(test_str == l_str2);
	REQUIRE(l_str1   == l_str2);

	lua_close(state);
}

TEST_CASE("Test Value specialization for tuples", "types_tuple") {
	lua_State* state = luaL_newstate();

	int a = 13;
	std::string b("Hello");
	float c = 0.37;

	// Push normal tuple
	auto tuple = std::make_tuple(a, b, c);
	REQUIRE(luwra::Value<decltype(tuple)>::push(state, tuple) == 3);

	// Push nested tuple
	auto tuple_nested = std::make_tuple(a, b, c, tuple);
	REQUIRE(luwra::Value<decltype(tuple_nested)>::push(state, tuple_nested) == 6);

	lua_close(state);
}
<|endoftext|>


<commit_before>#ifndef ALPINOCORPUS_EITHER_HH
#define ALPINOCORPUS_EITHER_HH

namespace alpinocorpus {

/**
 * Either is an option type that resembles the Either type in Haskell.
 * It's used to indicate that computation results in two possible type:
 * the left type or the right type (which could have the same type).
 *
 * Unfortunately, we do not have algebraic data types in C++, so both
 * posibilities are encoded in the same type. The isLeft() and isRight()
 * methods can be used to probe whether we have a left or right value.
 *
 * In error handling the convention is that <tt>Left L</tt> is an error,
 * and information about the error is encoded using the type <tt>L</tt>.
 * <tt>Right R</tt> is a succesful computation with a result of the type
 * <tt>R</tt>.
 */
template <typename L, typename R>
class Either {
public:
	static Either left(L left);
	static Either right(R right);

	bool isLeft();
	bool isRight();
	L left();
	R right();
private:
	enum Result { LEFT, RIGHT };

	Either(Result result, L left, R right) :
		d_result(result), d_left(left), d_right(right) {}

	Result d_result;
	L d_left;
	R d_right;
};

template <typename L, typename R>
inline Either<L, R> Either<L, R>::left(L left)
{
	return Either(LEFT, left, R());
}

template <typename L, typename R>
inline Either<L, R> Either<L, R>::right(R right)
{
	return Either(RIGHT, L(), right);
}

template <typename L, typename R>
inline bool Either<L, R>::isLeft()
{
	return d_result == LEFT;
}

template <typename L, typename R>
inline bool Either<L, R>::isRight()
{
	return d_result == RIGHT;
}

template <typename L, typename R>
inline L Either<L, R>::left()
{
	return d_left;
}

template <typename L, typename R>
inline R Either<L, R>::right()
{
	return d_right;
}

struct Empty {};

}

#endif // ALPINOCORPUS_EITHER_HH
<commit_msg>Either: Add a note about boost::variant.<commit_after>#ifndef ALPINOCORPUS_EITHER_HH
#define ALPINOCORPUS_EITHER_HH

namespace alpinocorpus {

/**
 * Either is an option type that resembles the Either type in Haskell.
 * It's used to indicate that computation results in two possible type:
 * the left type or the right type (which could have the same type).
 *
 * Unfortunately, we do not have algebraic data types in C++, so both
 * posibilities are encoded in the same type. The isLeft() and isRight()
 * methods can be used to probe whether we have a left or right value.
 *
 * In error handling the convention is that <tt>Left L</tt> is an error,
 * and information about the error is encoded using the type <tt>L</tt>.
 * <tt>Right R</tt> is a succesful computation with a result of the type
 * <tt>R</tt>.
 *
 * Note: we could have used boost::variant, but I think it is kinda
 *       heavyweight. It does more, but also has a more complex API.
 */
template <typename L, typename R>
class Either {
public:
	static Either left(L left);
	static Either right(R right);

	bool isLeft();
	bool isRight();
	L left();
	R right();
private:
	enum Result { LEFT, RIGHT };

	Either(Result result, L left, R right) :
		d_result(result), d_left(left), d_right(right) {}

	Result d_result;
	L d_left;
	R d_right;
};

template <typename L, typename R>
inline Either<L, R> Either<L, R>::left(L left)
{
	return Either(LEFT, left, R());
}

template <typename L, typename R>
inline Either<L, R> Either<L, R>::right(R right)
{
	return Either(RIGHT, L(), right);
}

template <typename L, typename R>
inline bool Either<L, R>::isLeft()
{
	return d_result == LEFT;
}

template <typename L, typename R>
inline bool Either<L, R>::isRight()
{
	return d_result == RIGHT;
}

template <typename L, typename R>
inline L Either<L, R>::left()
{
	return d_left;
}

template <typename L, typename R>
inline R Either<L, R>::right()
{
	return d_right;
}

struct Empty {};

}

#endif // ALPINOCORPUS_EITHER_HH
<|endoftext|>


<commit_before>#ifndef ALEPH_GEOMETRY_COVER_TREE_HH__
#define ALEPH_GEOMETRY_COVER_TREE_HH__

#include <algorithm>
#include <iterator>
#include <limits>
#include <memory>
#include <ostream>
#include <queue>
#include <stack>
#include <stdexcept>
#include <vector>

// FIXME: remove after debugging
#include <iostream>

#include <cassert>
#include <cmath>

namespace aleph
{

namespace geometry
{

/**
  @class CoverTree
  @brief Generic cover tree data structure

  This class models a cover tree data structure, as described in the
  paper "Cover trees for nearest neighbor" by Beygelzimer et al.; an
  implementation is given at:

    http://hunch.net/~jl/projects/cover_tree/cover_tree.html

  This implementation attempts to be as generic as possible. It uses
  the simplified description of the cover tree, as given by Izbicki,
  Shelton in "Faster Cover Trees".
*/

template <class Point, class Metric> class CoverTree
{
public:

  /**
    Covering constant of the cover tree. It might make sense to change
    this later on in order to improve performance. Some papers set the
    constant to `1.3`.
  */

  constexpr static const double coveringConstant = 2.0;

  class Node
  {
  public:

    /** Creates a new node that stores a point */
    Node( const Point& point, long level )
      : _point( point )
      , _level( level )
    {
    }

    /** Calculates current covering distance of the node */
    double coveringDistance() const noexcept
    {
      return std::pow( coveringConstant, static_cast<double>( _level ) );
    }

    /** @returns true if the node is a leaf node */
    bool isLeaf() const noexcept
    {
      return _children.empty();
    }

    void insert( const Point& p )
    {
      auto d = Metric()( _point, p );

      std::cerr << __PRETTY_FUNCTION__ << ": Covering distance           = " << this->coveringDistance() << "\n";
      std::cerr << __PRETTY_FUNCTION__ << ": Distance from point to root = " << d << "\n";

      if( d > this->coveringDistance() )
      {
        while( d > 2 * this->coveringDistance() )
        {
          std::cerr << __PRETTY_FUNCTION__ << ": Distance is bigger than covering distance; need to raise level of tree\n";

          // -----------------------------------------------------------
          //
          // Find a leaf node that can become the new root node with
          // a raised level.

          std::stack<Node*> nodes;
          nodes.push( this );

          Node* leaf   = nullptr;
          Node* parent = nullptr;

          while( !nodes.empty() )
          {
            auto&& node = nodes.top();
            for( auto&& child : parent->_children )
            {
              if( child->isLeaf() )
              {
                leaf   = child.get();
                parent = node;
                break;
              }
            }

            nodes.pop();
          }

          // There is no leaf, so there is nothing to do and we just
          // skip to the bottom where we add the current node as the
          // new root of the tree.
          if( !leaf )
            break;

          assert( leaf );
          assert( parent );

          // Remove leaf from subtree ----------------------------------
          //
          // The previous tree does not contain the leaf node any more,
          // and it can be added as the new root node.

          std::unique_ptr<Node> leaf_ptr( nullptr );

          parent->_children.erase(
            std::remove_if(
              parent->_children.begin(), parent->_children.end(),
              [&leaf, &leaf_ptr] ( std::unique_ptr<Node>& child )
              {
                if( child.get() == leaf )
                {
                  leaf_ptr = std::move( child );
                  return true;
                }

                return false;
              }
            ),
            parent->_children.end()
          );

          // Make leaf node the new root node --------------------------
          //
          // Notice that this does increase the level of the current
          // root. This has to be adjusted for.

          auto oldRoot
            = std::unique_ptr<Node>( new Node( this->_point, this->_level ) );

          for( auto&& child : _children )
            oldRoot->_children.push_back( std::move( child ) );

          _point = leaf->_point;
          _level = _level + 1;

          _children.clear();
          _children.push_back( std::move( oldRoot ) );
        }

        // Make current point the new root -----------------------------

        auto oldRoot
          = std::unique_ptr<Node>( new Node( this->_point, this->_level ) );

        for( auto&& child : _children )
          oldRoot->_children.push_back( std::move( child ) );

        _point = p;
        _level = _level + 1;

        _children.clear();
        _children.push_back( std::move( oldRoot ) );

        return;
      }

      return insert_( p );
    }

    /**
      Auxiliary function for performing the recursive insertion of a new
      node into the tree.
    */

    void insert_( const Point& p )
    {
      for( auto&& child : _children )
      {
        auto d = Metric()( child->_point, p );
        if( d <= child->coveringDistance() )
        {
          std::cerr << __PRETTY_FUNCTION__ << ": Recursive enumeration of the tree\n";

          // We found a node in which the new point can be inserted
          // *without* violating the covering invariant.
          child->insert_( p );
          return;
        }
      }

      // Add the new point as a child of the current root node. Note the
      // level adjustment.
      _children.push_back( std::unique_ptr<Node>( new Node( p, _level - 1 ) ) );
    }

    Point _point; //< The point stored in the node
    long  _level; //< The level of the node

    /**
      All children of the node. Their order depends on the insertion
      order into the data set.
    */

    std::vector< std::unique_ptr<Node> > _children;
  };

  /**
    Inserts a new point into the cover tree. If the tree is empty,
    the new point will become the root of the tree. Else, it shall
    be inserted according to the covering invariant.
  */

  void insert( const Point& p )
  {
    if( !_root )
      _root = std::unique_ptr<Node>( new Node(p,1) );
    else
      _root->insert( p );
  }

  // Pretty-printing function for the tree; this is only meant for
  // debugging purposes and could conceivably be implemented using
  // `std::ostream`.
  void print( std::ostream& o )
  {
    std::queue<const Node*> nodes;
    nodes.push( _root.get() );

    while( !nodes.empty() )
    {
      {
        auto n = nodes.size();

        for( decltype(n) i = 0; i < n; i++ )
        {
          auto&& node = nodes.front();

          if( i == 0 )
            o << node->_level << ": ";
          else
            o << " ";

          o << node->_point;

          for( auto&& child : node->_children )
            nodes.push( child.get() );

          nodes.pop();
        }

        o << "\n";
      }
    }
  }

private:

  /** Root pointer of the tree */
  std::unique_ptr<Node> _root;
};

} // namespace geometry

} // namespace aleph

#endif
<commit_msg>Documented tree creation<commit_after>#ifndef ALEPH_GEOMETRY_COVER_TREE_HH__
#define ALEPH_GEOMETRY_COVER_TREE_HH__

#include <algorithm>
#include <iterator>
#include <limits>
#include <memory>
#include <ostream>
#include <queue>
#include <stack>
#include <stdexcept>
#include <vector>

// FIXME: remove after debugging
#include <iostream>

#include <cassert>
#include <cmath>

namespace aleph
{

namespace geometry
{

/**
  @class CoverTree
  @brief Generic cover tree data structure

  This class models a cover tree data structure, as described in the
  paper "Cover trees for nearest neighbor" by Beygelzimer et al.; an
  implementation is given at:

    http://hunch.net/~jl/projects/cover_tree/cover_tree.html

  This implementation attempts to be as generic as possible. It uses
  the simplified description of the cover tree, as given by Izbicki,
  Shelton in "Faster Cover Trees".
*/

template <class Point, class Metric> class CoverTree
{
public:

  /**
    Covering constant of the cover tree. It might make sense to change
    this later on in order to improve performance. Some papers set the
    constant to `1.3`.
  */

  constexpr static const double coveringConstant = 2.0;

  class Node
  {
  public:

    /** Creates a new node that stores a point */
    Node( const Point& point, long level )
      : _point( point )
      , _level( level )
    {
    }

    /** Calculates current covering distance of the node */
    double coveringDistance() const noexcept
    {
      return std::pow( coveringConstant, static_cast<double>( _level ) );
    }

    /** @returns true if the node is a leaf node */
    bool isLeaf() const noexcept
    {
      return _children.empty();
    }

    void insert( const Point& p )
    {
      auto d = Metric()( _point, p );

      std::cerr << __PRETTY_FUNCTION__ << ": Covering distance           = " << this->coveringDistance() << "\n";
      std::cerr << __PRETTY_FUNCTION__ << ": Distance from point to root = " << d << "\n";

      if( d > this->coveringDistance() )
      {
        while( d > 2 * this->coveringDistance() )
        {
          std::cerr << __PRETTY_FUNCTION__ << ": Distance is bigger than covering distance; need to raise level of tree\n";

          // -----------------------------------------------------------
          //
          // Find a leaf node that can become the new root node with
          // a raised level.

          std::stack<Node*> nodes;
          nodes.push( this );

          Node* leaf   = nullptr;
          Node* parent = nullptr;

          while( !nodes.empty() )
          {
            auto&& node = nodes.top();
            for( auto&& child : parent->_children )
            {
              if( child->isLeaf() )
              {
                leaf   = child.get();
                parent = node;
                break;
              }
            }

            nodes.pop();
          }

          // There is no leaf, so there is nothing to do and we just
          // skip to the bottom where we add the current node as the
          // new root of the tree.
          if( !leaf )
            break;

          assert( leaf );
          assert( parent );

          // Remove leaf from subtree ----------------------------------
          //
          // The previous tree does not contain the leaf node any more,
          // and it can be added as the new root node.

          std::unique_ptr<Node> leaf_ptr( nullptr );

          parent->_children.erase(
            std::remove_if(
              parent->_children.begin(), parent->_children.end(),
              [&leaf, &leaf_ptr] ( std::unique_ptr<Node>& child )
              {
                if( child.get() == leaf )
                {
                  leaf_ptr = std::move( child );
                  return true;
                }

                return false;
              }
            ),
            parent->_children.end()
          );

          // Make leaf node the new root node --------------------------
          //
          // Notice that this does increase the level of the current
          // root. This has to be adjusted for.

          auto oldRoot
            = std::unique_ptr<Node>( new Node( this->_point, this->_level ) );

          for( auto&& child : _children )
            oldRoot->_children.push_back( std::move( child ) );

          _point = leaf->_point;
          _level = _level + 1;

          _children.clear();
          _children.push_back( std::move( oldRoot ) );
        }

        // Make current point the new root -----------------------------
        //
        // So far, the new point has not yet been inserted into the
        // tree. This needs to be done now while the cover is valid
        // again.

        auto oldRoot
          = std::unique_ptr<Node>( new Node( this->_point, this->_level ) );

        for( auto&& child : _children )
          oldRoot->_children.push_back( std::move( child ) );

        _point = p;
        _level = _level + 1;

        _children.clear();
        _children.push_back( std::move( oldRoot ) );

        return;
      }

      return insert_( p );
    }

    /**
      Auxiliary function for performing the recursive insertion of a new
      node into the tree.
    */

    void insert_( const Point& p )
    {
      for( auto&& child : _children )
      {
        auto d = Metric()( child->_point, p );
        if( d <= child->coveringDistance() )
        {
          std::cerr << __PRETTY_FUNCTION__ << ": Recursive enumeration of the tree\n";

          // We found a node in which the new point can be inserted
          // *without* violating the covering invariant.
          child->insert_( p );
          return;
        }
      }

      // Add the new point as a child of the current root node. Note the
      // level adjustment.
      _children.push_back( std::unique_ptr<Node>( new Node( p, _level - 1 ) ) );
    }

    Point _point; //< The point stored in the node
    long  _level; //< The level of the node

    /**
      All children of the node. Their order depends on the insertion
      order into the data set.
    */

    std::vector< std::unique_ptr<Node> > _children;
  };

  /**
    Inserts a new point into the cover tree. If the tree is empty,
    the new point will become the root of the tree. Else, it shall
    be inserted according to the covering invariant.
  */

  void insert( const Point& p )
  {
    if( !_root )
      _root = std::unique_ptr<Node>( new Node(p,1) );
    else
      _root->insert( p );
  }

  // Pretty-printing function for the tree; this is only meant for
  // debugging purposes and could conceivably be implemented using
  // `std::ostream`.
  void print( std::ostream& o )
  {
    std::queue<const Node*> nodes;
    nodes.push( _root.get() );

    while( !nodes.empty() )
    {
      {
        auto n = nodes.size();

        for( decltype(n) i = 0; i < n; i++ )
        {
          auto&& node = nodes.front();

          if( i == 0 )
            o << node->_level << ": ";
          else
            o << " ";

          o << node->_point;

          for( auto&& child : node->_children )
            nodes.push( child.get() );

          nodes.pop();
        }

        o << "\n";
      }
    }
  }

private:

  /** Root pointer of the tree */
  std::unique_ptr<Node> _root;
};

} // namespace geometry

} // namespace aleph

#endif
<|endoftext|>