diff --git a/src/lib/accesscasted.hpp b/src/lib/access-casted.hpp similarity index 88% rename from src/lib/accesscasted.hpp rename to src/lib/access-casted.hpp index b6832f37f..1a5d69f72 100644 --- a/src/lib/accesscasted.hpp +++ b/src/lib/access-casted.hpp @@ -1,5 +1,5 @@ /* - ACCESSCASTED.hpp - util template to access a value using conversion or cast as appropriate + ACCESS-CASTED.hpp - util template to access a value using conversion or cast as appropriate Copyright (C) Lumiera.org 2008, Hermann Vosseler @@ -21,13 +21,13 @@ */ -/** @file accesscasted.hpp - ** Helper for accessing a value employing either conversion or downcast +/** @file access-casted.hpp + ** Helper for accessing a value, employing either conversion or downcast, ** depending on the relation of the source type (type of the original value) ** and the target type (type we need within the usage context). ** When instantiating AcessCasted, we get a template static function ** \c AcessCasted::access(SRC& elm), but the actual implementation - ** is chosen using boost::type_traits. If no viable implementation can be + ** is chosen using boost::type_traits. If no sensible implementation can be ** selected, \c EmptyVal::create() is invoked instead, which by default ** creates a NULL value or similar by using the no-argument ctor of the ** type TAR. Alternatively, you may define an specialisation of EmptyVal, @@ -38,8 +38,8 @@ */ -#ifndef UTIL_ACCESSCASTED_H -#define UTIL_ACCESSCASTED_H +#ifndef UTIL_ACCESS_CASTED_H +#define UTIL_ACCESS_CASTED_H #include #include @@ -143,23 +143,23 @@ namespace util { template static typename enable_if< use_dynamic_downcast, TAR>::type - access (ELM& elem) - { - return dynamic_cast (elem); + access (ELM& elem) + { + return dynamic_cast (elem); } template static typename enable_if< use_static_downcast, TAR>::type - access (ELM& elem) - { - return static_cast (elem); + access (ELM& elem) + { + return static_cast (elem); } template static typename enable_if< use_conversion, TAR>::type - access (ELM& elem) - { - return elem; + access (ELM& elem) + { + return elem; } }; diff --git a/src/lib/bool-checkable.hpp b/src/lib/bool-checkable.hpp new file mode 100644 index 000000000..d10a1a150 --- /dev/null +++ b/src/lib/bool-checkable.hpp @@ -0,0 +1,121 @@ +/* + BOOL-CHECKABLE.hpp - mixin template for defining a safe conversion to bool + + Copyright (C) Lumiera.org + 2009, Hermann Vosseler + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + + +/** @file bool-checkable.hpp + ** When working with generic function objects and function pointers typed to + ** arbitrary signatures, often there is the necessity to hold onto such a functor + ** while hiding the actual signature behind an common interface ("type erasure"). + ** The usual solution based on subclassing has the downside of requiring separate + ** storage for the concrete functor object, which might become problematic when + ** dealing with lots of functor objects. + ** + ** Especially when dealing with tr1::function objects, all of the type differences + ** are actually encoded into 3 internal pointers, thus yielding the same size for + ** all various types of functors. Building on this observation, we can create an + ** common container object to store the varying functors inline, while hiding the + ** actual signature. + ** + ** There remains the problem of re-accessing the concrete functor later on. As + ** C++ has only rudimental introspection capabilities, we can only rely on the + ** usage context to provide the correct function signature; only when using a + ** virtual function for the re-access, we can perform at least a runtime-check. + ** + ** Thus there are various flavours for actually implementing this idea, and the + ** picking a suitable implementation depends largely on the context. Thus we + ** provide a common and expect the client code to pick an implementation policy. + ** + ** @see control::Mutation usage example + ** @see function-erasure-test.cpp + ** + */ + + +#ifndef LIB_BOOL_CHECKABLE_H +#define LIB_BOOL_CHECKABLE_H + + + +namespace lib { + + + + + /* + * Provide an implicit conversion to "bool". + * Inherit (mix-in) from this template by providing the + * concrete subclass type ("CRTP"). Additionally, to implement + * the specific logic of this bool check, the subclass using this + * template must provide a public function \c isValid() + * + * \par safe bool conversion + * Generally speaking, a direct automatic conversion to bool would be + * a dangerous feature, because bool is considered an "integral type" in C. + * Thus, you'd not only get the ability to write very expressive checks + * like \c if(object) -- you would also get automatic conversions to int + * where you'd never expect them. In C++ there is a well-known idiom to + * circumvent this problem. Unfortunately, this idiom isn't easy to + * grasp, involving the convoluted syntax of member pointers. + * So we try to hide away these details into a mixin. + * + * The idea this implementation is based on is the fact that a + * pointer-to-member is "somewhat a pointer" but not \em really a pointer. + * Similar to a pointer, a member pointer can be \em unbound, and this + * is the property we exploit here. But implementation-wise, a member pointer + * is a type information plus an offset into this type, and thus can't be + * converted to an integral type. Thus, depending on the result of the + * \c isValid() function, the conversion operator returns either a + * bound or unbound member pointer. + * + * @todo list some usage examples here + * @see bool-checkable-test.cpp + */ + template + struct BoolCheckable + { + typedef bool (T::*ValidityCheck)() const; + typedef ValidityCheck _unspecified_bool_type; + + /** implicit conversion to "bool" */ + operator _unspecified_bool_type() const ///< never throws + { + ValidityCheck isValid (&T::isValid); + T const& obj = static_cast (*this); + + return (obj.*isValid)()? isValid : 0; + } + + bool operator! () const ///< never throws + { + ValidityCheck isValid (&T::isValid); + T const& obj = static_cast (*this); + + return !(obj.*isValid)(); + } + + }; + + + + +} // namespace lib +#endif diff --git a/src/lib/frameid.hpp b/src/lib/frameid.hpp index 9cb95eb37..8f961b959 100644 --- a/src/lib/frameid.hpp +++ b/src/lib/frameid.hpp @@ -31,14 +31,14 @@ namespace lumiera /** - * Identification tuple for addressing frames unambiguosly. + * Identification tuple for addressing frames unambiguously. * * @todo currently (7/08) this is a dummy implementation to find out * what interface the Proc layer needs. Probably the backend will * later on define what is actually needed; this header should then * be replaced by a combined C/C++ header */ - class FrameID : boost::totally_ordered + class FrameID : boost::totally_ordered ////////////TODO it seems we don't need total ordering, only comparison. Clarify this! { long dummy; public: diff --git a/src/lib/wrapperptr.hpp b/src/lib/wrapperptr.hpp index db168cba1..ed4b43b82 100644 --- a/src/lib/wrapperptr.hpp +++ b/src/lib/wrapperptr.hpp @@ -27,7 +27,7 @@ #include "lib/variant.hpp" -#include "lib/accesscasted.hpp" +#include "lib/access-casted.hpp" #include "lib/meta/typelist.hpp" #include "proc/mobject/placement.hpp" diff --git a/src/proc/engine/nodeinvocation.hpp b/src/proc/engine/nodeinvocation.hpp index 8b350d382..33801eb4f 100644 --- a/src/proc/engine/nodeinvocation.hpp +++ b/src/proc/engine/nodeinvocation.hpp @@ -96,7 +96,7 @@ namespace engine { virtual BuffHandle fetch (FrameID const& fID) { return current_.fetch (fID); } - // note: allocateBuffer() is choosen specifically based on the actual node wiring + // note: allocateBuffer() is chosen specifically based on the actual node wiring }; @@ -110,7 +110,7 @@ namespace engine { * which form the actual invocation sequence. The various operations in this sequence * access the context via the references in this struct, while also using the inherited * public State interface. The object instance actually used as Invocation is created - * on the stack and parametrized according to the necessities of the invocation sequence + * on the stack and parametrised according to the necessities of the invocation sequence * actually configured. Initially, this real instance is configured without BuffTable, * because the invocation may be short-circuited due to Cache hit. Otherwise, when * the invocation sequence actually prepares to call the process function of this diff --git a/src/proc/state.hpp b/src/proc/state.hpp index a4a95edb7..e021d5890 100644 --- a/src/proc/state.hpp +++ b/src/proc/state.hpp @@ -50,7 +50,7 @@ namespace engine { * Intended as a performance shortcut to avoid calling * up through a chain of virtual functions when deep down * in chained ProcNode::pull() calls. This allows derived - * classes to proxy the state inteface. + * classes to proxy the state interface. */ virtual State& getCurrentImplementation () =0; @@ -62,7 +62,7 @@ namespace engine { * on the State implementation; it could be a temporary, located in * the cache, used for feeding calculated frames over a network, etc. * @return a BuffHandle encapsulating the information necessary to get - * at the actual buffer adress and for releasing the buffer. + * at the actual buffer address and for releasing the buffer. */ virtual BuffHandle allocateBuffer (BufferDescriptor const&) =0; @@ -79,7 +79,7 @@ namespace engine { /** try to fetch an existing buffer containing the denoted frame from * a cache or similar backing system (e.g. peer over the network). * @return either a handle to a readonly buffer, or a null handle - * @note the client is resposible for not modifying the provided data + * @note the client is responsible for not modifying the provided data */ virtual BuffHandle fetch (FrameID const&) =0; diff --git a/src/tool/try.cpp b/src/tool/try.cpp index f2496df9c..de0d698f9 100644 --- a/src/tool/try.cpp +++ b/src/tool/try.cpp @@ -17,7 +17,7 @@ #include //#include "include/nobugcfg.h" -#include "lib/meta/function-erasure.hpp" +#include "lib/bool-checkable.hpp" #include //#include @@ -37,7 +37,7 @@ using boost::format; } struct TestIt1 - : lumiera::typelist::BoolCheckable + : lib::BoolCheckable { int val_; diff --git a/tests/40components.tests b/tests/40components.tests index ba3050091..72174a526 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -2,18 +2,39 @@ TESTING "Component Test Suite: common and basic components" ./test-lib --group=c -TEST "Hello test" HelloWorld_test 3 < + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "lib/test/run.hpp" +#include "lib/bool-checkable.hpp" +#include "lib/test/test-helper.hpp" + +#include + +using std::cout; +using lib::test::showSizeof; + + +namespace lib { +namespace test{ + + /** + * An example custom type, + * which provides an implicit bool conversion + * to express some special validity check. + */ + + class ExampleCustomType123 + : public lib::BoolCheckable + { + + int val_; + + public: + + ExampleCustomType123 (int i) + : val_(i) + { } + + /** implements the custom logic to decide + * if this instance can be considered "valid" + */ + bool + isValid() const + { + return val_ % 3; + } + + }; + + + + + /********************************************************** + * @test verify the implementation of a validity check, + * to be accessed as an implicit conversion to bool. + * + * @see lib::BoolCheckable + * @todo list some usage examples here + */ + class BoolCheckable_test : public Test + { + + virtual void + run (Arg) + { + for (int i=1; i<16; ++i) + { + ExampleCustomType123 test (i); + + if (!test) + cout << "doIt \n"; + if (test) + cout << i << "\n"; + + ASSERT (test.isValid() == bool(test) ); + ASSERT (test.isValid() != !test); + } + + cout << showSizeof() <<"\n"; + ASSERT (sizeof (int) == sizeof (ExampleCustomType123)); + } + }; + + + /** Register this test class... */ + LAUNCHER (BoolCheckable_test, "unit common"); + + +}} // namespace lib::test