diff --git a/src/lib/util-coll.hpp b/src/lib/util-coll.hpp new file mode 100644 index 000000000..e3246f433 --- /dev/null +++ b/src/lib/util-coll.hpp @@ -0,0 +1,167 @@ +/* + UTIL-COLL.hpp - helpers and convenience shortcuts for working with collections + + Copyright (C) Lumiera.org + 2012, 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 util-coll.hpp + ** Some small helpers and convenience shortcuts to ease working with + ** collections and sequences (given by iterator). Mostly, these are tiny bits of + ** existing functionality, just packaged in a more fluent and readable way. + ** - accessors + ** - \c first() to get the first element + ** - \c last() to access the last element + ** + ** @warning some functions only available when including itertools.hpp beforehand + ** + ** @see util-collection-test.cpp + ** @see util-foreach.hpp + ** + */ + + +#ifndef UTIL_COLL_H +#define UTIL_COLL_H + +#include "lib/util.hpp" +#include "lib/meta/trait.hpp" + +#include + + + +namespace util { + + using boost::enable_if; + using boost::disable_if; + + namespace { // predicates to pick the right implementation + + using lib::meta::Yes_t; + using lib::meta::No_t; + + template + struct treat_as_STL_Container + { + typedef typename lib::meta::Unwrap::Type TaT; + + enum{ value = lib::meta::can_STL_ForEach::value + &&!lib::meta::can_IterForEach::value + }; + }; + + template + struct treat_as_LumieraIterator + { + enum{ value = lib::meta::can_IterForEach::value + }; + }; + + template + struct can_direct_access_Last + { + typedef typename lib::meta::Unwrap::Type TaT; + + enum{ value = lib::meta::can_STL_backIteration::value + }; + }; + + + template + inline void + __ensure_nonempty(COL const& coll) + { + if (util::isnil(coll)) + throw lumiera::error::Logic("attempt to access the first element of an empty collection" + ,lumiera::error::LUMIERA_ERROR_BOTTOM_VALUE); + } + } + + + + + /* === specialisations for STL-like containers and Lumiera Forward Iterators === */ + + /** access the first element of a STL-like container. + * @note the container is taken by \c const& and + * the \c const is \em stripped before access. + */ + template + inline typename enable_if< treat_as_STL_Container, + typename COLL::reference >::type + first (COLL const& coll) + { + using lib::meta::unwrap; + + __ensure_nonempty(coll); + return *(unwrap(coll).begin()); + } + + + /** access the last element of a STL-like container. + * @note the container is taken by \c const& and + * the \c const is \em stripped before access. + */ + template + inline typename enable_if< can_direct_access_Last, + typename COLL::reference >::type + last (COLL const& coll) + { + using lib::meta::unwrap; + + __ensure_nonempty(coll); + return *(unwrap(coll).rbegin()); + } + + + + /** extract the first element yielded by an Lumiera Forward Iterator. + * @warning the iterator is modified. + */ + template + inline typename enable_if< treat_as_LumieraIterator, + typename IT::reference >::type + first (IT ii) + { + __ensure_nonempty(ii); + return *ii; + } + + +#ifdef LIB_ITERTOOLS_H + /** extract the last element yielded by an Lumiera Forward Iterator. + * @warning the iterator is extracted until exhaustion (linear complexity). + * @note returning by-value, contrary to the other tools in this suite + * @note only available when including itertools.hpp beforehand + */ + template + inline typename enable_if< treat_as_LumieraIterator, + typename IT::value_type >::type + last (IT ii) + { + __ensure_nonempty(ii); + return lib::pull_last (ii); + } +#endif + + + +} // namespace util +#endif /*UTIL_COLL_H*/ diff --git a/tests/40core.tests b/tests/40core.tests index 5152d4f68..0922946ec 100644 --- a/tests/40core.tests +++ b/tests/40core.tests @@ -1420,6 +1420,11 @@ out: :0:1$ END +TEST "collection utils" UtilCollection_test < @@ -42,6 +43,7 @@ using test::Test; using util::isnil; +using util::last; using std::vector; using std::tr1::function; //using std::cout; @@ -204,8 +206,8 @@ namespace test { vector plannedChunk; lib::append_all (jobs, plannedChunk); + Duration coveredTime (Offset(refPoint, last(plannedChunk).getNominalTime())); #if false /////////////////////////////////////////////////////////////////////////////////////////////////////////////UNIMPLEMENTED :: TICKET #880 - Duration coveredTime (refPoint, last(plannedChunk).getNominalTime()); CHECK (coveredTime >= timings.getPlanningChunkDuration()); TimeVar nextFrameStart (refPoint); diff --git a/tests/library/util-collection-test.cpp b/tests/library/util-collection-test.cpp new file mode 100644 index 000000000..dd98144b6 --- /dev/null +++ b/tests/library/util-collection-test.cpp @@ -0,0 +1,133 @@ +/* + UtilCollection(Test) - helpers and shortcuts for working with collections + + Copyright (C) Lumiera.org + 2012, 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. + +* *****************************************************/ + + +#include "lib/test/run.hpp" +#include "lib/itertools.hpp" +#include "lib/util-coll.hpp" +#include "lib/iter-adapter.hpp" +#include "lib/meta/trait.hpp" + + +#include +#include + + +using ::Test; + +using util::first; +using util::last; + +using lib::meta::can_STL_ForEach; +using lib::meta::can_IterForEach; +using lib::meta::can_STL_backIteration; + +using boost::lexical_cast; + + + +namespace util { +namespace test { + + typedef std::vector VecI; + typedef lib::RangeIter RangeI; + + + + namespace{ // Test data and operations + + uint NUM_ELMS = 20; + + VecI + someNumberz (uint count) + { + VecI numbers; + numbers.reserve(count); + while (count) + numbers.push_back(count--); + + return numbers; + } + + } // (End) test data and operations + + + + /********************************************************************* + * @test verify some convenience shortcuts and helpers dealing + * with Collections and sequences (Iterators). + * - metafunctions to distinguish STL containers and Lumiera Iterators + * - get the first element + * - get the last element + */ + class UtilCollection_test : public Test + { + + void + run (Arg arg) + { + verify_typeDetectors(); + + if (0 < arg.size()) NUM_ELMS = lexical_cast (arg[0]); + + VecI container = someNumberz (NUM_ELMS); + RangeI iterator(container.begin(), container.end()); + + verify_accessFirstLast (container, NUM_ELMS); + verify_accessFirstLast (iterator, NUM_ELMS); + } + + + template + void + verify_accessFirstLast (COL const& col, uint lim) + { + uint theFirst = lim; + uint theLast = 1; + + CHECK (first(col) == theFirst); + CHECK (last(col) == theLast); + } + + + void + verify_typeDetectors() + { + CHECK ( can_STL_ForEach::value); + CHECK ( can_STL_backIteration::value); + + CHECK (!can_STL_ForEach::value); + CHECK (!can_STL_backIteration::value); + + CHECK (!can_IterForEach::value); + CHECK ( can_IterForEach::value); + } + }; + + + + + LAUNCHER (UtilCollection_test, "unit common"); + + +}} // namespace util::test +