<commit_before>#pragma once

#include <algorithm>
#include <utility>
#include <memory>
#include <string>
#include <vector>
#include <uv.h>
#include "event.hpp"
#include "handle.hpp"
#include "stream.hpp"
#include "util.hpp"
#include "loop.hpp"

namespace uvw {

namespace details {

enum class UVProcessFlags: std::underlying_type_t<uv_process_flags> {
    SETUID = UV_PROCESS_SETUID,
    SETGID = UV_PROCESS_SETGID,
    WINDOWS_VERBATIM_ARGUMENTS = UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
    DETACHED = UV_PROCESS_DETACHED,
    WINDOWS_HIDE = UV_PROCESS_WINDOWS_HIDE
};

enum class UVStdIOFlags: std::underlying_type_t<uv_stdio_flags> {
    IGNORE_STREAM = UV_IGNORE,
    CREATE_PIPE = UV_CREATE_PIPE,
    INHERIT_FD = UV_INHERIT_FD,
    INHERIT_STREAM = UV_INHERIT_STREAM,
    READABLE_PIPE = UV_READABLE_PIPE,
    WRITABLE_PIPE = UV_WRITABLE_PIPE
};

}

/**
 * @brief ExitEvent event.
 *
 * It will be emitted by ProcessHandle according with its functionalities.
 */
struct ExitEvent: Event<ExitEvent> {
    explicit ExitEvent(int64_t code, int sig) noexcept
        : status{code}, signal{sig}
    {}

    int64_t status; /*!< The exit status. */
    int signal; /*!< The signal that caused the process to terminate, if any. */
};

/**
 * @brief The ProcessHandle handle.
 *
 * Process handles will spawn a new process and allow the user to control it and
 * establish communication channels with it using streams.
 */
class ProcessHandle final: public Handle<ProcessHandle, uv_process_t> {
    static void exitCallback(uv_process_t *handle, int64_t exitStatus, int termSignal) {
        ProcessHandle &process = *(static_cast<ProcessHandle*>(handle->data));
        process.publish(ExitEvent{exitStatus, termSignal});
    }

public:
    using Process = details::UVProcessFlags;
    using StdIO = details::UVStdIOFlags;

    ProcessHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref)
        : Handle{std::move(ca), std::move(ref)}
    {
        uv_stdio_container_t stdin;
        stdin.flags = static_cast<uv_stdio_flags>(StdIO::IGNORE_STREAM);
        poFdStdio.push_back(std::move(stdin));
    }

    /**
     * @brief Disables inheritance for file descriptors/handles.
     *
     * Disables inheritance for file descriptors/handles that this process
     * inherited from its parent. The effect is that child processes spawned by
     * this process don’t accidentally inherit these handles.

     * It is recommended to call this function as early in your program as
     * possible, before the inherited file descriptors can be closed or
     * duplicated.
     *
     * See the official
     * [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_disable_stdio_inheritance)
     * for further details.
     */
    static void disableStdIOInheritance() noexcept {
        uv_disable_stdio_inheritance();
    }

    /**
     * @brief kill Sends the specified signal to the given PID.
     * @param pid A valid process id.
     * @param signum A valid signal identifier.
     * @return True in case of success, false otherwise.
     */
    static bool kill(int pid, int signum) noexcept {
        return (0 == uv_kill(pid, signum));
    }

    /**
     * @brief Initializes the handle.
     * @return True in case of success, false otherwise.
     */
    bool init() const noexcept { return true; }

    /**
     * @brief spawn Starts the process.
     *
     * If the process isn't successfully spawned, an ErrorEvent event will be
     * emitted by the handle.
     *
     * See the official
     * [documentation](http://docs.libuv.org/en/v1.x/process.html)
     * for further details.
     *
     * @param file Path pointing to the program to be executed.
     * @param args Command line arguments.
     * @param env Optional environment for the new process.
     */
    void spawn(const char *file, char **args, char **env = nullptr) {
        uv_process_options_t po;

        po.exit_cb = &exitCallback;

        po.file = file;
        po.args = args;
        po.env = env;
        po.cwd = poCwd.empty() ? nullptr : poCwd.data();
        po.flags = poFlags;
        po.uid = poUid;
        po.gid = poGid;

        /**
         * See the constructor, poFdStdio[0] is stdin. It must be poStdio[0] by
         * convention. From the official documentation:
         *
         * > The convention is that stdio[0] points to stdin, fd 1 is used
         * > for stdout, and fd 2 is stderr.
         */
        std::vector<uv_stdio_container_t> poStdio{poFdStdio.size() + poStreamStdio.size()};
        poStdio.insert(poStdio.begin(), poStreamStdio.cbegin(), poStreamStdio.cend());
        poStdio.insert(poStdio.begin(), poFdStdio.cbegin(), poFdStdio.cend());

        invoke(&uv_spawn, parent(), get(), &po);
    }

    /**
     * @brief Sends the specified signal to the internal process handle.
     * @param signum A valid signal identifier.
     */
    void kill(int signum) {
        invoke(&uv_process_kill, get(), signum);
    }

    /**
     * @brief Gets the PID of the spawned process.
     *
     * It’s set after calling `spawn()`.
     *
     * @return The PID of the spawned process.
     */
    int pid() noexcept {
        return get()->pid;
    }

    /**
     * @brief Sets the current working directory for the subprocess.
     * @param path The working directory to be used when `spawn()` is invoked.
     * @return A reference to this process handle.
     */
    ProcessHandle& cwd(std::string &path) noexcept {
        poCwd = path;
        return *this;
    }

    /**
     * @brief Sets flags that control how `spawn()` behaves.
     *
     * Available flags are:
     *
     * * `ProcessHandle::Process::SETUID`
     * * `ProcessHandle::Process::SETGID`
     * * `ProcessHandle::Process::WINDOWS_VERBATIM_ARGUMENTS`
     * * `ProcessHandle::Process::DETACHED`
     * * `ProcessHandle::Process::WINDOWS_HIDE`
     *
     * See the official
     * [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_process_flags)
     * for further details.
     *
     * @param flags A valid set of flags.
     * @return A reference to this process handle.
     */
    ProcessHandle& flags(Flags<Process> flags) noexcept {
        poFlags = flags;
        return *this;
    }

    /**
     * @brief Makes a `stdio` handle available to the child process.
     *
     * Available flags are:
     *
     * * `ProcessHandle::StdIO::IGNORE_STREAM`
     * * `ProcessHandle::StdIO::CREATE_PIPE`
     * * `ProcessHandle::StdIO::INHERIT_FD`
     * * `ProcessHandle::StdIO::INHERIT_STREAM`
     * * `ProcessHandle::StdIO::READABLE_PIPE`
     * * `ProcessHandle::StdIO::WRITABLE_PIPE`
     *
     * See the official
     * [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_stdio_flags)
     * for further details.
     *
     * @param stream A valid `stdio` handle.
     * @param flags A valid set of flags.
     * @return A reference to this process handle.
     */
    template<typename T, typename U>
    ProcessHandle& stdio(StreamHandle<T, U> &stream, Flags<StdIO> flags) {
        uv_stdio_container_t container;
        Flags<StdIO>::Type fgs = flags;
        container.flags = static_cast<uv_stdio_flags>(fgs);
        container.data.stream = get<uv_stream_t>(stream);
        poStreamStdio.push_back(std::move(container));
        return *this;
    }

    /**
     * @brief Makes a file descriptor available to the child process.
     *
     * Available flags are:
     *
     * * `ProcessHandle::StdIO::IGNORE_STREAM`
     * * `ProcessHandle::StdIO::CREATE_PIPE`
     * * `ProcessHandle::StdIO::INHERIT_FD`
     * * `ProcessHandle::StdIO::INHERIT_STREAM`
     * * `ProcessHandle::StdIO::READABLE_PIPE`
     * * `ProcessHandle::StdIO::WRITABLE_PIPE`
     *
     * Default file descriptors are:
     *     * `uvw::StdIN` for `stdin`
     *     * `uvw::StdOUT` for `stdout`
     *     * `uvw::StdERR` for `stderr`
     *
     * See the official
     * [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_stdio_flags)
     * for further details.
     *
     * @param fd A valid file descriptor.
     * @param flags A valid set of flags.
     * @return A reference to this process handle.
     */
    ProcessHandle& stdio(FileHandle fd, Flags<StdIO> flags) {
        auto fgs = static_cast<uv_stdio_flags>(Flags<StdIO>::Type{flags});

        auto actual = FileHandle::Type{fd};

        if(actual == FileHandle::Type{StdIN}) {
            poFdStdio[0].flags = fgs;
        } else {
            auto it = std::find_if(poFdStdio.begin(), poFdStdio.end(), [actual](auto &&container){
                return container.data.fd == actual;
            });

            if(it == poFdStdio.cend()) {
                uv_stdio_container_t container;
                container.flags = fgs;
                container.data.fd = actual;
                poFdStdio.push_back(std::move(container));
            } else {
                it->flags = fgs;
                it->data.fd = actual;
            }
        }

        return *this;
    }

    /**
     * @brief Sets the child process' user id.
     * @param id A valid user id to be used.
     * @return A reference to this process handle.
     */
    ProcessHandle& uid(Uid id) {
        poUid = id;
        return *this;
    }

    /**
     * @brief Sets the child process' group id.
     * @param id A valid group id to be used.
     * @return A reference to this process handle.
     */
    ProcessHandle& gid(Gid id) {
        poGid = id;
        return *this;
    }

private:
    std::string poCwd;
    Flags<Process> poFlags;
    std::vector<uv_stdio_container_t> poFdStdio;
    std::vector<uv_stdio_container_t> poStreamStdio;
    Uid poUid;
    Gid poGid;
};

}
<commit_msg>win: damn it<commit_after>#pragma once

#include <algorithm>
#include <utility>
#include <memory>
#include <string>
#include <vector>
#include <uv.h>
#include "event.hpp"
#include "handle.hpp"
#include "stream.hpp"
#include "util.hpp"
#include "loop.hpp"

namespace uvw {

namespace details {

enum class UVProcessFlags: std::underlying_type_t<uv_process_flags> {
    SETUID = UV_PROCESS_SETUID,
    SETGID = UV_PROCESS_SETGID,
    WINDOWS_VERBATIM_ARGUMENTS = UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
    DETACHED = UV_PROCESS_DETACHED,
    WINDOWS_HIDE = UV_PROCESS_WINDOWS_HIDE
};

enum class UVStdIOFlags: std::underlying_type_t<uv_stdio_flags> {
    IGNORE_STREAM = UV_IGNORE,
    CREATE_PIPE = UV_CREATE_PIPE,
    INHERIT_FD = UV_INHERIT_FD,
    INHERIT_STREAM = UV_INHERIT_STREAM,
    READABLE_PIPE = UV_READABLE_PIPE,
    WRITABLE_PIPE = UV_WRITABLE_PIPE
};

}

/**
 * @brief ExitEvent event.
 *
 * It will be emitted by ProcessHandle according with its functionalities.
 */
struct ExitEvent: Event<ExitEvent> {
    explicit ExitEvent(int64_t code, int sig) noexcept
        : status{code}, signal{sig}
    {}

    int64_t status; /*!< The exit status. */
    int signal; /*!< The signal that caused the process to terminate, if any. */
};

/**
 * @brief The ProcessHandle handle.
 *
 * Process handles will spawn a new process and allow the user to control it and
 * establish communication channels with it using streams.
 */
class ProcessHandle final: public Handle<ProcessHandle, uv_process_t> {
    static void exitCallback(uv_process_t *handle, int64_t exitStatus, int termSignal) {
        ProcessHandle &process = *(static_cast<ProcessHandle*>(handle->data));
        process.publish(ExitEvent{exitStatus, termSignal});
    }

public:
    using Process = details::UVProcessFlags;
    using StdIO = details::UVStdIOFlags;

    ProcessHandle(ConstructorAccess ca, std::shared_ptr<Loop> ref)
        : Handle{std::move(ca), std::move(ref)}, poFdStdio{1}
    {
        // stdin container default initialization
        poFdStdio[0].flags = static_cast<uv_stdio_flags>(StdIO::IGNORE_STREAM);
    }

    /**
     * @brief Disables inheritance for file descriptors/handles.
     *
     * Disables inheritance for file descriptors/handles that this process
     * inherited from its parent. The effect is that child processes spawned by
     * this process don’t accidentally inherit these handles.

     * It is recommended to call this function as early in your program as
     * possible, before the inherited file descriptors can be closed or
     * duplicated.
     *
     * See the official
     * [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_disable_stdio_inheritance)
     * for further details.
     */
    static void disableStdIOInheritance() noexcept {
        uv_disable_stdio_inheritance();
    }

    /**
     * @brief kill Sends the specified signal to the given PID.
     * @param pid A valid process id.
     * @param signum A valid signal identifier.
     * @return True in case of success, false otherwise.
     */
    static bool kill(int pid, int signum) noexcept {
        return (0 == uv_kill(pid, signum));
    }

    /**
     * @brief Initializes the handle.
     * @return True in case of success, false otherwise.
     */
    bool init() const noexcept { return true; }

    /**
     * @brief spawn Starts the process.
     *
     * If the process isn't successfully spawned, an ErrorEvent event will be
     * emitted by the handle.
     *
     * See the official
     * [documentation](http://docs.libuv.org/en/v1.x/process.html)
     * for further details.
     *
     * @param file Path pointing to the program to be executed.
     * @param args Command line arguments.
     * @param env Optional environment for the new process.
     */
    void spawn(const char *file, char **args, char **env = nullptr) {
        uv_process_options_t po;

        po.exit_cb = &exitCallback;

        po.file = file;
        po.args = args;
        po.env = env;
        po.cwd = poCwd.empty() ? nullptr : poCwd.data();
        po.flags = poFlags;
        po.uid = poUid;
        po.gid = poGid;

        /**
         * See the constructor, poFdStdio[0] is stdin. It must be poStdio[0] by
         * convention. From the official documentation:
         *
         * > The convention is that stdio[0] points to stdin, fd 1 is used
         * > for stdout, and fd 2 is stderr.
         */
        std::vector<uv_stdio_container_t> poStdio{poFdStdio.size() + poStreamStdio.size()};
        poStdio.insert(poStdio.begin(), poStreamStdio.cbegin(), poStreamStdio.cend());
        poStdio.insert(poStdio.begin(), poFdStdio.cbegin(), poFdStdio.cend());

        invoke(&uv_spawn, parent(), get(), &po);
    }

    /**
     * @brief Sends the specified signal to the internal process handle.
     * @param signum A valid signal identifier.
     */
    void kill(int signum) {
        invoke(&uv_process_kill, get(), signum);
    }

    /**
     * @brief Gets the PID of the spawned process.
     *
     * It’s set after calling `spawn()`.
     *
     * @return The PID of the spawned process.
     */
    int pid() noexcept {
        return get()->pid;
    }

    /**
     * @brief Sets the current working directory for the subprocess.
     * @param path The working directory to be used when `spawn()` is invoked.
     * @return A reference to this process handle.
     */
    ProcessHandle& cwd(std::string &path) noexcept {
        poCwd = path;
        return *this;
    }

    /**
     * @brief Sets flags that control how `spawn()` behaves.
     *
     * Available flags are:
     *
     * * `ProcessHandle::Process::SETUID`
     * * `ProcessHandle::Process::SETGID`
     * * `ProcessHandle::Process::WINDOWS_VERBATIM_ARGUMENTS`
     * * `ProcessHandle::Process::DETACHED`
     * * `ProcessHandle::Process::WINDOWS_HIDE`
     *
     * See the official
     * [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_process_flags)
     * for further details.
     *
     * @param flags A valid set of flags.
     * @return A reference to this process handle.
     */
    ProcessHandle& flags(Flags<Process> flags) noexcept {
        poFlags = flags;
        return *this;
    }

    /**
     * @brief Makes a `stdio` handle available to the child process.
     *
     * Available flags are:
     *
     * * `ProcessHandle::StdIO::IGNORE_STREAM`
     * * `ProcessHandle::StdIO::CREATE_PIPE`
     * * `ProcessHandle::StdIO::INHERIT_FD`
     * * `ProcessHandle::StdIO::INHERIT_STREAM`
     * * `ProcessHandle::StdIO::READABLE_PIPE`
     * * `ProcessHandle::StdIO::WRITABLE_PIPE`
     *
     * See the official
     * [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_stdio_flags)
     * for further details.
     *
     * @param stream A valid `stdio` handle.
     * @param flags A valid set of flags.
     * @return A reference to this process handle.
     */
    template<typename T, typename U>
    ProcessHandle& stdio(StreamHandle<T, U> &stream, Flags<StdIO> flags) {
        uv_stdio_container_t container;
        Flags<StdIO>::Type fgs = flags;
        container.flags = static_cast<uv_stdio_flags>(fgs);
        container.data.stream = get<uv_stream_t>(stream);
        poStreamStdio.push_back(std::move(container));
        return *this;
    }

    /**
     * @brief Makes a file descriptor available to the child process.
     *
     * Available flags are:
     *
     * * `ProcessHandle::StdIO::IGNORE_STREAM`
     * * `ProcessHandle::StdIO::CREATE_PIPE`
     * * `ProcessHandle::StdIO::INHERIT_FD`
     * * `ProcessHandle::StdIO::INHERIT_STREAM`
     * * `ProcessHandle::StdIO::READABLE_PIPE`
     * * `ProcessHandle::StdIO::WRITABLE_PIPE`
     *
     * Default file descriptors are:
     *     * `uvw::StdIN` for `stdin`
     *     * `uvw::StdOUT` for `stdout`
     *     * `uvw::StdERR` for `stderr`
     *
     * See the official
     * [documentation](http://docs.libuv.org/en/v1.x/process.html#c.uv_stdio_flags)
     * for further details.
     *
     * @param fd A valid file descriptor.
     * @param flags A valid set of flags.
     * @return A reference to this process handle.
     */
    ProcessHandle& stdio(FileHandle fd, Flags<StdIO> flags) {
        auto fgs = static_cast<uv_stdio_flags>(Flags<StdIO>::Type{flags});

        auto actual = FileHandle::Type{fd};

        if(actual == FileHandle::Type{StdIN}) {
            poFdStdio[0].flags = fgs;
        } else {
            auto it = std::find_if(poFdStdio.begin(), poFdStdio.end(), [actual](auto &&container){
                return container.data.fd == actual;
            });

            if(it == poFdStdio.cend()) {
                uv_stdio_container_t container;
                container.flags = fgs;
                container.data.fd = actual;
                poFdStdio.push_back(std::move(container));
            } else {
                it->flags = fgs;
                it->data.fd = actual;
            }
        }

        return *this;
    }

    /**
     * @brief Sets the child process' user id.
     * @param id A valid user id to be used.
     * @return A reference to this process handle.
     */
    ProcessHandle& uid(Uid id) {
        poUid = id;
        return *this;
    }

    /**
     * @brief Sets the child process' group id.
     * @param id A valid group id to be used.
     * @return A reference to this process handle.
     */
    ProcessHandle& gid(Gid id) {
        poGid = id;
        return *this;
    }

private:
    std::string poCwd;
    Flags<Process> poFlags;
    std::vector<uv_stdio_container_t> poFdStdio;
    std::vector<uv_stdio_container_t> poStreamStdio;
    Uid poUid;
    Gid poGid;
};

}
<|endoftext|>


<commit_before>/*
 * Copyright 2016, Masayoshi Mizutani, mizutani@sfc.wide.ad.jp
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 * * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <vector>
#include <string>

#include "./gtest.h"
#include "../argparse.hpp"

class ParserRequired : public ::testing::Test {
public:
  argparse::Parser psr;
  argparse::Argument *arg;
  virtual void SetUp() {
    arg = &(psr.add_argument("-a").required(true));
  }
};

TEST_F(ParserRequired, store_ok) {
  argparse::Argv seq = {"./test", "-a", "v1"};
  argparse::Values val = psr.parse_args(seq);
  EXPECT_TRUE(val.is_set("a"));
  EXPECT_EQ(1, val.size("a"));
  EXPECT_EQ("v1", val.get("a", 0));
}

TEST_F(ParserRequired, store_ng) {
  argparse::Argv seq = {"./test"};
  EXPECT_THROW(psr.parse_args(seq), argparse::exception::ParseError);
}

<commit_msg>append additional test for Argument::required of Parser<commit_after>/*
 * Copyright 2016, Masayoshi Mizutani, mizutani@sfc.wide.ad.jp
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 * * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <vector>
#include <string>

#include "./gtest.h"
#include "../argparse.hpp"

class ParserRequired : public ::testing::Test {
public:
  argparse::Parser psr;
  argparse::Argument *arg;
  virtual void SetUp() {
    arg = &(psr.add_argument("-a").required(true));
  }
};

TEST_F(ParserRequired, store_ok) {
  argparse::Argv seq = {"./test", "-a", "v1"};
  argparse::Values val = psr.parse_args(seq);
  EXPECT_TRUE(val.is_set("a"));
  EXPECT_EQ(1, val.size("a"));
  EXPECT_EQ("v1", val.get("a", 0));
}

TEST_F(ParserRequired, store_ng) {
  argparse::Argv seq = {"./test"};
  EXPECT_THROW(psr.parse_args(seq), argparse::exception::ParseError);
}

TEST_F(ParserRequired, append_ok) {
  arg->action("append");
  argparse::Argv seq = {"./test", "-a", "v1"};
  argparse::Values val = psr.parse_args(seq);
  EXPECT_TRUE(val.is_set("a"));
  EXPECT_EQ(1, val.size("a"));
  EXPECT_EQ("v1", val.get("a", 0));
}

TEST_F(ParserRequired, append_ng) {
  arg->action("append");
  argparse::Argv seq = {"./test"};
  EXPECT_THROW(psr.parse_args(seq), argparse::exception::ParseError);
}

TEST_F(ParserRequired, store_const_ok) {
  arg->action("store_const").set_const("c");
  argparse::Argv seq = {"./test", "-a"};
  argparse::Values val = psr.parse_args(seq);
  EXPECT_TRUE(val.is_set("a"));
}

TEST_F(ParserRequired, store_const_ng) {
  arg->action("store_const").set_const("c");
  argparse::Argv seq = {"./test"};
  EXPECT_THROW(psr.parse_args(seq), argparse::exception::ParseError);
}

TEST_F(ParserRequired, append_const_ok) {
  arg->action("append_const").set_const("c");
  argparse::Argv seq = {"./test", "-a", "-a"};
  argparse::Values val = psr.parse_args(seq);
  EXPECT_TRUE(val.is_set("a"));
  EXPECT_EQ(2, val.size("a"));
}

TEST_F(ParserRequired, append_const_ng) {
  arg->action("append_const").set_const("c");
  argparse::Argv seq = {"./test"};
  EXPECT_THROW(psr.parse_args(seq), argparse::exception::ParseError);
}

TEST_F(ParserRequired, store_true) {
  arg->action("store_true");
  argparse::Argv seq = {"./test"};
  argparse::Values val = psr.parse_args(seq);
  EXPECT_TRUE(val.is_set("a"));
}

TEST_F(ParserRequired, store_false) {
  arg->action("store_false");
  argparse::Argv seq = {"./test"};
  argparse::Values val = psr.parse_args(seq);
  EXPECT_TRUE(val.is_set("a"));
}

TEST_F(ParserRequired, count_ok) {
  arg->action("count");
  argparse::Argv seq = {"./test", "-a"};
  argparse::Values val = psr.parse_args(seq);
  EXPECT_TRUE(val.is_set("a"));
}

TEST_F(ParserRequired, count_ng) {
  arg->action("count");
  argparse::Argv seq = {"./test"};
  EXPECT_THROW(psr.parse_args(seq), argparse::exception::ParseError);
}<|endoftext|>


<commit_before>/****************************************************************************
**
** This file is part of the CAMP library.
**
** The MIT License (MIT)
**
** Copyright (C) 2009-2014 TEGESO/TEGESOFT and/or its subsidiary(-ies) and mother company.
** Contact: Tegesoft Information (contact@tegesoft.com)
**
** 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 "arrayproperty.hpp"
#include <camp/classget.hpp>
#include <camp/errors.hpp>
#include <camp/arrayproperty.hpp>
#include <boost/test/unit_test.hpp>

using namespace ArrayPropertyTest;

//-----------------------------------------------------------------------------
struct ArrayPropertyFixture
{
    ArrayPropertyFixture()
    {
        const camp::Class& metaclass = camp::classByType<MyClass>();
        bools   = &static_cast<const camp::ArrayProperty&>(metaclass.property("bools"));
        ints    = &static_cast<const camp::ArrayProperty&>(metaclass.property("ints"));
        strings = &static_cast<const camp::ArrayProperty&>(metaclass.property("strings"));
        objects = &static_cast<const camp::ArrayProperty&>(metaclass.property("objects"));
    }

    const camp::ArrayProperty* bools;
    const camp::ArrayProperty* ints;
    const camp::ArrayProperty* strings;
    const camp::ArrayProperty* objects;
    MyClass object;
};

//-----------------------------------------------------------------------------
//                         Tests for camp::ArrayProperty
//-----------------------------------------------------------------------------
BOOST_FIXTURE_TEST_SUITE(ARRAYPROPERTY, ArrayPropertyFixture)

//-----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(type)
{
    BOOST_CHECK_EQUAL(bools->type(),   camp::arrayType);
    BOOST_CHECK_EQUAL(ints->type(),    camp::arrayType);
    BOOST_CHECK_EQUAL(strings->type(), camp::arrayType);
    BOOST_CHECK_EQUAL(objects->type(), camp::arrayType);
}

//-----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(elementType)
{
    BOOST_CHECK_EQUAL(bools->elementType(),   camp::boolType);
    BOOST_CHECK_EQUAL(ints->elementType(),    camp::intType);
    BOOST_CHECK_EQUAL(strings->elementType(), camp::stringType);
    BOOST_CHECK_EQUAL(objects->elementType(), camp::userType);
}

//-----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(dynamic)
{
    BOOST_CHECK_EQUAL(bools->dynamic(),   false);
    BOOST_CHECK_EQUAL(ints->dynamic(),    false);
    BOOST_CHECK_EQUAL(strings->dynamic(), true);
    BOOST_CHECK_EQUAL(objects->dynamic(), true);
}

//-----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(size)
{
    BOOST_CHECK_EQUAL(bools->size(object),   boost::size(object.bools));
    BOOST_CHECK_EQUAL(ints->size(object),    object.ints.size());
    BOOST_CHECK_EQUAL(strings->size(object), object.strings.size());
    BOOST_CHECK_EQUAL(objects->size(object), object.objects.size());
}

//-----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(get)
{
    BOOST_CHECK_EQUAL(bools->get(object, 0), camp::Value(object.bools[0]));
    BOOST_CHECK_EQUAL(bools->get(object, 1), camp::Value(object.bools[1]));
    BOOST_CHECK_THROW(bools->get(object, 2), camp::OutOfRange);

    BOOST_CHECK_EQUAL(ints->get(object, 0), camp::Value(object.ints[0]));
    BOOST_CHECK_EQUAL(ints->get(object, 1), camp::Value(object.ints[1]));
    BOOST_CHECK_EQUAL(ints->get(object, 2), camp::Value(object.ints[2]));
    BOOST_CHECK_THROW(ints->get(object, 3), camp::OutOfRange);

    BOOST_CHECK_EQUAL(strings->get(object, 0), camp::Value(object.strings[0]));
    BOOST_CHECK_EQUAL(strings->get(object, 1), camp::Value(object.strings[1]));
    BOOST_CHECK_EQUAL(strings->get(object, 2), camp::Value(object.strings[2]));
    BOOST_CHECK_EQUAL(strings->get(object, 3), camp::Value(object.strings[3]));
    BOOST_CHECK_THROW(strings->get(object, 4), camp::OutOfRange);

    std::list<MyType>::const_iterator it = object.objects.begin();
    BOOST_CHECK_EQUAL(objects->get(object, 0), camp::Value(*boost::next(it, 0)));
    BOOST_CHECK_EQUAL(objects->get(object, 1), camp::Value(*boost::next(it, 1)));
    BOOST_CHECK_EQUAL(objects->get(object, 2), camp::Value(*boost::next(it, 2)));
    BOOST_CHECK_EQUAL(objects->get(object, 3), camp::Value(*boost::next(it, 3)));
    BOOST_CHECK_EQUAL(objects->get(object, 4), camp::Value(*boost::next(it, 4)));
    BOOST_CHECK_THROW(objects->get(object, 5), camp::OutOfRange);
}

//-----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(set)
{
    bools->set(object, 1, true);
    ints->set(object, 1, 20);
    strings->set(object, 1, "hello");
    objects->set(object, 1, MyType(8));

    BOOST_CHECK_EQUAL(object.bools[1],   true);
    BOOST_CHECK_EQUAL(object.ints[1],    20);
    BOOST_CHECK_EQUAL(object.strings[1], "hello");
    BOOST_CHECK(*boost::next(object.objects.begin(), 1) == MyType(8));

    BOOST_CHECK_THROW(bools->set(object, 10, true),        camp::OutOfRange);
    BOOST_CHECK_THROW(ints->set(object, 10, 1),            camp::OutOfRange);
    BOOST_CHECK_THROW(strings->set(object, 10, "hi"),      camp::OutOfRange);
    BOOST_CHECK_THROW(objects->set(object, 10, MyType(9)), camp::OutOfRange);
}

//-----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(insert)
{
    BOOST_CHECK_THROW(bools->insert(object, 0, true), camp::ForbiddenWrite);
    BOOST_CHECK_THROW(ints->insert(object, 0, true),  camp::ForbiddenWrite);

    std::size_t stringsSize = object.strings.size();
    std::size_t objectsSize = object.objects.size();

    strings->insert(object, 1, "bonjour");
    objects->insert(object, 1, MyType(10));

    BOOST_CHECK_EQUAL(object.strings.size(), stringsSize + 1);
    BOOST_CHECK_EQUAL(object.objects.size(), objectsSize + 1);

    BOOST_CHECK_EQUAL(object.strings[1], "bonjour");
    BOOST_CHECK(*boost::next(object.objects.begin(), 1) == MyType(10));
}

//-----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(remove)
{
    BOOST_CHECK_THROW(bools->remove(object, 0), camp::ForbiddenWrite);
    BOOST_CHECK_THROW(ints->remove(object, 0),  camp::ForbiddenWrite);

    std::string string1 = object.strings[1];
    MyType      object1 = *boost::next(object.objects.begin(), 1);

    std::size_t stringsSize = object.strings.size();
    std::size_t objectsSize = object.objects.size();

    strings->remove(object, 0);
    objects->remove(object, 0);

    BOOST_CHECK_EQUAL(object.strings.size(), stringsSize - 1);
    BOOST_CHECK_EQUAL(object.objects.size(), objectsSize - 1);

    BOOST_CHECK(object.strings.front() == string1);
    BOOST_CHECK(object.objects.front() == object1);
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Use std::next.<commit_after>/****************************************************************************
**
** This file is part of the CAMP library.
**
** The MIT License (MIT)
**
** Copyright (C) 2009-2014 TEGESO/TEGESOFT and/or its subsidiary(-ies) and mother company.
** Contact: Tegesoft Information (contact@tegesoft.com)
**
** 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 "arrayproperty.hpp"
#include <camp/classget.hpp>
#include <camp/errors.hpp>
#include <camp/arrayproperty.hpp>
#include <boost/test/unit_test.hpp>

using namespace ArrayPropertyTest;

//-----------------------------------------------------------------------------
struct ArrayPropertyFixture
{
    ArrayPropertyFixture()
    {
        const camp::Class& metaclass = camp::classByType<MyClass>();
        bools   = &static_cast<const camp::ArrayProperty&>(metaclass.property("bools"));
        ints    = &static_cast<const camp::ArrayProperty&>(metaclass.property("ints"));
        strings = &static_cast<const camp::ArrayProperty&>(metaclass.property("strings"));
        objects = &static_cast<const camp::ArrayProperty&>(metaclass.property("objects"));
    }

    const camp::ArrayProperty* bools;
    const camp::ArrayProperty* ints;
    const camp::ArrayProperty* strings;
    const camp::ArrayProperty* objects;
    MyClass object;
};

//-----------------------------------------------------------------------------
//                         Tests for camp::ArrayProperty
//-----------------------------------------------------------------------------
BOOST_FIXTURE_TEST_SUITE(ARRAYPROPERTY, ArrayPropertyFixture)

//-----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(type)
{
    BOOST_CHECK_EQUAL(bools->type(),   camp::arrayType);
    BOOST_CHECK_EQUAL(ints->type(),    camp::arrayType);
    BOOST_CHECK_EQUAL(strings->type(), camp::arrayType);
    BOOST_CHECK_EQUAL(objects->type(), camp::arrayType);
}

//-----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(elementType)
{
    BOOST_CHECK_EQUAL(bools->elementType(),   camp::boolType);
    BOOST_CHECK_EQUAL(ints->elementType(),    camp::intType);
    BOOST_CHECK_EQUAL(strings->elementType(), camp::stringType);
    BOOST_CHECK_EQUAL(objects->elementType(), camp::userType);
}

//-----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(dynamic)
{
    BOOST_CHECK_EQUAL(bools->dynamic(),   false);
    BOOST_CHECK_EQUAL(ints->dynamic(),    false);
    BOOST_CHECK_EQUAL(strings->dynamic(), true);
    BOOST_CHECK_EQUAL(objects->dynamic(), true);
}

//-----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(size)
{
    BOOST_CHECK_EQUAL(bools->size(object),   boost::size(object.bools));
    BOOST_CHECK_EQUAL(ints->size(object),    object.ints.size());
    BOOST_CHECK_EQUAL(strings->size(object), object.strings.size());
    BOOST_CHECK_EQUAL(objects->size(object), object.objects.size());
}

//-----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(get)
{
    BOOST_CHECK_EQUAL(bools->get(object, 0), camp::Value(object.bools[0]));
    BOOST_CHECK_EQUAL(bools->get(object, 1), camp::Value(object.bools[1]));
    BOOST_CHECK_THROW(bools->get(object, 2), camp::OutOfRange);

    BOOST_CHECK_EQUAL(ints->get(object, 0), camp::Value(object.ints[0]));
    BOOST_CHECK_EQUAL(ints->get(object, 1), camp::Value(object.ints[1]));
    BOOST_CHECK_EQUAL(ints->get(object, 2), camp::Value(object.ints[2]));
    BOOST_CHECK_THROW(ints->get(object, 3), camp::OutOfRange);

    BOOST_CHECK_EQUAL(strings->get(object, 0), camp::Value(object.strings[0]));
    BOOST_CHECK_EQUAL(strings->get(object, 1), camp::Value(object.strings[1]));
    BOOST_CHECK_EQUAL(strings->get(object, 2), camp::Value(object.strings[2]));
    BOOST_CHECK_EQUAL(strings->get(object, 3), camp::Value(object.strings[3]));
    BOOST_CHECK_THROW(strings->get(object, 4), camp::OutOfRange);

    std::list<MyType>::const_iterator it = object.objects.begin();
    BOOST_CHECK_EQUAL(objects->get(object, 0), camp::Value(*std::next(it, 0)));
    BOOST_CHECK_EQUAL(objects->get(object, 1), camp::Value(*std::next(it, 1)));
    BOOST_CHECK_EQUAL(objects->get(object, 2), camp::Value(*std::next(it, 2)));
    BOOST_CHECK_EQUAL(objects->get(object, 3), camp::Value(*std::next(it, 3)));
    BOOST_CHECK_EQUAL(objects->get(object, 4), camp::Value(*std::next(it, 4)));
    BOOST_CHECK_THROW(objects->get(object, 5), camp::OutOfRange);
}

//-----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(set)
{
    bools->set(object, 1, true);
    ints->set(object, 1, 20);
    strings->set(object, 1, "hello");
    objects->set(object, 1, MyType(8));

    BOOST_CHECK_EQUAL(object.bools[1],   true);
    BOOST_CHECK_EQUAL(object.ints[1],    20);
    BOOST_CHECK_EQUAL(object.strings[1], "hello");
    BOOST_CHECK(*std::next(object.objects.begin(), 1) == MyType(8));

    BOOST_CHECK_THROW(bools->set(object, 10, true),        camp::OutOfRange);
    BOOST_CHECK_THROW(ints->set(object, 10, 1),            camp::OutOfRange);
    BOOST_CHECK_THROW(strings->set(object, 10, "hi"),      camp::OutOfRange);
    BOOST_CHECK_THROW(objects->set(object, 10, MyType(9)), camp::OutOfRange);
}

//-----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(insert)
{
    BOOST_CHECK_THROW(bools->insert(object, 0, true), camp::ForbiddenWrite);
    BOOST_CHECK_THROW(ints->insert(object, 0, true),  camp::ForbiddenWrite);

    std::size_t stringsSize = object.strings.size();
    std::size_t objectsSize = object.objects.size();

    strings->insert(object, 1, "bonjour");
    objects->insert(object, 1, MyType(10));

    BOOST_CHECK_EQUAL(object.strings.size(), stringsSize + 1);
    BOOST_CHECK_EQUAL(object.objects.size(), objectsSize + 1);

    BOOST_CHECK_EQUAL(object.strings[1], "bonjour");
    BOOST_CHECK(*std::next(object.objects.begin(), 1) == MyType(10));
}

//-----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(remove)
{
    BOOST_CHECK_THROW(bools->remove(object, 0), camp::ForbiddenWrite);
    BOOST_CHECK_THROW(ints->remove(object, 0),  camp::ForbiddenWrite);

    std::string string1 = object.strings[1];
    MyType      object1 = *std::next(object.objects.begin(), 1);

    std::size_t stringsSize = object.strings.size();
    std::size_t objectsSize = object.objects.size();

    strings->remove(object, 0);
    objects->remove(object, 0);

    BOOST_CHECK_EQUAL(object.strings.size(), stringsSize - 1);
    BOOST_CHECK_EQUAL(object.objects.size(), objectsSize - 1);

    BOOST_CHECK(object.strings.front() == string1);
    BOOST_CHECK(object.objects.front() == object1);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>/*
 *  VHDL code generation for logic devices.
 *
 *  Copyright (C) 2008  Nick Gasson (nick@nickg.me.uk)
 *
 *  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.
 */

#include "vhdl_target.h"
#include "vhdl_element.hh"

#include <cassert>
#include <sstream>
#include <iostream>

/*
 * Convert the inputs of a logic gate to a binary expression.
 */
static vhdl_expr *inputs_to_expr(vhdl_scope *scope, vhdl_binop_t op,
                                 ivl_net_logic_t log)
{
   // Not always std_logic but this is probably OK since
   // the program has already been type checked
   vhdl_binop_expr *gate =
      new vhdl_binop_expr(op, vhdl_type::std_logic());

   int npins = ivl_logic_pins(log);
   for (int i = 1; i < npins; i++) {
      ivl_nexus_t input = ivl_logic_pin(log, i);
      gate->add_expr(nexus_to_var_ref(scope, input));
   }

   return gate;
}

/*
 * Convert a gate intput to an unary expression.
 */
static vhdl_expr *input_to_expr(vhdl_scope *scope, vhdl_unaryop_t op,
                                ivl_net_logic_t log)
{
   ivl_nexus_t input = ivl_logic_pin(log, 1);
   assert(input);

   vhdl_expr *operand = nexus_to_var_ref(scope, input);
   return new vhdl_unaryop_expr(op, operand, vhdl_type::std_logic());
}

static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0)
{
   ivl_nexus_t output = ivl_logic_pin(log, 0);
   vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output);
   assert(lhs);

   vhdl_expr *val = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 1));
   assert(val);

   vhdl_expr *sel = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 2));
   assert(val);

   vhdl_expr *on = new vhdl_const_bit(if0 ? '0' : '1');
   vhdl_expr *cmp = new vhdl_binop_expr(sel, VHDL_BINOP_EQ, on, NULL);

   ivl_signal_t sig = find_signal_named(lhs->get_name(), arch->get_scope());
   char zbit;
   switch (ivl_signal_type(sig)) {
   case IVL_SIT_TRI0:
      zbit = '0';
      break;
   case IVL_SIT_TRI1:
      zbit = '1';
      break;
   case IVL_SIT_TRI:
   default:
      zbit = 'Z';
   }

   vhdl_const_bit *z = new vhdl_const_bit(zbit);
   vhdl_cassign_stmt *cass = new vhdl_cassign_stmt(lhs, z);
   cass->add_condition(val, cmp);

   arch->add_stmt(cass);
}

static void udp_logic(vhdl_arch *arch, ivl_net_logic_t log)
{
   ivl_udp_t udp = ivl_logic_udp(log);

   if (ivl_udp_sequ(udp)) {
      error("Sequential UDP devices not supported yet");
      return;
   }

   // As with regular case statements, the expression in a
   // `with .. select' statement must be "locally static".
   // This is achieved by first combining the inputs into
   // a temporary

   ostringstream ss;
   ss << ivl_logic_basename(log) << "_Tmp";
   int msb = ivl_udp_nin(udp) - 1;
   vhdl_type *tmp_type = vhdl_type::std_logic_vector(msb, 0);
   vhdl_signal_decl *tmp_decl =
      new vhdl_signal_decl(ss.str().c_str(), tmp_type);
   arch->get_scope()->add_decl(tmp_decl);

   int nin = ivl_udp_nin(udp);
   vhdl_expr *tmp_rhs;
   if (nin == 1) {
      tmp_rhs = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 1));
      tmp_rhs = tmp_rhs->cast(tmp_type);
   }
   else
      tmp_rhs = inputs_to_expr(arch->get_scope(), VHDL_BINOP_CONCAT, log);

   ss.str("");
   ss << "Input to " << ivl_logic_basename(log) << " "
      << ivl_udp_name(udp) << " UDP";
   tmp_decl->set_comment(ss.str());

   vhdl_var_ref *tmp_ref =
      new vhdl_var_ref(tmp_decl->get_name().c_str(), NULL);
   arch->add_stmt(new vhdl_cassign_stmt(tmp_ref, tmp_rhs));

   // Now we can implement the UDP as a `with .. select' statement
   // by reading values out of the table
   ivl_nexus_t output_nex = ivl_logic_pin(log, 0);
   vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), output_nex);
   vhdl_with_select_stmt *ws =
      new vhdl_with_select_stmt(new vhdl_var_ref(*tmp_ref), out);

   int nrows = ivl_udp_rows(udp);
   for (int i = 0; i < nrows; i++) {
      const char *row = ivl_udp_row(udp, i);

      vhdl_expr *value = new vhdl_const_bit(row[nin]);
      vhdl_expr *cond = new vhdl_const_bits(row, nin, false);
      vhdl_expr *delay = translate_time_expr(ivl_logic_delay(log, 1));

      ws->add_condition(value, cond, delay);
   }

   ss.str("");
   ss << "UDP " << ivl_udp_name(udp);
   ws->set_comment(ss.str());

   arch->add_stmt(ws);
}

static vhdl_expr *translate_logic_inputs(vhdl_scope *scope, ivl_net_logic_t log)
{
   switch (ivl_logic_type(log)) {
   case IVL_LO_NOT:
      return input_to_expr(scope, VHDL_UNARYOP_NOT, log);
   case IVL_LO_AND:
      return inputs_to_expr(scope, VHDL_BINOP_AND, log);
   case IVL_LO_OR:
      return inputs_to_expr(scope, VHDL_BINOP_OR, log);
   case IVL_LO_NAND:
      return inputs_to_expr(scope, VHDL_BINOP_NAND, log);
   case IVL_LO_NOR:
      return inputs_to_expr(scope, VHDL_BINOP_NOR, log);
   case IVL_LO_XOR:
      return inputs_to_expr(scope, VHDL_BINOP_XOR, log);
   case IVL_LO_XNOR:
      return inputs_to_expr(scope, VHDL_BINOP_XNOR, log);
   case IVL_LO_BUF:
   case IVL_LO_BUFZ:
      return nexus_to_var_ref(scope, ivl_logic_pin(log, 1));
   case IVL_LO_PULLUP:
      return new vhdl_const_bit('1');
   case IVL_LO_PULLDOWN:
      return new vhdl_const_bit('0');
   default:
      error("Don't know how to translate logic type = %d to expression",
            ivl_logic_type(log));
      return NULL;
   }
}

void draw_logic(vhdl_arch *arch, ivl_net_logic_t log)
{
   switch (ivl_logic_type(log)) {
   case IVL_LO_BUFIF0:
      bufif_logic(arch, log, true);
      break;
   case IVL_LO_BUFIF1:
      bufif_logic(arch, log, false);
      break;
   case IVL_LO_UDP:
      udp_logic(arch, log);
      break;
   default:
      {
         // The output is always pin zero
         ivl_nexus_t output = ivl_logic_pin(log, 0);
         vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output);

         vhdl_expr *rhs = translate_logic_inputs(arch->get_scope(), log);
         vhdl_cassign_stmt *ass = new vhdl_cassign_stmt(lhs, rhs);

         ivl_expr_t delay = ivl_logic_delay(log, 1);
         if (delay)
            ass->set_after(translate_time_expr(delay));

         arch->add_stmt(ass);
      }
   }
}
<commit_msg>Fix regression caused by UDP delay patch<commit_after>/*
 *  VHDL code generation for logic devices.
 *
 *  Copyright (C) 2008  Nick Gasson (nick@nickg.me.uk)
 *
 *  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.
 */

#include "vhdl_target.h"
#include "vhdl_element.hh"

#include <cassert>
#include <sstream>
#include <iostream>

/*
 * Convert the inputs of a logic gate to a binary expression.
 */
static vhdl_expr *inputs_to_expr(vhdl_scope *scope, vhdl_binop_t op,
                                 ivl_net_logic_t log)
{
   // Not always std_logic but this is probably OK since
   // the program has already been type checked
   vhdl_binop_expr *gate =
      new vhdl_binop_expr(op, vhdl_type::std_logic());

   int npins = ivl_logic_pins(log);
   for (int i = 1; i < npins; i++) {
      ivl_nexus_t input = ivl_logic_pin(log, i);
      gate->add_expr(nexus_to_var_ref(scope, input));
   }

   return gate;
}

/*
 * Convert a gate intput to an unary expression.
 */
static vhdl_expr *input_to_expr(vhdl_scope *scope, vhdl_unaryop_t op,
                                ivl_net_logic_t log)
{
   ivl_nexus_t input = ivl_logic_pin(log, 1);
   assert(input);

   vhdl_expr *operand = nexus_to_var_ref(scope, input);
   return new vhdl_unaryop_expr(op, operand, vhdl_type::std_logic());
}

static void bufif_logic(vhdl_arch *arch, ivl_net_logic_t log, bool if0)
{
   ivl_nexus_t output = ivl_logic_pin(log, 0);
   vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output);
   assert(lhs);

   vhdl_expr *val = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 1));
   assert(val);

   vhdl_expr *sel = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 2));
   assert(val);

   vhdl_expr *on = new vhdl_const_bit(if0 ? '0' : '1');
   vhdl_expr *cmp = new vhdl_binop_expr(sel, VHDL_BINOP_EQ, on, NULL);

   ivl_signal_t sig = find_signal_named(lhs->get_name(), arch->get_scope());
   char zbit;
   switch (ivl_signal_type(sig)) {
   case IVL_SIT_TRI0:
      zbit = '0';
      break;
   case IVL_SIT_TRI1:
      zbit = '1';
      break;
   case IVL_SIT_TRI:
   default:
      zbit = 'Z';
   }

   vhdl_const_bit *z = new vhdl_const_bit(zbit);
   vhdl_cassign_stmt *cass = new vhdl_cassign_stmt(lhs, z);
   cass->add_condition(val, cmp);

   arch->add_stmt(cass);
}

static void udp_logic(vhdl_arch *arch, ivl_net_logic_t log)
{
   ivl_udp_t udp = ivl_logic_udp(log);

   if (ivl_udp_sequ(udp)) {
      error("Sequential UDP devices not supported yet");
      return;
   }

   // As with regular case statements, the expression in a
   // `with .. select' statement must be "locally static".
   // This is achieved by first combining the inputs into
   // a temporary

   ostringstream ss;
   ss << ivl_logic_basename(log) << "_Tmp";
   int msb = ivl_udp_nin(udp) - 1;
   vhdl_type *tmp_type = vhdl_type::std_logic_vector(msb, 0);
   vhdl_signal_decl *tmp_decl =
      new vhdl_signal_decl(ss.str().c_str(), tmp_type);
   arch->get_scope()->add_decl(tmp_decl);

   int nin = ivl_udp_nin(udp);
   vhdl_expr *tmp_rhs;
   if (nin == 1) {
      tmp_rhs = nexus_to_var_ref(arch->get_scope(), ivl_logic_pin(log, 1));
      tmp_rhs = tmp_rhs->cast(tmp_type);
   }
   else
      tmp_rhs = inputs_to_expr(arch->get_scope(), VHDL_BINOP_CONCAT, log);

   ss.str("");
   ss << "Input to " << ivl_logic_basename(log) << " "
      << ivl_udp_name(udp) << " UDP";
   tmp_decl->set_comment(ss.str());

   vhdl_var_ref *tmp_ref =
      new vhdl_var_ref(tmp_decl->get_name().c_str(), NULL);
   arch->add_stmt(new vhdl_cassign_stmt(tmp_ref, tmp_rhs));

   // Now we can implement the UDP as a `with .. select' statement
   // by reading values out of the table
   ivl_nexus_t output_nex = ivl_logic_pin(log, 0);
   vhdl_var_ref *out = nexus_to_var_ref(arch->get_scope(), output_nex);
   vhdl_with_select_stmt *ws =
      new vhdl_with_select_stmt(new vhdl_var_ref(*tmp_ref), out);

   int nrows = ivl_udp_rows(udp);
   for (int i = 0; i < nrows; i++) {
      const char *row = ivl_udp_row(udp, i);

      vhdl_expr *value = new vhdl_const_bit(row[nin]);
      vhdl_expr *cond = new vhdl_const_bits(row, nin, false);

      ivl_expr_t delay_ex = ivl_logic_delay(log, 1);
      vhdl_expr *delay = NULL;
      if (delay_ex)
         delay = translate_time_expr(delay_ex);

      ws->add_condition(value, cond, delay);
   }

   ss.str("");
   ss << "UDP " << ivl_udp_name(udp);
   ws->set_comment(ss.str());

   arch->add_stmt(ws);
}

static vhdl_expr *translate_logic_inputs(vhdl_scope *scope, ivl_net_logic_t log)
{
   switch (ivl_logic_type(log)) {
   case IVL_LO_NOT:
      return input_to_expr(scope, VHDL_UNARYOP_NOT, log);
   case IVL_LO_AND:
      return inputs_to_expr(scope, VHDL_BINOP_AND, log);
   case IVL_LO_OR:
      return inputs_to_expr(scope, VHDL_BINOP_OR, log);
   case IVL_LO_NAND:
      return inputs_to_expr(scope, VHDL_BINOP_NAND, log);
   case IVL_LO_NOR:
      return inputs_to_expr(scope, VHDL_BINOP_NOR, log);
   case IVL_LO_XOR:
      return inputs_to_expr(scope, VHDL_BINOP_XOR, log);
   case IVL_LO_XNOR:
      return inputs_to_expr(scope, VHDL_BINOP_XNOR, log);
   case IVL_LO_BUF:
   case IVL_LO_BUFZ:
      return nexus_to_var_ref(scope, ivl_logic_pin(log, 1));
   case IVL_LO_PULLUP:
      return new vhdl_const_bit('1');
   case IVL_LO_PULLDOWN:
      return new vhdl_const_bit('0');
   default:
      error("Don't know how to translate logic type = %d to expression",
            ivl_logic_type(log));
      return NULL;
   }
}

void draw_logic(vhdl_arch *arch, ivl_net_logic_t log)
{
   switch (ivl_logic_type(log)) {
   case IVL_LO_BUFIF0:
      bufif_logic(arch, log, true);
      break;
   case IVL_LO_BUFIF1:
      bufif_logic(arch, log, false);
      break;
   case IVL_LO_UDP:
      udp_logic(arch, log);
      break;
   default:
      {
         // The output is always pin zero
         ivl_nexus_t output = ivl_logic_pin(log, 0);
         vhdl_var_ref *lhs = nexus_to_var_ref(arch->get_scope(), output);

         vhdl_expr *rhs = translate_logic_inputs(arch->get_scope(), log);
         vhdl_cassign_stmt *ass = new vhdl_cassign_stmt(lhs, rhs);

         ivl_expr_t delay = ivl_logic_delay(log, 1);
         if (delay)
            ass->set_after(translate_time_expr(delay));

         arch->add_stmt(ass);
      }
   }
}
<|endoftext|>


<commit_before>/** Copyright (C) 2016 Ultimaker - Released under terms of the AGPLv3 License */
#include "wallOverlap.h"

#include <cmath> // isfinite
#include <sstream>

#include "utils/AABB.h" // for debug output svg html
#include "utils/SVG.h"

namespace cura
{

WallOverlapComputation::WallOverlapComputation(Polygons& polygons, int line_width)
: overlap_linker(polygons, line_width)
, line_width(line_width)
{

}

float WallOverlapComputation::getFlow(Point& from, Point& to)
{
    using Point2LinkIt = PolygonProximityLinker::Point2Link::iterator;

    if (!overlap_linker.isLinked(from))
    { // [from] is not linked
        return 1;
    }
    const std::pair<Point2LinkIt, Point2LinkIt> to_links = overlap_linker.getLinks(to);
    if (to_links.first == to_links.second)
    { // [to] is not linked
        return 1;
    }

    int64_t overlap_area = 0;
    // note that we don't need to loop over all from_links, because they are handled in the previous getFlow(.) call (or in the very last)
    for (Point2LinkIt to_link_it = to_links.first; to_link_it != to_links.second; ++to_link_it)
    {
        const ProximityPointLink& to_link = to_link_it->second;
        ListPolyIt to_it = to_link.a;
        ListPolyIt to_other_it = to_link.b;
        if (to_link.a.p() != to)
        {
            assert(to_link.b.p() == to && "Either part of the link should be the point in the link!");
            std::swap(to_it, to_other_it);
        }
        ListPolyIt from_it = to_it.prev();
        assert(from_it.p() == from && "From location doesn't seem to be connected to destination location!");

        ListPolyIt to_other_next_it = to_other_it.next(); // move towards [from]; the lines on the other side move in the other direction
        //           to  from
        //   o<--o<--T<--F
        //   |       :   :
        //   v       :   :
        //   o-->o-->o-->o
        //           ,   ,
        //           ;   to_other_next
        //           to other

        bool are_in_same_general_direction = dot(from - to, to_other_it.p() - to_other_next_it.p()) > 0;
        // handle multiple points  linked to [to]
        //   o<<<T<<<F
        //     / |
        //    /  |
        //   o>>>o>>>o
        //   ,   ,
        //   ;   to other next
        //   to other
        if (!are_in_same_general_direction)
        {
            overlap_area += handlePotentialOverlap(to_link, to_other_next_it, to_it);
        }

        // handle multiple points  linked to [to_other]
        //   o<<<T<<<F
        //       |  /
        //       | /
        //   o>>>o>>>o
        bool all_are_in_same_general_direction = are_in_same_general_direction && dot(from - to, to_other_it.prev().p() - to_other_it.p()) > 0;
        if (!all_are_in_same_general_direction)
        {
            overlap_area += handlePotentialOverlap(to_link, to_other_it, from_it);
        }

        // handle normal case where the segment from-to overlaps with another segment
        //   o<<<T<<<F
        //       |   |
        //       |   |
        //   o>>>o>>>o
        //       ,   ,
        //       ;   to other next
        //       to other
        if (!are_in_same_general_direction)
        {
            overlap_area += handlePotentialOverlap(to_link, to_other_next_it, from_it);
        }
    }

    int64_t normal_area = vSize(from - to) * line_width;
    float ratio = float(normal_area - overlap_area) / normal_area;
    if (ratio > 1.0)
    {
        return 1.0;
    }
    if (ratio < 0.0)
    {
        return 0;
    }
    return ratio;
}

int64_t WallOverlapComputation::handlePotentialOverlap(const ProximityPointLink& link_a, const ListPolyIt from_it, const ListPolyIt to_it)
{
    const ProximityPointLink* link_b = overlap_linker.getLink(from_it, to_it);
    if (!link_b)
    {
        return 0;
    }
    if (!getIsPassed(link_a, *link_b))
    { // check whether the segment is already passed
        setIsPassed(link_a, *link_b);
        return 0;
    }
    // mark the segment as passed
    setIsPassed(link_a, *link_b);
    return getApproxOverlapArea(link_a, *link_b);
}

int64_t WallOverlapComputation::getApproxOverlapArea(const ProximityPointLink& from, const ProximityPointLink& to)
{
    return getApproxOverlapArea(from.a.p(), from.b.p(), from.dist, to.a.p(), to.b.p(), to.dist);
}

int64_t WallOverlapComputation::getApproxOverlapArea(const Point from_a, const Point from_b, const int64_t from_dist, const Point to_a, const Point to_b, const int64_t to_dist)
{
    const Point from_middle = from_a + from_b; // dont divide by two just yet
    const Point to_middle = to_a + to_b; // dont divide by two just yet

    const int64_t dist_2 = vSize(from_middle - to_middle);

    const int64_t average_dists_2 = line_width * 2 - from_dist - to_dist; // dont divide by two just yet

    const int64_t area = dist_2 * average_dists_2 / 4; // divide by 2 two times: once for the middles and once for the average_dists
    return area;
}

bool WallOverlapComputation::getIsPassed(const ProximityPointLink& link_a, const ProximityPointLink& link_b)
{
    return passed_links.find(SymmetricPair<ProximityPointLink>(link_a, link_b)) != passed_links.end();
}

void WallOverlapComputation::setIsPassed(const ProximityPointLink& link_a, const ProximityPointLink& link_b)
{
    passed_links.emplace(link_a, link_b);
}

}//namespace cura
<commit_msg>lil rename in wall overlap (CURA-1911)<commit_after>/** Copyright (C) 2016 Ultimaker - Released under terms of the AGPLv3 License */
#include "wallOverlap.h"

#include <cmath> // isfinite
#include <sstream>

#include "utils/AABB.h" // for debug output svg html
#include "utils/SVG.h"

namespace cura
{

WallOverlapComputation::WallOverlapComputation(Polygons& polygons, int line_width)
: overlap_linker(polygons, line_width)
, line_width(line_width)
{

}

float WallOverlapComputation::getFlow(Point& from, Point& to)
{
    using Point2LinkIt = PolygonProximityLinker::Point2Link::iterator;

    if (!overlap_linker.isLinked(from))
    { // [from] is not linked
        return 1;
    }
    const std::pair<Point2LinkIt, Point2LinkIt> to_links = overlap_linker.getLinks(to);
    if (to_links.first == to_links.second)
    { // [to] is not linked
        return 1;
    }

    int64_t overlap_area = 0;
    // note that we don't need to loop over all from_links, because they are handled in the previous getFlow(.) call (or in the very last)
    for (Point2LinkIt to_link_it = to_links.first; to_link_it != to_links.second; ++to_link_it)
    {
        const ProximityPointLink& to_link = to_link_it->second;
        ListPolyIt to_it = to_link.a;
        ListPolyIt to_other_it = to_link.b;
        if (to_link.a.p() != to)
        {
            assert(to_link.b.p() == to && "Either part of the link should be the point in the link!");
            std::swap(to_it, to_other_it);
        }
        ListPolyIt from_it = to_it.prev();
        assert(from_it.p() == from && "From location doesn't seem to be connected to destination location!");

        ListPolyIt to_other_next_it = to_other_it.next(); // move towards [from]; the lines on the other side move in the other direction
        //           to  from
        //   o<--o<--T<--F
        //   |       :   :
        //   v       :   :
        //   o-->o-->o-->o
        //           ,   ,
        //           ;   to_other_next
        //           to other

        bool are_in_same_general_direction = dot(from - to, to_other_it.p() - to_other_next_it.p()) > 0;
        // handle multiple points  linked to [to]
        //   o<<<T<<<F
        //     / |
        //    /  |
        //   o>>>o>>>o
        //   ,   ,
        //   ;   to other next
        //   to other
        if (!are_in_same_general_direction)
        {
            overlap_area += handlePotentialOverlap(to_link, to_other_next_it, to_it);
        }

        // handle multiple points  linked to [to_other]
        //   o<<<T<<<F
        //       |  /
        //       | /
        //   o>>>o>>>o
        bool all_are_in_same_general_direction = are_in_same_general_direction && dot(from - to, to_other_it.prev().p() - to_other_it.p()) > 0;
        if (!all_are_in_same_general_direction)
        {
            overlap_area += handlePotentialOverlap(to_link, to_other_it, from_it);
        }

        // handle normal case where the segment from-to overlaps with another segment
        //   o<<<T<<<F
        //       |   |
        //       |   |
        //   o>>>o>>>o
        //       ,   ,
        //       ;   to other next
        //       to other
        if (!are_in_same_general_direction)
        {
            overlap_area += handlePotentialOverlap(to_link, to_other_next_it, from_it);
        }
    }

    int64_t normal_area = vSize(from - to) * line_width;
    float ratio = float(normal_area - overlap_area) / normal_area;
    if (ratio > 1.0)
    {
        return 1.0;
    }
    if (ratio < 0.0)
    {
        return 0;
    }
    return ratio;
}

int64_t WallOverlapComputation::handlePotentialOverlap(const ProximityPointLink& link_a, const ListPolyIt from_it, const ListPolyIt to_it)
{
    const ProximityPointLink* link_b = overlap_linker.getLink(from_it, to_it);
    if (!link_b)
    {
        return 0;
    }
    if (!getIsPassed(link_a, *link_b))
    { // check whether the segment is already passed
        setIsPassed(link_a, *link_b);
        return 0;
    }
    // mark the segment as passed
    setIsPassed(link_a, *link_b);
    return getApproxOverlapArea(link_a, *link_b);
}

int64_t WallOverlapComputation::getApproxOverlapArea(const ProximityPointLink& from, const ProximityPointLink& to)
{
    return getApproxOverlapArea(from.a.p(), from.b.p(), from.dist, to.a.p(), to.b.p(), to.dist);
}

int64_t WallOverlapComputation::getApproxOverlapArea(const Point from_a, const Point from_b, const int64_t from_dist, const Point to_a, const Point to_b, const int64_t to_dist)
{
    const Point from_middle = from_a + from_b; // dont divide by two just yet
    const Point to_middle = to_a + to_b; // dont divide by two just yet

    const int64_t link_dist_2 = vSize(from_middle - to_middle);

    const int64_t average_overlap_dist_2 = line_width * 2 - from_dist - to_dist; // dont divide by two just yet

    const int64_t area = link_dist_2 * average_overlap_dist_2 / 4; // divide by 2 two times: once for the middles and once for the average_dists
    return area;
}

bool WallOverlapComputation::getIsPassed(const ProximityPointLink& link_a, const ProximityPointLink& link_b)
{
    return passed_links.find(SymmetricPair<ProximityPointLink>(link_a, link_b)) != passed_links.end();
}

void WallOverlapComputation::setIsPassed(const ProximityPointLink& link_a, const ProximityPointLink& link_b)
{
    passed_links.emplace(link_a, link_b);
}

}//namespace cura
<|endoftext|>


<commit_before>/*********************************************************************
* Software License Agreement (BSD License)
*
*  Copyright (c) 2010, Rice University
*  All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the Rice University nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
*  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
*  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
*  POSSIBILITY OF SUCH DAMAGE.
*********************************************************************/

/* Author: Ioan Sucan */

#include <gtest/gtest.h>
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
#include <libgen.h>
#include <iostream>

#include "ompl/base/ScopedState.h"
#include "ompl/base/manifolds/SE3StateManifold.h"
#include "ompl/base/SpaceInformation.h"
#include "ompl/util/Time.h"

using namespace ompl;

TEST(State, Scoped)
{
    base::SE3StateManifold *mSE3 = new base::SE3StateManifold();
    base::StateManifoldPtr pSE3(mSE3);

    base::RealVectorBounds b(3);
    b.setLow(0);
    b.setHigh(1);
    mSE3->setBounds(b);

    base::CompoundStateManifold *mC0 = new base::CompoundStateManifold();
    base::StateManifoldPtr pC0(mC0);
    mC0->addSubManifold(pSE3, 1.0);

    base::CompoundStateManifold *mC1 = new base::CompoundStateManifold();
    base::StateManifoldPtr pC1(mC1);
    mC1->addSubManifold(pC0, 1.0);

    base::CompoundStateManifold *mC2 = new base::CompoundStateManifold();
    base::StateManifoldPtr pC2(mC2);
    mC2->addSubManifold(mSE3->getSubManifold(1), 1.0);
    mC2->addSubManifold(mSE3->getSubManifold(0), 1.0);

    base::ScopedState<base::SE3StateManifold> sSE3(pSE3);
    base::ScopedState<base::RealVectorStateManifold> sSE3_R(mSE3->getSubManifold(0));
    base::ScopedState<base::SO3StateManifold> sSE3_SO2(mSE3->getSubManifold(1));
    base::ScopedState<base::CompoundStateManifold> sC0(pC0);
    base::ScopedState<> sC1(pC1);
    base::ScopedState<> sC2(pC2);

    sSE3.random();

    sSE3 >> sSE3_SO2;

    EXPECT_EQ(sSE3->rotation().x, sSE3_SO2->x);
    EXPECT_EQ(sSE3->rotation().y, sSE3_SO2->y);
    EXPECT_EQ(sSE3->rotation().z, sSE3_SO2->z);
    EXPECT_EQ(sSE3->rotation().w, sSE3_SO2->w);

    base::ScopedState<> sSE3_copy(pSE3);
    sSE3_copy << sSE3;
    EXPECT_EQ(sSE3_copy, sSE3);
    sSE3 >> sSE3_copy;
    EXPECT_EQ(sSE3_copy, sSE3);

    sSE3_R << sSE3_copy;

    EXPECT_EQ(sSE3->getX(), sSE3_R->values[0]);
    EXPECT_EQ(sSE3->getY(), sSE3_R->values[1]);
    EXPECT_EQ(sSE3->getZ(), sSE3_R->values[2]);

    sSE3_SO2 >> sC1;
    sC1 << sSE3_R;

    sC1 >> sC0;
    sSE3_copy = sC0->components[0];
    EXPECT_EQ(sSE3_copy, sSE3);

    sSE3.random();

    sSE3 >> sC2;
    sSE3_copy << sC2;
    EXPECT_EQ(sSE3_copy, sSE3);

    sSE3.random();
    sSE3 >> sSE3_SO2;
    sSE3 >> sSE3_R;

    (sSE3_R ^ sSE3_SO2) >> sSE3_copy;
    EXPECT_EQ(sSE3_copy, sSE3);
    EXPECT_EQ(sSE3_copy[pSE3 * sSE3_R.getManifold()], sSE3_R);
    EXPECT_EQ(sSE3_copy[sSE3_SO2.getManifold()], sSE3_SO2);

    sSE3->setY(1.0);
    EXPECT_NEAR(sSE3.reals()[1], 1.0, 1e-12);

    sSE3.random();
    std::vector<double> r = sSE3.reals();
    EXPECT_EQ(r.size(), 7);
    sSE3_copy = r;
    EXPECT_EQ(sSE3_copy, sSE3);
}

TEST(State, Allocation)
{
    base::StateManifoldPtr m(new base::SE3StateManifold());
    base::RealVectorBounds b(3);
    b.setLow(0);
    b.setHigh(1);
    m->as<base::SE3StateManifold>()->setBounds(b);
    base::SpaceInformation si(m);
    si.setup();

    const unsigned int N = 50000;
    const unsigned int M = 20;
    std::vector<base::State*> states(N, NULL);

    ompl::time::point start = ompl::time::now();
    for (unsigned int j = 0 ; j < M ; ++j)
    {
        for (unsigned int i = 0 ; i < N ; ++i)
            states[i] = si.allocState();

        for (unsigned int i = 0 ; i < N ; ++i)
            si.freeState(states[i]);
    }
    double d = ompl::time::seconds(ompl::time::now() - start);
    std::cout << (double)N * (double)M / d << " state allocations then frees per second" << std::endl;

    start = ompl::time::now();
    for (unsigned int j = 0 ; j < M ; ++j)
    {
        for (unsigned int i = 0 ; i < N ; ++i)
        {
            base::State *s = si.allocState();
            si.freeState(s);
        }
    }
    d = ompl::time::seconds(ompl::time::now() - start);
    std::cout << (double)N * (double)M / d << " mixed state allocations & frees per second" << std::endl;

    start = ompl::time::now();
    for (unsigned int j = 0 ; j < M ; ++j)
    {
        for (unsigned int i = 0 ; i < N ; ++i)
        {
            base::State *s = si.allocState();
            si.freeState(s);
            states[i] = si.allocState();
        }
        for (unsigned int i = 0 ; i < N ; ++i)
            si.freeState(states[i]);
    }
    d = ompl::time::seconds(ompl::time::now() - start);
    std::cout << (double)N * (double)M / d << " allocations per second" << std::endl;
}

void randomizedAllocator(const base::SpaceInformation *si)
{
    RNG r;
    const unsigned int n = 5000;

    std::vector<base::State*> states(n + 1, NULL);
    for (unsigned int i = 0 ; i < n * 1000 ; ++i)
    {
        int j = r.uniformInt(0, n);
        if (states[j] == NULL)
            states[j] = si->allocState();
        else
        {
            si->freeState(states[j]);
            states[j] = NULL;
        }
    }
    for (unsigned int i = 0 ; i < states.size() ; ++i)
        if (states[i])
            si->freeState(states[i]);
}

TEST(State, AllocationWithThreads)
{
    base::StateManifoldPtr m(new base::SE3StateManifold());
    base::RealVectorBounds b(3);
    b.setLow(0);
    b.setHigh(1);
    m->as<base::SE3StateManifold>()->setBounds(b);
    base::SpaceInformation si(m);
    si.setup();
    const int NT = 10;
    ompl::time::point start = ompl::time::now();
    std::vector<boost::thread*> threads;
    for (int i = 0 ; i < NT ; ++i)
        threads.push_back(new boost::thread(boost::bind(&randomizedAllocator, &si)));
    for (int i = 0 ; i < NT ; ++i)
    {
        threads[i]->join();
        delete threads[i];
    }
    std::cout << "Time spent randomly allocating & freeing states: "
        << ompl::time::seconds(ompl::time::now() - start) << std::endl;
}

int main(int argc, char **argv)
{
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<commit_msg>fix compilation warning<commit_after>/*********************************************************************
* Software License Agreement (BSD License)
*
*  Copyright (c) 2010, Rice University
*  All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the Rice University nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
*  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
*  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
*  POSSIBILITY OF SUCH DAMAGE.
*********************************************************************/

/* Author: Ioan Sucan */

#include <gtest/gtest.h>
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
#include <libgen.h>
#include <iostream>

#include "ompl/base/ScopedState.h"
#include "ompl/base/manifolds/SE3StateManifold.h"
#include "ompl/base/SpaceInformation.h"
#include "ompl/util/Time.h"

using namespace ompl;

TEST(State, Scoped)
{
    base::SE3StateManifold *mSE3 = new base::SE3StateManifold();
    base::StateManifoldPtr pSE3(mSE3);

    base::RealVectorBounds b(3);
    b.setLow(0);
    b.setHigh(1);
    mSE3->setBounds(b);

    base::CompoundStateManifold *mC0 = new base::CompoundStateManifold();
    base::StateManifoldPtr pC0(mC0);
    mC0->addSubManifold(pSE3, 1.0);

    base::CompoundStateManifold *mC1 = new base::CompoundStateManifold();
    base::StateManifoldPtr pC1(mC1);
    mC1->addSubManifold(pC0, 1.0);

    base::CompoundStateManifold *mC2 = new base::CompoundStateManifold();
    base::StateManifoldPtr pC2(mC2);
    mC2->addSubManifold(mSE3->getSubManifold(1), 1.0);
    mC2->addSubManifold(mSE3->getSubManifold(0), 1.0);

    base::ScopedState<base::SE3StateManifold> sSE3(pSE3);
    base::ScopedState<base::RealVectorStateManifold> sSE3_R(mSE3->getSubManifold(0));
    base::ScopedState<base::SO3StateManifold> sSE3_SO2(mSE3->getSubManifold(1));
    base::ScopedState<base::CompoundStateManifold> sC0(pC0);
    base::ScopedState<> sC1(pC1);
    base::ScopedState<> sC2(pC2);

    sSE3.random();

    sSE3 >> sSE3_SO2;

    EXPECT_EQ(sSE3->rotation().x, sSE3_SO2->x);
    EXPECT_EQ(sSE3->rotation().y, sSE3_SO2->y);
    EXPECT_EQ(sSE3->rotation().z, sSE3_SO2->z);
    EXPECT_EQ(sSE3->rotation().w, sSE3_SO2->w);

    base::ScopedState<> sSE3_copy(pSE3);
    sSE3_copy << sSE3;
    EXPECT_EQ(sSE3_copy, sSE3);
    sSE3 >> sSE3_copy;
    EXPECT_EQ(sSE3_copy, sSE3);

    sSE3_R << sSE3_copy;

    EXPECT_EQ(sSE3->getX(), sSE3_R->values[0]);
    EXPECT_EQ(sSE3->getY(), sSE3_R->values[1]);
    EXPECT_EQ(sSE3->getZ(), sSE3_R->values[2]);

    sSE3_SO2 >> sC1;
    sC1 << sSE3_R;

    sC1 >> sC0;
    sSE3_copy = sC0->components[0];
    EXPECT_EQ(sSE3_copy, sSE3);

    sSE3.random();

    sSE3 >> sC2;
    sSE3_copy << sC2;
    EXPECT_EQ(sSE3_copy, sSE3);

    sSE3.random();
    sSE3 >> sSE3_SO2;
    sSE3 >> sSE3_R;

    (sSE3_R ^ sSE3_SO2) >> sSE3_copy;
    EXPECT_EQ(sSE3_copy, sSE3);
    EXPECT_EQ(sSE3_copy[pSE3 * sSE3_R.getManifold()], sSE3_R);
    EXPECT_EQ(sSE3_copy[sSE3_SO2.getManifold()], sSE3_SO2);

    sSE3->setY(1.0);
    EXPECT_NEAR(sSE3.reals()[1], 1.0, 1e-12);

    sSE3.random();
    std::vector<double> r = sSE3.reals();
    EXPECT_EQ(r.size(), 7u);
    sSE3_copy = r;
    EXPECT_EQ(sSE3_copy, sSE3);
}

TEST(State, Allocation)
{
    base::StateManifoldPtr m(new base::SE3StateManifold());
    base::RealVectorBounds b(3);
    b.setLow(0);
    b.setHigh(1);
    m->as<base::SE3StateManifold>()->setBounds(b);
    base::SpaceInformation si(m);
    si.setup();

    const unsigned int N = 50000;
    const unsigned int M = 20;
    std::vector<base::State*> states(N, NULL);

    ompl::time::point start = ompl::time::now();
    for (unsigned int j = 0 ; j < M ; ++j)
    {
        for (unsigned int i = 0 ; i < N ; ++i)
            states[i] = si.allocState();

        for (unsigned int i = 0 ; i < N ; ++i)
            si.freeState(states[i]);
    }
    double d = ompl::time::seconds(ompl::time::now() - start);
    std::cout << (double)N * (double)M / d << " state allocations then frees per second" << std::endl;

    start = ompl::time::now();
    for (unsigned int j = 0 ; j < M ; ++j)
    {
        for (unsigned int i = 0 ; i < N ; ++i)
        {
            base::State *s = si.allocState();
            si.freeState(s);
        }
    }
    d = ompl::time::seconds(ompl::time::now() - start);
    std::cout << (double)N * (double)M / d << " mixed state allocations & frees per second" << std::endl;

    start = ompl::time::now();
    for (unsigned int j = 0 ; j < M ; ++j)
    {
        for (unsigned int i = 0 ; i < N ; ++i)
        {
            base::State *s = si.allocState();
            si.freeState(s);
            states[i] = si.allocState();
        }
        for (unsigned int i = 0 ; i < N ; ++i)
            si.freeState(states[i]);
    }
    d = ompl::time::seconds(ompl::time::now() - start);
    std::cout << (double)N * (double)M / d << " allocations per second" << std::endl;
}

void randomizedAllocator(const base::SpaceInformation *si)
{
    RNG r;
    const unsigned int n = 5000;

    std::vector<base::State*> states(n + 1, NULL);
    for (unsigned int i = 0 ; i < n * 1000 ; ++i)
    {
        int j = r.uniformInt(0, n);
        if (states[j] == NULL)
            states[j] = si->allocState();
        else
        {
            si->freeState(states[j]);
            states[j] = NULL;
        }
    }
    for (unsigned int i = 0 ; i < states.size() ; ++i)
        if (states[i])
            si->freeState(states[i]);
}

TEST(State, AllocationWithThreads)
{
    base::StateManifoldPtr m(new base::SE3StateManifold());
    base::RealVectorBounds b(3);
    b.setLow(0);
    b.setHigh(1);
    m->as<base::SE3StateManifold>()->setBounds(b);
    base::SpaceInformation si(m);
    si.setup();
    const int NT = 10;
    ompl::time::point start = ompl::time::now();
    std::vector<boost::thread*> threads;
    for (int i = 0 ; i < NT ; ++i)
        threads.push_back(new boost::thread(boost::bind(&randomizedAllocator, &si)));
    for (int i = 0 ; i < NT ; ++i)
    {
        threads[i]->join();
        delete threads[i];
    }
    std::cout << "Time spent randomly allocating & freeing states: "
        << ompl::time::seconds(ompl::time::now() - start) << std::endl;
}

int main(int argc, char **argv)
{
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>#include <iostream>
#include <string>

bool isUniqueChar1(const std::string &str);
bool isUniqueChar2(const std::string &str);
bool isUniqueChar3(const std::string &str);

int main(int argc, char *argv[])
{
    std::string str1 = "just one.";
    if ( isUniqueChar1(str1) )
    {
        std::cout << str1 << " has all unique characters." << std::endl;
    }
    else
    {
        std::cout << str1 << " hasn't all unique characters." << std::endl;
    }

    std::string str2 = "I am hahaya.";
    if ( isUniqueChar2(str2) )
    {
        std::cout << str2 << " has all unique characters." << std::endl;
    }
    else
    {
        std::cout << str2 << " hasn't all unique characters." << std::endl;
    }

    std::string str3 = "abcdefg";
    if ( isUniqueChar3(str3) )
    {
        std::cout << str3 << " has all unique characters." << std::endl;
    }
    else
    {
        std::cout << str3 << " hasn't all unique characters." << std::endl;
    }

    return 0;
}

//stringеַȫΪASCIIʱ(ⷨһ)
bool isUniqueChar1(const std::string &str)
{
    bool char_set[256];
    memset( char_set, 0, sizeof(char_set) ); //뽫λófalse

    for ( unsigned int i = 0; i < str.length(); ++i )
    {
        int value = (int)str.at(i);
        if ( char_set[value] )
        {
            return false;
        }
        char_set[value] = true;
    }
    return true;
}

//stringеַȫΪASCIIʱ(ⷨ)
bool isUniqueChar2(const std::string &str)
{
    int checker[8];
    memset(checker, 0, sizeof(checker)); //뽫λó0

    for ( unsigned int i = 0; i < str.length(); ++i )
    {
        int value = (int)str.at(i);
        int row = value/32;
        int colunm = value%32;
        if ( checker[row] & (1<<colunm) )
        {
            return false;
        }
        checker[row] |= (1<<colunm);
    }
    return true;
}

//stringеַȫΪĸʱ(ֻ'a' - 'z')
bool isUniqueChar3(const std::string &str)
{
    int checker = 0;    //뽫λó0

    for ( unsigned int i = 0; i < str.length(); ++i )
    {
        int value = (int)(str.at(i) - 'a' );
        if ( checker & (1<<value) )
        {
            return false;
        }
        checker |= (1<<value);
    }
    return true;
}
<commit_msg>change value name<commit_after>#include <iostream>
#include <string>

bool isUniqueChar1(const std::string &str);
bool isUniqueChar2(const std::string &str);
bool isUniqueChar3(const std::string &str);

int main(int argc, char *argv[])
{
    std::string str1 = "just one.";
    if ( isUniqueChar1(str1) )
    {
        std::cout << str1 << " has all unique characters." << std::endl;
    }
    else
    {
        std::cout << str1 << " hasn't all unique characters." << std::endl;
    }

    std::string str2 = "I am hahaya.";
    if ( isUniqueChar2(str2) )
    {
        std::cout << str2 << " has all unique characters." << std::endl;
    }
    else
    {
        std::cout << str2 << " hasn't all unique characters." << std::endl;
    }

    std::string str3 = "abcdefg";
    if ( isUniqueChar3(str3) )
    {
        std::cout << str3 << " has all unique characters." << std::endl;
    }
    else
    {
        std::cout << str3 << " hasn't all unique characters." << std::endl;
    }

    return 0;
}

//stringеַȫΪASCIIʱ(ⷨһ)
bool isUniqueChar1(const std::string &str)
{
    bool checker[256];
    memset( checker, 0, sizeof(checker) ); //뽫λófalse

    for ( unsigned int i = 0; i < str.length(); ++i )
    {
        int value = (int)str.at(i);
        if ( checker[value] )
        {
            return false;
        }
        checker[value] = true;
    }
    return true;
}

//stringеַȫΪASCIIʱ(ⷨ)
bool isUniqueChar2(const std::string &str)
{
    int checker[8];
    memset(checker, 0, sizeof(checker)); //뽫λó0

    for ( unsigned int i = 0; i < str.length(); ++i )
    {
        int value = (int)str.at(i);
        int row = value/32;
        int colunm = value%32;
        if ( checker[row] & (1<<colunm) )
        {
            return false;
        }
        checker[row] |= (1<<colunm);
    }
    return true;
}

//stringеַȫΪĸʱ(ֻ'a' - 'z')
bool isUniqueChar3(const std::string &str)
{
    int checker = 0;    //뽫λó0

    for ( unsigned int i = 0; i < str.length(); ++i )
    {
        int value = (int)(str.at(i) - 'a' );
        if ( checker & (1<<value) )
        {
            return false;
        }
        checker |= (1<<value);
    }
    return true;
}
<|endoftext|>