<commit_before>/**
@file IO/Datastore.hpp
@brief Datastore class.

@author Tim Howard
@copyright 2013 Tim Howard under the MIT license;
see @ref index or the accompanying LICENSE file for full text.
*/

#ifndef HORD_IO_DATASTORE_HPP_
#define HORD_IO_DATASTORE_HPP_

#include <Hord/config.hpp>
#include <Hord/traits.hpp>
#include <Hord/String.hpp>
#include <Hord/System/IDGenerator.hpp>
#include <Hord/IO/Defs.hpp>
#include <Hord/IO/Prop.hpp>
#include <Hord/Object/Defs.hpp>

#include <duct/StateStore.hpp>

#include <cassert>
#include <functional>
#include <iosfwd>

namespace Hord {
namespace IO {

// Forward declarations
class Datastore;

/**
	@addtogroup io
	@{
*/
/**
	@addtogroup datastore
	@{
*/

/**
	Base datastore.

	This is the data interface for hives.

	@note %Datastores must be locked when a single prop stream is
	active.
*/
class Datastore {
public:
	/**
		Type info.
	*/
	struct type_info final {
	/** @name Operations */ /// @{
		/**
			Construct a datastore of this type.

			@returns
			- The constructed datastore; or
			- @c nullptr if construction failed.
			@param root_path Root path.
		*/
		Datastore*
		(&construct)(
			String root_path
		) noexcept;
	/// @}
	};

	/**
		Ensure traits for deriving classes.

		@remarks All constructors should be hidden or deleted.

		@tparam D Deriving class.
	*/
	template<
		typename D
	>
	struct ensure_traits :
		traits::require_t<
			D,
			tw::capture_post<std::is_base_of, Datastore>::type,
			std::is_nothrow_destructible
		>,
		traits::disallow_t<
			D,
			std::is_default_constructible,
			tw::capture<std::is_constructible, String>::type,
			tw::is_fully_copyable,
			tw::is_fully_moveable
		>
	{};

protected:
/** @name Implementation */ /// @{
	/**
		open() implementation.

		@throws Error{ErrorCode::datastore_open_failed}
	*/
	virtual void
	open_impl() = 0;

	/**
		close() implementation.

		@remarks This is not called if @c is_open()==false.
	*/
	virtual void
	close_impl() = 0;

	/**
		acquire_input_stream() implementation.

		@throws Error{ErrorCode::datastore_object_not_found}
		@throws Error{ErrorCode::datastore_prop_void}
		@throws Error{ErrorCode::datastore_prop_unsupplied}
		@throws Error{..}
	*/
	virtual std::istream&
	acquire_input_stream_impl(
		IO::PropInfo const& prop_info
	) = 0;

	/**
		acquire_output_stream() implementation.

		@throws Error{ErrorCode::datastore_object_not_found}
		@throws Error{ErrorCode::datastore_prop_void}
		@throws Error{ErrorCode::datastore_prop_unsupplied}
		@throws Error{..}
	*/
	virtual std::ostream&
	acquire_output_stream_impl(
		IO::PropInfo const& prop_info
	) = 0;

	/**
		release_input_stream() implementation.

		@throws Error{ErrorCode::datastore_prop_not_locked}
		@throws Error{ErrorCode::datastore_object_not_found}
		@throws Error{ErrorCode::datastore_prop_unsupplied}
		@throws Error{..}
	*/
	virtual void
	release_input_stream_impl(
		IO::PropInfo const& prop_info
	) = 0;

	/**
		release_output_stream() implementation.

		@throws Error{ErrorCode::datastore_prop_not_locked}
		@throws Error{ErrorCode::datastore_object_not_found}
		@throws Error{ErrorCode::datastore_prop_unsupplied}
		@throws Error{..}
	*/
	virtual void
	release_output_stream_impl(
		IO::PropInfo const& prop_info
	) = 0;

	/**
		generate_id() implementation.

		@remarks The implementation should generate a unique ID
		within the entire ID set of the datastore -- i.e., including
		orphaned objects (such as trash).
	*/
	virtual Object::ID
	generate_id_impl(
		System::IDGenerator& generator
	) const noexcept = 0;

	/**
		create_object() implementation.

		@throws Error{ErrorCode::datastore_object_already_exists}
		@throws Error{..}
	*/
	virtual void
	create_object_impl(
		Object::ID const object_id,
		Object::Type const object_type
	) = 0;

	/**
		destroy_object() implementation.

		@throws Error{ErrorCode::datastore_object_not_found}
		@throws Error{..}
	*/
	virtual void
	destroy_object_impl(
		Object::ID const object_id
	) = 0;
/// @}

/** @name Internal state */ /// @{
	/**
		States.

		Implementations are permitted to define states @c 1<<8
		to @c 1<<31.
	*/
	enum class State : uint32_t {
		/** %Datastore is open. */
		opened = 1 << 0,
		/** %Datastore is locked. */
		locked = 1 << 1,

		/** First reserved state. */
		RESERVED_FIRST = 1 << 2,
		/** Last reserved state. */
		RESERVED_LAST = 1 << 7
	};

/** @cond INTERNAL */
#define HORD_STATE_ASSERT_VALID__(x__)	\
	assert(								\
		State::RESERVED_FIRST > x__ &&	\
		State::RESERVED_LAST  < x__		\
	);
/** @endcond */

	/**
		Enable state.

		@param state %State to enable.
	*/
	/*constexpr*/ void
	enable_state(
		State const state
	) noexcept {
		HORD_STATE_ASSERT_VALID__(state);
		m_states.enable(state);
	}

	/**
		Disable state.

		@param state %State to disable.
	*/
	/*constexpr*/ void
	disable_state(
		State const state
	) noexcept {
		HORD_STATE_ASSERT_VALID__(state);
		m_states.disable(state);
	}

	/**
		Enable or disable state.

		@param state %State to enable or disable.
		@param enable Whether to enable or disable the state.
	*/
	/*constexpr*/ void
	set_state(
		State const state,
		bool const enable
	) noexcept {
		HORD_STATE_ASSERT_VALID__(state);
		m_states.set(state, enable);
	}

	/**
		Test value of state.

		@returns
		- @c true if the state is enabled;
		- @c false if the state is disabled.
		@param state State to test.
	*/
	/*constexpr*/ bool
	test_state(
		State const state
	) const noexcept {
		HORD_STATE_ASSERT_VALID__(state);
		return m_states.test(state);
	}
#undef HORD_STATE_ASSERT_VALID__
/// @}

private:
	duct::StateStore<State> m_states;
	String m_root_path;

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

protected:
/** @name Constructors and destructor */ /// @{
	/**
		Constructor with root path.

		@param root_path Root path.
	*/
	Datastore(
		String root_path
	) noexcept;
public:
	/** Destructor. */
	virtual
	~Datastore() = 0;
/// @}

public:
/** @name Properties */ /// @{
	/**
		Set root path.

		@throws Error{ErrorCode::datastore_property_immutable}
		If the datastore is open.

		@param root_path New root path.
	*/
	void
	set_root_path(
		String root_path
	);

	/**
		Get root path.
	*/
	String const&
	get_root_path() const noexcept {
		return m_root_path;
	}

	/**
		Check if the datastore is open.
	*/
	bool
	is_open() const noexcept {
		return test_state(State::opened);
	}

	/**
		Check if the datastore is locked.
	*/
	bool
	is_locked() const noexcept {
		return test_state(State::locked);
	}
/// @}

/** @name Operations */ /// @{
	/**
		Open the datastore.

		@throws Error{ErrorCode::datastore_open_already}
		If the datastore is already open.

		@throws Error{ErrorCode::datastore_open_failed}
		If the datastore failed to open.
	*/
	void
	open();

	/**
		Close the datastore.

		@throws Error{ErrorCode::datastore_locked}
		If the datastore is locked.
	*/
	void
	close();

	/**
		Acquire raw stream for prop.

		@throws Error{ErrorCode::datastore_closed}
		If the datastore is closed.

		@throws Error{ErrorCode::datastore_locked}
		If the datastore is locked.

		@throws Error{ErrorCode::datastore_object_not_found}
		If @c prop_info.object_id does not exist in the datastore.

		@throws Error{ErrorCode::datastore_prop_void}
		If the object for @c prop_info.object_id has not yet created
		the prop (but it is otherwise valid). This can only occur
		when acquiring an input stream.

		@throws Error{ErrorCode::datastore_prop_unsupplied}
		If the object for @c prop_info.object_id does not supply the
		requested prop.

		@throws Error{..}
		Implementation-defined exceptions.

		@returns Raw prop stream.
		@param prop_info Prop info.

		@sa IO::PropInfo,
			IO::InputPropStream,
			IO::OutputPropStream
	*/
	std::istream&
	acquire_input_stream(
		IO::PropInfo const& prop_info
	);

	/** @copydoc acquire_input_stream(IO::PropInfo const&) */
	std::ostream&
	acquire_output_stream(
		IO::PropInfo const& prop_info
	);

	/**
		Release raw stream for prop.

		@throws Error{ErrorCode::datastore_closed}
		If the datastore is closed.

		@throws Error{ErrorCode::datastore_prop_not_locked}
		If either @a prop_info does not match the currently locked
		prop stream or there is no currently locked prop stream.

		@throws Error{ErrorCode::datastore_object_not_found}
		If @c prop_info.object_id does not exist in the datastore.

		@throws Error{ErrorCode::datastore_prop_unsupplied}
		If the object for @c prop_info.object_id does not supply
		the requested prop.

		@throws Error{..}
		Implementation-defined exceptions.

		@param prop_info Prop info.

		@sa IO::PropInfo,
			IO::InputPropStream,
			IO::OutputPropStream
	*/
	void
	release_input_stream(
		IO::PropInfo const& prop_info
	);

	/** @copydoc release_input_stream(IO::PropInfo const&) */
	void
	release_output_stream(
		IO::PropInfo const& prop_info
	);
/// @}

/** @name Objects */ /// @{
	/**
		Generate a %Hive-unique ID.

		@throws Error{ErrorCode::datastore_closed}
		If the datastore is closed.

		@returns The generated object ID.
		@param generator ID generator.
	*/
	Object::ID
	generate_id(
		System::IDGenerator& generator
	) const;

	/**
		Create an object in the datastore.

		@throws Error{ErrorCode::datastore_object_type_prohibited}
		If @c object_type!=Object::Type::Node, which is
		currently the only object type that can be created.

		@throws Error{ErrorCode::datastore_closed}
		If the datastore is closed.

		@throws Error{ErrorCode::datastore_locked}
		If the datastore is locked.

		@throws Error{ErrorCode::datastore_object_already_exists}
		If @a object_id already exists in the datastore.

		@throws Error{..}
		Implementation-defined exceptions.

		@param object_id ID of object.
		@param object_type Type of object.
	*/
	void
	create_object(
		Object::ID const object_id,
		Object::Type const object_type
	);

	/**
		Destroy an object in the datastore.

		@throws Error{ErrorCode::datastore_closed}
		If the datastore is closed.

		@throws Error{ErrorCode::datastore_locked}
		If the datastore is locked.

		@throws Error{ErrorCode::datastore_object_not_found}
		If @a object_id does not exist in the datastore.

		@throws Error{..}
		Implementation-defined exceptions.

		@param object_id ID of object.
	*/
	void
	destroy_object(
		Object::ID const object_id
	);
/// @}
};

/** @} */ // end of doc-group datastore
/** @} */ // end of doc-group io

} // namespace IO

template struct traits::require_t<
	IO::Datastore,
	std::has_virtual_destructor
>;

} // namespace Hord

#endif // HORD_IO_DATASTORE_HPP_
<commit_msg>IO::Datastore: removed ErrorCode::datastore_prop_unsupplied from stream release.<commit_after>/**
@file IO/Datastore.hpp
@brief Datastore class.

@author Tim Howard
@copyright 2013 Tim Howard under the MIT license;
see @ref index or the accompanying LICENSE file for full text.
*/

#ifndef HORD_IO_DATASTORE_HPP_
#define HORD_IO_DATASTORE_HPP_

#include <Hord/config.hpp>
#include <Hord/traits.hpp>
#include <Hord/String.hpp>
#include <Hord/System/IDGenerator.hpp>
#include <Hord/IO/Defs.hpp>
#include <Hord/IO/Prop.hpp>
#include <Hord/Object/Defs.hpp>

#include <duct/StateStore.hpp>

#include <cassert>
#include <functional>
#include <iosfwd>

namespace Hord {
namespace IO {

// Forward declarations
class Datastore;

/**
	@addtogroup io
	@{
*/
/**
	@addtogroup datastore
	@{
*/

/**
	Base datastore.

	This is the data interface for hives.

	@note %Datastores must be locked when a single prop stream is
	active.
*/
class Datastore {
public:
	/**
		Type info.
	*/
	struct type_info final {
	/** @name Operations */ /// @{
		/**
			Construct a datastore of this type.

			@returns
			- The constructed datastore; or
			- @c nullptr if construction failed.
			@param root_path Root path.
		*/
		Datastore*
		(&construct)(
			String root_path
		) noexcept;
	/// @}
	};

	/**
		Ensure traits for deriving classes.

		@remarks All constructors should be hidden or deleted.

		@tparam D Deriving class.
	*/
	template<
		typename D
	>
	struct ensure_traits :
		traits::require_t<
			D,
			tw::capture_post<std::is_base_of, Datastore>::type,
			std::is_nothrow_destructible
		>,
		traits::disallow_t<
			D,
			std::is_default_constructible,
			tw::capture<std::is_constructible, String>::type,
			tw::is_fully_copyable,
			tw::is_fully_moveable
		>
	{};

protected:
/** @name Implementation */ /// @{
	/**
		open() implementation.

		@throws Error{ErrorCode::datastore_open_failed}
	*/
	virtual void
	open_impl() = 0;

	/**
		close() implementation.

		@remarks This is not called if @c is_open()==false.
	*/
	virtual void
	close_impl() = 0;

	/**
		acquire_input_stream() implementation.

		@throws Error{ErrorCode::datastore_object_not_found}
		@throws Error{ErrorCode::datastore_prop_void}
		@throws Error{ErrorCode::datastore_prop_unsupplied}
		@throws Error{..}
	*/
	virtual std::istream&
	acquire_input_stream_impl(
		IO::PropInfo const& prop_info
	) = 0;

	/**
		acquire_output_stream() implementation.

		@throws Error{ErrorCode::datastore_object_not_found}
		@throws Error{ErrorCode::datastore_prop_void}
		@throws Error{ErrorCode::datastore_prop_unsupplied}
		@throws Error{..}
	*/
	virtual std::ostream&
	acquire_output_stream_impl(
		IO::PropInfo const& prop_info
	) = 0;

	/**
		release_input_stream() implementation.

		@throws Error{ErrorCode::datastore_prop_not_locked}
		@throws Error{ErrorCode::datastore_object_not_found}
		@throws Error{..}
	*/
	virtual void
	release_input_stream_impl(
		IO::PropInfo const& prop_info
	) = 0;

	/**
		release_output_stream() implementation.

		@throws Error{ErrorCode::datastore_prop_not_locked}
		@throws Error{ErrorCode::datastore_object_not_found}
		@throws Error{..}
	*/
	virtual void
	release_output_stream_impl(
		IO::PropInfo const& prop_info
	) = 0;

	/**
		generate_id() implementation.

		@remarks The implementation should generate a unique ID
		within the entire ID set of the datastore -- i.e., including
		orphaned objects (such as trash).
	*/
	virtual Object::ID
	generate_id_impl(
		System::IDGenerator& generator
	) const noexcept = 0;

	/**
		create_object() implementation.

		@throws Error{ErrorCode::datastore_object_already_exists}
		@throws Error{..}
	*/
	virtual void
	create_object_impl(
		Object::ID const object_id,
		Object::Type const object_type
	) = 0;

	/**
		destroy_object() implementation.

		@throws Error{ErrorCode::datastore_object_not_found}
		@throws Error{..}
	*/
	virtual void
	destroy_object_impl(
		Object::ID const object_id
	) = 0;
/// @}

/** @name Internal state */ /// @{
	/**
		States.

		Implementations are permitted to define states @c 1<<8
		to @c 1<<31.
	*/
	enum class State : uint32_t {
		/** %Datastore is open. */
		opened = 1 << 0,
		/** %Datastore is locked. */
		locked = 1 << 1,

		/** First reserved state. */
		RESERVED_FIRST = 1 << 2,
		/** Last reserved state. */
		RESERVED_LAST = 1 << 7
	};

/** @cond INTERNAL */
#define HORD_STATE_ASSERT_VALID__(x__)	\
	assert(								\
		State::RESERVED_FIRST > x__ &&	\
		State::RESERVED_LAST  < x__		\
	);
/** @endcond */

	/**
		Enable state.

		@param state %State to enable.
	*/
	/*constexpr*/ void
	enable_state(
		State const state
	) noexcept {
		HORD_STATE_ASSERT_VALID__(state);
		m_states.enable(state);
	}

	/**
		Disable state.

		@param state %State to disable.
	*/
	/*constexpr*/ void
	disable_state(
		State const state
	) noexcept {
		HORD_STATE_ASSERT_VALID__(state);
		m_states.disable(state);
	}

	/**
		Enable or disable state.

		@param state %State to enable or disable.
		@param enable Whether to enable or disable the state.
	*/
	/*constexpr*/ void
	set_state(
		State const state,
		bool const enable
	) noexcept {
		HORD_STATE_ASSERT_VALID__(state);
		m_states.set(state, enable);
	}

	/**
		Test value of state.

		@returns
		- @c true if the state is enabled;
		- @c false if the state is disabled.
		@param state State to test.
	*/
	/*constexpr*/ bool
	test_state(
		State const state
	) const noexcept {
		HORD_STATE_ASSERT_VALID__(state);
		return m_states.test(state);
	}
#undef HORD_STATE_ASSERT_VALID__
/// @}

private:
	duct::StateStore<State> m_states;
	String m_root_path;

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

protected:
/** @name Constructors and destructor */ /// @{
	/**
		Constructor with root path.

		@param root_path Root path.
	*/
	Datastore(
		String root_path
	) noexcept;
public:
	/** Destructor. */
	virtual
	~Datastore() = 0;
/// @}

public:
/** @name Properties */ /// @{
	/**
		Set root path.

		@throws Error{ErrorCode::datastore_property_immutable}
		If the datastore is open.

		@param root_path New root path.
	*/
	void
	set_root_path(
		String root_path
	);

	/**
		Get root path.
	*/
	String const&
	get_root_path() const noexcept {
		return m_root_path;
	}

	/**
		Check if the datastore is open.
	*/
	bool
	is_open() const noexcept {
		return test_state(State::opened);
	}

	/**
		Check if the datastore is locked.
	*/
	bool
	is_locked() const noexcept {
		return test_state(State::locked);
	}
/// @}

/** @name Operations */ /// @{
	/**
		Open the datastore.

		@throws Error{ErrorCode::datastore_open_already}
		If the datastore is already open.

		@throws Error{ErrorCode::datastore_open_failed}
		If the datastore failed to open.
	*/
	void
	open();

	/**
		Close the datastore.

		@throws Error{ErrorCode::datastore_locked}
		If the datastore is locked.
	*/
	void
	close();

	/**
		Acquire raw stream for prop.

		@throws Error{ErrorCode::datastore_closed}
		If the datastore is closed.

		@throws Error{ErrorCode::datastore_locked}
		If the datastore is locked.

		@throws Error{ErrorCode::datastore_object_not_found}
		If @c prop_info.object_id does not exist in the datastore.

		@throws Error{ErrorCode::datastore_prop_void}
		If the object for @c prop_info.object_id has not yet created
		the prop (but it is otherwise valid). This can only occur
		when acquiring an input stream.

		@throws Error{ErrorCode::datastore_prop_unsupplied}
		If the object for @c prop_info.object_id does not supply the
		requested prop.

		@throws Error{..}
		Implementation-defined exceptions.

		@returns Raw prop stream.
		@param prop_info Prop info.

		@sa IO::PropInfo,
			IO::InputPropStream,
			IO::OutputPropStream
	*/
	std::istream&
	acquire_input_stream(
		IO::PropInfo const& prop_info
	);

	/** @copydoc acquire_input_stream(IO::PropInfo const&) */
	std::ostream&
	acquire_output_stream(
		IO::PropInfo const& prop_info
	);

	/**
		Release raw stream for prop.

		@throws Error{ErrorCode::datastore_closed}
		If the datastore is closed.

		@throws Error{ErrorCode::datastore_prop_not_locked}
		If either @a prop_info does not match the currently locked
		prop stream or there is no currently locked prop stream.

		@throws Error{ErrorCode::datastore_object_not_found}
		If @c prop_info.object_id does not exist in the datastore.

		@throws Error{..}
		Implementation-defined exceptions.

		@param prop_info Prop info.

		@sa IO::PropInfo,
			IO::InputPropStream,
			IO::OutputPropStream
	*/
	void
	release_input_stream(
		IO::PropInfo const& prop_info
	);

	/** @copydoc release_input_stream(IO::PropInfo const&) */
	void
	release_output_stream(
		IO::PropInfo const& prop_info
	);
/// @}

/** @name Objects */ /// @{
	/**
		Generate a %Hive-unique ID.

		@throws Error{ErrorCode::datastore_closed}
		If the datastore is closed.

		@returns The generated object ID.
		@param generator ID generator.
	*/
	Object::ID
	generate_id(
		System::IDGenerator& generator
	) const;

	/**
		Create an object in the datastore.

		@throws Error{ErrorCode::datastore_object_type_prohibited}
		If @c object_type!=Object::Type::Node, which is
		currently the only object type that can be created.

		@throws Error{ErrorCode::datastore_closed}
		If the datastore is closed.

		@throws Error{ErrorCode::datastore_locked}
		If the datastore is locked.

		@throws Error{ErrorCode::datastore_object_already_exists}
		If @a object_id already exists in the datastore.

		@throws Error{..}
		Implementation-defined exceptions.

		@param object_id ID of object.
		@param object_type Type of object.
	*/
	void
	create_object(
		Object::ID const object_id,
		Object::Type const object_type
	);

	/**
		Destroy an object in the datastore.

		@throws Error{ErrorCode::datastore_closed}
		If the datastore is closed.

		@throws Error{ErrorCode::datastore_locked}
		If the datastore is locked.

		@throws Error{ErrorCode::datastore_object_not_found}
		If @a object_id does not exist in the datastore.

		@throws Error{..}
		Implementation-defined exceptions.

		@param object_id ID of object.
	*/
	void
	destroy_object(
		Object::ID const object_id
	);
/// @}
};

/** @} */ // end of doc-group datastore
/** @} */ // end of doc-group io

} // namespace IO

template struct traits::require_t<
	IO::Datastore,
	std::has_virtual_destructor
>;

} // namespace Hord

#endif // HORD_IO_DATASTORE_HPP_
<|endoftext|>


<commit_before>// Copyright (C) 2017 Jérôme Leclercq
// 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/Flags.hpp>
#include <Nazara/Core/Debug.hpp>

namespace Nz
{
	/*!
	* \ingroup core
	* \class Nz::Flags
	* \brief Core class used to combine enumeration values into flags bitfield
	*/

	/*!
	* \brief Constructs a Flags object using a bitfield
	*
	* \param value Bitfield to be used
	*
	* Uses a bitfield to builds the flag value. (e.g. if bit 0 is active, then Enum value 0 will be set as active).
	*/
	template<typename E>
	constexpr Flags<E>::Flags(BitField value) :
	m_value(value)
	{
	}

	/*!
	* \brief Constructs a Flags object using an Enum value
	*
	* \param enumVal enumVal
	*
	* Setup a Flags object with only one flag active (corresponding to the enum value passed as argument).
	*/
	template<typename E>
	constexpr Flags<E>::Flags(E enumVal) :
	Flags(GetFlagValue(enumVal))
	{
	}

	/*!
	* \brief Tests if all flags from a Flags object are enabled
	* \return True if all tested flags are enabled.
	*/
	template<typename E>
	constexpr bool Flags<E>::Test(const Flags& flags) const
	{
		return (m_value & flags.m_value) == flags.m_value;
	}

	/*!
	* \brief Tests any flag
	* \return True if any flag is enabled.
	*
	* This will convert to a boolean value allowing to check if any flag is set.
	*/
	template<typename E>
	constexpr Flags<E>::operator bool() const
	{
		return m_value != 0;
	}

	/*!
	* \brief Converts to an integer
	* \return Enabled flags as a integer
	*
	* This will only works if the integer type is large enough to store all flags states
	*/
	template<typename E>
	template<typename T, typename>
	constexpr Flags<E>::operator T() const
	{
		return m_value;
	}

	/*!
	* \brief Reverse flag states
	* \return Opposite enabled flags
	*
	* This will returns a copy of the Flags object with reversed flags states.
	*/
	template<typename E>
	constexpr Flags<E> Flags<E>::operator~() const
	{
		return Flags((~m_value) & ValueMask);
	}

	/*!
	* \brief Compare flag states
	* \return Shared flags
	*
	* \param rhs Flags to compare with.
	*
	* This will returns a copy of the Flags object with only enabled flags in common with the parameter
	*/
	template<typename E>
	constexpr Flags<E> Flags<E>::operator&(const Flags& rhs) const
	{
		return Flags(m_value & rhs.m_value);
	}

	/*!
	* \brief Combine flag states
	* \return Combined flags
	*
	* This will returns a copy of the Flags object with combined flags from the parameter.
	*
	* \param rhs Flags to combine with.
	*/
	template<typename E>
	constexpr Flags<E> Flags<E>::operator|(const Flags& rhs) const
	{
		return Flags(m_value | rhs.m_value);
	}

	/*!
	* \brief XOR flag states
	* \return XORed flags.
	*
	* \param rhs Flags to XOR with.
	*
	* This performs a XOR (Exclusive OR) on a copy of the flag object.
	* This will returns a copy of the object with disabled common flags and enabled unique ones.
	*/
	template<typename E>
	constexpr Flags<E> Flags<E>::operator^(const Flags& rhs) const
	{
		return Flags((m_value ^ rhs.m_value) & ValueMask);
	}

	/*!
	* \brief Check equality with flag object
	* \return True if both flags objects have the same states.
	*
	* \param rhs Flags to compare with.
	*
	* Compare two Flags object and returns true if the flag states are identical.
	*/
	template<typename E>
	constexpr bool Flags<E>::operator==(const Flags& rhs) const
	{
		return m_value == rhs.m_value;
	}

	/*!
	* \brief Check inequality with flag object
	* \return True if both flags objects have different states.
	*
	* \param rhs Flags to compare with.
	*
	* Compare two Flags object and returns true if the flag states are identical.
	*/
	template<typename E>
	constexpr bool Flags<E>::operator!=(const Flags& rhs) const
	{
		return !operator==(rhs);
	}

	/*!
	* \brief Combine flag states
	* \return A reference to the object.
	*
	* \param rhs Flags to combine with.
	*
	* This will enable flags which are enabled in parameter object and not in Flag object.
	*/
	template<typename E>
	/*constexpr*/ Flags<E>& Flags<E>::operator|=(const Flags& rhs)
	{
		m_value |= rhs.m_value;

		return *this;
	}

	/*!
	* \brief Compare flag states
	* \return A reference to the object.
	*
	* \param rhs Flags to compare with.
	*
	* This will disable flags which are disabled in parameter object and enabled in Flag object (and vice-versa).
	*/
	template<typename E>
	/*constexpr*/ Flags<E>& Flags<E>::operator&=(const Flags& rhs)
	{
		m_value &= rhs.m_value;

		return *this;
	}

	/*!
	* \brief XOR flag states
	* \return A reference to the object.
	*
	* \param rhs Flags to XOR with.
	*
	* This performs a XOR (Exclusive OR) on the flag object.
	* This will disable flags enabled in both Flags objects and enable those enabled in only one of the Flags objects.
	*/
	template<typename E>
	/*constexpr*/ Flags<E>& Flags<E>::operator^=(const Flags& rhs)
	{
		m_value ^= rhs.m_value;
		m_value &= ValueMask;

		return *this;
	}

	/*!
	* \brief Returns a bitfield corresponding to an enum value.
	* \return Bitfield representation of the enum value
	*
	* \param enumValue Enumeration value to get as a bitfield.
	*
	* Internally, every enum option is turned into a bit, this function allows to get a bitfield with only the bit of the enumeration value enabled.
	*/
	template<typename E>
	constexpr typename Flags<E>::BitField Flags<E>::GetFlagValue(E enumValue)
	{
		assert(enumValue < sizeof(BitField) * CHAR_BIT);
		return 1U << static_cast<BitField>(enumValue);
	}

	/*!
	* \brief Compare flag states
	* \return Compared flags
	*
	* This will returns a copy of the Flags object compared with the enum state.
	*
	* \param lhs Enum to compare with flags.
	* \param rhs Flags object.
	*/
	template<typename E>
	constexpr Flags<E> operator&(E lhs, Flags<E> rhs)
	{
		return rhs & lhs;
	}

	/*!
	* \brief Combine flag states
	* \return Combined flags
	*
	* This will returns a copy of the Flags object combined with the enum state.
	*
	* \param lhs Enum to combine with flags.
	* \param rhs Flags object.
	*/
	template<typename E>
	constexpr Flags<E> operator|(E lhs, Flags<E> rhs)
	{
		return rhs | lhs;
	}

	/*!
	* \brief XOR flag states
	* \return XORed flags
	*
	* This will returns a copy of the Flags object XORed with the enum state.
	*
	* \param lhs Enum to XOR with flags.
	* \param rhs Flags object.
	*/
	template<typename E>
	constexpr Flags<E> operator^(E lhs, Flags<E> rhs)
	{
		return rhs ^ lhs;
	}

	namespace FlagsOperators
	{
		/*!
		* \brief Override binary NOT operator on enum to turns into a Flags object.
		* \return A Flags object with reversed bits.
		*
		* \param lhs Enumeration value to reverse.
		*
		* Returns a Flags object with all state enabled except for the enum one.
		*/
		template<typename E>
		constexpr std::enable_if_t<IsEnumFlag<E>::value, Flags<E>> operator~(E lhs)
		{
			return ~Flags<E>(lhs);
		}

		/*!
		* \brief Override binary AND operator on enum to turns into a Flags object.
		* \return A Flags object with compare enum states.
		*
		* \param lhs First enumeration value to compare.
		* \param rhs Second enumeration value to compare.
		*
		* Returns a Flags object with compared states from the two enumeration values.
		* In this case, only one flag will be enabled if both enumeration values are the same.
		*/
		template<typename E>
		constexpr std::enable_if_t<IsEnumFlag<E>::value, Flags<E>> operator&(E lhs, E rhs)
		{
			return Flags<E>(lhs) & rhs;
		}

		/*!
		* \brief Override binary OR operator on enum to turns into a Flags object.
		* \return A Flags object with combined enum states.
		*
		* \param lhs First enumeration value to combine.
		* \param rhs Second enumeration value to combine.
		*
		* Returns a Flags object with combined states from the two enumeration values.
		*/
		template<typename E>
		constexpr std::enable_if_t<IsEnumFlag<E>::value, Flags<E>> operator|(E lhs, E rhs)
		{
			return Flags<E>(lhs) | rhs;
		}

		/*!
		* \brief Override binary XOR operator on enum to turns into a Flags object.
		* \return A Flags object with XORed enum states.
		*
		* \param lhs First enumeration value to compare.
		* \param rhs Second enumeration value to compare.
		*
		* Returns a Flags object with XORed states from the two enumeration values.
		* In this case, two flags will be enabled if both the enumeration values are different.
		*/
		template<typename E>
		constexpr std::enable_if_t<IsEnumFlag<E>::value, Flags<E>> operator^(E lhs, E rhs)
		{
			return Flags<E>(lhs) ^ rhs;
		}
	}
}

#include <Nazara/Core/DebugOff.hpp>
<commit_msg>Update Flags.inl<commit_after>// Copyright (C) 2017 Jérôme Leclercq
// 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/Flags.hpp>
#include <Nazara/Core/Debug.hpp>

namespace Nz
{
	/*!
	* \ingroup core
	* \class Nz::Flags
	* \brief Core class used to combine enumeration values into flags bitfield
	*/

	/*!
	* \brief Constructs a Flags object using a bitfield
	*
	* \param value Bitfield to be used
	*
	* Uses a bitfield to builds the flag value. (e.g. if bit 0 is active, then Enum value 0 will be set as active).
	*/
	template<typename E>
	constexpr Flags<E>::Flags(BitField value) :
	m_value(value)
	{
	}

	/*!
	* \brief Constructs a Flags object using an Enum value
	*
	* \param enumVal enumVal
	*
	* Setup a Flags object with only one flag active (corresponding to the enum value passed as argument).
	*/
	template<typename E>
	constexpr Flags<E>::Flags(E enumVal) :
	Flags(GetFlagValue(enumVal))
	{
	}

	/*!
	* \brief Tests if all flags from a Flags object are enabled
	* \return True if all tested flags are enabled.
	*/
	template<typename E>
	constexpr bool Flags<E>::Test(const Flags& flags) const
	{
		return (m_value & flags.m_value) == flags.m_value;
	}

	/*!
	* \brief Tests any flag
	* \return True if any flag is enabled.
	*
	* This will convert to a boolean value allowing to check if any flag is set.
	*/
	template<typename E>
	constexpr Flags<E>::operator bool() const
	{
		return m_value != 0;
	}

	/*!
	* \brief Converts to an integer
	* \return Enabled flags as a integer
	*
	* This will only works if the integer type is large enough to store all flags states
	*/
	template<typename E>
	template<typename T, typename>
	constexpr Flags<E>::operator T() const
	{
		return m_value;
	}

	/*!
	* \brief Reverse flag states
	* \return Opposite enabled flags
	*
	* This will returns a copy of the Flags object with reversed flags states.
	*/
	template<typename E>
	constexpr Flags<E> Flags<E>::operator~() const
	{
		return Flags((~m_value) & ValueMask);
	}

	/*!
	* \brief Compare flag states
	* \return Shared flags
	*
	* \param rhs Flags to compare with.
	*
	* This will returns a copy of the Flags object with only enabled flags in common with the parameter
	*/
	template<typename E>
	constexpr Flags<E> Flags<E>::operator&(const Flags& rhs) const
	{
		return Flags(m_value & rhs.m_value);
	}

	/*!
	* \brief Combine flag states
	* \return Combined flags
	*
	* This will returns a copy of the Flags object with combined flags from the parameter.
	*
	* \param rhs Flags to combine with.
	*/
	template<typename E>
	constexpr Flags<E> Flags<E>::operator|(const Flags& rhs) const
	{
		return Flags(m_value | rhs.m_value);
	}

	/*!
	* \brief XOR flag states
	* \return XORed flags.
	*
	* \param rhs Flags to XOR with.
	*
	* This performs a XOR (Exclusive OR) on a copy of the flag object.
	* This will returns a copy of the object with disabled common flags and enabled unique ones.
	*/
	template<typename E>
	constexpr Flags<E> Flags<E>::operator^(const Flags& rhs) const
	{
		return Flags((m_value ^ rhs.m_value) & ValueMask);
	}

	/*!
	* \brief Check equality with flag object
	* \return True if both flags objects have the same states.
	*
	* \param rhs Flags to compare with.
	*
	* Compare two Flags object and returns true if the flag states are identical.
	*/
	template<typename E>
	constexpr bool Flags<E>::operator==(const Flags& rhs) const
	{
		return m_value == rhs.m_value;
	}

	/*!
	* \brief Check inequality with flag object
	* \return True if both flags objects have different states.
	*
	* \param rhs Flags to compare with.
	*
	* Compare two Flags object and returns true if the flag states are identical.
	*/
	template<typename E>
	constexpr bool Flags<E>::operator!=(const Flags& rhs) const
	{
		return !operator==(rhs);
	}

	/*!
	* \brief Combine flag states
	* \return A reference to the object.
	*
	* \param rhs Flags to combine with.
	*
	* This will enable flags which are enabled in parameter object and not in Flag object.
	*/
	template<typename E>
	/*constexpr*/ Flags<E>& Flags<E>::operator|=(const Flags& rhs)
	{
		m_value |= rhs.m_value;

		return *this;
	}

	/*!
	* \brief Compare flag states
	* \return A reference to the object.
	*
	* \param rhs Flags to compare with.
	*
	* This will disable flags which are disabled in parameter object and enabled in Flag object (and vice-versa).
	*/
	template<typename E>
	/*constexpr*/ Flags<E>& Flags<E>::operator&=(const Flags& rhs)
	{
		m_value &= rhs.m_value;

		return *this;
	}

	/*!
	* \brief XOR flag states
	* \return A reference to the object.
	*
	* \param rhs Flags to XOR with.
	*
	* This performs a XOR (Exclusive OR) on the flag object.
	* This will disable flags enabled in both Flags objects and enable those enabled in only one of the Flags objects.
	*/
	template<typename E>
	/*constexpr*/ Flags<E>& Flags<E>::operator^=(const Flags& rhs)
	{
		m_value ^= rhs.m_value;
		m_value &= ValueMask;

		return *this;
	}

	/*!
	* \brief Returns a bitfield corresponding to an enum value.
	* \return Bitfield representation of the enum value
	*
	* \param enumValue Enumeration value to get as a bitfield.
	*
	* Internally, every enum option is turned into a bit, this function allows to get a bitfield with only the bit of the enumeration value enabled.
	*/
	template<typename E>
	constexpr typename Flags<E>::BitField Flags<E>::GetFlagValue(E enumValue)
	{
		return 1U << static_cast<BitField>(enumValue);
	}

	/*!
	* \brief Compare flag states
	* \return Compared flags
	*
	* This will returns a copy of the Flags object compared with the enum state.
	*
	* \param lhs Enum to compare with flags.
	* \param rhs Flags object.
	*/
	template<typename E>
	constexpr Flags<E> operator&(E lhs, Flags<E> rhs)
	{
		return rhs & lhs;
	}

	/*!
	* \brief Combine flag states
	* \return Combined flags
	*
	* This will returns a copy of the Flags object combined with the enum state.
	*
	* \param lhs Enum to combine with flags.
	* \param rhs Flags object.
	*/
	template<typename E>
	constexpr Flags<E> operator|(E lhs, Flags<E> rhs)
	{
		return rhs | lhs;
	}

	/*!
	* \brief XOR flag states
	* \return XORed flags
	*
	* This will returns a copy of the Flags object XORed with the enum state.
	*
	* \param lhs Enum to XOR with flags.
	* \param rhs Flags object.
	*/
	template<typename E>
	constexpr Flags<E> operator^(E lhs, Flags<E> rhs)
	{
		return rhs ^ lhs;
	}

	namespace FlagsOperators
	{
		/*!
		* \brief Override binary NOT operator on enum to turns into a Flags object.
		* \return A Flags object with reversed bits.
		*
		* \param lhs Enumeration value to reverse.
		*
		* Returns a Flags object with all state enabled except for the enum one.
		*/
		template<typename E>
		constexpr std::enable_if_t<IsEnumFlag<E>::value, Flags<E>> operator~(E lhs)
		{
			return ~Flags<E>(lhs);
		}

		/*!
		* \brief Override binary AND operator on enum to turns into a Flags object.
		* \return A Flags object with compare enum states.
		*
		* \param lhs First enumeration value to compare.
		* \param rhs Second enumeration value to compare.
		*
		* Returns a Flags object with compared states from the two enumeration values.
		* In this case, only one flag will be enabled if both enumeration values are the same.
		*/
		template<typename E>
		constexpr std::enable_if_t<IsEnumFlag<E>::value, Flags<E>> operator&(E lhs, E rhs)
		{
			return Flags<E>(lhs) & rhs;
		}

		/*!
		* \brief Override binary OR operator on enum to turns into a Flags object.
		* \return A Flags object with combined enum states.
		*
		* \param lhs First enumeration value to combine.
		* \param rhs Second enumeration value to combine.
		*
		* Returns a Flags object with combined states from the two enumeration values.
		*/
		template<typename E>
		constexpr std::enable_if_t<IsEnumFlag<E>::value, Flags<E>> operator|(E lhs, E rhs)
		{
			return Flags<E>(lhs) | rhs;
		}

		/*!
		* \brief Override binary XOR operator on enum to turns into a Flags object.
		* \return A Flags object with XORed enum states.
		*
		* \param lhs First enumeration value to compare.
		* \param rhs Second enumeration value to compare.
		*
		* Returns a Flags object with XORed states from the two enumeration values.
		* In this case, two flags will be enabled if both the enumeration values are different.
		*/
		template<typename E>
		constexpr std::enable_if_t<IsEnumFlag<E>::value, Flags<E>> operator^(E lhs, E rhs)
		{
			return Flags<E>(lhs) ^ rhs;
		}
	}
}

#include <Nazara/Core/DebugOff.hpp>
<|endoftext|>


<commit_before>// Time:  ctor:   O(n),
//        query:  O(logn),
//        modify: O(logn)
// Space: O(n)

/**
 * Definition of Interval:
 * classs Interval {
 *     int start, end;
 *     Interval(int start, int end) {
 *         this->start = start;
 *         this->end = end;
 *     }
 */

// Segment Tree solution.
class SegmentTreeSumNode {
public:
    int start, end;
    long long sum;
    SegmentTreeSumNode *left, *right;
    SegmentTreeSumNode(int start, int end, long long sum) {
        this->start = start;
        this->end = end;
        this->sum = sum;
        this->left = this->right = NULL;
    }
};

class Solution {
public:
    /* you may need to use some attributes here */
    SegmentTreeSumNode *root_;

    /**
     * @param A: An integer vector
     */
    Solution(vector<int> A) {
        root_ = build(A, 0, A.size() - 1);
    }

    /**
     * @param start, end: Indices
     * @return: The sum from start to end
     */
    long long query(int start, int end) {
        queryTree(root_, start, end);
    }

    /**
     * @param index, value: modify A[index] to value.
     */
    void modify(int index, int value) {
        modifyTree(root_, index, value);
    }

    // Query Sum in given range.
    long long queryTree(SegmentTreeSumNode *root, int start, int end) {
        // Out of range.
        if (root == nullptr || root->start > end || root->end <  start) {
            return 0;
        }

        // Current segment is totally within range [start, end]
        if (root->start >= start && root->end <= end) {
            return root->sum;
        }

        long long left = queryTree(root->left, start, end);
        long long right = queryTree(root->right, start, end);

        // Find sum in the children.
        return left + right;
    }

    void modifyTree(SegmentTreeSumNode *root, int index, int value) {
        // Out of range.
        if (root == nullptr || root->start > index || root->end < index) {
            return;
        }

        // Change the node's value with [index, index] to the new given value.
        if (root->start == index && root->end == index) {
            root->sum = value;
            return;
        }

        modifyTree(root->left, index, value);
        modifyTree(root->right, index, value);

        int left_sum = root->left != nullptr? root->left->sum : 0;
        int right_sum = root->right != nullptr? root->right->sum : 0;

        // Update sum.
        root->sum = left_sum + right_sum;
    }

    // Build segment tree.
    SegmentTreeSumNode *build(vector<int> &A, int start, int end) {
        if (start > end) {
            return nullptr;
        }

        // The root's start and end is given by build method.
        SegmentTreeSumNode *root = new SegmentTreeSumNode(start, end, 0);

        // If start equals to end, there will be no children for this node.
        if (start == end) {
            root->sum = A[start];
            return root;
        }

        // Left child: start=A.left, end=(A.left + A.right) / 2.
        root->left = build(A, start, (start + end) / 2);

        // Right child: start=(A.left + A.right) / 2 + 1, end=A.right.
        root->right = build(A, (start + end) / 2 + 1, end);

        long long left_sum = root->left != nullptr? root->left->sum : 0;
        long long right_sum = root->right != nullptr? root->right->sum : 0;

        // Update sum.
        root->sum = left_sum + right_sum;
        return root;
    }
};

// Time:  ctor:   O(n),
//        query:  O(logn),
//        modify: O(logn)
// Space: O(n)
// Binary Indexed Tree (BIT) solution.
class Solution2 {
public:
    /* you may need to use some attributes here */

    /**
     * @param A: An integer vector
     */
    Solution(vector<int> A) : nums_(A) {
        bit_ = vector<int>(nums_.size() + 1);
        for (int i = 1; i < bit_.size(); ++i) {
            bit_[i] = A[i - 1] + bit_[i - 1];
        }
        for (int i = bit_.size() - 1; i >= 1; --i) {
            int last_i = i - (i & -i);
            bit_[i] -= bit_[last_i];
        }
    }

    /**
     * @param start, end: Indices
     * @return: The sum from start to end
     */
    long long query(int start, int end) {
        int sum = sumRegion_bit(end);
        if (start > 0) {
            sum -= sumRegion_bit(start - 1);
        }
        return sum;
    }

    /**
     * @param index, value: modify A[index] to value.
     */
    void modify(int index, int value) {
        if (value - nums_[index]) {
            add(index, value - nums_[index]);
            nums_[index] = value;
        }
    }

private:
    vector<int> nums_;
    vector<int> bit_;

    int sumRegion_bit(int i) {
        ++i;
        int sum = 0;
        for (; i > 0; i -= lower_bit(i)) {
            sum += bit_[i];
        }
        return sum;
    }

    void add(int i, int val) {
        ++i;
        for (; i <= nums_.size(); i += lower_bit(i)) {
            bit_[i] += val;
        }
    }

    int lower_bit(int i) {
        return i & -i;
    }
};

<commit_msg>Update interval-sum-ii.cpp<commit_after>// Time:  ctor:   O(n),
//        query:  O(logn),
//        modify: O(logn)
// Space: O(n)

/**
 * Definition of Interval:
 * classs Interval {
 *     int start, end;
 *     Interval(int start, int end) {
 *         this->start = start;
 *         this->end = end;
 *     }
 */

// Segment Tree solution.
class SegmentTreeSumNode {
public:
    int start, end;
    long long sum;
    SegmentTreeSumNode *left, *right;
    SegmentTreeSumNode(int start, int end, long long sum) {
        this->start = start;
        this->end = end;
        this->sum = sum;
        this->left = this->right = NULL;
    }
};

class Solution {
public:
    /* you may need to use some attributes here */
    SegmentTreeSumNode *root_;

    /**
     * @param A: An integer vector
     */
    Solution(vector<int> A) {
        root_ = build(A, 0, A.size() - 1);
    }

    /**
     * @param start, end: Indices
     * @return: The sum from start to end
     */
    long long query(int start, int end) {
        queryTree(root_, start, end);
    }

    /**
     * @param index, value: modify A[index] to value.
     */
    void modify(int index, int value) {
        modifyTree(root_, index, value);
    }

    // Query Sum in given range.
    long long queryTree(SegmentTreeSumNode *root, int start, int end) {
        // Out of range.
        if (root == nullptr || root->start > end || root->end <  start) {
            return 0;
        }

        // Current segment is totally within range [start, end]
        if (root->start >= start && root->end <= end) {
            return root->sum;
        }

        long long left = queryTree(root->left, start, end);
        long long right = queryTree(root->right, start, end);

        // Find sum in the children.
        return left + right;
    }

    void modifyTree(SegmentTreeSumNode *root, int index, int value) {
        // Out of range.
        if (root == nullptr || root->start > index || root->end < index) {
            return;
        }

        // Change the node's value with [index, index] to the new given value.
        if (root->start == index && root->end == index) {
            root->sum = value;
            return;
        }

        modifyTree(root->left, index, value);
        modifyTree(root->right, index, value);

        int left_sum = root->left != nullptr? root->left->sum : 0;
        int right_sum = root->right != nullptr? root->right->sum : 0;

        // Update sum.
        root->sum = left_sum + right_sum;
    }

    // Build segment tree.
    SegmentTreeSumNode *build(vector<int> &A, int start, int end) {
        if (start > end) {
            return nullptr;
        }

        // The root's start and end is given by build method.
        SegmentTreeSumNode *root = new SegmentTreeSumNode(start, end, 0);

        // If start equals to end, there will be no children for this node.
        if (start == end) {
            root->sum = A[start];
            return root;
        }

        // Left child: start=A.left, end=(A.left + A.right) / 2.
        root->left = build(A, start, (start + end) / 2);

        // Right child: start=(A.left + A.right) / 2 + 1, end=A.right.
        root->right = build(A, (start + end) / 2 + 1, end);

        long long left_sum = root->left != nullptr? root->left->sum : 0;
        long long right_sum = root->right != nullptr? root->right->sum : 0;

        // Update sum.
        root->sum = left_sum + right_sum;
        return root;
    }
};

// Time:  ctor:   O(n),
//        query:  O(logn),
//        modify: O(logn)
// Space: O(n)
// Binary Indexed Tree (BIT) solution.
class Solution2 {
public:
    /* you may need to use some attributes here */

    /**
     * @param A: An integer vector
     */
    Solution(vector<int> A) : nums_(A) {
        bit_ = vector<int>(nums_.size() + 1);
        for (int i = 1; i < bit_.size(); ++i) {
            bit_[i] = A[i - 1] + bit_[i - 1];
        }
        for (int i = bit_.size() - 1; i >= 1; --i) {
            int last_i = i - lower_bit(i);
            bit_[i] -= bit_[last_i];
        }
    }

    /**
     * @param start, end: Indices
     * @return: The sum from start to end
     */
    long long query(int start, int end) {
        int sum = sumRegion_bit(end);
        if (start > 0) {
            sum -= sumRegion_bit(start - 1);
        }
        return sum;
    }

    /**
     * @param index, value: modify A[index] to value.
     */
    void modify(int index, int value) {
        if (value - nums_[index]) {
            add(index, value - nums_[index]);
            nums_[index] = value;
        }
    }

private:
    vector<int> nums_;
    vector<int> bit_;

    int sumRegion_bit(int i) {
        ++i;
        int sum = 0;
        for (; i > 0; i -= lower_bit(i)) {
            sum += bit_[i];
        }
        return sum;
    }

    void add(int i, int val) {
        ++i;
        for (; i <= nums_.size(); i += lower_bit(i)) {
            bit_[i] += val;
        }
    }

    int lower_bit(int i) {
        return i & -i;
    }
};

<|endoftext|>


<commit_before>#pragma once

#include <atomic>
#include <brynet/base/Noexcept.hpp>
#include <chrono>
#include <functional>
#include <memory>
#include <mutex>
#include <queue>
#include <vector>

namespace brynet { namespace base {

class TimerMgr;

class Timer final
{
public:
    using Ptr = std::shared_ptr<Timer>;
    using WeakPtr = std::weak_ptr<Timer>;
    using Callback = std::function<void(void)>;

    Timer(std::chrono::steady_clock::time_point startTime,
          std::chrono::nanoseconds lastTime,
          Callback&& callback) BRYNET_NOEXCEPT
        : mCallback(std::move(callback)),
          mStartTime(startTime),
          mLastTime(lastTime)
    {
    }

    const std::chrono::steady_clock::time_point& getStartTime() const
    {
        return mStartTime;
    }

    const std::chrono::nanoseconds& getLastTime() const
    {
        return mLastTime;
    }

    std::chrono::nanoseconds getLeftTime() const
    {
        const auto now = std::chrono::steady_clock::now();
        return getLastTime() - (now - getStartTime());
    }

    void cancel()
    {
        std::call_once(mExecuteOnceFlag, [this]() {
            mCallback = nullptr;
        });
    }

private:
    void operator()()
    {
        Callback callback;
        std::call_once(mExecuteOnceFlag, [&callback, this]() {
            callback = std::move(mCallback);
            mCallback = nullptr;
        });

        if (callback != nullptr)
        {
            callback();
        }
    }

private:
    std::once_flag mExecuteOnceFlag;
    Callback mCallback;
    const std::chrono::steady_clock::time_point mStartTime;
    const std::chrono::nanoseconds mLastTime;

    friend class TimerMgr;
};

class RepeatTimer
{
public:
    using Ptr = std::shared_ptr<RepeatTimer>;

    void cancel()
    {
        mCancel.store(true);
    }

    bool isCancel() const
    {
        return mCancel.load();
    }

private:
    std::atomic_bool mCancel = {false};
};

class TimerMgr final : public std::enable_shared_from_this<TimerMgr>
{
public:
    using Ptr = std::shared_ptr<TimerMgr>;

    template<typename F, typename... TArgs>
    Timer::WeakPtr addTimer(
            std::chrono::nanoseconds timeout,
            F&& callback,
            TArgs&&... args)
    {
        auto timer = std::make_shared<Timer>(
                std::chrono::steady_clock::now(),
                std::chrono::nanoseconds(timeout),
                std::bind(std::forward<F>(callback), std::forward<TArgs>(args)...));
        mTimers.push(timer);

        return timer;
    }

    template<typename F, typename... TArgs>
    RepeatTimer::Ptr addIntervalTimer(
            std::chrono::nanoseconds interval,
            F&& callback,
            TArgs&&... args)
    {
        auto sharedThis = shared_from_this();
        auto repeatTimer = std::make_shared<RepeatTimer>();
        auto wrapperCallback = std::bind(std::forward<F>(callback), std::forward<TArgs>(args)...);
        addTimer(interval, [sharedThis, interval, wrapperCallback, repeatTimer]() {
            stubRepeatTimerCallback(sharedThis, interval, wrapperCallback, repeatTimer);
        });

        return repeatTimer;
    }

    void addTimer(const Timer::Ptr& timer)
    {
        mTimers.push(timer);
    }

    void schedule()
    {
        while (!mTimers.empty())
        {
            auto tmp = mTimers.top();
            if (tmp->getLeftTime() > std::chrono::nanoseconds::zero())
            {
                break;
            }

            mTimers.pop();
            (*tmp)();
        }
    }

    bool isEmpty() const
    {
        return mTimers.empty();
    }

    // if timer empty, return zero
    std::chrono::nanoseconds nearLeftTime() const
    {
        if (mTimers.empty())
        {
            return std::chrono::nanoseconds::zero();
        }

        auto result = mTimers.top()->getLeftTime();
        if (result < std::chrono::nanoseconds::zero())
        {
            return std::chrono::nanoseconds::zero();
        }

        return result;
    }

    void clear()
    {
        while (!mTimers.empty())
        {
            mTimers.pop();
        }
    }

private:
    static void stubRepeatTimerCallback(TimerMgr::Ptr timerMgr,
                                        std::chrono::nanoseconds interval,
                                        std::function<void()> callback,
                                        RepeatTimer::Ptr repeatTimer)
    {
        if (repeatTimer->isCancel())
        {
            return;
        }
        callback();
        timerMgr->addTimer(interval, [timerMgr, interval, callback, repeatTimer]() {
            stubRepeatTimerCallback(timerMgr, interval, callback, repeatTimer);
        });
    }

private:
    class CompareTimer
    {
    public:
        bool operator()(const Timer::Ptr& left,
                        const Timer::Ptr& right) const
        {
            const auto startDiff = left->getStartTime() - right->getStartTime();
            const auto lastDiff = left->getLastTime() - right->getLastTime();
            const auto diff = startDiff.count() + lastDiff.count();
            return diff > 0;
        }
    };

    std::priority_queue<Timer::Ptr, std::vector<Timer::Ptr>, CompareTimer> mTimers;
};

}}// namespace brynet::base
<commit_msg>fix compiler in C++ 11<commit_after>#pragma once

#include <atomic>
#include <brynet/base/Noexcept.hpp>
#include <chrono>
#include <functional>
#include <memory>
#include <mutex>
#include <queue>
#include <vector>

namespace brynet { namespace base {

class TimerMgr;

class Timer final
{
public:
    using Ptr = std::shared_ptr<Timer>;
    using WeakPtr = std::weak_ptr<Timer>;
    using Callback = std::function<void(void)>;

    Timer(std::chrono::steady_clock::time_point startTime,
          std::chrono::nanoseconds lastTime,
          Callback&& callback) BRYNET_NOEXCEPT
        : mCallback(std::move(callback)),
          mStartTime(startTime),
          mLastTime(lastTime)
    {
    }

    const std::chrono::steady_clock::time_point& getStartTime() const
    {
        return mStartTime;
    }

    const std::chrono::nanoseconds& getLastTime() const
    {
        return mLastTime;
    }

    std::chrono::nanoseconds getLeftTime() const
    {
        const auto now = std::chrono::steady_clock::now();
        return getLastTime() - (now - getStartTime());
    }

    void cancel()
    {
        std::call_once(mExecuteOnceFlag, [this]() {
            mCallback = nullptr;
        });
    }

private:
    void operator()()
    {
        Callback callback;
        std::call_once(mExecuteOnceFlag, [&callback, this]() {
            callback = std::move(mCallback);
            mCallback = nullptr;
        });

        if (callback != nullptr)
        {
            callback();
        }
    }

private:
    std::once_flag mExecuteOnceFlag;
    Callback mCallback;
    const std::chrono::steady_clock::time_point mStartTime;
    const std::chrono::nanoseconds mLastTime;

    friend class TimerMgr;
};

class RepeatTimer
{
public:
    using Ptr = std::shared_ptr<RepeatTimer>;

    RepeatTimer()
    {
        mCancel.store(false);
    }

    void cancel()
    {
        mCancel.store(true);
    }

    bool isCancel() const
    {
        return mCancel.load();
    }

private:
    std::atomic_bool mCancel;
};

class TimerMgr final : public std::enable_shared_from_this<TimerMgr>
{
public:
    using Ptr = std::shared_ptr<TimerMgr>;

    template<typename F, typename... TArgs>
    Timer::WeakPtr addTimer(
            std::chrono::nanoseconds timeout,
            F&& callback,
            TArgs&&... args)
    {
        auto timer = std::make_shared<Timer>(
                std::chrono::steady_clock::now(),
                std::chrono::nanoseconds(timeout),
                std::bind(std::forward<F>(callback), std::forward<TArgs>(args)...));
        mTimers.push(timer);

        return timer;
    }

    template<typename F, typename... TArgs>
    RepeatTimer::Ptr addIntervalTimer(
            std::chrono::nanoseconds interval,
            F&& callback,
            TArgs&&... args)
    {
        auto sharedThis = shared_from_this();
        auto repeatTimer = std::make_shared<RepeatTimer>();
        auto wrapperCallback = std::bind(std::forward<F>(callback), std::forward<TArgs>(args)...);
        addTimer(interval, [sharedThis, interval, wrapperCallback, repeatTimer]() {
            stubRepeatTimerCallback(sharedThis, interval, wrapperCallback, repeatTimer);
        });

        return repeatTimer;
    }

    void addTimer(const Timer::Ptr& timer)
    {
        mTimers.push(timer);
    }

    void schedule()
    {
        while (!mTimers.empty())
        {
            auto tmp = mTimers.top();
            if (tmp->getLeftTime() > std::chrono::nanoseconds::zero())
            {
                break;
            }

            mTimers.pop();
            (*tmp)();
        }
    }

    bool isEmpty() const
    {
        return mTimers.empty();
    }

    // if timer empty, return zero
    std::chrono::nanoseconds nearLeftTime() const
    {
        if (mTimers.empty())
        {
            return std::chrono::nanoseconds::zero();
        }

        auto result = mTimers.top()->getLeftTime();
        if (result < std::chrono::nanoseconds::zero())
        {
            return std::chrono::nanoseconds::zero();
        }

        return result;
    }

    void clear()
    {
        while (!mTimers.empty())
        {
            mTimers.pop();
        }
    }

private:
    static void stubRepeatTimerCallback(TimerMgr::Ptr timerMgr,
                                        std::chrono::nanoseconds interval,
                                        std::function<void()> callback,
                                        RepeatTimer::Ptr repeatTimer)
    {
        if (repeatTimer->isCancel())
        {
            return;
        }
        callback();
        timerMgr->addTimer(interval, [timerMgr, interval, callback, repeatTimer]() {
            stubRepeatTimerCallback(timerMgr, interval, callback, repeatTimer);
        });
    }

private:
    class CompareTimer
    {
    public:
        bool operator()(const Timer::Ptr& left,
                        const Timer::Ptr& right) const
        {
            const auto startDiff = left->getStartTime() - right->getStartTime();
            const auto lastDiff = left->getLastTime() - right->getLastTime();
            const auto diff = startDiff.count() + lastDiff.count();
            return diff > 0;
        }
    };

    std::priority_queue<Timer::Ptr, std::vector<Timer::Ptr>, CompareTimer> mTimers;
};

}}// namespace brynet::base
<|endoftext|>


<commit_before>/*
 * eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: include/eos/core/read_obj.hpp
 *
 * Copyright 2017, 2018 Patrik Huber
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#pragma once

#ifndef EOS_READ_OBJ_HPP
#define EOS_READ_OBJ_HPP

#include "eos/core/Mesh.hpp"
#include "eos/cpp17/optional.hpp"

#include "Eigen/Core"

#include <cassert>
#include <fstream>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

namespace eos {
namespace core {

namespace detail {

/**
 * @brief Splits a string into a list of tokens.
 *
 * Taken from: https://stackoverflow.com/a/1493195/1345959
 */
template <class ContainerType>
void tokenize(const std::string& str, ContainerType& tokens, const std::string& delimiters = " ",
              bool trim_empty = false)
{
    std::string::size_type pos, last_pos = 0;
    const auto length = str.length();

    using value_type = typename ContainerType::value_type;
    using size_type = typename ContainerType::size_type;

    while (last_pos < length + 1)
    {
        pos = str.find_first_of(delimiters, last_pos);
        if (pos == std::string::npos)
        {
            pos = length;
        }

        if (pos != last_pos || !trim_empty)
            tokens.push_back(value_type(str.data() + last_pos, (size_type)pos - last_pos));

        last_pos = pos + 1;
    }
};

/**
 * @brief Parse a line starting with 'v ' from an obj file.
 *
 * Can contain either 3 ('x y z') or 6 ('x y z r g b') numbers.
 * The 'v ' should have already been stripped from \p line.
 *
 * Notes:
 * Could actually potentially consist of 3, 4, 6 or 7 elements? (xyz, xyzw,
 * xyzrgb, xyzwrgb)
 * assimp only deals with 3, 4 or 6 elements:
 * https://github.com/assimp/assimp/blob/master/code/ObjFileParser.cpp#L138
 *
 * For now, we don't support obj's containing homogeneous coordinates.
 * What we could do is that if we do encounter homogeneous coords, we could just divide by 'w', like assimp
 * does.
 *
 * Another obj parser we can check: https://github.com/qnzhou/PyMesh/blob/master/src/IO/OBJParser.cpp (and
 * same file with .h)
 */
inline std::pair<Eigen::Vector3f, cpp17::optional<Eigen::Vector3f>> parse_vertex(const std::string& line)
{
    std::vector<std::string> tokens;
    tokenize(line, tokens, " ");
    if (tokens.size() != 3 && tokens.size() != 6)
    {
        throw std::runtime_error(
            "Encountered a vertex ('v') line that does not consist of either 3 ('x y z') "
            "or 6 ('x y z r g b') numbers.");
    }
    const Eigen::Vector3f vertex(std::stof(tokens[0]), std::stof(tokens[1]), std::stof(tokens[2]));
    cpp17::optional<Eigen::Vector3f> vertex_color;
    if (tokens.size() == 6)
    {
        vertex_color = Eigen::Vector3f(std::stof(tokens[3]), std::stof(tokens[4]), std::stof(tokens[5]));
    }
    return {vertex, vertex_color};
};

/**
 * @brief Parse a line starting with 'vt ' from an obj file.
 *
 * A 'vt' line can contain either two ('u v') or three ('u v w') numbers. This parser currently only supports
 * 'u v'.
 */
inline Eigen::Vector2f parse_texcoords(const std::string& line)
{
    std::vector<std::string> tokens;
    tokenize(line, tokens, " ");
    if (tokens.size() != 2)
    {
        throw std::runtime_error("Encountered a texture coordinates ('vt') line that does not consist of two "
                                 "('u v') numbers. 'u v w' is not supported.");
    }
    const Eigen::Vector2f texcoords(std::stof(tokens[0]), std::stof(tokens[1]));
    return texcoords;
};

/**
 * @brief Parse a line starting with 'vn ' from an obj file.
 *
 * This is currently not implemented yet, as eos::core::Mesh doesn't store vertex normals anyway.
 */
inline void parse_vertex_normal(const std::string& line)
{
    throw std::runtime_error("Parsing \"vn\" is not yet implemented.");
};

/**
 * @brief Parse a line starting with 'f ' from an obj file.
 *
 * Note: Indices in obj's start at 1, not at 0.
 *
 * A face line contains 3 entries for triangles, but can be quads (=4 entries), and potentially more.
 * They're triplets of: vertex, texture and normal indices. Some of them can be missing. E.g.:
 *  f 1 2 3
 *  f 3/1 4/2 5/3
 *  f 6/4/1 3/5/3 7/6/5
 *  f 7//1 8//2 9//3
 */
inline auto parse_face(const std::string& line)
{
    using std::string;
    using std::vector;

    // Obj indices are 1-based.
    vector<int> vertex_indices;  // size() = 3 or 4
    vector<int> texture_indices; // size() = 3 or 4
    vector<int> normal_indices;  // size() = 3 or 4

    vector<string> tokens;
    tokenize(line, tokens, " ");
    if (tokens.size() != 3 && tokens.size() != 4)
    {
        // For now we need this to be 3 (triangles) or 4 (quads)
        throw std::runtime_error("Encountered a faces ('f') line that does not consist of three or four "
                                 "blocks of numbers. We currently only support 3 blocks (triangle meshes) "
                                 "and 4 blocks (quad meshes).");
    }
    // Now for each of these tokens, we want to split on "/":
    for (const auto& token : tokens)
    {
        vector<string> subtokens;
        tokenize(token, subtokens, "/", false); // don't trim empty -if we do, we lose positional information.
        assert(subtokens.size() > 0 && subtokens.size() <= 3);

        // There should always be a vertex index:
        vertex_indices.push_back(std::stoi(subtokens[0]) - 1); // obj indices are 1-based, so we subtract one.

        if (subtokens.size() == 2)
        {
            // We've got texture coordinate indices as well:
            texture_indices.push_back(std::stoi(subtokens[1]) - 1);
        }

        if (subtokens.size() == 3)
        {
            // We've got either texcoord indices *and* normal indices, or just normal indices:
            if (!subtokens[1].empty())
            {
                // We do have texcoord indices
                texture_indices.push_back(std::stoi(subtokens[1]) - 1);
            }
            // And push_back the normal indices:
            normal_indices.push_back(std::stoi(subtokens[2]) - 1);
            // Note if we use normal indices in the future: It looked like they can be zero in some cases?
        }
    }

    return std::make_tuple(vertex_indices, texture_indices, normal_indices);
};

} /* namespace detail */

/**
 * @brief Reads the given Wavefront .obj file into a \c Mesh.
 *
 * https://en.wikipedia.org/wiki/Wavefront_.obj_file as of 22 August 2017.
 *
 * @param[in] filename Input filename (ending in ".obj").
 * @return A Mesh with the data read from the obj file.
 */
inline Mesh read_obj(std::string filename)
{
    std::ifstream file(filename);
    if (!file)
    {
        throw std::runtime_error(std::string("Could not open obj file: " + filename));
    }

    // We'll need these helper functions for the parsing:
    const auto starts_with = [](const std::string& input, const std::string& match) {
        return input.size() >= match.size() && std::equal(match.begin(), match.end(), input.begin());
    };

    /*    auto trim_left = [](const std::string& input, std::string pattern = " \t") {
            auto first = input.find_first_not_of(pattern);
            if (first == std::string::npos)
            {
                return input;
            }
            return input.substr(first, input.size());
        }; */

    Mesh mesh;

    std::string line;
    while (getline(file, line))
    {
        if (starts_with(line, "#"))
        {
            continue;
        }

        if (starts_with(line, "v "))
        { // matching with a space so that it doesn't match 'vt'
            auto vertex_data =
                detail::parse_vertex(line.substr(2)); // pass the string without the first two characters
            mesh.vertices.push_back(
                Eigen::Vector3f(vertex_data.first[0], vertex_data.first[1], vertex_data.first[2]));
            if (vertex_data.second)
            { // there are vertex colours:
                mesh.colors.push_back(vertex_data.second.value());
            }
        }
        if (starts_with(line, "vt "))
        {
            const auto texcoords = detail::parse_texcoords(line.substr(3));
            mesh.texcoords.push_back(texcoords);
        }
        if (starts_with(line, "vn "))
        {
            // detail::parse_vertex_normal(line.substr(3));
            // Not handled yet, our Mesh class doesn't contain normals right now anyway.
        }
        // There's other things like "vp ", which we don't handle
        if (starts_with(line, "f "))
        {
            auto face_data = detail::parse_face(line.substr(2));
            if (std::get<0>(face_data).size() == 3) // 3 triangle indices, nothing to do:
            {
                mesh.tvi.push_back(
                    {std::get<0>(face_data)[0], std::get<0>(face_data)[1], std::get<0>(face_data)[2]});
            }
            // If their sizes are 4, we convert the quad to two triangles:
            // Actually I think MeshLab does the same, it shows the FaceWarehouse number of "Faces" as twice the "f" entries in the obj.
            else if (std::get<0>(face_data).size() == 4)
            {
                // Just create two faces with (quad[0], quad[1], quad[2]) and (quad[0], quad[2], quad[3]).
                mesh.tvi.push_back(
                    {std::get<0>(face_data)[0], std::get<0>(face_data)[1], std::get<0>(face_data)[2]});
                mesh.tvi.push_back(
                    {std::get<0>(face_data)[0], std::get<0>(face_data)[2], std::get<0>(face_data)[3]});
            }
            // We don't handle normal_indices for now.
        }
        // There can be other stuff in obj's like materials, named objects, etc., which are not handled here.
    }
    return mesh;
}

} /* namespace core */
} /* namespace eos */

#endif /* EOS_READ_OBJ_HPP */
<commit_msg>Simplify push_back<commit_after>/*
 * eos - A 3D Morphable Model fitting library written in modern C++11/14.
 *
 * File: include/eos/core/read_obj.hpp
 *
 * Copyright 2017, 2018 Patrik Huber
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#pragma once

#ifndef EOS_READ_OBJ_HPP
#define EOS_READ_OBJ_HPP

#include "eos/core/Mesh.hpp"
#include "eos/cpp17/optional.hpp"

#include "Eigen/Core"

#include <cassert>
#include <fstream>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

namespace eos {
namespace core {

namespace detail {

/**
 * @brief Splits a string into a list of tokens.
 *
 * Taken from: https://stackoverflow.com/a/1493195/1345959
 */
template <class ContainerType>
void tokenize(const std::string& str, ContainerType& tokens, const std::string& delimiters = " ",
              bool trim_empty = false)
{
    std::string::size_type pos, last_pos = 0;
    const auto length = str.length();

    using value_type = typename ContainerType::value_type;
    using size_type = typename ContainerType::size_type;

    while (last_pos < length + 1)
    {
        pos = str.find_first_of(delimiters, last_pos);
        if (pos == std::string::npos)
        {
            pos = length;
        }

        if (pos != last_pos || !trim_empty)
            tokens.push_back(value_type(str.data() + last_pos, (size_type)pos - last_pos));

        last_pos = pos + 1;
    }
};

/**
 * @brief Parse a line starting with 'v ' from an obj file.
 *
 * Can contain either 3 ('x y z') or 6 ('x y z r g b') numbers.
 * The 'v ' should have already been stripped from \p line.
 *
 * Notes:
 * Could actually potentially consist of 3, 4, 6 or 7 elements? (xyz, xyzw,
 * xyzrgb, xyzwrgb)
 * assimp only deals with 3, 4 or 6 elements:
 * https://github.com/assimp/assimp/blob/master/code/ObjFileParser.cpp#L138
 *
 * For now, we don't support obj's containing homogeneous coordinates.
 * What we could do is that if we do encounter homogeneous coords, we could just divide by 'w', like assimp
 * does.
 *
 * Another obj parser we can check: https://github.com/qnzhou/PyMesh/blob/master/src/IO/OBJParser.cpp (and
 * same file with .h)
 */
inline std::pair<Eigen::Vector3f, cpp17::optional<Eigen::Vector3f>> parse_vertex(const std::string& line)
{
    std::vector<std::string> tokens;
    tokenize(line, tokens, " ");
    if (tokens.size() != 3 && tokens.size() != 6)
    {
        throw std::runtime_error(
            "Encountered a vertex ('v') line that does not consist of either 3 ('x y z') "
            "or 6 ('x y z r g b') numbers.");
    }
    const Eigen::Vector3f vertex(std::stof(tokens[0]), std::stof(tokens[1]), std::stof(tokens[2]));
    cpp17::optional<Eigen::Vector3f> vertex_color;
    if (tokens.size() == 6)
    {
        vertex_color = Eigen::Vector3f(std::stof(tokens[3]), std::stof(tokens[4]), std::stof(tokens[5]));
    }
    return {vertex, vertex_color};
};

/**
 * @brief Parse a line starting with 'vt ' from an obj file.
 *
 * A 'vt' line can contain either two ('u v') or three ('u v w') numbers. This parser currently only supports
 * 'u v'.
 */
inline Eigen::Vector2f parse_texcoords(const std::string& line)
{
    std::vector<std::string> tokens;
    tokenize(line, tokens, " ");
    if (tokens.size() != 2)
    {
        throw std::runtime_error("Encountered a texture coordinates ('vt') line that does not consist of two "
                                 "('u v') numbers. 'u v w' is not supported.");
    }
    const Eigen::Vector2f texcoords(std::stof(tokens[0]), std::stof(tokens[1]));
    return texcoords;
};

/**
 * @brief Parse a line starting with 'vn ' from an obj file.
 *
 * This is currently not implemented yet, as eos::core::Mesh doesn't store vertex normals anyway.
 */
inline void parse_vertex_normal(const std::string& line)
{
    throw std::runtime_error("Parsing \"vn\" is not yet implemented.");
};

/**
 * @brief Parse a line starting with 'f ' from an obj file.
 *
 * Note: Indices in obj's start at 1, not at 0.
 *
 * A face line contains 3 entries for triangles, but can be quads (=4 entries), and potentially more.
 * They're triplets of: vertex, texture and normal indices. Some of them can be missing. E.g.:
 *  f 1 2 3
 *  f 3/1 4/2 5/3
 *  f 6/4/1 3/5/3 7/6/5
 *  f 7//1 8//2 9//3
 */
inline auto parse_face(const std::string& line)
{
    using std::string;
    using std::vector;

    // Obj indices are 1-based.
    vector<int> vertex_indices;  // size() = 3 or 4
    vector<int> texture_indices; // size() = 3 or 4
    vector<int> normal_indices;  // size() = 3 or 4

    vector<string> tokens;
    tokenize(line, tokens, " ");
    if (tokens.size() != 3 && tokens.size() != 4)
    {
        // For now we need this to be 3 (triangles) or 4 (quads)
        throw std::runtime_error("Encountered a faces ('f') line that does not consist of three or four "
                                 "blocks of numbers. We currently only support 3 blocks (triangle meshes) "
                                 "and 4 blocks (quad meshes).");
    }
    // Now for each of these tokens, we want to split on "/":
    for (const auto& token : tokens)
    {
        vector<string> subtokens;
        tokenize(token, subtokens, "/", false); // don't trim empty -if we do, we lose positional information.
        assert(subtokens.size() > 0 && subtokens.size() <= 3);

        // There should always be a vertex index:
        vertex_indices.push_back(std::stoi(subtokens[0]) - 1); // obj indices are 1-based, so we subtract one.

        if (subtokens.size() == 2)
        {
            // We've got texture coordinate indices as well:
            texture_indices.push_back(std::stoi(subtokens[1]) - 1);
        }

        if (subtokens.size() == 3)
        {
            // We've got either texcoord indices *and* normal indices, or just normal indices:
            if (!subtokens[1].empty())
            {
                // We do have texcoord indices
                texture_indices.push_back(std::stoi(subtokens[1]) - 1);
            }
            // And push_back the normal indices:
            normal_indices.push_back(std::stoi(subtokens[2]) - 1);
            // Note if we use normal indices in the future: It looked like they can be zero in some cases?
        }
    }

    return std::make_tuple(vertex_indices, texture_indices, normal_indices);
};

} /* namespace detail */

/**
 * @brief Reads the given Wavefront .obj file into a \c Mesh.
 *
 * https://en.wikipedia.org/wiki/Wavefront_.obj_file as of 22 August 2017.
 *
 * @param[in] filename Input filename (ending in ".obj").
 * @return A Mesh with the data read from the obj file.
 */
inline Mesh read_obj(std::string filename)
{
    std::ifstream file(filename);
    if (!file)
    {
        throw std::runtime_error(std::string("Could not open obj file: " + filename));
    }

    // We'll need these helper functions for the parsing:
    const auto starts_with = [](const std::string& input, const std::string& match) {
        return input.size() >= match.size() && std::equal(match.begin(), match.end(), input.begin());
    };

    /*    auto trim_left = [](const std::string& input, std::string pattern = " \t") {
            auto first = input.find_first_not_of(pattern);
            if (first == std::string::npos)
            {
                return input;
            }
            return input.substr(first, input.size());
        }; */

    Mesh mesh;

    std::string line;
    while (getline(file, line))
    {
        if (starts_with(line, "#"))
        {
            continue;
        }

        if (starts_with(line, "v "))
        { // matching with a space so that it doesn't match 'vt'
            auto vertex_data =
                detail::parse_vertex(line.substr(2)); // pass the string without the first two characters
            mesh.vertices.push_back(vertex_data.first);
            if (vertex_data.second)
            { // there are vertex colours:
                mesh.colors.push_back(vertex_data.second.value());
            }
        }
        if (starts_with(line, "vt "))
        {
            const auto texcoords = detail::parse_texcoords(line.substr(3));
            mesh.texcoords.push_back(texcoords);
        }
        if (starts_with(line, "vn "))
        {
            // detail::parse_vertex_normal(line.substr(3));
            // Not handled yet, our Mesh class doesn't contain normals right now anyway.
        }
        // There's other things like "vp ", which we don't handle
        if (starts_with(line, "f "))
        {
            auto face_data = detail::parse_face(line.substr(2));
            if (std::get<0>(face_data).size() == 3) // 3 triangle indices, nothing to do:
            {
                mesh.tvi.push_back(
                    {std::get<0>(face_data)[0], std::get<0>(face_data)[1], std::get<0>(face_data)[2]});
            }
            // If their sizes are 4, we convert the quad to two triangles:
            // Actually I think MeshLab does the same, it shows the FaceWarehouse number of "Faces" as twice the "f" entries in the obj.
            else if (std::get<0>(face_data).size() == 4)
            {
                // Just create two faces with (quad[0], quad[1], quad[2]) and (quad[0], quad[2], quad[3]).
                mesh.tvi.push_back(
                    {std::get<0>(face_data)[0], std::get<0>(face_data)[1], std::get<0>(face_data)[2]});
                mesh.tvi.push_back(
                    {std::get<0>(face_data)[0], std::get<0>(face_data)[2], std::get<0>(face_data)[3]});
            }
            // We don't handle normal_indices for now.
        }
        // There can be other stuff in obj's like materials, named objects, etc., which are not handled here.
    }
    return mesh;
}

} /* namespace core */
} /* namespace eos */

#endif /* EOS_READ_OBJ_HPP */
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: cachedprimitivebase.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: kz $ $Date: 2005-11-02 12:41:56 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef INCLUDED_CANVAS_CACHEDPRIMITIVEBASE_HXX
#define INCLUDED_CANVAS_CACHEDPRIMITIVEBASE_HXX

#ifndef _COM_SUN_STAR_UNO_REFERENCE_HXX_
#include <com/sun/star/uno/Reference.hxx>
#endif
#ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_
#include <com/sun/star/lang/XServiceInfo.hpp>
#endif
#ifndef _COM_SUN_STAR_RENDERING_XCANVAS_HPP_
#include <com/sun/star/rendering/XCanvas.hpp>
#endif
#ifndef _COM_SUN_STAR_RENDERING_XCACHEDPRIMITIVE_HPP_
#include <com/sun/star/rendering/XCachedPrimitive.hpp>
#endif
#ifndef _COM_SUN_STAR_RENDERING_VIEWSTATE_HPP__
#include <com/sun/star/rendering/ViewState.hpp>
#endif

#ifndef _CPPUHELPER_COMPBASE2_HXX_
#include <cppuhelper/compbase2.hxx>
#endif
#ifndef _COMPHELPER_BROADCASTHELPER_HXX_
#include <comphelper/broadcasthelper.hxx>
#endif

/* Definition of CachedPrimitiveBase class */

namespace canvas
{
    typedef ::cppu::WeakComponentImplHelper2< ::com::sun::star::rendering::XCachedPrimitive,
                                                   ::com::sun::star::lang::XServiceInfo > CachedPrimitiveBase_Base;

    /** Base class, providing common functionality for implementers of
        the XCachedPrimitive interface.
     */
    class CachedPrimitiveBase : public CachedPrimitiveBase_Base,
                                public ::comphelper::OBaseMutex
    {
    public:

        /** Create an XCachedPrimitive for given target canvas

            @param rUsedViewState
            The viewstate the original object was rendered with

            @param rTarget
            The target canvas the repaint should happen on.

            @param bFailForChangedViewTransform
            When true, derived classes will never receive doRedraw()
            calls with dissimilar view transformations and
            bSameViewTransform set to false. This is useful for cached
            objects where re-transforming the generated output is not
            desirable, e.g. for hinted font output.
         */
        CachedPrimitiveBase( const ::com::sun::star::rendering::ViewState&  rUsedViewState,
                             const ::com::sun::star::uno::Reference<
                                    ::com::sun::star::rendering::XCanvas >& rTarget,
                             bool                                           bFailForChangedViewTransform );

        /// Dispose all internal references
        virtual void SAL_CALL disposing();

        // XCachedPrimitive
        virtual ::sal_Int8 SAL_CALL redraw( const ::com::sun::star::rendering::ViewState& aState ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);

        // XServiceInfo
        virtual ::rtl::OUString SAL_CALL getImplementationName(  ) throw (::com::sun::star::uno::RuntimeException);
        virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (::com::sun::star::uno::RuntimeException);
        virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames(  ) throw (::com::sun::star::uno::RuntimeException);

    protected:
        ~CachedPrimitiveBase(); // we're a ref-counted UNO class. _We_ destroy ourselves.

    private:
        CachedPrimitiveBase( const CachedPrimitiveBase& );
        CachedPrimitiveBase& operator=( const CachedPrimitiveBase& );

        /** Actually perform the requested redraw.

            Clients must override this method, instead of the public
            redraw() one.

            @param rNewState
            The viewstate to redraw with

            @param rOldState
            The viewstate this cache object was created with.

            @param rTargetCanvas
            Target canvas to render to.

            @param bSameViewTransform
            When true, rNewState and rOldState have the same transformation.
         */
        virtual ::sal_Int8 doRedraw( const ::com::sun::star::rendering::ViewState&  rNewState,
                                     const ::com::sun::star::rendering::ViewState&  rOldState,
                                     const ::com::sun::star::uno::Reference<
                                         ::com::sun::star::rendering::XCanvas >&    rTargetCanvas,
                                     bool                                           bSameViewTransform ) = 0;

        ::com::sun::star::rendering::ViewState                                      maUsedViewState;
        ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvas >    mxTarget;
        const bool                                                                  mbFailForChangedViewTransform;
    };
}

#endif /* INCLUDED_CANVAS_CACHEDPRIMITIVEBASE_HXX */
<commit_msg>INTEGRATION: CWS changefileheader (1.2.136); FILE MERGED 2008/04/01 15:03:02 thb 1.2.136.3: #i85898# Stripping all external header guards 2008/04/01 10:49:25 thb 1.2.136.2: #i85898# Stripping all external header guards 2008/03/28 16:34:52 rt 1.2.136.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: cachedprimitivebase.hxx,v $
 * $Revision: 1.3 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef INCLUDED_CANVAS_CACHEDPRIMITIVEBASE_HXX
#define INCLUDED_CANVAS_CACHEDPRIMITIVEBASE_HXX

#include <com/sun/star/uno/Reference.hxx>
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/rendering/XCanvas.hpp>
#include <com/sun/star/rendering/XCachedPrimitive.hpp>
#include <com/sun/star/rendering/ViewState.hpp>
#include <cppuhelper/compbase2.hxx>
#include <comphelper/broadcasthelper.hxx>

/* Definition of CachedPrimitiveBase class */

namespace canvas
{
    typedef ::cppu::WeakComponentImplHelper2< ::com::sun::star::rendering::XCachedPrimitive,
                                                   ::com::sun::star::lang::XServiceInfo > CachedPrimitiveBase_Base;

    /** Base class, providing common functionality for implementers of
        the XCachedPrimitive interface.
     */
    class CachedPrimitiveBase : public CachedPrimitiveBase_Base,
                                public ::comphelper::OBaseMutex
    {
    public:

        /** Create an XCachedPrimitive for given target canvas

            @param rUsedViewState
            The viewstate the original object was rendered with

            @param rTarget
            The target canvas the repaint should happen on.

            @param bFailForChangedViewTransform
            When true, derived classes will never receive doRedraw()
            calls with dissimilar view transformations and
            bSameViewTransform set to false. This is useful for cached
            objects where re-transforming the generated output is not
            desirable, e.g. for hinted font output.
         */
        CachedPrimitiveBase( const ::com::sun::star::rendering::ViewState&  rUsedViewState,
                             const ::com::sun::star::uno::Reference<
                                    ::com::sun::star::rendering::XCanvas >& rTarget,
                             bool                                           bFailForChangedViewTransform );

        /// Dispose all internal references
        virtual void SAL_CALL disposing();

        // XCachedPrimitive
        virtual ::sal_Int8 SAL_CALL redraw( const ::com::sun::star::rendering::ViewState& aState ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException);

        // XServiceInfo
        virtual ::rtl::OUString SAL_CALL getImplementationName(  ) throw (::com::sun::star::uno::RuntimeException);
        virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) throw (::com::sun::star::uno::RuntimeException);
        virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames(  ) throw (::com::sun::star::uno::RuntimeException);

    protected:
        ~CachedPrimitiveBase(); // we're a ref-counted UNO class. _We_ destroy ourselves.

    private:
        CachedPrimitiveBase( const CachedPrimitiveBase& );
        CachedPrimitiveBase& operator=( const CachedPrimitiveBase& );

        /** Actually perform the requested redraw.

            Clients must override this method, instead of the public
            redraw() one.

            @param rNewState
            The viewstate to redraw with

            @param rOldState
            The viewstate this cache object was created with.

            @param rTargetCanvas
            Target canvas to render to.

            @param bSameViewTransform
            When true, rNewState and rOldState have the same transformation.
         */
        virtual ::sal_Int8 doRedraw( const ::com::sun::star::rendering::ViewState&  rNewState,
                                     const ::com::sun::star::rendering::ViewState&  rOldState,
                                     const ::com::sun::star::uno::Reference<
                                         ::com::sun::star::rendering::XCanvas >&    rTargetCanvas,
                                     bool                                           bSameViewTransform ) = 0;

        ::com::sun::star::rendering::ViewState                                      maUsedViewState;
        ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XCanvas >    mxTarget;
        const bool                                                                  mbFailForChangedViewTransform;
    };
}

#endif /* INCLUDED_CANVAS_CACHEDPRIMITIVEBASE_HXX */
<|endoftext|>


<commit_before>// Copyright (c) 2015 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include "../el_poll.h"
#include "../el_internal.h"
#include "el_linux_epoll.h"

namespace el {

Epoll::Epoll(void)
  : epoll_fd_(EL_NETINVAL)
  , event_count_(EVENT_COUNT)
  , events_(nullptr) {
  EL_ASSERT(Init(), "linux epoll init failed ...");
}

Epoll::~Epoll(void) {
  Destroy();
}

bool Epoll::Init(void) {
  if (EL_NETINVAL == (epoll_fd_ = epoll_create(EPOLL_COUNT)))
    return false;

  event_count_ = EVENT_COUNT;
  size_t size = sizeof(struct epoll_event) * event_count_;

  do {
    if (nullptr == (events_ = (struct epoll_event*)malloc(size)))
      break;

    return true;
  } while (0);

  Destroy();
  return false;
}

void Epoll::Destroy(void) {
  if (nullptr != events_) {
    free(events_);
    events_ = nullptr;
  }
  event_count_ = EVENT_COUNT;

  if (EL_NETINVAL != epoll_fd_) {
    close(epoll_fd_);
    epoll_fd_ = EL_NETINVAL;
  }
}

bool Epoll::Regrow(void) {
  uint32_t new_event_count = (0 != event_count_ ?
      2 * event_count_ : EVENT_COUNT);
  size_t size = sizeof(struct epoll_event) * new_event_count;

  events_ = (struct epoll_event*)realloc(events_, size);
  EL_ASSERT(nullptr != events_, "epoll regrow failed ...");

  event_count_ = new_event_count;
  return true;
}

bool Epoll::Insert(Connector& c) {
  return true;
}

void Epoll::Remove(Connector& c) {
}

bool Epoll::AddEvent(Connector& c, EventType event) {
  return true;
}

bool Epoll::DelEvent(Connector& c, EventType event) {
  return true;
}

bool Epoll::Dispatch(Dispatcher& dispatcher, uint32_t timeout) {
  return true;
}

}
<commit_msg>implementation of the epoll module for linux platform<commit_after>// Copyright (c) 2015 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include "../el_poll.h"
#include "../el_internal.h"
#include "el_linux_epoll.h"

namespace el {

Epoll::Epoll(void)
  : epoll_fd_(EL_NETINVAL)
  , event_count_(EVENT_COUNT)
  , events_(nullptr) {
  EL_ASSERT(Init(), "linux epoll init failed ...");
}

Epoll::~Epoll(void) {
  Destroy();
}

bool Epoll::Init(void) {
  if (EL_NETINVAL == (epoll_fd_ = epoll_create(EPOLL_COUNT)))
    return false;

  event_count_ = EVENT_COUNT;
  size_t size = sizeof(struct epoll_event) * event_count_;

  do {
    if (nullptr == (events_ = (struct epoll_event*)malloc(size)))
      break;

    return true;
  } while (0);

  Destroy();
  return false;
}

void Epoll::Destroy(void) {
  if (nullptr != events_) {
    free(events_);
    events_ = nullptr;
  }
  event_count_ = EVENT_COUNT;

  if (EL_NETINVAL != epoll_fd_) {
    close(epoll_fd_);
    epoll_fd_ = EL_NETINVAL;
  }
}

bool Epoll::Regrow(void) {
  uint32_t new_event_count = (0 != event_count_ ?
      2 * event_count_ : EVENT_COUNT);
  size_t size = sizeof(struct epoll_event) * new_event_count;

  events_ = (struct epoll_event*)realloc(events_, size);
  EL_ASSERT(nullptr != events_, "epoll regrow failed ...");

  event_count_ = new_event_count;
  return true;
}

bool Epoll::Insert(Connector& c) {
  struct epoll_event event;
  event.events = 0;
  event.data.ptr = &c;

  if (EL_NETERR == epoll_ctl(epoll_fd_,
        EPOLL_CTL_ADD, c.fd(), &event))
    return false;

  // add EPOLLET into connector
  // TODO:
  return true;
}

void Epoll::Remove(Connector& c) {
  struct epoll_event event;
  event.events = c.events();
  event.data.ptr = &c;

  epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, c.fd(), &event);
}

bool Epoll::AddEvent(Connector& c, EventType event) {
  struct epoll_event add_event;
  add_event.events = c.events();
  add_event.data.ptr = &c;

  if (event == EventType::EVENTTYPE_READ)
    add_event.events |= EPOLLIN;
  if (event == EventType::EVENTTYPE_WRITE)
    add_event.events |= EPOLLOUT;

  if (EL_NETERR == epoll_ctl(epoll_fd_,
        EPOLL_CTL_MOD, c.fd(), &add_event))
    return false;

  // add add_event.events into connector
  // TODO:
  return true;
}

bool Epoll::DelEvent(Connector& c, EventType event) {
  struct epoll_event del_event;
  del_event.events = c.events();
  del_event.data.ptr = &c;

  if (event == EventType::EVENTTYPE_READ)
    del_event.events &= ~EPOLLIN;
  if (event == EventType::EVENTTYPE_WRITE)
    del_event.events &= ~EPOLLOUT;

  if (EL_NETERR == epoll_ctl(epoll_fd_,
        EPOLL_CTL_MOD, c.fd(), &del_event))
    return false;

  // add del_event.events into connector
  // TODO:
  return true;
}

bool Epoll::Dispatch(Dispatcher& dispatcher, uint32_t timeout) {
  int num = epoll_wait(epoll_fd_, events_, event_count_, timeout);
  if (EL_NETERR == num || 0 == num)
    return false;

  Connector* c;
  for (auto i = 0; i < num; ++i) {
    c = static_cast<Connector*>(events_[i].data.ptr);
    if (nullptr == c)
      continue;

    if (EL_NETINVAL == c->fd())
      continue;
    if (events_[i].events & EPOLLIN)
      dispather.DispatchReader(*this, *c);

    if (EL_NETINVAL == c->fd())
      continue;
    if (events_[i].events & EPOLLOUT)
      dispatcher.DispatchWriter(*this, *c);
  }

  if (static_cast<uint32_t>(num) == event_count_)
    Regrow();

  return true;
}

}
<|endoftext|>