diff --git a/libwccl/ops/operator.h b/libwccl/ops/operator.h index 5997c5ab8c67d04806fbf712f83601fcd5252b15..19dc17e2ecb51e3d9b7c9d35855cccd42c39f39b 100644 --- a/libwccl/ops/operator.h +++ b/libwccl/ops/operator.h @@ -1,50 +1,345 @@ #ifndef LIBWCCL_OPS_OPERATOR_H #define LIBWCCL_OPS_OPERATOR_H -#include <libcorpus2/tagset.h> -#include <unicode/unistr.h> -#include <boost/noncopyable.hpp> +#include <boost/scoped_ptr.hpp> + +#include <libwccl/ops/parsedexpression.h> +#include <libwccl/ops/functions.h> +#include <libwccl/ops/constant.h> namespace Wccl { /** - * Abstract base class for WCCL operators + * Abstract base class for WCCL expressions that are functional + * operators */ -class Operator : public boost::noncopyable { +class FunctionalOperator : public ParsedExpression +{ public: /** - * Name of the Operator, in general a tagset is required, - * but some classes might not need that, so by default just forward - * to raw_operator_name(); + * Applies the functional operator to given sentence context. + * @returns Result of the application, in terms of base type of Value. */ - virtual const std::string operator_name(const Corpus2::Tagset& /*tagset*/) const { - return raw_operator_name(); - } + virtual boost::shared_ptr<const Value> base_apply(const SentenceContext& sc) = 0; + /** - * Name of the Operator that does not require a tagset, - * might be incomplete and/or contain internal info. - * - * Prefer operator_name(tagset). + * @returns A copy of the expression, with values of the variables + * copied as well. + * @see clone_clean_ptr - convenience version that returns clean copy. */ - virtual const std::string raw_operator_name() const = 0; + boost::shared_ptr<FunctionalOperator> clone_ptr() const; + /** - * String representation of the operator, by default it's just - * the name of the operator returned by operator_name(tagset) + * @returns A copy of the expression, with values of the variables + * set to their defaults. + * @see clone_ptr - a version that keeps values of the variables. */ - virtual std::string to_string(const Corpus2::Tagset& tagset) const { - return operator_name(tagset); - } + boost::shared_ptr<FunctionalOperator> clone_clean_ptr() const; + +protected: + explicit FunctionalOperator(const Variables& variables); + + FunctionalOperator* clone_internal() const = 0; +}; + + +/** + * Represents a parsed WCCL functional operator that returns a value of given type. + * @note The class methods are not thread-safe, but you can use clone method + * to acquire a separate copy of the Operator, and the copy can be used concurrently. + * @todo need to change copying of Variables once a clone method is available for them. + */ +template <class T> +class Operator : public FunctionalOperator, public detail::PtrCleanCloneable<Operator<T> > +{ +public: + Operator(const boost::shared_ptr<Function<T> >& body, const Variables& variables); + /** - * String representation of the operator that does not require a tagset, - * might be incomplete and/or contain internal info. - * - * By default it is just the raw_operator_name() + * Applies the functional operator to given sentence context. + * @returns Result of the application of this operator. + * @param sc SentenceContext of the Sentence to apply the operator to. + * @note The result is conciously marked as const, so a copy of operator data + * is not created unless necessary. + * @see apply() - equivalent method; the \link operator()() operator() \endlink allows + * more convenient functional notation, however if you only have a pointer + * you might prefer the apply method as shown below. The choice is yours. + * \code + * shared_ptr<const Bool> b; + * b = op(sc); + * // versus + * b = op.apply(sc); + * // or if you have a pointer... + * b = (*op_ptr)(sc); + * // versus + * b = op_ptr->apply(sc); + * \endcode + * @see copy_apply() - method that creates and returns a copy of the result + * for you to modify as you may see fit if you need it; + * this is convenience method over having to create a copy yourself. */ - virtual std::string to_raw_string() const { - return raw_operator_name(); - } + boost::shared_ptr<const T> operator()(const SentenceContext& sc); + + /** + * Applies the functional operator to given sentence context. + * @returns Result of the application of this operator. + * @param sc SentenceContext of the Sentence to apply the operator to. + * @note The result is conciously marked as const, so a copy of operator data + * is not created unless necessary. + * @see \link operator()() operator() \endlink - an equivalent of this method that allows for functional + * notation, treating Operator directly as a function + * @see copy_apply - method that creates and returns a copy of the result + * for you to modify as you may see fit if you need it; + * this is convenience method over having to create a copy yourself. + */ + boost::shared_ptr<const T> apply(const SentenceContext& sc); + + /** + * Applies the functional operator to given sentence context, returning pointer + * to a mutable Value. + * @returns Result of the application of this operator. + * @param sc SentenceContext of the Sentence to apply the operator to. + * @see \link operator()() operator() \endlink, apply - you may still be + * better off using them if you expect to work on a raw value rather + * than a pointer, as in e.g. + * \code + * StrSet s = *op(sc); + * StrSet s2 = *op_ptr->apply(sc); + * StrSet s3 = *(*op_ptr)(sc); // included for completeness + * //versus + * shared_ptr<StrSet> s_ptr = op.copy_apply(sc); + * shared_ptr<StrSet> s_ptr2 = op_ptr->copy_apply(sc); + * \endcode + */ + boost::shared_ptr<T> copy_apply(const SentenceContext& sc); + + /** + * Applies the functional operator to given sentence context. + * @returns Result of the application, in terms of base type of Value. + * @see \link operator()() operator() \endlink, apply - since you have + * a concrete type at hand, you probably want to use one of these + * two instead of this method that is inherited from FunctionalOperator + */ + boost::shared_ptr<const Value> base_apply(const SentenceContext& sc); + + /** + * Makes a copy of the Operator, having its own space for Variables. + * This allows the copy to be run concurrently (otherwise methods + * of this class are not thread-safe; concurrent executions + * on the same object would share Variables so don't do that). + * @returns A copy of the Operator, including copy of Variables' values. + * @note The values of the Variables are copied as they are, which is + * a usable feature. If that is not what you want, use clone_clean() + * or call clean() when you need it. + * @see clone_clean - a convenience version that returns a copy with + * all Variables set to their default values. + * @see clone_ptr - a version that returns a copy wrapped in a shared + * pointer + * @see clone_clean_ptr - a version that returns a copy wrapped + * in a shared pointer, and also having its Variables cleaned. + * @see \link Operator(const Operator&, bool) copy constructor \endlink - + * another way to create a copy + * @see \link operator=(const Operator&) operator= \endlink - assignment + * operator, yet another way to create a copy. + */ + Operator clone() const; + + /** + * Makes a copy of the Operator, having its own space for Variables. + * This allows the copy to be run concurrently (otherwise methods + * of this class are not thread-safe; concurrent executions + * on the same object would share Variables so don't do that). + * All the Variables in the copy will have default values. + * @returns A copy of the Operator with Variables that have default + * values. + * @see clone - a version that returns a copy without cleaning Variables. + * @see clone_ptr - a version that returns a copy wrapped in a shared + * pointer + * @see clone_clean_ptr - a version that returns a copy wrapped + * in a shared pointer, and also having its Variables cleaned. + */ + Operator clone_clean() const; + + /** + * @returns A copy of the expression, with values of the variables + * copied as well. + * @see clone_clean_ptr - convenience version that returns clean copy. + */ + boost::shared_ptr<Operator<T> > clone_ptr() const; + + /** + * @returns A copy of the expression, with values of the variables + * set to their defaults. + * @see clone_ptr - a version that keeps values of the variables. + */ + boost::shared_ptr<Operator<T> > clone_clean_ptr() const; + + /** + * Copy constructor, creates a copy with new set of values for + * variables, allowing concurrent run of semantically same Operator; + * running same physical Operator object is inherently not thread safe). + * @param other - the Operator to copy. + * @param clean - true if copy needs to have its variables + * set to default values, false to keep the values; false is default + */ + Operator(const Operator& other, bool clean = false); + + /** + * Default constructor. Produces operator that returns default + * value for given type. + */ + Operator(); + + /** + * Assignment operator to create a workable copy of other Operator + * (workable means it has a new set of values for variables, allowing + * concurrent run of semantically same Operator; running same physical + * Operator object is inherently not thread safe). + * @note The values for variables are kept as in the original Operator. + * @param other - Operator to copy + * @returns A reference to the current object, after assignment. + */ + Operator& operator=(const Operator& other); + + std::string to_string(const Corpus2::Tagset& tagset) const; + + std::string to_raw_string() const; + +protected: + Operator* clone_internal() const; + +private: + boost::shared_ptr<Function<T> > function_body_; }; +//--- implementation details --- + +inline +FunctionalOperator::FunctionalOperator( + const Variables &variables) + : ParsedExpression(variables) +{ +} + +inline +boost::shared_ptr<FunctionalOperator> FunctionalOperator::clone_ptr() const { + return boost::shared_ptr<FunctionalOperator>(clone_internal()); +} + +inline +boost::shared_ptr<FunctionalOperator> FunctionalOperator::clone_clean_ptr() const { + boost::shared_ptr<FunctionalOperator> copy(clone_internal()); + BOOST_ASSERT(copy); + copy->clean(); + return copy; +} + +template <class T> inline +Operator<T>::Operator( + const boost::shared_ptr<Function<T> >& body, + const Variables &variables) + : FunctionalOperator(variables), + function_body_(body) +{ + BOOST_ASSERT(body); +} + +template <class T> inline +boost::shared_ptr<const T> Operator<T>::apply(const SentenceContext &sc) { + return function_body_->apply(FunExecContext(sc, variables_)); +} + +template <class T> inline +boost::shared_ptr<const T> Operator<T>::operator()(const SentenceContext &sc) { + return apply(sc); +} + +template <class T> inline +boost::shared_ptr<T> Operator<T>::copy_apply(const SentenceContext &sc) { + return boost::make_shared<T>(*apply(sc)); +} + +template <class T> inline +boost::shared_ptr<const Value> Operator<T>::base_apply(const SentenceContext &sc) { + return apply(sc); +} + +template <class T> inline +Operator<T>* Operator<T>::clone_internal() const { + return new Operator<T>(function_body_, *variables_); +} + +template <class T> inline +Operator<T>::Operator(const Operator &other, bool clean) + : FunctionalOperator(*other.variables_), + function_body_(other.function_body_) +{ + BOOST_ASSERT(function_body_); + if(clean) { + this->clean(); + } +} + +template <class T> inline +Operator<T> Operator<T>::clone() const { + return *this; +} + +template <class T> inline +Operator<T> Operator<T>::clone_clean() const { + return Operator(*this, true); +} + +template <class T> inline +Operator<T>& Operator<T>::operator=(const Operator& other) { + BOOST_ASSERT(other.function_body_); + BOOST_ASSERT(other.variables_); + function_body_.reset(other.function_body_); + variables_.reset(new Variables(other.variables_)); + return *this; +} + +namespace detail { + +template<class T> +static boost::shared_ptr<Function<T> > DefaultFunction() { + static boost::shared_ptr<Function<T> > default_fun(new Constant<T>((T()))); + return default_fun; +} + +} + +template <class T> inline +Operator<T>::Operator() + : FunctionalOperator((Variables())), + function_body_(detail::DefaultFunction<T>()) +{ + BOOST_ASSERT(function_body_); +} + +template <class T> inline +boost::shared_ptr<Operator<T> > Operator<T>::clone_ptr() const { + return boost::shared_ptr<Operator<T> >(clone_internal()); +} + +template <class T> inline +boost::shared_ptr<Operator<T> > Operator<T>::clone_clean_ptr() const { + boost::shared_ptr<Operator<T> > copy(clone_internal()); + BOOST_ASSERT(copy); + copy->clean(); + return copy; +} + +template <class T> inline +std::string Operator<T>::to_string(const Corpus2::Tagset &tagset) const { + return function_body_->to_string(tagset); +} + +template <class T> inline +std::string Operator<T>::to_raw_string() const { + return function_body_->to_raw_string(); +} + } /* end ns Wccl */ #endif // LIBWCCL_OPS_OPERATOR_H