<commit_before>//     Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_TRAITS_HPP
#define TOML11_TRAITS_HPP

#include "from.hpp"
#include "into.hpp"

#include <chrono>
#include <forward_list>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>

#if __cplusplus >= 201703L
#if __has_include(<string_view>)
#include <string_view>
#endif // has_include(<string_view>)
#endif // cplusplus   >= C++17

namespace toml
{
template<typename C, template<typename ...> class T, template<typename ...> class A>
class basic_value;

namespace detail
{
// ---------------------------------------------------------------------------
// check whether type T is a kind of container/map class

struct has_iterator_impl
{
    template<typename T> static std::true_type  check(typename T::iterator*);
    template<typename T> static std::false_type check(...);
};
struct has_value_type_impl
{
    template<typename T> static std::true_type  check(typename T::value_type*);
    template<typename T> static std::false_type check(...);
};
struct has_key_type_impl
{
    template<typename T> static std::true_type  check(typename T::key_type*);
    template<typename T> static std::false_type check(...);
};
struct has_mapped_type_impl
{
    template<typename T> static std::true_type  check(typename T::mapped_type*);
    template<typename T> static std::false_type check(...);
};
struct has_reserve_method_impl
{
    template<typename T> static std::false_type check(...);
    template<typename T> static std::true_type  check(
        decltype(std::declval<T>().reserve(std::declval<std::size_t>()))*);
};
struct has_push_back_method_impl
{
    template<typename T> static std::false_type check(...);
    template<typename T> static std::true_type  check(
        decltype(std::declval<T>().push_back(std::declval<typename T::value_type>()))*);
};
struct is_comparable_impl
{
    template<typename T> static std::false_type check(...);
    template<typename T> static std::true_type  check(
        decltype(std::declval<T>() < std::declval<T>())*);
};

struct has_from_toml_method_impl
{
    template<typename T, typename C,
             template<typename ...> class Tb, template<typename ...> class A>
    static std::true_type  check(
        decltype(std::declval<T>().from_toml(
                std::declval<::toml::basic_value<C, Tb, A>>()))*);

    template<typename T, typename C,
             template<typename ...> class Tb, template<typename ...> class A>
    static std::false_type check(...);
};
struct has_into_toml_method_impl
{
    template<typename T>
    static std::true_type  check(decltype(std::declval<T>().into_toml())*);
    template<typename T>
    static std::false_type check(...);
};

struct has_specialized_from_impl
{
    template<typename T>
    static std::false_type check(...);
    template<typename T, std::size_t S = sizeof(::toml::from<T>)>
    static std::true_type check(::toml::from<T>*);
};
struct has_specialized_into_impl
{
    template<typename T>
    static std::false_type check(...);
    template<typename T, std::size_t S = sizeof(::toml::into<T>)>
    static std::true_type check(::toml::from<T>*);
};

/// Intel C++ compiler can not use decltype in parent class declaration, here
/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076
#ifdef __INTEL_COMPILER
#define decltype(...) std::enable_if<true, decltype(__VA_ARGS__)>::type
#endif

template<typename T>
struct has_iterator    : decltype(has_iterator_impl::check<T>(nullptr)){};
template<typename T>
struct has_value_type  : decltype(has_value_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_key_type    : decltype(has_key_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_mapped_type : decltype(has_mapped_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_reserve_method : decltype(has_reserve_method_impl::check<T>(nullptr)){};
template<typename T>
struct has_push_back_method : decltype(has_push_back_method_impl::check<T>(nullptr)){};
template<typename T>
struct is_comparable : decltype(is_comparable_impl::check<T>(nullptr)){};

template<typename T, typename C,
         template<typename ...> class Tb, template<typename ...> class A>
struct has_from_toml_method
: decltype(has_from_toml_method_impl::check<T, C, Tb, A>(nullptr)){};

template<typename T>
struct has_into_toml_method
: decltype(has_into_toml_method_impl::check<T>(nullptr)){};

template<typename T>
struct has_specialized_from : decltype(has_specialized_from_impl::check<T>(nullptr)){};
template<typename T>
struct has_specialized_into : decltype(has_specialized_into_impl::check<T>(nullptr)){};

#ifdef __INTEL_COMPILER
#undef decltype
#endif

// ---------------------------------------------------------------------------
// C++17 and/or/not

#if __cplusplus >= 201703L

using std::conjunction;
using std::disjunction;
using std::negation;

#else

template<typename ...> struct conjunction : std::true_type{};
template<typename T>   struct conjunction<T> : T{};
template<typename T, typename ... Ts>
struct conjunction<T, Ts...> :
    std::conditional<static_cast<bool>(T::value), conjunction<Ts...>, T>::type
{};

template<typename ...> struct disjunction : std::false_type{};
template<typename T>   struct disjunction<T> : T {};
template<typename T, typename ... Ts>
struct disjunction<T, Ts...> :
    std::conditional<static_cast<bool>(T::value), T, disjunction<Ts...>>::type
{};

template<typename T>
struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};

#endif

// ---------------------------------------------------------------------------
// type checkers

template<typename T> struct is_std_pair : std::false_type{};
template<typename T1, typename T2>
struct is_std_pair<std::pair<T1, T2>> : std::true_type{};

template<typename T> struct is_std_tuple : std::false_type{};
template<typename ... Ts>
struct is_std_tuple<std::tuple<Ts...>> : std::true_type{};

template<typename T> struct is_std_forward_list : std::false_type{};
template<typename T>
struct is_std_forward_list<std::forward_list<T>> : std::true_type{};

template<typename T> struct is_chrono_duration: std::false_type{};
template<typename Rep, typename Period>
struct is_chrono_duration<std::chrono::duration<Rep, Period>>: std::true_type{};

template<typename T>
struct is_map : conjunction< // map satisfies all the following conditions
    has_iterator<T>,         // has T::iterator
    has_value_type<T>,       // has T::value_type
    has_key_type<T>,         // has T::key_type
    has_mapped_type<T>       // has T::mapped_type
    >{};
template<typename T> struct is_map<T&>                : is_map<T>{};
template<typename T> struct is_map<T const&>          : is_map<T>{};
template<typename T> struct is_map<T volatile&>       : is_map<T>{};
template<typename T> struct is_map<T const volatile&> : is_map<T>{};

template<typename T>
struct is_container : conjunction<
    negation<is_map<T>>,                         // not a map
    negation<std::is_same<T, std::string>>,      // not a std::string
#if __cplusplus >= 201703L
    negation<std::is_same<T, std::string_view>>, // not a std::string_view
#endif
    has_iterator<T>,                             // has T::iterator
    has_value_type<T>                            // has T::value_type
    >{};
template<typename T> struct is_container<T&>                : is_container<T>{};
template<typename T> struct is_container<T const&>          : is_container<T>{};
template<typename T> struct is_container<T volatile&>       : is_container<T>{};
template<typename T> struct is_container<T const volatile&> : is_container<T>{};

template<typename T>
struct is_basic_value: std::false_type{};
template<typename T> struct is_basic_value<T&>                : is_basic_value<T>{};
template<typename T> struct is_basic_value<T const&>          : is_basic_value<T>{};
template<typename T> struct is_basic_value<T volatile&>       : is_basic_value<T>{};
template<typename T> struct is_basic_value<T const volatile&> : is_basic_value<T>{};
template<typename C, template<typename ...> class M, template<typename ...> class V>
struct is_basic_value<::toml::basic_value<C, M, V>>: std::true_type{};

// ---------------------------------------------------------------------------
// C++14 index_sequence

#if __cplusplus >= 201402L

using std::index_sequence;
using std::make_index_sequence;

#else

template<std::size_t ... Ns> struct index_sequence{};

template<typename IS, std::size_t N> struct push_back_index_sequence{};
template<std::size_t N, std::size_t ... Ns>
struct push_back_index_sequence<index_sequence<Ns...>, N>
{
    typedef index_sequence<Ns..., N> type;
};

template<std::size_t N>
struct index_sequence_maker
{
    typedef typename push_back_index_sequence<
        typename index_sequence_maker<N-1>::type, N>::type type;
};
template<>
struct index_sequence_maker<0>
{
    typedef index_sequence<0> type;
};
template<std::size_t N>
using make_index_sequence = typename index_sequence_maker<N-1>::type;

#endif // __cplusplus >= 2014

// ---------------------------------------------------------------------------
// C++14 enable_if_t

#if __cplusplus >= 201402L

using std::enable_if_t;

#else

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

#endif // __cplusplus >= 2014

// ---------------------------------------------------------------------------
// return_type_of_t

#if __cplusplus >= 201703L

template<typename F, typename ... Args>
using return_type_of_t = std::invoke_result_t<F, Args...>;

#else
// result_of is deprecated after C++17
template<typename F, typename ... Args>
using return_type_of_t = typename std::result_of<F(Args...)>::type;

#endif

// ---------------------------------------------------------------------------
// is_string_literal
//
// to use this, pass `typename remove_reference<T>::type` to T.

template<typename T>
struct is_string_literal:
disjunction<
    std::is_same<const char*, T>,
    conjunction<
        std::is_array<T>,
        std::is_same<const char, typename std::remove_extent<T>::type>
        >
    >{};

// ---------------------------------------------------------------------------
// C++20 remove_cvref_t

template<typename T>
struct remove_cvref
{
    using type = typename std::remove_cv<
        typename std::remove_reference<T>::type>::type;
};

template<typename T>
using remove_cvref_t = typename remove_cvref<T>::type;

}// detail
}//toml
#endif // TOML_TRAITS
<commit_msg>fix shadow and some undef warnings<commit_after>//     Copyright Toru Niina 2017.
// Distributed under the MIT License.
#ifndef TOML11_TRAITS_HPP
#define TOML11_TRAITS_HPP

#include "from.hpp"
#include "into.hpp"

#include <chrono>
#include <forward_list>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>

#if __cplusplus >= 201703L
#if __has_include(<string_view>)
#include <string_view>
#endif // has_include(<string_view>)
#endif // cplusplus   >= C++17

namespace toml
{
template<typename C, template<typename ...> class T, template<typename ...> class A>
class basic_value;

namespace detail
{
// ---------------------------------------------------------------------------
// check whether type T is a kind of container/map class

struct has_iterator_impl
{
    template<typename T> static std::true_type  check(typename T::iterator*);
    template<typename T> static std::false_type check(...);
};
struct has_value_type_impl
{
    template<typename T> static std::true_type  check(typename T::value_type*);
    template<typename T> static std::false_type check(...);
};
struct has_key_type_impl
{
    template<typename T> static std::true_type  check(typename T::key_type*);
    template<typename T> static std::false_type check(...);
};
struct has_mapped_type_impl
{
    template<typename T> static std::true_type  check(typename T::mapped_type*);
    template<typename T> static std::false_type check(...);
};
struct has_reserve_method_impl
{
    template<typename T> static std::false_type check(...);
    template<typename T> static std::true_type  check(
        decltype(std::declval<T>().reserve(std::declval<std::size_t>()))*);
};
struct has_push_back_method_impl
{
    template<typename T> static std::false_type check(...);
    template<typename T> static std::true_type  check(
        decltype(std::declval<T>().push_back(std::declval<typename T::value_type>()))*);
};
struct is_comparable_impl
{
    template<typename T> static std::false_type check(...);
    template<typename T> static std::true_type  check(
        decltype(std::declval<T>() < std::declval<T>())*);
};

struct has_from_toml_method_impl
{
    template<typename T, typename C,
             template<typename ...> class Tb, template<typename ...> class A>
    static std::true_type  check(
        decltype(std::declval<T>().from_toml(
                std::declval<::toml::basic_value<C, Tb, A>>()))*);

    template<typename T, typename C,
             template<typename ...> class Tb, template<typename ...> class A>
    static std::false_type check(...);
};
struct has_into_toml_method_impl
{
    template<typename T>
    static std::true_type  check(decltype(std::declval<T>().into_toml())*);
    template<typename T>
    static std::false_type check(...);
};

struct has_specialized_from_impl
{
    template<typename T>
    static std::false_type check(...);
    template<typename T, std::size_t S = sizeof(::toml::from<T>)>
    static std::true_type check(::toml::from<T>*);
};
struct has_specialized_into_impl
{
    template<typename T>
    static std::false_type check(...);
    template<typename T, std::size_t S = sizeof(::toml::into<T>)>
    static std::true_type check(::toml::from<T>*);
};

/// Intel C++ compiler can not use decltype in parent class declaration, here
/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076
#ifdef __INTEL_COMPILER
#define decltype(...) std::enable_if<true, decltype(__VA_ARGS__)>::type
#endif

template<typename T>
struct has_iterator    : decltype(has_iterator_impl::check<T>(nullptr)){};
template<typename T>
struct has_value_type  : decltype(has_value_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_key_type    : decltype(has_key_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_mapped_type : decltype(has_mapped_type_impl::check<T>(nullptr)){};
template<typename T>
struct has_reserve_method : decltype(has_reserve_method_impl::check<T>(nullptr)){};
template<typename T>
struct has_push_back_method : decltype(has_push_back_method_impl::check<T>(nullptr)){};
template<typename T>
struct is_comparable : decltype(is_comparable_impl::check<T>(nullptr)){};

template<typename T, typename C,
         template<typename ...> class Tb, template<typename ...> class A>
struct has_from_toml_method
: decltype(has_from_toml_method_impl::check<T, C, Tb, A>(nullptr)){};

template<typename T>
struct has_into_toml_method
: decltype(has_into_toml_method_impl::check<T>(nullptr)){};

template<typename T>
struct has_specialized_from : decltype(has_specialized_from_impl::check<T>(nullptr)){};
template<typename T>
struct has_specialized_into : decltype(has_specialized_into_impl::check<T>(nullptr)){};

#ifdef __INTEL_COMPILER
#undef decltype
#endif

// ---------------------------------------------------------------------------
// C++17 and/or/not

#if __cplusplus >= 201703L

using std::conjunction;
using std::disjunction;
using std::negation;

#else

template<typename ...> struct conjunction : std::true_type{};
template<typename T>   struct conjunction<T> : T{};
template<typename T, typename ... Ts>
struct conjunction<T, Ts...> :
    std::conditional<static_cast<bool>(T::value), conjunction<Ts...>, T>::type
{};

template<typename ...> struct disjunction : std::false_type{};
template<typename T>   struct disjunction<T> : T {};
template<typename T, typename ... Ts>
struct disjunction<T, Ts...> :
    std::conditional<static_cast<bool>(T::value), T, disjunction<Ts...>>::type
{};

template<typename T>
struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};

#endif

// ---------------------------------------------------------------------------
// type checkers

template<typename T> struct is_std_pair : std::false_type{};
template<typename T1, typename T2>
struct is_std_pair<std::pair<T1, T2>> : std::true_type{};

template<typename T> struct is_std_tuple : std::false_type{};
template<typename ... Ts>
struct is_std_tuple<std::tuple<Ts...>> : std::true_type{};

template<typename T> struct is_std_forward_list : std::false_type{};
template<typename T>
struct is_std_forward_list<std::forward_list<T>> : std::true_type{};

template<typename T> struct is_chrono_duration: std::false_type{};
template<typename Rep, typename Period>
struct is_chrono_duration<std::chrono::duration<Rep, Period>>: std::true_type{};

template<typename T>
struct is_map : conjunction< // map satisfies all the following conditions
    has_iterator<T>,         // has T::iterator
    has_value_type<T>,       // has T::value_type
    has_key_type<T>,         // has T::key_type
    has_mapped_type<T>       // has T::mapped_type
    >{};
template<typename T> struct is_map<T&>                : is_map<T>{};
template<typename T> struct is_map<T const&>          : is_map<T>{};
template<typename T> struct is_map<T volatile&>       : is_map<T>{};
template<typename T> struct is_map<T const volatile&> : is_map<T>{};

template<typename T>
struct is_container : conjunction<
    negation<is_map<T>>,                         // not a map
    negation<std::is_same<T, std::string>>,      // not a std::string
#if __cplusplus >= 201703L
#if __has_include(<string_view>)
    negation<std::is_same<T, std::string_view>>, // not a std::string_view
#endif // has_include(<string_view>)
#endif
    has_iterator<T>,                             // has T::iterator
    has_value_type<T>                            // has T::value_type
    >{};
template<typename T> struct is_container<T&>                : is_container<T>{};
template<typename T> struct is_container<T const&>          : is_container<T>{};
template<typename T> struct is_container<T volatile&>       : is_container<T>{};
template<typename T> struct is_container<T const volatile&> : is_container<T>{};

template<typename T>
struct is_basic_value: std::false_type{};
template<typename T> struct is_basic_value<T&>                : is_basic_value<T>{};
template<typename T> struct is_basic_value<T const&>          : is_basic_value<T>{};
template<typename T> struct is_basic_value<T volatile&>       : is_basic_value<T>{};
template<typename T> struct is_basic_value<T const volatile&> : is_basic_value<T>{};
template<typename C, template<typename ...> class M, template<typename ...> class V>
struct is_basic_value<::toml::basic_value<C, M, V>>: std::true_type{};

// ---------------------------------------------------------------------------
// C++14 index_sequence

#if __cplusplus >= 201402L

using std::index_sequence;
using std::make_index_sequence;

#else

template<std::size_t ... Ns> struct index_sequence{};

template<typename IS, std::size_t N> struct push_back_index_sequence{};
template<std::size_t N, std::size_t ... Ns>
struct push_back_index_sequence<index_sequence<Ns...>, N>
{
    typedef index_sequence<Ns..., N> type;
};

template<std::size_t N>
struct index_sequence_maker
{
    typedef typename push_back_index_sequence<
        typename index_sequence_maker<N-1>::type, N>::type type;
};
template<>
struct index_sequence_maker<0>
{
    typedef index_sequence<0> type;
};
template<std::size_t N>
using make_index_sequence = typename index_sequence_maker<N-1>::type;

#endif // __cplusplus >= 2014

// ---------------------------------------------------------------------------
// C++14 enable_if_t

#if __cplusplus >= 201402L

using std::enable_if_t;

#else

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

#endif // __cplusplus >= 2014

// ---------------------------------------------------------------------------
// return_type_of_t

#if __cplusplus >= 201703L

template<typename F, typename ... Args>
using return_type_of_t = std::invoke_result_t<F, Args...>;

#else
// result_of is deprecated after C++17
template<typename F, typename ... Args>
using return_type_of_t = typename std::result_of<F(Args...)>::type;

#endif

// ---------------------------------------------------------------------------
// is_string_literal
//
// to use this, pass `typename remove_reference<T>::type` to T.

template<typename T>
struct is_string_literal:
disjunction<
    std::is_same<const char*, T>,
    conjunction<
        std::is_array<T>,
        std::is_same<const char, typename std::remove_extent<T>::type>
        >
    >{};

// ---------------------------------------------------------------------------
// C++20 remove_cvref_t

template<typename T>
struct remove_cvref
{
    using type = typename std::remove_cv<
        typename std::remove_reference<T>::type>::type;
};

template<typename T>
using remove_cvref_t = typename remove_cvref<T>::type;

}// detail
}//toml
#endif // TOML_TRAITS
<|endoftext|>


<commit_before>/*!
 *  Copyright (c) 2015 by Contributors
 * \file im2rec.cc
 * \brief convert images into image recordio format
 *  Image Record Format: zeropad[64bit] imid[64bit] img-binary-content
 *  The 64bit zero pad was reserved for future purposes
 *
 *  Image List Format: unique-image-index label[s] path-to-image
 * \sa dmlc/recordio.h
 */
#include <cctype>
#include <cstring>
#include <string>
#include <vector>
#include <iomanip>
#include <sstream>
#include <dmlc/base.h>
#include <dmlc/io.h>
#include <dmlc/timer.h>
#include <dmlc/logging.h>
#include <dmlc/recordio.h>
#include <opencv2/opencv.hpp>
#include "../src/io/image_recordio.h"

int main(int argc, char *argv[]) {
  if (argc < 4) {
    printf("Usage: <image.lst> <image_root_dir> <output.rec> [additional parameters in form key=value]\n"\
           "Possible additional parameters:\n"\
           "\tcolor=USE_COLOR[default=1] Force color (1), gray image (0) or keep source unchanged (-1).\n"\
           "\tresize=newsize resize the shorter edge of image to the newsize, original images will be packed by default\n"\
           "\tlabel_width=WIDTH[default=1] specify the label_width in the list, by default set to 1\n"\
           "\tnsplit=NSPLIT[default=1] used for part generation, logically split the image.list to NSPLIT parts by position\n"\
           "\tpart=PART[default=0] used for part generation, pack the images from the specific part in image.list\n"\
           "\tcenter_crop=CENTER_CROP[default=0] specify whether to crop the center image to make it square.\n"\
           "\tquality=QUALITY[default=80] JPEG quality for encoding (1-100, default: 80) or PNG compression for encoding (1-9, default: 3).\n"\
           "\tencoding=ENCODING[default='.jpg'] Encoding type. Can be '.jpg' or '.png'\n"\
           "\tunchanged=UNCHANGED[default=0] Keep the original image encoding, size and color. If set to 1, it will ignore the others parameters.\n");
    return 0;
  }
  int label_width = 1;
  int new_size = -1;
  int nsplit = 1;
  int partid = 0;
  int center_crop = 0;
  int quality = 80;
  int color_mode = CV_LOAD_IMAGE_COLOR;
  int unchanged=0;
  std::string encoding(".jpg");
  for (int i = 4; i < argc; ++i) {
    char key[128], val[128];
    if (sscanf(argv[i], "%[^=]=%s", key, val) == 2) {
      if (!strcmp(key, "resize")) new_size = atoi(val);
      if (!strcmp(key, "label_width")) label_width = atoi(val);
      if (!strcmp(key, "nsplit")) nsplit = atoi(val);
      if (!strcmp(key, "part")) partid = atoi(val);
      if (!strcmp(key, "center_crop")) center_crop = atoi(val);
      if (!strcmp(key, "quality")) quality = atoi(val);
      if (!strcmp(key, "color")) color_mode = atoi(val);
      if (!strcmp(key, "encoding")) encoding = std::string(val);
      if (!strcmp(key, "unchanged")) unchanged = atoi(val);
    }
  }
  // Check parameters ranges
  if(color_mode != -1 && color_mode != 0 && color_mode != 1) {
      LOG(FATAL) << "Color mode must be -1, 0 or 1.";
  }
  if(encoding != std::string(".jpg") && encoding != std::string(".png")) {
      LOG(FATAL) << "Encoding mode must be .jpg or .png.";
  }

  if (new_size > 0) {
    LOG(INFO) << "New Image Size: Short Edge " << new_size;
  } else {
    LOG(INFO) << "Keep origin image size";
  }
  if (center_crop) {
    LOG(INFO) << "Center cropping to square";
  }
  if (color_mode == 0) {
    LOG(INFO) << "Use gray images";
  }
  if (color_mode == -1) {
    LOG(INFO) << "Keep original color mode";
  }
  LOG(INFO) << "Encoding is " << encoding;

  if(encoding == std::string(".png") and quality > 9) {
      quality = 3;
  }

  using namespace dmlc;
  const static size_t kBufferSize = 1 << 20UL;
  std::string root = argv[2];
  mxnet::io::ImageRecordIO rec;
  size_t imcnt = 0;
  double tstart = dmlc::GetTime();
  dmlc::InputSplit *flist = dmlc::InputSplit::
      Create(argv[1], partid, nsplit, "text");
  std::ostringstream os;
  if (nsplit == 1) {
    os << argv[3];
  } else {
    os << argv[3] << ".part" << std::setw(3) << std::setfill('0') << partid;
  }
  LOG(INFO) << "Write to output: " << os.str();
  dmlc::Stream *fo = dmlc::Stream::Create(os.str().c_str(), "w");
  LOG(INFO) << "Output: " << argv[3];
  dmlc::RecordIOWriter writer(fo);
  std::string fname, path, blob;
  std::vector<unsigned char> decode_buf;
  std::vector<unsigned char> encode_buf;
  std::vector<int> encode_params;
  if(encoding == std::string(".png")) {
      encode_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
      encode_params.push_back(quality);
      LOG(INFO) << "PNG encoding compression: " << quality;
  }
  else {
      encode_params.push_back(CV_IMWRITE_JPEG_QUALITY);
      encode_params.push_back(quality);
      LOG(INFO) << "JPEG encoding quality: " << quality;
  }
  dmlc::InputSplit::Blob line;

  while (flist->NextRecord(&line)) {
    std::string sline(static_cast<char*>(line.dptr), line.size);
    std::istringstream is(sline);
    if (!(is >> rec.header.image_id[0] >> rec.header.label)) continue;
    for (int k = 1; k < label_width; ++ k) {
      float tmp;
      CHECK(is >> tmp)
          << "Invalid ImageList, did you provide the correct label_width?";
    }
    CHECK(std::getline(is, fname));
    // eliminate invalid chars in the end
    while (fname.length() != 0 &&
           (isspace(*fname.rbegin()) || !isprint(*fname.rbegin()))) {
      fname.resize(fname.length() - 1);
    }
    // eliminate invalid chars in beginning.
    const char *p = fname.c_str();
    while (isspace(*p)) ++p;
    path = root + p;
    // use "r" is equal to rb in dmlc::Stream
    dmlc::Stream *fi = dmlc::Stream::Create(path.c_str(), "r");
    rec.SaveHeader(&blob);
    decode_buf.clear();
    size_t imsize = 0;
    while (true) {
      decode_buf.resize(imsize + kBufferSize);
      size_t nread = fi->Read(BeginPtr(decode_buf) + imsize, kBufferSize);
      imsize += nread;
      decode_buf.resize(imsize);
      if (nread != kBufferSize) break;
    }
    delete fi;

    if(unchanged != 1) {
      cv::Mat img = cv::imdecode(decode_buf, color_mode);
      CHECK(img.data != NULL) << "OpenCV decode fail:" << path;
      cv::Mat res = img;
      if (new_size > 0) {
        if (center_crop) {
          if (img.rows > img.cols) {
            int margin = (img.rows - img.cols)/2;
            img = img(cv::Range(margin, margin+img.cols), cv::Range(0, img.cols));
          } else {
            int margin = (img.cols - img.rows)/2;
            img = img(cv::Range(0, img.rows), cv::Range(margin, margin + img.rows));
          }
        }
        if (img.rows > img.cols) {
          cv::resize(img, res, cv::Size(new_size, img.rows * new_size / img.cols),
                     0, 0, CV_INTER_LINEAR);
        } else {
          cv::resize(img, res, cv::Size(new_size * img.cols / img.rows, new_size),
                     0, 0, CV_INTER_LINEAR);
        }
      }
      encode_buf.clear();
      CHECK(cv::imencode(encoding, res, encode_buf, encode_params));
      size_t bsize = blob.size();
      blob.resize(bsize + encode_buf.size());
      memcpy(BeginPtr(blob) + bsize,
             BeginPtr(encode_buf), encode_buf.size());
    }
    else {
      size_t bsize = blob.size();
      blob.resize(bsize + decode_buf.size());
      memcpy(BeginPtr(blob) + bsize,
             BeginPtr(decode_buf), decode_buf.size());
    }
    writer.WriteRecord(BeginPtr(blob), blob.size());
    // write header
    ++imcnt;
    if (imcnt % 1000 == 0) {
      LOG(INFO) << imcnt << " images processed, " << GetTime() - tstart << " sec elapsed";
    }
  }
  LOG(INFO) << "Total: " << imcnt << " images processed, " << GetTime() - tstart << " sec elapsed";
  delete fo;
  delete flist;
  return 0;
}
<commit_msg>output should use os.str<commit_after>/*!
 *  Copyright (c) 2015 by Contributors
 * \file im2rec.cc
 * \brief convert images into image recordio format
 *  Image Record Format: zeropad[64bit] imid[64bit] img-binary-content
 *  The 64bit zero pad was reserved for future purposes
 *
 *  Image List Format: unique-image-index label[s] path-to-image
 * \sa dmlc/recordio.h
 */
#include <cctype>
#include <cstring>
#include <string>
#include <vector>
#include <iomanip>
#include <sstream>
#include <dmlc/base.h>
#include <dmlc/io.h>
#include <dmlc/timer.h>
#include <dmlc/logging.h>
#include <dmlc/recordio.h>
#include <opencv2/opencv.hpp>
#include "../src/io/image_recordio.h"

int main(int argc, char *argv[]) {
  if (argc < 4) {
    printf("Usage: <image.lst> <image_root_dir> <output.rec> [additional parameters in form key=value]\n"\
           "Possible additional parameters:\n"\
           "\tcolor=USE_COLOR[default=1] Force color (1), gray image (0) or keep source unchanged (-1).\n"\
           "\tresize=newsize resize the shorter edge of image to the newsize, original images will be packed by default\n"\
           "\tlabel_width=WIDTH[default=1] specify the label_width in the list, by default set to 1\n"\
           "\tnsplit=NSPLIT[default=1] used for part generation, logically split the image.list to NSPLIT parts by position\n"\
           "\tpart=PART[default=0] used for part generation, pack the images from the specific part in image.list\n"\
           "\tcenter_crop=CENTER_CROP[default=0] specify whether to crop the center image to make it square.\n"\
           "\tquality=QUALITY[default=80] JPEG quality for encoding (1-100, default: 80) or PNG compression for encoding (1-9, default: 3).\n"\
           "\tencoding=ENCODING[default='.jpg'] Encoding type. Can be '.jpg' or '.png'\n"\
           "\tunchanged=UNCHANGED[default=0] Keep the original image encoding, size and color. If set to 1, it will ignore the others parameters.\n");
    return 0;
  }
  int label_width = 1;
  int new_size = -1;
  int nsplit = 1;
  int partid = 0;
  int center_crop = 0;
  int quality = 80;
  int color_mode = CV_LOAD_IMAGE_COLOR;
  int unchanged=0;
  std::string encoding(".jpg");
  for (int i = 4; i < argc; ++i) {
    char key[128], val[128];
    if (sscanf(argv[i], "%[^=]=%s", key, val) == 2) {
      if (!strcmp(key, "resize")) new_size = atoi(val);
      if (!strcmp(key, "label_width")) label_width = atoi(val);
      if (!strcmp(key, "nsplit")) nsplit = atoi(val);
      if (!strcmp(key, "part")) partid = atoi(val);
      if (!strcmp(key, "center_crop")) center_crop = atoi(val);
      if (!strcmp(key, "quality")) quality = atoi(val);
      if (!strcmp(key, "color")) color_mode = atoi(val);
      if (!strcmp(key, "encoding")) encoding = std::string(val);
      if (!strcmp(key, "unchanged")) unchanged = atoi(val);
    }
  }
  // Check parameters ranges
  if(color_mode != -1 && color_mode != 0 && color_mode != 1) {
      LOG(FATAL) << "Color mode must be -1, 0 or 1.";
  }
  if(encoding != std::string(".jpg") && encoding != std::string(".png")) {
      LOG(FATAL) << "Encoding mode must be .jpg or .png.";
  }

  if (new_size > 0) {
    LOG(INFO) << "New Image Size: Short Edge " << new_size;
  } else {
    LOG(INFO) << "Keep origin image size";
  }
  if (center_crop) {
    LOG(INFO) << "Center cropping to square";
  }
  if (color_mode == 0) {
    LOG(INFO) << "Use gray images";
  }
  if (color_mode == -1) {
    LOG(INFO) << "Keep original color mode";
  }
  LOG(INFO) << "Encoding is " << encoding;

  if(encoding == std::string(".png") and quality > 9) {
      quality = 3;
  }

  using namespace dmlc;
  const static size_t kBufferSize = 1 << 20UL;
  std::string root = argv[2];
  mxnet::io::ImageRecordIO rec;
  size_t imcnt = 0;
  double tstart = dmlc::GetTime();
  dmlc::InputSplit *flist = dmlc::InputSplit::
      Create(argv[1], partid, nsplit, "text");
  std::ostringstream os;
  if (nsplit == 1) {
    os << argv[3];
  } else {
    os << argv[3] << ".part" << std::setw(3) << std::setfill('0') << partid;
  }
  LOG(INFO) << "Write to output: " << os.str();
  dmlc::Stream *fo = dmlc::Stream::Create(os.str().c_str(), "w");
  LOG(INFO) << "Output: " << os.str();
  dmlc::RecordIOWriter writer(fo);
  std::string fname, path, blob;
  std::vector<unsigned char> decode_buf;
  std::vector<unsigned char> encode_buf;
  std::vector<int> encode_params;
  if(encoding == std::string(".png")) {
      encode_params.push_back(CV_IMWRITE_PNG_COMPRESSION);
      encode_params.push_back(quality);
      LOG(INFO) << "PNG encoding compression: " << quality;
  }
  else {
      encode_params.push_back(CV_IMWRITE_JPEG_QUALITY);
      encode_params.push_back(quality);
      LOG(INFO) << "JPEG encoding quality: " << quality;
  }
  dmlc::InputSplit::Blob line;

  while (flist->NextRecord(&line)) {
    std::string sline(static_cast<char*>(line.dptr), line.size);
    std::istringstream is(sline);
    if (!(is >> rec.header.image_id[0] >> rec.header.label)) continue;
    for (int k = 1; k < label_width; ++ k) {
      float tmp;
      CHECK(is >> tmp)
          << "Invalid ImageList, did you provide the correct label_width?";
    }
    CHECK(std::getline(is, fname));
    // eliminate invalid chars in the end
    while (fname.length() != 0 &&
           (isspace(*fname.rbegin()) || !isprint(*fname.rbegin()))) {
      fname.resize(fname.length() - 1);
    }
    // eliminate invalid chars in beginning.
    const char *p = fname.c_str();
    while (isspace(*p)) ++p;
    path = root + p;
    // use "r" is equal to rb in dmlc::Stream
    dmlc::Stream *fi = dmlc::Stream::Create(path.c_str(), "r");
    rec.SaveHeader(&blob);
    decode_buf.clear();
    size_t imsize = 0;
    while (true) {
      decode_buf.resize(imsize + kBufferSize);
      size_t nread = fi->Read(BeginPtr(decode_buf) + imsize, kBufferSize);
      imsize += nread;
      decode_buf.resize(imsize);
      if (nread != kBufferSize) break;
    }
    delete fi;

    if(unchanged != 1) {
      cv::Mat img = cv::imdecode(decode_buf, color_mode);
      CHECK(img.data != NULL) << "OpenCV decode fail:" << path;
      cv::Mat res = img;
      if (new_size > 0) {
        if (center_crop) {
          if (img.rows > img.cols) {
            int margin = (img.rows - img.cols)/2;
            img = img(cv::Range(margin, margin+img.cols), cv::Range(0, img.cols));
          } else {
            int margin = (img.cols - img.rows)/2;
            img = img(cv::Range(0, img.rows), cv::Range(margin, margin + img.rows));
          }
        }
        if (img.rows > img.cols) {
          cv::resize(img, res, cv::Size(new_size, img.rows * new_size / img.cols),
                     0, 0, CV_INTER_LINEAR);
        } else {
          cv::resize(img, res, cv::Size(new_size * img.cols / img.rows, new_size),
                     0, 0, CV_INTER_LINEAR);
        }
      }
      encode_buf.clear();
      CHECK(cv::imencode(encoding, res, encode_buf, encode_params));
      size_t bsize = blob.size();
      blob.resize(bsize + encode_buf.size());
      memcpy(BeginPtr(blob) + bsize,
             BeginPtr(encode_buf), encode_buf.size());
    }
    else {
      size_t bsize = blob.size();
      blob.resize(bsize + decode_buf.size());
      memcpy(BeginPtr(blob) + bsize,
             BeginPtr(decode_buf), decode_buf.size());
    }
    writer.WriteRecord(BeginPtr(blob), blob.size());
    // write header
    ++imcnt;
    if (imcnt % 1000 == 0) {
      LOG(INFO) << imcnt << " images processed, " << GetTime() - tstart << " sec elapsed";
    }
  }
  LOG(INFO) << "Total: " << imcnt << " images processed, " << GetTime() - tstart << " sec elapsed";
  delete fo;
  delete flist;
  return 0;
}
<|endoftext|>


<commit_before>/*
**  Copyright (C) 2012, 2013 Aldebaran Robotics
**  See COPYING for the license
*/

#include <boost/thread.hpp>
#include <boost/program_options.hpp>
#include <boost/make_shared.hpp>

#include <qi/preproc.hpp>
#include <qi/log.hpp>
#include <qi/application.hpp>
#include <qi/threadpool.hpp>

#include <qi/eventloop.hpp>

#include "eventloop_p.hpp"

#include <pthread.h>

qiLogCategory("qi.eventloop");

namespace qi {

  EventLoopAsio::EventLoopAsio()
  : _destroyMe(false)
  , _running(false)
  , _threaded(false)
  {
  }

  void EventLoopAsio::start()
  {
    if (_running || _threaded)
      return;
    _threaded = true;
    _thd = boost::thread(&EventLoopPrivate::run, this);
    while (!_running)
      qi::os::msleep(0);
  }

  EventLoopAsio::~EventLoopAsio()
  {
    if (_running && boost::this_thread::get_id() != _id)
      qiLogError() << "Destroying EventLoopPrivate from itself while running";
    stop();
    join();
  }

  void EventLoopAsio::destroy()
  {
    if (isInEventLoopThread())
      boost::thread(&EventLoopAsio::destroy, this);
    else
    {
      delete this;
    }
  }

  void EventLoopAsio::run()
  {
    qiLogDebug() << this << "run starting";
    qi::os::setCurrentThreadName("eventloop");
    _running = true;
    _id = boost::this_thread::get_id();
    _work = new boost::asio::io_service::work(_io);
    _io.run();
    bool destroyMe;
    {
      boost::recursive_mutex::scoped_lock sl(_mutex);
      _running = false;
      destroyMe = _destroyMe;
    }
    if (destroyMe)
      delete this;
  }

  bool EventLoopAsio::isInEventLoopThread()
  {
    return boost::this_thread::get_id() == _id;
  }

  void EventLoopAsio::stop()
  {
    qiLogDebug() << "stopping eventloopasio: " << this;
    boost::recursive_mutex::scoped_lock sl(_mutex);
    if (_work)
    {
      delete _work;
      _work = 0;
    }
  }

  void EventLoopAsio::join()
  {
    if (boost::this_thread::get_id() == _id)
    {
      qiLogError() << "Cannot join from within event loop thread";
      return;
    }
    if (_threaded)
      try {
        _thd.join();
      }
      catch(const boost::thread_resource_error& e)
      {
        qiLogWarning() << "Join an already joined thread: " << e.what();
      }
    else
      while (_running)
        qi::os::msleep(0);
  }

  void EventLoopAsio::post(uint64_t usDelay, const boost::function<void ()>& cb)
  {
    if (!usDelay)
      _io.post(cb);
    else
      asyncCall(usDelay, cb);
  }

  static void invoke_maybe(boost::function<void()> f, qi::Promise<void> p, const boost::system::error_code& erc)
  {
    if (!erc)
    {
      f();
      p.setValue(0);
    }
    else
      p.setError("Operation cancelled");
  }

  qi::Future<void> EventLoopAsio::asyncCall(uint64_t usDelay, boost::function<void ()> cb)
  {
    boost::shared_ptr<boost::asio::deadline_timer> timer = boost::make_shared<boost::asio::deadline_timer>(boost::ref(_io));
    timer->expires_from_now(boost::posix_time::microseconds(usDelay));
    qi::Promise<void> prom(boost::bind(&boost::asio::deadline_timer::cancel, timer));
    timer->async_wait(boost::bind(&invoke_maybe, cb, prom, _1));
    return prom.future();
  }

  void* EventLoopAsio::nativeHandle()
  {
    return static_cast<void*>(&_io);
  }

  EventLoopThreadPool::EventLoopThreadPool(int minWorkers, int maxWorkers, int minIdleWorkers, int maxIdleWorkers)
  {
    _stopping = false;
    _pool = new ThreadPool(minWorkers, maxWorkers, minIdleWorkers, maxIdleWorkers);
  }

  bool EventLoopThreadPool::isInEventLoopThread()
  {
    // The point is to know if a call will be synchronous. It never is
    // with thread pool
    return false;
  }

  void EventLoopThreadPool::start()
  {
  }

  void EventLoopThreadPool::run()
  {
  }

  void EventLoopThreadPool::join()
  {
    _pool->waitForAll();
  }

  void EventLoopThreadPool::stop()
  {
    _stopping = true;
  }

  void* EventLoopThreadPool::nativeHandle()
  {
    return 0;
  }

  void EventLoopThreadPool::destroy()
  {
    _stopping = true;
    // Ensure delete is not called from one of the threads of the event loop
    boost::thread(&EventLoopThreadPool::destroy, this);
  }

  EventLoopThreadPool::~EventLoopThreadPool()
  {
    delete _pool;
  }

  static void delay_call(uint64_t usDelay, boost::function<void()>* callback)
  {
    if (usDelay)
      qi::os::msleep(static_cast<unsigned int>(usDelay/1000));
    try
    {
      (*callback)();
    }
    catch(const std::exception& e)
    {
      qiLogError() << "Exception caught in async call: " << e.what();
    }
    catch(...)
    {
      qiLogError() << "Unknown exception caught in async call";
    }
    delete callback;
  }

  static void delay_call_notify(uint64_t usDelay, boost::function<void()> callback,
    qi::Promise<void> promise)
  {
    if (usDelay)
      qi::os::msleep(static_cast<unsigned int>(usDelay/1000));
    try
    {
      callback();
      promise.setValue(0);
    }
    catch(const std::exception& e)
    {
      promise.setError(std::string("Exception caught in async call: ")  + e.what());
    }
    catch(...)
    {
      promise.setError("Unknown exception caught in async call");
    }
  }

  void EventLoopThreadPool::post(uint64_t usDelay,
      const boost::function<void ()>& callback)
  {
    _pool->schedule(boost::bind(&delay_call, usDelay, new boost::function<void ()>(callback)));
  }

  qi::Future<void>  EventLoopThreadPool::asyncCall(uint64_t usDelay,
      boost::function<void ()> callback)
  {
    if (_stopping)
      return qi::makeFutureError<void>("Schedule attempt on destroyed thread pool");
    qi::Promise<void> promise;
    _pool->schedule(boost::bind(&delay_call_notify, usDelay, callback, promise));
    return promise.future();
  }

   // Basic pimpl bouncers.
  EventLoop::AsyncCallHandle::AsyncCallHandle()
  {
    _p = boost::make_shared<AsyncCallHandlePrivate>();
  }

  EventLoop::AsyncCallHandle::~AsyncCallHandle()
  {
  }

  void EventLoop::AsyncCallHandle::cancel()
  {
    _p->cancel();
  }

  EventLoop::EventLoop()
  : _p(0)
  {
  }

  EventLoop::~EventLoop()
  {
    if (_p)
      _p->destroy();
    _p = 0;
  }

  #define CHECK_STARTED                                                            \
  do {                                                                             \
    if (!_p)                                                                       \
      throw std::runtime_error("EventLoop " __HERE " : EventLoop not started");  \
  } while(0)

  bool EventLoop::isInEventLoopThread()
  {
    CHECK_STARTED;
    return _p->isInEventLoopThread();
  }

  void EventLoop::join()
  {
    CHECK_STARTED;
    _p->join();
  }

  void EventLoop::start()
  {
    if (_p)
      return;
    _p = new EventLoopAsio();
    _p->start();
  }

  void EventLoop::startThreadPool(int minWorkers, int maxWorkers, int minIdleWorkers, int maxIdleWorkers)
  {
    #define OR(name, val) (name==-1?val:name)
    if (_p)
      return;
    _p = new EventLoopThreadPool(OR(minWorkers, 2), OR(maxWorkers, 8), OR(minIdleWorkers,1), OR(maxIdleWorkers, 4));
    #undef OR
  }

  void EventLoop::stop()
  {
    CHECK_STARTED;
    _p->stop();
  }

  void EventLoop::run()
  {
    if (_p)
      return;
    _p = new EventLoopAsio();
    _p->run();
  }

  void *EventLoop::nativeHandle() {
    CHECK_STARTED;
    return _p->nativeHandle();
  }

  void EventLoop::post(const boost::function<void ()>& callback,uint64_t usDelay)
  {
    CHECK_STARTED;
    _p->post(usDelay, callback);
  }

  qi::Future<void>
  EventLoop::async(
    boost::function<void ()> callback,
    uint64_t usDelay)
  {
    CHECK_STARTED;
    return _p->asyncCall(usDelay, callback);
  }

  struct MonitorContext
  {
    EventLoop* target;
    EventLoop* helper;
    Future<void> mon;
    bool isFired;  // true: pinging, false: waiting for next ping.
    bool ending;
    uint64_t maxDelay;
    Promise<void> promise;
    int64_t startTime;
  };

  static void monitor_pingtimeout(boost::shared_ptr<MonitorContext> ctx)
  {
    //qiLogDebug("qi.EventLoop") << os::ustime() << " MON timeout " << ctx->isFired
    // << ' ' << (os::ustime() - ctx->startTime);
    if (!ctx->isFired)
      return; // Got the pong in the meantime, abort
    ctx->promise.setError("Event loop monitor timeout");
    /* Ping system is still on, but promise is set.
     * So future invocations of cancel() will be ignored, which makes the
     * monitoring unstopable.
     * So reset the value.
    */
    ctx->promise.reset();
  }

  static void monitor_cancel(boost::shared_ptr<MonitorContext> ctx)
  {
    //qiLogDebug("qi.EventLoop") << os::ustime() << " MON cancel " << ctx->isFired;
    ctx->ending = true;
    try {
      ctx->mon.cancel();
    }
    catch (...)
    {}
  }

  static void monitor_ping(boost::shared_ptr<MonitorContext> ctx)
  {
    if (ctx->ending)
      return;
    //qiLogDebug("qi.EventLoop") << os::ustime() << " MON ping " << ctx->isFired;
    if (ctx->isFired)
    { // This is a pong
      ctx->isFired = false;
      // Cancel monitoring async call
      try {
        ctx->mon.cancel();
      }
      catch (const std::exception& /*e*/) {
        //qiLogDebug("qi.EventLoop") << "MON " << e.what();
      }
      uint64_t pingDelay = os::ustime() - ctx->startTime;
      if (pingDelay > ctx->maxDelay / 2)
        qiLogDebug() << "Long ping " << pingDelay;
      // Wait a bit before pinging againg
      //qiLogDebug("qi.EventLoop") << os::ustime() << " MON delay " << ctx->maxDelay;
      ctx->helper->async(boost::bind(&monitor_ping, ctx), ctx->maxDelay*5);
    }
    else
    { // Delay between pings reached, ping again
      ctx->startTime = os::ustime();
      ctx->isFired = true;
      // Start monitor async first, or the ping async can trigger before the
      // monitor async is setup
      ctx->mon = ctx->helper->async(boost::bind(&monitor_pingtimeout, ctx), ctx->maxDelay);
      ctx->target->post(boost::bind(&monitor_ping, ctx));
      assert(ctx->mon.isCanceleable());
    }
  }

  qi::Future<void> EventLoop::monitorEventLoop(EventLoop* helper, uint64_t maxDelay)
  {
    // Context data is a Future*[2]
    boost::shared_ptr<MonitorContext> ctx = boost::make_shared<MonitorContext>();
    ctx->target = this;
    ctx->helper = helper;
    ctx->maxDelay = maxDelay;
    ctx->promise = Promise<void>(boost::bind(&monitor_cancel, ctx));
    ctx->isFired = false;
    ctx->ending = false;
    monitor_ping(ctx);
    return ctx->promise.future();
  }

  static void eventloop_stop(EventLoop* ctx)
  {
    ctx->stop();
    delete ctx;
  }

  static EventLoop* _netEventLoop = 0;
  static EventLoop* _objEventLoop = 0;
  static EventLoop* _poolEventLoop = 0;
  static double _monitorInterval = 0;

  static void monitor_notify(const char* which)
  {
    qiLogError() << which << " event loop stuck?";
  }
  static EventLoop* _get(EventLoop* &ctx, bool isPool)
  {
    if (!ctx)
    {
      if (! qi::Application::initialized())
      {
        qiLogInfo() << "Creating event loop while no qi::Application() is running";
      }
      ctx = new EventLoop();
      if (isPool)
        ctx->startThreadPool();
      else
        ctx->start();
      Application::atExit(boost::bind(&eventloop_stop, ctx));
      if (!isPool && _netEventLoop && _objEventLoop && _monitorInterval)
      {
        int64_t d = static_cast<qi::int64_t>(_monitorInterval * 1e6);
        _netEventLoop->monitorEventLoop(_objEventLoop, d)
          .connect(boost::bind(&monitor_notify, "network"));
        _objEventLoop->monitorEventLoop(_netEventLoop, d)
          .connect(boost::bind(&monitor_notify, "object"));
      }
    }
    return ctx;
  }

  EventLoop* getDefaultNetworkEventLoop()
  {
    return _get(_netEventLoop, false);
  }

  EventLoop* getDefaultObjectEventLoop()
  {
    return _get(_objEventLoop, false);
  }

  EventLoop* getDefaultThreadPoolEventLoop()
  {
    return _get(_poolEventLoop, true);
  }
  static void setMonitorInterval(double v)
  {
    _monitorInterval = v;
  }
  namespace {
  _QI_COMMAND_LINE_OPTIONS(
    "EventLoop monitoring",
    ("loop-monitor-latency", value<double>()->notifier(&setMonitorInterval), "Warn if event loop is stuck more than given duration in seconds")
    )
  }
}
<commit_msg>EventLoop: remove useless pthread include<commit_after>/*
**  Copyright (C) 2012, 2013 Aldebaran Robotics
**  See COPYING for the license
*/

#include <boost/thread.hpp>
#include <boost/program_options.hpp>
#include <boost/make_shared.hpp>

#include <qi/preproc.hpp>
#include <qi/log.hpp>
#include <qi/application.hpp>
#include <qi/threadpool.hpp>

#include <qi/eventloop.hpp>

#include "eventloop_p.hpp"

qiLogCategory("qi.eventloop");

namespace qi {

  EventLoopAsio::EventLoopAsio()
  : _destroyMe(false)
  , _running(false)
  , _threaded(false)
  {
  }

  void EventLoopAsio::start()
  {
    if (_running || _threaded)
      return;
    _threaded = true;
    _thd = boost::thread(&EventLoopPrivate::run, this);
    while (!_running)
      qi::os::msleep(0);
  }

  EventLoopAsio::~EventLoopAsio()
  {
    if (_running && boost::this_thread::get_id() != _id)
      qiLogError() << "Destroying EventLoopPrivate from itself while running";
    stop();
    join();
  }

  void EventLoopAsio::destroy()
  {
    if (isInEventLoopThread())
      boost::thread(&EventLoopAsio::destroy, this);
    else
    {
      delete this;
    }
  }

  void EventLoopAsio::run()
  {
    qiLogDebug() << this << "run starting";
    qi::os::setCurrentThreadName("eventloop");
    _running = true;
    _id = boost::this_thread::get_id();
    _work = new boost::asio::io_service::work(_io);
    _io.run();
    bool destroyMe;
    {
      boost::recursive_mutex::scoped_lock sl(_mutex);
      _running = false;
      destroyMe = _destroyMe;
    }
    if (destroyMe)
      delete this;
  }

  bool EventLoopAsio::isInEventLoopThread()
  {
    return boost::this_thread::get_id() == _id;
  }

  void EventLoopAsio::stop()
  {
    qiLogDebug() << "stopping eventloopasio: " << this;
    boost::recursive_mutex::scoped_lock sl(_mutex);
    if (_work)
    {
      delete _work;
      _work = 0;
    }
  }

  void EventLoopAsio::join()
  {
    if (boost::this_thread::get_id() == _id)
    {
      qiLogError() << "Cannot join from within event loop thread";
      return;
    }
    if (_threaded)
      try {
        _thd.join();
      }
      catch(const boost::thread_resource_error& e)
      {
        qiLogWarning() << "Join an already joined thread: " << e.what();
      }
    else
      while (_running)
        qi::os::msleep(0);
  }

  void EventLoopAsio::post(uint64_t usDelay, const boost::function<void ()>& cb)
  {
    if (!usDelay)
      _io.post(cb);
    else
      asyncCall(usDelay, cb);
  }

  static void invoke_maybe(boost::function<void()> f, qi::Promise<void> p, const boost::system::error_code& erc)
  {
    if (!erc)
    {
      f();
      p.setValue(0);
    }
    else
      p.setError("Operation cancelled");
  }

  qi::Future<void> EventLoopAsio::asyncCall(uint64_t usDelay, boost::function<void ()> cb)
  {
    boost::shared_ptr<boost::asio::deadline_timer> timer = boost::make_shared<boost::asio::deadline_timer>(boost::ref(_io));
    timer->expires_from_now(boost::posix_time::microseconds(usDelay));
    qi::Promise<void> prom(boost::bind(&boost::asio::deadline_timer::cancel, timer));
    timer->async_wait(boost::bind(&invoke_maybe, cb, prom, _1));
    return prom.future();
  }

  void* EventLoopAsio::nativeHandle()
  {
    return static_cast<void*>(&_io);
  }

  EventLoopThreadPool::EventLoopThreadPool(int minWorkers, int maxWorkers, int minIdleWorkers, int maxIdleWorkers)
  {
    _stopping = false;
    _pool = new ThreadPool(minWorkers, maxWorkers, minIdleWorkers, maxIdleWorkers);
  }

  bool EventLoopThreadPool::isInEventLoopThread()
  {
    // The point is to know if a call will be synchronous. It never is
    // with thread pool
    return false;
  }

  void EventLoopThreadPool::start()
  {
  }

  void EventLoopThreadPool::run()
  {
  }

  void EventLoopThreadPool::join()
  {
    _pool->waitForAll();
  }

  void EventLoopThreadPool::stop()
  {
    _stopping = true;
  }

  void* EventLoopThreadPool::nativeHandle()
  {
    return 0;
  }

  void EventLoopThreadPool::destroy()
  {
    _stopping = true;
    // Ensure delete is not called from one of the threads of the event loop
    boost::thread(&EventLoopThreadPool::destroy, this);
  }

  EventLoopThreadPool::~EventLoopThreadPool()
  {
    delete _pool;
  }

  static void delay_call(uint64_t usDelay, boost::function<void()>* callback)
  {
    if (usDelay)
      qi::os::msleep(static_cast<unsigned int>(usDelay/1000));
    try
    {
      (*callback)();
    }
    catch(const std::exception& e)
    {
      qiLogError() << "Exception caught in async call: " << e.what();
    }
    catch(...)
    {
      qiLogError() << "Unknown exception caught in async call";
    }
    delete callback;
  }

  static void delay_call_notify(uint64_t usDelay, boost::function<void()> callback,
    qi::Promise<void> promise)
  {
    if (usDelay)
      qi::os::msleep(static_cast<unsigned int>(usDelay/1000));
    try
    {
      callback();
      promise.setValue(0);
    }
    catch(const std::exception& e)
    {
      promise.setError(std::string("Exception caught in async call: ")  + e.what());
    }
    catch(...)
    {
      promise.setError("Unknown exception caught in async call");
    }
  }

  void EventLoopThreadPool::post(uint64_t usDelay,
      const boost::function<void ()>& callback)
  {
    _pool->schedule(boost::bind(&delay_call, usDelay, new boost::function<void ()>(callback)));
  }

  qi::Future<void>  EventLoopThreadPool::asyncCall(uint64_t usDelay,
      boost::function<void ()> callback)
  {
    if (_stopping)
      return qi::makeFutureError<void>("Schedule attempt on destroyed thread pool");
    qi::Promise<void> promise;
    _pool->schedule(boost::bind(&delay_call_notify, usDelay, callback, promise));
    return promise.future();
  }

   // Basic pimpl bouncers.
  EventLoop::AsyncCallHandle::AsyncCallHandle()
  {
    _p = boost::make_shared<AsyncCallHandlePrivate>();
  }

  EventLoop::AsyncCallHandle::~AsyncCallHandle()
  {
  }

  void EventLoop::AsyncCallHandle::cancel()
  {
    _p->cancel();
  }

  EventLoop::EventLoop()
  : _p(0)
  {
  }

  EventLoop::~EventLoop()
  {
    if (_p)
      _p->destroy();
    _p = 0;
  }

  #define CHECK_STARTED                                                            \
  do {                                                                             \
    if (!_p)                                                                       \
      throw std::runtime_error("EventLoop " __HERE " : EventLoop not started");  \
  } while(0)

  bool EventLoop::isInEventLoopThread()
  {
    CHECK_STARTED;
    return _p->isInEventLoopThread();
  }

  void EventLoop::join()
  {
    CHECK_STARTED;
    _p->join();
  }

  void EventLoop::start()
  {
    if (_p)
      return;
    _p = new EventLoopAsio();
    _p->start();
  }

  void EventLoop::startThreadPool(int minWorkers, int maxWorkers, int minIdleWorkers, int maxIdleWorkers)
  {
    #define OR(name, val) (name==-1?val:name)
    if (_p)
      return;
    _p = new EventLoopThreadPool(OR(minWorkers, 2), OR(maxWorkers, 8), OR(minIdleWorkers,1), OR(maxIdleWorkers, 4));
    #undef OR
  }

  void EventLoop::stop()
  {
    CHECK_STARTED;
    _p->stop();
  }

  void EventLoop::run()
  {
    if (_p)
      return;
    _p = new EventLoopAsio();
    _p->run();
  }

  void *EventLoop::nativeHandle() {
    CHECK_STARTED;
    return _p->nativeHandle();
  }

  void EventLoop::post(const boost::function<void ()>& callback,uint64_t usDelay)
  {
    CHECK_STARTED;
    _p->post(usDelay, callback);
  }

  qi::Future<void>
  EventLoop::async(
    boost::function<void ()> callback,
    uint64_t usDelay)
  {
    CHECK_STARTED;
    return _p->asyncCall(usDelay, callback);
  }

  struct MonitorContext
  {
    EventLoop* target;
    EventLoop* helper;
    Future<void> mon;
    bool isFired;  // true: pinging, false: waiting for next ping.
    bool ending;
    uint64_t maxDelay;
    Promise<void> promise;
    int64_t startTime;
  };

  static void monitor_pingtimeout(boost::shared_ptr<MonitorContext> ctx)
  {
    //qiLogDebug("qi.EventLoop") << os::ustime() << " MON timeout " << ctx->isFired
    // << ' ' << (os::ustime() - ctx->startTime);
    if (!ctx->isFired)
      return; // Got the pong in the meantime, abort
    ctx->promise.setError("Event loop monitor timeout");
    /* Ping system is still on, but promise is set.
     * So future invocations of cancel() will be ignored, which makes the
     * monitoring unstopable.
     * So reset the value.
    */
    ctx->promise.reset();
  }

  static void monitor_cancel(boost::shared_ptr<MonitorContext> ctx)
  {
    //qiLogDebug("qi.EventLoop") << os::ustime() << " MON cancel " << ctx->isFired;
    ctx->ending = true;
    try {
      ctx->mon.cancel();
    }
    catch (...)
    {}
  }

  static void monitor_ping(boost::shared_ptr<MonitorContext> ctx)
  {
    if (ctx->ending)
      return;
    //qiLogDebug("qi.EventLoop") << os::ustime() << " MON ping " << ctx->isFired;
    if (ctx->isFired)
    { // This is a pong
      ctx->isFired = false;
      // Cancel monitoring async call
      try {
        ctx->mon.cancel();
      }
      catch (const std::exception& /*e*/) {
        //qiLogDebug("qi.EventLoop") << "MON " << e.what();
      }
      uint64_t pingDelay = os::ustime() - ctx->startTime;
      if (pingDelay > ctx->maxDelay / 2)
        qiLogDebug() << "Long ping " << pingDelay;
      // Wait a bit before pinging againg
      //qiLogDebug("qi.EventLoop") << os::ustime() << " MON delay " << ctx->maxDelay;
      ctx->helper->async(boost::bind(&monitor_ping, ctx), ctx->maxDelay*5);
    }
    else
    { // Delay between pings reached, ping again
      ctx->startTime = os::ustime();
      ctx->isFired = true;
      // Start monitor async first, or the ping async can trigger before the
      // monitor async is setup
      ctx->mon = ctx->helper->async(boost::bind(&monitor_pingtimeout, ctx), ctx->maxDelay);
      ctx->target->post(boost::bind(&monitor_ping, ctx));
      assert(ctx->mon.isCanceleable());
    }
  }

  qi::Future<void> EventLoop::monitorEventLoop(EventLoop* helper, uint64_t maxDelay)
  {
    // Context data is a Future*[2]
    boost::shared_ptr<MonitorContext> ctx = boost::make_shared<MonitorContext>();
    ctx->target = this;
    ctx->helper = helper;
    ctx->maxDelay = maxDelay;
    ctx->promise = Promise<void>(boost::bind(&monitor_cancel, ctx));
    ctx->isFired = false;
    ctx->ending = false;
    monitor_ping(ctx);
    return ctx->promise.future();
  }

  static void eventloop_stop(EventLoop* ctx)
  {
    ctx->stop();
    delete ctx;
  }

  static EventLoop* _netEventLoop = 0;
  static EventLoop* _objEventLoop = 0;
  static EventLoop* _poolEventLoop = 0;
  static double _monitorInterval = 0;

  static void monitor_notify(const char* which)
  {
    qiLogError() << which << " event loop stuck?";
  }
  static EventLoop* _get(EventLoop* &ctx, bool isPool)
  {
    if (!ctx)
    {
      if (! qi::Application::initialized())
      {
        qiLogInfo() << "Creating event loop while no qi::Application() is running";
      }
      ctx = new EventLoop();
      if (isPool)
        ctx->startThreadPool();
      else
        ctx->start();
      Application::atExit(boost::bind(&eventloop_stop, ctx));
      if (!isPool && _netEventLoop && _objEventLoop && _monitorInterval)
      {
        int64_t d = static_cast<qi::int64_t>(_monitorInterval * 1e6);
        _netEventLoop->monitorEventLoop(_objEventLoop, d)
          .connect(boost::bind(&monitor_notify, "network"));
        _objEventLoop->monitorEventLoop(_netEventLoop, d)
          .connect(boost::bind(&monitor_notify, "object"));
      }
    }
    return ctx;
  }

  EventLoop* getDefaultNetworkEventLoop()
  {
    return _get(_netEventLoop, false);
  }

  EventLoop* getDefaultObjectEventLoop()
  {
    return _get(_objEventLoop, false);
  }

  EventLoop* getDefaultThreadPoolEventLoop()
  {
    return _get(_poolEventLoop, true);
  }
  static void setMonitorInterval(double v)
  {
    _monitorInterval = v;
  }
  namespace {
  _QI_COMMAND_LINE_OPTIONS(
    "EventLoop monitoring",
    ("loop-monitor-latency", value<double>()->notifier(&setMonitorInterval), "Warn if event loop is stuck more than given duration in seconds")
    )
  }
}
<|endoftext|>


<commit_before>// (C) Copyright 2017, Google Inc.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "commandlineflags.h"
#include "fileio.h"
#include "include_gunit.h"
#include "ligature_table.h"
#include "pango_font_info.h"

namespace tesseract {

const char kEngNonLigatureText[] = "fidelity effigy ſteep";
// Same as above text, but with "fi" in the first word and "ffi" in the second
// word replaced with their respective ligatures.
const char kEngLigatureText[] = "ﬁdelity eﬃgy ﬅeep";
// Same as kEngLigatureText but with "fi" in both words replaced with their
// ligature. The test Verdana font does not support the "ffi" or "ſt" ligature.
const char kRenderableEngLigatureText[] = "ﬁdelity efﬁgy ſteep";

static PangoFontMap* font_map;

class LigatureTableTest : public ::testing::Test {
 protected:
 void SetUp() override {
    static std::locale system_locale("");
    std::locale::global(system_locale);
    file::MakeTmpdir();

    lig_table_ = LigatureTable::Get();
    if (!font_map) {
      font_map = pango_cairo_font_map_new_for_font_type(CAIRO_FONT_TYPE_FT);
    }
    pango_cairo_font_map_set_default(PANGO_CAIRO_FONT_MAP(font_map));
  }

  static void SetUpTestCase() {
    FLAGS_fonts_dir = TESTING_DIR;
    FLAGS_fontconfig_tmpdir = FLAGS_test_tmpdir;
    file::MakeTmpdir();
    PangoFontInfo::SoftInitFontConfig(); // init early
  }
  LigatureTable* lig_table_;
};

TEST_F(LigatureTableTest, DoesFillLigatureTables) {
  EXPECT_GT(lig_table_->norm_to_lig_table().size(), 0);
  EXPECT_GT(lig_table_->lig_to_norm_table().size(), 0);
}

TEST_F(LigatureTableTest, DoesAddLigatures) {
  EXPECT_STREQ(kEngLigatureText,
               lig_table_->AddLigatures(kEngNonLigatureText, nullptr).c_str());
}

TEST_F(LigatureTableTest, DoesAddLigaturesWithSupportedFont) {
  PangoFontInfo font;
  EXPECT_TRUE(font.ParseFontDescriptionName("Verdana"));
printf("1:%s\n", kRenderableEngLigatureText);
printf("2:%s\n", lig_table_->AddLigatures(kEngNonLigatureText, &font).c_str());
  EXPECT_STREQ(kRenderableEngLigatureText,
               lig_table_->AddLigatures(kEngNonLigatureText, &font).c_str());
}

TEST_F(LigatureTableTest, DoesNotAddLigaturesWithUnsupportedFont) {
  PangoFontInfo font;
  EXPECT_TRUE(font.ParseFontDescriptionName("Lohit Hindi"));
  EXPECT_STREQ(kEngNonLigatureText,
               lig_table_->AddLigatures(kEngNonLigatureText, &font).c_str());
}

TEST_F(LigatureTableTest, DoesRemoveLigatures) {
  EXPECT_STREQ(kEngNonLigatureText,
               lig_table_->RemoveLigatures(kEngLigatureText).c_str());
}

TEST_F(LigatureTableTest, TestCustomLigatures) {
  const char* kTestCases[] = {
      "act",       "a\uE003", "publiſh",    "publi\uE006", "ſince",
      "\uE007nce", "aſleep",  "a\uE008eep", "neceſſary",   "nece\uE009ary",
  };
  for (size_t i = 0; i < ARRAYSIZE(kTestCases); i += 2) {
    EXPECT_STREQ(kTestCases[i + 1],
                 lig_table_->AddLigatures(kTestCases[i], nullptr).c_str());
    EXPECT_STREQ(kTestCases[i],
                 lig_table_->RemoveLigatures(kTestCases[i + 1]).c_str());
    EXPECT_STREQ(kTestCases[i],
                 lig_table_->RemoveCustomLigatures(kTestCases[i + 1]).c_str());
  }
}

TEST_F(LigatureTableTest, TestRemovesCustomLigatures) {
  const char* kTestCases[] = {
      "fiction",
      "ﬁ\uE003ion",
      "ﬁction",
  };
  for (size_t i = 0; i < ARRAYSIZE(kTestCases); i += 3) {
    EXPECT_STREQ(kTestCases[i + 1],
                 lig_table_->AddLigatures(kTestCases[i], nullptr).c_str());
    EXPECT_STREQ(kTestCases[i + 2],
                 lig_table_->RemoveCustomLigatures(kTestCases[i + 1]).c_str());
  }
}
}  // namespace
<commit_msg>Fix ligature_table_test<commit_after>// (C) Copyright 2017, Google Inc.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "commandlineflags.h"
#include "fileio.h"
#include "include_gunit.h"
#include "ligature_table.h"
#include "pango_font_info.h"

namespace tesseract {

const char kEngNonLigatureText[] = "fidelity effigy ſteep";
// Same as above text, but with "fi" in the first word and "ffi" in the second
// word replaced with their respective ligatures.
const char kEngLigatureText[] = "ﬁdelity eﬃgy ﬅeep";
// Same as kEngLigatureText but with "fi" in both words replaced with their
// ligature. The test Verdana font does not support the "ffi" or "ſt" ligature.
const char kRenderableEngLigatureText[] = "ﬁdelity efﬁgy ſteep";

static PangoFontMap* font_map;

class LigatureTableTest : public ::testing::Test {
 protected:
 void SetUp() override {
    lig_table_ = LigatureTable::Get();
    if (!font_map) {
      font_map = pango_cairo_font_map_new_for_font_type(CAIRO_FONT_TYPE_FT);
    }
    pango_cairo_font_map_set_default(PANGO_CAIRO_FONT_MAP(font_map));
  }

  static void SetUpTestCase() {
    static std::locale system_locale("");
    std::locale::global(system_locale);

    FLAGS_fonts_dir = TESTING_DIR;
    FLAGS_fontconfig_tmpdir = FLAGS_test_tmpdir;
    file::MakeTmpdir();
    PangoFontInfo::SoftInitFontConfig(); // init early
  }
  LigatureTable* lig_table_;
};

TEST_F(LigatureTableTest, DoesFillLigatureTables) {
  EXPECT_GT(lig_table_->norm_to_lig_table().size(), 0);
  EXPECT_GT(lig_table_->lig_to_norm_table().size(), 0);
}

TEST_F(LigatureTableTest, DoesAddLigatures) {
  EXPECT_STREQ(kEngLigatureText,
               lig_table_->AddLigatures(kEngNonLigatureText, nullptr).c_str());
}

TEST_F(LigatureTableTest, DoesAddLigaturesWithSupportedFont) {
  PangoFontInfo font;
  EXPECT_TRUE(font.ParseFontDescriptionName("Verdana"));
printf("1:%s\n", kRenderableEngLigatureText);
printf("2:%s\n", lig_table_->AddLigatures(kEngNonLigatureText, &font).c_str());
  EXPECT_STREQ(kRenderableEngLigatureText,
               lig_table_->AddLigatures(kEngNonLigatureText, &font).c_str());
}

TEST_F(LigatureTableTest, DoesNotAddLigaturesWithUnsupportedFont) {
  PangoFontInfo font;
  EXPECT_TRUE(font.ParseFontDescriptionName("Lohit Hindi"));
  EXPECT_STREQ(kEngNonLigatureText,
               lig_table_->AddLigatures(kEngNonLigatureText, &font).c_str());
}

TEST_F(LigatureTableTest, DoesRemoveLigatures) {
  EXPECT_STREQ(kEngNonLigatureText,
               lig_table_->RemoveLigatures(kEngLigatureText).c_str());
}

TEST_F(LigatureTableTest, TestCustomLigatures) {
  const char* kTestCases[] = {
      "act",       "a\uE003", "publiſh",    "publi\uE006", "ſince",
      "\uE007nce", "aſleep",  "a\uE008eep", "neceſſary",   "nece\uE009ary",
  };
  for (size_t i = 0; i < ARRAYSIZE(kTestCases); i += 2) {
    EXPECT_STREQ(kTestCases[i + 1],
                 lig_table_->AddLigatures(kTestCases[i], nullptr).c_str());
    EXPECT_STREQ(kTestCases[i],
                 lig_table_->RemoveLigatures(kTestCases[i + 1]).c_str());
    EXPECT_STREQ(kTestCases[i],
                 lig_table_->RemoveCustomLigatures(kTestCases[i + 1]).c_str());
  }
}

TEST_F(LigatureTableTest, TestRemovesCustomLigatures) {
  const char* kTestCases[] = {
      "fiction",
      "ﬁ\uE003ion",
      "ﬁction",
  };
  for (size_t i = 0; i < ARRAYSIZE(kTestCases); i += 3) {
    EXPECT_STREQ(kTestCases[i + 1],
                 lig_table_->AddLigatures(kTestCases[i], nullptr).c_str());
    EXPECT_STREQ(kTestCases[i + 2],
                 lig_table_->RemoveCustomLigatures(kTestCases[i + 1]).c_str());
  }
}
}  // namespace
<|endoftext|>


<commit_before>/*

Copyright (c) 2006, Arvid Norberg
All rights reserved.

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

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/version.hpp>
#include "libtorrent/pch.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/error_code.hpp"

namespace libtorrent
{
	boost::shared_ptr<file> file_pool::open_file(void* st, fs::path const& p
		, int m, error_code& ec)
	{
		TORRENT_ASSERT(st != 0);
		TORRENT_ASSERT(p.is_complete());
		TORRENT_ASSERT((m & file::rw_mask) == file::read_only
			|| (m & file::rw_mask) == file::read_write);
		boost::mutex::scoped_lock l(m_mutex);
		file_set::iterator i = m_files.find(p.string());
		if (i != m_files.end())
		{
			lru_file_entry& e = i->second;
			e.last_use = time_now();

			if (e.key != st && ((e.mode & file::rw_mask) != file::read_only
				|| (m & file::rw_mask) != file::read_only))
			{
				// this means that another instance of the storage
				// is using the exact same file.
#if BOOST_VERSION >= 103500
				ec = error_code(errors::file_collision, libtorrent_category);
#endif
				return boost::shared_ptr<file>();
			}

			e.key = st;
			// if we asked for a file in write mode,
			// and the cached file is is not opened in
			// write mode, re-open it
			if (((e.mode & file::rw_mask) != file::read_write)
				&& ((m & file::rw_mask) == file::read_write))
			{
				// close the file before we open it with
				// the new read/write privilages
				TORRENT_ASSERT(e.file_ptr.unique());
				e.file_ptr->close();
				if (!e.file_ptr->open(p, m, ec))
				{
					m_files.erase(i);
					return boost::shared_ptr<file>();
				}
				TORRENT_ASSERT(e.file_ptr->is_open());
				e.mode = m;
			}
			TORRENT_ASSERT((e.mode & file::no_buffer) == (m & file::no_buffer));
			return e.file_ptr;
		}
		// the file is not in our cache
		if ((int)m_files.size() >= m_size)
		{
			// the file cache is at its maximum size, close
			// the least recently used (lru) file from it
			remove_oldest();
		}
		lru_file_entry e;
		e.file_ptr.reset(new (std::nothrow)file);
		if (!e.file_ptr)
		{
			ec = error_code(ENOMEM, get_posix_category());
			return e.file_ptr;
		}
		if (!e.file_ptr->open(p, m, ec))
			return boost::shared_ptr<file>();
		e.mode = m;
		e.key = st;
		m_files.insert(std::make_pair(p.string(), e));
		TORRENT_ASSERT(e.file_ptr->is_open());
		return e.file_ptr;
	}

	void file_pool::remove_oldest()
	{
		file_set::iterator i = std::min_element(m_files.begin(), m_files.end()
			, boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _1))
				< boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _2)));
		if (i == m_files.end()) return;
		m_files.erase(i);
	}

	void file_pool::release(fs::path const& p)
	{
		boost::mutex::scoped_lock l(m_mutex);

		file_set::iterator i = m_files.find(p.string());
		if (i != m_files.end()) m_files.erase(i);
	}

	void file_pool::release(void* st)
	{
		boost::mutex::scoped_lock l(m_mutex);
		TORRENT_ASSERT(st != 0);

		for (file_set::iterator i = m_files.begin();
			i != m_files.end();)
		{
			if (i->second.key == st)
				m_files.erase(i++);
			else
				++i;
		}
	}

	void file_pool::resize(int size)
	{
		TORRENT_ASSERT(size > 0);
		if (size == m_size) return;
		boost::mutex::scoped_lock l(m_mutex);
		m_size = size;
		if (int(m_files.size()) <= m_size) return;

		// close the least recently used files
		while (int(m_files.size()) > m_size)
			remove_oldest();
	}

}
<commit_msg>added missing include<commit_after>/*

Copyright (c) 2006, Arvid Norberg
All rights reserved.

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

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include <boost/version.hpp>
#include <boost/bind.hpp>
#include "libtorrent/pch.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/error_code.hpp"

namespace libtorrent
{
	boost::shared_ptr<file> file_pool::open_file(void* st, fs::path const& p
		, int m, error_code& ec)
	{
		TORRENT_ASSERT(st != 0);
		TORRENT_ASSERT(p.is_complete());
		TORRENT_ASSERT((m & file::rw_mask) == file::read_only
			|| (m & file::rw_mask) == file::read_write);
		boost::mutex::scoped_lock l(m_mutex);
		file_set::iterator i = m_files.find(p.string());
		if (i != m_files.end())
		{
			lru_file_entry& e = i->second;
			e.last_use = time_now();

			if (e.key != st && ((e.mode & file::rw_mask) != file::read_only
				|| (m & file::rw_mask) != file::read_only))
			{
				// this means that another instance of the storage
				// is using the exact same file.
#if BOOST_VERSION >= 103500
				ec = error_code(errors::file_collision, libtorrent_category);
#endif
				return boost::shared_ptr<file>();
			}

			e.key = st;
			// if we asked for a file in write mode,
			// and the cached file is is not opened in
			// write mode, re-open it
			if (((e.mode & file::rw_mask) != file::read_write)
				&& ((m & file::rw_mask) == file::read_write))
			{
				// close the file before we open it with
				// the new read/write privilages
				TORRENT_ASSERT(e.file_ptr.unique());
				e.file_ptr->close();
				if (!e.file_ptr->open(p, m, ec))
				{
					m_files.erase(i);
					return boost::shared_ptr<file>();
				}
				TORRENT_ASSERT(e.file_ptr->is_open());
				e.mode = m;
			}
			TORRENT_ASSERT((e.mode & file::no_buffer) == (m & file::no_buffer));
			return e.file_ptr;
		}
		// the file is not in our cache
		if ((int)m_files.size() >= m_size)
		{
			// the file cache is at its maximum size, close
			// the least recently used (lru) file from it
			remove_oldest();
		}
		lru_file_entry e;
		e.file_ptr.reset(new (std::nothrow)file);
		if (!e.file_ptr)
		{
			ec = error_code(ENOMEM, get_posix_category());
			return e.file_ptr;
		}
		if (!e.file_ptr->open(p, m, ec))
			return boost::shared_ptr<file>();
		e.mode = m;
		e.key = st;
		m_files.insert(std::make_pair(p.string(), e));
		TORRENT_ASSERT(e.file_ptr->is_open());
		return e.file_ptr;
	}

	void file_pool::remove_oldest()
	{
		file_set::iterator i = std::min_element(m_files.begin(), m_files.end()
			, boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _1))
				< boost::bind(&lru_file_entry::last_use, boost::bind(&file_set::value_type::second, _2)));
		if (i == m_files.end()) return;
		m_files.erase(i);
	}

	void file_pool::release(fs::path const& p)
	{
		boost::mutex::scoped_lock l(m_mutex);

		file_set::iterator i = m_files.find(p.string());
		if (i != m_files.end()) m_files.erase(i);
	}

	void file_pool::release(void* st)
	{
		boost::mutex::scoped_lock l(m_mutex);
		TORRENT_ASSERT(st != 0);

		for (file_set::iterator i = m_files.begin();
			i != m_files.end();)
		{
			if (i->second.key == st)
				m_files.erase(i++);
			else
				++i;
		}
	}

	void file_pool::resize(int size)
	{
		TORRENT_ASSERT(size > 0);
		if (size == m_size) return;
		boost::mutex::scoped_lock l(m_mutex);
		m_size = size;
		if (int(m_files.size()) <= m_size) return;

		// close the least recently used files
		while (int(m_files.size()) > m_size)
			remove_oldest();
	}

}
<|endoftext|>


<commit_before>/*
 * This is mcs; a modular configuration system.
 *
 * Copyright (c) 2007 Diego Pettenò <flameeyes@gmail.com>
 * Copyright (c) 2007 William Pitcock <nenolod@sacredspiral.co.uk>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <kconfig.h>
#include <kapplication.h>
#include <kcmdlineargs.h>
#include <assert.h>

extern "C" {

  #include "libmcs/mcs.h"

/* ***************************************************************** */

  extern mcs_backend_t mcs_backend;
}

typedef struct {
	KConfig *cfg;
} mcs_kconfig_handle_t;

namespace {

	mcs_handle_t *
	mcs_kconfig_new(char *domain)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *)calloc(sizeof(mcs_kconfig_handle_t), 1);
		mcs_handle_t *out = (mcs_handle_t *)calloc(sizeof(mcs_handle_t), 1);

		if (!KApplication::kApplication())
		{
	  		/* Initialise a fake KDE application if none present */
			static char *fake_argv[] = { "mcs_backend" };

			KCmdLineArgs::init(1, fake_argv, "mcs_backend", "MCS KConfig Backend",
				"Just a fake application to be able to use KConfig backend with non-KDE applications.",
				"9999", false);
			new KApplication(false, false);
		}

		out->base = &mcs_backend;
		out->mcs_priv_handle = h;

		h->cfg = new KConfig(domain);

		return out;
	}

	void
	mcs_kconfig_destroy(mcs_handle_t *self)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		delete h->cfg;
		free(h);

		free(self);
	}

	mcs_response_t
	mcs_kconfig_get_string(mcs_handle_t *self, const char *section,
			       const char *key, char **value)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		if ( ! h->cfg->hasGroup(section) )
			return MCS_FAIL;

		h->cfg->setGroup(section);
		if ( ! h->cfg->hasKey(key) )
			return MCS_FAIL;

		QString entry = h->cfg->readEntry(key);
		*value = strdup(entry.latin1());

		return MCS_OK;
	}

	mcs_response_t
	mcs_kconfig_get_int(mcs_handle_t *self, const char *section,
		    const char *key, int *value)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		if ( ! h->cfg->hasGroup(section) )
			return MCS_FAIL;

		h->cfg->setGroup(section);
		if ( ! h->cfg->hasKey(key) )
			return MCS_FAIL;

		*value = h->cfg->readNumEntry(key);

		return MCS_OK;
	}

	mcs_response_t
	mcs_kconfig_get_bool(mcs_handle_t *self, const char *section,
			     const char *key, int *value)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		if ( ! h->cfg->hasGroup(section) )
			return MCS_FAIL;

		h->cfg->setGroup(section);
		if ( ! h->cfg->hasKey(key) )
			return MCS_FAIL;

		*value = h->cfg->readBoolEntry(key);

		return MCS_OK;
	}

	mcs_response_t
	mcs_kconfig_get_float(mcs_handle_t *self, const char *section,
			      const char *key, float *value)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		if ( ! h->cfg->hasGroup(section) )
			return MCS_FAIL;

		h->cfg->setGroup(section);
		if ( ! h->cfg->hasKey(key) )
			return MCS_FAIL;

		*value = (float)(h->cfg->readDoubleNumEntry(key));

		return MCS_OK;
	}

	mcs_response_t
	mcs_kconfig_get_double(mcs_handle_t *self, const char *section,
			       const char *key, double *value)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		if ( ! h->cfg->hasGroup(section) )
			return MCS_FAIL;

		h->cfg->setGroup(section);
		if ( ! h->cfg->hasKey(key) )
			return MCS_FAIL;

		*value = h->cfg->readDoubleNumEntry(key);

		return MCS_OK;
	}

	mcs_response_t
	mcs_kconfig_set_string(mcs_handle_t *self, const char *section,
			       const char *key, const char *value)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		h->cfg->setGroup(section);
		if ( ! value )
			h->cfg->writeEntry(key, QString::null);
		else
			h->cfg->writeEntry(key, value);

		return MCS_OK;
	}

	mcs_response_t
	mcs_kconfig_set_int(mcs_handle_t *self, const char *section,
			    const char *key, int value)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		h->cfg->setGroup(section);
		h->cfg->writeEntry(key, value);

		return MCS_OK;
	}

	mcs_response_t
	mcs_kconfig_set_bool(mcs_handle_t *self, const char *section,
			     const char *key, int value)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		h->cfg->setGroup(section);
		h->cfg->writeEntry(key, bool(value));

		return MCS_OK;
	}

	mcs_response_t
	mcs_kconfig_set_float(mcs_handle_t *self, const char *section,
			      const char *key, float value)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		h->cfg->setGroup(section);
		h->cfg->writeEntry(key, value);

		return MCS_OK;
	}

	mcs_response_t
	mcs_kconfig_set_double(mcs_handle_t *self, const char *section,
			       const char *key, double value)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		h->cfg->setGroup(section);
		h->cfg->writeEntry(key, value);

		return MCS_OK;
	}

	mcs_response_t
	mcs_kconfig_unset_key(mcs_handle_t *self, const char *section,
			      const char *key)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		h->cfg->deleteEntry(section, key);

		return MCS_OK;
	}

	mowgli_queue_t *
	mcs_kconfig_get_keys(mcs_handle_t *self, const char *section)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;
		mowgli_queue_t *out = NULL;

		//  <key    , value  >
		QMap<QString, QString> map = h->cfg->entryMap(section);

		for (QMap<QString, QString>::const_iterator i = map.constBegin();
			i != map.constEnd(); i++)
		{
			QString str = i.key();

			out = mowgli_queue_shift(out, strdup(str.local8Bit()));
		}

		return out;
	}

	mowgli_queue_t *
	mcs_kconfig_get_groups(mcs_handle_t *self)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;
		mowgli_queue_t *out = NULL;

		QStringList list = h->cfg->groupList();

		for (QStringList::const_iterator i = list.constBegin();
			i != list.constEnd(); i++)
		{
			QString str = *i;

			out = mowgli_queue_shift(out, strdup(str.local8Bit()));
		}

		return out;
	}
};

mcs_backend_t mcs_backend = {
	NULL,
	"kconfig",
	mcs_kconfig_new,
	mcs_kconfig_destroy,

	mcs_kconfig_get_string,
	mcs_kconfig_get_int,
	mcs_kconfig_get_bool,
	mcs_kconfig_get_float,
	mcs_kconfig_get_double,

	mcs_kconfig_set_string,
	mcs_kconfig_set_int,
	mcs_kconfig_set_bool,
	mcs_kconfig_set_float,
	mcs_kconfig_set_double,

	mcs_kconfig_unset_key,

	mcs_kconfig_get_keys,
	mcs_kconfig_get_groups
};
<commit_msg>work around a qt3 namespace bug<commit_after>/*
 * This is mcs; a modular configuration system.
 *
 * Copyright (c) 2007 Diego Pettenò <flameeyes@gmail.com>
 * Copyright (c) 2007 William Pitcock <nenolod@sacredspiral.co.uk>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

extern "C" {

  #include "libmcs/mcs.h"

/* ***************************************************************** */

  extern mcs_backend_t mcs_backend;
}

/* Work around a stupid Qt3 namespace bug. */
#undef FALSE
#undef TRUE

#include <kconfig.h>
#include <kapplication.h>
#include <kcmdlineargs.h>
#include <assert.h>

typedef struct {
	KConfig *cfg;
} mcs_kconfig_handle_t;

namespace {

	mcs_handle_t *
	mcs_kconfig_new(char *domain)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *)calloc(sizeof(mcs_kconfig_handle_t), 1);
		mcs_handle_t *out = (mcs_handle_t *)calloc(sizeof(mcs_handle_t), 1);

		if (!KApplication::kApplication())
		{
	  		/* Initialise a fake KDE application if none present */
			static char *fake_argv[] = { "mcs_backend" };

			KCmdLineArgs::init(1, fake_argv, "mcs_backend", "MCS KConfig Backend",
				"Just a fake application to be able to use KConfig backend with non-KDE applications.",
				"9999", false);
			new KApplication(false, false);
		}

		out->base = &mcs_backend;
		out->mcs_priv_handle = h;

		h->cfg = new KConfig(domain);

		return out;
	}

	void
	mcs_kconfig_destroy(mcs_handle_t *self)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		delete h->cfg;
		free(h);

		free(self);
	}

	mcs_response_t
	mcs_kconfig_get_string(mcs_handle_t *self, const char *section,
			       const char *key, char **value)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		if ( ! h->cfg->hasGroup(section) )
			return MCS_FAIL;

		h->cfg->setGroup(section);
		if ( ! h->cfg->hasKey(key) )
			return MCS_FAIL;

		QString entry = h->cfg->readEntry(key);
		*value = strdup(entry.latin1());

		return MCS_OK;
	}

	mcs_response_t
	mcs_kconfig_get_int(mcs_handle_t *self, const char *section,
		    const char *key, int *value)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		if ( ! h->cfg->hasGroup(section) )
			return MCS_FAIL;

		h->cfg->setGroup(section);
		if ( ! h->cfg->hasKey(key) )
			return MCS_FAIL;

		*value = h->cfg->readNumEntry(key);

		return MCS_OK;
	}

	mcs_response_t
	mcs_kconfig_get_bool(mcs_handle_t *self, const char *section,
			     const char *key, int *value)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		if ( ! h->cfg->hasGroup(section) )
			return MCS_FAIL;

		h->cfg->setGroup(section);
		if ( ! h->cfg->hasKey(key) )
			return MCS_FAIL;

		*value = h->cfg->readBoolEntry(key);

		return MCS_OK;
	}

	mcs_response_t
	mcs_kconfig_get_float(mcs_handle_t *self, const char *section,
			      const char *key, float *value)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		if ( ! h->cfg->hasGroup(section) )
			return MCS_FAIL;

		h->cfg->setGroup(section);
		if ( ! h->cfg->hasKey(key) )
			return MCS_FAIL;

		*value = (float)(h->cfg->readDoubleNumEntry(key));

		return MCS_OK;
	}

	mcs_response_t
	mcs_kconfig_get_double(mcs_handle_t *self, const char *section,
			       const char *key, double *value)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		if ( ! h->cfg->hasGroup(section) )
			return MCS_FAIL;

		h->cfg->setGroup(section);
		if ( ! h->cfg->hasKey(key) )
			return MCS_FAIL;

		*value = h->cfg->readDoubleNumEntry(key);

		return MCS_OK;
	}

	mcs_response_t
	mcs_kconfig_set_string(mcs_handle_t *self, const char *section,
			       const char *key, const char *value)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		h->cfg->setGroup(section);
		if ( ! value )
			h->cfg->writeEntry(key, QString::null);
		else
			h->cfg->writeEntry(key, value);

		return MCS_OK;
	}

	mcs_response_t
	mcs_kconfig_set_int(mcs_handle_t *self, const char *section,
			    const char *key, int value)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		h->cfg->setGroup(section);
		h->cfg->writeEntry(key, value);

		return MCS_OK;
	}

	mcs_response_t
	mcs_kconfig_set_bool(mcs_handle_t *self, const char *section,
			     const char *key, int value)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		h->cfg->setGroup(section);
		h->cfg->writeEntry(key, bool(value));

		return MCS_OK;
	}

	mcs_response_t
	mcs_kconfig_set_float(mcs_handle_t *self, const char *section,
			      const char *key, float value)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		h->cfg->setGroup(section);
		h->cfg->writeEntry(key, value);

		return MCS_OK;
	}

	mcs_response_t
	mcs_kconfig_set_double(mcs_handle_t *self, const char *section,
			       const char *key, double value)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		h->cfg->setGroup(section);
		h->cfg->writeEntry(key, value);

		return MCS_OK;
	}

	mcs_response_t
	mcs_kconfig_unset_key(mcs_handle_t *self, const char *section,
			      const char *key)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;

		h->cfg->deleteEntry(section, key);

		return MCS_OK;
	}

	mowgli_queue_t *
	mcs_kconfig_get_keys(mcs_handle_t *self, const char *section)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;
		mowgli_queue_t *out = NULL;

		//  <key    , value  >
		QMap<QString, QString> map = h->cfg->entryMap(section);

		for (QMap<QString, QString>::const_iterator i = map.constBegin();
			i != map.constEnd(); i++)
		{
			QString str = i.key();

			out = mowgli_queue_shift(out, strdup(str.local8Bit()));
		}

		return out;
	}

	mowgli_queue_t *
	mcs_kconfig_get_groups(mcs_handle_t *self)
	{
		mcs_kconfig_handle_t *h = (mcs_kconfig_handle_t *) self->mcs_priv_handle;
		mowgli_queue_t *out = NULL;

		QStringList list = h->cfg->groupList();

		for (QStringList::const_iterator i = list.constBegin();
			i != list.constEnd(); i++)
		{
			QString str = *i;

			out = mowgli_queue_shift(out, strdup(str.local8Bit()));
		}

		return out;
	}
};

mcs_backend_t mcs_backend = {
	NULL,
	"kconfig",
	mcs_kconfig_new,
	mcs_kconfig_destroy,

	mcs_kconfig_get_string,
	mcs_kconfig_get_int,
	mcs_kconfig_get_bool,
	mcs_kconfig_get_float,
	mcs_kconfig_get_double,

	mcs_kconfig_set_string,
	mcs_kconfig_set_int,
	mcs_kconfig_set_bool,
	mcs_kconfig_set_float,
	mcs_kconfig_set_double,

	mcs_kconfig_unset_key,

	mcs_kconfig_get_keys,
	mcs_kconfig_get_groups
};
<|endoftext|>


<commit_before>#ifndef __lxmaths__
#define __lxmaths__

#include "lxstack.hpp"
#include "lxtable.hpp"
#include <complex>
#include <cmath>

template <class Base> using complex<Base> = std::complex<Base>;

template <class Base> inline
void lux_push<complex<Base>>(lua_State *state, complex<Base> value)
{
	lua_newtable(state);
	lux_Table table(state);
	table<Base>("real", value.real());
	table<Base>("imag", value.imag());
}

template <class Base> inline
complex<Base> lux_opt<complex<Base>>(lua_State *state, int stack, complex<Base> opt)
{
	if (lua_istable(state, stack))
	{
		lux_Table table(state, stack);
		opt.real(table<Base>("real"));
		opt.imag(table<Base>("imag"));
	}
	return opt;
}

template <class Base> inline
complex<Base> lux_to<complex<Base>>(lua_State *state, int stack)
{
	lux_Table tab(state, stack);
	return complex<Base>(table<Base>("real"), table<Base>("imag"));
}

#endif // file
<commit_msg>Removed experimental file<commit_after><|endoftext|>