/* 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 ** - util::first() to get the first element ** - util::last() to access the last element ** - aggregate functions ** - util::max() compute the maximum of comparable numbers ** - util::min() ** ** @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 lib::meta::enable_if; using lib::meta::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 enable_if< treat_as_STL_Container, typename COLL::reference > 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 enable_if< can_direct_access_Last, typename COLL::reference > 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 enable_if< treat_as_LumieraIterator, typename IT::reference > 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 enable_if< treat_as_LumieraIterator, typename IT::value_type > last (IT ii) { __ensure_nonempty(ii); return lib::pull_last (ii); } #endif /* === generic container helpers === */ template inline auto max (IT&& elms) { using Val = typename std::remove_reference_t::value_type; Val res = std::numeric_limits::min(); for (auto const& elm : std::forward (elms)) if (elm > res) res = elm; return res; } template inline auto max (CON const& elms) { using Val = typename std::remove_reference_t::value_type; Val res = std::numeric_limits::min(); for (auto const& elm : elms) if (elm > res) res = elm; return res; } template inline auto min (IT&& elms) { using Val = typename std::remove_reference_t::value_type; Val res = std::numeric_limits::max(); for (auto const& elm : std::forward (elms)) if (elm < res) res = elm; return res; } template inline auto min (CON const& elms) { using Val = typename std::remove_reference_t::value_type; Val res = std::numeric_limits::max(); for (auto const& elm : elms) if (elm < res) res = elm; return res; } } // namespace util #endif /*UTIL_COLL_H*/