<commit_before>#ifndef POINTER_UTILS_STATE_PTR_HPP
#define POINTER_UTILS_STATE_PTR_HPP

#include <cassert>
#include <memory>

// Users can change the namespace of `state_ptr`.
// The default namespace is `putl` which stands for "Pointer Utils".
#ifndef UTILS_STATE_PTR_HPP_NAMESPACE
#define UTILS_STATE_PTR_HPP_NAMESPACE putl
#endif

namespace UTILS_STATE_PTR_HPP_NAMESPACE {
	namespace detail {
		/// \brief Returns the logarithm to the power of `2` for the given `number`.
		///
		/// Note: Returns `0` for the special case when `number` is `0`.
		template<typename T>
		constexpr auto log2(T number) -> T {
			T acc{0};
			while (number > 1) {
				number /= 2;
				acc += 1;
			}
			return acc;
		}
	}

	template<typename T,
	         typename S = uintptr_t,
	         size_t req_state_bits = detail::log2(alignof(T))>
	class state_ptr {
	public:
		/// \brief The element type.
		///
		/// The element type is the type that this state pointer points to.
		using element_type       = T;

		/// \brief Type representing a pointer to an element type.
		using pointer_type       = T*;

		/// \brief Type representing a pointer to a const element type.
		using const_pointer_type = T const*;

		/// \brief Type representing a reference to the element type.
		using reference_type     = typename std::add_lvalue_reference<T>::type;

		/// \brief The user defined type used to represent the state.
		using state_type         = S;

		/// \brief The type used internally to store the pointer and the state.
		using internal_type      = uintptr_t;

	private:
		/// \brief The maximum number of bits that can be reserved to represent
		///        the state depending on the alignment of the element type.
		constexpr static size_t state_bits_max = detail::log2(alignof(T));

		/// \brief The number of bits reserved for the value of the state.
		constexpr static size_t state_bits     = std::min(req_state_bits, state_bits_max);
		static_assert(req_state_bits <= state_bits_max, "The alignment of T is not sufficient to store the requested amount of state bits.");
		// static_assert(state_bits > 0, "The alignment of T is not sufficient to store an additional state.");

		/// \brief The number of bits reserved for the value of the pointer.
		constexpr static size_t ptr_bits   = 8 * sizeof(pointer_type) - state_bits;

		/// \brief The maximum value that is possible to be stored as state
		///        with the given amount of bits reserved for the value of the state.
		constexpr static internal_type state_max  = (1u << state_bits) - 1u;

		/// \brief The bit-mask to extract the state value out of the shared memory.
		constexpr static internal_type state_mask = state_bits == 0 ? 0 : (~internal_type{0}) >> ptr_bits;

		/// \brief The bit-mask to extract the pointer value out of the shared memory.
		constexpr static internal_type ptr_mask   = ~state_mask;

	public:
		/// \brief Creates a state_ptr instance initialized by a null-pointer and a given state.
		///
		/// Panics if the given state is out of bounds of valid state.
		constexpr state_ptr(std::nullptr_t, state_type) noexcept;

		/// \brief Creates a state_ptr instance pointing to the given pointee and
		///        initialized with the given state.
		///
		/// Panics if the given state is out of bounds of valid state.
		state_ptr(pointer_type ptr, state_type) noexcept;

		/// \brief Copies the given state_ptr.
		explicit state_ptr(state_ptr const& p) = default;

		/// \brief Sets the state value of this state_ptr to the given value.
		///
		/// Note: This panicks if assertions are enabled whenever the given state
		///       is out of bounds of the valid state space.
		///       When assertions are disabled this has undefined behaviour in the
		///       error case.
		void set_state(state_type new_state) noexcept;

		/// \brief Returns the current state of this state_ptr.
		auto get_state() const noexcept -> state_type;

		/// \brief Returns the wrapped pointer of this state_ptr.
		auto get_ptr() noexcept -> pointer_type;

		/// \brief Returns the wrapped pointer of this state_ptr.
		auto get_ptr() const noexcept -> const_pointer_type;

		/// \brief Forwards to the wrapped pointer as reference.
		auto operator*() const -> reference_type;

		/// \brief Forwards to the wrapped pointer.
		auto operator->() const noexcept -> pointer_type;

		/// \brief Returns false if this state_ptr wraps nullptr, and returns true otherwise.
		explicit operator bool() const noexcept;

		template<typename T1, typename S1, size_t ReqStateBits>
		friend bool operator==(state_ptr<T1, S1, ReqStateBits> const&, state_ptr<T1, S1, ReqStateBits> const&) noexcept;

		template<typename T1, typename S1, size_t ReqStateBits>
		friend bool operator!=(state_ptr<T1, S1, ReqStateBits> const&, state_ptr<T1, S1, ReqStateBits> const&) noexcept;

		template<typename T1, typename S1, size_t ReqStateBits>
		friend bool operator==(state_ptr<T1, S1, ReqStateBits> const&, nullptr_t) noexcept;

		template<typename T1, typename S1, size_t ReqStateBits>
		friend bool operator!=(state_ptr<T1, S1, ReqStateBits> const&, nullptr_t) noexcept;

		template<typename T1, typename S1, size_t ReqStateBits>
		friend bool operator==(nullptr_t, state_ptr<T1, S1, ReqStateBits> const&) noexcept;

		template<typename T1, typename S1, size_t ReqStateBits>
		friend bool operator!=(nullptr_t, state_ptr<T1, S1, ReqStateBits> const&) noexcept;

		template<typename T1, typename S1, size_t ReqStateBits>
		friend bool operator<(state_ptr<T1, S1, ReqStateBits> const& lhs, state_ptr<T1, S1, ReqStateBits> const& rhs) noexcept;

		template<typename T1, typename S1, size_t ReqStateBits>
		friend bool operator<=(state_ptr<T1, S1, ReqStateBits> const& lhs, state_ptr<T1, S1, ReqStateBits> const& rhs) noexcept;

		template<typename T1, typename S1, size_t ReqStateBits>
		friend bool operator> (state_ptr<T1, S1, ReqStateBits> const& lhs, state_ptr<T1, S1, ReqStateBits> const& rhs) noexcept;

		template<typename T1, typename S1, size_t ReqStateBits>
		friend bool operator<=(state_ptr<T1, S1, ReqStateBits> const& lhs, state_ptr<T1, S1, ReqStateBits> const& rhs) noexcept;

	private:
		/// \brief Returns the bits representing the pointer value as internal type.
		constexpr auto get_ptr_bits() const noexcept -> internal_type;

		/// \brief Returns the bits representing the state value as internal type.
		constexpr auto get_state_bits() const noexcept -> internal_type;

		/// \brief Returns `true` if the given state is within valid bounds for the state value.
		///        This is associated to the reserved bits for the state value.
		constexpr static bool is_valid_state(state_type) noexcept;

		/// \brief Asserts that the given state is within bounds for the state value.
		static void assert_valid_state(state_type) noexcept;

		/// \brief Asserts that the state of this state_ptr is within bounds.
		void assert_invariant() const noexcept;

	private:
		internal_type m_ptr_and_state;
	};

	/// =======================================================================
	///  Implementation of constructors and member functions.
	/// =======================================================================

	template<typename T, typename S, size_t StateBits>
	constexpr bool state_ptr<T, S, StateBits>::is_valid_state(state_type state) noexcept {
		return static_cast<internal_type>(state) <= state_max;
	}

	template<typename T, typename S, size_t StateBits>
	void state_ptr<T, S, StateBits>::assert_valid_state(state_type state) noexcept {
		return assert(is_valid_state(state) && "state value is out of bounds for this state_ptr");
	}

	template<typename T, typename S, size_t StateBits>
	constexpr state_ptr<T, S, StateBits>::state_ptr(
		std::nullptr_t,
		state_type state
	) noexcept :
		m_ptr_and_state{0}
	{
		assert_valid_state(state);
		set_state(state);
	}

	template<typename T, typename S, size_t StateBits>
	state_ptr<T, S, StateBits>::state_ptr(
		pointer_type ptr,
		state_type   state
	) noexcept :
		m_ptr_and_state{reinterpret_cast<uintptr_t>(ptr)}
	{
		assert_valid_state(state);
		set_state(state);
	}

	template<typename T, typename S, size_t StateBits>
	constexpr auto state_ptr<T, S, StateBits>::get_ptr_bits() const noexcept -> internal_type {
		return m_ptr_and_state & ptr_mask;
	}

	template<typename T, typename S, size_t StateBits>
	constexpr auto state_ptr<T, S, StateBits>::get_state_bits() const noexcept -> internal_type {
		return m_ptr_and_state & state_mask;
	}

	template<typename T, typename S, size_t StateBits>
	void state_ptr<T, S, StateBits>::assert_invariant() const noexcept {
		assert_valid_state(get_state());
	}

	template<typename T, typename S, size_t StateBits>
	void state_ptr<T, S, StateBits>::set_state(state_type new_state) noexcept {
		assert_valid_state(new_state);
		m_ptr_and_state = get_ptr_bits() | static_cast<internal_type>(new_state);
	}

	template<typename T, typename S, size_t StateBits>
	auto state_ptr<T, S, StateBits>::get_state() const noexcept -> state_type {
		return static_cast<state_type>(get_state_bits());
	}

	template<typename T, typename S, size_t StateBits>
	auto state_ptr<T, S, StateBits>::get_ptr() noexcept -> pointer_type {
		return reinterpret_cast<pointer_type>(get_ptr_bits());
	}

	template<typename T, typename S, size_t StateBits>
	auto state_ptr<T, S, StateBits>::get_ptr() const noexcept -> const_pointer_type {
		return reinterpret_cast<pointer_type>(get_ptr_bits());
	}

	template<typename T, typename S, size_t StateBits>
	auto state_ptr<T, S, StateBits>::operator*() const -> reference_type {
		return reinterpret_cast<reference_type>(get_ptr());
	}

	template<typename T, typename S, size_t StateBits>
	auto state_ptr<T, S, StateBits>::operator->() const noexcept -> pointer_type {
		return get_ptr();
	}

	template<typename T, typename S, size_t StateBits>
	state_ptr<T, S, StateBits>::operator bool() const noexcept {
		return get_ptr() != nullptr;
	}

	/// =======================================================================
	///  Implementation of comparison operators.
	/// =======================================================================

	template<typename T, typename S, size_t StateBits>
	auto operator==(state_ptr<T, S, StateBits> const& rhs, state_ptr<T, S, StateBits> const& lhs) noexcept -> bool {
		return lhs.m_ptr_and_state == rhs.m_ptr_and_state;
	}

	template<typename T, typename S, size_t StateBits>
	auto operator!=(state_ptr<T, S, StateBits> const& rhs, state_ptr<T, S, StateBits> const& lhs) noexcept -> bool {
		return !(lhs == rhs);
	}

	template<typename T, typename S, size_t StateBits>
	bool operator==(state_ptr<T, S, StateBits> const& rhs, nullptr_t) noexcept {
		return rhs.get_ptr() == nullptr;
	}

	template<typename T, typename S, size_t StateBits>
	bool operator!=(state_ptr<T, S, StateBits> const& rhs, nullptr_t) noexcept {
		return rhs.get_ptr() != nullptr;
	}

	template<typename T, typename S, size_t StateBits>
	bool operator==(nullptr_t, state_ptr<T, S, StateBits> const& lhs) noexcept {
		return nullptr == lhs;
	}

	template<typename T, typename S, size_t StateBits>
	bool operator!=(nullptr_t, state_ptr<T, S, StateBits> const& lhs) noexcept {
		return nullptr == lhs;
	}

	/// =======================================================================
	///  Implementation of relational operators.
	/// =======================================================================

	template<typename T, typename S, size_t StateBits>
	auto operator<(state_ptr<T, S, StateBits> const& rhs, state_ptr<T> const& lhs) noexcept -> bool {
		return !(lhs.m_ptr < rhs.m_ptr);
	}

	template<typename T, typename S, size_t StateBits>
	auto operator<=(state_ptr<T, S, StateBits> const& rhs, state_ptr<T> const& lhs) noexcept -> bool {
		return !(lhs > rhs);
	}

	template<typename T, typename S, size_t StateBits>
	auto operator>=(state_ptr<T, S, StateBits> const& rhs, state_ptr<T> const& lhs) noexcept -> bool {
		return !(lhs < rhs);
	}

	template<typename T, typename S, size_t StateBits>
	auto operator>(state_ptr<T, S, StateBits> const& rhs, state_ptr<T> const& lhs) noexcept -> bool {
		return !(lhs <= rhs);
	}
}

/// ===========================================================================
///  Implementation of default std::hash template specialization.
/// ===========================================================================

namespace std {
	template<typename T, typename S, size_t StateBits>
	struct hash<putl::state_ptr<T, S, StateBits>> {
	public:
		size_t operator()(const putl::state_ptr<T, S> &p) const
		{
			return std::hash<typename putl::state_ptr<T, S>::internal_type>()(p.m_ptr_and_state);
		}
	};
}

#endif // POINTER_UTILS_STATE_PTR_HPP
<commit_msg>added class-level documentation to state_ptr<commit_after>#ifndef POINTER_UTILS_STATE_PTR_HPP
#define POINTER_UTILS_STATE_PTR_HPP

#include <cassert>
#include <memory>

// Users can change the namespace of `state_ptr`.
// The default namespace is `putl` which stands for "Pointer Utils".
#ifndef UTILS_STATE_PTR_HPP_NAMESPACE
#define UTILS_STATE_PTR_HPP_NAMESPACE putl
#endif

namespace UTILS_STATE_PTR_HPP_NAMESPACE {
	namespace detail {
		/// \brief Returns the logarithm to the power of `2` for the given `number`.
		///
		/// Note: Returns `0` for the special case when `number` is `0`.
		template<typename T>
		constexpr auto log2(T number) -> T {
			T acc{0};
			while (number > 1) {
				number /= 2;
				acc += 1;
			}
			return acc;
		}
	}

	/// \brief A non-owning smart pointer that allows for storing an additional space-optimized
	///        state along the pointer value that is dependend on the wrapped type's alignment.
	///
	/// Users can use custom state types (e.g. user-defined enums) as state type.
	/// It is possible to further limit the representable state value, e.g. to adjust the state_ptr
	/// to the state type dimensions. E.g. When there are just two possible states (enum Bit { set=0, unset=1, dontknow=2 };)
	/// and the state_ptr for T allows for 3 state bits the user is still able to limit it to 2 bits.
	///
	/// Increasing the limit is not possible and will fail at compile-time!
	///
	/// The state_ptr interface is based on the interface that is provided by std::unique_ptr.
	///
	/// Note: It is planned to provide an implementation of an owning_state_ptr in the future.
	///
	template<typename T,
	         typename S = uintptr_t,
	         size_t req_state_bits = detail::log2(alignof(T))>
	class state_ptr {
	public:
		/// \brief The element type.
		///
		/// The element type is the type that this state pointer points to.
		using element_type       = T;

		/// \brief Type representing a pointer to an element type.
		using pointer_type       = T*;

		/// \brief Type representing a pointer to a const element type.
		using const_pointer_type = T const*;

		/// \brief Type representing a reference to the element type.
		using reference_type     = typename std::add_lvalue_reference<T>::type;

		/// \brief The user defined type used to represent the state.
		using state_type         = S;

		/// \brief The type used internally to store the pointer and the state.
		using internal_type      = uintptr_t;

	private:
		/// \brief The maximum number of bits that can be reserved to represent
		///        the state depending on the alignment of the element type.
		constexpr static size_t state_bits_max = detail::log2(alignof(T));

		/// \brief The number of bits reserved for the value of the state.
		constexpr static size_t state_bits     = std::min(req_state_bits, state_bits_max);
		static_assert(req_state_bits <= state_bits_max, "The alignment of T is not sufficient to store the requested amount of state bits.");
		// static_assert(state_bits > 0, "The alignment of T is not sufficient to store an additional state.");

		/// \brief The number of bits reserved for the value of the pointer.
		constexpr static size_t ptr_bits   = 8 * sizeof(pointer_type) - state_bits;

		/// \brief The maximum value that is possible to be stored as state
		///        with the given amount of bits reserved for the value of the state.
		constexpr static internal_type state_max  = (1u << state_bits) - 1u;

		/// \brief The bit-mask to extract the state value out of the shared memory.
		constexpr static internal_type state_mask = state_bits == 0 ? 0 : (~internal_type{0}) >> ptr_bits;

		/// \brief The bit-mask to extract the pointer value out of the shared memory.
		constexpr static internal_type ptr_mask   = ~state_mask;

	public:
		/// \brief Creates a state_ptr instance initialized by a null-pointer and a given state.
		///
		/// Panics if the given state is out of bounds of valid state.
		constexpr state_ptr(std::nullptr_t, state_type) noexcept;

		/// \brief Creates a state_ptr instance pointing to the given pointee and
		///        initialized with the given state.
		///
		/// Panics if the given state is out of bounds of valid state.
		state_ptr(pointer_type ptr, state_type) noexcept;

		/// \brief Copies the given state_ptr.
		explicit state_ptr(state_ptr const& p) = default;

		/// \brief Sets the state value of this state_ptr to the given value.
		///
		/// Note: This panicks if assertions are enabled whenever the given state
		///       is out of bounds of the valid state space.
		///       When assertions are disabled this has undefined behaviour in the
		///       error case.
		void set_state(state_type new_state) noexcept;

		/// \brief Returns the current state of this state_ptr.
		auto get_state() const noexcept -> state_type;

		/// \brief Returns the wrapped pointer of this state_ptr.
		auto get_ptr() noexcept -> pointer_type;

		/// \brief Returns the wrapped pointer of this state_ptr.
		auto get_ptr() const noexcept -> const_pointer_type;

		/// \brief Forwards to the wrapped pointer as reference.
		auto operator*() const -> reference_type;

		/// \brief Forwards to the wrapped pointer.
		auto operator->() const noexcept -> pointer_type;

		/// \brief Returns false if this state_ptr wraps nullptr, and returns true otherwise.
		explicit operator bool() const noexcept;

		template<typename T1, typename S1, size_t ReqStateBits>
		friend bool operator==(state_ptr<T1, S1, ReqStateBits> const&, state_ptr<T1, S1, ReqStateBits> const&) noexcept;

		template<typename T1, typename S1, size_t ReqStateBits>
		friend bool operator!=(state_ptr<T1, S1, ReqStateBits> const&, state_ptr<T1, S1, ReqStateBits> const&) noexcept;

		template<typename T1, typename S1, size_t ReqStateBits>
		friend bool operator==(state_ptr<T1, S1, ReqStateBits> const&, nullptr_t) noexcept;

		template<typename T1, typename S1, size_t ReqStateBits>
		friend bool operator!=(state_ptr<T1, S1, ReqStateBits> const&, nullptr_t) noexcept;

		template<typename T1, typename S1, size_t ReqStateBits>
		friend bool operator==(nullptr_t, state_ptr<T1, S1, ReqStateBits> const&) noexcept;

		template<typename T1, typename S1, size_t ReqStateBits>
		friend bool operator!=(nullptr_t, state_ptr<T1, S1, ReqStateBits> const&) noexcept;

		template<typename T1, typename S1, size_t ReqStateBits>
		friend bool operator<(state_ptr<T1, S1, ReqStateBits> const& lhs, state_ptr<T1, S1, ReqStateBits> const& rhs) noexcept;

		template<typename T1, typename S1, size_t ReqStateBits>
		friend bool operator<=(state_ptr<T1, S1, ReqStateBits> const& lhs, state_ptr<T1, S1, ReqStateBits> const& rhs) noexcept;

		template<typename T1, typename S1, size_t ReqStateBits>
		friend bool operator> (state_ptr<T1, S1, ReqStateBits> const& lhs, state_ptr<T1, S1, ReqStateBits> const& rhs) noexcept;

		template<typename T1, typename S1, size_t ReqStateBits>
		friend bool operator<=(state_ptr<T1, S1, ReqStateBits> const& lhs, state_ptr<T1, S1, ReqStateBits> const& rhs) noexcept;

	private:
		/// \brief Returns the bits representing the pointer value as internal type.
		constexpr auto get_ptr_bits() const noexcept -> internal_type;

		/// \brief Returns the bits representing the state value as internal type.
		constexpr auto get_state_bits() const noexcept -> internal_type;

		/// \brief Returns `true` if the given state is within valid bounds for the state value.
		///        This is associated to the reserved bits for the state value.
		constexpr static bool is_valid_state(state_type) noexcept;

		/// \brief Asserts that the given state is within bounds for the state value.
		static void assert_valid_state(state_type) noexcept;

		/// \brief Asserts that the state of this state_ptr is within bounds.
		void assert_invariant() const noexcept;

	private:
		internal_type m_ptr_and_state;
	};

	/// =======================================================================
	///  Implementation of constructors and member functions.
	/// =======================================================================

	template<typename T, typename S, size_t StateBits>
	constexpr bool state_ptr<T, S, StateBits>::is_valid_state(state_type state) noexcept {
		return static_cast<internal_type>(state) <= state_max;
	}

	template<typename T, typename S, size_t StateBits>
	void state_ptr<T, S, StateBits>::assert_valid_state(state_type state) noexcept {
		return assert(is_valid_state(state) && "state value is out of bounds for this state_ptr");
	}

	template<typename T, typename S, size_t StateBits>
	constexpr state_ptr<T, S, StateBits>::state_ptr(
		std::nullptr_t,
		state_type state
	) noexcept :
		m_ptr_and_state{0}
	{
		assert_valid_state(state);
		set_state(state);
	}

	template<typename T, typename S, size_t StateBits>
	state_ptr<T, S, StateBits>::state_ptr(
		pointer_type ptr,
		state_type   state
	) noexcept :
		m_ptr_and_state{reinterpret_cast<uintptr_t>(ptr)}
	{
		assert_valid_state(state);
		set_state(state);
	}

	template<typename T, typename S, size_t StateBits>
	constexpr auto state_ptr<T, S, StateBits>::get_ptr_bits() const noexcept -> internal_type {
		return m_ptr_and_state & ptr_mask;
	}

	template<typename T, typename S, size_t StateBits>
	constexpr auto state_ptr<T, S, StateBits>::get_state_bits() const noexcept -> internal_type {
		return m_ptr_and_state & state_mask;
	}

	template<typename T, typename S, size_t StateBits>
	void state_ptr<T, S, StateBits>::assert_invariant() const noexcept {
		assert_valid_state(get_state());
	}

	template<typename T, typename S, size_t StateBits>
	void state_ptr<T, S, StateBits>::set_state(state_type new_state) noexcept {
		assert_valid_state(new_state);
		m_ptr_and_state = get_ptr_bits() | static_cast<internal_type>(new_state);
	}

	template<typename T, typename S, size_t StateBits>
	auto state_ptr<T, S, StateBits>::get_state() const noexcept -> state_type {
		return static_cast<state_type>(get_state_bits());
	}

	template<typename T, typename S, size_t StateBits>
	auto state_ptr<T, S, StateBits>::get_ptr() noexcept -> pointer_type {
		return reinterpret_cast<pointer_type>(get_ptr_bits());
	}

	template<typename T, typename S, size_t StateBits>
	auto state_ptr<T, S, StateBits>::get_ptr() const noexcept -> const_pointer_type {
		return reinterpret_cast<pointer_type>(get_ptr_bits());
	}

	template<typename T, typename S, size_t StateBits>
	auto state_ptr<T, S, StateBits>::operator*() const -> reference_type {
		return reinterpret_cast<reference_type>(get_ptr());
	}

	template<typename T, typename S, size_t StateBits>
	auto state_ptr<T, S, StateBits>::operator->() const noexcept -> pointer_type {
		return get_ptr();
	}

	template<typename T, typename S, size_t StateBits>
	state_ptr<T, S, StateBits>::operator bool() const noexcept {
		return get_ptr() != nullptr;
	}

	/// =======================================================================
	///  Implementation of comparison operators.
	/// =======================================================================

	template<typename T, typename S, size_t StateBits>
	auto operator==(state_ptr<T, S, StateBits> const& rhs, state_ptr<T, S, StateBits> const& lhs) noexcept -> bool {
		return lhs.m_ptr_and_state == rhs.m_ptr_and_state;
	}

	template<typename T, typename S, size_t StateBits>
	auto operator!=(state_ptr<T, S, StateBits> const& rhs, state_ptr<T, S, StateBits> const& lhs) noexcept -> bool {
		return !(lhs == rhs);
	}

	template<typename T, typename S, size_t StateBits>
	bool operator==(state_ptr<T, S, StateBits> const& rhs, nullptr_t) noexcept {
		return rhs.get_ptr() == nullptr;
	}

	template<typename T, typename S, size_t StateBits>
	bool operator!=(state_ptr<T, S, StateBits> const& rhs, nullptr_t) noexcept {
		return rhs.get_ptr() != nullptr;
	}

	template<typename T, typename S, size_t StateBits>
	bool operator==(nullptr_t, state_ptr<T, S, StateBits> const& lhs) noexcept {
		return nullptr == lhs;
	}

	template<typename T, typename S, size_t StateBits>
	bool operator!=(nullptr_t, state_ptr<T, S, StateBits> const& lhs) noexcept {
		return nullptr == lhs;
	}

	/// =======================================================================
	///  Implementation of relational operators.
	/// =======================================================================

	template<typename T, typename S, size_t StateBits>
	auto operator<(state_ptr<T, S, StateBits> const& rhs, state_ptr<T> const& lhs) noexcept -> bool {
		return !(lhs.m_ptr < rhs.m_ptr);
	}

	template<typename T, typename S, size_t StateBits>
	auto operator<=(state_ptr<T, S, StateBits> const& rhs, state_ptr<T> const& lhs) noexcept -> bool {
		return !(lhs > rhs);
	}

	template<typename T, typename S, size_t StateBits>
	auto operator>=(state_ptr<T, S, StateBits> const& rhs, state_ptr<T> const& lhs) noexcept -> bool {
		return !(lhs < rhs);
	}

	template<typename T, typename S, size_t StateBits>
	auto operator>(state_ptr<T, S, StateBits> const& rhs, state_ptr<T> const& lhs) noexcept -> bool {
		return !(lhs <= rhs);
	}
}

/// ===========================================================================
///  Implementation of default std::hash template specialization.
/// ===========================================================================

namespace std {
	template<typename T, typename S, size_t StateBits>
	struct hash<putl::state_ptr<T, S, StateBits>> {
	public:
		size_t operator()(const putl::state_ptr<T, S> &p) const
		{
			return std::hash<typename putl::state_ptr<T, S>::internal_type>()(p.m_ptr_and_state);
		}
	};
}

#endif // POINTER_UTILS_STATE_PTR_HPP
<|endoftext|>


<commit_before><commit_msg>janitorial: readability<commit_after><|endoftext|>


<commit_before>#ifndef LIBTEN_HTTP_CLIENT_HH
#define LIBTEN_HTTP_CLIENT_HH

#include "ten/http/http_message.hh"
#include "ten/shared_pool.hh"
#include "ten/buffer.hh"
#include "ten/net.hh"
#include "ten/uri.hh"
#include <boost/algorithm/string/compare.hpp>

namespace ten {

//! thrown on http network errors
class http_error : public errorx {
public:
    http_error(const std::string &msg) : errorx(msg) {}
};

//! basic http client
class http_client {
private:
    netsock _sock;
    buffer _buf;
    std::string _host;
    uint16_t _port;

    void ensure_connection() {
        if (!_sock.valid()) {
            _sock = std::move(netsock(AF_INET, SOCK_STREAM));
            if (_sock.dial(_host.c_str(), _port) != 0) {
                throw http_error("dial");
            }
        }
    }

public:
    size_t max_content_length;

    http_client(const std::string &host_, uint16_t port_=80)
        : _buf(4*1024), _host(host_), _port(port_), max_content_length(~(size_t)0)
    {
        parse_host_port(_host, _port);
    }

    std::string host() const { return _host; }
    uint16_t port() const { return _port; }

    http_response perform(const std::string &method, const std::string &path,
                          const http_headers &hdrs = {}, const std::string &data = {},
                          std::chrono::milliseconds timeout = {})
    {
        uri u;
        u.scheme = "http";
        u.host = _host;
        u.port = _port;
        u.path = path;
        u.normalize();

        http_request r(method, u.compose_path(), hdrs);
        // HTTP/1.1 requires host header
        if (r.find("Host") == r.headers.end())
            r.set("Host", u.host);
        r.body = data;

        return perform(r, timeout);
    }

    http_response perform(http_request &r, std::chrono::milliseconds timeout = {}) {
        if (r.body.size()) {
            r.set("Content-Length", r.body.size());
        }

        // should really set a time in the future and calculate this each time
        unsigned ms = boost::numeric_cast<unsigned>(timeout.count());

        try {
            ensure_connection();

            http_response resp(&r);

            std::string hdata = r.data();
            ssize_t nw = _sock.send(hdata.c_str(), hdata.size(), 0, ms);
            bool badw = (size_t)nw != hdata.size();
            if (!badw && r.body.size()) {
                nw = _sock.send(r.body.c_str(), r.body.size(), 0, ms);
                badw = (size_t)nw != r.body.size();
            }
            if (badw) {
                _sock.close(); // socket is unusable after write failure
                resp.status_code = 499;
                resp.set_body("Short write");
                return resp;
            }

            http_parser parser;
            resp.parser_init(&parser);

            _buf.clear();

            while (!resp.complete) {
                _buf.reserve(4*1024);
                ssize_t nr = _sock.recv(_buf.back(), _buf.available(), 0, ms);
                if (nr <= 0) { throw http_error("recv"); }
                _buf.commit(nr);
                size_t len = _buf.size();
                resp.parse(&parser, _buf.front(), len);
                _buf.remove(len);
                if (resp.body.size() >= max_content_length) {
                    _sock.close(); // close this socket, we won't read anymore
                    return resp;
                }
            }
            // should not be any data left over in _buf
            CHECK(_buf.size() == 0);

            const auto conn = resp.get("Connection");
            if (boost::iequals(conn, "close")
                || (resp.http_version == http_1_0 && !boost::iequals(conn, "Keep-Alive")))
            {
                _sock.close();
            }
            return resp;
        } catch (errorx &e) {
            _sock.close();
            throw;
        }
    }

    http_response get(const std::string &path, std::chrono::milliseconds timeout = {}) {
        return perform("GET", path, {}, {}, timeout);
    }

    http_response post(const std::string &path, const std::string &data, std::chrono::milliseconds timeout = {}) {
        return perform("POST", path, {}, data, timeout);
    }

};

class http_pool : public shared_pool<http_client> {
public:
    http_pool(const std::string &host_, uint16_t port_, ssize_t max_conn)
        : shared_pool<http_client>("http://" + host_ + ":" + std::to_string(port_),
            std::bind(&http_pool::new_resource, this),
            max_conn
        ),
        _host(host_), _port(port_) {}

protected:
    std::string _host;
    uint16_t _port;

    std::shared_ptr<http_client> new_resource() {
        VLOG(3) << "new http_client resource " << _host << ":" << _port;
        return std::make_shared<http_client>(_host, _port);
    }
};

} // end namespace ten

#endif // LIBTEN_HTTP_CLIENT_HH
<commit_msg>log http_client activity<commit_after>#ifndef LIBTEN_HTTP_CLIENT_HH
#define LIBTEN_HTTP_CLIENT_HH

#include "ten/http/http_message.hh"
#include "ten/shared_pool.hh"
#include "ten/buffer.hh"
#include "ten/net.hh"
#include "ten/uri.hh"
#include <boost/algorithm/string/compare.hpp>

namespace ten {

//! thrown on http network errors
class http_error : public errorx {
public:
    http_error(const std::string &msg) : errorx(msg) {}
};

//! basic http client
class http_client {
private:
    netsock _sock;
    buffer _buf;
    std::string _host;
    uint16_t _port;

    void ensure_connection() {
        if (!_sock.valid()) {
            _sock = std::move(netsock(AF_INET, SOCK_STREAM));
            if (_sock.dial(_host.c_str(), _port) != 0) {
                throw http_error("dial");
            }
        }
    }

public:
    size_t max_content_length;

    http_client(const std::string &host_, uint16_t port_=80)
        : _buf(4*1024), _host(host_), _port(port_), max_content_length(~(size_t)0)
    {
        parse_host_port(_host, _port);
    }

    std::string host() const { return _host; }
    uint16_t port() const { return _port; }

    http_response perform(const std::string &method, const std::string &path,
                          const http_headers &hdrs = {}, const std::string &data = {},
                          std::chrono::milliseconds timeout = {})
    {
        uri u;
        u.scheme = "http";
        u.host = _host;
        u.port = _port;
        u.path = path;
        u.normalize();

        http_request r(method, u.compose_path(), hdrs);
        // HTTP/1.1 requires host header
        if (r.find("Host") == r.headers.end())
            r.set("Host", u.host);
        r.body = data;

        return perform(r, timeout);
    }

    http_response perform(http_request &r, std::chrono::milliseconds timeout = {}) {
        VLOG(4) << "-> " << r.method << " " << _host << ":" << _port << " " << r.uri;

        if (r.body.size()) {
            r.set("Content-Length", r.body.size());
        }

        // should really set a time in the future and calculate this each time
        unsigned ms = boost::numeric_cast<unsigned>(timeout.count());

        try {
            ensure_connection();

            http_response resp(&r);

            std::string hdata = r.data();
            ssize_t nw = _sock.send(hdata.c_str(), hdata.size(), 0, ms);
            bool badw = (size_t)nw != hdata.size();
            if (!badw && r.body.size()) {
                nw = _sock.send(r.body.c_str(), r.body.size(), 0, ms);
                badw = (size_t)nw != r.body.size();
            }
            if (badw) {
                _sock.close(); // socket is unusable after write failure
                resp.status_code = 499;
                resp.set_body("Short write");
                return resp;
            }

            http_parser parser;
            resp.parser_init(&parser);

            _buf.clear();

            while (!resp.complete) {
                _buf.reserve(4*1024);
                ssize_t nr = _sock.recv(_buf.back(), _buf.available(), 0, ms);
                if (nr <= 0) { throw http_error("recv"); }
                _buf.commit(nr);
                size_t len = _buf.size();
                resp.parse(&parser, _buf.front(), len);
                _buf.remove(len);
                if (resp.body.size() >= max_content_length) {
                    _sock.close(); // close this socket, we won't read anymore
                    return resp;
                }
            }
            // should not be any data left over in _buf
            CHECK(_buf.size() == 0);

            const auto conn = resp.get("Connection");
            if (boost::iequals(conn, "close")
                || (resp.http_version == http_1_0 && !boost::iequals(conn, "Keep-Alive")))
            {
                _sock.close();
            }

            VLOG(4) << "<- " << resp.status_code << " [" << resp.body.size() << "]";
            return resp;
        } catch (errorx &e) {
            _sock.close();
            throw;
        }
    }

    http_response get(const std::string &path, std::chrono::milliseconds timeout = {}) {
        return perform("GET", path, {}, {}, timeout);
    }

    http_response post(const std::string &path, const std::string &data, std::chrono::milliseconds timeout = {}) {
        return perform("POST", path, {}, data, timeout);
    }

};

class http_pool : public shared_pool<http_client> {
public:
    http_pool(const std::string &host_, uint16_t port_, ssize_t max_conn)
        : shared_pool<http_client>("http://" + host_ + ":" + std::to_string(port_),
            std::bind(&http_pool::new_resource, this),
            max_conn
        ),
        _host(host_), _port(port_) {}

protected:
    std::string _host;
    uint16_t _port;

    std::shared_ptr<http_client> new_resource() {
        VLOG(3) << "new http_client resource " << _host << ":" << _port;
        return std::make_shared<http_client>(_host, _port);
    }
};

} // end namespace ten

#endif // LIBTEN_HTTP_CLIENT_HH
<|endoftext|>


<commit_before>#ifndef COFFEE_MILL_DCD_READER
#define COFFEE_MILL_DCD_READER
#include <memory>
#include <utility>
#include "DCDDef.hpp"

namespace coffeemill
{
    /*@brief > this class reads dcd file and contain information and       *
     *         array of snapshots of the trajectory.                       *
     *         You can get the vector and information separately and also  *
     *             can use this as wrapped std::vector<SnapShot>.          */
    class DCDReader
    {
        public:
            using iterator = std::vector<SnapShot>::iterator;
            using const_iterator = std::vector<SnapShot>::const_iterator;

        public:
            DCDReader(){}
            DCDReader(const std::string& fname)
            : filename(fname)
            {}

            DCDReader(const DCDReader& reader)            = delete;
            DCDReader(DCDReader&& reader)                 = delete;
            DCDReader& operator=(const DCDReader& reader) = delete;

            ~DCDReader() = default;

            void read_file();
            void read_file(const std::string& fname);

            int get_nset()       const {return nset;}
            int get_istart()     const {return istart;}
            int get_nstep_save() const {return nstep_save;}
            int get_nstep()      const {return nstep;}
            int get_nunit()      const {return nunit;}
            int get_npart()      const {return nparticle;}
            double get_delta_t() const {return delta_t;}

            std::pair<SnapShot, double> get_snapshot(const std::size_t i) const
            {
                return std::make_pair(data.at(i), delta_t * i);
            }

            bool is_file_specified()          const {return filename.empty();}
            bool is_open()                    const {return dcdfile.is_open();}
            bool empty()                      const {return data.empty();}
            std::size_t size()                const {return data.size();}
            SnapShot  at(const std::size_t i) const {return data.at(i);}
            SnapShot& at(const std::size_t i)       {return data.at(i);}
            SnapShot  operator[](const std::size_t i) const {return data[i];}
            SnapShot& operator[](const std::size_t i)       {return data[i];}
            iterator begin(){return data.begin();}
            iterator end(){return data.end();}
            const_iterator cbegin() const {return data.cbegin();}
            const_iterator cend() const {return data.cend();}

            std::vector<SnapShot>& get_all_data(){return data;}

        private:

            void read_header();
            void read_core();
            void read_head_block1();
            void read_head_block2();
            void read_head_block3();
            std::vector<double> read_coord();

        private:

            // These values are coded in files, not calculated value
            int nset;       // number of frame(a.k.a. SnapShot)
            int istart;     // initial value of isteps (nomally zero)
            int nstep_save; // nstep_save timesteps per one snapshot
            int nstep;      // total step number of the simulation
            int nunit;      // total unit number (chains??)
            int verCHARMM;  // version of CHARMM (usually unused)
            int nparticle;  // total number of particle
            double delta_t;

            std::string filename;
            std::ifstream dcdfile;
            std::vector<std::string> header; // comments in header block 2
            std::vector<SnapShot> data;      // trajectory data

        private:

            //XXX: size_value depends on the environment that the simulation
            //     runs, not on the environment where you analysis the dcd file.
            //     so these size value perhaps differ from the true value.
            static constexpr std::size_t size_int = sizeof(int);
            static constexpr std::size_t size_float = sizeof(float);
            static constexpr std::size_t size_char = sizeof(char);
    };
    typedef std::shared_ptr<DCDReader> DCDReaderSptr;

    void DCDReader::read_file(const std::string& fname)
    {
        if(filename.empty())
        {
            filename = fname;
        }
        else
        {
            std::cout << "Warning: DCDReader: you already specify filename. "
                      << filename << " but now you are trying to open "
                      << fname << ", so now open " << fname
                      << std::endl;
            filename = fname;
        }
        read_file();
        return;
    }

    void DCDReader::read_file()
    {
        if(filename.empty())
        {
            throw std::invalid_argument("filename is not specified!");
        }
        else if(!dcdfile.is_open())
        {
            dcdfile.open(filename, std::ios::binary);
            if(dcdfile.fail())
            {
                throw std::invalid_argument("file open error: " + filename);
            }
        }
        else
        {
            throw std::logic_error(
                    "filename is not specified but file is open!?");
        }
        read_header();
        read_core();
        dcdfile.close();
        std::cout << "Info   : dcd file(" << filename
                  <<  ") reading completed" << std::endl;
        return;
    }

    // necessary?
    void DCDReader::read_header()
    {
        read_head_block1();
        read_head_block2();
        read_head_block3();
        return;
    }

    void DCDReader::read_head_block1()
    {
        char *cbytes = new char[size_int];
        dcdfile.read(cbytes, size_int);
        int byte = *reinterpret_cast<int*>(cbytes);
        if(byte != 84)
        {
            std::cout << "Warning: this file may not be cafemol output."
                      << std::endl;
            std::cout << "       : header block 1 : " << byte << "bytes"
                      << std::endl;
        }
        delete [] cbytes;

        char *ccord = new char [5];
        dcdfile.read(ccord, 4);
        ccord[4] = '\0';
        std::string cord(ccord);
        delete [] ccord;

        if(cord == "CORD")
        {
            std::cout << "Info   : file signature is CORD. normal dcd file."
                      << std::endl;
        }
        else if(cord == "VELD")
        {
            std::cout << "Info   : file signature is VELD. normal vdcd file."
                      << std::endl;
        }
        else
        {
            std::cout << "Error  : unknown signature : " << cord << std::endl;
            throw std::invalid_argument("Unknown File");
        }

        char *cnset = new char[size_int];
        dcdfile.read(cnset, size_int);
        nset = *reinterpret_cast<int*>(cnset);
        delete [] cnset;

        std::cout << "Info   : nset = " << nset << std::endl;

        char *cistart = new char[size_int];
        dcdfile.read(cistart, size_int);
        istart = *reinterpret_cast<int*>(cistart);
        delete [] cistart;

        std::cout << "Info   : istart = " << istart << std::endl;

        char *cnstep_save = new char[size_int];
        dcdfile.read(cnstep_save, size_int);
        nstep_save = *reinterpret_cast<int*>(cnstep_save);
        delete [] cnstep_save;

        std::cout << "Info   : nstep_save = " << nstep_save << std::endl;

        char *cnstep = new char[size_int];
        dcdfile.read(cnstep, size_int);
        nstep = *reinterpret_cast<int*>(cnstep);
        delete [] cnstep;

        std::cout << "Info   : nstep = " << nstep << std::endl;

        char *cnunit = new char[size_int];
        dcdfile.read(cnunit, size_int);
        nunit = *reinterpret_cast<int*>(cnunit);
        delete [] cnunit;

        std::cout << "Info   : nunit = " << nunit << std::endl;

        char *null_1 = new char[16];
        dcdfile.read(null_1, 16);
        delete [] null_1;

        char *cdelta = new char[size_float];
        dcdfile.read(cdelta, size_float);
        delta_t = static_cast<double>(*reinterpret_cast<float*>(cdelta));
        delete [] cdelta;

        std::cout << "Info   : delta t = " << delta_t << std::endl;

        char *null_2 = new char[36];
        dcdfile.read(null_2, 36);
        delete [] null_2;

        char *cverCHARMM = new char[size_int];
        dcdfile.read(cverCHARMM, size_int);
        verCHARMM = *reinterpret_cast<int*>(cverCHARMM);
        delete [] cverCHARMM;

        char *cbytes_f = new char[size_int];
        dcdfile.read(cbytes_f, size_int);
        if(byte != *reinterpret_cast<int*>(cbytes_f))
        {
            throw std::invalid_argument(
                    "header block1 has invalid size information");
        }
        delete [] cbytes_f;

        return;
    }

    void DCDReader::read_head_block2()
    {
        char *cbytes = new char[size_int];
        dcdfile.read(cbytes, size_int);
        int bytes = *reinterpret_cast<int*>(cbytes);
        delete [] cbytes;

        char *clines = new char[size_int];
        dcdfile.read(clines, size_int);
        int lines = *reinterpret_cast<int*>(clines);
        delete [] clines;

        if((80 * lines + 4) != bytes)
        {
            std::cout << "Error  : header block2 size = "
                      << bytes << " bytes."
                      << " But block2 has " << lines
                      << "lines" << std::endl;
            throw std::invalid_argument("header block2 has invalid size");
        }

        std::cout << "Info   : dcd file header begin" << std::endl;
        for(int i(0); i<lines; ++i)
        {
            char *line = new char[81];
            dcdfile.read(line, 80);
            line[80] = '\0';
            std::cout << line << std::endl;
            header.push_back(std::string(line));
            delete [] line;
        }
        std::cout << "Info   : header end" << std::endl;

        char *cbytes_f = new char[size_int];
        dcdfile.read(cbytes_f, size_int);
        if(bytes != *reinterpret_cast<int*>(cbytes_f))
        {
            throw std::invalid_argument(
                    "header block2 has invalid size information");
        }
        delete [] cbytes_f;
    }

    void DCDReader::read_head_block3()
    {
        char *cbytes = new char[size_int];
        dcdfile.read(cbytes, size_int);
        int bytes = *reinterpret_cast<int*>(cbytes);
        delete [] cbytes;

        char *cnpart = new char[size_int];
        dcdfile.read(cnpart, size_int);
        nparticle = *reinterpret_cast<int*>(cnpart);
        delete [] cnpart;

        std::cout << "Info   : there are " << nparticle
                  << " particles in this file" << std::endl;

        char *cbytes_f = new char[size_int];
        dcdfile.read(cbytes_f, size_int);
        if(bytes != *reinterpret_cast<int*>(cbytes_f))
        {
            throw std::invalid_argument(
                    "header block3 has invalid size information");
        }
        delete [] cbytes_f;
        return;
    }

    //read all of the coordinate blocks of the trajectory coded in the file
    void DCDReader::read_core()
    {
        data.reserve(nset);

        for(int i(0); i<=nset; ++i)
        {
            std::vector<double> x(read_coord());
            std::vector<double> y(read_coord());
            std::vector<double> z(read_coord());
            if(static_cast<std::size_t>(nparticle) != x.size() ||
               static_cast<std::size_t>(nparticle) != y.size() ||
               static_cast<std::size_t>(nparticle) != z.size())
            {
                std::cout << "Warning: number of values of coordinate differs"
                          << " from nparticle" << std::endl;
                throw std::invalid_argument("error in reading property");
            }

            SnapShot temp_snapshot(nparticle);
            for(int c(0); c < nparticle; ++c)
            {
                temp_snapshot[c] = Realvec(x[c], y[c], z[c]);
            }
            data.push_back(temp_snapshot);
        }

        return;
    }

    std::vector<double> DCDReader::read_coord()
    {
        char *cbytes = new char[size_int];
        dcdfile.read(cbytes, size_int);
        int bytes(*reinterpret_cast<int*>(cbytes));
        if(bytes / size_float != nparticle)
        {
            std::cout << "Error  : "
                      << "dcd file coordinate has "
                      << bytes << " bytes but nparticle is"
                      << nparticle << ", and sizeof float is "
                      << size_float << std::endl;
            throw std::invalid_argument(
                    "dcd: coordinate block has invalid byte-information");
        }
        delete [] cbytes;

        std::vector<double> coordinate(nparticle);
        for(int i(0); i<nparticle; ++i)
        {
            char *cfloat = new char[size_float];
            dcdfile.read(cfloat, size_float);
            coordinate[i] =
                static_cast<double>(*reinterpret_cast<float*>(cfloat));
            delete [] cfloat;
        }

        char *cbytes_f = new char[size_int];
        dcdfile.read(cbytes_f, size_int);
        if(bytes != *reinterpret_cast<int*>(cbytes_f))
        {
            std::cout << "Error  : "
                      << "dcd file coordinate header-byte-information "
                      << "is not same as footer-byte-information" <<std::endl;
            throw std::invalid_argument(
                    "dcd coordinate block has invalid byte-information");
        }
        delete [] cbytes_f;

        return coordinate;
    }

}//end namespace coffeemill

#endif //COFFEE_MILL_DCD_READER
<commit_msg>fix: DCDReader reading flames<commit_after>#ifndef COFFEE_MILL_DCD_READER
#define COFFEE_MILL_DCD_READER
#include <memory>
#include <utility>
#include "DCDDef.hpp"

namespace coffeemill
{
    /*@brief > this class reads dcd file and contain information and       *
     *         array of snapshots of the trajectory.                       *
     *         You can get the vector and information separately and also  *
     *             can use this as wrapped std::vector<SnapShot>.          */
    class DCDReader
    {
        public:
            using iterator = std::vector<SnapShot>::iterator;
            using const_iterator = std::vector<SnapShot>::const_iterator;

        public:
            DCDReader(){}
            DCDReader(const std::string& fname)
            : filename(fname)
            {}

            DCDReader(const DCDReader& reader)            = delete;
            DCDReader(DCDReader&& reader)                 = delete;
            DCDReader& operator=(const DCDReader& reader) = delete;

            ~DCDReader() = default;

            void read_file();
            void read_file(const std::string& fname);

            int get_nset()       const {return nset;}
            int get_istart()     const {return istart;}
            int get_nstep_save() const {return nstep_save;}
            int get_nstep()      const {return nstep;}
            int get_nunit()      const {return nunit;}
            int get_npart()      const {return nparticle;}
            double get_delta_t() const {return delta_t;}

            std::pair<SnapShot, double> get_snapshot(const std::size_t i) const
            {
                return std::make_pair(data.at(i), delta_t * i);
            }

            bool is_file_specified()          const {return filename.empty();}
            bool is_open()                    const {return dcdfile.is_open();}
            bool empty()                      const {return data.empty();}
            std::size_t size()                const {return data.size();}
            SnapShot  at(const std::size_t i) const {return data.at(i);}
            SnapShot& at(const std::size_t i)       {return data.at(i);}
            SnapShot  operator[](const std::size_t i) const {return data[i];}
            SnapShot& operator[](const std::size_t i)       {return data[i];}
            iterator begin(){return data.begin();}
            iterator end(){return data.end();}
            const_iterator cbegin() const {return data.cbegin();}
            const_iterator cend() const {return data.cend();}

            std::vector<SnapShot>& get_all_data(){return data;}

        private:

            void read_header();
            void read_core();
            void read_head_block1();
            void read_head_block2();
            void read_head_block3();
            std::vector<double> read_coord();

        private:

            // These values are coded in files, not calculated value
            int nset;       // number of frame(a.k.a. SnapShot)
            int istart;     // initial value of isteps (nomally zero)
            int nstep_save; // nstep_save timesteps per one snapshot
            int nstep;      // total step number of the simulation
            int nunit;      // total unit number (chains??)
            int verCHARMM;  // version of CHARMM (usually unused)
            int nparticle;  // total number of particle
            double delta_t;

            std::string filename;
            std::ifstream dcdfile;
            std::vector<std::string> header; // comments in header block 2
            std::vector<SnapShot> data;      // trajectory data

        private:

            //XXX: size_value depends on the environment that the simulation
            //     runs, not on the environment where you analysis the dcd file.
            //     so these size value perhaps differ from the true value.
            static constexpr std::size_t size_int = sizeof(int);
            static constexpr std::size_t size_float = sizeof(float);
            static constexpr std::size_t size_char = sizeof(char);
    };
    typedef std::shared_ptr<DCDReader> DCDReaderSptr;

    void DCDReader::read_file(const std::string& fname)
    {
        if(filename.empty())
        {
            filename = fname;
        }
        else
        {
            std::cout << "Warning: DCDReader: you already specify filename. "
                      << filename << " but now you are trying to open "
                      << fname << ", so now open " << fname
                      << std::endl;
            filename = fname;
        }
        read_file();
        return;
    }

    void DCDReader::read_file()
    {
        if(filename.empty())
        {
            throw std::invalid_argument("filename is not specified!");
        }
        else if(!dcdfile.is_open())
        {
            dcdfile.open(filename, std::ios::binary);
            if(dcdfile.fail())
            {
                throw std::invalid_argument("file open error: " + filename);
            }
        }
        else
        {
            throw std::logic_error(
                    "filename is not specified but file is open!?");
        }
        read_header();
        read_core();
        dcdfile.close();
        std::cout << "Info   : dcd file(" << filename
                  <<  ") reading completed" << std::endl;
        return;
    }

    // necessary?
    void DCDReader::read_header()
    {
        read_head_block1();
        read_head_block2();
        read_head_block3();
        return;
    }

    void DCDReader::read_head_block1()
    {
        char *cbytes = new char[size_int];
        dcdfile.read(cbytes, size_int);
        int byte = *reinterpret_cast<int*>(cbytes);
        if(byte != 84)
        {
            std::cout << "Warning: this file may not be cafemol output."
                      << std::endl;
            std::cout << "       : header block 1 : " << byte << "bytes"
                      << std::endl;
        }
        delete [] cbytes;

        char *ccord = new char [5];
        dcdfile.read(ccord, 4);
        ccord[4] = '\0';
        std::string cord(ccord);
        delete [] ccord;

        if(cord == "CORD")
        {
            std::cout << "Info   : file signature is CORD. normal dcd file."
                      << std::endl;
        }
        else if(cord == "VELD")
        {
            std::cout << "Info   : file signature is VELD. normal vdcd file."
                      << std::endl;
        }
        else
        {
            std::cout << "Error  : unknown signature : " << cord << std::endl;
            throw std::invalid_argument("Unknown File");
        }

        char *cnset = new char[size_int];
        dcdfile.read(cnset, size_int);
        nset = *reinterpret_cast<int*>(cnset);
        delete [] cnset;

        std::cout << "Info   : nset = " << nset << std::endl;

        char *cistart = new char[size_int];
        dcdfile.read(cistart, size_int);
        istart = *reinterpret_cast<int*>(cistart);
        delete [] cistart;

        std::cout << "Info   : istart = " << istart << std::endl;

        char *cnstep_save = new char[size_int];
        dcdfile.read(cnstep_save, size_int);
        nstep_save = *reinterpret_cast<int*>(cnstep_save);
        delete [] cnstep_save;

        std::cout << "Info   : nstep_save = " << nstep_save << std::endl;

        char *cnstep = new char[size_int];
        dcdfile.read(cnstep, size_int);
        nstep = *reinterpret_cast<int*>(cnstep);
        delete [] cnstep;

        std::cout << "Info   : nstep = " << nstep << std::endl;

        char *cnunit = new char[size_int];
        dcdfile.read(cnunit, size_int);
        nunit = *reinterpret_cast<int*>(cnunit);
        delete [] cnunit;

        std::cout << "Info   : nunit = " << nunit << std::endl;

        char *null_1 = new char[16];
        dcdfile.read(null_1, 16);
        delete [] null_1;

        char *cdelta = new char[size_float];
        dcdfile.read(cdelta, size_float);
        delta_t = static_cast<double>(*reinterpret_cast<float*>(cdelta));
        delete [] cdelta;

        std::cout << "Info   : delta t = " << delta_t << std::endl;

        char *null_2 = new char[36];
        dcdfile.read(null_2, 36);
        delete [] null_2;

        char *cverCHARMM = new char[size_int];
        dcdfile.read(cverCHARMM, size_int);
        verCHARMM = *reinterpret_cast<int*>(cverCHARMM);
        delete [] cverCHARMM;

        char *cbytes_f = new char[size_int];
        dcdfile.read(cbytes_f, size_int);
        if(byte != *reinterpret_cast<int*>(cbytes_f))
        {
            throw std::invalid_argument(
                    "header block1 has invalid size information");
        }
        delete [] cbytes_f;

        return;
    }

    void DCDReader::read_head_block2()
    {
        char *cbytes = new char[size_int];
        dcdfile.read(cbytes, size_int);
        int bytes = *reinterpret_cast<int*>(cbytes);
        delete [] cbytes;

        char *clines = new char[size_int];
        dcdfile.read(clines, size_int);
        int lines = *reinterpret_cast<int*>(clines);
        delete [] clines;

        if((80 * lines + 4) != bytes)
        {
            std::cout << "Error  : header block2 size = "
                      << bytes << " bytes."
                      << " But block2 has " << lines
                      << "lines" << std::endl;
            throw std::invalid_argument("header block2 has invalid size");
        }

        std::cout << "Info   : dcd file header begin" << std::endl;
        for(int i(0); i<lines; ++i)
        {
            char *line = new char[81];
            dcdfile.read(line, 80);
            line[80] = '\0';
            std::cout << line << std::endl;
            header.push_back(std::string(line));
            delete [] line;
        }
        std::cout << "Info   : header end" << std::endl;

        char *cbytes_f = new char[size_int];
        dcdfile.read(cbytes_f, size_int);
        if(bytes != *reinterpret_cast<int*>(cbytes_f))
        {
            throw std::invalid_argument(
                    "header block2 has invalid size information");
        }
        delete [] cbytes_f;
    }

    void DCDReader::read_head_block3()
    {
        char *cbytes = new char[size_int];
        dcdfile.read(cbytes, size_int);
        int bytes = *reinterpret_cast<int*>(cbytes);
        delete [] cbytes;

        char *cnpart = new char[size_int];
        dcdfile.read(cnpart, size_int);
        nparticle = *reinterpret_cast<int*>(cnpart);
        delete [] cnpart;

        std::cout << "Info   : there are " << nparticle
                  << " particles in this file" << std::endl;

        char *cbytes_f = new char[size_int];
        dcdfile.read(cbytes_f, size_int);
        if(bytes != *reinterpret_cast<int*>(cbytes_f))
        {
            throw std::invalid_argument(
                    "header block3 has invalid size information");
        }
        delete [] cbytes_f;
        return;
    }

    //read all of the coordinate blocks of the trajectory coded in the file
    void DCDReader::read_core()
    {
        data.reserve(nset);

        for(int i(0); i<nset; ++i)
        {
            std::vector<double> x(read_coord());
            std::vector<double> y(read_coord());
            std::vector<double> z(read_coord());
            if(static_cast<std::size_t>(nparticle) != x.size() ||
               static_cast<std::size_t>(nparticle) != y.size() ||
               static_cast<std::size_t>(nparticle) != z.size())
            {
                std::cout << "Warning: number of values of coordinate differs"
                          << " from nparticle" << std::endl;
                throw std::invalid_argument("error in reading property");
            }

            SnapShot temp_snapshot(nparticle);
            for(int c(0); c < nparticle; ++c)
            {
                temp_snapshot[c] = Realvec(x[c], y[c], z[c]);
            }
            data.push_back(temp_snapshot);
        }

        return;
    }

    std::vector<double> DCDReader::read_coord()
    {
        char *cbytes = new char[size_int];
        dcdfile.read(cbytes, size_int);
        int bytes(*reinterpret_cast<int*>(cbytes));
        if(bytes / size_float != nparticle)
        {
            std::cout << "Error  : "
                      << "dcd file coordinate has "
                      << bytes << " bytes but nparticle is"
                      << nparticle << ", and sizeof float is "
                      << size_float << std::endl;
            throw std::invalid_argument(
                    "dcd: coordinate block has invalid byte-information");
        }
        delete [] cbytes;

        std::vector<double> coordinate(nparticle);
        for(int i(0); i<nparticle; ++i)
        {
            char *cfloat = new char[size_float];
            dcdfile.read(cfloat, size_float);
            coordinate[i] =
                static_cast<double>(*reinterpret_cast<float*>(cfloat));
            delete [] cfloat;
        }

        char *cbytes_f = new char[size_int];
        dcdfile.read(cbytes_f, size_int);
        if(bytes != *reinterpret_cast<int*>(cbytes_f))
        {
            std::cout << "Error  : "
                      << "dcd file coordinate header-byte-information "
                      << "is not same as footer-byte-information" <<std::endl;
            throw std::invalid_argument(
                    "dcd coordinate block has invalid byte-information");
        }
        delete [] cbytes_f;

        return coordinate;
    }

}//end namespace coffeemill

#endif //COFFEE_MILL_DCD_READER
<|endoftext|>


<commit_before>#ifndef COFFEE_MILL_DCD_WRITER
#define COFFEE_MILL_DCD_WRITER
#include <cstring>
#include "DCDDef.hpp"

namespace coffeemill
{
    class DCDWriter
    {
        public:

            DCDWriter():header_written(false), header_set(false){}
            DCDWriter(const std::string& filename_)
                :header_written(false), header_set(false),
                 dcdfile(filename_, std::ios::out|std::ios::binary),
                 filename(filename_)
            {
                if(dcdfile.fail())
                    throw std::invalid_argument("file open error");
            }
            ~DCDWriter()
            {
                dcdfile.close();
            }

            void write_file();
            void write_file(const std::string& filename);

            void write_header();
            void write_SnapShot(SnapShot& snapshot);

            void set_nset(int nset_){nset = nset_;}
            void set_istart(int istart_){istart = istart_;}
            void set_nstep_save(int nsave_){nstep_save = nsave_;}
            void set_nstep(int nstep_){nstep = nstep_;}
            void set_nunit(int nunit_){nunit = nunit_;}
            void set_npart(int npart_){nparticle = npart_;}
            void set_delta_t(double dt){delta_t = dt;}
            void set_header(const std::vector<std::string>& h);

            SnapShot& at(int i){return data.at(i);}

            void set_all_data(const std::vector<SnapShot>& data_)
            {data = data_;}

        private:

            void write_core();
            void write_head_block1();
            void write_head_block2();
            void write_head_block3();
            void write_user_set_header();
            void write_coord(std::vector<double>& coord);

        private:

            bool header_written;
            bool header_set;
            int nset;// number of frame
            int istart;// initial value of isteps
            int nstep_save;// saving frequency
            int nstep;// total step number
            int nunit;// total unit number
            int verCHARMM;
            int nparticle;// total number of particle
            double delta_t;
            std::vector<SnapShot> data;
            std::ofstream dcdfile;
            std::string filename;
            std::vector<std::string> header;

        private:

            static constexpr int size_int = sizeof(int);
            static constexpr int size_float = sizeof(float);
            static constexpr int size_char = sizeof(char);
    };

    void DCDWriter::write_file(const std::string& filename_)
    {
        if(dcdfile.is_open())
        {
            std::cout << "Warning: DCDWriter already open a dcd file: "
                      << filename
                      << std::endl;
        }
        else
        {
            dcdfile.open(filename_, std::ios::out|std::ios::binary);
            if(dcdfile.fail())
                throw std::invalid_argument("file open error");
        }
        write_file();
        return;
    }

    void DCDWriter::write_file()
    {
        if(dcdfile.fail())
            throw std::invalid_argument("file open error");
        if(header_written)
            throw std::invalid_argument("file is partially written");
        write_header();
        write_core();
        std::cout << "Info   : write_file completed" << std::endl;
        return;
    }

    void DCDWriter::write_SnapShot(SnapShot& snapshot)
    {
        if(!header_written)
            throw std::invalid_argument("write DCD file without header");

        std::vector<double> x((snapshot).size());
        std::vector<double> y((snapshot).size());
        std::vector<double> z((snapshot).size());
        int counter(0);
        for(SnapShot::iterator ssiter = (snapshot).begin();
            ssiter != (snapshot).end(); ++ssiter)
        {
            x.at(counter) = (*ssiter)[0];
            y.at(counter) = (*ssiter)[1];
            z.at(counter) = (*ssiter)[2];
            ++counter;
        }
        write_coord(x);
        write_coord(y);
        write_coord(z);

        return;
    }

    void DCDWriter::set_header(const std::vector<std::string>& h)
    {
        if(!header.empty())
            std::cout << "Warning: trying to set header but header is not empty"
                      << std::endl;
        for(auto iter = h.begin(); iter != h.end(); ++iter)
        {
            if((*iter).size() > 80)
            {
                throw std::invalid_argument("too long header line");
            }
            else if((*iter).size() < 80)
            {
                std::string filler((80 - (*iter).size()), '=');
                header.push_back((*iter) + filler);
            }
            else
            {
                header.push_back(*iter);
            }
        }
        header_set = true;
        return;
    }

    void DCDWriter::write_header()
    {
        write_head_block1();
        if(header_set)
        {
            write_user_set_header();
        }
        else
        {
            write_head_block2();
        }
        write_head_block3();
        header_written = true;
        return;
    }

    void DCDWriter::write_head_block1()
    {
        int wrote(0);
        int bytes(84);
        dcdfile.write(reinterpret_cast<char*>(&bytes), sizeof(int));

        char cord[5] = "CORD";
        dcdfile.write(reinterpret_cast<char*>(&cord), sizeof(char)*4);
        wrote += sizeof(char)*4;

        dcdfile.write(reinterpret_cast<char*>(&nset), sizeof(int));
        wrote += sizeof(int);

        dcdfile.write(reinterpret_cast<char*>(&istart), sizeof(int));
        wrote += sizeof(int);

        dcdfile.write(reinterpret_cast<char*>(&nstep_save), sizeof(int));
        wrote += sizeof(int);

        dcdfile.write(reinterpret_cast<char*>(&nstep), sizeof(int));
        wrote += sizeof(int);

        dcdfile.write(reinterpret_cast<char*>(&nunit), sizeof(int));
        wrote += sizeof(int);

        // null data
        int fill_zero(0);
        for(int i(0); i<4; ++i)
        {
            dcdfile.write(reinterpret_cast<char*>(&fill_zero), sizeof(int));
            wrote += sizeof(int);
        }

        float dt(static_cast<float>(delta_t));
        dcdfile.write(reinterpret_cast<char*>(&dt), sizeof(float));
        wrote += sizeof(float);

        // null data
        for(int i(0); i<9; ++i)
        {
            dcdfile.write(reinterpret_cast<char*>(&fill_zero), sizeof(int));
            wrote += sizeof(int);
        }

        dcdfile.write(reinterpret_cast<char*>(&verCHARMM), sizeof(int));
        wrote += sizeof(int);

        if(wrote != bytes)
        {
            throw std::invalid_argument("byte information error");
        }

        dcdfile.write(reinterpret_cast<char*>(&bytes), sizeof(int));
        return;
    }

    void DCDWriter::write_head_block2()
    {
        int lines(4);
        int bytes(4 + 80*lines);
        int wrote(0);
        dcdfile.write(reinterpret_cast<char*>(&bytes), sizeof(int));

        dcdfile.write(reinterpret_cast<char*>(&lines), sizeof(int));
        wrote += sizeof(int);

        size_t filename_length(filename.size());
        std::string fileinfo;
        if(filename_length > 41)
        {
            fileinfo = "==================== original file is " + filename.substr(0,63);
        }
        else
        {
            fileinfo = "==================== original file is " + filename + ' ';
//             std::cout << "fileinfo size: " << fileinfo.size() << std::endl;
            std::string filler((80 - fileinfo.size()), '=');
            fileinfo = fileinfo + filler;
            if(fileinfo.size() != 80)
            {
                std::cout << "filename: " << filename.size() << std::endl;
                std::cout << "filler size: " << filler.size() << std::endl;
                std::cout << "fileinfo size: " << fileinfo.size() << std::endl;
                throw std::invalid_argument("line size error");
            }
        }

        char line1[81] = "==================== Molecular Dynamics Code : CafeMol ver.  2.01.1485 =========";
        char line2[81] = "==================== Developed by Kyoto University =============================";
        char line3[81] = "==================== This file is modified using coffee-mill ===================";
        char line4[81];
        sprintf(line4, "%s", fileinfo.c_str());

        dcdfile.write(reinterpret_cast<char*>(&line1), sizeof(char)*80);
        wrote += sizeof(char)*80;
        dcdfile.write(reinterpret_cast<char*>(&line2), sizeof(char)*80);
        wrote += sizeof(char)*80;
        dcdfile.write(reinterpret_cast<char*>(&line3), sizeof(char)*80);
        wrote += sizeof(char)*80;
        dcdfile.write(reinterpret_cast<char*>(&line4), sizeof(char)*80);
        wrote += sizeof(char)*80;

        if(wrote != bytes)
            throw std::invalid_argument("byte information error");

        dcdfile.write(reinterpret_cast<char*>(&bytes), sizeof(int));
        return;
    }

    void DCDWriter::write_user_set_header()
    {
        int lines(header.size());
        int bytes(4 + 80*lines);
        int wrote(0);
        dcdfile.write(reinterpret_cast<char*>(&bytes), sizeof(int));

        dcdfile.write(reinterpret_cast<char*>(&lines), sizeof(int));
        wrote += sizeof(int);

        for(auto iter = header.begin(); iter != header.end(); ++iter)
        {
            char* line = new char[81];
            memcpy(line, (*iter).c_str(), 81);
            dcdfile.write(reinterpret_cast<char*>(&line), sizeof(char)*80);
            wrote += sizeof(char)*80;
        }

        if(wrote != bytes)
            throw std::invalid_argument("byte information error");

        dcdfile.write(reinterpret_cast<char*>(&bytes), sizeof(int));
        return;
    }

    void DCDWriter::write_head_block3()
    {
        int bytes(sizeof(int));
        dcdfile.write(reinterpret_cast<char*>(&bytes), sizeof(int));
        dcdfile.write(reinterpret_cast<char*>(&nparticle), sizeof(int));
        dcdfile.write(reinterpret_cast<char*>(&bytes), sizeof(int));
        return;
    }

    void DCDWriter::write_core()
    {
        for(auto iter = data.begin(); iter != data.end(); ++iter)
        {
            write_SnapShot(*iter);
        }
        return;
    }

    void DCDWriter::write_coord(std::vector<double>& coord)
    {
        int size(coord.size());
        int bytes(size * sizeof(float));
        dcdfile.write(reinterpret_cast<char*>(&bytes), sizeof(int));

        for(std::vector<double>::iterator iter = coord.begin();
            iter != coord.end(); ++iter)
        {
            float temp(static_cast<float>(*iter));
            dcdfile.write(reinterpret_cast<char*>(&temp), sizeof(float));
        }

        dcdfile.write(reinterpret_cast<char*>(&bytes), sizeof(int));
        return;
    }

}//end namespace coffeemill

#endif //COFFEE_MILL_DCD_WRITER
<commit_msg>DCDWriter uses size_type<commit_after>#ifndef COFFEE_MILL_DCD_WRITER
#define COFFEE_MILL_DCD_WRITER
#include <cstring>
#include "DCDDef.hpp"

namespace coffeemill
{
    class DCDWriter
    {
        public:

            DCDWriter():header_written(false), header_set(false){}

            DCDWriter(const std::string& filename_)
                :header_written(false), header_set(false),
                 filename(filename_),
                 dcdfile(filename_, std::ios::out|std::ios::binary)
            {
                if(dcdfile.fail())
                    throw std::invalid_argument("file open error");
            }

            ~DCDWriter()
            {
                dcdfile.close();
            }

            void write_file();
            void write_file(const std::string& filename);

            void write_header();
            void write_SnapShot(SnapShot& snapshot);

            void set_nset(int nset_){nset = nset_;}
            void set_istart(int istart_){istart = istart_;}
            void set_nstep_save(int nsave_){nstep_save = nsave_;}
            void set_nstep(int nstep_){nstep = nstep_;}
            void set_nunit(int nunit_){nunit = nunit_;}
            void set_npart(int npart_){nparticle = npart_;}
            void set_delta_t(double dt){delta_t = dt;}
            void set_header(const std::vector<std::string>& h);

            SnapShot& at(int i){return data.at(i);}

            void set_all_data(const std::vector<SnapShot>& data_)
            {data = data_;}

        private:

            void write_core();
            void write_head_block1();
            void write_head_block2();
            void write_head_block3();
            void write_user_set_header();
            void write_coord(std::vector<double>& coord);

        private:

            bool header_written;
            bool header_set;
            int nset;// number of frame
            int istart;// initial value of isteps
            int nstep_save;// saving frequency
            int nstep;// total step number
            int nunit;// total unit number
            int verCHARMM;
            int nparticle;// total number of particle
            double delta_t;
            std::string filename;
            std::ofstream dcdfile;
            std::vector<std::string> header;
            std::vector<SnapShot> data;

        private:

            static constexpr int size_int = sizeof(int);
            static constexpr int size_float = sizeof(float);
            static constexpr int size_char = sizeof(char);
    };

    void DCDWriter::write_file(const std::string& filename_)
    {
        if(dcdfile.is_open())
        {
            std::cout << "Warning: DCDWriter already open a dcd file: "
                      << filename
                      << std::endl;
        }
        else
        {
            dcdfile.open(filename_, std::ios::out|std::ios::binary);
            if(dcdfile.fail())
                throw std::invalid_argument("file open error");
        }
        write_file();
        return;
    }

    void DCDWriter::write_file()
    {
        if(dcdfile.fail())
            throw std::invalid_argument("file open error");
        if(header_written)
            throw std::invalid_argument("file is partially written");
        write_header();
        write_core();
        std::cout << "Info   : write_file completed" << std::endl;
        return;
    }

    void DCDWriter::write_SnapShot(SnapShot& snapshot)
    {
        if(!header_written)
            throw std::invalid_argument("write DCD file without header");

        std::vector<double> x((snapshot).size());
        std::vector<double> y((snapshot).size());
        std::vector<double> z((snapshot).size());
        int counter(0);
        for(auto iter = (snapshot).begin(); iter != (snapshot).end(); ++iter)
        {
            x.at(counter) = (*iter)[0];
            y.at(counter) = (*iter)[1];
            z.at(counter) = (*iter)[2];
            ++counter;
        }
        write_coord(x);
        write_coord(y);
        write_coord(z);

        return;
    }

    void DCDWriter::set_header(const std::vector<std::string>& h)
    {
        if(!header.empty())
            std::cout << "Warning: trying to set header but header is not empty"
                      << std::endl;
        for(auto iter = h.begin(); iter != h.end(); ++iter)
        {
            if((*iter).size() > 80)
            {
                throw std::invalid_argument("too long header line");
            }
            else if((*iter).size() < 80)
            {
                std::string filler((80 - (*iter).size()), '=');
                header.push_back((*iter) + filler);
            }
            else
            {
                header.push_back(*iter);
            }
        }
        header_set = true;
        return;
    }

    void DCDWriter::write_header()
    {
        write_head_block1();
        if(header_set)
        {
            write_user_set_header();
        }
        else
        {
            write_head_block2();
        }
        write_head_block3();
        header_written = true;
        return;
    }

    void DCDWriter::write_head_block1()
    {
        int wrote(0);
        int bytes(84);
        dcdfile.write(reinterpret_cast<char*>(&bytes), size_int);

        char cord[5] = "CORD";
        dcdfile.write(reinterpret_cast<char*>(&cord), size_char*4);
        wrote += size_char*4;

        dcdfile.write(reinterpret_cast<char*>(&nset), size_int);
        wrote += size_int;

        dcdfile.write(reinterpret_cast<char*>(&istart), size_int);
        wrote += size_int;

        dcdfile.write(reinterpret_cast<char*>(&nstep_save), size_int);
        wrote += size_int;

        dcdfile.write(reinterpret_cast<char*>(&nstep), size_int);
        wrote += size_int;

        dcdfile.write(reinterpret_cast<char*>(&nunit), size_int);
        wrote += size_int;

        // null data
        int fill_zero(0);
        for(int i(0); i<4; ++i)
        {
            dcdfile.write(reinterpret_cast<char*>(&fill_zero), size_int);
            wrote += size_int;
        }

        float dt(static_cast<float>(delta_t));
        dcdfile.write(reinterpret_cast<char*>(&dt), size_float);
        wrote += size_float;

        // null data
        for(int i(0); i<9; ++i)
        {
            dcdfile.write(reinterpret_cast<char*>(&fill_zero), size_int);
            wrote += size_int;
        }

        dcdfile.write(reinterpret_cast<char*>(&verCHARMM), size_int);
        wrote += size_int;

        if(wrote != bytes)
        {
            throw std::invalid_argument("byte information error");
        }

        dcdfile.write(reinterpret_cast<char*>(&bytes), size_int);
        return;
    }

    void DCDWriter::write_head_block2()
    {
        int lines(4);
        int bytes(4 + 80*lines);
        int wrote(0);
        dcdfile.write(reinterpret_cast<char*>(&bytes), size_int);

        dcdfile.write(reinterpret_cast<char*>(&lines), size_int);
        wrote += size_int;

        size_t filename_length(filename.size());
        std::string fileinfo;
        if(filename_length > 41)
        {
            fileinfo = "==================== original file is " + filename.substr(0,63);
        }
        else
        {
            fileinfo = "==================== original file is " + filename + ' ';
//             std::cout << "fileinfo size: " << fileinfo.size() << std::endl;
            std::string filler((80 - fileinfo.size()), '=');
            fileinfo = fileinfo + filler;
            if(fileinfo.size() != 80)
            {
                std::cout << "filename: " << filename.size() << std::endl;
                std::cout << "filler size: " << filler.size() << std::endl;
                std::cout << "fileinfo size: " << fileinfo.size() << std::endl;
                throw std::invalid_argument("line size error");
            }
        }

        char line1[81] = "==================== Molecular Dynamics Code : CafeMol ver.  2.01.1485 =========";
        char line2[81] = "==================== Developed by Kyoto University =============================";
        char line3[81] = "==================== This file is modified using coffee-mill ===================";
        char line4[81];
        sprintf(line4, "%s", fileinfo.c_str());

        dcdfile.write(reinterpret_cast<char*>(&line1), size_char*80);
        wrote += size_char*80;
        dcdfile.write(reinterpret_cast<char*>(&line2), size_char*80);
        wrote += size_char*80;
        dcdfile.write(reinterpret_cast<char*>(&line3), size_char*80);
        wrote += size_char*80;
        dcdfile.write(reinterpret_cast<char*>(&line4), size_char*80);
        wrote += size_char*80;

        if(wrote != bytes)
            throw std::invalid_argument("byte information error");

        dcdfile.write(reinterpret_cast<char*>(&bytes), size_int);
        return;
    }

    void DCDWriter::write_user_set_header()
    {
        int lines(header.size());
        int bytes(4 + 80*lines);
        int wrote(0);
        dcdfile.write(reinterpret_cast<char*>(&bytes), size_int);

        dcdfile.write(reinterpret_cast<char*>(&lines), size_int);
        wrote += size_int;

        for(auto iter = header.begin(); iter != header.end(); ++iter)
        {
            char* line = new char[81];
            memcpy(line, (*iter).c_str(), 81);
            dcdfile.write(reinterpret_cast<char*>(&line), size_char*80);
            wrote += size_char*80;
        }

        if(wrote != bytes)
            throw std::invalid_argument("byte information error");

        dcdfile.write(reinterpret_cast<char*>(&bytes), size_int);
        return;
    }

    void DCDWriter::write_head_block3()
    {
        int bytes(size_int);
        dcdfile.write(reinterpret_cast<char*>(&bytes), size_int);
        dcdfile.write(reinterpret_cast<char*>(&nparticle), size_int);
        dcdfile.write(reinterpret_cast<char*>(&bytes), size_int);
        return;
    }

    void DCDWriter::write_core()
    {
        for(auto iter = data.begin(); iter != data.end(); ++iter)
        {
            write_SnapShot(*iter);
        }
        return;
    }

    void DCDWriter::write_coord(std::vector<double>& coord)
    {
        int size(coord.size());
        int bytes(size * size_float);
        dcdfile.write(reinterpret_cast<char*>(&bytes), size_int);

        for(auto iter = coord.begin(); iter != coord.end(); ++iter)
        {
            float temp(static_cast<float>(*iter));
            dcdfile.write(reinterpret_cast<char*>(&temp), size_float);
        }

        dcdfile.write(reinterpret_cast<char*>(&bytes), size_int);
        return;
    }

}//end namespace coffeemill

#endif //COFFEE_MILL_DCD_WRITER
<|endoftext|>