<commit_before>/* String conversion definitions.
 *
 * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/stringconv instead.
 *
 * Copyright (c) 2000-2019, Jeroen T. Vermeulen.
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 */
#ifndef PQXX_H_STRINGCONV
#define PQXX_H_STRINGCONV

#include "pqxx/compiler-public.hxx"

#include <algorithm>
#include <cstring>
#include <limits>
#include <sstream>
#include <stdexcept>
#include <typeinfo>

#if __has_include(<charconv>)
#include <charconv>
#endif

#include "pqxx/except.hxx"

namespace pqxx::internal
{
/// Implementation classes for @c str.
/** We can't define these directly as @c str because of the way
 * @c std::enable_if works: to make that work, we need an extra template
 * parameter, which then seems to break template deduction when we define a
 * @c str{value}.
 */
template<typename T, typename E> class str_impl;

/// Attempt to demangle @c std::type_info::name() to something human-readable.
PQXX_LIBEXPORT std::string demangle_type_name(const char[]);
} // namespace pqxx::internal

namespace pqxx
{
/// Marker-type wrapper: zero-terminated @c std::string_view.
/** This is basically a @c std::string_view, but it adds the guarantee that
 * if its data pointer is non-null, there is a terminating zero byte right
 * after the contents.
 *
 * This means that it can also be used as a C-style string, which often matters
 * since libpqxx builds on top of a C library.  Therefore, it also adds a
 * @c c_str method.
 */
class PQXX_LIBEXPORT zview : public std::string_view
{
public:
  template<typename ...Args> constexpr zview(Args &&...args) :
    std::string_view(std::forward<Args>(args)...)
  {}

  /// Either a null pointer, or a zero-terminated text buffer.
  constexpr const char *c_str() const noexcept { return data(); }
};

/**
 * @defgroup stringconversion String conversion
 *
 * The PostgreSQL server accepts and represents data in string form.  It has
 * its own formats for various data types.  The string conversions define how
 * various C++ types translate to and from their respective PostgreSQL text
 * representations.
 *
 * Each conversion is defined by specialisations of certain templates:
 * @c string_traits, @c to_buf, and @c str.  It gets complicated if you want
 * top performance, but until you do, all you really need to care about when
 * converting values between C++ in-memory representations such as @c int and
 * the postgres string representations is the @c pqxx::to_string and
 * @c pqxx::from_string functions.
 *
 * If you need to convert a type which is not supported out of the box, you'll
 * need to define your own specialisations for these templates, similar to the
 * ones defined here and in `pqxx/conversions.hxx`.  Any conversion code which
 * "sees" your specialisation will now support your conversion.  In particular,
 * you'll be able to read result fields into a variable of the new type.
 *
 * There is a macro to help you define conversions for individual enumeration
 * types.  The conversion will represent enumeration values as numeric strings.
 */
//@{

/// A human-readable name for a type, used in error messages and such.
/** Actually this may not always be very user-friendly.  It uses
 * @c std::type_info::name().  On gcc-like compilers we try to demangle its
 * output.  Visual Studio produces human-friendly names out of the box.
 *
 * This variable is not inline.  Inlining it gives rise to "memory leak"
 * warnings from asan, the address sanitizer, possibly from use of
 * @c std::type_info::name.
 */
template<typename TYPE> const std::string type_name{
	internal::demangle_type_name(typeid(TYPE).name())};

/// Traits describing a type's "null value," if any.
/** Some C++ types have a special value or state which correspond directly to
 * SQL's NULL.
 *
 * The @c nullness traits describe whether it exists, and whether a particular
 * value is null.
 */
template<typename TYPE, typename ENABLE = void> struct nullness
{
  /// Does this type have a null value?
  static bool has_null;

  /// Is @c value a null?
  static bool is_null(const TYPE &value);

  /// Return a null value.
  /** Don't use this in generic code to compare a value and see whether it is
   * null.  Some types may have multiple null values which do not compare as
   * equal, or may define a null value which is not equal to anything including
   * itself, like in SQL.
   */
  static TYPE null();
};

/// Nullness traits describing a type which does not have a null value.
template<typename TYPE> struct no_null
{
  static constexpr bool has_null = false;
  static constexpr bool is_null(const TYPE &) noexcept { return false; }
};

// XXX: Add template parameter for binary support.
/// Traits class for use in string conversions.
/** Specialize this template for a type for which you wish to add to_string
 * and from_string support.
 */
template<typename TYPE, typename ENABLE = void> struct string_traits
{
  /// Return a @c string_view representing value, plus terminating zero.
  /** Produces a @c string_view containing the PostgreSQL string representation
   * for @c value.
   *
   * Uses the space from @c begin to @c end as a buffer, if needed.  The
   * returned string may lie somewhere in that buffer, or it may be a
   * compile-time constant, or it may be null if value was a null value.  Even
   * if the string is stored in the buffer, its @c begin() may or may not be
   * the same as @c begin.
   *
   * The @c string_view is guaranteed to be valid as long as the buffer from
   * @c begin to @c end remains accessible and unmodified.
   *
   * @throws pqxx::conversion_overrun if the provided buffer space may not be
   * enough.  For maximum performance, this is a conservative estimate.  It may
   * complain about a buffer which is actually large enough for your value, if
   * an exact check gets too expensive.
   */
  static inline zview to_buf(char *begin, char *end, const TYPE &value);

  static inline TYPE from_string(std::string_view text);
};

// XXX: Can we do this more efficiently for arbitrary tuples of values?
// XXX: An "into_buf" might help: to_buf with exact placement.
/// Value-to-string converter: represent value as a postgres-compatible string.
/** @warning This feature is experimental.  It may change, or disappear.
 *
 * Turns a value of (more or less) any type into its PostgreSQL string
 * representation.  It keeps the string representation "alive" in memory while
 * the @c str object exists.  After that, accessing the string becomes
 * undefined.
 *
 * @c warning The value cannot be null.
 *
 * In situations where convenience matters more than performance, use the
 * @c to_string functions which create and return a @c std::string.  It's
 * expensive but convenient.  If you need extreme memory efficiency, consider
 * using @c to_buf and allocating your own buffer.  In the space between those
 * two extremes, use @c str.
 */
template<typename T> class str : internal::str_impl<T, void>
{
public:
  str() =delete;
  str(const str &) =delete;
  str(str &&) =delete;

  explicit str(const T &value) : internal::str_impl<T, void>{value} {}
  explicit str(T &value) : internal::str_impl<T, void>{value} {}

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

  using internal::str_impl<T, void>::view;
  using internal::str_impl<T, void>::c_str;
  operator zview() const { return view(); }
};

/// Nullness: Enums do not have an inherent null value.
template<typename ENUM>
struct nullness<ENUM, std::enable_if_t<std::is_enum_v<ENUM>>> : no_null<ENUM>
{
};
} // namespace pqxx

namespace pqxx::internal
{
/// Helper class for defining enum conversions.
/** The conversion will convert enum values to numeric strings, and vice versa.
 *
 * To define a string conversion for an enum type, derive a @c string_traits
 * specialisation for the enum from this struct.
 *
 * There's usually an easier way though: the @c PQXX_DECLARE_ENUM_CONVERSION
 * macro.  Use @c enum_traits manually only if you need to customise your
 * traits type in more detail.
 */
template<typename ENUM>
struct enum_traits
{
  using impl_type = std::underlying_type_t<ENUM>;
  using impl_traits = string_traits<impl_type>;

  static inline constexpr int buffer_budget =
	string_traits<impl_type>::buffer_budget;

  static constexpr zview to_buf(char *begin, char *end, const ENUM &value)
  { return impl_traits::to_buf(begin, end, static_cast<impl_type>(value)); }

  static ENUM from_string(std::string_view text)
  { return static_cast<ENUM>(impl_traits::from_string(text)); }
};
} // namespace pqxx::internal

/// Macro: Define a string conversion for an enum type.
/** This specialises the @c pqxx::string_traits template, so use it in the
 * @c ::pqxx namespace.
 *
 * For example:
 *
 *      #include <iostream>
 *      #include <pqxx/strconv>
 *      enum X { xa, xb };
 *      namespace pqxx { PQXX_DECLARE_ENUM_CONVERSION(x); }
 *      int main() { std::cout << pqxx::to_string(xa) << std::endl; }
 */
#define PQXX_DECLARE_ENUM_CONVERSION(ENUM) \
template<> struct string_traits<ENUM> : pqxx::internal::enum_traits<ENUM> {}; \
template<> const std::string type_name<ENUM>{#ENUM}

namespace pqxx
{
/// Attempt to convert postgres-generated string to given built-in type.
/** If the form of the value found in the string does not match the expected
 * type, e.g. if a decimal point is found when converting to an integer type,
 * the conversion fails.  Overflows (e.g. converting "9999999999" to a 16-bit
 * C++ type) are also treated as errors.  If in some cases this behaviour should
 * be inappropriate, convert to something bigger such as @c long @c int first
 * and then truncate the resulting value.
 *
 * Only the simplest possible conversions are supported.  Fancy features like
 * hexadecimal or octal, spurious signs, or exponent notation won't work.
 * Whitespace is not stripped away.  Only the kinds of strings that come out of
 * PostgreSQL and out of to_string() can be converted.
 */
template<typename T> inline T from_string(std::string_view text)
{ return string_traits<T>::from_string(text); }

/// Attempt to convert postgres-generated string to given built-in object.
/** This is like the single-argument form of the function, except instead of
 * returning the value, it sets @c obj to the value.
 *
 * You may find this more convenient in that it infers the type you want from
 * the argument you pass.  But there are disadvantages: it requires an
 * assignment operator, and it may be less efficient.
 */
template<typename T> inline void from_string(std::string_view text, T &obj)
{ obj = from_string<T>(text); }

/// Convert a value to a readable string that PostgreSQL will understand.
/** This is the convenient way to represent a value as text.  It's also fairly
 * expensive, since it creates a @c std::string.  The @c pqxx::str class is a
 * more efficient but slightly less convenient alternative.  Probably.
 * Depending on the type of value you're trying to convert.
 *
 * The conversion does no special formatting, and ignores any locale settings.
 * The resulting string will be human-readable and in a format suitable for use
 * in SQL queries.  It won't have niceties such as "thousands separators"
 * though.
 */
template<typename TYPE> inline std::string to_string(const TYPE &obj);

/// Is @c value null?
template<typename TYPE> inline bool is_null(const TYPE &value)
{
  if constexpr (nullness<TYPE>::has_null) return nullness<TYPE>::is_null(value);
  else return false;
}
//@}
} // namespace pqxx

#include "pqxx/internal/conversions.hxx"
#endif
<commit_msg>Remove obsolete parameter.<commit_after>/* String conversion definitions.
 *
 * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/stringconv instead.
 *
 * Copyright (c) 2000-2019, Jeroen T. Vermeulen.
 *
 * See COPYING for copyright license.  If you did not receive a file called
 * COPYING with this source code, please notify the distributor of this mistake,
 * or contact the author.
 */
#ifndef PQXX_H_STRINGCONV
#define PQXX_H_STRINGCONV

#include "pqxx/compiler-public.hxx"

#include <algorithm>
#include <cstring>
#include <limits>
#include <sstream>
#include <stdexcept>
#include <typeinfo>

#if __has_include(<charconv>)
#include <charconv>
#endif

#include "pqxx/except.hxx"

namespace pqxx::internal
{
/// Implementation classes for @c str.
/** We can't define these directly as @c str because of the way
 * @c std::enable_if works: to make that work, we need an extra template
 * parameter, which then seems to break template deduction when we define a
 * @c str{value}.
 */
template<typename T, typename E> class str_impl;

/// Attempt to demangle @c std::type_info::name() to something human-readable.
PQXX_LIBEXPORT std::string demangle_type_name(const char[]);
} // namespace pqxx::internal

namespace pqxx
{
/// Marker-type wrapper: zero-terminated @c std::string_view.
/** This is basically a @c std::string_view, but it adds the guarantee that
 * if its data pointer is non-null, there is a terminating zero byte right
 * after the contents.
 *
 * This means that it can also be used as a C-style string, which often matters
 * since libpqxx builds on top of a C library.  Therefore, it also adds a
 * @c c_str method.
 */
class PQXX_LIBEXPORT zview : public std::string_view
{
public:
  template<typename ...Args> constexpr zview(Args &&...args) :
    std::string_view(std::forward<Args>(args)...)
  {}

  /// Either a null pointer, or a zero-terminated text buffer.
  constexpr const char *c_str() const noexcept { return data(); }
};

/**
 * @defgroup stringconversion String conversion
 *
 * The PostgreSQL server accepts and represents data in string form.  It has
 * its own formats for various data types.  The string conversions define how
 * various C++ types translate to and from their respective PostgreSQL text
 * representations.
 *
 * Each conversion is defined by specialisations of certain templates:
 * @c string_traits, @c to_buf, and @c str.  It gets complicated if you want
 * top performance, but until you do, all you really need to care about when
 * converting values between C++ in-memory representations such as @c int and
 * the postgres string representations is the @c pqxx::to_string and
 * @c pqxx::from_string functions.
 *
 * If you need to convert a type which is not supported out of the box, you'll
 * need to define your own specialisations for these templates, similar to the
 * ones defined here and in `pqxx/conversions.hxx`.  Any conversion code which
 * "sees" your specialisation will now support your conversion.  In particular,
 * you'll be able to read result fields into a variable of the new type.
 *
 * There is a macro to help you define conversions for individual enumeration
 * types.  The conversion will represent enumeration values as numeric strings.
 */
//@{

/// A human-readable name for a type, used in error messages and such.
/** Actually this may not always be very user-friendly.  It uses
 * @c std::type_info::name().  On gcc-like compilers we try to demangle its
 * output.  Visual Studio produces human-friendly names out of the box.
 *
 * This variable is not inline.  Inlining it gives rise to "memory leak"
 * warnings from asan, the address sanitizer, possibly from use of
 * @c std::type_info::name.
 */
template<typename TYPE> const std::string type_name{
	internal::demangle_type_name(typeid(TYPE).name())};

/// Traits describing a type's "null value," if any.
/** Some C++ types have a special value or state which correspond directly to
 * SQL's NULL.
 *
 * The @c nullness traits describe whether it exists, and whether a particular
 * value is null.
 */
template<typename TYPE, typename ENABLE = void> struct nullness
{
  /// Does this type have a null value?
  static bool has_null;

  /// Is @c value a null?
  static bool is_null(const TYPE &value);

  /// Return a null value.
  /** Don't use this in generic code to compare a value and see whether it is
   * null.  Some types may have multiple null values which do not compare as
   * equal, or may define a null value which is not equal to anything including
   * itself, like in SQL.
   */
  static TYPE null();
};

/// Nullness traits describing a type which does not have a null value.
template<typename TYPE> struct no_null
{
  static constexpr bool has_null = false;
  static constexpr bool is_null(const TYPE &) noexcept { return false; }
};

// XXX: Add template parameter for binary support.
/// Traits class for use in string conversions.
/** Specialize this template for a type for which you wish to add to_string
 * and from_string support.
 */
template<typename TYPE> struct string_traits
{
  /// Return a @c string_view representing value, plus terminating zero.
  /** Produces a @c string_view containing the PostgreSQL string representation
   * for @c value.
   *
   * Uses the space from @c begin to @c end as a buffer, if needed.  The
   * returned string may lie somewhere in that buffer, or it may be a
   * compile-time constant, or it may be null if value was a null value.  Even
   * if the string is stored in the buffer, its @c begin() may or may not be
   * the same as @c begin.
   *
   * The @c string_view is guaranteed to be valid as long as the buffer from
   * @c begin to @c end remains accessible and unmodified.
   *
   * @throws pqxx::conversion_overrun if the provided buffer space may not be
   * enough.  For maximum performance, this is a conservative estimate.  It may
   * complain about a buffer which is actually large enough for your value, if
   * an exact check gets too expensive.
   */
  static inline zview to_buf(char *begin, char *end, const TYPE &value);

  static inline TYPE from_string(std::string_view text);
};

// XXX: Can we do this more efficiently for arbitrary tuples of values?
// XXX: An "into_buf" might help: to_buf with exact placement.
/// Value-to-string converter: represent value as a postgres-compatible string.
/** @warning This feature is experimental.  It may change, or disappear.
 *
 * Turns a value of (more or less) any type into its PostgreSQL string
 * representation.  It keeps the string representation "alive" in memory while
 * the @c str object exists.  After that, accessing the string becomes
 * undefined.
 *
 * @c warning The value cannot be null.
 *
 * In situations where convenience matters more than performance, use the
 * @c to_string functions which create and return a @c std::string.  It's
 * expensive but convenient.  If you need extreme memory efficiency, consider
 * using @c to_buf and allocating your own buffer.  In the space between those
 * two extremes, use @c str.
 */
template<typename T> class str : internal::str_impl<T, void>
{
public:
  str() =delete;
  str(const str &) =delete;
  str(str &&) =delete;

  explicit str(const T &value) : internal::str_impl<T, void>{value} {}
  explicit str(T &value) : internal::str_impl<T, void>{value} {}

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

  using internal::str_impl<T, void>::view;
  using internal::str_impl<T, void>::c_str;
  operator zview() const { return view(); }
};

/// Nullness: Enums do not have an inherent null value.
template<typename ENUM>
struct nullness<ENUM, std::enable_if_t<std::is_enum_v<ENUM>>> : no_null<ENUM>
{
};
} // namespace pqxx

namespace pqxx::internal
{
/// Helper class for defining enum conversions.
/** The conversion will convert enum values to numeric strings, and vice versa.
 *
 * To define a string conversion for an enum type, derive a @c string_traits
 * specialisation for the enum from this struct.
 *
 * There's usually an easier way though: the @c PQXX_DECLARE_ENUM_CONVERSION
 * macro.  Use @c enum_traits manually only if you need to customise your
 * traits type in more detail.
 */
template<typename ENUM>
struct enum_traits
{
  using impl_type = std::underlying_type_t<ENUM>;
  using impl_traits = string_traits<impl_type>;

  static inline constexpr int buffer_budget =
	string_traits<impl_type>::buffer_budget;

  static constexpr zview to_buf(char *begin, char *end, const ENUM &value)
  { return impl_traits::to_buf(begin, end, static_cast<impl_type>(value)); }

  static ENUM from_string(std::string_view text)
  { return static_cast<ENUM>(impl_traits::from_string(text)); }
};
} // namespace pqxx::internal

/// Macro: Define a string conversion for an enum type.
/** This specialises the @c pqxx::string_traits template, so use it in the
 * @c ::pqxx namespace.
 *
 * For example:
 *
 *      #include <iostream>
 *      #include <pqxx/strconv>
 *      enum X { xa, xb };
 *      namespace pqxx { PQXX_DECLARE_ENUM_CONVERSION(x); }
 *      int main() { std::cout << pqxx::to_string(xa) << std::endl; }
 */
#define PQXX_DECLARE_ENUM_CONVERSION(ENUM) \
template<> struct string_traits<ENUM> : pqxx::internal::enum_traits<ENUM> {}; \
template<> const std::string type_name<ENUM>{#ENUM}

namespace pqxx
{
/// Attempt to convert postgres-generated string to given built-in type.
/** If the form of the value found in the string does not match the expected
 * type, e.g. if a decimal point is found when converting to an integer type,
 * the conversion fails.  Overflows (e.g. converting "9999999999" to a 16-bit
 * C++ type) are also treated as errors.  If in some cases this behaviour should
 * be inappropriate, convert to something bigger such as @c long @c int first
 * and then truncate the resulting value.
 *
 * Only the simplest possible conversions are supported.  Fancy features like
 * hexadecimal or octal, spurious signs, or exponent notation won't work.
 * Whitespace is not stripped away.  Only the kinds of strings that come out of
 * PostgreSQL and out of to_string() can be converted.
 */
template<typename T> inline T from_string(std::string_view text)
{ return string_traits<T>::from_string(text); }

/// Attempt to convert postgres-generated string to given built-in object.
/** This is like the single-argument form of the function, except instead of
 * returning the value, it sets @c obj to the value.
 *
 * You may find this more convenient in that it infers the type you want from
 * the argument you pass.  But there are disadvantages: it requires an
 * assignment operator, and it may be less efficient.
 */
template<typename T> inline void from_string(std::string_view text, T &obj)
{ obj = from_string<T>(text); }

/// Convert a value to a readable string that PostgreSQL will understand.
/** This is the convenient way to represent a value as text.  It's also fairly
 * expensive, since it creates a @c std::string.  The @c pqxx::str class is a
 * more efficient but slightly less convenient alternative.  Probably.
 * Depending on the type of value you're trying to convert.
 *
 * The conversion does no special formatting, and ignores any locale settings.
 * The resulting string will be human-readable and in a format suitable for use
 * in SQL queries.  It won't have niceties such as "thousands separators"
 * though.
 */
template<typename TYPE> inline std::string to_string(const TYPE &obj);

/// Is @c value null?
template<typename TYPE> inline bool is_null(const TYPE &value)
{
  if constexpr (nullness<TYPE>::has_null) return nullness<TYPE>::is_null(value);
  else return false;
}
//@}
} // namespace pqxx

#include "pqxx/internal/conversions.hxx"
#endif
<|endoftext|>


<commit_before>#ifndef PROTON_TUPLE_HEADER
#define PROTON_TUPLE_HEADER

/** @file tuple.hpp
 *  @brief tuple support.
 *  Please include this header instead of \<tuple\>.
 */

#include <tuple>
#include <algorithm>
#include <iostream>
#include <initializer_list>
#include <algorithm>
#include <stdexcept>
#include <limits>

#include <proton/base.hpp>

namespace proton{

namespace detail{

// helper function to print a tuple of any size
template<typename T, std::size_t I>
struct output_tuple {
    static void output(std::ostream& s, T&& t)
    {
        output_tuple<T, I-1>::output(s,t);
        s << ", " << std::get<I-1>(t);
    }
};

template<typename T>
struct output_tuple<T, 1> {
    static void output(std::ostream& s, T&& t)
    {
        s << std::get<0>(t);
    }
};

template<typename T>
struct output_tuple<T, 0> {
    static void output(std::ostream& s, T&& t)
    {
    }
};

constexpr long fix_index(long i, long size)
{
    return (i>size)?
				size
			:(
				(i<0)?
					(i+size < 0 ?
						0
					:
						i+size
					)
				:
					i
			);
}

constexpr long sub_index(long i, long size)
{
    return (i>=size)?
				size-1
			:(
				(i<0)?
					(i+size < 0 ?
						0
					:
						i+size
					)
				:
					i
			);
}

constexpr long get_index(long i, long size)
{
    return (i>=size)?
				-1
			:(
				(i<0)?
					(i+size < 0 ?
						-1
					:
						i+size
					)
				:
					i
			);
}

template<long i, typename ...T>
struct at_index{
	const std::tuple<T...>* p;
	typedef decltype(std::get<get_index(i,sizeof...(T))>(*p)) type;
};

constexpr long fix_size(long begin, long end, long size)
{
	return fix_index(begin,size)>fix_index(end,size)  ?
				0
			:
				fix_index(end,size)-fix_index(begin,size);
}

template<typename T, size_t begin, size_t size>
struct sub{
private:
	static_assert(begin < std::tuple_size<T>::value, "out of range");

	std::tuple<typename std::tuple_element<begin, T>::type> *p;
	typedef typename sub<T, begin+1,
						(begin+size > std::tuple_size<T>::value ?
							(std::tuple_size<T>::value-begin-1)
							: (size-1))
						>::type next_types;
	next_types* q;

public:
	typedef decltype(std::tuple_cat(*p,*q)) type;
};

template<typename T, size_t begin>
struct sub<T, begin, 0>{
	typedef std::tuple<> type;
};

template<typename T, size_t begin>
struct sub<T,begin,1>{
	static_assert(begin < std::tuple_size<T>::value, "out of range");

	typedef std::tuple<typename std::tuple_element<begin,T>::type > type;
};

template<typename ...T>
struct len_t<std::tuple<T...> >{
    static size_t result(const std::tuple<T...>& x)
    {
        return sizeof...(T);
    }
};

template<typename T, long begin, long end>
struct sub_type{
public:
	typedef typename sub<T, fix_index(begin, std::tuple_size<T>::value),
			fix_size(begin, end, std::tuple_size<T>::value)>::type type;
};

} // ns detail

/** @addtogroup tuple
 * @{
 */

/** like x[index] in python
 */

template<long index, typename ...T>
typename detail::at_index<index,T...>::type
	at(const std::tuple<T...>& x)
{
	return std::get<detail::get_index(index,sizeof...(T))>(x);
}

/** get a slice of tuple x[begin:end] in python
 */
template<long begin, long end=std::numeric_limits<long>::max(), typename ...T>
typename detail::sub_type<std::tuple<T...>, begin, end>::type
	sub(const std::tuple<T...>& x)
{
	typedef typename detail::sub_type<std::tuple<T...>, begin, end>::type ret_t;
#ifdef __clang__
	return ret_t(*reinterpret_cast<const ret_t*>(&std::get<(detail::sub_index(begin, sizeof...(T)))>(x)));
#else
	#ifdef __GNUC__
		return ret_t(*reinterpret_cast<const ret_t*>(&std::get<(detail::sub_index(end-1, sizeof...(T)))>(x)));
	#else
		static_assert(0, "unknown compiler")
	#endif
#endif
}

/** general output for tuple.
 * @param s the output stream
 * @param x the tuple to be outputed
 * @return s
 */
template <typename ...T>
std::ostream& operator<<(std::ostream& s, const std::tuple<T...>& x)
{
    s << "(";
    detail::output_tuple<decltype(x), sizeof...(T)>::output(s,x);
    s << ")";
    return s;
}

template <typename ...T>
std::wostream& operator<<(std::wostream& s, const std::tuple<T...>& x)
{
    s << L"(";
    detail::output_tuple<decltype(x), sizeof...(T)>::output(s,x);
    s << L")";
    return s;
}

/** tuple + tuple
 */
template<typename T2, typename ...T1>
auto operator+(const std::tuple<T1...>& x, T2&& y) -> decltype(std::tuple_cat(x,y))
{
	return std::tuple_cat(x,y);
}

template<typename T2, typename ...T1>
auto operator+(std::tuple<T1...>&& x, T2&& y) -> decltype(std::tuple_cat(x,y))
{
	return std::tuple_cat(x,y);
}

/** eq to make_tuple
 */
template<typename ...T>
auto _t(T&& ...x) -> decltype(std::make_tuple(x...))
{
	return std::make_tuple(x...);
}

/** eq to forward_as_tuple
 */
template<typename ...T>
auto _f(T&& ...x) -> decltype(std::forward_as_tuple(x...))
{
	return std::forward_as_tuple(x...);
}

#if 0
/* vector_ * n
 */
template<typename T, typename A>
vector_<T,A> operator*(const std::vector<T,A>& s, size_t n)
{
    vector_<T,A> r;
    r.reserve(s.size()*n);
    for(size_t i=0; i<n; i++)
        r.extend(s);
    return r;
}

/* n * vector_
 */
template<typename T, typename A>
vector_<T,A> operator*(size_t n, const std::vector<T,A>& s)
{
    return s*n;
}
#endif

/**
 * @example tuple.cpp
 * @}
 */
}

#endif // PROTON_TUPLE_HEADER
<commit_msg>test another workaround<commit_after>#ifndef PROTON_TUPLE_HEADER
#define PROTON_TUPLE_HEADER

/** @file tuple.hpp
 *  @brief tuple support.
 *  Please include this header instead of \<tuple\>.
 */

#include <tuple>
#include <algorithm>
#include <iostream>
#include <initializer_list>
#include <algorithm>
#include <stdexcept>
#include <limits>

#include <proton/base.hpp>

namespace proton{

namespace detail{

// helper function to print a tuple of any size
template<typename T, std::size_t I>
struct output_tuple {
    static void output(std::ostream& s, T&& t)
    {
        output_tuple<T, I-1>::output(s,t);
        s << ", " << std::get<I-1>(t);
    }
};

template<typename T>
struct output_tuple<T, 1> {
    static void output(std::ostream& s, T&& t)
    {
        s << std::get<0>(t);
    }
};

template<typename T>
struct output_tuple<T, 0> {
    static void output(std::ostream& s, T&& t)
    {
    }
};

constexpr long fix_index(long i, long size)
{
    return (i>size)?
				size
			:(
				(i<0)?
					(i+size < 0 ?
						0
					:
						i+size
					)
				:
					i
			);
}

constexpr long sub_index(long i, long size)
{
    return (i>=size)?
				size-1
			:(
				(i<0)?
					(i+size < 0 ?
						0
					:
						i+size
					)
				:
					i
			);
}

constexpr long get_index(long i, long size)
{
    return (i>=size)?
				-1
			:(
				(i<0)?
					(i+size < 0 ?
						-1
					:
						i+size
					)
				:
					i
			);
}

template<long i, typename ...T>
struct at_index{
	const std::tuple<T...>* p;
	typedef decltype(std::get<get_index(i,sizeof...(T))>(*p)) type;
};

constexpr long fix_size(long begin, long end, long size)
{
	return fix_index(begin,size)>fix_index(end,size)  ?
				0
			:
				fix_index(end,size)-fix_index(begin,size);
}

template<typename T, size_t begin, size_t size>
struct sub{
private:
	static_assert(begin < std::tuple_size<T>::value, "out of range");

	std::tuple<typename std::tuple_element<begin, T>::type> *p;
	typedef typename sub<T, begin+1,
						(begin+size > std::tuple_size<T>::value ?
							(std::tuple_size<T>::value-begin-1)
							: (size-1))
						>::type next_types;
	next_types* q;

public:
	typedef decltype(std::tuple_cat(*p,*q)) type;
};

template<typename T, size_t begin>
struct sub<T, begin, 0>{
	typedef std::tuple<> type;
};

template<typename T, size_t begin>
struct sub<T,begin,1>{
	static_assert(begin < std::tuple_size<T>::value, "out of range");

	typedef std::tuple<typename std::tuple_element<begin,T>::type > type;
};

template<typename ...T>
struct len_t<std::tuple<T...> >{
    static size_t result(const std::tuple<T...>& x)
    {
        return sizeof...(T);
    }
};

template<typename T>
class tuple_size;

template<typename ...T>
class tuple_size<std::tuple<T...> >{
public:
	static constexpr size_t value=sizeof...(T);
};

template<typename T, long begin, long end>
struct sub_type{
public:
	typedef typename sub<T, fix_index(begin, tuple_size<T>::value),
			fix_size(begin, end, tuple_size<T>::value)>::type type;
};

} // ns detail

/** @addtogroup tuple
 * @{
 */

/** like x[index] in python
 */

template<long index, typename ...T>
typename detail::at_index<index,T...>::type
	at(const std::tuple<T...>& x)
{
	return std::get<detail::get_index(index,sizeof...(T))>(x);
}

/** get a slice of tuple x[begin:end] in python
 */
template<long begin, long end=std::numeric_limits<long>::max(), typename ...T>
typename detail::sub_type<std::tuple<T...>, begin, end>::type
	sub(const std::tuple<T...>& x)
{
	typedef typename detail::sub_type<std::tuple<T...>, begin, end>::type ret_t;
#ifdef __clang__
	return ret_t(*reinterpret_cast<const ret_t*>(&std::get<(detail::sub_index(begin, sizeof...(T)))>(x)));
#else
	#ifdef __GNUC__
		return ret_t(*reinterpret_cast<const ret_t*>(&std::get<(detail::sub_index(end-1, sizeof...(T)))>(x)));
	#else
		static_assert(0, "unknown compiler")
	#endif
#endif
}

/** general output for tuple.
 * @param s the output stream
 * @param x the tuple to be outputed
 * @return s
 */
template <typename ...T>
std::ostream& operator<<(std::ostream& s, const std::tuple<T...>& x)
{
    s << "(";
    detail::output_tuple<decltype(x), sizeof...(T)>::output(s,x);
    s << ")";
    return s;
}

template <typename ...T>
std::wostream& operator<<(std::wostream& s, const std::tuple<T...>& x)
{
    s << L"(";
    detail::output_tuple<decltype(x), sizeof...(T)>::output(s,x);
    s << L")";
    return s;
}

/** tuple + tuple
 */
template<typename T2, typename ...T1>
auto operator+(const std::tuple<T1...>& x, T2&& y) -> decltype(std::tuple_cat(x,y))
{
	return std::tuple_cat(x,y);
}

template<typename T2, typename ...T1>
auto operator+(std::tuple<T1...>&& x, T2&& y) -> decltype(std::tuple_cat(x,y))
{
	return std::tuple_cat(x,y);
}

/** eq to make_tuple
 */
template<typename ...T>
auto _t(T&& ...x) -> decltype(std::make_tuple(x...))
{
	return std::make_tuple(x...);
}

/** eq to forward_as_tuple
 */
template<typename ...T>
auto _f(T&& ...x) -> decltype(std::forward_as_tuple(x...))
{
	return std::forward_as_tuple(x...);
}

#if 0
/* vector_ * n
 */
template<typename T, typename A>
vector_<T,A> operator*(const std::vector<T,A>& s, size_t n)
{
    vector_<T,A> r;
    r.reserve(s.size()*n);
    for(size_t i=0; i<n; i++)
        r.extend(s);
    return r;
}

/* n * vector_
 */
template<typename T, typename A>
vector_<T,A> operator*(size_t n, const std::vector<T,A>& s)
{
    return s*n;
}
#endif

/**
 * @example tuple.cpp
 * @}
 */
}

#endif // PROTON_TUPLE_HEADER
<|endoftext|>


<commit_before>#include "openmc/dagmc.h"

#include "openmc/cell.h"
#include "openmc/constants.h"
#include "openmc/error.h"
#include "openmc/file_utils.h"
#include "openmc/string_utils.h"
#include "openmc/settings.h"
#include "openmc/geometry.h"

#ifdef DAGMC

#include "uwuw.hpp"
#include "dagmcmetadata.hpp"

#endif

#include <string>
#include <sstream>
#include <algorithm>
#include <fstream>

namespace openmc {

#ifdef DAGMC
const bool dagmc_enabled = true;
#else
const bool dagmc_enabled = false;
#endif

}

#ifdef DAGMC

const std::string DAGMC_FILENAME = "dagmc.h5m";

namespace openmc {

namespace model {

moab::DagMC* DAG;

} // namespace model

bool get_uwuw_materials_xml(std::string& s) {
  UWUW uwuw(DAGMC_FILENAME.c_str());

  std::stringstream ss;
  bool uwuw_mats_present = false;
  if (uwuw.material_library.size() != 0) {
    uwuw_mats_present = true;
    // write header
    ss << "<?xml version=\"1.0\"?>\n";
    ss << "<materials>\n";
    const auto& mat_lib = uwuw.material_library;
    // write materials
    for (auto mat : mat_lib) { ss << mat.second.openmc("atom"); }
    // write footer
    ss << "</materials>";
    s = ss.str();
  }

  return uwuw_mats_present;
}

pugi::xml_document* read_uwuw_materials() {
  pugi::xml_document* doc = nullptr;

  std::string s;
  bool found_uwuw_mats = get_uwuw_materials_xml(s);
  if (found_uwuw_mats) {
    doc = new pugi::xml_document();
    pugi::xml_parse_result result = doc->load_string(s.c_str());
  }
  return doc;
}

bool write_uwuw_materials_xml() {
  std::string s;
  bool found_uwuw_mats = get_uwuw_materials_xml(s);
    // if there is a material library in the file
  if (found_uwuw_mats) {
    // write a material.xml file
    std::ofstream mats_xml("materials.xml");
    mats_xml << s;
    mats_xml.close();
  }

  return found_uwuw_mats;
}

void load_dagmc_geometry()
{
  if (!model::DAG) {
    model::DAG = new moab::DagMC();
  }

  /// Materials \\\

  // create uwuw instance
  UWUW uwuw(DAGMC_FILENAME.c_str());

  // check for uwuw material definitions
  bool using_uwuw = !uwuw.material_library.empty();

  // notify user if UWUW materials are going to be used
  if (using_uwuw) {
    std::cout << "Found UWUW Materials in the DAGMC geometry file.\n";
  }

  int32_t dagmc_univ_id = 0; // universe is always 0 for DAGMC runs

  // load the DAGMC geometry
  moab::ErrorCode rval = model::DAG->load_file(DAGMC_FILENAME.c_str());
  MB_CHK_ERR_CONT(rval);

  // initialize acceleration data structures
  rval = model::DAG->init_OBBTree();
  MB_CHK_ERR_CONT(rval);

  // parse model metadata
  dagmcMetaData DMD(model::DAG);
  if (using_uwuw) {
    DMD.load_property_data();
  }
  std::vector<std::string> keywords {"temp", "mat", "density", "boundary"};
  std::map<std::string, std::string> dum;
  std::string delimiters = ":/";
  rval = model::DAG->parse_properties(keywords, dum, delimiters.c_str());
  MB_CHK_ERR_CONT(rval);

  /// Cells (Volumes) \\\

  // initialize cell objects
  model::n_cells = model::DAG->num_entities(3);
  moab::EntityHandle graveyard = 0;
  for (int i = 0; i < model::n_cells; i++) {
    moab::EntityHandle vol_handle = model::DAG->entity_by_index(3, i+1);

    // set cell ids using global IDs
    DAGCell* c = new DAGCell();
    c->id_ = model::DAG->id_by_index(3, i+1);
    c->dagmc_ptr_ = model::DAG;
    c->universe_ = dagmc_univ_id; // set to zero for now
    c->fill_ = C_NONE; // no fill, single universe

    model::cells.push_back(c);
    model::cell_map[c->id_] = i;

    // Populate the Universe vector and dict
    auto it = model::universe_map.find(dagmc_univ_id);
    if (it == model::universe_map.end()) {
      model::universes.push_back(new Universe());
      model::universes.back()-> id_ = dagmc_univ_id;
      model::universes.back()->cells_.push_back(i);
      model::universe_map[dagmc_univ_id] = model::universes.size() - 1;
    } else {
      model::universes[it->second]->cells_.push_back(i);
    }

    // check for temperature assignment
    std::string temp_value;
    if (model::DAG->has_prop(vol_handle, "temp")) {
      rval = model::DAG->prop_value(vol_handle, "temp", temp_value);
      MB_CHK_ERR_CONT(rval);
      double temp = std::stod(temp_value);
      c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * temp));
    } else {
      c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * settings::temperature_default));
    }

    // MATERIALS

    if (model::DAG->is_implicit_complement(vol_handle)) {
      if (model::DAG->has_prop(vol_handle, "mat")) {
        // if the implicit complement has been assigned a material, use it
        std::string comp_mat = DMD.volume_material_property_data_eh[vol_handle];
        // Note: material numbers are set by UWUW
        int mat_number = uwuw.material_library[comp_mat].metadata["mat_number"].asInt();
        c->material_.push_back(mat_number);
      } else {
        // if no material is found, the implicit complement is void
        c->material_.push_back(MATERIAL_VOID);
      }
      continue;
    }

    // determine volume material assignment
    std::string mat_value;
    if (model::DAG->has_prop(vol_handle, "mat")) {
      rval = model::DAG->prop_value(vol_handle, "mat", mat_value);
      MB_CHK_ERR_CONT(rval);
    } else {
      std::stringstream err_msg;
      err_msg << "Volume " << c->id_ << " has no material assignment.";
      fatal_error(err_msg.str());
    }

    std::string cmp_str = mat_value;
    to_lower(cmp_str);

    if (cmp_str.find("graveyard") != std::string::npos) {
      graveyard = vol_handle;
    }

    // material void checks
    if (cmp_str.find("void") != std::string::npos   ||
        cmp_str.find("vacuum") != std::string::npos ||
        cmp_str.find("graveyard") != std::string::npos) {
      c->material_.push_back(MATERIAL_VOID);
    } else {
      if (using_uwuw) {
        // lookup material in uwuw if the were present
        std::string uwuw_mat = DMD.volume_material_property_data_eh[vol_handle];
        if (uwuw.material_library.count(uwuw_mat) != 0) {
          // Note: material numbers are set by UWUW
          int mat_number = uwuw.material_library[uwuw_mat].metadata["mat_number"].asInt();
          c->material_.push_back(mat_number);
        } else {
          std::stringstream err_msg;
          err_msg << "Material with value " << mat_value << " not found ";
          err_msg << "in the UWUW material library";
          fatal_error(err_msg);
        }
      } else {
        // if not using UWUW materials, we'll find this material
        // later in the materials.xml
        c->material_.push_back(std::stoi(mat_value));
      }
    }
  }

  // allocate the cell overlap count if necessary
  if (settings::check_overlaps) {
    model::overlap_check_count.resize(model::cells.size(), 0);
  }

  if (!graveyard) {
    std::cout << "WARNING: No graveyard volume found in the DagMC model.\n";
    std::cout << "This may result in lost particles and rapid simulation failure.\n";
  }

  /// Surfaces \\\

  // initialize surface objects
  int n_surfaces = model::DAG->num_entities(2);
  model::surfaces.resize(n_surfaces);

  for (int i = 0; i < n_surfaces; i++) {
    moab::EntityHandle surf_handle = model::DAG->entity_by_index(2, i+1);

    // set cell ids using global IDs
    DAGSurface* s = new DAGSurface();
    s->id_ = model::DAG->id_by_index(2, i+1);
    s->dagmc_ptr_ = model::DAG;

    // set BCs
    std::string bc_value;
    if (model::DAG->has_prop(surf_handle, "boundary")) {
      rval = model::DAG->prop_value(surf_handle, "boundary", bc_value);
      MB_CHK_ERR_CONT(rval);
      to_lower(bc_value);

      if (bc_value == "transmit" || bc_value == "transmission") {
        s->bc_ = BC_TRANSMIT;
      } else if (bc_value == "vacuum") {
        s->bc_ = BC_VACUUM;
      } else if (bc_value == "reflective" || bc_value == "reflect" || bc_value == "reflecting") {
        s->bc_ = BC_REFLECT;
      } else if (bc_value == "periodic") {
        fatal_error("Periodic boundary condition not supported in DAGMC.");
      } else {
        std::stringstream err_msg;
        err_msg << "Unknown boundary condition \"" << s->bc_
                << "\" specified on surface " << s->id_;
        fatal_error(err_msg);
      }
    } else {
      // if no condition is found, set to transmit
      s->bc_ = BC_TRANSMIT;
    }

    // graveyard check
    moab::Range parent_vols;
    rval = model::DAG->moab_instance()->get_parent_meshsets(surf_handle, parent_vols);
    MB_CHK_ERR_CONT(rval);

    // if this surface belongs to the graveyard
    if (graveyard && parent_vols.find(graveyard) != parent_vols.end()) {
      // set BC to vacuum
      s->bc_ = BC_VACUUM;
    }

    // add to global array and map
    model::surfaces[i] = s;
    model::surface_map[s->id_] = s->id_;
  }

  return;
}

void free_memory_dagmc()
{
  delete model::DAG;
}

}
#endif
<commit_msg>Using warning output function instead of cout.<commit_after>#include "openmc/dagmc.h"

#include "openmc/cell.h"
#include "openmc/constants.h"
#include "openmc/error.h"
#include "openmc/file_utils.h"
#include "openmc/string_utils.h"
#include "openmc/settings.h"
#include "openmc/geometry.h"

#ifdef DAGMC

#include "uwuw.hpp"
#include "dagmcmetadata.hpp"

#endif

#include <string>
#include <sstream>
#include <algorithm>
#include <fstream>

namespace openmc {

#ifdef DAGMC
const bool dagmc_enabled = true;
#else
const bool dagmc_enabled = false;
#endif

}

#ifdef DAGMC

const std::string DAGMC_FILENAME = "dagmc.h5m";

namespace openmc {

namespace model {

moab::DagMC* DAG;

} // namespace model

bool get_uwuw_materials_xml(std::string& s) {
  UWUW uwuw(DAGMC_FILENAME.c_str());

  std::stringstream ss;
  bool uwuw_mats_present = false;
  if (uwuw.material_library.size() != 0) {
    uwuw_mats_present = true;
    // write header
    ss << "<?xml version=\"1.0\"?>\n";
    ss << "<materials>\n";
    const auto& mat_lib = uwuw.material_library;
    // write materials
    for (auto mat : mat_lib) { ss << mat.second.openmc("atom"); }
    // write footer
    ss << "</materials>";
    s = ss.str();
  }

  return uwuw_mats_present;
}

pugi::xml_document* read_uwuw_materials() {
  pugi::xml_document* doc = nullptr;

  std::string s;
  bool found_uwuw_mats = get_uwuw_materials_xml(s);
  if (found_uwuw_mats) {
    doc = new pugi::xml_document();
    pugi::xml_parse_result result = doc->load_string(s.c_str());
  }
  return doc;
}

bool write_uwuw_materials_xml() {
  std::string s;
  bool found_uwuw_mats = get_uwuw_materials_xml(s);
    // if there is a material library in the file
  if (found_uwuw_mats) {
    // write a material.xml file
    std::ofstream mats_xml("materials.xml");
    mats_xml << s;
    mats_xml.close();
  }

  return found_uwuw_mats;
}

void load_dagmc_geometry()
{
  if (!model::DAG) {
    model::DAG = new moab::DagMC();
  }

  /// Materials \\\

  // create uwuw instance
  UWUW uwuw(DAGMC_FILENAME.c_str());

  // check for uwuw material definitions
  bool using_uwuw = !uwuw.material_library.empty();

  // notify user if UWUW materials are going to be used
  if (using_uwuw) {
    std::cout << "Found UWUW Materials in the DAGMC geometry file.\n";
  }

  int32_t dagmc_univ_id = 0; // universe is always 0 for DAGMC runs

  // load the DAGMC geometry
  moab::ErrorCode rval = model::DAG->load_file(DAGMC_FILENAME.c_str());
  MB_CHK_ERR_CONT(rval);

  // initialize acceleration data structures
  rval = model::DAG->init_OBBTree();
  MB_CHK_ERR_CONT(rval);

  // parse model metadata
  dagmcMetaData DMD(model::DAG);
  if (using_uwuw) {
    DMD.load_property_data();
  }
  std::vector<std::string> keywords {"temp", "mat", "density", "boundary"};
  std::map<std::string, std::string> dum;
  std::string delimiters = ":/";
  rval = model::DAG->parse_properties(keywords, dum, delimiters.c_str());
  MB_CHK_ERR_CONT(rval);

  /// Cells (Volumes) \\\

  // initialize cell objects
  model::n_cells = model::DAG->num_entities(3);
  moab::EntityHandle graveyard = 0;
  for (int i = 0; i < model::n_cells; i++) {
    moab::EntityHandle vol_handle = model::DAG->entity_by_index(3, i+1);

    // set cell ids using global IDs
    DAGCell* c = new DAGCell();
    c->id_ = model::DAG->id_by_index(3, i+1);
    c->dagmc_ptr_ = model::DAG;
    c->universe_ = dagmc_univ_id; // set to zero for now
    c->fill_ = C_NONE; // no fill, single universe

    model::cells.push_back(c);
    model::cell_map[c->id_] = i;

    // Populate the Universe vector and dict
    auto it = model::universe_map.find(dagmc_univ_id);
    if (it == model::universe_map.end()) {
      model::universes.push_back(new Universe());
      model::universes.back()-> id_ = dagmc_univ_id;
      model::universes.back()->cells_.push_back(i);
      model::universe_map[dagmc_univ_id] = model::universes.size() - 1;
    } else {
      model::universes[it->second]->cells_.push_back(i);
    }

    // check for temperature assignment
    std::string temp_value;
    if (model::DAG->has_prop(vol_handle, "temp")) {
      rval = model::DAG->prop_value(vol_handle, "temp", temp_value);
      MB_CHK_ERR_CONT(rval);
      double temp = std::stod(temp_value);
      c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * temp));
    } else {
      c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * settings::temperature_default));
    }

    // MATERIALS

    if (model::DAG->is_implicit_complement(vol_handle)) {
      if (model::DAG->has_prop(vol_handle, "mat")) {
        // if the implicit complement has been assigned a material, use it
        std::string comp_mat = DMD.volume_material_property_data_eh[vol_handle];
        // Note: material numbers are set by UWUW
        int mat_number = uwuw.material_library[comp_mat].metadata["mat_number"].asInt();
        c->material_.push_back(mat_number);
      } else {
        // if no material is found, the implicit complement is void
        c->material_.push_back(MATERIAL_VOID);
      }
      continue;
    }

    // determine volume material assignment
    std::string mat_value;
    if (model::DAG->has_prop(vol_handle, "mat")) {
      rval = model::DAG->prop_value(vol_handle, "mat", mat_value);
      MB_CHK_ERR_CONT(rval);
    } else {
      std::stringstream err_msg;
      err_msg << "Volume " << c->id_ << " has no material assignment.";
      fatal_error(err_msg.str());
    }

    std::string cmp_str = mat_value;
    to_lower(cmp_str);

    if (cmp_str.find("graveyard") != std::string::npos) {
      graveyard = vol_handle;
    }

    // material void checks
    if (cmp_str.find("void") != std::string::npos   ||
        cmp_str.find("vacuum") != std::string::npos ||
        cmp_str.find("graveyard") != std::string::npos) {
      c->material_.push_back(MATERIAL_VOID);
    } else {
      if (using_uwuw) {
        // lookup material in uwuw if the were present
        std::string uwuw_mat = DMD.volume_material_property_data_eh[vol_handle];
        if (uwuw.material_library.count(uwuw_mat) != 0) {
          // Note: material numbers are set by UWUW
          int mat_number = uwuw.material_library[uwuw_mat].metadata["mat_number"].asInt();
          c->material_.push_back(mat_number);
        } else {
          std::stringstream err_msg;
          err_msg << "Material with value " << mat_value << " not found ";
          err_msg << "in the UWUW material library";
          fatal_error(err_msg);
        }
      } else {
        // if not using UWUW materials, we'll find this material
        // later in the materials.xml
        c->material_.push_back(std::stoi(mat_value));
      }
    }
  }

  // allocate the cell overlap count if necessary
  if (settings::check_overlaps) {
    model::overlap_check_count.resize(model::cells.size(), 0);
  }

  if (!graveyard) {
    warning("No graveyard volume found in the DagMC model.");
    warning("This may result in lost particles and rapid simulation failure.");
  }

  /// Surfaces \\\

  // initialize surface objects
  int n_surfaces = model::DAG->num_entities(2);
  model::surfaces.resize(n_surfaces);

  for (int i = 0; i < n_surfaces; i++) {
    moab::EntityHandle surf_handle = model::DAG->entity_by_index(2, i+1);

    // set cell ids using global IDs
    DAGSurface* s = new DAGSurface();
    s->id_ = model::DAG->id_by_index(2, i+1);
    s->dagmc_ptr_ = model::DAG;

    // set BCs
    std::string bc_value;
    if (model::DAG->has_prop(surf_handle, "boundary")) {
      rval = model::DAG->prop_value(surf_handle, "boundary", bc_value);
      MB_CHK_ERR_CONT(rval);
      to_lower(bc_value);

      if (bc_value == "transmit" || bc_value == "transmission") {
        s->bc_ = BC_TRANSMIT;
      } else if (bc_value == "vacuum") {
        s->bc_ = BC_VACUUM;
      } else if (bc_value == "reflective" || bc_value == "reflect" || bc_value == "reflecting") {
        s->bc_ = BC_REFLECT;
      } else if (bc_value == "periodic") {
        fatal_error("Periodic boundary condition not supported in DAGMC.");
      } else {
        std::stringstream err_msg;
        err_msg << "Unknown boundary condition \"" << s->bc_
                << "\" specified on surface " << s->id_;
        fatal_error(err_msg);
      }
    } else {
      // if no condition is found, set to transmit
      s->bc_ = BC_TRANSMIT;
    }

    // graveyard check
    moab::Range parent_vols;
    rval = model::DAG->moab_instance()->get_parent_meshsets(surf_handle, parent_vols);
    MB_CHK_ERR_CONT(rval);

    // if this surface belongs to the graveyard
    if (graveyard && parent_vols.find(graveyard) != parent_vols.end()) {
      // set BC to vacuum
      s->bc_ = BC_VACUUM;
    }

    // add to global array and map
    model::surfaces[i] = s;
    model::surface_map[s->id_] = s->id_;
  }

  return;
}

void free_memory_dagmc()
{
  delete model::DAG;
}

}
#endif
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
//
// Package:   pan_tilt
//
// Library:   libpan_tilt
//
// File:      ptCalib.cxx
//
/*! \file
 *
 * $LastChangedDate$
 * $Rev$
 *
 * \brief PanTiltCalib - Pan-Tilt calibration class implementation.
 *
 * \author Robin Knight   (robin.knight@roadnarrows.com)
 * \author Daniel Packard (daniel@roadnarrows.com)
 *
 * \par Copyright:
 * (C) 2014  RoadNarrows
 * (http://www.RoadNarrows.com)
 * \n All Rights Reserved
 */
/*
 * @EulaBegin@
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that
 * (1) The above copyright notice and the following two paragraphs
 * appear in all copies of the source code and (2) redistributions
 * including binaries reproduces these notices in the supporting
 * documentation.   Substantial modifications to this software may be
 * copyrighted by their authors and need not follow the licensing terms
 * described here, provided that the new terms are clearly indicated in
 * all files where they apply.
 *
 * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY MEMBERS/EMPLOYEES
 * OF ROADNARROW LLC OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY
 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
 * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
 * EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 *
 * THE AUTHOR AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
 * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * @EulaEnd@
 */
////////////////////////////////////////////////////////////////////////////////

#include "rnr/rnrconfig.h"
#include "rnr/log.h"

#include "Dynamixel/Dynamixel.h"
#include "Dynamixel/DynaServo.h"

#include "pan_tilt/pan_tilt.h"
#include "pan_tilt/ptJoint.h"
#include "pan_tilt/ptCalib.h"
#include "pan_tilt/ptRobot.h"

using namespace std;
using namespace pan_tilt;

// ---------------------------------------------------------------------------
// Private Interface
// ---------------------------------------------------------------------------

// debug switch
#undef  CALIB_DEBUG_ENABLE

#ifdef CALIB_DEBUG_ENABLE

#define CALIB_DBG(servoid, fmt, ...) \
  do \
  { \
    fprintf(stderr, "DBG: %s(): Servo: %d: " fmt, \
      LOGFUNCNAME, servoid, ##__VA_ARGS__); \
    fflush(stderr); \
  } while(0)

#else

#define CALIB_DBG(servoid, fmt, ...)

#endif // CALIB_DEBUG_ENABLE

/*!
 * \brief Convenience macro for trying to get a servo object from dynamixel
 * chain.
 *
 * Failure is considered a software bug since the chain has already be
 * verified.
 *
 * Only works locally.
 *
 * \param [in] nServoId   Servo id.
 * \param [out] pServo    Pointer to associated servo object.
 *
 * \return On failure, forces return from calling function with the appropriate
 * error code.
 */
#define PT_TRY_GET_SERVO(nServoId, pServo) \
  do \
  { \
    if( (pServo = m_robot.m_pDynaChain->GetServo(nServoId)) == NULL ) \
    { \
      LOGERROR("BUG: Servo %d: Cannot find in dynamixel chain.", nServoId); \
      return -PT_ECODE_INTERNAL; \
    } \
  } while(0)

/*!
 * \brief Calibration order by master servo id.
 */
static const char *CalibOrder[] = { "pan", "tilt" };

int PanTiltCalib::calibrate()
{
  PanTiltRobot::MapRobotJoints::iterator  pos;

  PanTiltRobotJoint  *pJoint;
  int                 nServoId;
  size_t            i;
  int               rc;

  for(i=0, rc=PT_OK; (i<arraysize(CalibOrder)) && (rc >= 0); ++i)
  {
    nServoId = m_robot.getMasterServoId(CalibOrder[i]);

    // no joint in this product version with associated master servo id
    if( (pos = m_robot.m_kin.find(nServoId)) == m_robot.m_kin.end() )
    {
      continue;
    }

    pJoint = &(pos->second);

    // already calibrated
    if( pJoint->m_eOpState == PanTiltOpStateCalibrated )
    {
      continue;
    }

    pJoint->m_eOpState  = PanTiltOpStateCalibrating;

    // physical limits
    rc = calibrateJointByTorqueLimits(*pJoint);

    pJoint->m_eOpState =  rc == PT_OK? PanTiltOpStateCalibrated:
                                       PanTiltOpStateUncalibrated;
  }

  return rc;
}

int PanTiltCalib::calibrateJointByTorqueLimits(PanTiltRobotJoint &joint)
{
  static int    TuneCalSpeed  = 75;     // calibration speed
  static int    TuneBackoff   = 15;     // backoff position (ticks)

  int         nServoId;         // servo id
  DynaServo  *pServo;           // joint's master servo
  bool        bIsReverse;       // odometer is [not] reversed
  int         nOdStartPos;      // user's starting position
  int         nOdGoalPos;       // working goal position
  int         nOldMinLimit;     // original odometer minimum limit
  int         nOldMaxLimit;     // original odometer maximum limit
  int         nNewMinLimit;     // new odometer minimum limit
  int         nNewMaxLimit;     // new odometer maximum limit
  int         nDeltaMin;        // delta odometer minimums
  int         nDeltaMax;        // delta odometer maximums
  int         nDeltaAvg;        // delta average

  nServoId      = joint.m_nMasterServoId;
  nOldMinLimit  = joint.m_nMinPhyLimitOd;
  nOldMaxLimit  = joint.m_nMaxPhyLimitOd;
  bIsReverse    = joint.m_nMasterServoDir == DYNA_DIR_CCW? false: true;

  // dynamixel servo object in dynamixel chain
  PT_TRY_GET_SERVO(nServoId, pServo);

  nOdStartPos = pServo->GetOdometer();

  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  // Find minimum joint limit.
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

  LOGDIAG3("Joint %s (servo=%d): "
           "Determining minimum joint limit by torque limit.",
      joint.m_strName.c_str(), nServoId);

  //
  // A continuous mode servo must have its joint minimum limit within 360
  // degreees of joint rotation from the current position. Go to this endpoint
  // until the torque limit is found.
  //
  if( joint.m_eJointType == PanTiltJointTypeContinuous )
  {
    nOdGoalPos = M_TAU * -joint.m_fTicksPerJointRad;
  }

  //
  // A servo mode servo has encoder endpoints that are known and finite. Go to
  // the appropriate endpoint until the torque limit is found.
  //
  else
  {
    if( (nOdGoalPos = pServo->CalcOdometerAtEncMin()) > 0 )
    {
      nOdGoalPos = pServo->CalcOdometerAtEncMax();
    }
  }

  //LOGDIAG3("MOVE TO MINIMUM LIMIT.");
  moveWait(pServo, nOdGoalPos, TuneCalSpeed);

  nNewMinLimit = pServo->GetOdometer();

  //
  // Off load servo by moving back to starting calibration position.
  //
  //LOGDIAG3("MOVE BACK TO START.");
  moveWait(pServo, nOdStartPos, TuneCalSpeed);

  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  // Find maximum limit.
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

  LOGDIAG3("Joint %s (servo=%d): "
           "Determining maximum joint limit by torque limit.",
      joint.m_strName.c_str(), nServoId);

  //
  // A continuous mode servo must have its joint minimum limit within 360
  // degreees of joint rotation from the current position. Go to this endpoint
  // until the torque limit is found.
  //
  if( joint.m_eJointType == PanTiltJointTypeContinuous )
  {
    nOdGoalPos = M_TAU * joint.m_fTicksPerJointRad;
  }

  //
  // A servo mode servo has encoder endpoints that are known and finite. Go to
  // the appropriate endpoint until the torque limit is found.
  //
  else
  {
    if( (nOdGoalPos = pServo->CalcOdometerAtEncMin()) < 0 )
    {
      nOdGoalPos = pServo->CalcOdometerAtEncMax();
    }
  }

  //LOGDIAG3("MOVE TO MAXIMUM LIMIT.");
  moveWait(pServo, nOdGoalPos, TuneCalSpeed);

  nNewMaxLimit = pServo->GetOdometer();

  //
  // Off load servo by moving back to starting calibration position
  //
  //LOGDIAG3("MOVE BACK TO START AGAIN.");
  moveWait(pServo, nOdStartPos, TuneCalSpeed);

  //
  // Calculate best new zero degree point.
  //
  nDeltaMin = nNewMinLimit - nOldMinLimit;
  nDeltaMax = nNewMaxLimit - nOldMaxLimit;
  nDeltaAvg = (nDeltaMin + nDeltaMax) / 2;

  //
  // Move to new zero point position.
  //
  //LOGDIAG3("MOVE TO NEW ZERO=%d.", nOdStartPos+nDeltaAvg);
  moveWait(pServo, nOdStartPos+nDeltaAvg, TuneCalSpeed);

  //
  // Reset odometer to new zero degree position.
  //
  m_robot.resetOdometerForServo(nServoId, bIsReverse);

  //
  // Adjust limits and positions to adjusted zero degree point.
  //
  joint.m_nMinPhyLimitOd    = nNewMinLimit - nDeltaAvg;
  joint.m_nMaxPhyLimitOd    = nNewMaxLimit - nDeltaAvg;

  joint.m_fMinPhyLimitRads  = (double)joint.m_nMinPhyLimitOd /
                                      joint.m_fTicksPerJointRad;
  joint.m_fMaxPhyLimitRads  = (double)joint.m_nMaxPhyLimitOd /
                                      joint.m_fTicksPerJointRad;

  joint.m_nMinSoftLimitOd   = joint.m_nMinPhyLimitOd + TuneBackoff;
  joint.m_nMaxSoftLimitOd   = joint.m_nMaxPhyLimitOd - TuneBackoff;

  joint.m_fMinSoftLimitRads = (double)joint.m_nMinSoftLimitOd /
                                      joint.m_fTicksPerJointRad;
  joint.m_fMaxSoftLimitRads = (double)joint.m_nMaxSoftLimitOd /
                                      joint.m_fTicksPerJointRad;

  //
  // Finally move to ideal calibration position.
  //
  if( joint.m_fCalibPosRads != 0.0 )
  {
    nOdGoalPos = (int)(joint.m_fCalibPosRads * joint.m_fTicksPerJointRad);
    //LOGDIAG3("MOVE TO CALIB ZERO PT=%d.", nOdGoalPos);
    moveWait(pServo, nOdGoalPos, TuneCalSpeed);
  }

  //
  // Calibrated.
  //
  LOGDIAG3("Joint %s (servo=%d): Calibrated:\n"
          "  Torque [min, max] limits: [%.2lfdeg (od=%d), %.2lfdeg (od=%d)].",
      joint.m_strName.c_str(), nServoId,
      radToDeg(joint.m_fMinPhyLimitRads), joint.m_nMinPhyLimitOd,
      radToDeg(joint.m_fMaxPhyLimitRads), joint.m_nMaxPhyLimitOd);

  return PT_OK;
}

int PanTiltCalib::moveWait(DynaServo *pServo, int nOdGoalPos, int nSpeed)
{
  static uint_t TuneWaituSec  = 300000;
  static int    TuneDeltaErr  = 5;

  int   nOdBefore;
  int   nOdAfter;
  bool  bMoving;

  nSpeed *= pServo->CalcSpeedDir(nOdGoalPos);

  // start move
  pServo->MoveAtSpeedTo(nSpeed, nOdGoalPos);

  CALIB_DBG(pServo->GetServoId(), "moveWait: move at speed=%d to %d\n",
                nSpeed, nOdGoalPos);

  // wait until move is completed
  do
  {
    nOdBefore = pServo->GetOdometer();
    usleep(TuneWaituSec);   // pthread cancelation point
    nOdAfter = pServo->GetOdometer();

    CALIB_DBG(pServo->GetServoId(), "moveWait: curspeed=%d, curpos=%d\n",
          pServo->GetCurSpeed(), nOdAfter);

    pServo->ReadIsMoving(&bMoving);
  }
  while( bMoving );
  //while( iabs(nOdBefore - nOdAfter) > TuneDeltaErr );

  return pServo->GetOdometer();
}
<commit_msg>fixed include bug<commit_after>////////////////////////////////////////////////////////////////////////////////
//
// Package:   pan_tilt
//
// Library:   libpan_tilt
//
// File:      ptCalib.cxx
//
/*! \file
 *
 * $LastChangedDate$
 * $Rev$
 *
 * \brief PanTiltCalib - Pan-Tilt calibration class implementation.
 *
 * \author Robin Knight   (robin.knight@roadnarrows.com)
 * \author Daniel Packard (daniel@roadnarrows.com)
 *
 * \par Copyright:
 * (C) 2014  RoadNarrows
 * (http://www.RoadNarrows.com)
 * \n All Rights Reserved
 */
/*
 * @EulaBegin@
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that
 * (1) The above copyright notice and the following two paragraphs
 * appear in all copies of the source code and (2) redistributions
 * including binaries reproduces these notices in the supporting
 * documentation.   Substantial modifications to this software may be
 * copyrighted by their authors and need not follow the licensing terms
 * described here, provided that the new terms are clearly indicated in
 * all files where they apply.
 *
 * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY MEMBERS/EMPLOYEES
 * OF ROADNARROW LLC OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY
 * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
 * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
 * EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 *
 * THE AUTHOR AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
 * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * @EulaEnd@
 */
////////////////////////////////////////////////////////////////////////////////

#include "unistd.h"

#include "rnr/rnrconfig.h"
#include "rnr/log.h"

#include "Dynamixel/Dynamixel.h"
#include "Dynamixel/DynaServo.h"

#include "pan_tilt/pan_tilt.h"
#include "pan_tilt/ptJoint.h"
#include "pan_tilt/ptCalib.h"
#include "pan_tilt/ptRobot.h"

using namespace std;
using namespace pan_tilt;

// ---------------------------------------------------------------------------
// Private Interface
// ---------------------------------------------------------------------------

// debug switch
#undef  CALIB_DEBUG_ENABLE

#ifdef CALIB_DEBUG_ENABLE

#define CALIB_DBG(servoid, fmt, ...) \
  do \
  { \
    fprintf(stderr, "DBG: %s(): Servo: %d: " fmt, \
      LOGFUNCNAME, servoid, ##__VA_ARGS__); \
    fflush(stderr); \
  } while(0)

#else

#define CALIB_DBG(servoid, fmt, ...)

#endif // CALIB_DEBUG_ENABLE

/*!
 * \brief Convenience macro for trying to get a servo object from dynamixel
 * chain.
 *
 * Failure is considered a software bug since the chain has already be
 * verified.
 *
 * Only works locally.
 *
 * \param [in] nServoId   Servo id.
 * \param [out] pServo    Pointer to associated servo object.
 *
 * \return On failure, forces return from calling function with the appropriate
 * error code.
 */
#define PT_TRY_GET_SERVO(nServoId, pServo) \
  do \
  { \
    if( (pServo = m_robot.m_pDynaChain->GetServo(nServoId)) == NULL ) \
    { \
      LOGERROR("BUG: Servo %d: Cannot find in dynamixel chain.", nServoId); \
      return -PT_ECODE_INTERNAL; \
    } \
  } while(0)

/*!
 * \brief Calibration order by master servo id.
 */
static const char *CalibOrder[] = { "pan", "tilt" };

int PanTiltCalib::calibrate()
{
  PanTiltRobot::MapRobotJoints::iterator  pos;

  PanTiltRobotJoint  *pJoint;
  int                 nServoId;
  size_t            i;
  int               rc;

  for(i=0, rc=PT_OK; (i<arraysize(CalibOrder)) && (rc >= 0); ++i)
  {
    nServoId = m_robot.getMasterServoId(CalibOrder[i]);

    // no joint in this product version with associated master servo id
    if( (pos = m_robot.m_kin.find(nServoId)) == m_robot.m_kin.end() )
    {
      continue;
    }

    pJoint = &(pos->second);

    // already calibrated
    if( pJoint->m_eOpState == PanTiltOpStateCalibrated )
    {
      continue;
    }

    pJoint->m_eOpState  = PanTiltOpStateCalibrating;

    // physical limits
    rc = calibrateJointByTorqueLimits(*pJoint);

    pJoint->m_eOpState =  rc == PT_OK? PanTiltOpStateCalibrated:
                                       PanTiltOpStateUncalibrated;
  }

  return rc;
}

int PanTiltCalib::calibrateJointByTorqueLimits(PanTiltRobotJoint &joint)
{
  static int    TuneCalSpeed  = 75;     // calibration speed
  static int    TuneBackoff   = 15;     // backoff position (ticks)

  int         nServoId;         // servo id
  DynaServo  *pServo;           // joint's master servo
  bool        bIsReverse;       // odometer is [not] reversed
  int         nOdStartPos;      // user's starting position
  int         nOdGoalPos;       // working goal position
  int         nOldMinLimit;     // original odometer minimum limit
  int         nOldMaxLimit;     // original odometer maximum limit
  int         nNewMinLimit;     // new odometer minimum limit
  int         nNewMaxLimit;     // new odometer maximum limit
  int         nDeltaMin;        // delta odometer minimums
  int         nDeltaMax;        // delta odometer maximums
  int         nDeltaAvg;        // delta average

  nServoId      = joint.m_nMasterServoId;
  nOldMinLimit  = joint.m_nMinPhyLimitOd;
  nOldMaxLimit  = joint.m_nMaxPhyLimitOd;
  bIsReverse    = joint.m_nMasterServoDir == DYNA_DIR_CCW? false: true;

  // dynamixel servo object in dynamixel chain
  PT_TRY_GET_SERVO(nServoId, pServo);

  nOdStartPos = pServo->GetOdometer();

  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  // Find minimum joint limit.
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

  LOGDIAG3("Joint %s (servo=%d): "
           "Determining minimum joint limit by torque limit.",
      joint.m_strName.c_str(), nServoId);

  //
  // A continuous mode servo must have its joint minimum limit within 360
  // degreees of joint rotation from the current position. Go to this endpoint
  // until the torque limit is found.
  //
  if( joint.m_eJointType == PanTiltJointTypeContinuous )
  {
    nOdGoalPos = M_TAU * -joint.m_fTicksPerJointRad;
  }

  //
  // A servo mode servo has encoder endpoints that are known and finite. Go to
  // the appropriate endpoint until the torque limit is found.
  //
  else
  {
    if( (nOdGoalPos = pServo->CalcOdometerAtEncMin()) > 0 )
    {
      nOdGoalPos = pServo->CalcOdometerAtEncMax();
    }
  }

  //LOGDIAG3("MOVE TO MINIMUM LIMIT.");
  moveWait(pServo, nOdGoalPos, TuneCalSpeed);

  nNewMinLimit = pServo->GetOdometer();

  //
  // Off load servo by moving back to starting calibration position.
  //
  //LOGDIAG3("MOVE BACK TO START.");
  moveWait(pServo, nOdStartPos, TuneCalSpeed);

  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  // Find maximum limit.
  // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

  LOGDIAG3("Joint %s (servo=%d): "
           "Determining maximum joint limit by torque limit.",
      joint.m_strName.c_str(), nServoId);

  //
  // A continuous mode servo must have its joint minimum limit within 360
  // degreees of joint rotation from the current position. Go to this endpoint
  // until the torque limit is found.
  //
  if( joint.m_eJointType == PanTiltJointTypeContinuous )
  {
    nOdGoalPos = M_TAU * joint.m_fTicksPerJointRad;
  }

  //
  // A servo mode servo has encoder endpoints that are known and finite. Go to
  // the appropriate endpoint until the torque limit is found.
  //
  else
  {
    if( (nOdGoalPos = pServo->CalcOdometerAtEncMin()) < 0 )
    {
      nOdGoalPos = pServo->CalcOdometerAtEncMax();
    }
  }

  //LOGDIAG3("MOVE TO MAXIMUM LIMIT.");
  moveWait(pServo, nOdGoalPos, TuneCalSpeed);

  nNewMaxLimit = pServo->GetOdometer();

  //
  // Off load servo by moving back to starting calibration position
  //
  //LOGDIAG3("MOVE BACK TO START AGAIN.");
  moveWait(pServo, nOdStartPos, TuneCalSpeed);

  //
  // Calculate best new zero degree point.
  //
  nDeltaMin = nNewMinLimit - nOldMinLimit;
  nDeltaMax = nNewMaxLimit - nOldMaxLimit;
  nDeltaAvg = (nDeltaMin + nDeltaMax) / 2;

  //
  // Move to new zero point position.
  //
  //LOGDIAG3("MOVE TO NEW ZERO=%d.", nOdStartPos+nDeltaAvg);
  moveWait(pServo, nOdStartPos+nDeltaAvg, TuneCalSpeed);

  //
  // Reset odometer to new zero degree position.
  //
  m_robot.resetOdometerForServo(nServoId, bIsReverse);

  //
  // Adjust limits and positions to adjusted zero degree point.
  //
  joint.m_nMinPhyLimitOd    = nNewMinLimit - nDeltaAvg;
  joint.m_nMaxPhyLimitOd    = nNewMaxLimit - nDeltaAvg;

  joint.m_fMinPhyLimitRads  = (double)joint.m_nMinPhyLimitOd /
                                      joint.m_fTicksPerJointRad;
  joint.m_fMaxPhyLimitRads  = (double)joint.m_nMaxPhyLimitOd /
                                      joint.m_fTicksPerJointRad;

  joint.m_nMinSoftLimitOd   = joint.m_nMinPhyLimitOd + TuneBackoff;
  joint.m_nMaxSoftLimitOd   = joint.m_nMaxPhyLimitOd - TuneBackoff;

  joint.m_fMinSoftLimitRads = (double)joint.m_nMinSoftLimitOd /
                                      joint.m_fTicksPerJointRad;
  joint.m_fMaxSoftLimitRads = (double)joint.m_nMaxSoftLimitOd /
                                      joint.m_fTicksPerJointRad;

  //
  // Finally move to ideal calibration position.
  //
  if( joint.m_fCalibPosRads != 0.0 )
  {
    nOdGoalPos = (int)(joint.m_fCalibPosRads * joint.m_fTicksPerJointRad);
    //LOGDIAG3("MOVE TO CALIB ZERO PT=%d.", nOdGoalPos);
    moveWait(pServo, nOdGoalPos, TuneCalSpeed);
  }

  //
  // Calibrated.
  //
  LOGDIAG3("Joint %s (servo=%d): Calibrated:\n"
          "  Torque [min, max] limits: [%.2lfdeg (od=%d), %.2lfdeg (od=%d)].",
      joint.m_strName.c_str(), nServoId,
      radToDeg(joint.m_fMinPhyLimitRads), joint.m_nMinPhyLimitOd,
      radToDeg(joint.m_fMaxPhyLimitRads), joint.m_nMaxPhyLimitOd);

  return PT_OK;
}

int PanTiltCalib::moveWait(DynaServo *pServo, int nOdGoalPos, int nSpeed)
{
  static uint_t TuneWaituSec  = 300000;
  static int    TuneDeltaErr  = 5;

  int   nOdBefore;
  int   nOdAfter;
  bool  bMoving;

  nSpeed *= pServo->CalcSpeedDir(nOdGoalPos);

  // start move
  pServo->MoveAtSpeedTo(nSpeed, nOdGoalPos);

  CALIB_DBG(pServo->GetServoId(), "moveWait: move at speed=%d to %d\n",
                nSpeed, nOdGoalPos);

  // wait until move is completed
  do
  {
    nOdBefore = pServo->GetOdometer();
    usleep(TuneWaituSec);   // pthread cancelation point
    nOdAfter = pServo->GetOdometer();

    CALIB_DBG(pServo->GetServoId(), "moveWait: curspeed=%d, curpos=%d\n",
          pServo->GetCurSpeed(), nOdAfter);

    pServo->ReadIsMoving(&bMoving);
  }
  while( bMoving );
  //while( iabs(nOdBefore - nOdAfter) > TuneDeltaErr );

  return pServo->GetOdometer();
}
<|endoftext|>


<commit_before>#include "gdrive/drive.hpp"
#include "jconer/json.hpp"
using namespace JCONER;
namespace GDRIVE {

DriveService::DriveService(Credential cred)
    :_cred(cred)
{
}

FileService::FileService(Credential cred)
    :DriveService(cred)
{
#ifdef GDRIVE_DEBUG
    CLASS_INIT_LOGGER("FileService", L_DEBUG)
#endif
}

std::vector<GFile> FileService::List() {
    std::vector<GFile> files;
    std::string next_link = "";
    RequestBody body;
    body["maxRequest"] = "1000";
    Request request(FILE_URL, RM_GET);
    request.add_body(body);

    while(true) {
        Response resp = _cred.request(request);
        PError error;
        JObject* value = (JObject*)loads(resp.content(), error);
        if (value != NULL) {
            if (value->contain("items")) {
                JArray* items = (JArray*)value->get("items");
                for(int i = 0; i < items->size(); i ++ ) {
                    JObject* item = (JObject*)items->get(i);
                    GFile file;
                    file.from_json(item);
                    files.push_back(file);
                    CLOG_DEBUG("Get file %s\n", file.title.c_str());
                }
            }
            if (value->contain("nextLink")) {
                next_link = ((JString*)value->get("nextLink"))->getValue();
                request = Request(next_link, RM_GET);
                delete value;
            } else {
                delete value;
                break;
            }
        }
    }
    return files;
}

GFile FileService::Get(std::string id) {
    std::string url(FILE_URL "/");
    url += id;
    Request request(url, RM_GET);
    Response resp = _cred.request(request);
    PError error;
    JObject* obj = (JObject*)loads(resp.content(), error);
    GFile file;
    if (obj != NULL) {
        file.from_json(obj);
        delete obj;
    }
    return file;
    //CLOG_DEBUG("%s\n", resp.content().c_str());
}

}
<commit_msg>Fix the segmentation bug when getting file<commit_after>#include "gdrive/drive.hpp"
#include "jconer/json.hpp"
using namespace JCONER;
namespace GDRIVE {

DriveService::DriveService(Credential cred)
    :_cred(cred)
{
}

FileService::FileService(Credential cred)
    :DriveService(cred)
{
#ifdef GDRIVE_DEBUG
    CLASS_INIT_LOGGER("FileService", L_DEBUG)
#endif
}

std::vector<GFile> FileService::List() {
    std::vector<GFile> files;
    std::string next_link = "";
    RequestBody body;
    body["maxRequest"] = "1000";
    Request request(FILE_URL, RM_GET);
    request.add_body(body);

    while(true) {
        Response resp = _cred.request(request);
        PError error;
        JObject* value = (JObject*)loads(resp.content(), error);
        if (value != NULL) {
            if (value->contain("items")) {
                JArray* items = (JArray*)value->get("items");
                for(int i = 0; i < items->size(); i ++ ) {
                    JObject* item = (JObject*)items->get(i);
                    GFile file;
                    file.from_json(item);
                    files.push_back(file);
                    CLOG_DEBUG("Get file %s\n", file.title.c_str());
                }
            }
            if (value->contain("nextLink")) {
                next_link = ((JString*)value->get("nextLink"))->getValue();
                request = Request(next_link, RM_GET);
                delete value;
            } else {
                delete value;
                break;
            }
        }
    }
    return files;
}

GFile FileService::Get(std::string id) {
    VarString vs;
    vs.append(FILE_URL).append('/').append(id);
    Request request(vs.toString(), RM_GET);
    Response resp = _cred.request(request);
    PError error;
    JObject* obj = (JObject*)loads(resp.content(), error);
    GFile file;
    if (obj != NULL) {
        file.from_json(obj);
        delete obj;
    }
    return file;
}

}
<|endoftext|>


<commit_before>/******************************************************************************
 * This file is part of the Gluon Development Platform
 * Copyright (c) 2010 Arjen Hiemstra <ahiemstra@heimr.nl>
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "materialasset.h"

#include <core/gdlhandler.h>
#include <graphics/material.h>
#include <graphics/materialinstance.h>
#include <graphics/engine.h>

#include <QtGui/QAction>

REGISTER_OBJECTTYPE( GluonEngine, MaterialAsset )

using namespace GluonEngine;

class MaterialAsset::MaterialAssetPrivate
{
    public:
        MaterialAssetPrivate() : material( 0 ) {}
        ~MaterialAssetPrivate() {}

        QPixmap icon;

        GluonGraphics::Material* material;

        QList<QAction*> actions;
};

MaterialAsset::MaterialAsset( QObject* parent )
    : Asset( parent )
    , d( new MaterialAssetPrivate )
{
    QAction* newInstance = new QAction( "New instance", 0 );
    connect( newInstance, SIGNAL( triggered( bool ) ), SLOT( createInstance() ) );
    d->actions.append( newInstance );
}

MaterialAsset::~MaterialAsset()
{
    // TODO: MaterialAsset needs to clean up after itself. This needs loading process fixes though.
    //if(d->material)
    //    GluonGraphics::Engine::instance()->destroyMaterial(name());
    delete d;
}

QIcon MaterialAsset::icon() const
{
    if( d->icon.isNull() )
        return GluonEngine::Asset::icon();

    return QIcon( d->icon );
}

const QStringList MaterialAsset::supportedMimeTypes() const
{
    QStringList types;

    types << "application/x-gluon-material";

    return types;
}

void MaterialAsset::load()
{
    if( !file().isEmpty() )
    {
        if( !d->material )
            d->material = GluonGraphics::Engine::instance()->createMaterial( name() );

        if( d->material->load( file() ) )
        {
            d->material->build();
            mimeData()->setText( name() );

            Asset::load();
            return;
        }
    }

    debug( "Error loading material: %1", name() );
}

const QList<AssetTemplate*> MaterialAsset::templates()
{
    QList<AssetTemplate*> templates;
    templates.append( new AssetTemplate( "Material", "material_template.gml", "material", this ) );
    templates.append( new AssetTemplate( "Animated Sprite Material", "animatedsprite_template.gml", "material", this ) );
    return templates;
}

QList<QAction*> MaterialAsset::actions()
{
    return d->actions;
}

void MaterialAsset::setName( const QString& newName )
{
    if( d->material )
    {
        GluonGraphics::Engine::instance()->removeMaterial( name() );
        GluonGraphics::Engine::instance()->addMaterial( newName, d->material );
    }
    GluonEngine::Asset::setName( newName );
}

bool MaterialAsset::shouldSerializeChildren() const
{
    return true;
}

void MaterialAsset::sanitize()
{
    GluonCore::GluonObject::sanitize();

    if( !d->material )
        d->material = GluonGraphics::Engine::instance()->createMaterial( name() );

    QObjectList allChildren = children();
    foreach( QObject * child, allChildren )
    {
        GluonGraphics::MaterialInstance* instance = qobject_cast<GluonGraphics::MaterialInstance*>( child );
        if( instance && d->material )
            instance->setMaterial( d->material );
    }
}

void MaterialAsset::createInstance()
{
    if( !isLoaded() )
        return;

    GluonGraphics::MaterialInstance* instance = new GluonGraphics::MaterialInstance( this );
    instance->setName( "New Instance" );
    instance->setPropertiesFromMaterial();
    instance->setMaterial( d->material );
}

Q_EXPORT_PLUGIN2( gluon_asset_material, GluonEngine::MaterialAsset )

#include "materialasset.moc"
<commit_msg>Fix the memory leak in the material asset<commit_after>/******************************************************************************
 * This file is part of the Gluon Development Platform
 * Copyright (c) 2010 Arjen Hiemstra <ahiemstra@heimr.nl>
 *
 * 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 Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "materialasset.h"

#include <core/gdlhandler.h>
#include <graphics/material.h>
#include <graphics/materialinstance.h>
#include <graphics/engine.h>

#include <QtGui/QAction>

REGISTER_OBJECTTYPE( GluonEngine, MaterialAsset )

using namespace GluonEngine;

class MaterialAsset::MaterialAssetPrivate
{
    public:
        MaterialAssetPrivate() : material( 0 ) {}
        ~MaterialAssetPrivate() {}

        QPixmap icon;

        GluonGraphics::Material* material;

        QList<QAction*> actions;
};

MaterialAsset::MaterialAsset( QObject* parent )
    : Asset( parent )
    , d( new MaterialAssetPrivate )
{
    QAction* newInstance = new QAction( "New instance", 0 );
    connect( newInstance, SIGNAL( triggered( bool ) ), SLOT( createInstance() ) );
    d->actions.append( newInstance );
}

MaterialAsset::~MaterialAsset()
{
    // TODO: MaterialAsset needs to clean up after itself. This needs loading process fixes though.
    //if(d->material)
    //    GluonGraphics::Engine::instance()->destroyMaterial(name());
    qDeleteAll( d->actions );
    delete d;
}

QIcon MaterialAsset::icon() const
{
    if( d->icon.isNull() )
        return GluonEngine::Asset::icon();

    return QIcon( d->icon );
}

const QStringList MaterialAsset::supportedMimeTypes() const
{
    QStringList types;

    types << "application/x-gluon-material";

    return types;
}

void MaterialAsset::load()
{
    if( !file().isEmpty() )
    {
        if( !d->material )
            d->material = GluonGraphics::Engine::instance()->createMaterial( name() );

        if( d->material->load( file() ) )
        {
            d->material->build();
            mimeData()->setText( name() );

            Asset::load();
            return;
        }
    }

    debug( "Error loading material: %1", name() );
}

const QList<AssetTemplate*> MaterialAsset::templates()
{
    QList<AssetTemplate*> templates;
    templates.append( new AssetTemplate( "Material", "material_template.gml", "material", this ) );
    templates.append( new AssetTemplate( "Animated Sprite Material", "animatedsprite_template.gml", "material", this ) );
    return templates;
}

QList<QAction*> MaterialAsset::actions()
{
    return d->actions;
}

void MaterialAsset::setName( const QString& newName )
{
    if( d->material )
    {
        GluonGraphics::Engine::instance()->removeMaterial( name() );
        GluonGraphics::Engine::instance()->addMaterial( newName, d->material );
    }
    GluonEngine::Asset::setName( newName );
}

bool MaterialAsset::shouldSerializeChildren() const
{
    return true;
}

void MaterialAsset::sanitize()
{
    GluonCore::GluonObject::sanitize();

    if( !d->material )
        d->material = GluonGraphics::Engine::instance()->createMaterial( name() );

    QObjectList allChildren = children();
    foreach( QObject * child, allChildren )
    {
        GluonGraphics::MaterialInstance* instance = qobject_cast<GluonGraphics::MaterialInstance*>( child );
        if( instance && d->material )
            instance->setMaterial( d->material );
    }
}

void MaterialAsset::createInstance()
{
    if( !isLoaded() )
        return;

    GluonGraphics::MaterialInstance* instance = new GluonGraphics::MaterialInstance( this );
    instance->setName( "New Instance" );
    instance->setPropertiesFromMaterial();
    instance->setMaterial( d->material );
}

Q_EXPORT_PLUGIN2( gluon_asset_material, GluonEngine::MaterialAsset )

#include "materialasset.moc"
<|endoftext|>


<commit_before>// Copyright (C) 2015 Alexandre Janniaux
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/Posix/FileImpl.hpp>
#include <Nazara/Core/Error.hpp>
#include <cstdio>
#include <Nazara/Core/Debug.hpp>

namespace Nz
{
	FileImpl::FileImpl(const File* parent) :
	m_endOfFile(false),
	m_endOfFileUpdated(true)
	{
		NazaraUnused(parent);
	}

	void FileImpl::Close()
	{
		if (m_fileDescriptor != -1)
			close(m_fileDescriptor);
	}

	bool FileImpl::EndOfFile() const
	{
		if (!m_endOfFileUpdated)
		{
			struct stat64 fileSize;
			if (fstat64(m_fileDescriptor, &fileSize) == -1)
				fileSize.st_size = 0;

			m_endOfFile = (GetCursorPos() >= static_cast<UInt64>(fileSize.st_size));
			m_endOfFileUpdated = true;
		}

		return m_endOfFile;
	}

	void FileImpl::Flush()
	{
		if (fsync(m_fileDescriptor) == -1)
			NazaraError("Unable to flush file: " + Error::GetLastSystemError());
	}

	UInt64 FileImpl::GetCursorPos() const
	{
		off64_t position = lseek64(m_fileDescriptor, 0, SEEK_CUR);
		return static_cast<UInt64>(position);
	}

	bool FileImpl::Open(const String& filePath, OpenModeFlags mode)
	{
		int flags;
		mode_t permissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;

		if ((mode & OpenMode_ReadWrite) == OpenMode_ReadWrite)
			flags = O_CREAT | O_RDWR;
		else if ((mode & OpenMode_ReadOnly) == OpenMode_ReadOnly)
			flags = O_RDONLY;
		else if ((mode & OpenMode_WriteOnly) == OpenMode_WriteOnly)
			flags = O_CREAT | O_WRONLY;
		else
			return false;

		if (mode & OpenMode_Append)
			flags |= O_APPEND;

		if (mode & OpenMode_Truncate)
			flags |= O_TRUNC;

		///TODO: lock
		//if ((mode & OpenMode_Lock) == 0)
		//	shareMode |= FILE_SHARE_WRITE;

		m_fileDescriptor = open64(filePath.GetConstBuffer(), flags, permissions);
		return m_fileDescriptor != -1;
	}

	std::size_t FileImpl::Read(void* buffer, std::size_t size)
	{
		ssize_t bytes;
		if ((bytes = read(m_fileDescriptor, buffer, size)) != -1)
		{
			m_endOfFile = (static_cast<std::size_t>(bytes) != size);
			m_endOfFileUpdated = true;

			return static_cast<std::size_t>(bytes);
		}
		else
			return 0;
	}

	bool FileImpl::SetCursorPos(CursorPosition pos, Int64 offset)
	{
		int moveMethod;
		switch (pos)
		{
			case CursorPosition_AtBegin:
				moveMethod = SEEK_SET;
				break;

			case CursorPosition_AtCurrent:
				moveMethod = SEEK_CUR;
				break;

			case CursorPosition_AtEnd:
				moveMethod = SEEK_END;
				break;

			default:
				NazaraInternalError("Cursor position not handled (0x" + String::Number(pos, 16) + ')');
				return false;
		}

		m_endOfFileUpdated = false;

		return lseek64(m_fileDescriptor, offset, moveMethod) != -1;
	}

	bool FileImpl::SetSize(UInt64 size)
	{
		return ftruncate64(m_fileDescriptor, size) != 0;
	}

	std::size_t FileImpl::Write(const void* buffer, std::size_t size)
	{
		lockf64(m_fileDescriptor, F_LOCK, size);
		ssize_t written = write(m_fileDescriptor, buffer, size);
		lockf64(m_fileDescriptor, F_ULOCK, size);

		m_endOfFileUpdated = false;

		return written;
	}

	bool FileImpl::Copy(const String& sourcePath, const String& targetPath)
	{
		int fd1 = open64(sourcePath.GetConstBuffer(), O_RDONLY);
		if (fd1 == -1)
		{
			NazaraError("Fail to open input file (" + sourcePath + "): " + Error::GetLastSystemError());
			return false;
		}

		mode_t permissions;
		struct stat sb;
		if (fstat(fd1, &sb) == -1) // get permission from first file
		{
			NazaraWarning("Could not get permissions of source file");
			permissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
		}
		else
		{
			permissions = sb.st_mode & ~S_IFMT; // S_IFMT: bit mask for the file type bit field -> ~S_IFMT: general permissions
		}

		int fd2 = open64(targetPath.GetConstBuffer(), O_WRONLY | O_TRUNC, permissions);
		if (fd2 == -1)
		{
			NazaraError("Fail to open output file (" + targetPath + "): " + Error::GetLastSystemError()); // TODO: more info ?
			close(fd1);
			return false;
		}

		char buffer[512];
		ssize_t bytes;
		do
		{
			bytes = read(fd1,buffer,512);
			if (bytes == -1)
			{
				close(fd1);
				close(fd2);
				NazaraError("An error occured from copy : " + Error::GetLastSystemError());
				return false;
			}
			write(fd2,buffer,bytes);
		}
		while (bytes == 512);

		close(fd1);
		close(fd2);
		return true;
	}

	bool FileImpl::Delete(const String& filePath)
	{
		bool success = unlink(filePath.GetConstBuffer()) != -1;

		if (success)
			return true;
		else
		{
			NazaraError("Failed to delete file (" + filePath + "): " + Error::GetLastSystemError());
			return false;
		}
	}

	bool FileImpl::Exists(const String& filePath)
	{
		const char* path = filePath.GetConstBuffer();
		if (access(path, F_OK) != -1)
			return true;

		return false;
	}

	time_t FileImpl::GetCreationTime(const String& filePath)
	{
		NazaraUnused(filePath);

		NazaraWarning("Posix has no creation time information");
		return 0;
	}

	time_t FileImpl::GetLastAccessTime(const String& filePath)
	{
		struct stat64 stats;
		stat64(filePath.GetConstBuffer(), &stats);

		return stats.st_atime;
	}

	time_t FileImpl::GetLastWriteTime(const String& filePath)
	{
		struct stat64 stats;
		stat64(filePath.GetConstBuffer(), &stats);

		return stats.st_mtime;
	}

	UInt64 FileImpl::GetSize(const String& filePath)
	{
		struct stat64 stats;
		stat64(filePath.GetConstBuffer(), &stats);

		return static_cast<UInt64>(stats.st_size);
	}

	bool FileImpl::Rename(const String& sourcePath, const String& targetPath)
	{
		bool success = std::rename(sourcePath.GetConstBuffer(), targetPath.GetConstBuffer()) != -1;

		if (success)
			return true;
		else
		{
			NazaraError("Unable to rename file: " + Error::GetLastSystemError());
			return false;
		}
	}
}
<commit_msg>Core/File: Fix OpenMode_MustExist for Linux<commit_after>// Copyright (C) 2015 Alexandre Janniaux
// This file is part of the "Nazara Engine - Core module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/Posix/FileImpl.hpp>
#include <Nazara/Core/Error.hpp>
#include <cstdio>
#include <Nazara/Core/Debug.hpp>

namespace Nz
{
	FileImpl::FileImpl(const File* parent) :
	m_endOfFile(false),
	m_endOfFileUpdated(true)
	{
		NazaraUnused(parent);
	}

	void FileImpl::Close()
	{
		if (m_fileDescriptor != -1)
			close(m_fileDescriptor);
	}

	bool FileImpl::EndOfFile() const
	{
		if (!m_endOfFileUpdated)
		{
			struct stat64 fileSize;
			if (fstat64(m_fileDescriptor, &fileSize) == -1)
				fileSize.st_size = 0;

			m_endOfFile = (GetCursorPos() >= static_cast<UInt64>(fileSize.st_size));
			m_endOfFileUpdated = true;
		}

		return m_endOfFile;
	}

	void FileImpl::Flush()
	{
		if (fsync(m_fileDescriptor) == -1)
			NazaraError("Unable to flush file: " + Error::GetLastSystemError());
	}

	UInt64 FileImpl::GetCursorPos() const
	{
		off64_t position = lseek64(m_fileDescriptor, 0, SEEK_CUR);
		return static_cast<UInt64>(position);
	}

	bool FileImpl::Open(const String& filePath, OpenModeFlags mode)
	{
		int flags;
		mode_t permissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;

		if ((mode & OpenMode_ReadWrite) == OpenMode_ReadWrite)
			flags = O_CREAT | O_RDWR;
		else if ((mode & OpenMode_ReadOnly) == OpenMode_ReadOnly)
			flags = O_RDONLY;
		else if ((mode & OpenMode_WriteOnly) == OpenMode_WriteOnly)
			flags = O_CREAT | O_WRONLY;
		else
			return false;

		if (mode & OpenMode_Append)
			flags |= O_APPEND;

		if (mode & OpenMode_MustExist)
			flags &= ~O_CREAT;

		if (mode & OpenMode_Truncate)
			flags |= O_TRUNC;

		///TODO: lock
		//if ((mode & OpenMode_Lock) == 0)
		//	shareMode |= FILE_SHARE_WRITE;

		m_fileDescriptor = open64(filePath.GetConstBuffer(), flags, permissions);
		return m_fileDescriptor != -1;
	}

	std::size_t FileImpl::Read(void* buffer, std::size_t size)
	{
		ssize_t bytes;
		if ((bytes = read(m_fileDescriptor, buffer, size)) != -1)
		{
			m_endOfFile = (static_cast<std::size_t>(bytes) != size);
			m_endOfFileUpdated = true;

			return static_cast<std::size_t>(bytes);
		}
		else
			return 0;
	}

	bool FileImpl::SetCursorPos(CursorPosition pos, Int64 offset)
	{
		int moveMethod;
		switch (pos)
		{
			case CursorPosition_AtBegin:
				moveMethod = SEEK_SET;
				break;

			case CursorPosition_AtCurrent:
				moveMethod = SEEK_CUR;
				break;

			case CursorPosition_AtEnd:
				moveMethod = SEEK_END;
				break;

			default:
				NazaraInternalError("Cursor position not handled (0x" + String::Number(pos, 16) + ')');
				return false;
		}

		m_endOfFileUpdated = false;

		return lseek64(m_fileDescriptor, offset, moveMethod) != -1;
	}

	bool FileImpl::SetSize(UInt64 size)
	{
		return ftruncate64(m_fileDescriptor, size) != 0;
	}

	std::size_t FileImpl::Write(const void* buffer, std::size_t size)
	{
		lockf64(m_fileDescriptor, F_LOCK, size);
		ssize_t written = write(m_fileDescriptor, buffer, size);
		lockf64(m_fileDescriptor, F_ULOCK, size);

		m_endOfFileUpdated = false;

		return written;
	}

	bool FileImpl::Copy(const String& sourcePath, const String& targetPath)
	{
		int fd1 = open64(sourcePath.GetConstBuffer(), O_RDONLY);
		if (fd1 == -1)
		{
			NazaraError("Fail to open input file (" + sourcePath + "): " + Error::GetLastSystemError());
			return false;
		}

		mode_t permissions;
		struct stat sb;
		if (fstat(fd1, &sb) == -1) // get permission from first file
		{
			NazaraWarning("Could not get permissions of source file");
			permissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
		}
		else
		{
			permissions = sb.st_mode & ~S_IFMT; // S_IFMT: bit mask for the file type bit field -> ~S_IFMT: general permissions
		}

		int fd2 = open64(targetPath.GetConstBuffer(), O_WRONLY | O_TRUNC, permissions);
		if (fd2 == -1)
		{
			NazaraError("Fail to open output file (" + targetPath + "): " + Error::GetLastSystemError()); // TODO: more info ?
			close(fd1);
			return false;
		}

		char buffer[512];
		ssize_t bytes;
		do
		{
			bytes = read(fd1,buffer,512);
			if (bytes == -1)
			{
				close(fd1);
				close(fd2);
				NazaraError("An error occured from copy : " + Error::GetLastSystemError());
				return false;
			}
			write(fd2,buffer,bytes);
		}
		while (bytes == 512);

		close(fd1);
		close(fd2);
		return true;
	}

	bool FileImpl::Delete(const String& filePath)
	{
		bool success = unlink(filePath.GetConstBuffer()) != -1;

		if (success)
			return true;
		else
		{
			NazaraError("Failed to delete file (" + filePath + "): " + Error::GetLastSystemError());
			return false;
		}
	}

	bool FileImpl::Exists(const String& filePath)
	{
		const char* path = filePath.GetConstBuffer();
		if (access(path, F_OK) != -1)
			return true;

		return false;
	}

	time_t FileImpl::GetCreationTime(const String& filePath)
	{
		NazaraUnused(filePath);

		NazaraWarning("Posix has no creation time information");
		return 0;
	}

	time_t FileImpl::GetLastAccessTime(const String& filePath)
	{
		struct stat64 stats;
		stat64(filePath.GetConstBuffer(), &stats);

		return stats.st_atime;
	}

	time_t FileImpl::GetLastWriteTime(const String& filePath)
	{
		struct stat64 stats;
		stat64(filePath.GetConstBuffer(), &stats);

		return stats.st_mtime;
	}

	UInt64 FileImpl::GetSize(const String& filePath)
	{
		struct stat64 stats;
		stat64(filePath.GetConstBuffer(), &stats);

		return static_cast<UInt64>(stats.st_size);
	}

	bool FileImpl::Rename(const String& sourcePath, const String& targetPath)
	{
		bool success = std::rename(sourcePath.GetConstBuffer(), targetPath.GetConstBuffer()) != -1;

		if (success)
			return true;
		else
		{
			NazaraError("Unable to rename file: " + Error::GetLastSystemError());
			return false;
		}
	}
}
<|endoftext|>