add convenience shortcut to access a collection's last element

actually two accessor functinons first() and last(),
which automatically pick a proper implementation,
either by iteration or by direct access
This commit is contained in:
Fischlurch 2013-01-13 16:49:20 +01:00
parent 740f3d0211
commit 727fdd8691
4 changed files with 308 additions and 1 deletions

167
src/lib/util-coll.hpp Normal file
View file

@ -0,0 +1,167 @@
/*
UTIL-COLL.hpp - helpers and convenience shortcuts for working with collections
Copyright (C) Lumiera.org
2012, Hermann Vosseler <Ichthyostega@web.de>
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 <boost/utility/enable_if.hpp>
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<typename T>
struct treat_as_STL_Container
{
typedef typename lib::meta::Unwrap<T>::Type TaT;
enum{ value = lib::meta::can_STL_ForEach<TaT>::value
&&!lib::meta::can_IterForEach<T>::value
};
};
template<typename T>
struct treat_as_LumieraIterator
{
enum{ value = lib::meta::can_IterForEach<T>::value
};
};
template<typename T>
struct can_direct_access_Last
{
typedef typename lib::meta::Unwrap<T>::Type TaT;
enum{ value = lib::meta::can_STL_backIteration<TaT>::value
};
};
template<typename COL>
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 <typename COLL>
inline typename enable_if< treat_as_STL_Container<COLL>,
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 <typename COLL>
inline typename enable_if< can_direct_access_Last<COLL>,
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 <typename IT>
inline typename enable_if< treat_as_LumieraIterator<IT>,
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 <typename IT>
inline typename enable_if< treat_as_LumieraIterator<IT>,
typename IT::value_type >::type
last (IT ii)
{
__ensure_nonempty(ii);
return lib::pull_last (ii);
}
#endif
} // namespace util
#endif /*UTIL_COLL_H*/

View file

@ -1420,6 +1420,11 @@ out: :0:1$
END
TEST "collection utils" UtilCollection_test <<END
return: 0
END
TEST "VectorTransfer_test" VectorTransfer_test <<END
return: 0
END

View file

@ -33,6 +33,7 @@
#include "lib/time/timequant.hpp"
#include "lib/singleton.hpp"
#include "lib/itertools.hpp"
#include "lib/util-coll.hpp"
#include "lib/util.hpp"
//#include <boost/scoped_ptr.hpp>
@ -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<Job> 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);

View file

@ -0,0 +1,133 @@
/*
UtilCollection(Test) - helpers and shortcuts for working with collections
Copyright (C) Lumiera.org
2012, Hermann Vosseler <Ichthyostega@web.de>
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 <boost/lexical_cast.hpp>
#include <vector>
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<uint> VecI;
typedef lib::RangeIter<VecI::iterator> 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<uint> (arg[0]);
VecI container = someNumberz (NUM_ELMS);
RangeI iterator(container.begin(), container.end());
verify_accessFirstLast (container, NUM_ELMS);
verify_accessFirstLast (iterator, NUM_ELMS);
}
template<class COL>
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<VecI>::value);
CHECK ( can_STL_backIteration<VecI>::value);
CHECK (!can_STL_ForEach<RangeI>::value);
CHECK (!can_STL_backIteration<RangeI>::value);
CHECK (!can_IterForEach<VecI>::value);
CHECK ( can_IterForEach<RangeI>::value);
}
};
LAUNCHER (UtilCollection_test, "unit common");
}} // namespace util::test