diff options
Diffstat (limited to 'meowpp/utility/factory.h')
-rw-r--r-- | meowpp/utility/factory.h | 383 |
1 files changed, 383 insertions, 0 deletions
diff --git a/meowpp/utility/factory.h b/meowpp/utility/factory.h new file mode 100644 index 0000000..8e350a0 --- /dev/null +++ b/meowpp/utility/factory.h @@ -0,0 +1,383 @@ +/*! + * @file factory.h + * @brief Contains a base class for a factory. + * + * A factory contains an array of inputs, an array of outputs and an operation. + * You can update some elements in the array of inputs and then call + * `Factory::Update()` to update the outputs (it will run the operation only if + * some input elements are changed since last update). + * + * @author cathook + */ + +#ifndef __MEOWPP_UTILITY_FACTORY_H__ +#define __MEOWPP_UTILITY_FACTORY_H__ + +#include "operation.h" +#include "pointer.h" +#include "self.h" + + +namespace meow { + +namespace factory_types { + + +/*! + * @brief A base class for kinds of factory classes. + */ +class Base { + protected: + struct BaseData { + Pointer<Operation const> oper; + Pointer<Pointer<Object const>> inputs; + Pointer<Pointer<Object>> outputs; + + //! An array with each elements points to the input elements with + //! non-constant type. + Pointer<Pointer<Object>> non_const_inputs; + + //! An array with each elements points to the output elements with + //! constant type. + Pointer<Pointer<Object const>> const_outputs; + + /*! + * @brief Constructor. + * @param [in] arg_oper The operation this factory should run. + * @param [in] arg_inputs A pointer points to the array of the input + * elements. + * @param [in] arg_outputs A pointer points to the array of the output + * elements. + */ + BaseData(Pointer<Operation const> const& arg_oper, + Pointer<Pointer<Object const>> const& arg_inputs, + Pointer<Pointer<Object>> const& arg_outputs): + oper(arg_oper), + inputs(arg_inputs), + outputs(arg_outputs), + non_const_inputs(new Pointer<Object>[oper->inputs_size()], ARRAY, true), + const_outputs( + new Pointer<Object const>[oper->outputs_size()], ARRAY, true) { + for (int i = 0, i_max = oper->inputs_size(); i < i_max; ++i) { + non_const_inputs[i] = Pointer<Object>( + const_cast<Object*>(inputs[i].address()), SINGLE, false); + } + for (int i = 0, i_max = oper->outputs_size(); i < i_max; ++i) { + const_outputs[i] = Pointer<Object const>( + outputs[i].address(), SINGLE, false); + } + }; + }; + + Base() {} + + public: + virtual ~Base() {} + + /*! + * @brief Updates the output elements by re-run the operation. + */ + virtual State Update() const = 0; + + /*! + * @brief Returns whether the last time calling `Update()` did update really + * or not. + * + * If the input elements were not changed before `Update()` be called, it + * might be returns false (depends on how it implements). + */ + virtual bool HasRedo() const = 0; + + /*! + * @brief Gets the operation. + */ + virtual Pointer<Operation const> operation() const = 0; + + /*! + * @brief Gets the pointer points to the array of input elements. + */ + virtual Pointer<Pointer<Object>> inputs() const = 0; + + /*! + * @brief Gets the pointer points to the array of output elements. + */ + virtual Pointer<Pointer<Object const>> outputs() const = 0; +}; + + +/*! + * An implement of the factory class. + * + * When the function `Update()` be called, no matter whether the input elements + * has changed or not, it will do the operation. + */ +class CheckOff : public Base { + private: + struct Data : Base::BaseData { + Data(Pointer<Operation const> const& arg_oper, + Pointer<Pointer<Object const>> const& arg_inputs, + Pointer<Pointer<Object>> const& arg_outputs) : + BaseData(arg_oper, arg_inputs, arg_outputs) {} + }; + + Self<Data> const self_; + + public: + + /*! + * @brief Constructor. + * @param [in] arg_oper The operation for this factory to run. + * @param [in] arg_inputs A pointer points to the array of the pointer points + * to the input elements. + * @param [in] arg_outputs A pointer points to the array of the pointer points + * to the output elements. + */ + CheckOff(Pointer<Operation const> const& arg_oper, + Pointer<Pointer<Object const>> const& arg_inputs, + Pointer<Pointer<Object>> const& arg_outputs) : + self_(Data(arg_oper, arg_inputs, arg_outputs)) {} + + /*! + * @brief Updates the output elements by running the operation. + */ + State Update() const { + return self_->oper->Operate(self_->inputs, self_->outputs); + } + + /*! + * @brief It will always return true. + */ + bool HasRedo() const { + return true; + } + + /*! + * @brief Gets the operation. + */ + virtual Pointer<Operation const> operation() const { + return self_->oper; + } + + /*! + * @brief Gets the pointer points to the array of input elements. + */ + Pointer<Pointer<Object>> inputs() const { + return self_->non_const_inputs; + } + + /*! + * @brief Gets the pointer points to the array of output elements. + */ + Pointer<Pointer<Object const>> outputs() const { + return self_->const_outputs; + } + +}; + + +/*! + * An implement of the factory class. + * + * It will check whether the input elements has changed before running the + * operation. + */ +class CheckOn : public Base { + private: + struct Data : Base::BaseData { + //! Stores the last input elements which are using to check whether the + //! input elements have changed or not. + Pointer<Pointer<Object>> old_inputs; + + //! Stores the state returned by the operation last time. + State last_state; + + //! Stores whether the last `Update()` run the operation or not. + bool has_redo; + + //! Stores whether it has not run the `Update()` yet. + bool first_time; + + Data(Pointer<Operation const> const& arg_oper, + Pointer<Pointer<Object const>> const& arg_inputs, + Pointer<Pointer<Object>> const& arg_outputs) : + BaseData(arg_oper, arg_inputs, arg_outputs), + old_inputs(new Pointer<Object>[oper->inputs_size()], ARRAY, true), + has_redo(false), + first_time(true) { + for (int i = 0, i_max = oper->inputs_size(); i < i_max; ++i) { + old_inputs[i] = Pointer<Object>(inputs[i]->Copy(), SINGLE, true); + } + } + }; + + Self<Data> const self_; + + public: + + /*! + * @brief Constructor. + * @param [in] arg_oper The operation this factory should run. + * @param [in] arg_inputs A pointer points to the array of the input + * elements. + * @param [in] arg_outputs A pointer points to the array of the output + * elements. + */ + CheckOn(Pointer<Operation const> const& arg_oper, + Pointer<Pointer<Object const>> const& arg_inputs, + Pointer<Pointer<Object>> const& arg_outputs) : + self_(Data(arg_oper, arg_inputs, arg_outputs)) {} + + /*! + * @brief Updates the output elements if needs. + * + * It will check whether the input elements different from the old ones first. + */ + State Update() const { + bool needs_to_update = self_->first_time; + if (!needs_to_update) { + for (int i = 0, i_max = self_->oper->inputs_size(); i < i_max; ++i) { + Object const* old = self_->old_inputs[i].address(); + Object const* cur = self_->inputs[i].address(); + if (!old->Equals(cur)) { + needs_to_update = true; + break; + } + } + } + if (!needs_to_update) { + self_()->has_redo = false; + } else { + for (int i = 0, i_max = self_->oper->inputs_size(); i < i_max; ++i) { + Object* old = self_->old_inputs[i].address(); + Object const* cur = self_->inputs[i].address(); + old->CopyFrom(cur); + } + self_()->last_state = self_->oper->Operate(self_->inputs, self_->outputs); + self_()->has_redo = true; + } + self_()->first_time = false; + return self_->last_state; + } + + /*! + * @brief Returns whether the output elements have been re-generated by + * running the operation again. + * + * It will check whether the input elements different from the old ones first. + */ + bool HasRedo() const { + return self_->has_redo; + } + + /*! + * @brief Gets the operation. + */ + virtual Pointer<Operation const> operation() const { + return self_->oper; + } + + /*! + * @brief Gets the array of the input elements. + */ + Pointer<Pointer<Object>> inputs() const { + return self_->non_const_inputs; + } + + /*! + * @brief Gets the array of the output elements. + */ + Pointer<Pointer<Object const>> outputs() const { + return self_->const_outputs; + } + +}; + +} // factory_types + + +/*! + * @brief A class which contains input elements, output elements and an + * operation. + */ +class Factory : public Object { + private: + + Pointer<factory_types::Base> factory_; + + public: + + /*! + * @brief Constructor. + */ + Factory(Pointer<Operation const> const& arg_oper, + Pointer<Pointer<Object const>> const& arg_inputs, + Pointer<Pointer<Object>> const& arg_outputs, + bool arg_check_before_update) { + if (arg_check_before_update) { + factory_ = Pointer<factory_types::Base>( + new factory_types::CheckOn( + arg_oper, arg_inputs, arg_outputs), SINGLE, true); + } else { + factory_ = Pointer<factory_types::Base>( + new factory_types::CheckOff( + arg_oper, arg_inputs, arg_outputs), SINGLE, true); + } + } + + /*! + * @brief Updates the output elements. + */ + State Update() const { + return factory_->Update(); + } + + /*! + * @brief Returns whether the output elements have been re-generated by + * running the operation again. + */ + bool HasRedo() const { + return factory_->HasRedo(); + } + + /*! + * @brief Gets the operation. + */ + Pointer<Operation const> operation() const { + return factory_->operation(); + } + + /*! + * @brief Gets the array of the input elements. + */ + Pointer<Pointer<Object>> inputs() const { + return factory_->inputs(); + } + + /*! + * @brief Gets the array of the output elements. + */ + Pointer<Pointer<Object const>> outputs() const { + return factory_->outputs(); + } + + Object* Copy() const { + return NULL; + } + + Object* CopyFrom(Object const* another_factory) { + return NULL; + } + + bool Equals(Object const* another_factory) { + return false; + } + +#ifdef MEOWPP_UTILITY_FACTORY_TESTING + friend class FactoryTest; +#endif + +}; + +} // meow + +#endif // __MEOWPP_UTILITY_FACTORY_H__ |