<commit_before>#ifndef FILESYSTEM_TEST_HELPER_HPP
#define FILESYSTEM_TEST_HELPER_HPP

#include <experimental/filesystem>
#include <cassert>
#include <cstdio> // for printf
#include <string>
#include <fstream>
#include <random>
#include <chrono>

namespace fs = std::experimental::filesystem;

// static test helpers

#ifndef LIBCXX_FILESYSTEM_STATIC_TEST_ROOT
#warning "STATIC TESTS DISABLED"
#else // LIBCXX_FILESYSTEM_STATIC_TEST_ROOT

namespace StaticEnv {

inline fs::path makePath(fs::path const& p) {
    static const fs::path env_path = LIBCXX_FILESYSTEM_STATIC_TEST_ROOT;
    return env_path / p;
}

static const fs::path Root = LIBCXX_FILESYSTEM_STATIC_TEST_ROOT;

static const fs::path TestFileList[] = {
        makePath("empty_file"),
        makePath("non_empty_file"),
        makePath("dir1/file1"),
        makePath("dir1/file2")
};
const std::size_t TestFileListSize = sizeof(TestFileList) / sizeof(fs::path);

static const fs::path TestDirList[] = {
        makePath("dir1"),
        makePath("dir1/dir2"),
        makePath("dir1/dir2/dir3")
};
const std::size_t TestDirListSize = sizeof(TestDirList) / sizeof(fs::path);

static const fs::path File          = TestFileList[0];
static const fs::path Dir           = TestDirList[0];
static const fs::path Dir2          = TestDirList[1];
static const fs::path Dir3          = TestDirList[2];
static const fs::path SymlinkToFile = makePath("symlink_to_empty_file");
static const fs::path SymlinkToDir  = makePath("symlink_to_dir");
static const fs::path BadSymlink    = makePath("bad_symlink");
static const fs::path DNE           = makePath("DNE");
static const fs::path EmptyFile     = TestFileList[0];
static const fs::path NonEmptyFile  = TestFileList[1];
static const fs::path CharFile      = "/dev/null"; // Hopefully this exists

static const fs::path DirIterationList[] = {
    makePath("dir1/dir2"),
    makePath("dir1/file1"),
    makePath("dir1/file2")
};
const std::size_t DirIterationListSize = sizeof(DirIterationList)
                                        / sizeof(fs::path);

static const fs::path DirIterationListDepth1[] = {
    makePath("dir1/dir2/afile3"),
    makePath("dir1/dir2/dir3"),
    makePath("dir1/dir2/symlink_to_dir3"),
    makePath("dir1/dir2/file4"),
};

static const fs::path RecDirIterationList[] = {
    makePath("dir1/dir2"),
    makePath("dir1/file1"),
    makePath("dir1/file2"),
    makePath("dir1/dir2/afile3"),
    makePath("dir1/dir2/dir3"),
    makePath("dir1/dir2/symlink_to_dir3"),
    makePath("dir1/dir2/file4"),
    makePath("dir1/dir2/dir3/file5")
};

static const fs::path RecDirFollowSymlinksIterationList[] = {
    makePath("dir1/dir2"),
    makePath("dir1/file1"),
    makePath("dir1/file2"),
    makePath("dir1/dir2/afile3"),
    makePath("dir1/dir2/dir3"),
    makePath("dir1/dir2/file4"),
    makePath("dir1/dir2/dir3/file5"),
    makePath("dir1/dir2/symlink_to_dir3"),
    makePath("dir1/dir2/symlink_to_dir3/file5"),
};

} // namespace StaticEnv

#endif // LIBCXX_FILESYSTEM_STATIC_TEST_ROOT

#ifndef LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT
#warning LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT must be defined
#else // LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT

#ifndef LIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER
#error LIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER must be defined
#endif

struct scoped_test_env
{
    scoped_test_env() : test_root(random_env_path())
        { fs_helper_run(fs_make_cmd("init_test_directory", test_root)); }

    ~scoped_test_env()
        { fs_helper_run(fs_make_cmd("destroy_test_directory", test_root)); }

    scoped_test_env(scoped_test_env const &) = delete;
    scoped_test_env & operator=(scoped_test_env const &) = delete;

    fs::path make_env_path(std::string p) { return sanitize_path(p); }

    std::string sanitize_path(std::string raw) {
        assert(raw.find("..") == std::string::npos);
        std::string const& root = test_root.native();
        if (root.compare(0, root.size(), raw, 0, root.size()) != 0) {
            assert(raw.front() != '\\');
            fs::path tmp(test_root);
            tmp /= raw;
            return std::move(const_cast<std::string&>(tmp.native()));
        }
        return raw;
    }

    std::string create_file(std::string filename, std::size_t size = 0) {
        filename = sanitize_path(std::move(filename));
        std::string out_str(size, 'a');
        {
            std::ofstream out(filename.c_str());
            out << out_str;
        }
        return filename;
    }

    std::string create_dir(std::string filename) {
        filename = sanitize_path(std::move(filename));
        fs_helper_run(fs_make_cmd("create_dir", filename));
        return filename;
    }

    std::string create_symlink(std::string source, std::string to) {
        source = sanitize_path(std::move(source));
        to = sanitize_path(std::move(to));
        fs_helper_run(fs_make_cmd("create_symlink", source, to));
        return to;
    }

    std::string create_hardlink(std::string source, std::string to) {
        source = sanitize_path(std::move(source));
        to = sanitize_path(std::move(to));
        fs_helper_run(fs_make_cmd("create_hardlink", source, to));
        return to;
    }

    std::string create_fifo(std::string file) {
        file = sanitize_path(std::move(file));
        fs_helper_run(fs_make_cmd("create_fifo", file));
        return file;
    }

  // OS X and FreeBSD doesn't support socket files so we shouldn't even
  // allow tests to call this unguarded.
#if !defined(__FreeBSD__) && !defined(__APPLE__)
    std::string create_socket(std::string file) {
        file = sanitize_path(std::move(file));
        fs_helper_run(fs_make_cmd("create_socket", file));
        return file;
    }
#endif

    fs::path const test_root;

private:
    static char to_hex(int ch) {
        return ch < 10 ? static_cast<char>('0' + ch)
                       : static_cast<char>('a' + (ch - 10));
    }

    static char random_hex_char() {
        static std::mt19937 rd { std::random_device{}() };
        static std::uniform_int_distribution<int> mrand{0, 15};
        return to_hex( mrand(rd) );
    }

    static std::string unique_path_suffix() {
        std::string model = "test.%%%%%%";
        for (auto & ch :  model) {
            if (ch == '%') ch = random_hex_char();
        }
        return model;
    }

    // This could potentially introduce a filesystem race with other tests
    // running at the same time, but oh well, it's just test code.
    static inline fs::path random_env_path() {
        static const char* env_path = LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT;
        fs::path p = fs::path(env_path) / unique_path_suffix();
        assert(p.parent_path() == env_path);
        return p;
    }

    static inline std::string make_arg(std::string const& arg) {
        return "'" + arg + "'";
    }

    static inline std::string make_arg(std::size_t arg) {
        return std::to_string(arg);
    }

    template <class T>
    static inline std::string
    fs_make_cmd(std::string const& cmd_name, T const& arg) {
        return cmd_name + "(" + make_arg(arg) + ")";
    }

    template <class T, class U>
    static inline std::string
    fs_make_cmd(std::string const& cmd_name, T const& arg1, U const& arg2) {
        return cmd_name + "(" + make_arg(arg1) + ", " + make_arg(arg2) + ")";
    }

    static inline void fs_helper_run(std::string const& raw_cmd) {
        // check that the fs test root in the enviroment matches what we were
        // compiled with.
        static bool checked = checkDynamicTestRoot();
        std::string cmd = LIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER;
        cmd += " \"" + raw_cmd + "\"";
        int ret = std::system(cmd.c_str());
        assert(ret == 0);
    }

    static bool checkDynamicTestRoot() {
        char* fs_root = std::getenv("LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT");
        if (!fs_root) {
            std::printf("ERROR: LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT must be a defined "
                         "environment variable when running the test.\n");
            std::abort();
        }
        if (std::string(fs_root) != LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT) {
            std::printf("ERROR: LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT enviroment variable"
                        " must have the same value as when the test was compiled.\n");
            std::printf("   Current Value:  '%s'\n", fs_root);
            std::printf("   Expected Value: '%s'\n", LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT);
            std::abort();
        }
        return true;
    }

};

#endif // LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT

// Misc test types

#define CONCAT2(LHS, RHS) LHS##RHS
#define CONCAT(LHS, RHS) CONCAT2(LHS, RHS)
#define MKSTR(Str) {Str, CONCAT(L, Str), CONCAT(u, Str), CONCAT(U, Str)}

struct MultiStringType {
  const char* s;
  const wchar_t* w;
  const char16_t* u16;
  const char32_t* u32;

  operator const char* () const { return s; }
  operator const wchar_t* () const { return w; }
  operator const char16_t* () const { return u16; }
  operator const char32_t* () const { return u32; }
};

const MultiStringType PathList[] = {
        MKSTR(""),
        MKSTR(" "),
        MKSTR("//"),
        MKSTR("."),
        MKSTR(".."),
        MKSTR("foo"),
        MKSTR("/"),
        MKSTR("/foo"),
        MKSTR("foo/"),
        MKSTR("/foo/"),
        MKSTR("foo/bar"),
        MKSTR("/foo/bar"),
        MKSTR("//net"),
        MKSTR("//net/foo"),
        MKSTR("///foo///"),
        MKSTR("///foo///bar"),
        MKSTR("/."),
        MKSTR("./"),
        MKSTR("/.."),
        MKSTR("../"),
        MKSTR("foo/."),
        MKSTR("foo/.."),
        MKSTR("foo/./"),
        MKSTR("foo/./bar"),
        MKSTR("foo/../"),
        MKSTR("foo/../bar"),
        MKSTR("c:"),
        MKSTR("c:/"),
        MKSTR("c:foo"),
        MKSTR("c:/foo"),
        MKSTR("c:foo/"),
        MKSTR("c:/foo/"),
        MKSTR("c:/foo/bar"),
        MKSTR("prn:"),
        MKSTR("c:\\"),
        MKSTR("c:\\foo"),
        MKSTR("c:foo\\"),
        MKSTR("c:\\foo\\"),
        MKSTR("c:\\foo/"),
        MKSTR("c:/foo\\bar"),
        MKSTR("//"),
        MKSTR("/finally/we/need/one/really/really/really/really/really/really/really/long/string")
};
const unsigned PathListSize = sizeof(PathList) / sizeof(MultiStringType);

template <class Iter>
Iter IterEnd(Iter B) {
  using VT = typename std::iterator_traits<Iter>::value_type;
  for (; *B != VT{}; ++B)
    ;
  return B;
}

template <class CharT>
const CharT* StrEnd(CharT const* P) {
    return IterEnd(P);
}

template <class CharT>
std::size_t StrLen(CharT const* P) {
    return StrEnd(P) - P;
}

// Testing the allocation behavior of the code_cvt functions requires
// *knowing* that the allocation was not done by "path::__str_".
// This hack forces path to allocate enough memory.
inline void PathReserve(fs::path& p, std::size_t N) {
  auto const& native_ref = p.native();
  const_cast<std::string&>(native_ref).reserve(N);
}

template <class Iter1, class Iter2>
bool checkCollectionsEqual(
    Iter1 start1, Iter1 const end1
  , Iter2 start2, Iter2 const end2
  )
{
    while (start1 != end1 && start2 != end2) {
        if (*start1 != *start2) {
            return false;
        }
        ++start1; ++start2;
    }
    return (start1 == end1 && start2 == end2);
}

template <class Iter1, class Iter2>
bool checkCollectionsEqualBackwards(
    Iter1 const start1, Iter1 end1
  , Iter2 const start2, Iter2 end2
  )
{
    while (start1 != end1 && start2 != end2) {
        --end1; --end2;
        if (*end1 != *end2) {
            return false;
        }
    }
    return (start1 == end1 && start2 == end2);
}

// We often need to test that the error_code was cleared if no error occurs
// this function returns a error_code which is set to an error that will
// never be returned by the filesystem functions.
inline std::error_code GetTestEC() {
    return std::make_error_code(std::errc::address_family_not_supported);
}

// Provide our own Sleep routine since std::this_thread::sleep_for is not
// available in single-threaded mode.
void SleepFor(std::chrono::seconds dur) {
    using namespace std::chrono;
    const auto curr_time = steady_clock::now();
    auto wake_time = curr_time + dur;
    while (steady_clock::now() < wake_time)
        ;
}

#endif /* FILESYSTEM_TEST_HELPER_HPP */
<commit_msg>Fix SleepFor(...) helper when a monotonic clock is not available.<commit_after>#ifndef FILESYSTEM_TEST_HELPER_HPP
#define FILESYSTEM_TEST_HELPER_HPP

#include <experimental/filesystem>
#include <cassert>
#include <cstdio> // for printf
#include <string>
#include <fstream>
#include <random>
#include <chrono>

namespace fs = std::experimental::filesystem;

// static test helpers

#ifndef LIBCXX_FILESYSTEM_STATIC_TEST_ROOT
#warning "STATIC TESTS DISABLED"
#else // LIBCXX_FILESYSTEM_STATIC_TEST_ROOT

namespace StaticEnv {

inline fs::path makePath(fs::path const& p) {
    static const fs::path env_path = LIBCXX_FILESYSTEM_STATIC_TEST_ROOT;
    return env_path / p;
}

static const fs::path Root = LIBCXX_FILESYSTEM_STATIC_TEST_ROOT;

static const fs::path TestFileList[] = {
        makePath("empty_file"),
        makePath("non_empty_file"),
        makePath("dir1/file1"),
        makePath("dir1/file2")
};
const std::size_t TestFileListSize = sizeof(TestFileList) / sizeof(fs::path);

static const fs::path TestDirList[] = {
        makePath("dir1"),
        makePath("dir1/dir2"),
        makePath("dir1/dir2/dir3")
};
const std::size_t TestDirListSize = sizeof(TestDirList) / sizeof(fs::path);

static const fs::path File          = TestFileList[0];
static const fs::path Dir           = TestDirList[0];
static const fs::path Dir2          = TestDirList[1];
static const fs::path Dir3          = TestDirList[2];
static const fs::path SymlinkToFile = makePath("symlink_to_empty_file");
static const fs::path SymlinkToDir  = makePath("symlink_to_dir");
static const fs::path BadSymlink    = makePath("bad_symlink");
static const fs::path DNE           = makePath("DNE");
static const fs::path EmptyFile     = TestFileList[0];
static const fs::path NonEmptyFile  = TestFileList[1];
static const fs::path CharFile      = "/dev/null"; // Hopefully this exists

static const fs::path DirIterationList[] = {
    makePath("dir1/dir2"),
    makePath("dir1/file1"),
    makePath("dir1/file2")
};
const std::size_t DirIterationListSize = sizeof(DirIterationList)
                                        / sizeof(fs::path);

static const fs::path DirIterationListDepth1[] = {
    makePath("dir1/dir2/afile3"),
    makePath("dir1/dir2/dir3"),
    makePath("dir1/dir2/symlink_to_dir3"),
    makePath("dir1/dir2/file4"),
};

static const fs::path RecDirIterationList[] = {
    makePath("dir1/dir2"),
    makePath("dir1/file1"),
    makePath("dir1/file2"),
    makePath("dir1/dir2/afile3"),
    makePath("dir1/dir2/dir3"),
    makePath("dir1/dir2/symlink_to_dir3"),
    makePath("dir1/dir2/file4"),
    makePath("dir1/dir2/dir3/file5")
};

static const fs::path RecDirFollowSymlinksIterationList[] = {
    makePath("dir1/dir2"),
    makePath("dir1/file1"),
    makePath("dir1/file2"),
    makePath("dir1/dir2/afile3"),
    makePath("dir1/dir2/dir3"),
    makePath("dir1/dir2/file4"),
    makePath("dir1/dir2/dir3/file5"),
    makePath("dir1/dir2/symlink_to_dir3"),
    makePath("dir1/dir2/symlink_to_dir3/file5"),
};

} // namespace StaticEnv

#endif // LIBCXX_FILESYSTEM_STATIC_TEST_ROOT

#ifndef LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT
#warning LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT must be defined
#else // LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT

#ifndef LIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER
#error LIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER must be defined
#endif

struct scoped_test_env
{
    scoped_test_env() : test_root(random_env_path())
        { fs_helper_run(fs_make_cmd("init_test_directory", test_root)); }

    ~scoped_test_env()
        { fs_helper_run(fs_make_cmd("destroy_test_directory", test_root)); }

    scoped_test_env(scoped_test_env const &) = delete;
    scoped_test_env & operator=(scoped_test_env const &) = delete;

    fs::path make_env_path(std::string p) { return sanitize_path(p); }

    std::string sanitize_path(std::string raw) {
        assert(raw.find("..") == std::string::npos);
        std::string const& root = test_root.native();
        if (root.compare(0, root.size(), raw, 0, root.size()) != 0) {
            assert(raw.front() != '\\');
            fs::path tmp(test_root);
            tmp /= raw;
            return std::move(const_cast<std::string&>(tmp.native()));
        }
        return raw;
    }

    std::string create_file(std::string filename, std::size_t size = 0) {
        filename = sanitize_path(std::move(filename));
        std::string out_str(size, 'a');
        {
            std::ofstream out(filename.c_str());
            out << out_str;
        }
        return filename;
    }

    std::string create_dir(std::string filename) {
        filename = sanitize_path(std::move(filename));
        fs_helper_run(fs_make_cmd("create_dir", filename));
        return filename;
    }

    std::string create_symlink(std::string source, std::string to) {
        source = sanitize_path(std::move(source));
        to = sanitize_path(std::move(to));
        fs_helper_run(fs_make_cmd("create_symlink", source, to));
        return to;
    }

    std::string create_hardlink(std::string source, std::string to) {
        source = sanitize_path(std::move(source));
        to = sanitize_path(std::move(to));
        fs_helper_run(fs_make_cmd("create_hardlink", source, to));
        return to;
    }

    std::string create_fifo(std::string file) {
        file = sanitize_path(std::move(file));
        fs_helper_run(fs_make_cmd("create_fifo", file));
        return file;
    }

  // OS X and FreeBSD doesn't support socket files so we shouldn't even
  // allow tests to call this unguarded.
#if !defined(__FreeBSD__) && !defined(__APPLE__)
    std::string create_socket(std::string file) {
        file = sanitize_path(std::move(file));
        fs_helper_run(fs_make_cmd("create_socket", file));
        return file;
    }
#endif

    fs::path const test_root;

private:
    static char to_hex(int ch) {
        return ch < 10 ? static_cast<char>('0' + ch)
                       : static_cast<char>('a' + (ch - 10));
    }

    static char random_hex_char() {
        static std::mt19937 rd { std::random_device{}() };
        static std::uniform_int_distribution<int> mrand{0, 15};
        return to_hex( mrand(rd) );
    }

    static std::string unique_path_suffix() {
        std::string model = "test.%%%%%%";
        for (auto & ch :  model) {
            if (ch == '%') ch = random_hex_char();
        }
        return model;
    }

    // This could potentially introduce a filesystem race with other tests
    // running at the same time, but oh well, it's just test code.
    static inline fs::path random_env_path() {
        static const char* env_path = LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT;
        fs::path p = fs::path(env_path) / unique_path_suffix();
        assert(p.parent_path() == env_path);
        return p;
    }

    static inline std::string make_arg(std::string const& arg) {
        return "'" + arg + "'";
    }

    static inline std::string make_arg(std::size_t arg) {
        return std::to_string(arg);
    }

    template <class T>
    static inline std::string
    fs_make_cmd(std::string const& cmd_name, T const& arg) {
        return cmd_name + "(" + make_arg(arg) + ")";
    }

    template <class T, class U>
    static inline std::string
    fs_make_cmd(std::string const& cmd_name, T const& arg1, U const& arg2) {
        return cmd_name + "(" + make_arg(arg1) + ", " + make_arg(arg2) + ")";
    }

    static inline void fs_helper_run(std::string const& raw_cmd) {
        // check that the fs test root in the enviroment matches what we were
        // compiled with.
        static bool checked = checkDynamicTestRoot();
        std::string cmd = LIBCXX_FILESYSTEM_DYNAMIC_TEST_HELPER;
        cmd += " \"" + raw_cmd + "\"";
        int ret = std::system(cmd.c_str());
        assert(ret == 0);
    }

    static bool checkDynamicTestRoot() {
        char* fs_root = std::getenv("LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT");
        if (!fs_root) {
            std::printf("ERROR: LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT must be a defined "
                         "environment variable when running the test.\n");
            std::abort();
        }
        if (std::string(fs_root) != LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT) {
            std::printf("ERROR: LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT enviroment variable"
                        " must have the same value as when the test was compiled.\n");
            std::printf("   Current Value:  '%s'\n", fs_root);
            std::printf("   Expected Value: '%s'\n", LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT);
            std::abort();
        }
        return true;
    }

};

#endif // LIBCXX_FILESYSTEM_DYNAMIC_TEST_ROOT

// Misc test types

#define CONCAT2(LHS, RHS) LHS##RHS
#define CONCAT(LHS, RHS) CONCAT2(LHS, RHS)
#define MKSTR(Str) {Str, CONCAT(L, Str), CONCAT(u, Str), CONCAT(U, Str)}

struct MultiStringType {
  const char* s;
  const wchar_t* w;
  const char16_t* u16;
  const char32_t* u32;

  operator const char* () const { return s; }
  operator const wchar_t* () const { return w; }
  operator const char16_t* () const { return u16; }
  operator const char32_t* () const { return u32; }
};

const MultiStringType PathList[] = {
        MKSTR(""),
        MKSTR(" "),
        MKSTR("//"),
        MKSTR("."),
        MKSTR(".."),
        MKSTR("foo"),
        MKSTR("/"),
        MKSTR("/foo"),
        MKSTR("foo/"),
        MKSTR("/foo/"),
        MKSTR("foo/bar"),
        MKSTR("/foo/bar"),
        MKSTR("//net"),
        MKSTR("//net/foo"),
        MKSTR("///foo///"),
        MKSTR("///foo///bar"),
        MKSTR("/."),
        MKSTR("./"),
        MKSTR("/.."),
        MKSTR("../"),
        MKSTR("foo/."),
        MKSTR("foo/.."),
        MKSTR("foo/./"),
        MKSTR("foo/./bar"),
        MKSTR("foo/../"),
        MKSTR("foo/../bar"),
        MKSTR("c:"),
        MKSTR("c:/"),
        MKSTR("c:foo"),
        MKSTR("c:/foo"),
        MKSTR("c:foo/"),
        MKSTR("c:/foo/"),
        MKSTR("c:/foo/bar"),
        MKSTR("prn:"),
        MKSTR("c:\\"),
        MKSTR("c:\\foo"),
        MKSTR("c:foo\\"),
        MKSTR("c:\\foo\\"),
        MKSTR("c:\\foo/"),
        MKSTR("c:/foo\\bar"),
        MKSTR("//"),
        MKSTR("/finally/we/need/one/really/really/really/really/really/really/really/long/string")
};
const unsigned PathListSize = sizeof(PathList) / sizeof(MultiStringType);

template <class Iter>
Iter IterEnd(Iter B) {
  using VT = typename std::iterator_traits<Iter>::value_type;
  for (; *B != VT{}; ++B)
    ;
  return B;
}

template <class CharT>
const CharT* StrEnd(CharT const* P) {
    return IterEnd(P);
}

template <class CharT>
std::size_t StrLen(CharT const* P) {
    return StrEnd(P) - P;
}

// Testing the allocation behavior of the code_cvt functions requires
// *knowing* that the allocation was not done by "path::__str_".
// This hack forces path to allocate enough memory.
inline void PathReserve(fs::path& p, std::size_t N) {
  auto const& native_ref = p.native();
  const_cast<std::string&>(native_ref).reserve(N);
}

template <class Iter1, class Iter2>
bool checkCollectionsEqual(
    Iter1 start1, Iter1 const end1
  , Iter2 start2, Iter2 const end2
  )
{
    while (start1 != end1 && start2 != end2) {
        if (*start1 != *start2) {
            return false;
        }
        ++start1; ++start2;
    }
    return (start1 == end1 && start2 == end2);
}

template <class Iter1, class Iter2>
bool checkCollectionsEqualBackwards(
    Iter1 const start1, Iter1 end1
  , Iter2 const start2, Iter2 end2
  )
{
    while (start1 != end1 && start2 != end2) {
        --end1; --end2;
        if (*end1 != *end2) {
            return false;
        }
    }
    return (start1 == end1 && start2 == end2);
}

// We often need to test that the error_code was cleared if no error occurs
// this function returns a error_code which is set to an error that will
// never be returned by the filesystem functions.
inline std::error_code GetTestEC() {
    return std::make_error_code(std::errc::address_family_not_supported);
}

// Provide our own Sleep routine since std::this_thread::sleep_for is not
// available in single-threaded mode.
void SleepFor(std::chrono::seconds dur) {
    using namespace std::chrono;
#if defined(_LIBCPP_HAS_NO_MONOTONIC_CLOCK)
    using Clock = system_clock;
#else
    using Clock = steady_clock;
#endif
    const auto wake_time = Clock::now() + dur;
    while (Clock::now() < wake_time)
        ;
}

#endif /* FILESYSTEM_TEST_HELPER_HPP */
<|endoftext|>


<commit_before>// Copyright 2010-2014 RethinkDB, all rights reserved.
#include "rdb_protocol/wire_func.hpp"

#include "containers/archive/boost_types.hpp"
#include "containers/archive/stl_types.hpp"
#include "containers/archive/archive.hpp"
#include "rdb_protocol/env.hpp"
#include "rdb_protocol/func.hpp"
#include "rdb_protocol/protocol.hpp"
#include "rdb_protocol/term_walker.hpp"
#include "stl_utils.hpp"

namespace ql {

wire_func_t::wire_func_t() { }

wire_func_t::wire_func_t(const counted_t<func_t> &f) : func(f) {
    r_sanity_check(func.has());
}

wire_func_t::wire_func_t(protob_t<const Term> body, std::vector<sym_t> arg_names,
                         protob_t<const Backtrace> backtrace) {
    compile_env_t env(var_visibility_t().with_func_arg_name_list(arg_names));
    func = make_counted<reql_func_t>(backtrace, var_scope_t(), arg_names, compile_term(&env, body));
}

wire_func_t::wire_func_t(const wire_func_t &copyee)
    : func(copyee.func) { }

wire_func_t &wire_func_t::operator=(const wire_func_t &assignee) {
    func = assignee.func;
    return *this;
}

wire_func_t::~wire_func_t() { }

counted_t<func_t> wire_func_t::compile_wire_func() const {
    r_sanity_check(func.has() || func_can_be_null());
    return func;
}

protob_t<const Backtrace> wire_func_t::get_bt() const {
    r_sanity_check(func.has());
    return func->backtrace();
}

enum class wire_func_type_t { REQL, JS };

ARCHIVE_PRIM_MAKE_RANGED_SERIALIZABLE(wire_func_type_t, int8_t,
                                      wire_func_type_t::REQL, wire_func_type_t::JS);

template <cluster_version_t W>
class wire_func_serialization_visitor_t : public func_visitor_t {
public:
    explicit wire_func_serialization_visitor_t(write_message_t *_wm) : wm(_wm) { }

    void on_reql_func(const reql_func_t *reql_func) {
        serialize<W>(wm, wire_func_type_t::REQL);
        const var_scope_t &scope = reql_func->captured_scope;
        serialize<W>(wm, scope);
        const std::vector<sym_t> &arg_names = reql_func->arg_names;
        serialize<W>(wm, arg_names);
        const protob_t<const Term> &body = reql_func->body->get_src();
        serialize_protobuf(wm, *body);
        const protob_t<const Backtrace> &backtrace = reql_func->backtrace();
        serialize_protobuf(wm, *backtrace);
    }

    void on_js_func(const js_func_t *js_func) {
        serialize<W>(wm, wire_func_type_t::JS);
        const std::string &js_source = js_func->js_source;
        serialize<W>(wm, js_source);
        const uint64_t &js_timeout_ms = js_func->js_timeout_ms;
        serialize<W>(wm, js_timeout_ms);
        const protob_t<const Backtrace> &backtrace = js_func->backtrace();
        serialize_protobuf(wm, *backtrace);
    }

private:
    write_message_t *wm;
};

template <cluster_version_t W>
void wire_func_t::rdb_serialize(write_message_t *wm) const {
    if (func_can_be_null()) {
        serialize<W>(wm, func.has());
        if (!func.has()) return;
    }
    r_sanity_check(func.has());
    wire_func_serialization_visitor_t<W> v(wm);
    func->visit(&v);
}

template <cluster_version_t W>
archive_result_t wire_func_t::rdb_deserialize(read_stream_t *s) {
    archive_result_t res;

    if (func_can_be_null()) {
        bool has;
        res = deserialize<W>(s, &has);
        if (bad(res)) return res;
        if (!has) return archive_result_t::SUCCESS;
    }

    wire_func_type_t type;
    res = deserialize<W>(s, &type);
    if (bad(res)) { return res; }
    switch (type) {
    case wire_func_type_t::REQL: {
        var_scope_t scope;
        res = deserialize<W>(s, &scope);
        if (bad(res)) { return res; }

        std::vector<sym_t> arg_names;
        res = deserialize<W>(s, &arg_names);
        if (bad(res)) { return res; }

        protob_t<Term> body = make_counted_term();
        res = deserialize_protobuf(s, &*body);
        if (bad(res)) { return res; }

        protob_t<Backtrace> backtrace = make_counted_backtrace();
        res = deserialize_protobuf(s, &*backtrace);
        if (bad(res)) { return res; }

        compile_env_t env(
            scope.compute_visibility().with_func_arg_name_list(arg_names));
        func = make_counted<reql_func_t>(
            backtrace, scope, arg_names, compile_term(&env, body));
        return res;
    } break;
    case wire_func_type_t::JS: {
        std::string js_source;
        res = deserialize<W>(s, &js_source);
        if (bad(res)) { return res; }

        uint64_t js_timeout_ms;
        res = deserialize<W>(s, &js_timeout_ms);
        if (bad(res)) { return res; }

        protob_t<Backtrace> backtrace = make_counted_backtrace();
        res = deserialize_protobuf(s, &*backtrace);
        if (bad(res)) { return res; }

        func = make_counted<js_func_t>(js_source, js_timeout_ms, backtrace);
        return res;
    } break;
    default:
        unreachable();
    }
}

INSTANTIATE_SELF_SINCE_v1_13(wire_func_t);

group_wire_func_t::group_wire_func_t(std::vector<counted_t<func_t> > &&_funcs,
                                     bool _append_index, bool _multi)
    : append_index(_append_index), multi(_multi) {
    funcs.reserve(_funcs.size());
    for (size_t i = 0; i < _funcs.size(); ++i) {
        funcs.push_back(wire_func_t(std::move(_funcs[i])));
    }
}

std::vector<counted_t<func_t> > group_wire_func_t::compile_funcs() const {
    std::vector<counted_t<func_t> > ret;
    ret.reserve(funcs.size());
    for (size_t i = 0; i < funcs.size(); ++i) {
        ret.push_back(funcs[i].compile_wire_func());
    }
    return std::move(ret);
}

bool group_wire_func_t::should_append_index() const {
    return append_index;
}

bool group_wire_func_t::is_multi() const {
    return multi;
}

protob_t<const Backtrace> group_wire_func_t::get_bt() const {
    return bt.get_bt();
}

RDB_IMPL_ME_SERIALIZABLE_4(group_wire_func_t, funcs, append_index, multi, bt);

RDB_IMPL_ME_SERIALIZABLE_0(count_wire_func_t);

map_wire_func_t map_wire_func_t::make_safely(
    pb::dummy_var_t dummy_var,
    const std::function<protob_t<Term>(sym_t argname)> &body_generator,
    protob_t<const Backtrace> backtrace) {
    const sym_t varname = dummy_var_to_sym(dummy_var);
    protob_t<Term> body = body_generator(varname);
    propagate_backtrace(body.get(), backtrace.get());
    return map_wire_func_t(body, make_vector(varname), backtrace);
}

RDB_IMPL_SERIALIZABLE_2(filter_wire_func_t, filter_func, default_filter_val);

template <cluster_version_t W>
void bt_wire_func_t::rdb_serialize(write_message_t *wm) const {
    serialize_protobuf(wm, *bt);
}

template <cluster_version_t W>
archive_result_t bt_wire_func_t::rdb_deserialize(read_stream_t *s) {
    protob_t<Backtrace> backtrace = make_counted_backtrace();
    archive_result_t res = deserialize_protobuf(s, const_cast<Backtrace *>(&*bt));
    if (bad(res)) { return res; }
    bt = backtrace;
    return archive_result_t::SUCCESS;
}

INSTANTIATE_SELF_SINCE_v1_13(bt_wire_func_t);

}  // namespace ql
<commit_msg>Made bt_wire_func_t deserialization not be broken.<commit_after>// Copyright 2010-2014 RethinkDB, all rights reserved.
#include "rdb_protocol/wire_func.hpp"

#include "containers/archive/boost_types.hpp"
#include "containers/archive/stl_types.hpp"
#include "containers/archive/archive.hpp"
#include "rdb_protocol/env.hpp"
#include "rdb_protocol/func.hpp"
#include "rdb_protocol/protocol.hpp"
#include "rdb_protocol/term_walker.hpp"
#include "stl_utils.hpp"

namespace ql {

wire_func_t::wire_func_t() { }

wire_func_t::wire_func_t(const counted_t<func_t> &f) : func(f) {
    r_sanity_check(func.has());
}

wire_func_t::wire_func_t(protob_t<const Term> body, std::vector<sym_t> arg_names,
                         protob_t<const Backtrace> backtrace) {
    compile_env_t env(var_visibility_t().with_func_arg_name_list(arg_names));
    func = make_counted<reql_func_t>(backtrace, var_scope_t(), arg_names, compile_term(&env, body));
}

wire_func_t::wire_func_t(const wire_func_t &copyee)
    : func(copyee.func) { }

wire_func_t &wire_func_t::operator=(const wire_func_t &assignee) {
    func = assignee.func;
    return *this;
}

wire_func_t::~wire_func_t() { }

counted_t<func_t> wire_func_t::compile_wire_func() const {
    r_sanity_check(func.has() || func_can_be_null());
    return func;
}

protob_t<const Backtrace> wire_func_t::get_bt() const {
    r_sanity_check(func.has());
    return func->backtrace();
}

enum class wire_func_type_t { REQL, JS };

ARCHIVE_PRIM_MAKE_RANGED_SERIALIZABLE(wire_func_type_t, int8_t,
                                      wire_func_type_t::REQL, wire_func_type_t::JS);

template <cluster_version_t W>
class wire_func_serialization_visitor_t : public func_visitor_t {
public:
    explicit wire_func_serialization_visitor_t(write_message_t *_wm) : wm(_wm) { }

    void on_reql_func(const reql_func_t *reql_func) {
        serialize<W>(wm, wire_func_type_t::REQL);
        const var_scope_t &scope = reql_func->captured_scope;
        serialize<W>(wm, scope);
        const std::vector<sym_t> &arg_names = reql_func->arg_names;
        serialize<W>(wm, arg_names);
        const protob_t<const Term> &body = reql_func->body->get_src();
        serialize_protobuf(wm, *body);
        const protob_t<const Backtrace> &backtrace = reql_func->backtrace();
        serialize_protobuf(wm, *backtrace);
    }

    void on_js_func(const js_func_t *js_func) {
        serialize<W>(wm, wire_func_type_t::JS);
        const std::string &js_source = js_func->js_source;
        serialize<W>(wm, js_source);
        const uint64_t &js_timeout_ms = js_func->js_timeout_ms;
        serialize<W>(wm, js_timeout_ms);
        const protob_t<const Backtrace> &backtrace = js_func->backtrace();
        serialize_protobuf(wm, *backtrace);
    }

private:
    write_message_t *wm;
};

template <cluster_version_t W>
void wire_func_t::rdb_serialize(write_message_t *wm) const {
    if (func_can_be_null()) {
        serialize<W>(wm, func.has());
        if (!func.has()) return;
    }
    r_sanity_check(func.has());
    wire_func_serialization_visitor_t<W> v(wm);
    func->visit(&v);
}

template <cluster_version_t W>
archive_result_t wire_func_t::rdb_deserialize(read_stream_t *s) {
    archive_result_t res;

    if (func_can_be_null()) {
        bool has;
        res = deserialize<W>(s, &has);
        if (bad(res)) return res;
        if (!has) return archive_result_t::SUCCESS;
    }

    wire_func_type_t type;
    res = deserialize<W>(s, &type);
    if (bad(res)) { return res; }
    switch (type) {
    case wire_func_type_t::REQL: {
        var_scope_t scope;
        res = deserialize<W>(s, &scope);
        if (bad(res)) { return res; }

        std::vector<sym_t> arg_names;
        res = deserialize<W>(s, &arg_names);
        if (bad(res)) { return res; }

        protob_t<Term> body = make_counted_term();
        res = deserialize_protobuf(s, &*body);
        if (bad(res)) { return res; }

        protob_t<Backtrace> backtrace = make_counted_backtrace();
        res = deserialize_protobuf(s, &*backtrace);
        if (bad(res)) { return res; }

        compile_env_t env(
            scope.compute_visibility().with_func_arg_name_list(arg_names));
        func = make_counted<reql_func_t>(
            backtrace, scope, arg_names, compile_term(&env, body));
        return res;
    } break;
    case wire_func_type_t::JS: {
        std::string js_source;
        res = deserialize<W>(s, &js_source);
        if (bad(res)) { return res; }

        uint64_t js_timeout_ms;
        res = deserialize<W>(s, &js_timeout_ms);
        if (bad(res)) { return res; }

        protob_t<Backtrace> backtrace = make_counted_backtrace();
        res = deserialize_protobuf(s, &*backtrace);
        if (bad(res)) { return res; }

        func = make_counted<js_func_t>(js_source, js_timeout_ms, backtrace);
        return res;
    } break;
    default:
        unreachable();
    }
}

INSTANTIATE_SELF_SINCE_v1_13(wire_func_t);

group_wire_func_t::group_wire_func_t(std::vector<counted_t<func_t> > &&_funcs,
                                     bool _append_index, bool _multi)
    : append_index(_append_index), multi(_multi) {
    funcs.reserve(_funcs.size());
    for (size_t i = 0; i < _funcs.size(); ++i) {
        funcs.push_back(wire_func_t(std::move(_funcs[i])));
    }
}

std::vector<counted_t<func_t> > group_wire_func_t::compile_funcs() const {
    std::vector<counted_t<func_t> > ret;
    ret.reserve(funcs.size());
    for (size_t i = 0; i < funcs.size(); ++i) {
        ret.push_back(funcs[i].compile_wire_func());
    }
    return std::move(ret);
}

bool group_wire_func_t::should_append_index() const {
    return append_index;
}

bool group_wire_func_t::is_multi() const {
    return multi;
}

protob_t<const Backtrace> group_wire_func_t::get_bt() const {
    return bt.get_bt();
}

RDB_IMPL_ME_SERIALIZABLE_4(group_wire_func_t, funcs, append_index, multi, bt);

RDB_IMPL_ME_SERIALIZABLE_0(count_wire_func_t);

map_wire_func_t map_wire_func_t::make_safely(
    pb::dummy_var_t dummy_var,
    const std::function<protob_t<Term>(sym_t argname)> &body_generator,
    protob_t<const Backtrace> backtrace) {
    const sym_t varname = dummy_var_to_sym(dummy_var);
    protob_t<Term> body = body_generator(varname);
    propagate_backtrace(body.get(), backtrace.get());
    return map_wire_func_t(body, make_vector(varname), backtrace);
}

RDB_IMPL_SERIALIZABLE_2(filter_wire_func_t, filter_func, default_filter_val);

template <cluster_version_t W>
void bt_wire_func_t::rdb_serialize(write_message_t *wm) const {
    serialize_protobuf(wm, *bt);
}

template <cluster_version_t W>
archive_result_t bt_wire_func_t::rdb_deserialize(read_stream_t *s) {
    protob_t<Backtrace> backtrace = make_counted_backtrace();
    archive_result_t res = deserialize_protobuf(s, backtrace.get());
    if (bad(res)) { return res; }
    bt = std::move(backtrace);
    return archive_result_t::SUCCESS;
}

INSTANTIATE_SELF_SINCE_v1_13(bt_wire_func_t);

}  // namespace ql
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2015] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/
#ifndef REALM_COLUMN_DATETIME_HPP
#define REALM_COLUMN_DATETIME_HPP

#include <realm/column.hpp>

namespace realm {

struct NewDate {
    NewDate(int64_t seconds, uint32_t nanoseconds) : m_seconds(seconds), m_nanoseconds(nanoseconds), m_is_null(false)
    {
        REALM_ASSERT_3(nanoseconds, <, 1000000000);
    }
    NewDate(const null&) : m_is_null(true) { }
    NewDate() : NewDate(null()) { }

    bool is_null() const { return m_is_null; }
    bool operator == (const NewDate& rhs) const { return m_seconds == rhs.m_seconds && m_nanoseconds == rhs.m_nanoseconds; }
    bool operator != (const NewDate& rhs) const { return m_seconds != rhs.m_seconds || m_nanoseconds != rhs.m_nanoseconds; }
    bool operator > (const NewDate& rhs) const { return (m_seconds > rhs.m_seconds) || (m_seconds == rhs.m_seconds && m_nanoseconds > rhs.m_nanoseconds); }
    bool operator < (const NewDate& rhs) const { return (m_seconds < rhs.m_seconds) || (m_seconds == rhs.m_seconds && m_nanoseconds < rhs.m_nanoseconds); }
    bool operator <= (const NewDate& rhs) const { return *this < rhs || *this == rhs; }
    bool operator >= (const NewDate& rhs) const { return *this > rhs || *this == rhs; }
    NewDate& operator = (const NewDate& rhs) = default;

    template<class Ch, class Tr>
    friend std::basic_ostream<Ch, Tr>& operator<<(std::basic_ostream<Ch, Tr>& out, const DateTime&);

    int64_t m_seconds;
    uint32_t m_nanoseconds;
    bool m_is_null;
};

template<class C, class T>
inline std::basic_ostream<C, T>& operator<<(std::basic_ostream<C, T>& out, const NewDate& d)
{
    out << "NewDate(" << d.m_seconds << ", " << d.m_nanoseconds << ")";
    return out;
}

class DateTimeColumn : public ColumnBase, public ColumnTemplate<NewDate> {
public:
    DateTimeColumn();
    /// Get the number of entries in this column. This operation is relatively
    /// slow.
    size_t size() const noexcept override;
    /// Whether or not this column is nullable.
    bool is_nullable() const noexcept override;
    /// Whether or not the value at \a row_ndx is NULL. If the column is not
    /// nullable, always returns false.
    bool is_null(size_t row_ndx) const noexcept override;
    /// Sets the value at \a row_ndx to be NULL.
    /// \throw LogicError Thrown if this column is not nullable.
    void set_null(size_t row_ndx) override;
    void insert_rows(size_t row_ndx, size_t num_rows_to_insert, size_t prior_num_rows, bool nullable) override;
    void erase_rows(size_t row_ndx, size_t num_rows_to_erase, size_t prior_num_rows,
                    bool broken_reciprocal_backlinks) override;
    void move_last_row_over(size_t row_ndx, size_t prior_num_rows,
                            bool broken_reciprocal_backlinks) override;
    void clear(size_t num_rows, bool broken_reciprocal_backlinks) override;
    void swap_rows(size_t row_ndx_1, size_t row_ndx_2) override;
    void destroy() noexcept override;
    StringData get_index_data(size_t, StringIndex::StringConversionBuffer& buffer) const noexcept override;
    Allocator& get_alloc() const noexcept override;
    /// Returns the 'ref' of the root array.
    ref_type get_ref() const noexcept override;
    MemRef get_mem() const noexcept override;
    void replace_root_array(std::unique_ptr<Array> leaf) override;
    MemRef clone_deep(Allocator& alloc) const override;
    void detach() override;
    bool is_attached() const noexcept override;
    ref_type write(size_t slice_offset, size_t slice_size, size_t table_size, _impl::OutputStream&) const override;
    void set_parent(ArrayParent*, size_t ndx_in_parent) noexcept override;
    size_t get_ndx_in_parent() const noexcept override;
    void set_ndx_in_parent(size_t ndx_in_parent) noexcept override;
    void update_from_parent(size_t old_baseline) noexcept override;
    void refresh_accessor_tree(size_t new_col_ndx, const Spec&) override;
#ifdef REALM_DEBUG
    void verify() const override;
    void to_dot(std::ostream&, StringData title = StringData()) const override;
    void do_dump_node_structure(std::ostream&, int level) const override;
    void leaf_to_dot(MemRef, ArrayParent*, size_t ndx_in_parent, std::ostream&) const override;
#endif
    void add(const NewDate& ndt = NewDate{});
    NewDate get(size_t row_ndx) const noexcept;
    NewDate get_val(size_t row_ndx) const override;
    void set(size_t row_ndx, const NewDate& ndt);
private:
    IntNullColumn m_seconds;
    IntegerColumn m_nanoseconds;
};

// Implementation

inline DateTimeColumn::DateTimeColumn() :
    m_seconds(Allocator::get_default(), IntNullColumn::create(Allocator::get_default())),
    m_nanoseconds(Allocator::get_default(), IntegerColumn::create(Allocator::get_default()))
{
}

/// Get the number of entries in this column. This operation is relatively
/// slow.
inline size_t DateTimeColumn::size() const noexcept
{
    // FIXME: Consider debug asserts on the columns having the same size
    return m_seconds.size();
}

/// Whether or not this column is nullable.
inline bool DateTimeColumn::is_nullable() const noexcept
{
    return m_seconds.is_nullable();
}

/// Whether or not the value at \a row_ndx is NULL. If the column is not
/// nullable, always returns false.
inline bool DateTimeColumn::is_null(size_t row_ndx) const noexcept
{
    return m_seconds.is_null(row_ndx);
}

/// Sets the value at \a row_ndx to be NULL.
/// \throw LogicError Thrown if this column is not nullable.
inline void DateTimeColumn::set_null(size_t row_ndx)
{
    m_seconds.set_null(row_ndx);
}

inline void DateTimeColumn::insert_rows(size_t row_ndx, size_t num_rows_to_insert, size_t prior_num_rows,
                                        bool nullable)
{
    m_seconds.insert_rows(row_ndx, num_rows_to_insert, prior_num_rows, nullable);
    m_nanoseconds.insert_rows(row_ndx, num_rows_to_insert, prior_num_rows, false);
}

inline void DateTimeColumn::erase_rows(size_t row_ndx, size_t num_rows_to_erase, size_t prior_num_rows,
                                       bool broken_reciprocal_backlinks)
{
    m_seconds.erase_rows(row_ndx, num_rows_to_erase, prior_num_rows, broken_reciprocal_backlinks);
    m_nanoseconds.erase_rows(row_ndx, num_rows_to_erase, prior_num_rows, broken_reciprocal_backlinks);
}

inline void DateTimeColumn::move_last_row_over(size_t row_ndx, size_t prior_num_rows,
                                               bool broken_reciprocal_backlinks)
{
    m_seconds.move_last_row_over(row_ndx, prior_num_rows, broken_reciprocal_backlinks);
    m_nanoseconds.move_last_row_over(row_ndx, prior_num_rows, broken_reciprocal_backlinks);
}

inline void DateTimeColumn::clear(size_t num_rows, bool broken_reciprocal_backlinks)
{
    m_seconds.clear(num_rows, broken_reciprocal_backlinks);
    m_nanoseconds.clear(num_rows, broken_reciprocal_backlinks);
}

inline void DateTimeColumn::swap_rows(size_t row_ndx_1, size_t row_ndx_2)
{
    m_seconds.swap_rows(row_ndx_1, row_ndx_2);
    m_nanoseconds.swap_rows(row_ndx_1, row_ndx_2);
}

inline void DateTimeColumn::destroy() noexcept
{
    m_seconds.destroy();
    m_nanoseconds.destroy();
}

inline StringData DateTimeColumn::get_index_data(size_t, StringIndex::StringConversionBuffer& /*buffer*/) const noexcept
{
    // FIXME: Dummy implementation
    return null();
}

inline Allocator& DateTimeColumn::get_alloc() const noexcept
{
    // FIXME: Dummy implementation
    return Allocator::get_default();
}

inline ref_type DateTimeColumn::get_ref() const noexcept
{
    // FIXME: Dummy implementation
    return 0;
}

inline MemRef DateTimeColumn::get_mem() const noexcept
{
    // FIXME: Dummy implementation
    return MemRef();
}

inline void DateTimeColumn::replace_root_array(std::unique_ptr<Array> /*leaf*/)
{
    // FIXME: Dummy implementation
}

inline MemRef DateTimeColumn::clone_deep(Allocator& /*alloc*/) const
{
    // FIXME: Dummy implementation
    return MemRef();
}

inline void DateTimeColumn::detach()
{
    m_seconds.detach();
    m_nanoseconds.detach();
}

inline bool DateTimeColumn::is_attached() const noexcept
{
    // FIXME: Assert on both columns having same attached state?
    return m_seconds.is_attached();
}

inline ref_type DateTimeColumn::write(size_t /*slice_offset*/, size_t /*slice_size*/, size_t /*table_size*/,
                                      _impl::OutputStream&) const
{
    // FIXME: Dummy implementation
    return 0;
}

inline void DateTimeColumn::set_parent(ArrayParent*, size_t /*ndx_in_parent*/) noexcept
{
    // FIXME: Dummy implementation
}

inline size_t DateTimeColumn::get_ndx_in_parent() const noexcept
{
    // FIXME: Dummy implementation
    return 0;
}

inline void DateTimeColumn::set_ndx_in_parent(size_t /*ndx_in_parent*/) noexcept
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::update_from_parent(size_t /*old_baseline*/) noexcept
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::refresh_accessor_tree(size_t /*new_col_ndx*/, const Spec&)
{
    // FIXME: Dummy implementation
}

#ifdef REALM_DEBUG

inline void DateTimeColumn::verify() const
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::to_dot(std::ostream&, StringData /*title*/) const
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::do_dump_node_structure(std::ostream&, int /*level*/) const
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::leaf_to_dot(MemRef, ArrayParent*, size_t /*ndx_in_parent*/, std::ostream&) const
{
    // FIXME: Dummy implementation
}

#endif

inline void DateTimeColumn::add(const NewDate& ndt)
{
    bool is_null = ndt.is_null();
    util::Optional<int64_t> seconds = is_null ? util::none : util::make_optional(ndt.m_seconds);
    int32_t nanoseconds = is_null ? 0 : ndt.m_nanoseconds;
    m_seconds.add(seconds);
    m_nanoseconds.add(nanoseconds);
}

inline NewDate DateTimeColumn::get(size_t row_ndx) const noexcept
{
    util::Optional<int64_t> seconds = m_seconds.get(row_ndx);
    return seconds ? NewDate(*seconds, int32_t(m_nanoseconds.get(row_ndx))) : NewDate(null());
}

inline NewDate DateTimeColumn::get_val(size_t row_ndx) const
{
    return get(row_ndx);
}

inline void DateTimeColumn::set(size_t row_ndx, const NewDate& ndt)
{
    bool is_null = ndt.is_null();
    util::Optional<int64_t> seconds = is_null ? util::none : util::make_optional(ndt.m_seconds);
    int32_t nanoseconds = is_null ? 0 : ndt.m_nanoseconds;
    m_seconds.set(row_ndx, seconds);
    m_nanoseconds.set(row_ndx, nanoseconds);
}

} // namespace realm

#endif // REALM_COLUMN_DATETIME_HPP
<commit_msg><< operator bug<commit_after>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2015] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/
#ifndef REALM_COLUMN_DATETIME_HPP
#define REALM_COLUMN_DATETIME_HPP

#include <realm/column.hpp>

namespace realm {

struct NewDate {
    NewDate(int64_t seconds, uint32_t nanoseconds) : m_seconds(seconds), m_nanoseconds(nanoseconds), m_is_null(false)
    {
        REALM_ASSERT_3(nanoseconds, <, 1000000000);
    }
    NewDate(const null&) : m_is_null(true) { }
    NewDate() : NewDate(null()) { }

    bool is_null() const { return m_is_null; }
    bool operator == (const NewDate& rhs) const { return m_seconds == rhs.m_seconds && m_nanoseconds == rhs.m_nanoseconds; }
    bool operator != (const NewDate& rhs) const { return m_seconds != rhs.m_seconds || m_nanoseconds != rhs.m_nanoseconds; }
    bool operator > (const NewDate& rhs) const { return (m_seconds > rhs.m_seconds) || (m_seconds == rhs.m_seconds && m_nanoseconds > rhs.m_nanoseconds); }
    bool operator < (const NewDate& rhs) const { return (m_seconds < rhs.m_seconds) || (m_seconds == rhs.m_seconds && m_nanoseconds < rhs.m_nanoseconds); }
    bool operator <= (const NewDate& rhs) const { return *this < rhs || *this == rhs; }
    bool operator >= (const NewDate& rhs) const { return *this > rhs || *this == rhs; }
    NewDate& operator = (const NewDate& rhs) = default;

    template<class Ch, class Tr>
    friend std::basic_ostream<Ch, Tr>& operator<<(std::basic_ostream<Ch, Tr>& out, const NewDate&);

    int64_t m_seconds;
    uint32_t m_nanoseconds;
    bool m_is_null;
};

template<class C, class T>
inline std::basic_ostream<C, T>& operator<<(std::basic_ostream<C, T>& out, const NewDate& d)
{
    out << "NewDate(" << d.m_seconds << ", " << d.m_nanoseconds << ")";
    return out;
}

class DateTimeColumn : public ColumnBase, public ColumnTemplate<NewDate> {
public:
    DateTimeColumn();
    /// Get the number of entries in this column. This operation is relatively
    /// slow.
    size_t size() const noexcept override;
    /// Whether or not this column is nullable.
    bool is_nullable() const noexcept override;
    /// Whether or not the value at \a row_ndx is NULL. If the column is not
    /// nullable, always returns false.
    bool is_null(size_t row_ndx) const noexcept override;
    /// Sets the value at \a row_ndx to be NULL.
    /// \throw LogicError Thrown if this column is not nullable.
    void set_null(size_t row_ndx) override;
    void insert_rows(size_t row_ndx, size_t num_rows_to_insert, size_t prior_num_rows, bool nullable) override;
    void erase_rows(size_t row_ndx, size_t num_rows_to_erase, size_t prior_num_rows,
                    bool broken_reciprocal_backlinks) override;
    void move_last_row_over(size_t row_ndx, size_t prior_num_rows,
                            bool broken_reciprocal_backlinks) override;
    void clear(size_t num_rows, bool broken_reciprocal_backlinks) override;
    void swap_rows(size_t row_ndx_1, size_t row_ndx_2) override;
    void destroy() noexcept override;
    StringData get_index_data(size_t, StringIndex::StringConversionBuffer& buffer) const noexcept override;
    Allocator& get_alloc() const noexcept override;
    /// Returns the 'ref' of the root array.
    ref_type get_ref() const noexcept override;
    MemRef get_mem() const noexcept override;
    void replace_root_array(std::unique_ptr<Array> leaf) override;
    MemRef clone_deep(Allocator& alloc) const override;
    void detach() override;
    bool is_attached() const noexcept override;
    ref_type write(size_t slice_offset, size_t slice_size, size_t table_size, _impl::OutputStream&) const override;
    void set_parent(ArrayParent*, size_t ndx_in_parent) noexcept override;
    size_t get_ndx_in_parent() const noexcept override;
    void set_ndx_in_parent(size_t ndx_in_parent) noexcept override;
    void update_from_parent(size_t old_baseline) noexcept override;
    void refresh_accessor_tree(size_t new_col_ndx, const Spec&) override;
#ifdef REALM_DEBUG
    void verify() const override;
    void to_dot(std::ostream&, StringData title = StringData()) const override;
    void do_dump_node_structure(std::ostream&, int level) const override;
    void leaf_to_dot(MemRef, ArrayParent*, size_t ndx_in_parent, std::ostream&) const override;
#endif
    void add(const NewDate& ndt = NewDate{});
    NewDate get(size_t row_ndx) const noexcept;
    NewDate get_val(size_t row_ndx) const override;
    void set(size_t row_ndx, const NewDate& ndt);
private:
    IntNullColumn m_seconds;
    IntegerColumn m_nanoseconds;
};

// Implementation

inline DateTimeColumn::DateTimeColumn() :
    m_seconds(Allocator::get_default(), IntNullColumn::create(Allocator::get_default())),
    m_nanoseconds(Allocator::get_default(), IntegerColumn::create(Allocator::get_default()))
{
}

/// Get the number of entries in this column. This operation is relatively
/// slow.
inline size_t DateTimeColumn::size() const noexcept
{
    // FIXME: Consider debug asserts on the columns having the same size
    return m_seconds.size();
}

/// Whether or not this column is nullable.
inline bool DateTimeColumn::is_nullable() const noexcept
{
    return m_seconds.is_nullable();
}

/// Whether or not the value at \a row_ndx is NULL. If the column is not
/// nullable, always returns false.
inline bool DateTimeColumn::is_null(size_t row_ndx) const noexcept
{
    return m_seconds.is_null(row_ndx);
}

/// Sets the value at \a row_ndx to be NULL.
/// \throw LogicError Thrown if this column is not nullable.
inline void DateTimeColumn::set_null(size_t row_ndx)
{
    m_seconds.set_null(row_ndx);
}

inline void DateTimeColumn::insert_rows(size_t row_ndx, size_t num_rows_to_insert, size_t prior_num_rows,
                                        bool nullable)
{
    m_seconds.insert_rows(row_ndx, num_rows_to_insert, prior_num_rows, nullable);
    m_nanoseconds.insert_rows(row_ndx, num_rows_to_insert, prior_num_rows, false);
}

inline void DateTimeColumn::erase_rows(size_t row_ndx, size_t num_rows_to_erase, size_t prior_num_rows,
                                       bool broken_reciprocal_backlinks)
{
    m_seconds.erase_rows(row_ndx, num_rows_to_erase, prior_num_rows, broken_reciprocal_backlinks);
    m_nanoseconds.erase_rows(row_ndx, num_rows_to_erase, prior_num_rows, broken_reciprocal_backlinks);
}

inline void DateTimeColumn::move_last_row_over(size_t row_ndx, size_t prior_num_rows,
                                               bool broken_reciprocal_backlinks)
{
    m_seconds.move_last_row_over(row_ndx, prior_num_rows, broken_reciprocal_backlinks);
    m_nanoseconds.move_last_row_over(row_ndx, prior_num_rows, broken_reciprocal_backlinks);
}

inline void DateTimeColumn::clear(size_t num_rows, bool broken_reciprocal_backlinks)
{
    m_seconds.clear(num_rows, broken_reciprocal_backlinks);
    m_nanoseconds.clear(num_rows, broken_reciprocal_backlinks);
}

inline void DateTimeColumn::swap_rows(size_t row_ndx_1, size_t row_ndx_2)
{
    m_seconds.swap_rows(row_ndx_1, row_ndx_2);
    m_nanoseconds.swap_rows(row_ndx_1, row_ndx_2);
}

inline void DateTimeColumn::destroy() noexcept
{
    m_seconds.destroy();
    m_nanoseconds.destroy();
}

inline StringData DateTimeColumn::get_index_data(size_t, StringIndex::StringConversionBuffer& /*buffer*/) const noexcept
{
    // FIXME: Dummy implementation
    return null();
}

inline Allocator& DateTimeColumn::get_alloc() const noexcept
{
    // FIXME: Dummy implementation
    return Allocator::get_default();
}

inline ref_type DateTimeColumn::get_ref() const noexcept
{
    // FIXME: Dummy implementation
    return 0;
}

inline MemRef DateTimeColumn::get_mem() const noexcept
{
    // FIXME: Dummy implementation
    return MemRef();
}

inline void DateTimeColumn::replace_root_array(std::unique_ptr<Array> /*leaf*/)
{
    // FIXME: Dummy implementation
}

inline MemRef DateTimeColumn::clone_deep(Allocator& /*alloc*/) const
{
    // FIXME: Dummy implementation
    return MemRef();
}

inline void DateTimeColumn::detach()
{
    m_seconds.detach();
    m_nanoseconds.detach();
}

inline bool DateTimeColumn::is_attached() const noexcept
{
    // FIXME: Assert on both columns having same attached state?
    return m_seconds.is_attached();
}

inline ref_type DateTimeColumn::write(size_t /*slice_offset*/, size_t /*slice_size*/, size_t /*table_size*/,
                                      _impl::OutputStream&) const
{
    // FIXME: Dummy implementation
    return 0;
}

inline void DateTimeColumn::set_parent(ArrayParent*, size_t /*ndx_in_parent*/) noexcept
{
    // FIXME: Dummy implementation
}

inline size_t DateTimeColumn::get_ndx_in_parent() const noexcept
{
    // FIXME: Dummy implementation
    return 0;
}

inline void DateTimeColumn::set_ndx_in_parent(size_t /*ndx_in_parent*/) noexcept
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::update_from_parent(size_t /*old_baseline*/) noexcept
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::refresh_accessor_tree(size_t /*new_col_ndx*/, const Spec&)
{
    // FIXME: Dummy implementation
}

#ifdef REALM_DEBUG

inline void DateTimeColumn::verify() const
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::to_dot(std::ostream&, StringData /*title*/) const
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::do_dump_node_structure(std::ostream&, int /*level*/) const
{
    // FIXME: Dummy implementation
}

inline void DateTimeColumn::leaf_to_dot(MemRef, ArrayParent*, size_t /*ndx_in_parent*/, std::ostream&) const
{
    // FIXME: Dummy implementation
}

#endif

inline void DateTimeColumn::add(const NewDate& ndt)
{
    bool is_null = ndt.is_null();
    util::Optional<int64_t> seconds = is_null ? util::none : util::make_optional(ndt.m_seconds);
    int32_t nanoseconds = is_null ? 0 : ndt.m_nanoseconds;
    m_seconds.add(seconds);
    m_nanoseconds.add(nanoseconds);
}

inline NewDate DateTimeColumn::get(size_t row_ndx) const noexcept
{
    util::Optional<int64_t> seconds = m_seconds.get(row_ndx);
    return seconds ? NewDate(*seconds, int32_t(m_nanoseconds.get(row_ndx))) : NewDate(null());
}

inline NewDate DateTimeColumn::get_val(size_t row_ndx) const
{
    return get(row_ndx);
}

inline void DateTimeColumn::set(size_t row_ndx, const NewDate& ndt)
{
    bool is_null = ndt.is_null();
    util::Optional<int64_t> seconds = is_null ? util::none : util::make_optional(ndt.m_seconds);
    int32_t nanoseconds = is_null ? 0 : ndt.m_nanoseconds;
    m_seconds.set(row_ndx, seconds);
    m_nanoseconds.set(row_ndx, nanoseconds);
}

} // namespace realm

#endif // REALM_COLUMN_DATETIME_HPP
<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System.
 */

#include <gtest/gtest.h>

#include "publish/except.h"
#include "publish/settings.h"

using namespace std;  // NOLINT

namespace publish {

class T_Transaction : public ::testing::Test {
 protected:
  virtual void SetUp() {
  }

 protected:
};

TEST_F(T_Transaction, Template) {
  SettingsTransaction settings("test.cvmfs.io");
  EXPECT_FALSE(settings.HasTemplate());
  EXPECT_THROW(settings.SetTemplate("", "/foo"), EPublish);
  EXPECT_THROW(settings.SetTemplate("/foo", ""), EPublish);
  settings.SetTemplate("/foo", "/bar");
  EXPECT_TRUE(settings.HasTemplate());
  EXPECT_EQ("foo", settings.template_from());
  EXPECT_EQ("bar", settings.template_to());
}

}  // namespace publish
<commit_msg>[publish] unit test skeleton for transaction<commit_after>/**
 * This file is part of the CernVM File System.
 */

#include <gtest/gtest.h>

#include "c_repository.h"
#include "publish/except.h"
#include "publish/repository.h"
#include "publish/settings.h"

using namespace std;  // NOLINT

namespace publish {

class T_Transaction : public ::testing::Test {
 protected:
  virtual void SetUp() {
  }

 protected:
};

TEST_F(T_Transaction, TemplateSettings) {
  SettingsTransaction settings("test.cvmfs.io");
  EXPECT_FALSE(settings.HasTemplate());
  EXPECT_THROW(settings.SetTemplate("", "/foo"), EPublish);
  EXPECT_THROW(settings.SetTemplate("/foo", ""), EPublish);
  settings.SetTemplate("/foo", "/bar");
  EXPECT_TRUE(settings.HasTemplate());
  EXPECT_EQ("foo", settings.template_from());
  EXPECT_EQ("bar", settings.template_to());
}

TEST_F(T_Transaction, BasicTransaction) {
  Publisher *publisher = GetTestPublisher();
  EXPECT_FALSE(publisher->in_transaction());
  publisher->Transaction();
  EXPECT_TRUE(publisher->in_transaction());
  delete publisher;

  // TODO(jblomer): add more tests when publish and abort are implemented
}

}  // namespace publish
<|endoftext|>


<commit_before>//
// EnviroGUI.cpp
// GUI-specific functionality of the Enviro class
//
// Copyright (c) 2003-2007 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include "vtlib/vtlib.h"
#include "vtlib/core/Terrain.h"
#include "vtdata/vtLog.h"
#include "vtui/Helper.h"
#include "vtui/InstanceDlg.h"
#include "vtui/ProfileDlg.h"

#include "EnviroGUI.h"
#include "EnviroApp.h"
#include "EnviroFrame.h"
#include "canvas.h"
#include "DistanceDlg3d.h"
#include "LayerDlg.h"
#include "StyleDlg.h"

#if WIN32 || !wxUSE_JOYSTICK
  #include "vtui/Joystick.h"
#else
  #include "wx/joystick.h"
#endif

DECLARE_APP(EnviroApp);

//
// This is a 'singleton', the only instance of the global application object
//
EnviroGUI g_App;

// helper
EnviroFrame *GetFrame()
{
	return dynamic_cast<EnviroFrame *>(wxGetApp().GetTopWindow());
}

EnviroGUI::EnviroGUI()
{
	m_pJFlyer = NULL;
}

EnviroGUI::~EnviroGUI()
{
}

void EnviroGUI::ShowPopupMenu(const IPoint2 &pos)
{
	GetFrame()->ShowPopupMenu(pos);
}

void EnviroGUI::SetTerrainToGUI(vtTerrain *pTerrain)
{
	GetFrame()->SetTerrainToGUI(pTerrain);

	if (pTerrain && m_pJFlyer)
	{
		float speed = pTerrain->GetParams().GetValueFloat(STR_NAVSPEED);
		m_pJFlyer->SetSpeed(speed);
	}
}

void EnviroGUI::SetFlightSpeed(float speed)
{
	if (m_pJFlyer)
		m_pJFlyer->SetSpeed(speed);
	Enviro::SetFlightSpeed(speed);
}

const char *AppStateNames[] =
{
	"AS_Initializing",
	"AS_Neutral",
	"AS_Orbit",
	"AS_FlyingIn",
	"AS_SwitchToTerrain",
	"AS_Terrain",
	"AS_MovingOut",
	"AS_Error"
};

void EnviroGUI::SetState(AppState s)
{
	// if entering or leaving terrain or orbit state
	AppState previous = m_state;
	m_state = s;

	if (m_state != previous)
	{
		VTLOG("Changing app state from %s to %s\n", AppStateNames[previous],
			AppStateNames[m_state]);
	}

	if ((previous == AS_Terrain && m_state != AS_Terrain) ||
		(previous == AS_Orbit && m_state != AS_Orbit) ||
		(previous != AS_Terrain && m_state == AS_Terrain) ||
		(previous != AS_Orbit && m_state == AS_Orbit))
	{
		GetFrame()->RefreshToolbar();
	}
}

vtString EnviroGUI::GetStringFromUser(const vtString &title, const vtString &msg)
{
	wxString caption(title, wxConvUTF8);
	wxString message(msg, wxConvUTF8);
	wxString str = wxGetTextFromUser(message, caption, _T(""), GetFrame());
	return (vtString) (const char *) str.mb_str(wxConvUTF8);
}

void EnviroGUI::ShowProgress(bool bShow)
{
	if (bShow)
		OpenProgressDialog2(_("Creating Terrain"), false, GetFrame());
	else
		CloseProgressDialog2();
}

void EnviroGUI::SetProgressTerrain(vtTerrain *pTerr)
{
	pTerr->SetProgressCallback(progress_callback_minor);
}

void EnviroGUI::UpdateProgress(const char *msg, int amount1, int amount2)
{
	wxString str(msg, wxConvUTF8);

	// Try to translate it; a translation might be available.
	// If the string is not found in any of the loaded message catalogs,
	// the original string is returned.
	wxString str2 = wxGetTranslation(str);

	UpdateProgressDialog2(amount1, amount2, str2);
}

void EnviroGUI::RefreshLayerView()
{
	LayerDlg *dlg = GetFrame()->m_pLayerDlg;
	dlg->RefreshTreeContents();
}

void EnviroGUI::UpdateLayerView()
{
	LayerDlg *dlg = GetFrame()->m_pLayerDlg;
	dlg->UpdateTreeTerrain();
}

void EnviroGUI::ShowLayerView()
{
	LayerDlg *dlg = GetFrame()->m_pLayerDlg;
	dlg->Show(true);
}

void EnviroGUI::CameraChanged()
{
	GetFrame()->CameraChanged();
}

void EnviroGUI::EarthPosUpdated()
{
	GetFrame()->EarthPosUpdated(m_EarthPos);
}

void EnviroGUI::ShowDistance(const DPoint2 &p1, const DPoint2 &p2,
							 double fGround, double fVertical)
{
	GetFrame()->m_pDistanceDlg->SetPoints(p1, p2, false);
	GetFrame()->m_pDistanceDlg->SetGroundAndVertical(fGround, fVertical, true);

	if (GetFrame()->m_pProfileDlg)
		GetFrame()->m_pProfileDlg->SetPoints(p1, p2);
}

void EnviroGUI::ShowDistance(const DLine2 &path,
							 double fGround, double fVertical)
{
	GetFrame()->m_pDistanceDlg->SetPath(path, false);
	GetFrame()->m_pDistanceDlg->SetGroundAndVertical(fGround, fVertical, true);

	if (GetFrame()->m_pProfileDlg)
		GetFrame()->m_pProfileDlg->SetPath(path);
}

vtTagArray *EnviroGUI::GetInstanceFromGUI()
{
	return GetFrame()->m_pInstanceDlg->GetTagArray();
}

bool EnviroGUI::OnMouseEvent(vtMouseEvent &event)
{
	return GetFrame()->OnMouseEvent(event);
}

void EnviroGUI::SetupScene3()
{
	GetFrame()->Setup3DScene();

#if wxUSE_JOYSTICK || WIN32
	m_pJFlyer = new vtJoystickEngine;
	m_pJFlyer->SetName2("Joystick");
	vtGetScene()->AddEngine(m_pJFlyer);
	m_pJFlyer->SetTarget(m_pNormalCamera);
#endif
}

void EnviroGUI::SetTimeEngineToGUI(class vtTimeEngine *pEngine)
{
	GetFrame()->SetTimeEngine(pEngine);
}

//////////////////////////////////////////////////////////////////////

void EnviroGUI::SaveVegetation(bool bAskFilename)
{
	vtTerrain *pTerr = GetCurrentTerrain();
	vtPlantInstanceArray &pia = pTerr->GetPlantInstances();

	vtString fname = pia.GetFilename();

	if (bAskFilename)
	{
		// save current directory
		wxString path = wxGetCwd();

		wxString default_file(StartOfFilename(fname), wxConvUTF8);
		wxString default_dir(ExtractPath(fname), wxConvUTF8);

		EnableContinuousRendering(false);
		wxFileDialog saveFile(NULL, _("Save Vegetation Data"), default_dir,
			default_file, _("Vegetation Files (*.vf)|*.vf"), wxFD_SAVE);
		bool bResult = (saveFile.ShowModal() == wxID_OK);
		EnableContinuousRendering(true);
		if (!bResult)
		{
			wxSetWorkingDirectory(path);	// restore
			return;
		}
		wxString str = saveFile.GetPath();
		fname = str.mb_str(wxConvUTF8);
		pia.SetFilename(fname);
	}
	pia.WriteVF(fname);
}

void EnviroGUI::SaveStructures(bool bAskFilename)
{
	vtStructureArray3d *sa = GetCurrentTerrain()->GetStructureLayer();
	vtString fname = sa->GetFilename();
	if (bAskFilename)
	{
		// save current directory
		wxString path = wxGetCwd();

		wxString default_file(StartOfFilename(fname), wxConvUTF8);
		wxString default_dir(ExtractPath(fname), wxConvUTF8);

		EnableContinuousRendering(false);
		wxFileDialog saveFile(NULL, _("Save Built Structures Data"),
			default_dir, default_file, _("Structure Files (*.vtst)|*.vtst"),
			wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
		bool bResult = (saveFile.ShowModal() == wxID_OK);
		EnableContinuousRendering(true);
		if (!bResult)
		{
			wxSetWorkingDirectory(path);	// restore
			return;
		}
		wxString str = saveFile.GetPath();
		fname = str.mb_str(wxConvUTF8);
		sa->SetFilename(fname);
	}
	sa->WriteXML(fname);
}

bool EnviroGUI::IsAcceptable(vtTerrain *pTerr)
{
	return GetFrame()->IsAcceptable(pTerr);
}

void EnviroGUI::ShowMessage(const vtString &str)
{
	EnableContinuousRendering(false);

	wxString str2(str, wxConvUTF8);
	wxMessageBox(str2);

	EnableContinuousRendering(true);
}

///////////////////////////////////////////////////////////////////////

vtJoystickEngine::vtJoystickEngine()
{
	m_fSpeed = 1.0f;
	m_fLastTime = 0.0f;

	m_pStick = new wxJoystick;
	if (!m_pStick->IsOk())
	{
		delete m_pStick;
		m_pStick = NULL;
	}
}
void vtJoystickEngine::Eval()
{
	if (!m_pStick)
		return;

	float fTime = vtGetTime(), fElapsed = fTime - m_fLastTime;

	vtTransform *pTarget = (vtTransform*) GetTarget();
	if (pTarget)
	{
		wxPoint p = m_pStick->GetPosition();
		int buttons = m_pStick->GetButtonState();
		float dx = ((float)p.x / 32768) - 1.0f;
		float dy = ((float)p.y / 32768) - 1.0f;

		// use a small dead zone to avoid drift
		const float dead_zone = 0.04f;

		if (buttons & wxJOY_BUTTON2)
		{
			// move up down left right
			if (fabs(dx) > dead_zone)
				pTarget->TranslateLocal(FPoint3(dx * m_fSpeed * fElapsed, 0.0f, 0.0f));
			if (fabs(dy) > dead_zone)
				pTarget->Translate1(FPoint3(0.0f, dy * m_fSpeed * fElapsed, 0.0f));
		}
		else if (buttons & wxJOY_BUTTON3)
		{
			// pitch up down, yaw left right
			if (fabs(dx) > dead_zone)
				pTarget->RotateParent(FPoint3(0,1,0), -dx * fElapsed);
			if (fabs(dy) > dead_zone)
				pTarget->RotateLocal(FPoint3(1,0,0), dy * fElapsed);
		}
		else
		{
			// move forward-backward, turn left-right
			if (fabs(dy) > dead_zone)
				pTarget->TranslateLocal(FPoint3(0.0f, 0.0f, dy * m_fSpeed * fElapsed));
			if (fabs(dx) > dead_zone)
				pTarget->RotateParent(FPoint3(0,1,0), -dx * fElapsed);
		}
	}
	m_fLastTime = fTime;
}

///////////////////////////////////////////////////////////////////////
// Helpers

vtAbstractLayer *CreateNewAbstractPointLayer(vtTerrain *pTerr)
{
	// make a new abstract layer (points)
	vtFeatureSetPoint2D *pSet = new vtFeatureSetPoint2D;
	vtTagArray &props = pSet->GetProperties();
	pSet->SetFilename("Untitled.shp");
	pSet->AddField("Label", FT_String);

	// Ask style for the new point layer
	props.SetValueBool("Geometry", false, true);
	props.SetValueBool("Labels", true, true);
	props.SetValueRGBi("LabelColor", RGBi(255,255,0), true);
	props.SetValueFloat("Elevation", 10.0f, true);
	props.SetValueInt("TextFieldIndex", 0, true);

	StyleDlg dlg(NULL, -1, _("Style"));
	dlg.SetFeatureSet(pSet);
	dlg.SetOptions(vtGetDataPath(), props);
	if (dlg.ShowModal() != wxID_OK)
	{
		delete pSet;
		return NULL;
	}
	dlg.GetOptions(props);

	// wrap the features in an abstract layer
	vtAbstractLayer *pLay = new vtAbstractLayer;
	pLay->pSet = pSet;

	// add the new layer to the terrain
	pTerr->GetLayers().Append(pLay);
	pTerr->SetAbstractLayer(pLay);

	return pLay;
}
<commit_msg>close progress on terrain load error, to avoid stuck dialog<commit_after>//
// EnviroGUI.cpp
// GUI-specific functionality of the Enviro class
//
// Copyright (c) 2003-2007 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include "vtlib/vtlib.h"
#include "vtlib/core/Terrain.h"
#include "vtdata/vtLog.h"
#include "vtui/Helper.h"
#include "vtui/InstanceDlg.h"
#include "vtui/ProfileDlg.h"

#include "EnviroGUI.h"
#include "EnviroApp.h"
#include "EnviroFrame.h"
#include "canvas.h"
#include "DistanceDlg3d.h"
#include "LayerDlg.h"
#include "StyleDlg.h"

#if WIN32 || !wxUSE_JOYSTICK
  #include "vtui/Joystick.h"
#else
  #include "wx/joystick.h"
#endif

DECLARE_APP(EnviroApp);

//
// This is a 'singleton', the only instance of the global application object
//
EnviroGUI g_App;

// helper
EnviroFrame *GetFrame()
{
	return dynamic_cast<EnviroFrame *>(wxGetApp().GetTopWindow());
}

EnviroGUI::EnviroGUI()
{
	m_pJFlyer = NULL;
}

EnviroGUI::~EnviroGUI()
{
}

void EnviroGUI::ShowPopupMenu(const IPoint2 &pos)
{
	GetFrame()->ShowPopupMenu(pos);
}

void EnviroGUI::SetTerrainToGUI(vtTerrain *pTerrain)
{
	GetFrame()->SetTerrainToGUI(pTerrain);

	if (pTerrain && m_pJFlyer)
	{
		float speed = pTerrain->GetParams().GetValueFloat(STR_NAVSPEED);
		m_pJFlyer->SetSpeed(speed);
	}
}

void EnviroGUI::SetFlightSpeed(float speed)
{
	if (m_pJFlyer)
		m_pJFlyer->SetSpeed(speed);
	Enviro::SetFlightSpeed(speed);
}

const char *AppStateNames[] =
{
	"AS_Initializing",
	"AS_Neutral",
	"AS_Orbit",
	"AS_FlyingIn",
	"AS_SwitchToTerrain",
	"AS_Terrain",
	"AS_MovingOut",
	"AS_Error"
};

void EnviroGUI::SetState(AppState s)
{
	// if entering or leaving terrain or orbit state
	AppState previous = m_state;
	m_state = s;

	if (m_state != previous)
	{
		VTLOG("Changing app state from %s to %s\n", AppStateNames[previous],
			AppStateNames[m_state]);
	}

	if ((previous == AS_Terrain && m_state != AS_Terrain) ||
		(previous == AS_Orbit && m_state != AS_Orbit) ||
		(previous != AS_Terrain && m_state == AS_Terrain) ||
		(previous != AS_Orbit && m_state == AS_Orbit))
	{
		GetFrame()->RefreshToolbar();
	}

	if (s == AS_Error)
	{
		// If we encounter an error while trying to open a terrain, don't get
		//  stuck in a progress dialog.
		CloseProgressDialog2();
	}
}

vtString EnviroGUI::GetStringFromUser(const vtString &title, const vtString &msg)
{
	wxString caption(title, wxConvUTF8);
	wxString message(msg, wxConvUTF8);
	wxString str = wxGetTextFromUser(message, caption, _T(""), GetFrame());
	return (vtString) (const char *) str.mb_str(wxConvUTF8);
}

void EnviroGUI::ShowProgress(bool bShow)
{
	if (bShow)
		OpenProgressDialog2(_("Creating Terrain"), false, GetFrame());
	else
		CloseProgressDialog2();
}

void EnviroGUI::SetProgressTerrain(vtTerrain *pTerr)
{
	pTerr->SetProgressCallback(progress_callback_minor);
}

void EnviroGUI::UpdateProgress(const char *msg, int amount1, int amount2)
{
	wxString str(msg, wxConvUTF8);

	// Try to translate it; a translation might be available.
	// If the string is not found in any of the loaded message catalogs,
	// the original string is returned.
	wxString str2 = wxGetTranslation(str);

	UpdateProgressDialog2(amount1, amount2, str2);
}

void EnviroGUI::RefreshLayerView()
{
	LayerDlg *dlg = GetFrame()->m_pLayerDlg;
	dlg->RefreshTreeContents();
}

void EnviroGUI::UpdateLayerView()
{
	LayerDlg *dlg = GetFrame()->m_pLayerDlg;
	dlg->UpdateTreeTerrain();
}

void EnviroGUI::ShowLayerView()
{
	LayerDlg *dlg = GetFrame()->m_pLayerDlg;
	dlg->Show(true);
}

void EnviroGUI::CameraChanged()
{
	GetFrame()->CameraChanged();
}

void EnviroGUI::EarthPosUpdated()
{
	GetFrame()->EarthPosUpdated(m_EarthPos);
}

void EnviroGUI::ShowDistance(const DPoint2 &p1, const DPoint2 &p2,
							 double fGround, double fVertical)
{
	GetFrame()->m_pDistanceDlg->SetPoints(p1, p2, false);
	GetFrame()->m_pDistanceDlg->SetGroundAndVertical(fGround, fVertical, true);

	if (GetFrame()->m_pProfileDlg)
		GetFrame()->m_pProfileDlg->SetPoints(p1, p2);
}

void EnviroGUI::ShowDistance(const DLine2 &path,
							 double fGround, double fVertical)
{
	GetFrame()->m_pDistanceDlg->SetPath(path, false);
	GetFrame()->m_pDistanceDlg->SetGroundAndVertical(fGround, fVertical, true);

	if (GetFrame()->m_pProfileDlg)
		GetFrame()->m_pProfileDlg->SetPath(path);
}

vtTagArray *EnviroGUI::GetInstanceFromGUI()
{
	return GetFrame()->m_pInstanceDlg->GetTagArray();
}

bool EnviroGUI::OnMouseEvent(vtMouseEvent &event)
{
	return GetFrame()->OnMouseEvent(event);
}

void EnviroGUI::SetupScene3()
{
	GetFrame()->Setup3DScene();

#if wxUSE_JOYSTICK || WIN32
	m_pJFlyer = new vtJoystickEngine;
	m_pJFlyer->SetName2("Joystick");
	vtGetScene()->AddEngine(m_pJFlyer);
	m_pJFlyer->SetTarget(m_pNormalCamera);
#endif
}

void EnviroGUI::SetTimeEngineToGUI(class vtTimeEngine *pEngine)
{
	GetFrame()->SetTimeEngine(pEngine);
}

//////////////////////////////////////////////////////////////////////

void EnviroGUI::SaveVegetation(bool bAskFilename)
{
	vtTerrain *pTerr = GetCurrentTerrain();
	vtPlantInstanceArray &pia = pTerr->GetPlantInstances();

	vtString fname = pia.GetFilename();

	if (bAskFilename)
	{
		// save current directory
		wxString path = wxGetCwd();

		wxString default_file(StartOfFilename(fname), wxConvUTF8);
		wxString default_dir(ExtractPath(fname), wxConvUTF8);

		EnableContinuousRendering(false);
		wxFileDialog saveFile(NULL, _("Save Vegetation Data"), default_dir,
			default_file, _("Vegetation Files (*.vf)|*.vf"), wxFD_SAVE);
		bool bResult = (saveFile.ShowModal() == wxID_OK);
		EnableContinuousRendering(true);
		if (!bResult)
		{
			wxSetWorkingDirectory(path);	// restore
			return;
		}
		wxString str = saveFile.GetPath();
		fname = str.mb_str(wxConvUTF8);
		pia.SetFilename(fname);
	}
	pia.WriteVF(fname);
}

void EnviroGUI::SaveStructures(bool bAskFilename)
{
	vtStructureArray3d *sa = GetCurrentTerrain()->GetStructureLayer();
	vtString fname = sa->GetFilename();
	if (bAskFilename)
	{
		// save current directory
		wxString path = wxGetCwd();

		wxString default_file(StartOfFilename(fname), wxConvUTF8);
		wxString default_dir(ExtractPath(fname), wxConvUTF8);

		EnableContinuousRendering(false);
		wxFileDialog saveFile(NULL, _("Save Built Structures Data"),
			default_dir, default_file, _("Structure Files (*.vtst)|*.vtst"),
			wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
		bool bResult = (saveFile.ShowModal() == wxID_OK);
		EnableContinuousRendering(true);
		if (!bResult)
		{
			wxSetWorkingDirectory(path);	// restore
			return;
		}
		wxString str = saveFile.GetPath();
		fname = str.mb_str(wxConvUTF8);
		sa->SetFilename(fname);
	}
	sa->WriteXML(fname);
}

bool EnviroGUI::IsAcceptable(vtTerrain *pTerr)
{
	return GetFrame()->IsAcceptable(pTerr);
}

void EnviroGUI::ShowMessage(const vtString &str)
{
	EnableContinuousRendering(false);

	wxString str2(str, wxConvUTF8);
	wxMessageBox(str2);

	EnableContinuousRendering(true);
}

///////////////////////////////////////////////////////////////////////

vtJoystickEngine::vtJoystickEngine()
{
	m_fSpeed = 1.0f;
	m_fLastTime = 0.0f;

	m_pStick = new wxJoystick;
	if (!m_pStick->IsOk())
	{
		delete m_pStick;
		m_pStick = NULL;
	}
}
void vtJoystickEngine::Eval()
{
	if (!m_pStick)
		return;

	float fTime = vtGetTime(), fElapsed = fTime - m_fLastTime;

	vtTransform *pTarget = (vtTransform*) GetTarget();
	if (pTarget)
	{
		wxPoint p = m_pStick->GetPosition();
		int buttons = m_pStick->GetButtonState();
		float dx = ((float)p.x / 32768) - 1.0f;
		float dy = ((float)p.y / 32768) - 1.0f;

		// use a small dead zone to avoid drift
		const float dead_zone = 0.04f;

		if (buttons & wxJOY_BUTTON2)
		{
			// move up down left right
			if (fabs(dx) > dead_zone)
				pTarget->TranslateLocal(FPoint3(dx * m_fSpeed * fElapsed, 0.0f, 0.0f));
			if (fabs(dy) > dead_zone)
				pTarget->Translate1(FPoint3(0.0f, dy * m_fSpeed * fElapsed, 0.0f));
		}
		else if (buttons & wxJOY_BUTTON3)
		{
			// pitch up down, yaw left right
			if (fabs(dx) > dead_zone)
				pTarget->RotateParent(FPoint3(0,1,0), -dx * fElapsed);
			if (fabs(dy) > dead_zone)
				pTarget->RotateLocal(FPoint3(1,0,0), dy * fElapsed);
		}
		else
		{
			// move forward-backward, turn left-right
			if (fabs(dy) > dead_zone)
				pTarget->TranslateLocal(FPoint3(0.0f, 0.0f, dy * m_fSpeed * fElapsed));
			if (fabs(dx) > dead_zone)
				pTarget->RotateParent(FPoint3(0,1,0), -dx * fElapsed);
		}
	}
	m_fLastTime = fTime;
}

///////////////////////////////////////////////////////////////////////
// Helpers

vtAbstractLayer *CreateNewAbstractPointLayer(vtTerrain *pTerr)
{
	// make a new abstract layer (points)
	vtFeatureSetPoint2D *pSet = new vtFeatureSetPoint2D;
	vtTagArray &props = pSet->GetProperties();
	pSet->SetFilename("Untitled.shp");
	pSet->AddField("Label", FT_String);

	// Ask style for the new point layer
	props.SetValueBool("Geometry", false, true);
	props.SetValueBool("Labels", true, true);
	props.SetValueRGBi("LabelColor", RGBi(255,255,0), true);
	props.SetValueFloat("Elevation", 10.0f, true);
	props.SetValueInt("TextFieldIndex", 0, true);

	StyleDlg dlg(NULL, -1, _("Style"));
	dlg.SetFeatureSet(pSet);
	dlg.SetOptions(vtGetDataPath(), props);
	if (dlg.ShowModal() != wxID_OK)
	{
		delete pSet;
		return NULL;
	}
	dlg.GetOptions(props);

	// wrap the features in an abstract layer
	vtAbstractLayer *pLay = new vtAbstractLayer;
	pLay->pSet = pSet;

	// add the new layer to the terrain
	pTerr->GetLayers().Append(pLay);
	pTerr->SetAbstractLayer(pLay);

	return pLay;
}
<|endoftext|>


<commit_before>/******************************************************************************

  nomlib - C++11 cross-platform game engine

Copyright (c) 2013, 2014 Jeffrey Carpenter <i8degrees@gmail.com>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. 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.

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.

******************************************************************************/
#ifndef NOMLIB_MATH_HELPERS_HPP
#define NOMLIB_MATH_HELPERS_HPP

#include <random>
#include <cmath>

#include "nomlib/config.hpp"
#include "nomlib/math/Point2.hpp"
#include "nomlib/math/Size2.hpp"

namespace nom {

const double PI = 4.0 * atan ( 1.0 );

namespace priv {

extern std::random_device rd;
extern std::default_random_engine rd_generator;

} // namespace priv

/// \brief Initialize the default random engine.
///
/// \param seed The seed sequence value for the random number generator.
///
/// \remarks This function does not need to be called when the use of a known
/// seed source is not necessary.
///
/// \note This function should only be called once, and before using any of the
/// random number generators provided by nomlib.
///
/// \see nom::uniform_int_rand, nom::uniform_real_rand.
void init_rand(uint32 seed_seq);

/// \brief Generate a random number.
///
/// \return Random number between the specified start and end numbers.
///
/// \remarks This function should only be used with signed or unsigned integers.
template <typename T>
T uniform_int_rand(T start_range, T end_range)
{
  std::uniform_int_distribution<T> distribution(start_range, end_range);

  return distribution(priv::rd_generator);
}

/// \brief Generate a random number.
///
/// \return Random number between the specified start and end numbers.
///
/// \remarks This function should only be used with float or double numbers.
template <typename T>
T uniform_real_rand(T start_range, T end_range)
{
  std::uniform_real_distribution<T> distribution(start_range, end_range);

  return distribution(priv::rd_generator);
}

/// Rotates a given X & Y coordinate point along a given pivot axis
/// (rotation point) at the given angle (in degrees), clockwise.
const Point2d rotate_points ( float angle, float x, float y, float pivot_x, float pivot_y );

/// \brief Round a fractional value.
///
/// \param number The 32-bit floating-point number to round.
///
/// \returns The rounded value as a signed 32-bit integer.
///
/// \remarks The number is round up when it is greater than 0.5 and rounded
/// down when the number is less than 0.5
template <typename T>
T round_float(real32 number)
{
  real32 ret = number < 0.0f ? ceilf(number - 0.5f) : floorf(number + 0.5f);
  return NOM_SCAST(T, ret);
}

/// \brief Round a fractional value.
///
/// \param number The 64-bit floating-point number to round.
///
/// \returns The rounded value as a signed 64-bit integer.
///
/// \remarks The number is round up when it is greater than 0.5 and rounded
template <typename T>
T round_double(real64 number)
{
  real64 ret = number < 0.0f ? ceil(number - 0.5f) : floor(number + 0.5f);
  return NOM_SCAST(T, ret);
}

} // namespace nom

#endif // include guard defined
<commit_msg>math_helpers: Add ::round_float_down, ::round_float_up<commit_after>/******************************************************************************

  nomlib - C++11 cross-platform game engine

Copyright (c) 2013, 2014 Jeffrey Carpenter <i8degrees@gmail.com>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
   list of conditions and the following disclaimer.
2. 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.

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.

******************************************************************************/
#ifndef NOMLIB_MATH_HELPERS_HPP
#define NOMLIB_MATH_HELPERS_HPP

#include <random>
#include <cmath>

#include "nomlib/config.hpp"
#include "nomlib/math/Point2.hpp"
#include "nomlib/math/Size2.hpp"

namespace nom {

const double PI = 4.0 * atan ( 1.0 );

namespace priv {

extern std::random_device rd;
extern std::default_random_engine rd_generator;

} // namespace priv

/// \brief Initialize the default random engine.
///
/// \param seed The seed sequence value for the random number generator.
///
/// \remarks This function does not need to be called when the use of a known
/// seed source is not necessary.
///
/// \note This function should only be called once, and before using any of the
/// random number generators provided by nomlib.
///
/// \see nom::uniform_int_rand, nom::uniform_real_rand.
void init_rand(uint32 seed_seq);

/// \brief Generate a random number.
///
/// \return Random number between the specified start and end numbers.
///
/// \remarks This function should only be used with signed or unsigned integers.
template <typename T>
T uniform_int_rand(T start_range, T end_range)
{
  std::uniform_int_distribution<T> distribution(start_range, end_range);

  return distribution(priv::rd_generator);
}

/// \brief Generate a random number.
///
/// \return Random number between the specified start and end numbers.
///
/// \remarks This function should only be used with float or double numbers.
template <typename T>
T uniform_real_rand(T start_range, T end_range)
{
  std::uniform_real_distribution<T> distribution(start_range, end_range);

  return distribution(priv::rd_generator);
}

/// Rotates a given X & Y coordinate point along a given pivot axis
/// (rotation point) at the given angle (in degrees), clockwise.
const Point2d rotate_points ( float angle, float x, float y, float pivot_x, float pivot_y );

/// \brief Round a fractional value.
///
/// \param number The 32-bit floating-point number to round.
///
/// \remarks The number is round up when it is greater than 0.5 and rounded
/// down when the number is less than 0.5
template <typename T>
T round_float(real32 number)
{
  real32 ret = number < 0.0f ? ceilf(number - 0.5f) : floorf(number + 0.5f);
  return NOM_SCAST(T, ret);
}

/// \brief Round a fractional value down to the nearest integral number.
///
/// \param number The 32-bit floating-point number to round.
template <typename T>
T round_float_down(real32 number)
{
  real32 ret = floorf(number);
  return NOM_SCAST(T, ret);
}

/// \brief Round a fractional value up to the largest integral number.
///
/// \param number The 32-bit floating-point number to round.
template <typename T>
T round_float_up(real32 number)
{
  real32 ret = ceilf(number);
  return NOM_SCAST(T, ret);
}

/// \brief Round a fractional value.
///
/// \param number The 64-bit floating-point number to round.
///
/// \remarks The number is round up when it is greater than 0.5 and rounded
/// down when the number is less than 0.5.
template <typename T>
T round_double(real64 number)
{
  real64 ret = number < 0.0f ? ceil(number - 0.5f) : floor(number + 0.5f);
  return NOM_SCAST(T, ret);
}

} // namespace nom

#endif // include guard defined
<|endoftext|>