aboutsummaryrefslogtreecommitdiffstats
path: root/meowpp/utility/factory.h
diff options
context:
space:
mode:
Diffstat (limited to 'meowpp/utility/factory.h')
-rw-r--r--meowpp/utility/factory.h383
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__