<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//  Credits:
//  I gratefully acknowledge the inspiring work of Maxim Shemanarev (McSeem),
//  author of Anti-Grain Geometry (http://www.antigrain.com). I have used
//  the datastructure from AGG as a template for my own.

#ifndef MAPNIK_VERTEX_VECTOR_HPP
#define MAPNIK_VERTEX_VECTOR_HPP

// mapnik
#include <mapnik/vertex.hpp>
#include <mapnik/noncopyable.hpp>

// stl
#include <tuple>
#include <cstring>  // required for memcpy with linux/g++

namespace mapnik
{

template <typename T>
class vertex_vector : private mapnik::noncopyable
{
    using coord_type = T;
    enum block_e {
        block_shift = 8,
        block_size  = 1<<block_shift,
        block_mask  = block_size - 1,
        grow_by     = 256
    };
public:
    // required for iterators support
    using value_type = std::tuple<unsigned,coord_type,coord_type>;
    using size_type = std::size_t;
    using command_size = std::uint8_t;
private:
    unsigned num_blocks_;
    unsigned max_blocks_;
    coord_type** vertices_;
    command_size** commands_;
    size_type pos_;

public:

    vertex_vector()
        : num_blocks_(0),
          max_blocks_(0),
          vertices_(0),
          commands_(0),
          pos_(0) {}

    ~vertex_vector()
    {
        if ( num_blocks_ )
        {
            coord_type** vertices=vertices_ + num_blocks_ - 1;
            while ( num_blocks_-- )
            {
                ::operator delete(*vertices);
                --vertices;
            }
            ::operator delete(vertices_);
        }
    }
    size_type size() const
    {
        return pos_;
    }

    void push_back (coord_type x,coord_type y,command_size command)
    {
        size_type block = pos_ >> block_shift;
        if (block >= num_blocks_)
        {
            allocate_block(block);
        }
        coord_type* vertex = vertices_[block] + ((pos_ & block_mask) << 1);
        command_size* cmd= commands_[block] + (pos_ & block_mask);

        *cmd = static_cast<command_size>(command);
        *vertex++ = x;
        *vertex   = y;
        ++pos_;
    }
    unsigned get_vertex(unsigned pos,coord_type* x,coord_type* y) const
    {
        if (pos >= pos_) return SEG_END;
        size_type block = pos >> block_shift;
        const coord_type* vertex = vertices_[block] + (( pos & block_mask) << 1);
        *x = (*vertex++);
        *y = (*vertex);
        return commands_[block] [pos & block_mask];
    }

    void set_command(unsigned pos, unsigned command)
    {
        if (pos < pos_)
        {
            size_type block = pos >> block_shift;
            commands_[block] [pos & block_mask] = command;
        }
    }
private:
    void allocate_block(size_type block)
    {
        if (block >= max_blocks_)
        {
            coord_type** new_vertices =
                static_cast<coord_type**>(::operator new (sizeof(coord_type*)*((max_blocks_ + grow_by) * 2)));
            command_size** new_commands = (command_size**)(new_vertices + max_blocks_ + grow_by);
            if (vertices_)
            {
                std::memcpy(new_vertices,vertices_,max_blocks_ * sizeof(coord_type*));
                std::memcpy(new_commands,commands_,max_blocks_ * sizeof(command_size*));
                ::operator delete(vertices_);
            }
            vertices_ = new_vertices;
            commands_ = new_commands;
            max_blocks_ += grow_by;
        }
        vertices_[block] = static_cast<coord_type*>
            (::operator new(sizeof(coord_type)*(block_size * 2 + block_size / (sizeof(coord_type)))));

        commands_[block] = (command_size*)(vertices_[block] + block_size*2);
        ++num_blocks_;
    }
};

}

#endif // MAPNIK_VERTEX_VECTOR_HPP
<commit_msg>include <cstdint> - fixes msvs compile - refs #2396<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//  Credits:
//  I gratefully acknowledge the inspiring work of Maxim Shemanarev (McSeem),
//  author of Anti-Grain Geometry (http://www.antigrain.com). I have used
//  the datastructure from AGG as a template for my own.

#ifndef MAPNIK_VERTEX_VECTOR_HPP
#define MAPNIK_VERTEX_VECTOR_HPP

// mapnik
#include <mapnik/vertex.hpp>
#include <mapnik/noncopyable.hpp>

// stl
#include <tuple>
#include <cstring>  // required for memcpy with linux/g++
#include <cstdint>

namespace mapnik
{

template <typename T>
class vertex_vector : private mapnik::noncopyable
{
    using coord_type = T;
    enum block_e {
        block_shift = 8,
        block_size  = 1<<block_shift,
        block_mask  = block_size - 1,
        grow_by     = 256
    };
public:
    // required for iterators support
    using value_type = std::tuple<unsigned,coord_type,coord_type>;
    using size_type = std::size_t;
    using command_size = std::uint8_t;
private:
    unsigned num_blocks_;
    unsigned max_blocks_;
    coord_type** vertices_;
    command_size** commands_;
    size_type pos_;

public:

    vertex_vector()
        : num_blocks_(0),
          max_blocks_(0),
          vertices_(0),
          commands_(0),
          pos_(0) {}

    ~vertex_vector()
    {
        if ( num_blocks_ )
        {
            coord_type** vertices=vertices_ + num_blocks_ - 1;
            while ( num_blocks_-- )
            {
                ::operator delete(*vertices);
                --vertices;
            }
            ::operator delete(vertices_);
        }
    }
    size_type size() const
    {
        return pos_;
    }

    void push_back (coord_type x,coord_type y,command_size command)
    {
        size_type block = pos_ >> block_shift;
        if (block >= num_blocks_)
        {
            allocate_block(block);
        }
        coord_type* vertex = vertices_[block] + ((pos_ & block_mask) << 1);
        command_size* cmd= commands_[block] + (pos_ & block_mask);

        *cmd = static_cast<command_size>(command);
        *vertex++ = x;
        *vertex   = y;
        ++pos_;
    }
    unsigned get_vertex(unsigned pos,coord_type* x,coord_type* y) const
    {
        if (pos >= pos_) return SEG_END;
        size_type block = pos >> block_shift;
        const coord_type* vertex = vertices_[block] + (( pos & block_mask) << 1);
        *x = (*vertex++);
        *y = (*vertex);
        return commands_[block] [pos & block_mask];
    }

    void set_command(unsigned pos, unsigned command)
    {
        if (pos < pos_)
        {
            size_type block = pos >> block_shift;
            commands_[block] [pos & block_mask] = command;
        }
    }
private:
    void allocate_block(size_type block)
    {
        if (block >= max_blocks_)
        {
            coord_type** new_vertices =
                static_cast<coord_type**>(::operator new (sizeof(coord_type*)*((max_blocks_ + grow_by) * 2)));
            command_size** new_commands = (command_size**)(new_vertices + max_blocks_ + grow_by);
            if (vertices_)
            {
                std::memcpy(new_vertices,vertices_,max_blocks_ * sizeof(coord_type*));
                std::memcpy(new_commands,commands_,max_blocks_ * sizeof(command_size*));
                ::operator delete(vertices_);
            }
            vertices_ = new_vertices;
            commands_ = new_commands;
            max_blocks_ += grow_by;
        }
        vertices_[block] = static_cast<coord_type*>
            (::operator new(sizeof(coord_type)*(block_size * 2 + block_size / (sizeof(coord_type)))));

        commands_[block] = (command_size*)(vertices_[block] + block_size*2);
        ++num_blocks_;
    }
};

}

#endif // MAPNIK_VERTEX_VECTOR_HPP
<|endoftext|>


<commit_before>// Copyright Joshua Boyce 2010-2012.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// This file is part of HadesMem.
// <http://www.raptorfactor.com/> <raptorfactor@raptorfactor.com>

#pragma once

#include <vector>
#include <utility>
#include <type_traits>

#include "hadesmem/detail/warning_disable_prefix.hpp"
#include <boost/assert.hpp>
#include <boost/mpl/at.hpp>
#include <boost/preprocessor.hpp>
#include <boost/function_types/result_type.hpp>
#include <boost/function_types/function_arity.hpp>
#include <boost/function_types/parameter_types.hpp>
#include "hadesmem/detail/warning_disable_suffix.hpp"

#include <windows.h>

namespace hadesmem
{

class Process;

enum class CallConv
{
  kDefault,
  kCdecl,
  kStdCall,
  kThisCall,
  kFastCall,
  kX64
};

class RemoteFunctionRet
{
public:
  RemoteFunctionRet(DWORD_PTR return_int_ptr,
    DWORD64 return_int_64,
    float return_float,
    double return_double,
    DWORD last_error) BOOST_NOEXCEPT;

  DWORD_PTR GetReturnValue() const BOOST_NOEXCEPT;

  DWORD64 GetReturnValue64() const BOOST_NOEXCEPT;

  float GetReturnValueFloat() const BOOST_NOEXCEPT;

  double GetReturnValueDouble() const BOOST_NOEXCEPT;

  DWORD GetLastError() const BOOST_NOEXCEPT;

  template <typename T>
  T GetReturnValue() const BOOST_NOEXCEPT
  {
    static_assert(std::is_integral<T>::value ||
      std::is_pointer<T>::value ||
      std::is_same<float, typename std::remove_cv<T>::type>::value ||
      std::is_same<double, typename std::remove_cv<T>::type>::value,
      "Only integral, pointer, or floating point types are supported.");

    return GetReturnValueImpl(T());
  }

private:
  template <typename T>
  T GetReturnValueIntImpl(std::true_type const&) const BOOST_NOEXCEPT
  {
    union Conv
    {
      T t;
      DWORD64 d;
    };
    Conv conv;
    conv.d = GetReturnValue64();
    return conv.t;
  }

  template <typename T>
  T GetReturnValueIntImpl(std::false_type const&) const BOOST_NOEXCEPT
  {
    union Conv
    {
      T t;
      DWORD_PTR d;
    };
    Conv conv;
    conv.d = GetReturnValue();
    return conv.t;
  }

  template <typename T>
  T GetReturnValueImpl(T /*t*/) const BOOST_NOEXCEPT
  {
    return GetReturnValueIntImpl<T>(std::integral_constant<bool,
      (sizeof(T) == sizeof(DWORD64))>());
  }

  float GetReturnValueImpl(float /*t*/) const BOOST_NOEXCEPT
  {
    return GetReturnValueFloat();
  }

  double GetReturnValueImpl(double /*t*/) const BOOST_NOEXCEPT
  {
    return GetReturnValueDouble();
  }

  DWORD_PTR int_ptr_;
  DWORD64 int_64_;
  float float_;
  double double_;
  DWORD last_error_;
};

class CallArg
{
public:
  template <typename T>
  CallArg(T t) BOOST_NOEXCEPT
    : type_(ArgType::kPtrType),
    arg_()
  {
    static_assert(std::is_integral<T>::value ||
      std::is_pointer<T>::value ||
      std::is_same<float, typename std::remove_cv<T>::type>::value ||
      std::is_same<double, typename std::remove_cv<T>::type>::value,
      "Only integral, pointer, or floating point types are supported.");

    static_assert(sizeof(T) <= sizeof(void*) ||
      std::is_same<double, typename std::remove_cv<T>::type>::value ||
      (std::is_integral<T>::value && sizeof(T) <= sizeof(DWORD64)),
      "Currently only memsize (or smaller) types are supported (doubles "
      "and 64-bit integrals excepted).");

    Initialize(t);
  }

  template <typename V>
  void Visit(V* v) const
  {
    switch (type_)
    {
    case ArgType::kPtrType:
      (*v)(arg_.p);
      break;
    case ArgType::kFloatType:
      (*v)(arg_.f);
      break;
    case ArgType::kDoubleType:
      (*v)(arg_.d);
      break;
    case ArgType::kInt64Type:
      (*v)(arg_.i);
      break;
    default:
      BOOST_ASSERT("Invalid type." && false);
    }
  }

private:
  template <typename T>
  void InitializeIntegralImpl(T t, typename std::enable_if<sizeof(T) <=
    sizeof(DWORD_PTR)>::type* /*dummy*/ = 0) BOOST_NOEXCEPT
  {
    type_ = ArgType::kPtrType;
    union Conv
    {
      T t;
      void* p;
    };
    Conv conv;
    conv.t = t;
    arg_.p = conv.p;
  }

  template <typename T>
  void InitializeIntegralImpl(T t, typename std::enable_if<sizeof(void*) !=
    sizeof(DWORD64) && sizeof(T) == sizeof(DWORD64)>::type* /*dummy*/ = 0)
    BOOST_NOEXCEPT
  {
    type_ = ArgType::kInt64Type;
    union Conv
    {
      T t;
      DWORD64 i;
    };
    Conv conv;
    conv.t = t;
    arg_.i = conv.i;
  }

  template <typename T>
  void Initialize(T t, typename std::enable_if<std::is_integral<T>::value ||
    std::is_pointer<T>::value>::type* /*dummy*/ = nullptr) BOOST_NOEXCEPT
  {
    InitializeIntegralImpl(t);
  }

  template <typename T>
  void Initialize(T t, typename std::enable_if<std::is_same<float,
    typename std::remove_cv<T>::type>::value>::type* /*dummy*/ = nullptr)
    BOOST_NOEXCEPT
  {
    type_ = ArgType::kFloatType;
    arg_.f = t;
  }

  template <typename T>
  void Initialize(T t, typename std::enable_if<std::is_same<double,
    typename std::remove_cv<T>::type>::value>::type* /*dummy*/ = nullptr)
    BOOST_NOEXCEPT
  {
    type_ = ArgType::kDoubleType;
    arg_.d = t;
  }

  enum class ArgType
  {
    kPtrType,
    kFloatType,
    kDoubleType,
    kInt64Type
  };

  union Arg
  {
    void* p;
    float f;
    double d;
    DWORD64 i;
  };

  ArgType type_;
  Arg arg_;
};

RemoteFunctionRet Call(Process const& process,
  LPCVOID address,
  CallConv call_conv,
  std::vector<CallArg> const& args);

std::vector<RemoteFunctionRet> CallMulti(Process const& process,
  std::vector<LPCVOID> const& addresses,
  std::vector<CallConv> const& call_convs,
  std::vector<std::vector<CallArg>> const& args_full);

template <typename T>
struct VoidToInt
{
  typedef T type;
};

template <>
struct VoidToInt<void>
{
  typedef int type;
};

#ifndef HADESMEM_CALL_MAX_ARGS
#define HADESMEM_CALL_MAX_ARGS 20
#endif // #ifndef HADESMEM_CALL_MAX_ARGS

static_assert(HADESMEM_CALL_MAX_ARGS < BOOST_PP_LIMIT_REPEAT,
  "HADESMEM_CALL_MAX_ARGS exceeds Boost.Preprocessor repeat limit.");

static_assert(HADESMEM_CALL_MAX_ARGS < BOOST_PP_LIMIT_ITERATION,
  "HADESMEM_CALL_MAX_ARGS exceeds Boost.Preprocessor iteration limit.");

#define HADESMEM_CALL_ADD_ARG(z, n, unused) \
typedef typename boost::mpl::at_c<\
  boost::function_types::parameter_types<FuncT>, \
  n>::type A##n;\
static_assert(std::is_convertible<T##n, A##n>::value, \
  "Can not convert argument to type specified in function prototype.");\
A##n a##n = t##n;\
args.push_back(a##n);\

#define BOOST_PP_LOCAL_MACRO(n)\
template <typename FuncT BOOST_PP_ENUM_TRAILING_PARAMS(n, typename T)>\
std::pair<typename VoidToInt<\
  typename boost::function_types::result_type<FuncT>::type>::type, DWORD> \
  Call(Process const& process, LPCVOID address, CallConv call_conv \
  BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(n, T, t))\
{\
  static_assert(boost::function_types::function_arity<FuncT>::value == n, \
    "Invalid number of arguments.");\
  std::vector<CallArg> args;\
  BOOST_PP_REPEAT(n, HADESMEM_CALL_ADD_ARG, ~)\
  RemoteFunctionRet const ret = Call(process, address, call_conv, args);\
  typedef typename VoidToInt<\
    typename boost::function_types::result_type<FuncT>::type>::type ResultT;\
  return std::make_pair(ret.GetReturnValue<ResultT>(), ret.GetLastError());\
}\

#define BOOST_PP_LOCAL_LIMITS (0, HADESMEM_CALL_MAX_ARGS)

#if defined(HADESMEM_MSVC)
#pragma warning(push)
#pragma warning(disable: 4100)
#endif // #if defined(HADESMEM_MSVC)

#if defined(HADESMEM_GCC)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif // #if defined(HADESMEM_GCC)

#include BOOST_PP_LOCAL_ITERATE()

#if defined(HADESMEM_MSVC)
#pragma warning(pop)
#endif // #if defined(HADESMEM_MSVC)

#if defined(HADESMEM_GCC)
#pragma GCC diagnostic pop
#endif // #if defined(HADESMEM_GCC)

#undef HADESMEM_CALL_DEFINE_ARG

#undef HADESMEM_CALL_ADD_ARG

class MultiCall
{
public:
  explicit MultiCall(Process const* process);

  MultiCall(MultiCall const& other);

  MultiCall& operator=(MultiCall const& other);

  MultiCall(MultiCall&& other) BOOST_NOEXCEPT;

  MultiCall& operator=(MultiCall&& other) BOOST_NOEXCEPT;

  ~MultiCall();

#define HADESMEM_CALL_ADD_ARG(z, n, unused) \
typedef typename boost::mpl::at_c<\
  boost::function_types::parameter_types<FuncT>, \
  n>::type A##n;\
static_assert(std::is_convertible<T##n, A##n>::value, \
  "Can not convert argument to type specified in function prototype.");\
A##n a##n = t##n;\
args.push_back(a##n);\

#define BOOST_PP_LOCAL_MACRO(n)\
template <typename FuncT BOOST_PP_ENUM_TRAILING_PARAMS(n, typename T)>\
  void Add(Process const& process, LPCVOID address, CallConv call_conv \
  BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(n, T, t))\
{\
  static_assert(boost::function_types::function_arity<FuncT>::value == n, \
    "Invalid number of arguments.");\
  std::vector<CallArg> args;\
  BOOST_PP_REPEAT(n, HADESMEM_CALL_ADD_ARG, ~)\
  addresses_.push_back(address);\
  call_convs_.push_back(call_conv);\
  args_.push_back(args);\
}\

#define BOOST_PP_LOCAL_LIMITS (0, HADESMEM_CALL_MAX_ARGS)

#if defined(HADESMEM_MSVC)
#pragma warning(push)
#pragma warning(disable: 4100)
#endif // #if defined(HADESMEM_MSVC)

#if defined(HADESMEM_GCC)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif // #if defined(HADESMEM_GCC)

#include BOOST_PP_LOCAL_ITERATE()

#if defined(HADESMEM_MSVC)
#pragma warning(pop)
#endif // #if defined(HADESMEM_MSVC)

#if defined(HADESMEM_GCC)
#pragma GCC diagnostic pop
#endif // #if defined(HADESMEM_GCC)

#undef HADESMEM_CALL_DEFINE_ARG

#undef HADESMEM_CALL_ADD_ARG

  std::vector<RemoteFunctionRet> Call() const;

private:
  Process const* process_;
  std::vector<LPCVOID> addresses_;
  std::vector<CallConv> call_convs_;
  std::vector<std::vector<CallArg>> args_;
};

}
<commit_msg>* Remove the last of the enable_if hackery.<commit_after>// Copyright Joshua Boyce 2010-2012.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// This file is part of HadesMem.
// <http://www.raptorfactor.com/> <raptorfactor@raptorfactor.com>

#pragma once

#include <vector>
#include <utility>
#include <type_traits>

#include "hadesmem/detail/warning_disable_prefix.hpp"
#include <boost/assert.hpp>
#include <boost/mpl/at.hpp>
#include <boost/preprocessor.hpp>
#include <boost/function_types/result_type.hpp>
#include <boost/function_types/function_arity.hpp>
#include <boost/function_types/parameter_types.hpp>
#include "hadesmem/detail/warning_disable_suffix.hpp"

#include <windows.h>

namespace hadesmem
{

class Process;

enum class CallConv
{
  kDefault,
  kCdecl,
  kStdCall,
  kThisCall,
  kFastCall,
  kX64
};

class RemoteFunctionRet
{
public:
  RemoteFunctionRet(DWORD_PTR return_int_ptr,
    DWORD64 return_int_64,
    float return_float,
    double return_double,
    DWORD last_error) BOOST_NOEXCEPT;

  DWORD_PTR GetReturnValue() const BOOST_NOEXCEPT;

  DWORD64 GetReturnValue64() const BOOST_NOEXCEPT;

  float GetReturnValueFloat() const BOOST_NOEXCEPT;

  double GetReturnValueDouble() const BOOST_NOEXCEPT;

  DWORD GetLastError() const BOOST_NOEXCEPT;

  template <typename T>
  T GetReturnValue() const BOOST_NOEXCEPT
  {
    static_assert(std::is_integral<T>::value ||
      std::is_pointer<T>::value ||
      std::is_same<float, typename std::remove_cv<T>::type>::value ||
      std::is_same<double, typename std::remove_cv<T>::type>::value,
      "Only integral, pointer, or floating point types are supported.");

    return GetReturnValueImpl(T());
  }

private:
  template <typename T>
  T GetReturnValueIntImpl(std::true_type const&) const BOOST_NOEXCEPT
  {
    union Conv
    {
      T t;
      DWORD64 d;
    };
    Conv conv;
    conv.d = GetReturnValue64();
    return conv.t;
  }

  template <typename T>
  T GetReturnValueIntImpl(std::false_type const&) const BOOST_NOEXCEPT
  {
    union Conv
    {
      T t;
      DWORD_PTR d;
    };
    Conv conv;
    conv.d = GetReturnValue();
    return conv.t;
  }

  template <typename T>
  T GetReturnValueImpl(T /*t*/) const BOOST_NOEXCEPT
  {
    return GetReturnValueIntImpl<T>(std::integral_constant<bool,
      (sizeof(T) == sizeof(DWORD64))>());
  }

  float GetReturnValueImpl(float /*t*/) const BOOST_NOEXCEPT
  {
    return GetReturnValueFloat();
  }

  double GetReturnValueImpl(double /*t*/) const BOOST_NOEXCEPT
  {
    return GetReturnValueDouble();
  }

  DWORD_PTR int_ptr_;
  DWORD64 int_64_;
  float float_;
  double double_;
  DWORD last_error_;
};

class CallArg
{
public:
  template <typename T>
  CallArg(T t) BOOST_NOEXCEPT
    : type_(ArgType::kPtrType),
    arg_()
  {
    static_assert(std::is_integral<T>::value ||
      std::is_pointer<T>::value ||
      std::is_same<float, typename std::remove_cv<T>::type>::value ||
      std::is_same<double, typename std::remove_cv<T>::type>::value,
      "Only integral, pointer, or floating point types are supported.");

    static_assert(sizeof(T) <= sizeof(void*) ||
      std::is_same<double, typename std::remove_cv<T>::type>::value ||
      (std::is_integral<T>::value && sizeof(T) <= sizeof(DWORD64)),
      "Currently only memsize (or smaller) types are supported (doubles "
      "and 64-bit integrals excepted).");

    Initialize(t);
  }

  template <typename V>
  void Visit(V* v) const
  {
    switch (type_)
    {
    case ArgType::kPtrType:
      (*v)(arg_.p);
      break;
    case ArgType::kFloatType:
      (*v)(arg_.f);
      break;
    case ArgType::kDoubleType:
      (*v)(arg_.d);
      break;
    case ArgType::kInt64Type:
      (*v)(arg_.i);
      break;
    default:
      BOOST_ASSERT("Invalid type." && false);
    }
  }

private:
  template <typename T>
  void InitializeIntegralImpl(T t, std::false_type const&) BOOST_NOEXCEPT
  {
    type_ = ArgType::kPtrType;
    union Conv
    {
      T t;
      void* p;
    };
    Conv conv;
    conv.t = t;
    arg_.p = conv.p;
  }

  template <typename T>
  void InitializeIntegralImpl(T t, std::true_type const&) BOOST_NOEXCEPT
  {
    type_ = ArgType::kInt64Type;
    union Conv
    {
      T t;
      DWORD64 i;
    };
    Conv conv;
    conv.t = t;
    arg_.i = conv.i;
  }

  template <typename T>
  void Initialize(T t) BOOST_NOEXCEPT
  {
    InitializeIntegralImpl(t, std::integral_constant<bool,
      (sizeof(void*) != sizeof(DWORD64) && sizeof(T) == sizeof(DWORD64))>());
  }

  void Initialize(float t) BOOST_NOEXCEPT
  {
    type_ = ArgType::kFloatType;
    arg_.f = t;
  }

  void Initialize(double t) BOOST_NOEXCEPT
  {
    type_ = ArgType::kDoubleType;
    arg_.d = t;
  }

  enum class ArgType
  {
    kPtrType,
    kFloatType,
    kDoubleType,
    kInt64Type
  };

  union Arg
  {
    void* p;
    float f;
    double d;
    DWORD64 i;
  };

  ArgType type_;
  Arg arg_;
};

RemoteFunctionRet Call(Process const& process,
  LPCVOID address,
  CallConv call_conv,
  std::vector<CallArg> const& args);

std::vector<RemoteFunctionRet> CallMulti(Process const& process,
  std::vector<LPCVOID> const& addresses,
  std::vector<CallConv> const& call_convs,
  std::vector<std::vector<CallArg>> const& args_full);

template <typename T>
struct VoidToInt
{
  typedef T type;
};

template <>
struct VoidToInt<void>
{
  typedef int type;
};

#ifndef HADESMEM_CALL_MAX_ARGS
#define HADESMEM_CALL_MAX_ARGS 20
#endif // #ifndef HADESMEM_CALL_MAX_ARGS

static_assert(HADESMEM_CALL_MAX_ARGS < BOOST_PP_LIMIT_REPEAT,
  "HADESMEM_CALL_MAX_ARGS exceeds Boost.Preprocessor repeat limit.");

static_assert(HADESMEM_CALL_MAX_ARGS < BOOST_PP_LIMIT_ITERATION,
  "HADESMEM_CALL_MAX_ARGS exceeds Boost.Preprocessor iteration limit.");

#define HADESMEM_CALL_ADD_ARG(z, n, unused) \
typedef typename boost::mpl::at_c<\
  boost::function_types::parameter_types<FuncT>, \
  n>::type A##n;\
static_assert(std::is_convertible<T##n, A##n>::value, \
  "Can not convert argument to type specified in function prototype.");\
A##n a##n = t##n;\
args.push_back(a##n);\

#define BOOST_PP_LOCAL_MACRO(n)\
template <typename FuncT BOOST_PP_ENUM_TRAILING_PARAMS(n, typename T)>\
std::pair<typename VoidToInt<\
  typename boost::function_types::result_type<FuncT>::type>::type, DWORD> \
  Call(Process const& process, LPCVOID address, CallConv call_conv \
  BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(n, T, t))\
{\
  static_assert(boost::function_types::function_arity<FuncT>::value == n, \
    "Invalid number of arguments.");\
  std::vector<CallArg> args;\
  BOOST_PP_REPEAT(n, HADESMEM_CALL_ADD_ARG, ~)\
  RemoteFunctionRet const ret = Call(process, address, call_conv, args);\
  typedef typename VoidToInt<\
    typename boost::function_types::result_type<FuncT>::type>::type ResultT;\
  return std::make_pair(ret.GetReturnValue<ResultT>(), ret.GetLastError());\
}\

#define BOOST_PP_LOCAL_LIMITS (0, HADESMEM_CALL_MAX_ARGS)

#if defined(HADESMEM_MSVC)
#pragma warning(push)
#pragma warning(disable: 4100)
#endif // #if defined(HADESMEM_MSVC)

#if defined(HADESMEM_GCC)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif // #if defined(HADESMEM_GCC)

#include BOOST_PP_LOCAL_ITERATE()

#if defined(HADESMEM_MSVC)
#pragma warning(pop)
#endif // #if defined(HADESMEM_MSVC)

#if defined(HADESMEM_GCC)
#pragma GCC diagnostic pop
#endif // #if defined(HADESMEM_GCC)

#undef HADESMEM_CALL_DEFINE_ARG

#undef HADESMEM_CALL_ADD_ARG

class MultiCall
{
public:
  explicit MultiCall(Process const* process);

  MultiCall(MultiCall const& other);

  MultiCall& operator=(MultiCall const& other);

  MultiCall(MultiCall&& other) BOOST_NOEXCEPT;

  MultiCall& operator=(MultiCall&& other) BOOST_NOEXCEPT;

  ~MultiCall();

#define HADESMEM_CALL_ADD_ARG(z, n, unused) \
typedef typename boost::mpl::at_c<\
  boost::function_types::parameter_types<FuncT>, \
  n>::type A##n;\
static_assert(std::is_convertible<T##n, A##n>::value, \
  "Can not convert argument to type specified in function prototype.");\
A##n a##n = t##n;\
args.push_back(a##n);\

#define BOOST_PP_LOCAL_MACRO(n)\
template <typename FuncT BOOST_PP_ENUM_TRAILING_PARAMS(n, typename T)>\
  void Add(Process const& process, LPCVOID address, CallConv call_conv \
  BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(n, T, t))\
{\
  static_assert(boost::function_types::function_arity<FuncT>::value == n, \
    "Invalid number of arguments.");\
  std::vector<CallArg> args;\
  BOOST_PP_REPEAT(n, HADESMEM_CALL_ADD_ARG, ~)\
  addresses_.push_back(address);\
  call_convs_.push_back(call_conv);\
  args_.push_back(args);\
}\

#define BOOST_PP_LOCAL_LIMITS (0, HADESMEM_CALL_MAX_ARGS)

#if defined(HADESMEM_MSVC)
#pragma warning(push)
#pragma warning(disable: 4100)
#endif // #if defined(HADESMEM_MSVC)

#if defined(HADESMEM_GCC)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif // #if defined(HADESMEM_GCC)

#include BOOST_PP_LOCAL_ITERATE()

#if defined(HADESMEM_MSVC)
#pragma warning(pop)
#endif // #if defined(HADESMEM_MSVC)

#if defined(HADESMEM_GCC)
#pragma GCC diagnostic pop
#endif // #if defined(HADESMEM_GCC)

#undef HADESMEM_CALL_DEFINE_ARG

#undef HADESMEM_CALL_ADD_ARG

  std::vector<RemoteFunctionRet> Call() const;

private:
  Process const* process_;
  std::vector<LPCVOID> addresses_;
  std::vector<CallConv> call_convs_;
  std::vector<std::vector<CallArg>> args_;
};

}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2009-2011, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#ifndef SCHED_COROUTINE_CORO_HXX
# define SCHED_COROUTINE_CORO_HXX

# include <libport/config.h>
# include <libport/debug.hh>
# include <libport/local-data.hh>
# include <libport/thread-data.hh>

# if ! defined __UCLIBC__ && defined LIBPORT_SCHED_MULTITHREAD
typedef ::libport::LocalSingleton<Coro*, ::libport::localdata::Thread>
  LocalCoroPtr;
# else
 /* Under uclibc, we need pthread local data to be coroutine-specific for proper
  * exception handling. So current_coro ptr cannot be a pthread local.
  */
typedef Coro* LocalCoroPtr;
# endif

// Hook stuff for uclibc-workaround
SCHED_API extern LocalCoroPtr coroutine_current_;
SCHED_API extern Coro* coroutine_main_;
SCHED_API extern void (*coroutine_free_hook)(Coro*);
SCHED_API extern void (*coroutine_new_hook) (Coro*);
// Hack to force inclusion of hook object when the user links against a static
// libsched
SCHED_API void coroutine_force_hook_linkage();

inline Coro*
coroutine_current()
{
  return coroutine_current_;
}

inline Coro*
coroutine_main()
{
  return coroutine_main_;
}

inline Coro*
coroutine_new(size_t stack_size)
{
  GD_CATEGORY(Sched.Coroutine);
  Coro* res = Coro_new();
  GD_FINFO_TRACE("Create coroutine: %s.", res);
  Coro_setStackSize_(res,
                     (stack_size
                      ? stack_size
                      : sched::configuration.default_stack_size));
  if (coroutine_new_hook)
    coroutine_new_hook(res);
  return res;
}

inline void
coroutine_free(Coro* coro)
{
  GD_CATEGORY(Sched.Coroutine);
  GD_FINFO_TRACE("Free coroutine: %s.", coro);
  if (coroutine_free_hook)
    coroutine_free_hook(coro);
  Coro_free(coro);
}

inline void*
coroutine_current_stack_pointer(Coro*)
{
  return Coro_CurrentStackPointer();
}

inline void*
coroutine_stack_addr(Coro* self)
{
  return self->stack;
}

inline size_t
coroutine_stack_size(Coro* self)
{
  return self->requestedStackSize;
}

inline void
coroutine_initialize_main(Coro* coro)
{
  GD_CATEGORY(Sched.Coroutine);
  GD_FINFO_TRACE("Initialize main coroutine: %s.", coro);
  coroutine_main_ = coro;
  coroutine_current_ = coro;
  Coro_initializeMainCoro(coro);
  coroutine_force_hook_linkage();
}

template<typename T>
inline void
coroutine_start(Coro* self, Coro* other, void (*callback)(T*), T* context)
{
  GD_CATEGORY(Sched.Coroutine);
  GD_FINFO_TRACE("Start coroutine: %s.", other);
  coroutine_current_ = other;
  Coro_startCoro_(self, other, context,
		  reinterpret_cast<CoroStartCallback*>(callback));
  coroutine_current_ = self;
}

inline void
coroutine_switch_to(Coro* self, Coro* next)
{
  GD_CATEGORY(Sched.Coroutine);
  GD_FINFO_TRACE("Switch coroutine: %s => %s.", self, next);
  coroutine_current_ = next;
  Coro_switchTo_(self, next);
  coroutine_current_ = self;
}

#endif // SCHED_COROUTINE_CORO_HXX
<commit_msg>Replace allocation of coroutine space of "2^x + 16" by allocations of "2^x" only.<commit_after>/*
 * Copyright (C) 2009-2011, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#ifndef SCHED_COROUTINE_CORO_HXX
# define SCHED_COROUTINE_CORO_HXX

# include <libport/config.h>
# include <libport/debug.hh>
# include <libport/local-data.hh>
# include <libport/thread-data.hh>

# if ! defined __UCLIBC__ && defined LIBPORT_SCHED_MULTITHREAD
typedef ::libport::LocalSingleton<Coro*, ::libport::localdata::Thread>
  LocalCoroPtr;
# else
 /* Under uclibc, we need pthread local data to be coroutine-specific for proper
  * exception handling. So current_coro ptr cannot be a pthread local.
  */
typedef Coro* LocalCoroPtr;
# endif

// Hook stuff for uclibc-workaround
SCHED_API extern LocalCoroPtr coroutine_current_;
SCHED_API extern Coro* coroutine_main_;
SCHED_API extern void (*coroutine_free_hook)(Coro*);
SCHED_API extern void (*coroutine_new_hook) (Coro*);
// Hack to force inclusion of hook object when the user links against a static
// libsched
SCHED_API void coroutine_force_hook_linkage();

inline Coro*
coroutine_current()
{
  return coroutine_current_;
}

inline Coro*
coroutine_main()
{
  return coroutine_main_;
}

inline Coro*
coroutine_new(size_t stack_size)
{
  GD_CATEGORY(Sched.Coroutine);
  Coro* res = Coro_new();
  GD_FINFO_TRACE("Create coroutine: %s.", res);
  // Coro_allocStackIfNeeded used these values to allocate stack space and
  // add 16 bytes for its meta-data.  As we use power of 2 for stack space,
  // we don't want to allocate 2^x + 16, because this may be a source of
  // inefficiency.
  Coro_setStackSize_(res,
                     (stack_size > 16
                      ? stack_size - 16
                      : sched::configuration.default_stack_size - 16));
  if (coroutine_new_hook)
    coroutine_new_hook(res);
  return res;
}

inline void
coroutine_free(Coro* coro)
{
  GD_CATEGORY(Sched.Coroutine);
  GD_FINFO_TRACE("Free coroutine: %s.", coro);
  if (coroutine_free_hook)
    coroutine_free_hook(coro);
  Coro_free(coro);
}

inline void*
coroutine_current_stack_pointer(Coro*)
{
  return Coro_CurrentStackPointer();
}

inline void*
coroutine_stack_addr(Coro* self)
{
  return self->stack;
}

inline size_t
coroutine_stack_size(Coro* self)
{
  return self->requestedStackSize;
}

inline void
coroutine_initialize_main(Coro* coro)
{
  GD_CATEGORY(Sched.Coroutine);
  GD_FINFO_TRACE("Initialize main coroutine: %s.", coro);
  coroutine_main_ = coro;
  coroutine_current_ = coro;
  Coro_initializeMainCoro(coro);
  coroutine_force_hook_linkage();
}

template<typename T>
inline void
coroutine_start(Coro* self, Coro* other, void (*callback)(T*), T* context)
{
  GD_CATEGORY(Sched.Coroutine);
  GD_FINFO_TRACE("Start coroutine: %s.", other);
  coroutine_current_ = other;
  Coro_startCoro_(self, other, context,
		  reinterpret_cast<CoroStartCallback*>(callback));
  coroutine_current_ = self;
}

inline void
coroutine_switch_to(Coro* self, Coro* next)
{
  GD_CATEGORY(Sched.Coroutine);
  GD_FINFO_TRACE("Switch coroutine: %s => %s.", self, next);
  coroutine_current_ = next;
  Coro_switchTo_(self, next);
  coroutine_current_ = self;
}

#endif // SCHED_COROUTINE_CORO_HXX
<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstring>
#include <cerrno>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <mist/stream.h>
#include <mist/flv_tag.h>
#include <mist/defines.h>
#include <mist/ts_packet.h>
#include <mist/timing.h>
#include <mist/mp4_generic.h>
#include "input_ts.h"

#include <mist/tinythread.h>
#include <sys/stat.h>

/// \todo Implement this trigger equivalent...
/*
if(Triggers::shouldTrigger("STREAM_PUSH", smp)){
  std::string payload = streamName+"\n" + myConn.getHost() +"\n"+capa["name"].asStringRef()+"\n"+reqUrl;
  if (!Triggers::doTrigger("STREAM_PUSH", payload, smp)){
    DEBUG_MSG(DLVL_FAIL, "Push from %s to %s rejected - STREAM_PUSH trigger denied the push", myConn.getHost().c_str(), streamName.c_str());
    myConn.close();
    configLock.post();
    configLock.close();
    return;
  }
}
*/

#ifdef TSLIVE_INPUT
std::string globalStreamName;
TS::Stream liveStream(true);
Util::Config * cfgPointer = NULL;

#define THREAD_TIMEOUT 15
std::map<unsigned long long, unsigned long long> threadTimer;

std::set<unsigned long> claimableThreads;

void parseThread(void * ignored) {

  std::string semName = "MstInTSStreamClaim" + globalStreamName;
  IPC::semaphore lock(semName.c_str(), O_CREAT | O_RDWR, ACCESSPERMS, 1);

  int tid = -1;
  lock.wait();
  if (claimableThreads.size()) {
    tid = *claimableThreads.begin();
    claimableThreads.erase(claimableThreads.begin());
  }
  lock.post();
  if (tid == -1) {
    return;
  }

  if (liveStream.isDataTrack(tid)){
    if (!Util::startInput(globalStreamName)) {
      return;
    }
  }

  Mist::negotiationProxy myProxy;
  myProxy.streamName = globalStreamName;
  DTSC::Meta myMeta;

  if (liveStream.isDataTrack(tid)){
    char userPageName[NAME_BUFFER_SIZE];
    snprintf(userPageName, NAME_BUFFER_SIZE, SHM_USERS, globalStreamName.c_str());
    myProxy.userClient = IPC::sharedClient(userPageName, PLAY_EX_SIZE, true);
  }

  threadTimer[tid] = Util::bootSecs();
  while (Util::bootSecs() - threadTimer[tid] < THREAD_TIMEOUT && cfgPointer->is_active) {
    liveStream.parse(tid);
    if (liveStream.hasPacket(tid)){
      liveStream.initializeMetadata(myMeta, tid);
      DTSC::Packet pack;
      liveStream.getPacket(tid, pack);
      if (pack && myMeta.tracks.count(tid)){
        myProxy.bufferLivePacket(pack, myMeta);
      }

      lock.wait();
      threadTimer[tid] = Util::bootSecs();
      lock.post();
    }
    if (liveStream.isDataTrack(tid)){
      myProxy.userClient.keepAlive();
    }
    if (!liveStream.hasPacket(tid)){
      Util::sleep(100);
    }
  }
  lock.wait();
  threadTimer.erase(tid);
  lock.post();
  liveStream.eraseTrack(tid);
  myProxy.userClient.finish();
}

#endif

namespace Mist {

  /// Constructor of TS Input
  /// \arg cfg Util::Config that contains all current configurations.
  inputTS::inputTS(Util::Config * cfg) : Input(cfg) {
    capa["name"] = "TS";
    capa["decs"] = "Enables TS Input";
    capa["source_match"] = "/*.ts";
    capa["priority"] = 9ll;
    capa["codecs"][0u][0u].append("H264");
    capa["codecs"][0u][0u].append("HEVC");
    capa["codecs"][0u][1u].append("AAC");
    capa["codecs"][0u][1u].append("AC3");

    capa["optional"]["port"]["name"] = "UDP Port";
    capa["optional"]["port"]["help"] = "The UDP port on which to listen for incoming UDP Packets, optionally prefixed by the interface IP.";
    capa["optional"]["port"]["type"] = "string";
    capa["optional"]["port"]["default"] = "9876";
    capa["optional"]["port"]["option"] = "--port";
    cfg->addOption("port",
                   JSON::fromString("{\"arg\":\"string\",\"value\":9876,\"short\":\"p\",\"long\":\"port\",\"help\":\"The UDP port on which to listen for incoming UDP Packets, optionally prefixed by the interface IP.\"}"));

    capa["optional"]["multicastinterface"]["name"] = "TS Multicast interface";
    capa["optional"]["multicastinterface"]["help"] = "The interface(s) on which to listen for UDP Multicast packets, comma separated.";
    capa["optional"]["multicastinterface"]["option"] = "--multicast-interface";
    capa["optional"]["multicastinterface"]["type"] = "str";
    capa["optional"]["multicastinterface"]["default"] = "";
    cfg->addOption("multicastinterface",
                   JSON::fromString("{\"arg\":\"string\",\"value\":\"\",\"short\":\"M\",\"long\":\"multicast-interface\",\"help\":\"The interfaces on which to listen for UDP Multicast packets, space separatered.\"}"));

    pushing = false;
    inFile = NULL;

#ifdef TSLIVE_INPUT
    standAlone = false;
#endif
  }

  inputTS::~inputTS() {
    if (inFile) {
      fclose(inFile);
    }
#ifdef TSLIVE_INPUT
    std::string semName = "MstInTSStreamClaim" + globalStreamName;
    IPC::semaphore lock(semName.c_str(), O_CREAT | O_RDWR, ACCESSPERMS, 1);
    lock.wait();
    threadTimer.clear();
    claimableThreads.clear();
    lock.post();
#endif
  }

#ifdef TSLIVE_INPUT

  ///Live Setup of TS Input
  bool inputTS::setup() {
    INFO_MSG("Setup start");
    if (config->getString("input") == "-") {
      inFile = stdin;
    } else {
      pushing = true;
      udpCon.setBlocking(false);
      std::string ipPort = config->getString("port");
      size_t colon = ipPort.rfind(':');
      if (colon != std::string::npos) {
        udpCon.bind(JSON::Value(ipPort.substr(colon + 1)).asInt(), ipPort.substr(0, colon), config->getString("multicastinterface"));
      } else {
        udpCon.bind(JSON::Value(ipPort).asInt(), "", config->getString("multicastinterface"));
      }
    }
    INFO_MSG("Setup complete");
    return true;
  }

#else

  ///Setup of TS Input
  bool inputTS::setup() {
    if (config->getString("input") != "-") {
      inFile = fopen(config->getString("input").c_str(), "r");
    }
    if (!inFile) {
      return false;
    }
    return true;
  }

#endif

  ///Track selector of TS Input
  ///\arg trackSpec specifies which tracks  are to be selected
  ///\todo test whether selecting a subset of tracks work
  void inputTS::trackSelect(std::string trackSpec) {
    selectedTracks.clear();
    long long int index;
    while (trackSpec != "") {
      index = trackSpec.find(' ');
      selectedTracks.insert(atoi(trackSpec.substr(0, index).c_str()));
      if (index != std::string::npos) {
        trackSpec.erase(0, index + 1);
      } else {
        trackSpec = "";
      }
    }
  }

#ifdef TSLIVE_INPUT
  //This implementation in used in the live version of TS input, where no header is available in advance.
  //Reading the header returns true in this case, to continue parsing the actual stream.
  bool inputTS::readHeader() {
    return true;
  }
#else
  ///Reads headers from a TS stream, and saves them into metadata
  ///It works by going through the entire TS stream, and every time
  ///It encounters a new PES start, it writes the currently found PES data
  ///for a specific track to metadata. After the entire stream has been read,
  ///it writes the remaining metadata.
  ///\todo Find errors, perhaps parts can be made more modular
  bool inputTS::readHeader() {
    if (!inFile) {
      return false;
    }
    DTSC::File tmp(config->getString("input") + ".dtsh");
    if (tmp) {
      myMeta = tmp.getMeta();
      return true;
    }

    TS::Packet packet;//to analyse and extract data
    fseek(inFile, 0, SEEK_SET);//seek to beginning

    bool first = true;
    long long int lastBpos = 0;
    while (packet.FromFile(inFile) && !feof(inFile)) {
      tsStream.parse(packet, lastBpos);
      lastBpos = ftell(inFile);
      while (tsStream.hasPacketOnEachTrack()) {
        if (first) {
          tsStream.initializeMetadata(myMeta);
          first = false;
        }
        DTSC::Packet headerPack;
        tsStream.getEarliestPacket(headerPack);
        myMeta.update(headerPack);
      }

    }

    fseek(inFile, 0, SEEK_SET);
    std::ofstream oFile(std::string(config->getString("input") + ".dtsh").c_str());
    oFile << myMeta.toJSON().toNetPacked();
    oFile.close();
    return true;
  }
#endif

  ///Gets the next packet that is to be sent
  ///At the moment, the logic of sending the last packet that was finished has been implemented,
  ///but the seeking and finding data is not yet ready.
  ///\todo Finish the implementation
  void inputTS::getNext(bool smart) {
    INSANE_MSG("Getting next");
    thisPacket.null();
    bool hasPacket = (selectedTracks.size() == 1 ? tsStream.hasPacket(*selectedTracks.begin()) : tsStream.hasPacketOnEachTrack());
    while (!hasPacket && (pushing || !feof(inFile)) && config->is_active) {
      if (!pushing) {
        unsigned int bPos = ftell(inFile);
        tsBuf.FromFile(inFile);
        if (selectedTracks.count(tsBuf.getPID())) {
          tsStream.parse(tsBuf, bPos);
        }
      } else {
        while (udpCon.Receive()) {
          udpDataBuffer.append(udpCon.data, udpCon.data_len);
          while (udpDataBuffer.size() > 188 && (udpDataBuffer[0] != 0x47 || udpDataBuffer[188] != 0x47)) {
            size_t syncPos = udpDataBuffer.find("\107", 1);
            udpDataBuffer.erase(0, syncPos);
          }
          while (udpDataBuffer.size() >= 188) {
            tsBuf.FromPointer(udpDataBuffer.data());
            tsStream.parse(tsBuf, 0);
            udpDataBuffer.erase(0, 188);
          }
        }
        Util::sleep(500);
      }
      hasPacket = (selectedTracks.size() == 1 ? tsStream.hasPacket(*selectedTracks.begin()) : tsStream.hasPacketOnEachTrack());
    }
    if (!hasPacket) {
      if (inFile && !feof(inFile)) {
        getNext();
      }
      if (pushing) {
        sleep(500);
      }
      return;
    }
    if (selectedTracks.size() == 1) {
      tsStream.getPacket(*selectedTracks.begin(), thisPacket);
    } else {
      tsStream.getEarliestPacket(thisPacket);
    }
    tsStream.initializeMetadata(myMeta);
    if (!myMeta.tracks.count(thisPacket.getTrackId())) {
      getNext();
    }
  }

  void inputTS::readPMT() {
    //save current file position
    int bpos = ftell(inFile);
    if (fseek(inFile, 0, SEEK_SET)) {
      FAIL_MSG("Seek to 0 failed");
      return;
    }

    TS::Packet tsBuffer;
    while (!tsStream.hasPacketOnEachTrack() && tsBuffer.FromFile(inFile)) {
      tsStream.parse(tsBuffer, 0);
    }

    //Clear leaves the PMT in place
    tsStream.clear();

    //Restore original file position
    if (fseek(inFile, bpos, SEEK_SET)) {
      return;
    }

  }

  ///Seeks to a specific time
  void inputTS::seek(int seekTime) {
    tsStream.clear();
    readPMT();
    unsigned long seekPos = 0xFFFFFFFFull;
    for (std::set<unsigned long>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++) {
      unsigned long thisBPos = 0;
      for (std::deque<DTSC::Key>::iterator keyIt = myMeta.tracks[*it].keys.begin(); keyIt != myMeta.tracks[*it].keys.end(); keyIt++) {
        if (keyIt->getTime() > seekTime) {
          break;
        }
        thisBPos = keyIt->getBpos();
      }
      if (thisBPos < seekPos) {
        seekPos = thisBPos;
      }
    }
    fseek(inFile, seekPos, SEEK_SET);//seek to the correct position
  }

#ifdef TSLIVE_INPUT
  void inputTS::serve() {
    cfgPointer = config;
    globalStreamName = streamName;
    unsigned long long threadCheckTimer = Util::bootSecs();
    while (config->is_active) {
      if (!pushing) {
        unsigned int bPos = ftell(inFile);
        int ctr = 0;
        while (ctr < 20 && tsBuf.FromFile(inFile)){
          liveStream.add(tsBuf);
          ctr++;
        }
      } else {
        while (udpCon.Receive()) {
          int offset = 0;
          //Try to read full TS Packets
          //Assumption here is made that one UDP Datagram consists of complete TS Packets.
          //Assumption made because of possible packet loss issues
          while ((udpCon.data_len - offset) >= 188) {
            //Watch out! We push here to a global, in order for threads to be able to access it.
            liveStream.add(udpCon.data + offset);
            offset += 188;
          }
          if (offset < udpCon.data_len) {
            WARN_MSG("%d bytes left in datagram", udpCon.data_len - offset);
          }
        }
      }
      //Check for and spawn threads here.
      if (Util::bootSecs() - threadCheckTimer > 2) {
        std::set<unsigned long> activeTracks = liveStream.getActiveTracks();
        std::string semName = "MstInTSStreamClaim" + globalStreamName;
        IPC::semaphore lock(semName.c_str(), O_CREAT | O_RDWR, ACCESSPERMS, 1);
        lock.wait();
        for (std::set<unsigned long>::iterator it = activeTracks.begin(); it != activeTracks.end(); it++) {
          if (threadTimer.count(*it) && ((Util::bootSecs() - threadTimer[*it]) > (2 * THREAD_TIMEOUT))) {
            WARN_MSG("Thread for track %d timed out %d seconds ago without a clean shutdown.", *it, Util::bootSecs() - threadTimer[*it]);
            threadTimer.erase(*it);
          }
          if (!threadTimer.count(*it)) {

            //Add to list of unclaimed threads
            claimableThreads.insert(*it);

            //Spawn thread here.
            tthread::thread thisThread(parseThread, 0);
            thisThread.detach();
          }
        }
        lock.post();
        threadCheckTimer = Util::bootSecs();
      }
      Util::sleep(100);
    }
    finish();
    INFO_MSG("Input for stream %s closing clean", streamName.c_str());
  }

  void inputTS::finish() {
    std::string semName = "MstInTSStreamClaim" + globalStreamName;
    IPC::semaphore lock(semName.c_str(), O_CREAT | O_RDWR, ACCESSPERMS, 1);

    int threadCount = 0;
    do {
      lock.wait();
      threadCount = threadTimer.size();
      lock.post();
    } while (threadCount);
  }
#endif

}

<commit_msg>Fixed high CPU usage of TS input during shutdown.<commit_after>#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstring>
#include <cerrno>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <mist/stream.h>
#include <mist/flv_tag.h>
#include <mist/defines.h>
#include <mist/ts_packet.h>
#include <mist/timing.h>
#include <mist/mp4_generic.h>
#include "input_ts.h"

#include <mist/tinythread.h>
#include <sys/stat.h>

/// \todo Implement this trigger equivalent...
/*
if(Triggers::shouldTrigger("STREAM_PUSH", smp)){
  std::string payload = streamName+"\n" + myConn.getHost() +"\n"+capa["name"].asStringRef()+"\n"+reqUrl;
  if (!Triggers::doTrigger("STREAM_PUSH", payload, smp)){
    DEBUG_MSG(DLVL_FAIL, "Push from %s to %s rejected - STREAM_PUSH trigger denied the push", myConn.getHost().c_str(), streamName.c_str());
    myConn.close();
    configLock.post();
    configLock.close();
    return;
  }
}
*/

#ifdef TSLIVE_INPUT
std::string globalStreamName;
TS::Stream liveStream(true);
Util::Config * cfgPointer = NULL;

#define THREAD_TIMEOUT 15
std::map<unsigned long long, unsigned long long> threadTimer;

std::set<unsigned long> claimableThreads;

void parseThread(void * ignored) {

  std::string semName = "MstInTSStreamClaim" + globalStreamName;
  IPC::semaphore lock(semName.c_str(), O_CREAT | O_RDWR, ACCESSPERMS, 1);

  int tid = -1;
  lock.wait();
  if (claimableThreads.size()) {
    tid = *claimableThreads.begin();
    claimableThreads.erase(claimableThreads.begin());
  }
  lock.post();
  if (tid == -1) {
    return;
  }

  if (liveStream.isDataTrack(tid)){
    if (!Util::startInput(globalStreamName)) {
      return;
    }
  }

  Mist::negotiationProxy myProxy;
  myProxy.streamName = globalStreamName;
  DTSC::Meta myMeta;

  if (liveStream.isDataTrack(tid)){
    char userPageName[NAME_BUFFER_SIZE];
    snprintf(userPageName, NAME_BUFFER_SIZE, SHM_USERS, globalStreamName.c_str());
    myProxy.userClient = IPC::sharedClient(userPageName, PLAY_EX_SIZE, true);
  }

  threadTimer[tid] = Util::bootSecs();
  while (Util::bootSecs() - threadTimer[tid] < THREAD_TIMEOUT && cfgPointer->is_active) {
    liveStream.parse(tid);
    if (liveStream.hasPacket(tid)){
      liveStream.initializeMetadata(myMeta, tid);
      DTSC::Packet pack;
      liveStream.getPacket(tid, pack);
      if (pack && myMeta.tracks.count(tid)){
        myProxy.bufferLivePacket(pack, myMeta);
      }

      lock.wait();
      threadTimer[tid] = Util::bootSecs();
      lock.post();
    }
    if (liveStream.isDataTrack(tid)){
      myProxy.userClient.keepAlive();
    }
    if (!liveStream.hasPacket(tid)){
      Util::sleep(100);
    }
  }
  lock.wait();
  threadTimer.erase(tid);
  lock.post();
  liveStream.eraseTrack(tid);
  myProxy.userClient.finish();
}

#endif

namespace Mist {

  /// Constructor of TS Input
  /// \arg cfg Util::Config that contains all current configurations.
  inputTS::inputTS(Util::Config * cfg) : Input(cfg) {
    capa["name"] = "TS";
    capa["decs"] = "Enables TS Input";
    capa["source_match"] = "/*.ts";
    capa["priority"] = 9ll;
    capa["codecs"][0u][0u].append("H264");
    capa["codecs"][0u][0u].append("HEVC");
    capa["codecs"][0u][1u].append("AAC");
    capa["codecs"][0u][1u].append("AC3");

    capa["optional"]["port"]["name"] = "UDP Port";
    capa["optional"]["port"]["help"] = "The UDP port on which to listen for incoming UDP Packets, optionally prefixed by the interface IP.";
    capa["optional"]["port"]["type"] = "string";
    capa["optional"]["port"]["default"] = "9876";
    capa["optional"]["port"]["option"] = "--port";
    cfg->addOption("port",
                   JSON::fromString("{\"arg\":\"string\",\"value\":9876,\"short\":\"p\",\"long\":\"port\",\"help\":\"The UDP port on which to listen for incoming UDP Packets, optionally prefixed by the interface IP.\"}"));

    capa["optional"]["multicastinterface"]["name"] = "TS Multicast interface";
    capa["optional"]["multicastinterface"]["help"] = "The interface(s) on which to listen for UDP Multicast packets, comma separated.";
    capa["optional"]["multicastinterface"]["option"] = "--multicast-interface";
    capa["optional"]["multicastinterface"]["type"] = "str";
    capa["optional"]["multicastinterface"]["default"] = "";
    cfg->addOption("multicastinterface",
                   JSON::fromString("{\"arg\":\"string\",\"value\":\"\",\"short\":\"M\",\"long\":\"multicast-interface\",\"help\":\"The interfaces on which to listen for UDP Multicast packets, space separatered.\"}"));

    pushing = false;
    inFile = NULL;

#ifdef TSLIVE_INPUT
    standAlone = false;
#endif
  }

  inputTS::~inputTS() {
    if (inFile) {
      fclose(inFile);
    }
#ifdef TSLIVE_INPUT
    std::string semName = "MstInTSStreamClaim" + globalStreamName;
    IPC::semaphore lock(semName.c_str(), O_CREAT | O_RDWR, ACCESSPERMS, 1);
    lock.wait();
    threadTimer.clear();
    claimableThreads.clear();
    lock.post();
#endif
  }

#ifdef TSLIVE_INPUT

  ///Live Setup of TS Input
  bool inputTS::setup() {
    INFO_MSG("Setup start");
    if (config->getString("input") == "-") {
      inFile = stdin;
    } else {
      pushing = true;
      udpCon.setBlocking(false);
      std::string ipPort = config->getString("port");
      size_t colon = ipPort.rfind(':');
      if (colon != std::string::npos) {
        udpCon.bind(JSON::Value(ipPort.substr(colon + 1)).asInt(), ipPort.substr(0, colon), config->getString("multicastinterface"));
      } else {
        udpCon.bind(JSON::Value(ipPort).asInt(), "", config->getString("multicastinterface"));
      }
    }
    INFO_MSG("Setup complete");
    return true;
  }

#else

  ///Setup of TS Input
  bool inputTS::setup() {
    if (config->getString("input") != "-") {
      inFile = fopen(config->getString("input").c_str(), "r");
    }
    if (!inFile) {
      return false;
    }
    return true;
  }

#endif

  ///Track selector of TS Input
  ///\arg trackSpec specifies which tracks  are to be selected
  ///\todo test whether selecting a subset of tracks work
  void inputTS::trackSelect(std::string trackSpec) {
    selectedTracks.clear();
    long long int index;
    while (trackSpec != "") {
      index = trackSpec.find(' ');
      selectedTracks.insert(atoi(trackSpec.substr(0, index).c_str()));
      if (index != std::string::npos) {
        trackSpec.erase(0, index + 1);
      } else {
        trackSpec = "";
      }
    }
  }

#ifdef TSLIVE_INPUT
  //This implementation in used in the live version of TS input, where no header is available in advance.
  //Reading the header returns true in this case, to continue parsing the actual stream.
  bool inputTS::readHeader() {
    return true;
  }
#else
  ///Reads headers from a TS stream, and saves them into metadata
  ///It works by going through the entire TS stream, and every time
  ///It encounters a new PES start, it writes the currently found PES data
  ///for a specific track to metadata. After the entire stream has been read,
  ///it writes the remaining metadata.
  ///\todo Find errors, perhaps parts can be made more modular
  bool inputTS::readHeader() {
    if (!inFile) {
      return false;
    }
    DTSC::File tmp(config->getString("input") + ".dtsh");
    if (tmp) {
      myMeta = tmp.getMeta();
      return true;
    }

    TS::Packet packet;//to analyse and extract data
    fseek(inFile, 0, SEEK_SET);//seek to beginning

    bool first = true;
    long long int lastBpos = 0;
    while (packet.FromFile(inFile) && !feof(inFile)) {
      tsStream.parse(packet, lastBpos);
      lastBpos = ftell(inFile);
      while (tsStream.hasPacketOnEachTrack()) {
        if (first) {
          tsStream.initializeMetadata(myMeta);
          first = false;
        }
        DTSC::Packet headerPack;
        tsStream.getEarliestPacket(headerPack);
        myMeta.update(headerPack);
      }

    }

    fseek(inFile, 0, SEEK_SET);
    std::ofstream oFile(std::string(config->getString("input") + ".dtsh").c_str());
    oFile << myMeta.toJSON().toNetPacked();
    oFile.close();
    return true;
  }
#endif

  ///Gets the next packet that is to be sent
  ///At the moment, the logic of sending the last packet that was finished has been implemented,
  ///but the seeking and finding data is not yet ready.
  ///\todo Finish the implementation
  void inputTS::getNext(bool smart) {
    INSANE_MSG("Getting next");
    thisPacket.null();
    bool hasPacket = (selectedTracks.size() == 1 ? tsStream.hasPacket(*selectedTracks.begin()) : tsStream.hasPacketOnEachTrack());
    while (!hasPacket && (pushing || !feof(inFile)) && config->is_active) {
      if (!pushing) {
        unsigned int bPos = ftell(inFile);
        tsBuf.FromFile(inFile);
        if (selectedTracks.count(tsBuf.getPID())) {
          tsStream.parse(tsBuf, bPos);
        }
      } else {
        while (udpCon.Receive()) {
          udpDataBuffer.append(udpCon.data, udpCon.data_len);
          while (udpDataBuffer.size() > 188 && (udpDataBuffer[0] != 0x47 || udpDataBuffer[188] != 0x47)) {
            size_t syncPos = udpDataBuffer.find("\107", 1);
            udpDataBuffer.erase(0, syncPos);
          }
          while (udpDataBuffer.size() >= 188) {
            tsBuf.FromPointer(udpDataBuffer.data());
            tsStream.parse(tsBuf, 0);
            udpDataBuffer.erase(0, 188);
          }
        }
        Util::sleep(500);
      }
      hasPacket = (selectedTracks.size() == 1 ? tsStream.hasPacket(*selectedTracks.begin()) : tsStream.hasPacketOnEachTrack());
    }
    if (!hasPacket) {
      if (inFile && !feof(inFile)) {
        getNext();
      }
      if (pushing) {
        sleep(500);
      }
      return;
    }
    if (selectedTracks.size() == 1) {
      tsStream.getPacket(*selectedTracks.begin(), thisPacket);
    } else {
      tsStream.getEarliestPacket(thisPacket);
    }
    tsStream.initializeMetadata(myMeta);
    if (!myMeta.tracks.count(thisPacket.getTrackId())) {
      getNext();
    }
  }

  void inputTS::readPMT() {
    //save current file position
    int bpos = ftell(inFile);
    if (fseek(inFile, 0, SEEK_SET)) {
      FAIL_MSG("Seek to 0 failed");
      return;
    }

    TS::Packet tsBuffer;
    while (!tsStream.hasPacketOnEachTrack() && tsBuffer.FromFile(inFile)) {
      tsStream.parse(tsBuffer, 0);
    }

    //Clear leaves the PMT in place
    tsStream.clear();

    //Restore original file position
    if (fseek(inFile, bpos, SEEK_SET)) {
      return;
    }

  }

  ///Seeks to a specific time
  void inputTS::seek(int seekTime) {
    tsStream.clear();
    readPMT();
    unsigned long seekPos = 0xFFFFFFFFull;
    for (std::set<unsigned long>::iterator it = selectedTracks.begin(); it != selectedTracks.end(); it++) {
      unsigned long thisBPos = 0;
      for (std::deque<DTSC::Key>::iterator keyIt = myMeta.tracks[*it].keys.begin(); keyIt != myMeta.tracks[*it].keys.end(); keyIt++) {
        if (keyIt->getTime() > seekTime) {
          break;
        }
        thisBPos = keyIt->getBpos();
      }
      if (thisBPos < seekPos) {
        seekPos = thisBPos;
      }
    }
    fseek(inFile, seekPos, SEEK_SET);//seek to the correct position
  }

#ifdef TSLIVE_INPUT
  void inputTS::serve() {
    cfgPointer = config;
    globalStreamName = streamName;
    unsigned long long threadCheckTimer = Util::bootSecs();
    while (config->is_active) {
      if (!pushing) {
        unsigned int bPos = ftell(inFile);
        int ctr = 0;
        while (ctr < 20 && tsBuf.FromFile(inFile)){
          liveStream.add(tsBuf);
          ctr++;
        }
      } else {
        while (udpCon.Receive()) {
          int offset = 0;
          //Try to read full TS Packets
          //Assumption here is made that one UDP Datagram consists of complete TS Packets.
          //Assumption made because of possible packet loss issues
          while ((udpCon.data_len - offset) >= 188) {
            //Watch out! We push here to a global, in order for threads to be able to access it.
            liveStream.add(udpCon.data + offset);
            offset += 188;
          }
          if (offset < udpCon.data_len) {
            WARN_MSG("%d bytes left in datagram", udpCon.data_len - offset);
          }
        }
      }
      //Check for and spawn threads here.
      if (Util::bootSecs() - threadCheckTimer > 2) {
        std::set<unsigned long> activeTracks = liveStream.getActiveTracks();
        std::string semName = "MstInTSStreamClaim" + globalStreamName;
        IPC::semaphore lock(semName.c_str(), O_CREAT | O_RDWR, ACCESSPERMS, 1);
        lock.wait();
        for (std::set<unsigned long>::iterator it = activeTracks.begin(); it != activeTracks.end(); it++) {
          if (threadTimer.count(*it) && ((Util::bootSecs() - threadTimer[*it]) > (2 * THREAD_TIMEOUT))) {
            WARN_MSG("Thread for track %d timed out %d seconds ago without a clean shutdown.", *it, Util::bootSecs() - threadTimer[*it]);
            threadTimer.erase(*it);
          }
          if (!threadTimer.count(*it)) {

            //Add to list of unclaimed threads
            claimableThreads.insert(*it);

            //Spawn thread here.
            tthread::thread thisThread(parseThread, 0);
            thisThread.detach();
          }
        }
        lock.post();
        threadCheckTimer = Util::bootSecs();
      }
      Util::sleep(100);
    }
    finish();
    INFO_MSG("Input for stream %s closing clean", streamName.c_str());
  }

  void inputTS::finish() {
    std::string semName = "MstInTSStreamClaim" + globalStreamName;
    IPC::semaphore lock(semName.c_str(), O_CREAT | O_RDWR, ACCESSPERMS, 1);

    int threadCount = 0;
    do {
      lock.wait();
      threadCount = threadTimer.size();
      lock.post();
      if (threadCount){
        Util::sleep(100);
      }
    } while (threadCount);
  }
#endif

}

<|endoftext|>


<commit_before>/***************************************************************************
* Copyright (c) 2016, Wolf Vollprecht, Johan Mabille and Sylvain Corlay    *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XSIMD_ALGORITHMS_HPP
#define XSIMD_ALGORITHMS_HPP

#include "xsimd/memory/xsimd_load_store.hpp"

namespace xsimd
{
    template <class I1, class I2, class O1, class UF>
    void transform(I1 first, I2 last, O1 out_first, UF&& f)
    {
        using value_type = typename std::decay<decltype(*first)>::type;
        using traits = simd_traits<value_type>;
        using batch_type = typename traits::type;

        std::size_t size = static_cast<std::size_t>(std::distance(first, last));
        std::size_t simd_size = traits::size;

        const auto* ptr_begin = &(*first);
        const auto* ptr_end = &(*last);
        auto* ptr_out = &(*out_first);

        std::size_t align_begin = xsimd::get_alignment_offset(ptr_begin, size, simd_size);
        std::size_t out_align = xsimd::get_alignment_offset(ptr_out, size, simd_size);
        std::size_t align_end = align_begin + ((size - align_begin) & ~(simd_size - 1));

        if (align_begin == out_align)
        {
            for (std::size_t i = 0; i < align_begin; ++i)
            {
                out_first[i] = f(first[i]);
            }

            batch_type batch;
            for (std::size_t i = align_begin; i < align_end; i += simd_size)
            {
                xsimd::load_aligned(&first[i], batch);
                xsimd::store_aligned(&out_first[i], f(batch));
            }

            for (std::size_t i = align_end; i < size; ++i)
            {
                out_first[i] = f(first[i]);
            }
        }
        else
        {
            for (std::size_t i = 0; i < align_begin; ++i)
            {
                out_first[i] = f(first[i]);
            }

            batch_type batch;
            for (std::size_t i = align_begin; i < align_end; i += simd_size)
            {
                xsimd::load_aligned(&first[i], batch);
                xsimd::store_unaligned(&out_first[i], f(batch));
            }

            for (std::size_t i = align_end; i < size; ++i)
            {
                out_first[i] = f(first[i]);
            }
        }
    }

    template <class I1, class I2, class I3, class O1, class UF>
    void transform(I1 first_1, I2 last_1, I3 first_2, O1 out_first, UF&& f)
    {
        using value_type = typename std::decay<decltype(*first_1)>::type;
        using traits = simd_traits<value_type>;
        using batch_type = typename traits::type;

        std::size_t size = static_cast<std::size_t>(std::distance(first_1, last_1));
        std::size_t simd_size = traits::size;

        const auto* ptr_begin_1 = &(*first_1);
        const auto* ptr_begin_2 = &(*first_2);
        const auto* ptr_end = &(*last_1);
        auto* ptr_out = &(*out_first);

        std::size_t align_begin_1 = xsimd::get_alignment_offset(ptr_begin_1, size, simd_size);
        std::size_t align_begin_2 = xsimd::get_alignment_offset(ptr_begin_2, size, simd_size);
        std::size_t out_align = xsimd::get_alignment_offset(ptr_out, size, simd_size);
        std::size_t align_end = align_begin_1 + ((size - align_begin_1) & ~(simd_size - 1));

        #define XSIMD_LOOP_MACRO(A1, A2, A3)                                    \
            for (std::size_t i = 0; i < align_begin_1; ++i)                     \
            {                                                                   \
                out_first[i] = f(first_1[i], first_2[i]);                       \
            }                                                                   \
                                                                                \
            batch_type batch_1, batch_2;                                        \
            for (std::size_t i = align_begin_1; i < align_end; i += simd_size)  \
            {                                                                   \
                xsimd::A1(&first_1[i], batch_1);                                \
                xsimd::A2(&first_2[i], batch_2);                                \
                xsimd::A3(&out_first[i], f(batch_1, batch_2));                  \
            }                                                                   \
                                                                                \
            for (std::size_t i = align_end; i < size; ++i)                      \
            {                                                                   \
                out_first[i] = f(first_1[i], first_2[i]);                       \
            }                                                                   \

        if (align_begin_1 == out_align && align_begin_1 == align_begin_2)
        {
            XSIMD_LOOP_MACRO(load_aligned, load_aligned, store_aligned);
        }
        else if (align_begin_1 == out_align && align_begin_1 != align_begin_2)
        {
            XSIMD_LOOP_MACRO(load_aligned, load_unaligned, store_aligned);
        }
        else if (align_begin_1 != out_align && align_begin_1 == align_begin_2)
        {
            XSIMD_LOOP_MACRO(load_aligned, load_aligned, store_unaligned);
        }
        else if (align_begin_1 != out_align && align_begin_1 != align_begin_2)
        {
            XSIMD_LOOP_MACRO(load_aligned, load_unaligned, store_unaligned);
        }

        #undef XSIMD_LOOP_MACRO
    }

    // TODO: Remove this once we drop C++11 support
    namespace detail
    {
        struct plus
        {
            template <class X, class Y>
            auto operator()(X&& x, Y&& y) -> decltype(x + y) { return x + y; }
        };
    }

    template <class Iterator1, class Iterator2, class Init, class BinaryFunction = detail::plus>
    Init reduce(Iterator1 first, Iterator2 last, Init init, BinaryFunction&& binfun = detail::plus{})
    {
        using value_type = typename std::decay<decltype(*first)>::type;
        using traits = simd_traits<value_type>;
        using batch_type = typename traits::type;

        std::size_t size = static_cast<std::size_t>(std::distance(first, last));
        constexpr std::size_t simd_size = traits::size;

        const auto* const ptr_begin = &(*first);

        std::size_t align_begin = xsimd::get_alignment_offset(ptr_begin, size, simd_size);
        std::size_t align_end = align_begin + ((size - align_begin) & ~(simd_size - 1));

        // reduce initial unaligned part
        for (std::size_t i = 0; i < align_begin; ++i)
        {
            init = binfun(init, first[i]);
        }

        // reduce aligned part
        batch_type batch_init, batch;
        auto ptr = ptr_begin + align_begin;
        xsimd::load_aligned(ptr, batch_init);
        ptr += simd_size;
        for (auto const end = ptr_begin + align_end; ptr < end; ptr += simd_size)
        {
            xsimd::load_aligned(ptr, batch);
            batch_init = binfun(batch_init, batch);
        }

        // reduce across batch
        alignas(batch_type) std::array<value_type, simd_size> arr;
        xsimd::store_aligned(arr.data(), batch_init);
        for (auto x : arr) init = binfun(init, x);

        // reduce final unaligned part
        for (std::size_t i = align_end; i < size; ++i)
        {
            init = binfun(init, first[i]);
        }

        return init;
    }

}

#endif
<commit_msg>Do not dereference end iterators<commit_after>/***************************************************************************
* Copyright (c) 2016, Wolf Vollprecht, Johan Mabille and Sylvain Corlay    *
*                                                                          *
* Distributed under the terms of the BSD 3-Clause License.                 *
*                                                                          *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/

#ifndef XSIMD_ALGORITHMS_HPP
#define XSIMD_ALGORITHMS_HPP

#include "xsimd/memory/xsimd_load_store.hpp"

namespace xsimd
{
    template <class I1, class I2, class O1, class UF>
    void transform(I1 first, I2 last, O1 out_first, UF&& f)
    {
        using value_type = typename std::decay<decltype(*first)>::type;
        using traits = simd_traits<value_type>;
        using batch_type = typename traits::type;

        std::size_t size = static_cast<std::size_t>(std::distance(first, last));
        std::size_t simd_size = traits::size;

        const auto* ptr_begin = &(*first);
        auto* ptr_out = &(*out_first);

        std::size_t align_begin = xsimd::get_alignment_offset(ptr_begin, size, simd_size);
        std::size_t out_align = xsimd::get_alignment_offset(ptr_out, size, simd_size);
        std::size_t align_end = align_begin + ((size - align_begin) & ~(simd_size - 1));

        if (align_begin == out_align)
        {
            for (std::size_t i = 0; i < align_begin; ++i)
            {
                out_first[i] = f(first[i]);
            }

            batch_type batch;
            for (std::size_t i = align_begin; i < align_end; i += simd_size)
            {
                xsimd::load_aligned(&first[i], batch);
                xsimd::store_aligned(&out_first[i], f(batch));
            }

            for (std::size_t i = align_end; i < size; ++i)
            {
                out_first[i] = f(first[i]);
            }
        }
        else
        {
            for (std::size_t i = 0; i < align_begin; ++i)
            {
                out_first[i] = f(first[i]);
            }

            batch_type batch;
            for (std::size_t i = align_begin; i < align_end; i += simd_size)
            {
                xsimd::load_aligned(&first[i], batch);
                xsimd::store_unaligned(&out_first[i], f(batch));
            }

            for (std::size_t i = align_end; i < size; ++i)
            {
                out_first[i] = f(first[i]);
            }
        }
    }

    template <class I1, class I2, class I3, class O1, class UF>
    void transform(I1 first_1, I2 last_1, I3 first_2, O1 out_first, UF&& f)
    {
        using value_type = typename std::decay<decltype(*first_1)>::type;
        using traits = simd_traits<value_type>;
        using batch_type = typename traits::type;

        std::size_t size = static_cast<std::size_t>(std::distance(first_1, last_1));
        std::size_t simd_size = traits::size;

        const auto* ptr_begin_1 = &(*first_1);
        const auto* ptr_begin_2 = &(*first_2);
        auto* ptr_out = &(*out_first);

        std::size_t align_begin_1 = xsimd::get_alignment_offset(ptr_begin_1, size, simd_size);
        std::size_t align_begin_2 = xsimd::get_alignment_offset(ptr_begin_2, size, simd_size);
        std::size_t out_align = xsimd::get_alignment_offset(ptr_out, size, simd_size);
        std::size_t align_end = align_begin_1 + ((size - align_begin_1) & ~(simd_size - 1));

        #define XSIMD_LOOP_MACRO(A1, A2, A3)                                    \
            for (std::size_t i = 0; i < align_begin_1; ++i)                     \
            {                                                                   \
                out_first[i] = f(first_1[i], first_2[i]);                       \
            }                                                                   \
                                                                                \
            batch_type batch_1, batch_2;                                        \
            for (std::size_t i = align_begin_1; i < align_end; i += simd_size)  \
            {                                                                   \
                xsimd::A1(&first_1[i], batch_1);                                \
                xsimd::A2(&first_2[i], batch_2);                                \
                xsimd::A3(&out_first[i], f(batch_1, batch_2));                  \
            }                                                                   \
                                                                                \
            for (std::size_t i = align_end; i < size; ++i)                      \
            {                                                                   \
                out_first[i] = f(first_1[i], first_2[i]);                       \
            }                                                                   \

        if (align_begin_1 == out_align && align_begin_1 == align_begin_2)
        {
            XSIMD_LOOP_MACRO(load_aligned, load_aligned, store_aligned);
        }
        else if (align_begin_1 == out_align && align_begin_1 != align_begin_2)
        {
            XSIMD_LOOP_MACRO(load_aligned, load_unaligned, store_aligned);
        }
        else if (align_begin_1 != out_align && align_begin_1 == align_begin_2)
        {
            XSIMD_LOOP_MACRO(load_aligned, load_aligned, store_unaligned);
        }
        else if (align_begin_1 != out_align && align_begin_1 != align_begin_2)
        {
            XSIMD_LOOP_MACRO(load_aligned, load_unaligned, store_unaligned);
        }

        #undef XSIMD_LOOP_MACRO
    }

    // TODO: Remove this once we drop C++11 support
    namespace detail
    {
        struct plus
        {
            template <class X, class Y>
            auto operator()(X&& x, Y&& y) -> decltype(x + y) { return x + y; }
        };
    }

    template <class Iterator1, class Iterator2, class Init, class BinaryFunction = detail::plus>
    Init reduce(Iterator1 first, Iterator2 last, Init init, BinaryFunction&& binfun = detail::plus{})
    {
        using value_type = typename std::decay<decltype(*first)>::type;
        using traits = simd_traits<value_type>;
        using batch_type = typename traits::type;

        std::size_t size = static_cast<std::size_t>(std::distance(first, last));
        constexpr std::size_t simd_size = traits::size;

        const auto* const ptr_begin = &(*first);

        std::size_t align_begin = xsimd::get_alignment_offset(ptr_begin, size, simd_size);
        std::size_t align_end = align_begin + ((size - align_begin) & ~(simd_size - 1));

        // reduce initial unaligned part
        for (std::size_t i = 0; i < align_begin; ++i)
        {
            init = binfun(init, first[i]);
        }

        // reduce aligned part
        batch_type batch_init, batch;
        auto ptr = ptr_begin + align_begin;
        xsimd::load_aligned(ptr, batch_init);
        ptr += simd_size;
        for (auto const end = ptr_begin + align_end; ptr < end; ptr += simd_size)
        {
            xsimd::load_aligned(ptr, batch);
            batch_init = binfun(batch_init, batch);
        }

        // reduce across batch
        alignas(batch_type) std::array<value_type, simd_size> arr;
        xsimd::store_aligned(arr.data(), batch_init);
        for (auto x : arr) init = binfun(init, x);

        // reduce final unaligned part
        for (std::size_t i = align_end; i < size; ++i)
        {
            init = binfun(init, first[i]);
        }

        return init;
    }

}

#endif
<|endoftext|>


<commit_before>/*
 * Asynchronous input stream API, utilities for istream
 * implementations.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef ISTREAM_BUCKET_HXX
#define ISTREAM_BUCKET_HXX

#include "util/ConstBuffer.hxx"
#include "util/StaticArray.hxx"

class IstreamBucket {
public:
    enum class Type {
        BUFFER,
    };

private:
    Type type;

    union {
        ConstBuffer<void> buffer;
    };

public:
    IstreamBucket() = default;

    Type GetType() const {
        return type;
    }

    ConstBuffer<void> GetBuffer() const {
        assert(type == Type::BUFFER);

        return buffer;
    }

    void Set(ConstBuffer<void> _buffer) {
        type = Type::BUFFER;
        buffer = _buffer;
    }
};

class IstreamBucketList {
    typedef StaticArray<IstreamBucket, 64> List;
    List list;

    bool more = false;

public:
    IstreamBucketList() = default;

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

    void SetMore(bool _more=true) {
        more = _more;
    }

    bool HasMore() const {
        return more;
    }

    bool IsEmpty() const {
        return list.empty();
    }

    bool IsFull() const {
        return list.full();
    }

    void Clear() {
        list.clear();
    }

    void Push(const IstreamBucket &bucket) {
        if (IsFull()) {
            SetMore();
            return;
        }

        list.append(bucket);
    }

    void Push(ConstBuffer<void> buffer) {
        if (IsFull())
            return;

        list.append().Set(buffer);
    }

    List::const_iterator begin() const {
        return list.begin();
    }

    List::const_iterator end() const {
        return list.end();
    }

    gcc_pure
    bool HasNonBuffer() const {
        for (const auto &bucket : list)
            if (bucket.GetType() != IstreamBucket::Type::BUFFER)
                return true;
        return false;
    }

    gcc_pure
    size_t GetTotalBufferSize() const {
        size_t size = 0;
        for (const auto &bucket : list)
            if (bucket.GetType() == IstreamBucket::Type::BUFFER)
                size += bucket.GetBuffer().size;
        return size;
    }

    gcc_pure
    bool IsDepleted(size_t consumed) const {
        return !HasMore() && consumed == GetTotalBufferSize();
    }

    void SpliceBuffersFrom(IstreamBucketList &src, size_t max_size) {
        if (src.HasMore())
            SetMore();

        for (const auto &bucket : src) {
            if (bucket.GetType() != IstreamBucket::Type::BUFFER)
                max_size = 0;

            if (max_size == 0) {
                SetMore();
                break;
            }

            auto buffer = bucket.GetBuffer();
            if (buffer.size > max_size) {
                buffer.size = max_size;
                SetMore();
            }

            Push(buffer);
            max_size -= buffer.size;
        }
    }

    /**
     * Move buffer buckets from the given list, stopping at the first
     * no-buffer bucket.
     *
     * @return the number of bytes in all moved buffers
     */
    size_t SpliceBuffersFrom(IstreamBucketList &src) {
        if (src.HasMore())
            SetMore();

        size_t total_size = 0;
        for (const auto &bucket : src) {
            if (bucket.GetType() != IstreamBucket::Type::BUFFER) {
                SetMore();
                break;
            }

            auto buffer = bucket.GetBuffer();
            Push(bucket.GetBuffer());
            total_size += buffer.size;
        }

        return total_size;
    }
};

#endif
<commit_msg>istream/Bucket: set the "more" flag in Push(ConstBuffer)<commit_after>/*
 * Asynchronous input stream API, utilities for istream
 * implementations.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#ifndef ISTREAM_BUCKET_HXX
#define ISTREAM_BUCKET_HXX

#include "util/ConstBuffer.hxx"
#include "util/StaticArray.hxx"

class IstreamBucket {
public:
    enum class Type {
        BUFFER,
    };

private:
    Type type;

    union {
        ConstBuffer<void> buffer;
    };

public:
    IstreamBucket() = default;

    Type GetType() const {
        return type;
    }

    ConstBuffer<void> GetBuffer() const {
        assert(type == Type::BUFFER);

        return buffer;
    }

    void Set(ConstBuffer<void> _buffer) {
        type = Type::BUFFER;
        buffer = _buffer;
    }
};

class IstreamBucketList {
    typedef StaticArray<IstreamBucket, 64> List;
    List list;

    bool more = false;

public:
    IstreamBucketList() = default;

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

    void SetMore(bool _more=true) {
        more = _more;
    }

    bool HasMore() const {
        return more;
    }

    bool IsEmpty() const {
        return list.empty();
    }

    bool IsFull() const {
        return list.full();
    }

    void Clear() {
        list.clear();
    }

    void Push(const IstreamBucket &bucket) {
        if (IsFull()) {
            SetMore();
            return;
        }

        list.append(bucket);
    }

    void Push(ConstBuffer<void> buffer) {
        if (IsFull()) {
            SetMore();
            return;
        }

        list.append().Set(buffer);
    }

    List::const_iterator begin() const {
        return list.begin();
    }

    List::const_iterator end() const {
        return list.end();
    }

    gcc_pure
    bool HasNonBuffer() const {
        for (const auto &bucket : list)
            if (bucket.GetType() != IstreamBucket::Type::BUFFER)
                return true;
        return false;
    }

    gcc_pure
    size_t GetTotalBufferSize() const {
        size_t size = 0;
        for (const auto &bucket : list)
            if (bucket.GetType() == IstreamBucket::Type::BUFFER)
                size += bucket.GetBuffer().size;
        return size;
    }

    gcc_pure
    bool IsDepleted(size_t consumed) const {
        return !HasMore() && consumed == GetTotalBufferSize();
    }

    void SpliceBuffersFrom(IstreamBucketList &src, size_t max_size) {
        if (src.HasMore())
            SetMore();

        for (const auto &bucket : src) {
            if (bucket.GetType() != IstreamBucket::Type::BUFFER)
                max_size = 0;

            if (max_size == 0) {
                SetMore();
                break;
            }

            auto buffer = bucket.GetBuffer();
            if (buffer.size > max_size) {
                buffer.size = max_size;
                SetMore();
            }

            Push(buffer);
            max_size -= buffer.size;
        }
    }

    /**
     * Move buffer buckets from the given list, stopping at the first
     * no-buffer bucket.
     *
     * @return the number of bytes in all moved buffers
     */
    size_t SpliceBuffersFrom(IstreamBucketList &src) {
        if (src.HasMore())
            SetMore();

        size_t total_size = 0;
        for (const auto &bucket : src) {
            if (bucket.GetType() != IstreamBucket::Type::BUFFER) {
                SetMore();
                break;
            }

            auto buffer = bucket.GetBuffer();
            Push(bucket.GetBuffer());
            total_size += buffer.size;
        }

        return total_size;
    }
};

#endif
<|endoftext|>


<commit_before>#include <clpeak.h>

#define FETCH_PER_WI        16

int clPeak::runKernelLatency(cl::CommandQueue &queue, cl::Program &prog, device_info_t &devInfo)
{
    if(!isKernelLatency)
        return 0;

    cl::Context ctx = queue.getInfo<CL_QUEUE_CONTEXT>();
    cl_uint numItems = (devInfo.maxWGSize) * (devInfo.numCUs) * FETCH_PER_WI;
    cl::NDRange globalSize = (numItems / FETCH_PER_WI);
    cl::NDRange localSize = devInfo.maxWGSize;
    int iters = devInfo.kernelLatencyIters;
    float latency;

    try
    {
        cout << NEWLINE TAB TAB "Kernel launch latency : "; cout.flush();

        cl::Buffer inputBuf = cl::Buffer(ctx, CL_MEM_READ_ONLY, (numItems * sizeof(float)));
        cl::Buffer outputBuf = cl::Buffer(ctx, CL_MEM_WRITE_ONLY, (numItems * sizeof(float)));

        cl::Kernel kernel_v1(prog, "bandwidth_v1");
        kernel_v1.setArg(0, inputBuf), kernel_v1.setArg(1, outputBuf);

        // Dummy calls
        queue.enqueueNDRangeKernel(kernel_v1, cl::NullRange, globalSize, localSize);
        queue.enqueueNDRangeKernel(kernel_v1, cl::NullRange, globalSize, localSize);
        queue.finish();

        latency = 0;
        for(int i=0; i<iters; i++)
        {
            cl::Event timeEvent;
            queue.enqueueNDRangeKernel(kernel_v1, cl::NullRange, globalSize, localSize, NULL, &timeEvent);
            queue.finish();
            cl_ulong start = timeEvent.getProfilingInfo<CL_PROFILING_COMMAND_QUEUED>() / 1000;
            cl_ulong end = timeEvent.getProfilingInfo<CL_PROFILING_COMMAND_START>() / 1000;
            latency += ((float)end - start);
        }
        latency /= iters;

        cout << setprecision(2) << fixed;
        cout << latency << " us" << endl;
    }
    catch(cl::Error error)
    {
        if(error.err() == CL_OUT_OF_RESOURCES)
        {
            cout << "Out of resources! Skipped" << endl;
        } else {
            throw error;
        }
    }

    return 0;
}

<commit_msg>Fix event timer precision issue<commit_after>#include <clpeak.h>

#define FETCH_PER_WI        16

int clPeak::runKernelLatency(cl::CommandQueue &queue, cl::Program &prog, device_info_t &devInfo)
{
    if(!isKernelLatency)
        return 0;

    cl::Context ctx = queue.getInfo<CL_QUEUE_CONTEXT>();
    cl_uint numItems = (devInfo.maxWGSize) * (devInfo.numCUs) * FETCH_PER_WI;
    cl::NDRange globalSize = (numItems / FETCH_PER_WI);
    cl::NDRange localSize = devInfo.maxWGSize;
    int iters = devInfo.kernelLatencyIters;
    float latency;

    try
    {
        cout << NEWLINE TAB TAB "Kernel launch latency : "; cout.flush();

        cl::Buffer inputBuf = cl::Buffer(ctx, CL_MEM_READ_ONLY, (numItems * sizeof(float)));
        cl::Buffer outputBuf = cl::Buffer(ctx, CL_MEM_WRITE_ONLY, (numItems * sizeof(float)));

        cl::Kernel kernel_v1(prog, "bandwidth_v1");
        kernel_v1.setArg(0, inputBuf), kernel_v1.setArg(1, outputBuf);

        // Dummy calls
        queue.enqueueNDRangeKernel(kernel_v1, cl::NullRange, globalSize, localSize);
        queue.enqueueNDRangeKernel(kernel_v1, cl::NullRange, globalSize, localSize);
        queue.finish();

        latency = 0;
        for(int i=0; i<iters; i++)
        {
            cl::Event timeEvent;
            queue.enqueueNDRangeKernel(kernel_v1, cl::NullRange, globalSize, localSize, NULL, &timeEvent);
            queue.finish();
            cl_ulong start = timeEvent.getProfilingInfo<CL_PROFILING_COMMAND_QUEUED>() / 1000;
            cl_ulong end = timeEvent.getProfilingInfo<CL_PROFILING_COMMAND_START>() / 1000;
            latency += (float)(end - start);
        }
        latency /= iters;

        cout << setprecision(2) << fixed;
        cout << latency << " us" << endl;
    }
    catch(cl::Error error)
    {
        if(error.err() == CL_OUT_OF_RESOURCES)
        {
            cout << "Out of resources! Skipped" << endl;
        } else {
            throw error;
        }
    }

    return 0;
}

<|endoftext|>


<commit_before>
#include "component.h"
#include "entity.h"
#include "gtest/gtest.h"

/*
class TestC : public aronnax::Component {
  public:
    void update(aronnax::Entity &entity, const uint32_t dt)
    {
      return;
    }

    std::string getType()
    {
      return "TestComponent";
    }
};

class EntityTest : public testing::Test {
protected:

  virtual void SetUp() {
  }

  // Declares the variables your tests want to use.
  aronnax::Components cla_;
  aronnax::Entity ea_;
};
*/

TEST(Entity, DefaultConstructor) {
  const aronnax::Components cla_;
  const aronnax::Entity ea_(cla_);
  EXPECT_EQ(0, ea_.pos.x) << "Constructs with position as 0 by default";
  EXPECT_EQ(0, ea_.pos.y);
  EXPECT_EQ(0, ea_.box.x);
  EXPECT_EQ(0, ea_.box.y);
  EXPECT_EQ(0, ea_.v.x);
  EXPECT_EQ(0, ea_.v.y);
}
<commit_msg>Change entity test to use fixtures<commit_after>
#include "component.h"
#include "entity.h"
#include "gtest/gtest.h"

/*
class TestC : public aronnax::Component {
  public:
    void update(aronnax::Entity &entity, const uint32_t dt)
    {
      return;
    }

    std::string getType()
    {
      return "TestComponent";
    }
};
*/

class EntityTest : public testing::Test {
protected:

  virtual void SetUp() {
    ea_ = new aronnax::Entity(cla_);
  }

  // Declares the variables your tests want to use.
  aronnax::Components cla_;
  aronnax::Entity* ea_;
};

TEST_F(EntityTest, DefaultConstructor) {
  EXPECT_EQ(0, ea_->pos.x) << "Constructs with position as 0 by default";
  EXPECT_EQ(0, ea_->pos.y);
  EXPECT_EQ(0, ea_->box.x);
  EXPECT_EQ(0, ea_->box.y);
  EXPECT_EQ(0, ea_->v.x);
  EXPECT_EQ(0, ea_->v.y);
}
<|endoftext|>


<commit_before>#include "loggers.hh"
#include "progress-bar.hh"

namespace nix {

LogFormat defaultLogFormat = LogFormat::raw;

LogFormat parseLogFormat(const std::string & logFormatStr) {
    if (logFormatStr == "raw")
        return LogFormat::raw;
    else if (logFormatStr == "raw-with-logs")
        return LogFormat::rawWithLogs;
    else if (logFormatStr == "internal-json")
        return LogFormat::internalJson;
    else if (logFormatStr == "bar")
        return LogFormat::bar;
    else if (logFormatStr == "bar-with-logs")
        return LogFormat::barWithLogs;
    throw Error("option 'log-format' has an invalid value '%s'", logFormatStr);
}

Logger * makeDefaultLogger() {
    switch (defaultLogFormat) {
    case LogFormat::raw:
        return makeSimpleLogger(false);
    case LogFormat::rawWithLogs:
        return makeSimpleLogger(true);
    case LogFormat::internalJson:
        return makeJSONLogger(*makeSimpleLogger());
    case LogFormat::bar:
        return makeProgressBar();
    case LogFormat::barWithLogs:
        return makeProgressBar(true);
    }
}

void setLogFormat(const std::string & logFormatStr) {
    setLogFormat(parseLogFormat(logFormatStr));
}

void setLogFormat(const LogFormat & logFormat) {
    defaultLogFormat = logFormat;
    createDefaultLogger();
}

void createDefaultLogger() {
    logger = makeDefaultLogger();
}

}
<commit_msg>Shut up warning<commit_after>#include "loggers.hh"
#include "progress-bar.hh"

namespace nix {

LogFormat defaultLogFormat = LogFormat::raw;

LogFormat parseLogFormat(const std::string & logFormatStr) {
    if (logFormatStr == "raw")
        return LogFormat::raw;
    else if (logFormatStr == "raw-with-logs")
        return LogFormat::rawWithLogs;
    else if (logFormatStr == "internal-json")
        return LogFormat::internalJson;
    else if (logFormatStr == "bar")
        return LogFormat::bar;
    else if (logFormatStr == "bar-with-logs")
        return LogFormat::barWithLogs;
    throw Error("option 'log-format' has an invalid value '%s'", logFormatStr);
}

Logger * makeDefaultLogger() {
    switch (defaultLogFormat) {
    case LogFormat::raw:
        return makeSimpleLogger(false);
    case LogFormat::rawWithLogs:
        return makeSimpleLogger(true);
    case LogFormat::internalJson:
        return makeJSONLogger(*makeSimpleLogger());
    case LogFormat::bar:
        return makeProgressBar();
    case LogFormat::barWithLogs:
        return makeProgressBar(true);
    default:
        abort();
    }
}

void setLogFormat(const std::string & logFormatStr) {
    setLogFormat(parseLogFormat(logFormatStr));
}

void setLogFormat(const LogFormat & logFormat) {
    defaultLogFormat = logFormat;
    createDefaultLogger();
}

void createDefaultLogger() {
    logger = makeDefaultLogger();
}

}
<|endoftext|>