Forked from
ogs / ogs
11987 commits behind the upstream repository.
-
Dmitri Naumov authored
StringTools.h and FileTools.h mostly. fstream in few places.
Dmitri Naumov authoredStringTools.h and FileTools.h mostly. fstream in few places.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
Algorithm.h 9.47 KiB
/**
* \file
*
* \copyright
* Copyright (c) 2012-2020, OpenGeoSys Community (http://www.opengeosys.org)
* Distributed under a Modified BSD License.
* See accompanying file LICENSE.txt or
* http://www.opengeosys.org/project/license
*/
#pragma once
#include <algorithm>
#include <boost/optional.hpp>
#include <cassert>
#include <typeindex>
#include <typeinfo>
#include "Error.h"
#include "StringTools.h"
namespace BaseLib
{
/// excludeObjectCopy copies only those objects that position within the source
/// vector is not in the exclude_positions vector. The implementation of the
/// algorithm requires that the given positions in exclude_positions are sorted
/// in ascending order.
/// @param src_vec the vector of source objects
/// @param exclude_positions the positions of objects in the source vector that
/// do not have to be copied
/// @return vector that contains the copied objects
template <typename T>
std::vector<T> excludeObjectCopy(
std::vector<T> const& src_vec,
std::vector<std::size_t> const& exclude_positions)
{
std::vector<T> dest_vec;
if (exclude_positions.empty())
{
dest_vec = src_vec;
return dest_vec;
}
assert(exclude_positions.back() < src_vec.size());
std::copy_n(src_vec.cbegin(), exclude_positions[0],
std::back_inserter(dest_vec));
for (std::size_t i = 1; i < exclude_positions.size(); ++i)
{
std::copy_n(src_vec.cbegin() + exclude_positions[i - 1] + 1,
exclude_positions[i] - (exclude_positions[i - 1] + 1),
std::back_inserter(dest_vec));
}
std::copy(src_vec.cbegin() + exclude_positions.back() + 1, src_vec.cend(),
std::back_inserter(dest_vec));
return dest_vec;
}
template <typename T>
void excludeObjectCopy(std::vector<T> const& src_vec,
std::vector<std::size_t> const& exclude_positions,
std::vector<T>& dest_vec)
{
dest_vec = excludeObjectCopy(src_vec, exclude_positions);
}
template <typename InputIt, typename Predicate>
typename std::iterator_traits<InputIt>::reference findElementOrError(
InputIt begin, InputIt end, Predicate predicate,
std::string const& error = "")
{
auto it = std::find_if(begin, end, predicate);
if (it == end)
{
OGS_FATAL("Element not found in the input range; {:s}", error.c_str());
}
return *it;
}
//! Inserts the given \c key with the given \c value into the \c map if an entry
//! with the
//! given \c key does not yet exist; otherwise an \c error_message is printed
//! and the
//! program is aborted.
//! Note: The type of \c key must be std::type_index.
template <typename Map, typename Key, typename Value>
void insertIfTypeIndexKeyUniqueElseError(Map& map, Key const& key,
Value&& value,
std::string const& error_message)
{
auto const inserted = map.emplace(key, std::forward<Value>(value));
if (!inserted.second)
{ // insertion failed, i.e., key already exists
OGS_FATAL("{:s} Key `{:s}' already exists.", error_message.c_str(),
tostring(key.hash_code()).c_str());
}
}
//! Inserts the given \c key with the given \c value into the \c map if an entry
//! with the
//! given \c key does not yet exist; otherwise an \c error_message is printed
//! and the
//! program is aborted.
template <typename Map, typename Key, typename Value>
void insertIfKeyUniqueElseError(Map& map, Key const& key, Value&& value,
std::string const& error_message)
{
auto const inserted = map.emplace(key, std::forward<Value>(value));
if (!inserted.second)
{ // insertion failed, i.e., key already exists
OGS_FATAL("{:s} Key `{:s}' already exists.", error_message.c_str(),
tostring(key).c_str());
}
}
//! Inserts the given \c key with the given \c value into the \c map if neither
//! an entry
//! with the given \c key nor an entry with the given \c value already exists;
//! otherwise an \c error_message is printed and the program is aborted.
template <typename Map, typename Key, typename Value>
void insertIfKeyValueUniqueElseError(Map& map, Key const& key, Value&& value,
std::string const& error_message)
{
auto value_compare = [&value](typename Map::value_type const& elem) {
return value == elem.second;
};
if (std::find_if(map.cbegin(), map.cend(), value_compare) != map.cend())
{
OGS_FATAL("{:s} Value `{:s}' already exists.", error_message.c_str(),
tostring(value).c_str());
}
auto const inserted = map.emplace(key, std::forward<Value>(value));
if (!inserted.second)
{ // insertion failed, i.e., key already exists
OGS_FATAL("{:s} Key `{:s}' already exists.", error_message.c_str(),
tostring(key).c_str());
}
}
//! Returns the value of \c key from the given \c map if such an entry exists;
//! otherwise an \c error_message is printed and the program is aborted.
//! Cf. also the const overload below.
//! \remark Use as: \code{.cpp} get_or_error<Value>(some_map, some_key, "error
//! message") \endcode
template <typename Map, typename Key>
typename Map::mapped_type& getOrError(Map& map, Key const& key,
std::string const& error_message)
{
auto it = map.find(key);
if (it == map.end())
{
OGS_FATAL("{:s} Key `{:s}' does not exist.", error_message.c_str(),
tostring(key).c_str());
}
return it->second;
}
//! \overload
template <typename Map, typename Key>
typename Map::mapped_type const& getOrError(Map const& map, Key const& key,
std::string const& error_message)
{
auto it = map.find(key);
if (it == map.end())
{
OGS_FATAL("{:s} Key `{:s}' does not exist.", error_message.c_str(),
tostring(key).c_str());
}
return it->second;
}
//! Returns the value of from the given \c container if such an entry fulfilling
//! the \c predicate exists;
//! otherwise an \c error_message is printed and the program is aborted.
template <typename Container, typename Predicate>
typename Container::value_type const& getIfOrError(
Container const& container,
Predicate&& predicate,
std::string const& error_message)
{
auto it = std::find_if(begin(container), end(container), predicate);
if (it == end(container))
{
OGS_FATAL("Could not find element matching the predicate: {:s}",
error_message.c_str());
}
return *it;
}
/// Make the entries of the std::vector \c v unique. The remaining entries will
/// be sorted.
template <typename T>
void makeVectorUnique(std::vector<T>& v)
{
std::sort(v.begin(), v.end());
auto it = std::unique(v.begin(), v.end());
v.erase(it, v.end());
}
/// Make the entries of the std::vector \c v unique using the given binary
/// function. The remaining entries will be sorted.
template <typename T, class Compare>
void makeVectorUnique(std::vector<T>& v, Compare comp)
{
std::sort(v.begin(), v.end(), comp);
auto it = std::unique(v.begin(), v.end());
v.erase(it, v.end());
}
/**
* Reorder a vector by a given index vector.
*
* Note: It is good enough in performance for medium size vectors.
*/
template <typename ValueType, typename IndexType>
void reorderVector(std::vector<ValueType>& v,
std::vector<IndexType> const& order)
{
std::vector<ValueType> temp_v(v.size());
temp_v.swap(v);
for (std::size_t i=0; i<order.size(); i++)
{
std::swap(v[i], temp_v[order[i]]);
}
}
template <typename Container>
void uniquePushBack(Container& container,
typename Container::value_type const& element)
{
if (std::find(container.begin(), container.end(), element) ==
container.end())
{
container.push_back(element);
}
}
template <typename Container>
bool contains(Container const& container,
typename Container::value_type const& element)
{
return std::find(container.begin(), container.end(), element) !=
container.end();
}
template <typename Container, typename Predicate>
bool containsIf(Container const& container, Predicate&& predicate)
{
return std::find_if(container.begin(), container.end(), predicate) !=
container.end();
}
template <typename Container>
boost::optional<typename Container::value_type> findFirstNotEqualElement(
Container const& container, typename Container::value_type const& element)
{
auto const it =
std::find_if_not(container.begin(), container.end(),
[&element](typename Container::value_type const& e) {
return e == element;
});
return it == container.end() ? boost::none : boost::make_optional(*it);
}
/// Returns the index of first element in container or, if the element is not
/// found a std::size_t maximum value.
///
/// The maximum value of std::size_t is chosen, because such an index cannot
/// exist in a container; the maximum index is std::size_t::max-1.
template <typename Container>
std::size_t findIndex(Container const& container,
typename Container::value_type const& element)
{
auto const it = std::find(container.begin(), container.end(), element);
if (it == container.end())
{
return std::numeric_limits<std::size_t>::max();
}
return std::distance(container.begin(), it);
}
} // namespace BaseLib