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:
parent
740f3d0211
commit
727fdd8691
4 changed files with 308 additions and 1 deletions
167
src/lib/util-coll.hpp
Normal file
167
src/lib/util-coll.hpp
Normal 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*/
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
133
tests/library/util-collection-test.cpp
Normal file
133
tests/library/util-collection-test.cpp
Normal 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
|
||||
|
||||
Loading…
Reference in a new issue