<commit_before>/*
Copyright 2011-2017 Frederic Langlet
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
you may obtain a copy of the License at

                http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef _IOUtil_
#define _IOUtil_
#include <sys/stat.h>
#include "../types.hpp"

#include "Error.hpp"
#include "IOException.hpp"

#ifdef _MSC_VER
#include "../msvc_dirent.hpp"
#else
#include <dirent.h>
#endif

using namespace std;

static void createFileList(string target, vector<string>& files) THROW
{
    struct stat buffer;

    if (target[target.size()-1] == PATH_SEPARATOR)
        target = target.substr(0, target.size()-1);

    if (stat(target.c_str(), &buffer) != 0) {
        stringstream ss;
        ss << "Cannot access input file '" << target << "'";
        throw IOException(ss.str(), Error::ERR_OPEN_FILE);
    }

    if ((buffer.st_mode & S_IFREG) != 0) {
        // Target is regular file
        files.push_back(target);
        return;
    }

    if ((buffer.st_mode & S_IFDIR) == 0) {
        // Target is neither regular file nor directory
        stringstream ss;
        ss << "Invalid file type '" << target << "'";
        throw IOException(ss.str(), Error::ERR_OPEN_FILE);
    }

    bool isRecursive = (target.size() <= 2) || (target[target.size()-1] != '.') ||
               (target[target.size()-2] != PATH_SEPARATOR);

    if (isRecursive) {
       if (target[target.size()-1] != PATH_SEPARATOR) {
          stringstream ss;
          ss << target << PATH_SEPARATOR;
          target = ss.str();
       }
    } else {
       target = target.substr(0, target.size()-1);
    }

    DIR* dir = opendir(target.c_str());
    struct dirent* ent;

    if (dir != nullptr) {
        while ((ent = readdir(dir)) != nullptr) {
            string fullpath = target + ent->d_name;

            if (stat(fullpath.c_str(), &buffer) != 0) {
                stringstream ss;
                ss << "Cannot access input file '" << target << ent->d_name << "'";
                throw IOException(ss.str(), Error::ERR_OPEN_FILE);
            }

            if (ent->d_name[0] != '.')
            {
               if ((buffer.st_mode & S_IFREG) != 0){
                   files.push_back(fullpath);
               }
               else if ((isRecursive) && ((buffer.st_mode & S_IFDIR) != 0)) {
                   createFileList(fullpath, files);
               }
            }
        }

        closedir(dir);
    }
    else {
        stringstream ss;
        ss << "Cannot read directory '" << target << "'";
        throw IOException(ss.str(), Error::ERR_READ_FILE);
    }
}

#endif<commit_msg>Fix compilation warning with clang.<commit_after>/*
Copyright 2011-2017 Frederic Langlet
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
you may obtain a copy of the License at

                http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#ifndef _IOUtil_
#define _IOUtil_
#include <sys/stat.h>
#include "../types.hpp"

#include "Error.hpp"
#include "IOException.hpp"

#ifdef _MSC_VER
#include "../msvc_dirent.hpp"
#else
#include <dirent.h>
#endif

using namespace std;

static inline void createFileList(string target, vector<string>& files) THROW
{
    struct stat buffer;

    if (target[target.size()-1] == PATH_SEPARATOR)
        target = target.substr(0, target.size()-1);

    if (stat(target.c_str(), &buffer) != 0) {
        stringstream ss;
        ss << "Cannot access input file '" << target << "'";
        throw IOException(ss.str(), Error::ERR_OPEN_FILE);
    }

    if ((buffer.st_mode & S_IFREG) != 0) {
        // Target is regular file
        files.push_back(target);
        return;
    }

    if ((buffer.st_mode & S_IFDIR) == 0) {
        // Target is neither regular file nor directory
        stringstream ss;
        ss << "Invalid file type '" << target << "'";
        throw IOException(ss.str(), Error::ERR_OPEN_FILE);
    }

    bool isRecursive = (target.size() <= 2) || (target[target.size()-1] != '.') ||
               (target[target.size()-2] != PATH_SEPARATOR);

    if (isRecursive) {
       if (target[target.size()-1] != PATH_SEPARATOR) {
          stringstream ss;
          ss << target << PATH_SEPARATOR;
          target = ss.str();
       }
    } else {
       target = target.substr(0, target.size()-1);
    }

    DIR* dir = opendir(target.c_str());
    struct dirent* ent;

    if (dir != nullptr) {
        while ((ent = readdir(dir)) != nullptr) {
            string fullpath = target + ent->d_name;

            if (stat(fullpath.c_str(), &buffer) != 0) {
                stringstream ss;
                ss << "Cannot access input file '" << target << ent->d_name << "'";
                throw IOException(ss.str(), Error::ERR_OPEN_FILE);
            }

            if (ent->d_name[0] != '.')
            {
               if ((buffer.st_mode & S_IFREG) != 0){
                   files.push_back(fullpath);
               }
               else if ((isRecursive) && ((buffer.st_mode & S_IFDIR) != 0)) {
                   createFileList(fullpath, files);
               }
            }
        }

        closedir(dir);
    }
    else {
        stringstream ss;
        ss << "Cannot read directory '" << target << "'";
        throw IOException(ss.str(), Error::ERR_READ_FILE);
    }
}

#endif<|endoftext|>


<commit_before>#pragma once
#include <cstdint>
#include <limits>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#include <nmmintrin.h>

#define __builtin_popcount __popcnt
#define __builtin_popcountll _mm_popcnt_u64

// bit operations (_builtin_ctz (ctzl, ctzll) and __builtin_clz (clzl, clzll)) for Visual Studio
// https://gist.github.com/pps83/3210a2f980fd02bb2ba2e5a1fc4a2ef0

static inline int __builtin_ctz(unsigned x) {
    unsigned long ret;
    _BitScanForward(&ret, x);
    return (int)ret;
}

static inline int __builtin_ctzll(unsigned long long x) {
    unsigned long ret;
    _BitScanForward64(&ret, x);
    return (int)ret;
}

static inline int __builtin_ctzl(unsigned long x) {
    return sizeof(x) == 8 ? __builtin_ctzll(x) : __builtin_ctz((uint32_t)x);
}

static inline int __builtin_clz(unsigned x) {
    //unsigned long ret;
    //_BitScanReverse(&ret, x);
    //return (int)(31 ^ ret);
    return (int)__lzcnt(x);
}

static inline int __builtin_clzll(unsigned long long x) {
    //unsigned long ret;
    //_BitScanReverse64(&ret, x);
    //return (int)(63 ^ ret);
    return (int)__lzcnt64(x);
}

static inline int __builtin_clzl(unsigned long x) {
    return sizeof(x) == 8 ? __builtin_clzll(x) : __builtin_clz((uint32_t)x);
}

#ifdef __cplusplus
static inline int __builtin_ctzl(unsigned long long x) {
    return __builtin_ctzll(x);
}

static inline int __builtin_clzl(unsigned long long x) {
    return __builtin_clzll(x);
}
#endif
#endif

// todo[c++17] use is_unsigned_v
// todo[c++17]: use constexpr if
template<typename T, typename std::enable_if_t<std::is_unsigned<T>::value>* = nullptr>
constexpr size_t popcount(const T value) noexcept {
    if (sizeof(T) <= sizeof(uint32_t)) {
        return __builtin_popcount(value);
    } else {
        return __builtin_popcountll(value);
    }
}

template<typename T, typename std::enable_if_t<!std::is_unsigned<T>::value>* = nullptr>
constexpr size_t popcount(const T value) noexcept {
    return popcount(static_cast<typename std::make_unsigned_t<T>>(value));
}

// todo[c++17]: use constexpr if
template<typename T, typename std::enable_if_t<std::is_unsigned<T>::value>* = nullptr>
constexpr size_t countl_zero(const T value) noexcept {
    constexpr size_t digits = std::numeric_limits<T>::digits;
    if (value == 0) {
        return digits;
    }
    if (sizeof(T) <= sizeof(uint32_t)) {
        return __builtin_clz(value) - (std::numeric_limits<uint32_t>::digits - digits);
    } else {
        return __builtin_clzll(value) - (std::numeric_limits<uint64_t>::digits - digits);
    }
}

template<typename T, typename std::enable_if_t<!std::is_unsigned<T>::value>* = nullptr>
constexpr size_t countl_zero(const T value) noexcept {
    return countl_zero(static_cast<typename std::make_unsigned_t<T>>(value));
}

// todo[c++17] use is_integral_v
template<typename T, typename std::enable_if_t<std::is_integral<T>::value>* = nullptr>
constexpr size_t countl_one(const T value) noexcept {
    return countl_zero(static_cast<T>(~value));
}

template<typename T, typename std::enable_if_t<std::is_unsigned<T>::value>* = nullptr>
constexpr size_t countr_zero(const T value) noexcept {
    if (value == 0) {
        return std::numeric_limits<T>::digits;
    }
    if (sizeof(T) <= sizeof(uint32_t)) {
        return __builtin_ctz(value);
    } else {
        return __builtin_ctzll(value);
    }
}

template<typename T, typename std::enable_if_t<!std::is_unsigned<T>::value>* = nullptr>
constexpr size_t countr_zero(const T value) noexcept {
    return countr_zero(static_cast<typename std::make_unsigned_t<T>>(value));
}

template<typename T, typename std::enable_if_t<std::is_integral<T>::value>* = nullptr>
constexpr size_t countr_one(const T value) noexcept {
    return countr_zero(static_cast<T>(~value));
}

template<typename T, typename std::enable_if_t<std::is_integral<T>::value>* = nullptr>
constexpr bool has_single_bit(const T value) noexcept {
    return value != 0 && (value & (value - 1)) == 0;
}

template<typename T, typename std::enable_if_t<std::is_unsigned<T>::value>* = nullptr>
constexpr T bit_ceil(const T value) noexcept {
    if (value == 0) {
        return 1;
    }
    return static_cast<T>(T{1} << (std::numeric_limits<T>::digits - countl_zero(static_cast<T>(value - 1))));
}

template<typename T, typename std::enable_if_t<!std::is_unsigned<T>::value>* = nullptr>
constexpr T bit_ceil(const T value) noexcept {
    return static_cast<T>(bit_ceil(static_cast<typename std::make_unsigned_t<T>>(value)));
}

template<typename T, typename std::enable_if_t<std::is_unsigned<T>::value>* = nullptr>
constexpr T bit_floor(const T value) noexcept {
    if (value == 0) {
        return 0;
    }
    return static_cast<T>(T{1} << (std::numeric_limits<T>::digits - 1 - countl_zero(value)));
}

template<typename T, typename std::enable_if_t<!std::is_unsigned<T>::value>* = nullptr>
constexpr T bit_floor(const T value) noexcept {
    return static_cast<T>(bit_floor(static_cast<typename std::make_unsigned_t<T>>(value)));
}

template<typename T, typename std::enable_if_t<std::is_unsigned<T>::value>* = nullptr>
constexpr size_t bit_width(const T value) noexcept {
    return static_cast<T>(std::numeric_limits<T>::digits - countl_zero(value));
}

template<typename T, typename std::enable_if_t<!std::is_unsigned<T>::value>* = nullptr>
constexpr size_t bit_width(const T value) noexcept {
    return bit_width(static_cast<typename std::make_unsigned_t<T>>(value));
}

template<typename T, typename std::enable_if_t<std::is_integral<T>::value>* = nullptr>
constexpr bool test_bit(const T mask, const std::size_t bit_id) noexcept {
    return mask & (T{1} << bit_id);
}

template<typename T, typename std::enable_if_t<std::is_unsigned<T>::value>* = nullptr>
constexpr size_t binary_power(const T value) {
    if (value == 0) {
        return 0;
    }
    return bit_width(value) - 1;
}
<commit_msg>Implemented to_binary_string() method.<commit_after>#pragma once
#include <cstdint>
#include <limits>
#include <type_traits>

#ifdef _MSC_VER
#include <intrin.h>
#include <nmmintrin.h>

#define __builtin_popcount __popcnt
#define __builtin_popcountll _mm_popcnt_u64

// bit operations (_builtin_ctz (ctzl, ctzll) and __builtin_clz (clzl, clzll)) for Visual Studio
// https://gist.github.com/pps83/3210a2f980fd02bb2ba2e5a1fc4a2ef0

static inline int __builtin_ctz(unsigned x) {
    unsigned long ret;
    _BitScanForward(&ret, x);
    return (int)ret;
}

static inline int __builtin_ctzll(unsigned long long x) {
    unsigned long ret;
    _BitScanForward64(&ret, x);
    return (int)ret;
}

static inline int __builtin_ctzl(unsigned long x) {
    return sizeof(x) == 8 ? __builtin_ctzll(x) : __builtin_ctz((uint32_t)x);
}

static inline int __builtin_clz(unsigned x) {
    //unsigned long ret;
    //_BitScanReverse(&ret, x);
    //return (int)(31 ^ ret);
    return (int)__lzcnt(x);
}

static inline int __builtin_clzll(unsigned long long x) {
    //unsigned long ret;
    //_BitScanReverse64(&ret, x);
    //return (int)(63 ^ ret);
    return (int)__lzcnt64(x);
}

static inline int __builtin_clzl(unsigned long x) {
    return sizeof(x) == 8 ? __builtin_clzll(x) : __builtin_clz((uint32_t)x);
}

#ifdef __cplusplus
static inline int __builtin_ctzl(unsigned long long x) {
    return __builtin_ctzll(x);
}

static inline int __builtin_clzl(unsigned long long x) {
    return __builtin_clzll(x);
}
#endif
#endif

// todo[c++17] use is_unsigned_v
// todo[c++17]: use constexpr if
template<typename T, typename std::enable_if_t<std::is_unsigned<T>::value>* = nullptr>
constexpr size_t popcount(const T value) noexcept {
    if (sizeof(T) <= sizeof(uint32_t)) {
        return __builtin_popcount(value);
    } else {
        return __builtin_popcountll(value);
    }
}

template<typename T, typename std::enable_if_t<!std::is_unsigned<T>::value>* = nullptr>
constexpr size_t popcount(const T value) noexcept {
    return popcount(static_cast<typename std::make_unsigned_t<T>>(value));
}

// todo[c++17]: use constexpr if
template<typename T, typename std::enable_if_t<std::is_unsigned<T>::value>* = nullptr>
constexpr size_t countl_zero(const T value) noexcept {
    constexpr size_t digits = std::numeric_limits<T>::digits;
    if (value == 0) {
        return digits;
    }
    if (sizeof(T) <= sizeof(uint32_t)) {
        return __builtin_clz(value) - (std::numeric_limits<uint32_t>::digits - digits);
    } else {
        return __builtin_clzll(value) - (std::numeric_limits<uint64_t>::digits - digits);
    }
}

template<typename T, typename std::enable_if_t<!std::is_unsigned<T>::value>* = nullptr>
constexpr size_t countl_zero(const T value) noexcept {
    return countl_zero(static_cast<typename std::make_unsigned_t<T>>(value));
}

// todo[c++17] use is_integral_v
template<typename T, typename std::enable_if_t<std::is_integral<T>::value>* = nullptr>
constexpr size_t countl_one(const T value) noexcept {
    return countl_zero(static_cast<T>(~value));
}

template<typename T, typename std::enable_if_t<std::is_unsigned<T>::value>* = nullptr>
constexpr size_t countr_zero(const T value) noexcept {
    if (value == 0) {
        return std::numeric_limits<T>::digits;
    }
    if (sizeof(T) <= sizeof(uint32_t)) {
        return __builtin_ctz(value);
    } else {
        return __builtin_ctzll(value);
    }
}

template<typename T, typename std::enable_if_t<!std::is_unsigned<T>::value>* = nullptr>
constexpr size_t countr_zero(const T value) noexcept {
    return countr_zero(static_cast<typename std::make_unsigned_t<T>>(value));
}

template<typename T, typename std::enable_if_t<std::is_integral<T>::value>* = nullptr>
constexpr size_t countr_one(const T value) noexcept {
    return countr_zero(static_cast<T>(~value));
}

template<typename T, typename std::enable_if_t<std::is_integral<T>::value>* = nullptr>
constexpr bool has_single_bit(const T value) noexcept {
    return value != 0 && (value & (value - 1)) == 0;
}

template<typename T, typename std::enable_if_t<std::is_unsigned<T>::value>* = nullptr>
constexpr T bit_ceil(const T value) noexcept {
    if (value == 0) {
        return 1;
    }
    return static_cast<T>(T{1} << (std::numeric_limits<T>::digits - countl_zero(static_cast<T>(value - 1))));
}

template<typename T, typename std::enable_if_t<!std::is_unsigned<T>::value>* = nullptr>
constexpr T bit_ceil(const T value) noexcept {
    return static_cast<T>(bit_ceil(static_cast<typename std::make_unsigned_t<T>>(value)));
}

template<typename T, typename std::enable_if_t<std::is_unsigned<T>::value>* = nullptr>
constexpr T bit_floor(const T value) noexcept {
    if (value == 0) {
        return 0;
    }
    return static_cast<T>(T{1} << (std::numeric_limits<T>::digits - 1 - countl_zero(value)));
}

template<typename T, typename std::enable_if_t<!std::is_unsigned<T>::value>* = nullptr>
constexpr T bit_floor(const T value) noexcept {
    return static_cast<T>(bit_floor(static_cast<typename std::make_unsigned_t<T>>(value)));
}

template<typename T, typename std::enable_if_t<std::is_unsigned<T>::value>* = nullptr>
constexpr size_t bit_width(const T value) noexcept {
    return static_cast<T>(std::numeric_limits<T>::digits - countl_zero(value));
}

template<typename T, typename std::enable_if_t<!std::is_unsigned<T>::value>* = nullptr>
constexpr size_t bit_width(const T value) noexcept {
    return bit_width(static_cast<typename std::make_unsigned_t<T>>(value));
}

template<typename T, typename std::enable_if_t<std::is_integral<T>::value>* = nullptr>
constexpr bool test_bit(const T mask, const std::size_t bit_id) noexcept {
    return mask & (T{1} << bit_id);
}

template<typename T, typename std::enable_if_t<std::is_unsigned<T>::value>* = nullptr>
constexpr size_t binary_power(const T value) {
    if (value == 0) {
        return 0;
    }
    return bit_width(value) - 1;
}

template<typename T, typename std::enable_if_t<std::is_unsigned<T>::value>* = nullptr>
std::string to_binary_string(const T value) {
    if (value == 0) {
        return "0";
    }
    std::string res;
    for (size_t i = 0; i < bit_width(value); ++i) {
        res += (test_bit(value, i) ? '1' : '0');
    }
    return res;
}

template<typename T, typename std::enable_if_t<!std::is_unsigned<T>::value>* = nullptr>
std::string to_binary_string(const T value) {
    return to_binary_string(static_cast<typename std::make_unsigned_t<T>>(value));
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Arista Networks, Inc.  All rights reserved.
// Arista Networks, Inc. Confidential and Proprietary.

#include "eos/version.h"
#include "config.h"  // Generated by configure

const char * const version = PACKAGE_VERSION "-stubs";
const uint8_t version_major = SDK_VERSION_MAJOR;
const uint8_t version_minor = SDK_VERSION_MINOR;
const uint8_t version_patch = SDK_VERSION_PATCH;
const char * const build_project = SDK_BUILD_PROJECT;
const char * const build_user = SDK_BUILD_USER;
const char * const build_path = SDK_BUILD_PATH;
const uint32_t build_cl = SDK_BUILD_PROJECT_CL;
const uint64_t build_timestamp = SDK_BUILD_TIMESTAMP;
<commit_msg>@1964689 Fix version.cpp in the stubs package.<commit_after>// Copyright (c) 2013 Arista Networks, Inc.  All rights reserved.
// Arista Networks, Inc. Confidential and Proprietary.

#include "eos/version.h"
#include "config.h"  // Generated by configure

namespace eos {

const char * const version = PACKAGE_VERSION "-stubs";
const uint8_t version_major = SDK_VERSION_MAJOR;
const uint8_t version_minor = SDK_VERSION_MINOR;
const uint8_t version_patch = SDK_VERSION_PATCH;
const char * const build_project = SDK_BUILD_PROJECT;
const char * const build_user = SDK_BUILD_USER;
const char * const build_path = SDK_BUILD_PATH;
const uint32_t build_cl = SDK_BUILD_PROJECT_CL;
const uint64_t build_timestamp = SDK_BUILD_TIMESTAMP;

}
<|endoftext|>


<commit_before>#include "geometry/epoch.hpp"
#include "geometry/named_quantities.hpp"
#include "geometry/grassmann.hpp"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "integrators/symplectic_runge_kutta_nyström_integrator.hpp"
#include "physics/solar_system.hpp"
#include "quantities/elementary_functions.hpp"
#include "quantities/quantities.hpp"
#include "quantities/si.hpp"
#include "testing_utilities/numerics.hpp"

namespace principia {

using astronomy::ICRFJ2000Equator;
using geometry::JulianDate;
using geometry::Sign;
using integrators::McLachlanAtela1992Order5Optimal;
using quantities::ArcCos;
using quantities::si::Kilo;
using quantities::si::Metre;
using quantities::si::Milli;
using quantities::si::Minute;
using quantities::si::Nano;
using quantities::si::Second;
using testing_utilities::AbsoluteError;
using ::testing::AllOf;
using ::testing::Gt;
using ::testing::Lt;

namespace physics {

class EclipseTest : public testing::Test {
 protected:
  EclipseTest() {
    solar_system_1950_.Initialize(
        SOLUTION_DIR / "astronomy" / "gravity_model.proto.txt",
        SOLUTION_DIR / "astronomy" /
            "initial_state_jd_2433282_500000000.proto.txt");
  }

  void CheckLunarUmbralEclipse(Instant const& current_time,
                         Sign const moon_offset_sign) {
    auto ephemeris = solar_system_1950_.MakeEphemeris(
        McLachlanAtela1992Order5Optimal<Position<ICRFJ2000Equator>>(),
        45 * Minute, 5 * Milli(Metre));

    ephemeris->Prolong(current_time + 86400 * Second);  // Prolong 1 day past date of eclipse.
    auto const sun = solar_system_1950_.massive_body(*ephemeris, "Sun");
    auto const earth = solar_system_1950_.massive_body(*ephemeris, "Earth");
    auto const moon = solar_system_1950_.massive_body(*ephemeris, "Moon");

    auto const q_sun = ephemeris->trajectory(sun)
                           ->EvaluatePosition(current_time, /*hint=*/nullptr);
    auto const q_moon = ephemeris->trajectory(moon)
                            ->EvaluatePosition(current_time, /*hint=*/nullptr);
    auto const q_earth = ephemeris->trajectory(earth)
                             ->EvaluatePosition(current_time, /*hint=*/nullptr);

    // MassiveBody will need radius information.  Or non-hardcoded data from
    // https://github.com/mockingbirdnest/Principia/blob/master/astronomy/gravity_model.proto.txt
    auto const r_sun = 696000.0 * Kilo(Metre);
    auto const r_earth = 6378.1363 * Kilo(Metre);
    auto const r_moon = 1738.0 * Kilo(Metre);

    // Checking body angles at the target time.
    // Angle formed by a right circular cone with sides defined by tangent lines
    // between Sun and Earth, and axis running through the centers of each.
    auto const umbral_half_aperture =
        ArcSin((r_sun - r_earth) / (q_sun - q_earth).Norm());
    auto const apex_of_moon_locus_at_umbral_contact =
        q_earth +
        Normalize(q_earth - q_sun) * (r_earth + moon_offset_sign * r_moon) /
            Sin(umbral_half_aperture);
    // Angle between Earth and Moon as seen at
    // apex_of_moon_locus_at_umbral_contact.
    auto const earth_moon_angle =
        ArcCos(InnerProduct(apex_of_moon_locus_at_umbral_contact - q_earth,
                            apex_of_moon_locus_at_umbral_contact - q_moon) /
               ((apex_of_moon_locus_at_umbral_contact - q_moon).Norm() *
                (apex_of_moon_locus_at_umbral_contact - q_earth).Norm()));
    // We are at the desired contact if the angle between Earth and Moon from
    // the apex of locus of the moon at that contact is the same value as the
    // half-aperture of the umbra (Earth-Sun cone).
    EXPECT_THAT(AbsoluteError(umbral_half_aperture, earth_moon_angle),
                AllOf(Lt(1.0 * Milli(Radian)), Gt(1.0 * Nano(Radian))))
        << NAMED(umbral_half_aperture) << ", " << NAMED(earth_moon_angle)
        << ", " << NAMED(current_time);
  }

  void CheckLunarPenumbralEclipse(Instant const& current_time,
                         Sign const moon_offset_sign) {
    auto ephemeris = solar_system_1950_.MakeEphemeris(
        McLachlanAtela1992Order5Optimal<Position<ICRFJ2000Equator>>(),
        45 * Minute, 5 * Milli(Metre));

    ephemeris->Prolong(current_time + 86400 * Second);  // Prolong 1 day past date of eclipse.
    auto const sun = solar_system_1950_.massive_body(*ephemeris, "Sun");
    auto const earth = solar_system_1950_.massive_body(*ephemeris, "Earth");
    auto const moon = solar_system_1950_.massive_body(*ephemeris, "Moon");

    auto const q_sun = ephemeris->trajectory(sun)
                           ->EvaluatePosition(current_time, /*hint=*/nullptr);
    auto const q_moon = ephemeris->trajectory(moon)
                            ->EvaluatePosition(current_time, /*hint=*/nullptr);
    auto const q_earth = ephemeris->trajectory(earth)
                             ->EvaluatePosition(current_time, /*hint=*/nullptr);

    // MassiveBody will need radius information.  Or non-hardcoded data from
    // https://github.com/mockingbirdnest/Principia/blob/master/astronomy/gravity_model.proto.txt
    auto const r_sun = 696000.0 * Kilo(Metre);
    auto const r_earth = 6378.1363 * Kilo(Metre);
    auto const r_moon = 1738.0 * Kilo(Metre);

    auto const penumbral_half_aperture =
        ArcSin((r_sun + r_earth) / (q_sun - q_earth).Norm());
    auto const apex_of_moon_locus_at_penumbral_contact =
        q_earth +
        Normalize(q_sun - q_earth) * (r_earth + moon_offset_sign * r_moon) /
            Sin(penumbral_half_aperture);
    // Angle between Earth and Moon as seen at
    // apex_of_moon_locus_at_penumbral_contact.
    auto const earth_moon_angle =
        ArcCos(InnerProduct(apex_of_moon_locus_at_penumbral_contact - q_earth,
                            apex_of_moon_locus_at_penumbral_contact - q_moon) /
               ((apex_of_moon_locus_at_penumbral_contact - q_moon).Norm() *
                (apex_of_moon_locus_at_penumbral_contact - q_earth).Norm()));
    // We are at the desired contact if the angle between Earth and Moon from
    // the apex of locus of the moon at that contact is the same value as the
    // half-aperture of the penumbra.
    EXPECT_THAT(AbsoluteError(penumbral_half_aperture, earth_moon_angle),
                AllOf(Lt(1.0 * Milli(Radian)), Gt(1.0 * Nano(Radian))))
        << NAMED(penumbral_half_aperture) << ", " << NAMED(earth_moon_angle)
        << ", " << NAMED(current_time);
  }

  SolarSystem<ICRFJ2000Equator> solar_system_1950_;
};

TEST_F(EclipseTest, Dummy) {
  // Dates are TDB Julian Day for 1950-04-02.
  auto P1 = JulianDate(2433374.25788409);  // 18:10:49 UT
  auto U1 = JulianDate(2433374.29850909);  // 19:09:19
  auto U2 = JulianDate(2433374.354979);    // 20:30:38
  auto U3 = JulianDate(2433374.37367113);  // 20:57:33
  auto U4 = JulianDate(2433374.43016419);  // 22:18:54
  auto P4 = JulianDate(2433374.47075446);  // 23:17:21

  Sign const U14 = Sign(1);
  Sign const U23 = Sign(-1);
  CheckLunarPenumbralEclipse(P1, U14);
  CheckLunarUmbralEclipse(U1, U14);
  CheckLunarUmbralEclipse(U2, U23);
  CheckLunarUmbralEclipse(U3, U23);
  CheckLunarUmbralEclipse(U4, U14);
  CheckLunarPenumbralEclipse(P4, U14);

  // Dates are TDB Julian Day for 1950-09-26.
  P1 = JulianDate(2433550.55712016);  // 01:21:43 UT
  U1 = JulianDate(2433550.60578913);  // 02:31:48
  U2 = JulianDate(2433550.66325441);  // 03:54:33
  U3 = JulianDate(2433550.69399515);  // 04:38:49
  U4 = JulianDate(2433550.75144885);  // 06:01:33
  P4 = JulianDate(2433550.800222);  // 07:11:47

  CheckLunarPenumbralEclipse(P1, U14);
  CheckLunarUmbralEclipse(U1, U14);
  CheckLunarUmbralEclipse(U2, U23);
  CheckLunarUmbralEclipse(U3, U23);
  CheckLunarUmbralEclipse(U4, U14);
  CheckLunarPenumbralEclipse(P4, U14);

  // Dates are TDB Julian Day for 1951-03-23.
  P1 = JulianDate(2433728.86842806);  // 08:50:50
  P4 = JulianDate(2433729.01725909);  // 12:24:19

  CheckLunarPenumbralEclipse(P1, U14);
  CheckLunarPenumbralEclipse(P4, U14);

  // Dates are TDB Julian Day for 1951-09-15.
  P1 = JulianDate(2433904.93736321);  // 10:29:16
  P4 = JulianDate(2433905.1002799);  // 14:23:52

  CheckLunarPenumbralEclipse(P1, U14);
  CheckLunarPenumbralEclipse(P4, U14);

  // Dates are TDB Julian Day for 1952-02-11 (or 10 for P1).
  P1 = JulianDate(2434053.42282623);  // P1 = 22:08:20 UT
  U1 = JulianDate(2434053.50334705);  // U1 = 00:04:17
  U4 = JulianDate(2434053.55203917);  // U4 = 01:14:24
  P4 = JulianDate(2434053.63249055);  // P4 = 03:10:15

  CheckLunarPenumbralEclipse(P1, U14);
  CheckLunarUmbralEclipse(U1, U14);
  CheckLunarUmbralEclipse(U4, U14);
  CheckLunarPenumbralEclipse(P4, U14);

  // Dates are TDB Julian Day for 1952-08-05.
  P1 = JulianDate(2434230.22830075);  // P1 = 17:28:13 UT
  U1 = JulianDate(2434230.27385631);  // U1 = 18:33:49
  U4 = JulianDate(2434230.37606695);  // U4 = 21:01:00
  P4 = JulianDate(2434230.42161093);  // P4 = 22:06:35

  CheckLunarPenumbralEclipse(P1, U14);
  CheckLunarUmbralEclipse(U1, U14);
  CheckLunarUmbralEclipse(U4, U14);
  CheckLunarPenumbralEclipse(P4, U14);

  // Later on for additional accuracy: 2 * ArcTan((x_norm_y -
  // y_normx).Norm(),(x_norm_y + y_norm_x).Norm())
  // x_norm_y = x * y.Norm() and y_norm_x = y * x.Norm()

  // Future is not now: check 2048-01-01 Lunar eclipse.
  /*P1 = JulianDate(2469076.66235167);  // 03:52:39 UT
  U1 = JulianDate(2469076.71279148);  // 05:05:17
  U2 = JulianDate(2469076.76776833);  // 06:24:27
  U3 = JulianDate(2469076.80661092);  // 07:20:23
  U4 = JulianDate(2469076.86158778);  // 08:39:33
  P4 = JulianDate(2469076.91195815);  // 09:52:05

  CheckLunarPenumbralEclipse(P1, U14);
  CheckLunarUmbralEclipse(U1, U14);
  CheckLunarUmbralEclipse(U2, U23);
  CheckLunarUmbralEclipse(U3, U23);
  CheckLunarUmbralEclipse(U4, U14);
  CheckLunarPenumbralEclipse(P4, U14); */
}

}  // namespace physics
}  // namespace principia
<commit_msg>No far future, but near future and formatted.<commit_after>#include "geometry/epoch.hpp"
#include "geometry/named_quantities.hpp"
#include "geometry/grassmann.hpp"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "integrators/symplectic_runge_kutta_nyström_integrator.hpp"
#include "physics/solar_system.hpp"
#include "quantities/elementary_functions.hpp"
#include "quantities/quantities.hpp"
#include "quantities/si.hpp"
#include "testing_utilities/numerics.hpp"

namespace principia {

using astronomy::ICRFJ2000Equator;
using geometry::JulianDate;
using geometry::Sign;
using integrators::McLachlanAtela1992Order5Optimal;
using quantities::ArcCos;
using quantities::si::Kilo;
using quantities::si::Metre;
using quantities::si::Milli;
using quantities::si::Minute;
using quantities::si::Nano;
using quantities::si::Second;
using testing_utilities::AbsoluteError;
using ::testing::AllOf;
using ::testing::Gt;
using ::testing::Lt;

namespace physics {

class EclipseTest : public testing::Test {
 protected:
  EclipseTest() {
    solar_system_1950_.Initialize(
        SOLUTION_DIR / "astronomy" / "gravity_model.proto.txt",
        SOLUTION_DIR / "astronomy" /
            "initial_state_jd_2433282_500000000.proto.txt");
  }

  void CheckLunarUmbralEclipse(Instant const& current_time,
                               Sign const moon_offset_sign) {
    auto ephemeris = solar_system_1950_.MakeEphemeris(
        McLachlanAtela1992Order5Optimal<Position<ICRFJ2000Equator>>(),
        45 * Minute, 5 * Milli(Metre));

    ephemeris->Prolong(current_time +
                       86400 * Second);  // Prolong 1 day past date of eclipse.
    auto const sun = solar_system_1950_.massive_body(*ephemeris, "Sun");
    auto const earth = solar_system_1950_.massive_body(*ephemeris, "Earth");
    auto const moon = solar_system_1950_.massive_body(*ephemeris, "Moon");

    auto const q_sun = ephemeris->trajectory(sun)
                           ->EvaluatePosition(current_time, /*hint=*/nullptr);
    auto const q_moon = ephemeris->trajectory(moon)
                            ->EvaluatePosition(current_time, /*hint=*/nullptr);
    auto const q_earth = ephemeris->trajectory(earth)
                             ->EvaluatePosition(current_time, /*hint=*/nullptr);

    // MassiveBody will need radius information.  Or non-hardcoded data from
    // https://github.com/mockingbirdnest/Principia/blob/master/astronomy/gravity_model.proto.txt
    auto const r_sun = 696000.0 * Kilo(Metre);
    auto const r_earth = 6378.1363 * Kilo(Metre);
    auto const r_moon = 1738.0 * Kilo(Metre);

    // Checking body angles at the target time.
    // Angle formed by a right circular cone with sides defined by tangent lines
    // between Sun and Earth, and axis running through the centers of each.
    auto const umbral_half_aperture =
        ArcSin((r_sun - r_earth) / (q_sun - q_earth).Norm());
    auto const apex_of_moon_locus_at_umbral_contact =
        q_earth +
        Normalize(q_earth - q_sun) * (r_earth + moon_offset_sign * r_moon) /
            Sin(umbral_half_aperture);
    // Angle between Earth and Moon as seen at
    // apex_of_moon_locus_at_umbral_contact.
    auto const earth_moon_angle =
        ArcCos(InnerProduct(apex_of_moon_locus_at_umbral_contact - q_earth,
                            apex_of_moon_locus_at_umbral_contact - q_moon) /
               ((apex_of_moon_locus_at_umbral_contact - q_moon).Norm() *
                (apex_of_moon_locus_at_umbral_contact - q_earth).Norm()));
    // We are at the desired contact if the angle between Earth and Moon from
    // the apex of locus of the moon at that contact is the same value as the
    // half-aperture of the umbra (Earth-Sun cone).
    EXPECT_THAT(AbsoluteError(umbral_half_aperture, earth_moon_angle),
                AllOf(Lt(1.0 * Milli(Radian)), Gt(1.0 * Nano(Radian))))
        << NAMED(umbral_half_aperture) << ", " << NAMED(earth_moon_angle)
        << ", " << NAMED(current_time);
  }

  void CheckLunarPenumbralEclipse(Instant const& current_time,
                                  Sign const moon_offset_sign) {
    auto ephemeris = solar_system_1950_.MakeEphemeris(
        McLachlanAtela1992Order5Optimal<Position<ICRFJ2000Equator>>(),
        45 * Minute, 5 * Milli(Metre));

    ephemeris->Prolong(current_time +
                       86400 * Second);  // Prolong 1 day past date of eclipse.
    auto const sun = solar_system_1950_.massive_body(*ephemeris, "Sun");
    auto const earth = solar_system_1950_.massive_body(*ephemeris, "Earth");
    auto const moon = solar_system_1950_.massive_body(*ephemeris, "Moon");

    auto const q_sun = ephemeris->trajectory(sun)
                           ->EvaluatePosition(current_time, /*hint=*/nullptr);
    auto const q_moon = ephemeris->trajectory(moon)
                            ->EvaluatePosition(current_time, /*hint=*/nullptr);
    auto const q_earth = ephemeris->trajectory(earth)
                             ->EvaluatePosition(current_time, /*hint=*/nullptr);

    // MassiveBody will need radius information.  Or non-hardcoded data from
    // https://github.com/mockingbirdnest/Principia/blob/master/astronomy/gravity_model.proto.txt
    auto const r_sun = 696000.0 * Kilo(Metre);
    auto const r_earth = 6378.1363 * Kilo(Metre);
    auto const r_moon = 1738.0 * Kilo(Metre);

    auto const penumbral_half_aperture =
        ArcSin((r_sun + r_earth) / (q_sun - q_earth).Norm());
    auto const apex_of_moon_locus_at_penumbral_contact =
        q_earth +
        Normalize(q_sun - q_earth) * (r_earth + moon_offset_sign * r_moon) /
            Sin(penumbral_half_aperture);
    // Angle between Earth and Moon as seen at
    // apex_of_moon_locus_at_penumbral_contact.
    auto const earth_moon_angle =
        ArcCos(InnerProduct(apex_of_moon_locus_at_penumbral_contact - q_earth,
                            apex_of_moon_locus_at_penumbral_contact - q_moon) /
               ((apex_of_moon_locus_at_penumbral_contact - q_moon).Norm() *
                (apex_of_moon_locus_at_penumbral_contact - q_earth).Norm()));
    // We are at the desired contact if the angle between Earth and Moon from
    // the apex of locus of the moon at that contact is the same value as the
    // half-aperture of the penumbra.
    EXPECT_THAT(AbsoluteError(penumbral_half_aperture, earth_moon_angle),
                AllOf(Lt(1.0 * Milli(Radian)), Gt(1.0 * Nano(Radian))))
        << NAMED(penumbral_half_aperture) << ", " << NAMED(earth_moon_angle)
        << ", " << NAMED(current_time);
  }

  SolarSystem<ICRFJ2000Equator> solar_system_1950_;
};

TEST_F(EclipseTest, Dummy) {
  // Dates are TDB Julian Day for 1950-04-02.
  auto P1 = JulianDate(2433374.25788409);  // 18:10:49 UT
  auto U1 = JulianDate(2433374.29850909);  // 19:09:19
  auto U2 = JulianDate(2433374.354979);    // 20:30:38
  auto U3 = JulianDate(2433374.37367113);  // 20:57:33
  auto U4 = JulianDate(2433374.43016419);  // 22:18:54
  auto P4 = JulianDate(2433374.47075446);  // 23:17:21

  Sign const U14 = Sign(1);
  Sign const U23 = Sign(-1);
  CheckLunarPenumbralEclipse(P1, U14);
  CheckLunarUmbralEclipse(U1, U14);
  CheckLunarUmbralEclipse(U2, U23);
  CheckLunarUmbralEclipse(U3, U23);
  CheckLunarUmbralEclipse(U4, U14);
  CheckLunarPenumbralEclipse(P4, U14);

  // Dates are TDB Julian Day for 1950-09-26.
  P1 = JulianDate(2433550.55712016);  // 01:21:43 UT
  U1 = JulianDate(2433550.60578913);  // 02:31:48
  U2 = JulianDate(2433550.66325441);  // 03:54:33
  U3 = JulianDate(2433550.69399515);  // 04:38:49
  U4 = JulianDate(2433550.75144885);  // 06:01:33
  P4 = JulianDate(2433550.800222);    // 07:11:47

  CheckLunarPenumbralEclipse(P1, U14);
  CheckLunarUmbralEclipse(U1, U14);
  CheckLunarUmbralEclipse(U2, U23);
  CheckLunarUmbralEclipse(U3, U23);
  CheckLunarUmbralEclipse(U4, U14);
  CheckLunarPenumbralEclipse(P4, U14);

  // Dates are TDB Julian Day for 1951-03-23.
  P1 = JulianDate(2433728.86842806);  // 08:50:50
  P4 = JulianDate(2433729.01725909);  // 12:24:19

  CheckLunarPenumbralEclipse(P1, U14);
  CheckLunarPenumbralEclipse(P4, U14);

  // Dates are TDB Julian Day for 1951-09-15.
  P1 = JulianDate(2433904.93736321);  // 10:29:16
  P4 = JulianDate(2433905.1002799);   // 14:23:52

  CheckLunarPenumbralEclipse(P1, U14);
  CheckLunarPenumbralEclipse(P4, U14);

  // Dates are TDB Julian Day for 1952-02-11 (or 10 for P1).
  P1 = JulianDate(2434053.42282623);  // P1 = 22:08:20 UT
  U1 = JulianDate(2434053.50334705);  // U1 = 00:04:17
  U4 = JulianDate(2434053.55203917);  // U4 = 01:14:24
  P4 = JulianDate(2434053.63249055);  // P4 = 03:10:15

  CheckLunarPenumbralEclipse(P1, U14);
  CheckLunarUmbralEclipse(U1, U14);
  CheckLunarUmbralEclipse(U4, U14);
  CheckLunarPenumbralEclipse(P4, U14);

  // Dates are TDB Julian Day for 1952-08-05.
  P1 = JulianDate(2434230.22830075);  // P1 = 17:28:13 UT
  U1 = JulianDate(2434230.27385631);  // U1 = 18:33:49
  U4 = JulianDate(2434230.37606695);  // U4 = 21:01:00
  P4 = JulianDate(2434230.42161093);  // P4 = 22:06:35

  CheckLunarPenumbralEclipse(P1, U14);
  CheckLunarUmbralEclipse(U1, U14);
  CheckLunarUmbralEclipse(U4, U14);
  CheckLunarPenumbralEclipse(P4, U14);

  // Later on for additional accuracy: 2 * ArcTan((x_norm_y -
  // y_normx).Norm(),(x_norm_y + y_norm_x).Norm())
  // x_norm_y = x * y.Norm() and y_norm_x = y * x.Norm()

  // Future is not now: check 2048-01-01 Lunar eclipse.
  /*P1 = JulianDate(2469076.66235167);  // 03:52:39 UT
  U1 = JulianDate(2469076.71279148);  // 05:05:17
  U2 = JulianDate(2469076.76776833);  // 06:24:27
  U3 = JulianDate(2469076.80661092);  // 07:20:23
  U4 = JulianDate(2469076.86158778);  // 08:39:33
  P4 = JulianDate(2469076.91195815);  // 09:52:05

  CheckLunarPenumbralEclipse(P1, U14);
  CheckLunarUmbralEclipse(U1, U14);
  CheckLunarUmbralEclipse(U2, U23);
  CheckLunarUmbralEclipse(U3, U23);
  CheckLunarUmbralEclipse(U4, U14);
  CheckLunarPenumbralEclipse(P4, U14); */
}

}  // namespace physics
}  // namespace principia
<|endoftext|>


<commit_before>/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:

/*
COPYING CONDITIONS NOTICE:

  This program is free software; you can redistribute it and/or modify
  it under the terms of version 2 of the GNU General Public License as
  published by the Free Software Foundation, and provided that the
  following conditions are met:

      * Redistributions of source code must retain this COPYING
        CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
        DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
        PATENT MARKING NOTICE (below), and the PATENT RIGHTS
        GRANT (below).

      * Redistributions in binary form must reproduce this COPYING
        CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
        DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
        PATENT MARKING NOTICE (below), and the PATENT RIGHTS
        GRANT (below) in the documentation and/or other materials
        provided with the distribution.

  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.

COPYRIGHT NOTICE:

  TokuDB, Tokutek Fractal Tree Indexing Library.
  Copyright (C) 2007-2013 Tokutek, Inc.

DISCLAIMER:

  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.

UNIVERSITY PATENT NOTICE:

  The technology is licensed by the Massachusetts Institute of
  Technology, Rutgers State University of New Jersey, and the Research
  Foundation of State University of New York at Stony Brook under
  United States of America Serial No. 11/760379 and to the patents
  and/or patent applications resulting from it.

PATENT MARKING NOTICE:

  This software is covered by US Patent No. 8,185,551.
  This software is covered by US Patent No. 8,489,638.

PATENT RIGHTS GRANT:

  "THIS IMPLEMENTATION" means the copyrightable works distributed by
  Tokutek as part of the Fractal Tree project.

  "PATENT CLAIMS" means the claims of patents that are owned or
  licensable by Tokutek, both currently or in the future; and that in
  the absence of this license would be infringed by THIS
  IMPLEMENTATION or by using or running THIS IMPLEMENTATION.

  "PATENT CHALLENGE" shall mean a challenge to the validity,
  patentability, enforceability and/or non-infringement of any of the
  PATENT CLAIMS or otherwise opposing any of the PATENT CLAIMS.

  Tokutek hereby grants to you, for the term and geographical scope of
  the PATENT CLAIMS, a non-exclusive, no-charge, royalty-free,
  irrevocable (except as stated in this section) patent license to
  make, have made, use, offer to sell, sell, import, transfer, and
  otherwise run, modify, and propagate the contents of THIS
  IMPLEMENTATION, where such license applies only to the PATENT
  CLAIMS.  This grant does not include claims that would be infringed
  only as a consequence of further modifications of THIS
  IMPLEMENTATION.  If you or your agent or licensee institute or order
  or agree to the institution of patent litigation against any entity
  (including a cross-claim or counterclaim in a lawsuit) alleging that
  THIS IMPLEMENTATION constitutes direct or contributory patent
  infringement, or inducement of patent infringement, then any rights
  granted to you under this License shall terminate as of the date
  such litigation is filed.  If you or your agent or exclusive
  licensee institute or order or agree to the institution of a PATENT
  CHALLENGE, then Tokutek may terminate any rights granted to you
  under this License.
*/

#ident "Copyright (c) 2007-2013 Tokutek Inc.  All rights reserved."
#ident "The technology is licensed by the Massachusetts Institute of Technology, Rutgers State University of New Jersey, and the Research Foundation of State University of New York at Stony Brook under United States of America Serial No. 11/760379 and to the patents and/or patent applications resulting from it."

#include <pthread.h>

#include <toku_include/memory.h>

#include <util/scoped_malloc.h>

// The __thread storage class modifier isn't well supported on osx, but we
// aren't worried about the performance on osx, so we provide a
// pass-through implementation of scoped mallocs.
#ifdef __APPLE__

namespace toku {

    scoped_malloc::scoped_malloc(const size_t size)
        : m_size(size),
          m_local(false),
          m_buf(toku_xmalloc(size)) {}

    scoped_malloc::~scoped_malloc() {
        toku_free(m_buf);
    }

} // namespace toku

void toku_scoped_malloc_init(void) {}
void toku_scoped_malloc_destroy(void) {}

#else // __APPLE__

namespace toku {

    // see pthread_key handling at the bottom
    //
    // when we use gcc 4.8, we can use the 'thread_local' keyword and proper
    // c++ constructors/destructors instead of this pthread wizardy.
    static pthread_key_t tl_stack_destroy_pthread_key;

    class tl_stack {
        // 1MB
        static const size_t STACK_SIZE = 1 * 1024 * 1024;

    public:
        void init() {
            m_stack = reinterpret_cast<char *>(toku_xmalloc(STACK_SIZE));
            m_current_offset = 0;
            int r = pthread_setspecific(tl_stack_destroy_pthread_key, this);
            invariant_zero(r);
        }

        void destroy() {
            if (m_stack != NULL) {
                toku_free(m_stack);
                m_stack = NULL;
            }
        }

        // Allocate 'size' bytes and return a pointer to the first byte
        void *alloc(const size_t size) {
            if (m_stack == NULL) {
                init();
            }
            invariant(m_current_offset + size <= STACK_SIZE);
            void *mem = &m_stack[m_current_offset];
            m_current_offset += size;
            return mem;
        }

        // Give back a previously allocated region of 'size' bytes.
        void dealloc(const size_t size) {
            invariant(m_current_offset >= size);
            m_current_offset -= size;
        }

        // Get the current size of free-space in bytes.
        size_t get_free_space() const {
            invariant(m_current_offset <= STACK_SIZE);
            return STACK_SIZE - m_current_offset;
        }

    private:
        // Offset of the free region in the stack
        size_t m_current_offset;
        char *m_stack;
    };

    // Each thread has its own local stack.
    static __thread tl_stack local_stack;

    // Memory is allocated from thread-local storage if available, otherwise from malloc(1).
    scoped_malloc::scoped_malloc(const size_t size) :
        m_size(size),
        m_local(local_stack.get_free_space() >= m_size),
        m_buf(m_local ? local_stack.alloc(m_size) : toku_xmalloc(m_size)) {
    }

    scoped_malloc::~scoped_malloc() {
        if (m_local) {
            local_stack.dealloc(m_size);
        } else {
            toku_free(m_buf);
        }
    }

} // namespace toku

// pthread key handling:
// - there is a process-wide pthread key that is associated with the destructor for a tl_stack
// - on process construction, we initialize the key; on destruction, we clean it up.
// - when a thread first uses its tl_stack, it calls pthread_setspecific(&destroy_key, "some key"),
//   associating the destroy key with the tl_stack_destroy destructor
// - when a thread terminates, it calls the associated destructor; tl_stack_destroy.

static void tl_stack_destroy(void *key) {
    invariant_notnull(key);
    toku::tl_stack *st = reinterpret_cast<toku::tl_stack *>(key);
    st->destroy();
}

void toku_scoped_malloc_init(void) {
    int r = pthread_key_create(&toku::tl_stack_destroy_pthread_key, tl_stack_destroy);
    invariant_zero(r);
}

void toku_scoped_malloc_destroy(void) {
    // We're deregistering the destructor key here. When this thread exits,
    // the tl_stack destructor won't get called, so we need to do that first.
    tl_stack_destroy(&toku::local_stack);
    int r = pthread_key_delete(toku::tl_stack_destroy_pthread_key);
    invariant_zero(r);
}

#endif // !__APPLE__
<commit_msg>fixes #171 maintain a global map of registered tl_stack objects that we can iterate over and clean up, which prevents a memory leak when the fractal tree shared library unloads before all thread-local destructors run<commit_after>/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
// vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:

/*
COPYING CONDITIONS NOTICE:

  This program is free software; you can redistribute it and/or modify
  it under the terms of version 2 of the GNU General Public License as
  published by the Free Software Foundation, and provided that the
  following conditions are met:

      * Redistributions of source code must retain this COPYING
        CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
        DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
        PATENT MARKING NOTICE (below), and the PATENT RIGHTS
        GRANT (below).

      * Redistributions in binary form must reproduce this COPYING
        CONDITIONS NOTICE, the COPYRIGHT NOTICE (below), the
        DISCLAIMER (below), the UNIVERSITY PATENT NOTICE (below), the
        PATENT MARKING NOTICE (below), and the PATENT RIGHTS
        GRANT (below) in the documentation and/or other materials
        provided with the distribution.

  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.

COPYRIGHT NOTICE:

  TokuDB, Tokutek Fractal Tree Indexing Library.
  Copyright (C) 2007-2013 Tokutek, Inc.

DISCLAIMER:

  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.

UNIVERSITY PATENT NOTICE:

  The technology is licensed by the Massachusetts Institute of
  Technology, Rutgers State University of New Jersey, and the Research
  Foundation of State University of New York at Stony Brook under
  United States of America Serial No. 11/760379 and to the patents
  and/or patent applications resulting from it.

PATENT MARKING NOTICE:

  This software is covered by US Patent No. 8,185,551.
  This software is covered by US Patent No. 8,489,638.

PATENT RIGHTS GRANT:

  "THIS IMPLEMENTATION" means the copyrightable works distributed by
  Tokutek as part of the Fractal Tree project.

  "PATENT CLAIMS" means the claims of patents that are owned or
  licensable by Tokutek, both currently or in the future; and that in
  the absence of this license would be infringed by THIS
  IMPLEMENTATION or by using or running THIS IMPLEMENTATION.

  "PATENT CHALLENGE" shall mean a challenge to the validity,
  patentability, enforceability and/or non-infringement of any of the
  PATENT CLAIMS or otherwise opposing any of the PATENT CLAIMS.

  Tokutek hereby grants to you, for the term and geographical scope of
  the PATENT CLAIMS, a non-exclusive, no-charge, royalty-free,
  irrevocable (except as stated in this section) patent license to
  make, have made, use, offer to sell, sell, import, transfer, and
  otherwise run, modify, and propagate the contents of THIS
  IMPLEMENTATION, where such license applies only to the PATENT
  CLAIMS.  This grant does not include claims that would be infringed
  only as a consequence of further modifications of THIS
  IMPLEMENTATION.  If you or your agent or licensee institute or order
  or agree to the institution of patent litigation against any entity
  (including a cross-claim or counterclaim in a lawsuit) alleging that
  THIS IMPLEMENTATION constitutes direct or contributory patent
  infringement, or inducement of patent infringement, then any rights
  granted to you under this License shall terminate as of the date
  such litigation is filed.  If you or your agent or exclusive
  licensee institute or order or agree to the institution of a PATENT
  CHALLENGE, then Tokutek may terminate any rights granted to you
  under this License.
*/

#ident "Copyright (c) 2007-2013 Tokutek Inc.  All rights reserved."
#ident "The technology is licensed by the Massachusetts Institute of Technology, Rutgers State University of New Jersey, and the Research Foundation of State University of New York at Stony Brook under United States of America Serial No. 11/760379 and to the patents and/or patent applications resulting from it."

#include <set>
#include <pthread.h>

#include <toku_include/memory.h>
#include <portability/toku_pthread.h>

#include <util/scoped_malloc.h>

// The __thread storage class modifier isn't well supported on osx, but we
// aren't worried about the performance on osx, so we provide a
// pass-through implementation of scoped mallocs.
#ifdef __APPLE__

namespace toku {

    scoped_malloc::scoped_malloc(const size_t size)
        : m_size(size),
          m_local(false),
          m_buf(toku_xmalloc(size)) {}

    scoped_malloc::~scoped_malloc() {
        toku_free(m_buf);
    }

} // namespace toku

void toku_scoped_malloc_init(void) {}
void toku_scoped_malloc_destroy(void) {}

#else // __APPLE__

namespace toku {

    // see pthread_key handling at the bottom
    //
    // when we use gcc 4.8, we can use the 'thread_local' keyword and proper c++
    // constructors/destructors instead of this pthread / global set wizardy.
    static pthread_key_t tl_stack_destroy_pthread_key;
    class tl_stack;
    std::set<tl_stack *> *global_stack_set;
    toku_mutex_t global_stack_set_mutex = TOKU_MUTEX_INITIALIZER;

    class tl_stack {
        // 1MB
        static const size_t STACK_SIZE = 1 * 1024 * 1024;

    public:
        void init() {
            m_stack = reinterpret_cast<char *>(toku_xmalloc(STACK_SIZE));
            m_current_offset = 0;
            int r = pthread_setspecific(tl_stack_destroy_pthread_key, this);
            invariant_zero(r);
        }

        void destroy() {
            if (m_stack != NULL) {
                toku_free(m_stack);
                m_stack = NULL;
            }
        }

        // initialize a tl_stack and insert it into the global map
        static void init_and_register(tl_stack *st) {
            st->init();
            invariant_notnull(global_stack_set);

            toku_mutex_lock(&global_stack_set_mutex);
            std::pair<std::set<tl_stack *>::iterator, bool> p = global_stack_set->insert(st);
            invariant(p.second);
            toku_mutex_unlock(&global_stack_set_mutex);
        }

        // destruct a tl_stack and remove it from the global map
        // passed in as void * to match the generic pthread destructor API
        static void destroy_and_deregister(void *key) {
            invariant_notnull(key);
            tl_stack *st = reinterpret_cast<tl_stack *>(key);
            st->destroy();

            toku_mutex_lock(&global_stack_set_mutex);
            invariant_notnull(global_stack_set);
            size_t n = global_stack_set->erase(st);
            invariant(n == 1);
            toku_mutex_unlock(&global_stack_set_mutex);
        }

        // Allocate 'size' bytes and return a pointer to the first byte
        void *alloc(const size_t size) {
            if (m_stack == NULL) {
                init_and_register(this);
            }
            invariant(m_current_offset + size <= STACK_SIZE);
            void *mem = &m_stack[m_current_offset];
            m_current_offset += size;
            return mem;
        }

        // Give back a previously allocated region of 'size' bytes.
        void dealloc(const size_t size) {
            invariant(m_current_offset >= size);
            m_current_offset -= size;
        }

        // Get the current size of free-space in bytes.
        size_t get_free_space() const {
            invariant(m_current_offset <= STACK_SIZE);
            return STACK_SIZE - m_current_offset;
        }

    private:
        // Offset of the free region in the stack
        size_t m_current_offset;
        char *m_stack;
    };

    // Each thread has its own local stack.
    static __thread tl_stack local_stack;

    // Memory is allocated from thread-local storage if available, otherwise from malloc(1).
    scoped_malloc::scoped_malloc(const size_t size) :
        m_size(size),
        m_local(local_stack.get_free_space() >= m_size),
        m_buf(m_local ? local_stack.alloc(m_size) : toku_xmalloc(m_size)) {
    }

    scoped_malloc::~scoped_malloc() {
        if (m_local) {
            local_stack.dealloc(m_size);
        } else {
            toku_free(m_buf);
        }
    }

} // namespace toku

// pthread key handling:
// - there is a process-wide pthread key that is associated with the destructor for a tl_stack
// - on process construction, we initialize the key; on destruction, we clean it up.
// - when a thread first uses its tl_stack, it calls pthread_setspecific(&destroy_key, "some key"),
//   associating the destroy key with the tl_stack_destroy_and_deregister destructor
// - when a thread terminates, it calls the associated destructor; tl_stack_destroy_and_deregister.

void toku_scoped_malloc_init(void) {
    toku_mutex_lock(&toku::global_stack_set_mutex);
    invariant_null(toku::global_stack_set);
    toku::global_stack_set = new std::set<toku::tl_stack *>();
    toku_mutex_unlock(&toku::global_stack_set_mutex);

    int r = pthread_key_create(&toku::tl_stack_destroy_pthread_key,
                               toku::tl_stack::destroy_and_deregister);
    invariant_zero(r);
}

void toku_scoped_malloc_destroy(void) {
    toku_mutex_lock(&toku::global_stack_set_mutex);
    invariant_notnull(toku::global_stack_set);
    // Destroy any tl_stacks that were registered as thread locals but did not
    // get a chance to clean up using the pthread key destructor (because this code
    // is now running before those threads fully shutdown)
    for (std::set<toku::tl_stack *>::iterator i = toku::global_stack_set->begin();
         i != toku::global_stack_set->end(); i++) {
        (*i)->destroy();
    }
    delete toku::global_stack_set;
    toku_mutex_unlock(&toku::global_stack_set_mutex);

    // We're deregistering the destructor key here. When this thread exits,
    // the tl_stack destructor won't get called, so we need to do that first.
    int r = pthread_key_delete(toku::tl_stack_destroy_pthread_key);
    invariant_zero(r);
}

#endif // !__APPLE__
<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkSplitColumnComponents.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkSplitColumnComponents.h"

#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkAbstractArray.h"
#include "vtkTable.h"

#include "vtksys/ios/sstream"

vtkCxxRevisionMacro(vtkSplitColumnComponents, "1.2");
vtkStandardNewMacro(vtkSplitColumnComponents);
//---------------------------------------------------------------------------
vtkSplitColumnComponents::vtkSplitColumnComponents()
{
  this->SetNumberOfInputPorts(1);
  this->SetNumberOfOutputPorts(1);
}

//---------------------------------------------------------------------------
vtkSplitColumnComponents::~vtkSplitColumnComponents()
{
}

//---------------------------------------------------------------------------
// Templated function in an anonymous namespace to copy the data from the
// specified component in one column to a single component column
namespace {

template<typename T>
void CopyArrayData(T* source, T* destination, int components, int c,
                   unsigned int length)
{
  for (unsigned int i = 0; i < length; ++i)
    {
    destination[i] = source[i*components + c];
    }
}

} // End of anonymous namespace

//---------------------------------------------------------------------------
int vtkSplitColumnComponents::RequestData(
  vtkInformation*,
  vtkInformationVector** inputVector,
  vtkInformationVector* outputVector)
{
  // Get input tables
  vtkInformation* table1Info = inputVector[0]->GetInformationObject(0);
  vtkTable* table = vtkTable::SafeDownCast(
    table1Info->Get(vtkDataObject::DATA_OBJECT()));

  // Get output table
  vtkInformation* outInfo = outputVector->GetInformationObject(0);
  vtkTable* output = vtkTable::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  // Add columns from table, split multiple component columns as necessary
  for (int i = 0; i < table->GetNumberOfColumns(); ++i)
    {
    vtkAbstractArray* col = table->GetColumn(i);
    char* name = col->GetName();
    int components = col->GetNumberOfComponents();
    if (components == 1)
      {
      output->AddColumn(col);
      }
    else if (components > 1)
      {
      // Split the multicomponent column up into individual columns
      int colSize = col->GetNumberOfTuples();
      for (int j = 0; j < components; ++j)
        {
        vtksys_ios::ostringstream ostr;
        ostr << name << " (" << j << ")";
        vtkAbstractArray* newCol = vtkAbstractArray::CreateArray(col->GetDataType());
        newCol->SetNumberOfTuples(col->GetNumberOfTuples());
        newCol->SetName(ostr.str().c_str());
        newCol->SetNumberOfTuples(colSize);
        // Now copy the components into their new columns
        switch(col->GetDataType())
          {
          vtkTemplateMacro(
              CopyArrayData(static_cast<VTK_TT*>(col->GetVoidPointer(0)),
                            static_cast<VTK_TT*>(newCol->GetVoidPointer(0)),
                            components, j, colSize));
          }

        output->AddColumn(newCol);
        newCol->Delete();
        }
      }
    }

  return 1;
}

//---------------------------------------------------------------------------
void vtkSplitColumnComponents::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}
<commit_msg>ENH: Now using vtkExtraExtendedTemplateMacro!!!<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkSplitColumnComponents.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkSplitColumnComponents.h"

#include "vtkInformation.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkAbstractArray.h"
#include "vtkTable.h"

#include "vtksys/ios/sstream"

vtkCxxRevisionMacro(vtkSplitColumnComponents, "1.3");
vtkStandardNewMacro(vtkSplitColumnComponents);
//---------------------------------------------------------------------------
vtkSplitColumnComponents::vtkSplitColumnComponents()
{
  this->SetNumberOfInputPorts(1);
  this->SetNumberOfOutputPorts(1);
}

//---------------------------------------------------------------------------
vtkSplitColumnComponents::~vtkSplitColumnComponents()
{
}

//---------------------------------------------------------------------------
// Templated function in an anonymous namespace to copy the data from the
// specified component in one column to a single component column
namespace {

template<typename T>
void CopyArrayData(T* source, T* destination, int components, int c,
                   unsigned int length)
{
  for (unsigned int i = 0; i < length; ++i)
    {
    destination[i] = source[i*components + c];
    }
}

} // End of anonymous namespace

//---------------------------------------------------------------------------
int vtkSplitColumnComponents::RequestData(
  vtkInformation*,
  vtkInformationVector** inputVector,
  vtkInformationVector* outputVector)
{
  // Get input tables
  vtkInformation* table1Info = inputVector[0]->GetInformationObject(0);
  vtkTable* table = vtkTable::SafeDownCast(
    table1Info->Get(vtkDataObject::DATA_OBJECT()));

  // Get output table
  vtkInformation* outInfo = outputVector->GetInformationObject(0);
  vtkTable* output = vtkTable::SafeDownCast(
    outInfo->Get(vtkDataObject::DATA_OBJECT()));

  // Add columns from table, split multiple component columns as necessary
  for (int i = 0; i < table->GetNumberOfColumns(); ++i)
    {
    vtkAbstractArray* col = table->GetColumn(i);
    char* name = col->GetName();
    int components = col->GetNumberOfComponents();
    if (components == 1)
      {
      output->AddColumn(col);
      }
    else if (components > 1)
      {
      // Split the multicomponent column up into individual columns
      int colSize = col->GetNumberOfTuples();
      for (int j = 0; j < components; ++j)
        {
        vtksys_ios::ostringstream ostr;
        ostr << name << " (" << j << ")";
        vtkAbstractArray* newCol = vtkAbstractArray::CreateArray(col->GetDataType());
        newCol->SetNumberOfTuples(col->GetNumberOfTuples());
        newCol->SetName(ostr.str().c_str());
        newCol->SetNumberOfTuples(colSize);
        // Now copy the components into their new columns
        switch(col->GetDataType())
          {
          vtkExtraExtendedTemplateMacro(
              CopyArrayData(static_cast<VTK_TT*>(col->GetVoidPointer(0)),
                            static_cast<VTK_TT*>(newCol->GetVoidPointer(0)),
                            components, j, colSize));
          }

        output->AddColumn(newCol);
        newCol->Delete();
        }
      }
    }

  return 1;
}

//---------------------------------------------------------------------------
void vtkSplitColumnComponents::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}
<|endoftext|>


<commit_before>#pragma once

#include "feature_merger.hpp"

#include "../indexer/scales.hpp"

#include "../defines.hpp"

/// Process FeatureBuilder1 for world map. Main functions:
/// - check for visibility in world map
/// - merge linear features
template <class FeatureOutT>
class WorldMapGenerator
{
  class EmitterImpl : public FeatureEmitterIFace
  {
    FeatureOutT m_output;

  public:
    template <class TInfo>
    explicit EmitterImpl(TInfo const & info)
      : m_output(info.m_datFilePrefix + WORLD_FILE_NAME + info.m_datFileSuffix)
    {
    }

    /// This function is called after merging linear features.
    virtual void operator() (FeatureBuilder1 const & fb)
    {
      // do additional check for suitable size of feature
      if (NeedPushToWorld(fb) && scales::IsGoodForLevel(scales::GetUpperWorldScale(), fb.GetLimitRect()))
        PushSure(fb);
    }

    bool NeedPushToWorld(FeatureBuilder1 const & fb) const
    {
      // GetMinFeatureDrawScale also checks suitable size for AREA features
      return (scales::GetUpperWorldScale() >= fb.GetMinFeatureDrawScale());
    }

    void PushSure(FeatureBuilder1 const & fb) { m_output(fb); }
  };

  EmitterImpl m_worldBucket;
  FeatureTypesProcessor m_typesCorrector;
  FeatureMergeProcessor m_merger;

public:
  template <class TInfo>
  explicit WorldMapGenerator(TInfo const & info)
    : m_worldBucket(info),
      m_merger(POINT_COORD_BITS - (scales::GetUpperScale() - scales::GetUpperWorldScale()) / 2)
  {
    // Do not strip last types for given tags,
    // for example, do not cut 'admin_level' in  'boundary-administrative-XXX'.
    char const * arr1[][3] = {
      { "boundary", "administrative", "2" },
      { "boundary", "administrative", "3" },
      { "boundary", "administrative", "4" }
    };

    for (size_t i = 0; i < ARRAY_SIZE(arr1); ++i)
      m_typesCorrector.SetDontNormalizeType(arr1[i]);

    char const * arr2[]  = { "boundary", "administrative", "4", "state" };
    m_typesCorrector.SetDontNormalizeType(arr2);

    /// @todo It's not obvious to integrate link->way conversion.
    /// Review it in future.
    /*
    char const * arr3[][2]  = {
      { "highway", "motorway_link" },
      { "highway", "primary_link" },
      { "highway", "secondary_link" },
      { "highway", "trunk_link" }
    };
    char const * arr4[][2]  = {
      { "highway", "motorway" },
      { "highway", "primary" },
      { "highway", "secondary" },
      { "highway", "trunk" }
    };
    STATIS_ASSERT(ARRAY_SIZE(arr3) == ARRAY_SIZE(arr4));

    for (size_t i = 0; i < ARRAY_SIZE(arr3); ++i)
      m_typesCorrector.SetMappingTypes(arr3[i], arr4[i]);
    */
  }

  void operator()(FeatureBuilder1 fb)
  {
    if (m_worldBucket.NeedPushToWorld(fb))
    {
      if (fb.GetGeomType() == feature::GEOM_LINE)
      {
        MergedFeatureBuilder1 * p = m_typesCorrector(fb);
        if (p)
          m_merger(p);
      }
      else
      {
        if (feature::PreprocessForWorldMap(fb));
          m_worldBucket.PushSure(fb);
      }
    }
  }

  void DoMerge()
  {
    m_merger.DoMerge(m_worldBucket);
  }
};
<commit_msg>[generator] Fix typo.<commit_after>#pragma once

#include "feature_merger.hpp"

#include "../indexer/scales.hpp"

#include "../defines.hpp"

/// Process FeatureBuilder1 for world map. Main functions:
/// - check for visibility in world map
/// - merge linear features
template <class FeatureOutT>
class WorldMapGenerator
{
  class EmitterImpl : public FeatureEmitterIFace
  {
    FeatureOutT m_output;

  public:
    template <class TInfo>
    explicit EmitterImpl(TInfo const & info)
      : m_output(info.m_datFilePrefix + WORLD_FILE_NAME + info.m_datFileSuffix)
    {
    }

    /// This function is called after merging linear features.
    virtual void operator() (FeatureBuilder1 const & fb)
    {
      // do additional check for suitable size of feature
      if (NeedPushToWorld(fb) && scales::IsGoodForLevel(scales::GetUpperWorldScale(), fb.GetLimitRect()))
        PushSure(fb);
    }

    bool NeedPushToWorld(FeatureBuilder1 const & fb) const
    {
      // GetMinFeatureDrawScale also checks suitable size for AREA features
      return (scales::GetUpperWorldScale() >= fb.GetMinFeatureDrawScale());
    }

    void PushSure(FeatureBuilder1 const & fb) { m_output(fb); }
  };

  EmitterImpl m_worldBucket;
  FeatureTypesProcessor m_typesCorrector;
  FeatureMergeProcessor m_merger;

public:
  template <class TInfo>
  explicit WorldMapGenerator(TInfo const & info)
    : m_worldBucket(info),
      m_merger(POINT_COORD_BITS - (scales::GetUpperScale() - scales::GetUpperWorldScale()) / 2)
  {
    // Do not strip last types for given tags,
    // for example, do not cut 'admin_level' in  'boundary-administrative-XXX'.
    char const * arr1[][3] = {
      { "boundary", "administrative", "2" },
      { "boundary", "administrative", "3" },
      { "boundary", "administrative", "4" }
    };

    for (size_t i = 0; i < ARRAY_SIZE(arr1); ++i)
      m_typesCorrector.SetDontNormalizeType(arr1[i]);

    char const * arr2[]  = { "boundary", "administrative", "4", "state" };
    m_typesCorrector.SetDontNormalizeType(arr2);

    /// @todo It's not obvious to integrate link->way conversion.
    /// Review it in future.
    /*
    char const * arr3[][2]  = {
      { "highway", "motorway_link" },
      { "highway", "primary_link" },
      { "highway", "secondary_link" },
      { "highway", "trunk_link" }
    };
    char const * arr4[][2]  = {
      { "highway", "motorway" },
      { "highway", "primary" },
      { "highway", "secondary" },
      { "highway", "trunk" }
    };
    STATIS_ASSERT(ARRAY_SIZE(arr3) == ARRAY_SIZE(arr4));

    for (size_t i = 0; i < ARRAY_SIZE(arr3); ++i)
      m_typesCorrector.SetMappingTypes(arr3[i], arr4[i]);
    */
  }

  void operator()(FeatureBuilder1 fb)
  {
    if (m_worldBucket.NeedPushToWorld(fb))
    {
      if (fb.GetGeomType() == feature::GEOM_LINE)
      {
        MergedFeatureBuilder1 * p = m_typesCorrector(fb);
        if (p)
          m_merger(p);
      }
      else
      {
        if (feature::PreprocessForWorldMap(fb))
          m_worldBucket.PushSure(fb);
      }
    }
  }

  void DoMerge()
  {
    m_merger.DoMerge(m_worldBucket);
  }
};
<|endoftext|>


<commit_before>//  Copyright (c) 2013, Facebook, Inc.  All rights reserved.
//  This source code is licensed under the BSD-style license found in the
//  LICENSE file in the root directory of this source tree. An additional grant
//  of patent rights can be found in the PATENTS file in the same directory.
//

#include "rocksdb/sst_dump_tool.h"

#include <map>
#include <string>
#include <vector>
#include <inttypes.h>

#include "db/dbformat.h"
#include "db/memtable.h"
#include "db/write_batch_internal.h"
#include "rocksdb/db.h"
#include "rocksdb/env.h"
#include "rocksdb/immutable_options.h"
#include "rocksdb/iterator.h"
#include "rocksdb/slice_transform.h"
#include "rocksdb/status.h"
#include "rocksdb/table.h"
#include "rocksdb/table_properties.h"
#include "table/block.h"
#include "table/block_based_table_factory.h"
#include "table/block_builder.h"
#include "table/format.h"
#include "table/meta_blocks.h"
#include "table/plain_table_factory.h"
#include "util/ldb_cmd.h"
#include "util/random.h"
#include "util/testharness.h"
#include "util/testutil.h"

namespace rocksdb {

class SstFileReader {
 public:
  explicit SstFileReader(const std::string& file_name,
                         bool verify_checksum,
                         bool output_hex);

  Status ReadSequential(bool print_kv,
                        uint64_t read_num,
                        bool has_from,
                        const std::string& from_key,
                        bool has_to,
                        const std::string& to_key);

  Status ReadTableProperties(
      std::shared_ptr<const TableProperties>* table_properties);
  uint64_t GetReadNumber() { return read_num_; }
  TableProperties* GetInitTableProperties() { return table_properties_.get(); }

 private:
  Status NewTableReader(const std::string& file_path);
  Status ReadTableProperties(uint64_t table_magic_number,
                             RandomAccessFile* file, uint64_t file_size);
  Status SetTableOptionsByMagicNumber(uint64_t table_magic_number);
  Status SetOldTableOptions();

  std::string file_name_;
  uint64_t read_num_;
  bool verify_checksum_;
  bool output_hex_;
  EnvOptions soptions_;

  Status init_result_;
  unique_ptr<TableReader> table_reader_;
  unique_ptr<RandomAccessFile> file_;
  // options_ and internal_comparator_ will also be used in
  // ReadSequential internally (specifically, seek-related operations)
  Options options_;
  const ImmutableCFOptions ioptions_;
  InternalKeyComparator internal_comparator_;
  unique_ptr<TableProperties> table_properties_;
};

SstFileReader::SstFileReader(const std::string& file_path,
                             bool verify_checksum,
                             bool output_hex)
    :file_name_(file_path), read_num_(0), verify_checksum_(verify_checksum),
    output_hex_(output_hex), ioptions_(options_),
    internal_comparator_(BytewiseComparator()) {
  fprintf(stdout, "Process %s\n", file_path.c_str());

  init_result_ = NewTableReader(file_name_);
}

extern uint64_t kBlockBasedTableMagicNumber;
extern uint64_t kLegacyBlockBasedTableMagicNumber;
extern uint64_t kPlainTableMagicNumber;
extern uint64_t kLegacyPlainTableMagicNumber;

Status SstFileReader::NewTableReader(const std::string& file_path) {
  uint64_t magic_number;

  // read table magic number
  Footer footer;

  unique_ptr<RandomAccessFile> file;
  uint64_t file_size;
  Status s = options_.env->NewRandomAccessFile(file_path, &file_, soptions_);
  if (s.ok()) {
    s = options_.env->GetFileSize(file_path, &file_size);
  }
  if (s.ok()) {
    s = ReadFooterFromFile(file_.get(), file_size, &footer);
  }
  if (s.ok()) {
    magic_number = footer.table_magic_number();
  }

  if (s.ok()) {
    if (magic_number == kPlainTableMagicNumber ||
        magic_number == kLegacyPlainTableMagicNumber) {
      soptions_.use_mmap_reads = true;
      options_.env->NewRandomAccessFile(file_path, &file_, soptions_);
    }
    options_.comparator = &internal_comparator_;
    // For old sst format, ReadTableProperties might fail but file can be read
    if (ReadTableProperties(magic_number, file_.get(), file_size).ok()) {
      SetTableOptionsByMagicNumber(magic_number);
    } else {
      SetOldTableOptions();
    }
  }

  if (s.ok()) {
    s = options_.table_factory->NewTableReader(
        ioptions_, soptions_, internal_comparator_, std::move(file_), file_size,
        &table_reader_);
  }
  return s;
}

Status SstFileReader::ReadTableProperties(uint64_t table_magic_number,
                                          RandomAccessFile* file,
                                          uint64_t file_size) {
  TableProperties* table_properties = nullptr;
  Status s = rocksdb::ReadTableProperties(file, file_size, table_magic_number,
                                          options_.env, options_.info_log.get(),
                                          &table_properties);
  if (s.ok()) {
    table_properties_.reset(table_properties);
  } else {
    fprintf(stdout, "Not able to read table properties\n");
  }
  return s;
}

Status SstFileReader::SetTableOptionsByMagicNumber(
    uint64_t table_magic_number) {
  assert(table_properties_);
  if (table_magic_number == kBlockBasedTableMagicNumber ||
      table_magic_number == kLegacyBlockBasedTableMagicNumber) {
    options_.table_factory = std::make_shared<BlockBasedTableFactory>();
    fprintf(stdout, "Sst file format: block-based\n");
    auto& props = table_properties_->user_collected_properties;
    auto pos = props.find(BlockBasedTablePropertyNames::kIndexType);
    if (pos != props.end()) {
      auto index_type_on_file = static_cast<BlockBasedTableOptions::IndexType>(
          DecodeFixed32(pos->second.c_str()));
      if (index_type_on_file ==
          BlockBasedTableOptions::IndexType::kHashSearch) {
        options_.prefix_extractor.reset(NewNoopTransform());
      }
    }
  } else if (table_magic_number == kPlainTableMagicNumber ||
             table_magic_number == kLegacyPlainTableMagicNumber) {
    options_.allow_mmap_reads = true;

    PlainTableOptions plain_table_options;
    plain_table_options.user_key_len = kPlainTableVariableLength;
    plain_table_options.bloom_bits_per_key = 0;
    plain_table_options.hash_table_ratio = 0;
    plain_table_options.index_sparseness = 1;
    plain_table_options.huge_page_tlb_size = 0;
    plain_table_options.encoding_type = kPlain;
    plain_table_options.full_scan_mode = true;

    options_.table_factory.reset(NewPlainTableFactory(plain_table_options));
    fprintf(stdout, "Sst file format: plain table\n");
  } else {
    char error_msg_buffer[80];
    snprintf(error_msg_buffer, sizeof(error_msg_buffer) - 1,
             "Unsupported table magic number --- %lx",
             (long)table_magic_number);
    return Status::InvalidArgument(error_msg_buffer);
  }

  return Status::OK();
}

Status SstFileReader::SetOldTableOptions() {
  assert(table_properties_ == nullptr);
  options_.table_factory = std::make_shared<BlockBasedTableFactory>();
  fprintf(stdout, "Sst file format: block-based(old version)\n");

  return Status::OK();
}

Status SstFileReader::ReadSequential(bool print_kv,
                                     uint64_t read_num,
                                     bool has_from,
                                     const std::string& from_key,
                                     bool has_to,
                                     const std::string& to_key) {
  if (!table_reader_) {
    return init_result_;
  }

  Iterator* iter = table_reader_->NewIterator(ReadOptions(verify_checksum_,
                                                         false));
  uint64_t i = 0;
  if (has_from) {
    InternalKey ikey(from_key, kMaxSequenceNumber, kValueTypeForSeek);
    iter->Seek(ikey.Encode());
  } else {
    iter->SeekToFirst();
  }
  for (; iter->Valid(); iter->Next()) {
    Slice key = iter->key();
    Slice value = iter->value();
    ++i;
    if (read_num > 0 && i > read_num)
      break;

    ParsedInternalKey ikey;
    if (!ParseInternalKey(key, &ikey)) {
      std::cerr << "Internal Key ["
                << key.ToString(true /* in hex*/)
                << "] parse error!\n";
      continue;
    }

    // If end marker was specified, we stop before it
    if (has_to && BytewiseComparator()->Compare(ikey.user_key, to_key) >= 0) {
      break;
    }

    if (print_kv) {
      fprintf(stdout, "%s => %s\n",
          ikey.DebugString(output_hex_).c_str(),
          value.ToString(output_hex_).c_str());
    }
  }

  read_num_ += i;

  Status ret = iter->status();
  delete iter;
  return ret;
}

Status SstFileReader::ReadTableProperties(
    std::shared_ptr<const TableProperties>* table_properties) {
  if (!table_reader_) {
    return init_result_;
  }

  *table_properties = table_reader_->GetTableProperties();
  return init_result_;
}

namespace {

void print_help() {
  fprintf(stderr,
          "sst_dump [--command=check|scan|none] [--verify_checksum] "
          "--file=data_dir_OR_sst_file"
          " [--output_hex]"
          " [--input_key_hex]"
          " [--from=<user_key>]"
          " [--to=<user_key>]"
          " [--read_num=NUM]"
          " [--show_properties]\n");
}

string HexToString(const string& str) {
  string parsed;
  if (str[0] != '0' || str[1] != 'x') {
    fprintf(stderr, "Invalid hex input %s.  Must start with 0x\n",
            str.c_str());
    throw "Invalid hex input";
  }

  for (unsigned int i = 2; i < str.length();) {
    int c;
    sscanf(str.c_str() + i, "%2X", &c);
    parsed.push_back(c);
    i += 2;
  }
  return parsed;
}

}  // namespace

void SSTDumpTool::Run(int argc, char** argv) {
  const char* dir_or_file = nullptr;
  uint64_t read_num = -1;
  std::string command;

  char junk;
  uint64_t n;
  bool verify_checksum = false;
  bool output_hex = false;
  bool input_key_hex = false;
  bool has_from = false;
  bool has_to = false;
  bool show_properties = false;
  std::string from_key;
  std::string to_key;
  for (int i = 1; i < argc; i++) {
    if (strncmp(argv[i], "--file=", 7) == 0) {
      dir_or_file = argv[i] + 7;
    } else if (strcmp(argv[i], "--output_hex") == 0) {
      output_hex = true;
    } else if (strcmp(argv[i], "--input_key_hex") == 0) {
      input_key_hex = true;
    } else if (sscanf(argv[i],
               "--read_num=%lu%c",
               (unsigned long*)&n, &junk) == 1) {
      read_num = n;
    } else if (strcmp(argv[i], "--verify_checksum") == 0) {
      verify_checksum = true;
    } else if (strncmp(argv[i], "--command=", 10) == 0) {
      command = argv[i] + 10;
    } else if (strncmp(argv[i], "--from=", 7) == 0) {
      from_key = argv[i] + 7;
      has_from = true;
    } else if (strncmp(argv[i], "--to=", 5) == 0) {
      to_key = argv[i] + 5;
      has_to = true;
    } else if (strcmp(argv[i], "--show_properties") == 0) {
      show_properties = true;
    } else {
      print_help();
      exit(1);
    }
  }

  if (input_key_hex) {
    if (has_from) {
      from_key = HexToString(from_key);
    }
    if (has_to) {
      to_key = HexToString(to_key);
    }
  }

  if (dir_or_file == nullptr) {
    print_help();
    exit(1);
  }

  std::vector<std::string> filenames;
  rocksdb::Env* env = rocksdb::Env::Default();
  rocksdb::Status st = env->GetChildren(dir_or_file, &filenames);
  bool dir = true;
  if (!st.ok()) {
    filenames.clear();
    filenames.push_back(dir_or_file);
    dir = false;
  }

  fprintf(stdout, "from [%s] to [%s]\n",
      rocksdb::Slice(from_key).ToString(true).c_str(),
      rocksdb::Slice(to_key).ToString(true).c_str());

  uint64_t total_read = 0;
  for (size_t i = 0; i < filenames.size(); i++) {
    std::string filename = filenames.at(i);
    if (filename.length() <= 4 ||
        filename.rfind(".sst") != filename.length() - 4) {
      // ignore
      continue;
    }
    if (dir) {
      filename = std::string(dir_or_file) + "/" + filename;
    }
    rocksdb::SstFileReader reader(filename, verify_checksum,
                                  output_hex);
    // scan all files in give file path.
    if (command == "" || command == "scan" || command == "check") {
      st = reader.ReadSequential(command != "check",
                                 read_num > 0 ? (read_num - total_read) :
                                                read_num,
                                 has_from, from_key, has_to, to_key);
      if (!st.ok()) {
        fprintf(stderr, "%s: %s\n", filename.c_str(),
            st.ToString().c_str());
      }
      total_read += reader.GetReadNumber();
      if (read_num > 0 && total_read > read_num) {
        break;
      }
    }
    if (show_properties) {
      const rocksdb::TableProperties* table_properties;

      std::shared_ptr<const rocksdb::TableProperties>
          table_properties_from_reader;
      st = reader.ReadTableProperties(&table_properties_from_reader);
      if (!st.ok()) {
        fprintf(stderr, "%s: %s\n", filename.c_str(), st.ToString().c_str());
        fprintf(stderr, "Try to use initial table properties\n");
        table_properties = reader.GetInitTableProperties();
      } else {
        table_properties = table_properties_from_reader.get();
      }
      if (table_properties != nullptr) {
        fprintf(stdout,
                "Table Properties:\n"
                "------------------------------\n"
                "  %s",
                table_properties->ToString("\n  ", ": ").c_str());
        fprintf(stdout, "# deleted keys: %zd\n",
                rocksdb::GetDeletedKeys(
                    table_properties->user_collected_properties));
      }
    }
  }
}
}  // namespace rocksdb
<commit_msg>fix make static_lib error<commit_after>//  Copyright (c) 2013, Facebook, Inc.  All rights reserved.
//  This source code is licensed under the BSD-style license found in the
//  LICENSE file in the root directory of this source tree. An additional grant
//  of patent rights can be found in the PATENTS file in the same directory.
//

#include "rocksdb/sst_dump_tool.h"

#include <map>
#include <string>
#include <vector>
#include <inttypes.h>

#include "db/dbformat.h"
#include "db/memtable.h"
#include "db/write_batch_internal.h"
#include "rocksdb/db.h"
#include "rocksdb/env.h"
#include "rocksdb/immutable_options.h"
#include "rocksdb/iterator.h"
#include "rocksdb/slice_transform.h"
#include "rocksdb/status.h"
#include "rocksdb/table.h"
#include "rocksdb/table_properties.h"
#include "table/block.h"
#include "table/block_based_table_factory.h"
#include "table/block_builder.h"
#include "table/format.h"
#include "table/meta_blocks.h"
#include "table/plain_table_factory.h"
#include "util/ldb_cmd.h"
#include "util/random.h"
#include "util/testharness.h"
#include "util/testutil.h"

namespace rocksdb {

class SstFileReader {
 public:
  explicit SstFileReader(const std::string& file_name,
                         bool verify_checksum,
                         bool output_hex);

  Status ReadSequential(bool print_kv,
                        uint64_t read_num,
                        bool has_from,
                        const std::string& from_key,
                        bool has_to,
                        const std::string& to_key);

  Status ReadTableProperties(
      std::shared_ptr<const TableProperties>* table_properties);
  uint64_t GetReadNumber() { return read_num_; }
  TableProperties* GetInitTableProperties() { return table_properties_.get(); }

 private:
  Status NewTableReader(const std::string& file_path);
  Status ReadTableProperties(uint64_t table_magic_number,
                             RandomAccessFile* file, uint64_t file_size);
  Status SetTableOptionsByMagicNumber(uint64_t table_magic_number);
  Status SetOldTableOptions();

  std::string file_name_;
  uint64_t read_num_;
  bool verify_checksum_;
  bool output_hex_;
  EnvOptions soptions_;

  Status init_result_;
  unique_ptr<TableReader> table_reader_;
  unique_ptr<RandomAccessFile> file_;
  // options_ and internal_comparator_ will also be used in
  // ReadSequential internally (specifically, seek-related operations)
  Options options_;
  const ImmutableCFOptions ioptions_;
  InternalKeyComparator internal_comparator_;
  unique_ptr<TableProperties> table_properties_;
};

SstFileReader::SstFileReader(const std::string& file_path,
                             bool verify_checksum,
                             bool output_hex)
    :file_name_(file_path), read_num_(0), verify_checksum_(verify_checksum),
    output_hex_(output_hex), ioptions_(options_),
    internal_comparator_(BytewiseComparator()) {
  fprintf(stdout, "Process %s\n", file_path.c_str());

  init_result_ = NewTableReader(file_name_);
}

extern uint64_t kBlockBasedTableMagicNumber;
extern uint64_t kLegacyBlockBasedTableMagicNumber;
extern uint64_t kPlainTableMagicNumber;
extern uint64_t kLegacyPlainTableMagicNumber;

Status SstFileReader::NewTableReader(const std::string& file_path) {
  uint64_t magic_number;

  // read table magic number
  Footer footer;

  unique_ptr<RandomAccessFile> file;
  uint64_t file_size;
  Status s = options_.env->NewRandomAccessFile(file_path, &file_, soptions_);
  if (s.ok()) {
    s = options_.env->GetFileSize(file_path, &file_size);
  }
  if (s.ok()) {
    s = ReadFooterFromFile(file_.get(), file_size, &footer);
  }
  if (s.ok()) {
    magic_number = footer.table_magic_number();
  }

  if (s.ok()) {
    if (magic_number == kPlainTableMagicNumber ||
        magic_number == kLegacyPlainTableMagicNumber) {
      soptions_.use_mmap_reads = true;
      options_.env->NewRandomAccessFile(file_path, &file_, soptions_);
    }
    options_.comparator = &internal_comparator_;
    // For old sst format, ReadTableProperties might fail but file can be read
    if (ReadTableProperties(magic_number, file_.get(), file_size).ok()) {
      SetTableOptionsByMagicNumber(magic_number);
    } else {
      SetOldTableOptions();
    }
  }

  if (s.ok()) {
    s = options_.table_factory->NewTableReader(
        ioptions_, soptions_, internal_comparator_, std::move(file_), file_size,
        &table_reader_);
  }
  return s;
}

Status SstFileReader::ReadTableProperties(uint64_t table_magic_number,
                                          RandomAccessFile* file,
                                          uint64_t file_size) {
  TableProperties* table_properties = nullptr;
  Status s = rocksdb::ReadTableProperties(file, file_size, table_magic_number,
                                          options_.env, options_.info_log.get(),
                                          &table_properties);
  if (s.ok()) {
    table_properties_.reset(table_properties);
  } else {
    fprintf(stdout, "Not able to read table properties\n");
  }
  return s;
}

Status SstFileReader::SetTableOptionsByMagicNumber(
    uint64_t table_magic_number) {
  assert(table_properties_);
  if (table_magic_number == kBlockBasedTableMagicNumber ||
      table_magic_number == kLegacyBlockBasedTableMagicNumber) {
    options_.table_factory = std::make_shared<BlockBasedTableFactory>();
    fprintf(stdout, "Sst file format: block-based\n");
    auto& props = table_properties_->user_collected_properties;
    auto pos = props.find(BlockBasedTablePropertyNames::kIndexType);
    if (pos != props.end()) {
      auto index_type_on_file = static_cast<BlockBasedTableOptions::IndexType>(
          DecodeFixed32(pos->second.c_str()));
      if (index_type_on_file ==
          BlockBasedTableOptions::IndexType::kHashSearch) {
        options_.prefix_extractor.reset(NewNoopTransform());
      }
    }
  } else if (table_magic_number == kPlainTableMagicNumber ||
             table_magic_number == kLegacyPlainTableMagicNumber) {
    options_.allow_mmap_reads = true;

    PlainTableOptions plain_table_options;
    plain_table_options.user_key_len = kPlainTableVariableLength;
    plain_table_options.bloom_bits_per_key = 0;
    plain_table_options.hash_table_ratio = 0;
    plain_table_options.index_sparseness = 1;
    plain_table_options.huge_page_tlb_size = 0;
    plain_table_options.encoding_type = kPlain;
    plain_table_options.full_scan_mode = true;

    options_.table_factory.reset(NewPlainTableFactory(plain_table_options));
    fprintf(stdout, "Sst file format: plain table\n");
  } else {
    char error_msg_buffer[80];
    snprintf(error_msg_buffer, sizeof(error_msg_buffer) - 1,
             "Unsupported table magic number --- %lx",
             (long)table_magic_number);
    return Status::InvalidArgument(error_msg_buffer);
  }

  return Status::OK();
}

Status SstFileReader::SetOldTableOptions() {
  assert(table_properties_ == nullptr);
  options_.table_factory = std::make_shared<BlockBasedTableFactory>();
  fprintf(stdout, "Sst file format: block-based(old version)\n");

  return Status::OK();
}

Status SstFileReader::ReadSequential(bool print_kv,
                                     uint64_t read_num,
                                     bool has_from,
                                     const std::string& from_key,
                                     bool has_to,
                                     const std::string& to_key) {
  if (!table_reader_) {
    return init_result_;
  }

  Iterator* iter = table_reader_->NewIterator(ReadOptions(verify_checksum_,
                                                         false));
  uint64_t i = 0;
  if (has_from) {
    InternalKey ikey(from_key, kMaxSequenceNumber, kValueTypeForSeek);
    iter->Seek(ikey.Encode());
  } else {
    iter->SeekToFirst();
  }
  for (; iter->Valid(); iter->Next()) {
    Slice key = iter->key();
    Slice value = iter->value();
    ++i;
    if (read_num > 0 && i > read_num)
      break;

    ParsedInternalKey ikey;
    if (!ParseInternalKey(key, &ikey)) {
      std::cerr << "Internal Key ["
                << key.ToString(true /* in hex*/)
                << "] parse error!\n";
      continue;
    }

    // If end marker was specified, we stop before it
    if (has_to && BytewiseComparator()->Compare(ikey.user_key, to_key) >= 0) {
      break;
    }

    if (print_kv) {
      fprintf(stdout, "%s => %s\n",
          ikey.DebugString(output_hex_).c_str(),
          value.ToString(output_hex_).c_str());
    }
  }

  read_num_ += i;

  Status ret = iter->status();
  delete iter;
  return ret;
}

Status SstFileReader::ReadTableProperties(
    std::shared_ptr<const TableProperties>* table_properties) {
  if (!table_reader_) {
    return init_result_;
  }

  *table_properties = table_reader_->GetTableProperties();
  return init_result_;
}

namespace {

void print_help() {
  fprintf(stderr,
          "sst_dump [--command=check|scan|none] [--verify_checksum] "
          "--file=data_dir_OR_sst_file"
          " [--output_hex]"
          " [--input_key_hex]"
          " [--from=<user_key>]"
          " [--to=<user_key>]"
          " [--read_num=NUM]"
          " [--show_properties]\n");
}

string HexToString(const string& str) {
  string parsed;
  if (str[0] != '0' || str[1] != 'x') {
    fprintf(stderr, "Invalid hex input %s.  Must start with 0x\n",
            str.c_str());
    throw "Invalid hex input";
  }

  for (unsigned int i = 2; i < str.length();) {
    int c;
    sscanf(str.c_str() + i, "%2X", &c);
    parsed.push_back(c);
    i += 2;
  }
  return parsed;
}

}  // namespace

void SSTDumpTool::Run(int argc, char** argv) {
  const char* dir_or_file = nullptr;
  uint64_t read_num = -1;
  std::string command;

  char junk;
  uint64_t n;
  bool verify_checksum = false;
  bool output_hex = false;
  bool input_key_hex = false;
  bool has_from = false;
  bool has_to = false;
  bool show_properties = false;
  std::string from_key;
  std::string to_key;
  for (int i = 1; i < argc; i++) {
    if (strncmp(argv[i], "--file=", 7) == 0) {
      dir_or_file = argv[i] + 7;
    } else if (strcmp(argv[i], "--output_hex") == 0) {
      output_hex = true;
    } else if (strcmp(argv[i], "--input_key_hex") == 0) {
      input_key_hex = true;
    } else if (sscanf(argv[i],
               "--read_num=%lu%c",
               (unsigned long*)&n, &junk) == 1) {
      read_num = n;
    } else if (strcmp(argv[i], "--verify_checksum") == 0) {
      verify_checksum = true;
    } else if (strncmp(argv[i], "--command=", 10) == 0) {
      command = argv[i] + 10;
    } else if (strncmp(argv[i], "--from=", 7) == 0) {
      from_key = argv[i] + 7;
      has_from = true;
    } else if (strncmp(argv[i], "--to=", 5) == 0) {
      to_key = argv[i] + 5;
      has_to = true;
    } else if (strcmp(argv[i], "--show_properties") == 0) {
      show_properties = true;
    } else {
      print_help();
      exit(1);
    }
  }

  if (input_key_hex) {
    if (has_from) {
      from_key = HexToString(from_key);
    }
    if (has_to) {
      to_key = HexToString(to_key);
    }
  }

  if (dir_or_file == nullptr) {
    print_help();
    exit(1);
  }

  std::vector<std::string> filenames;
  rocksdb::Env* env = rocksdb::Env::Default();
  rocksdb::Status st = env->GetChildren(dir_or_file, &filenames);
  bool dir = true;
  if (!st.ok()) {
    filenames.clear();
    filenames.push_back(dir_or_file);
    dir = false;
  }

  fprintf(stdout, "from [%s] to [%s]\n",
      rocksdb::Slice(from_key).ToString(true).c_str(),
      rocksdb::Slice(to_key).ToString(true).c_str());

  uint64_t total_read = 0;
  for (size_t i = 0; i < filenames.size(); i++) {
    std::string filename = filenames.at(i);
    if (filename.length() <= 4 ||
        filename.rfind(".sst") != filename.length() - 4) {
      // ignore
      continue;
    }
    if (dir) {
      filename = std::string(dir_or_file) + "/" + filename;
    }
    rocksdb::SstFileReader reader(filename, verify_checksum,
                                  output_hex);
    // scan all files in give file path.
    if (command == "" || command == "scan" || command == "check") {
      st = reader.ReadSequential(command != "check",
                                 read_num > 0 ? (read_num - total_read) :
                                                read_num,
                                 has_from, from_key, has_to, to_key);
      if (!st.ok()) {
        fprintf(stderr, "%s: %s\n", filename.c_str(),
            st.ToString().c_str());
      }
      total_read += reader.GetReadNumber();
      if (read_num > 0 && total_read > read_num) {
        break;
      }
    }
    if (show_properties) {
      const rocksdb::TableProperties* table_properties;

      std::shared_ptr<const rocksdb::TableProperties>
          table_properties_from_reader;
      st = reader.ReadTableProperties(&table_properties_from_reader);
      if (!st.ok()) {
        fprintf(stderr, "%s: %s\n", filename.c_str(), st.ToString().c_str());
        fprintf(stderr, "Try to use initial table properties\n");
        table_properties = reader.GetInitTableProperties();
      } else {
        table_properties = table_properties_from_reader.get();
      }
      if (table_properties != nullptr) {
        fprintf(stdout,
                "Table Properties:\n"
                "------------------------------\n"
                "  %s",
                table_properties->ToString("\n  ", ": ").c_str());
        fprintf(stdout, "# deleted keys: %" PRIu64 "\n",
                rocksdb::GetDeletedKeys(
                    table_properties->user_collected_properties));
      }
    }
  }
}
}  // namespace rocksdb
<|endoftext|>