mirror of https://github.com/mamba-org/mamba.git
Some renaming in the utility library (#2387)
Rename vector_set > flat_set, move util_compare > util/compare, move util_cast > util/cast
This commit is contained in:
parent
aa8d28c6c5
commit
07477a25fe
|
@ -191,6 +191,11 @@ endforeach()
|
|||
|
||||
set(LIBMAMBA_PUBLIC_HEADERS
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/version.hpp
|
||||
# Utility library
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/util/flat_set.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/util/graph.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/util/compare.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/util/cast.hpp
|
||||
# Implementation of version and matching specs
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/specs/version.hpp
|
||||
# Core API (low-level)
|
||||
|
@ -230,13 +235,10 @@ set(LIBMAMBA_PUBLIC_HEADERS
|
|||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/url.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/util.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/fsutil.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/util_graph.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/util_os.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/util_random.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/util_scope.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/util_string.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/util_cast.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/util_compare.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/validate.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/virtual_packages.hpp
|
||||
${LIBMAMBA_INCLUDE_DIR}/mamba/core/env_lockfile.hpp
|
||||
|
|
|
@ -22,7 +22,7 @@ extern "C" // Incomplete header
|
|||
|
||||
#include "mamba/core/package_info.hpp"
|
||||
#include "mamba/core/pool.hpp"
|
||||
#include "mamba/core/util_graph.hpp"
|
||||
#include "mamba/util/graph.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
@ -73,7 +73,7 @@ namespace mamba
|
|||
{
|
||||
public:
|
||||
|
||||
using dependency_graph = DiGraph<PackageInfo>;
|
||||
using dependency_graph = util::DiGraph<PackageInfo>;
|
||||
|
||||
query_result(QueryType type, const std::string& query, dependency_graph&& dep_graph);
|
||||
|
||||
|
|
|
@ -23,7 +23,8 @@
|
|||
|
||||
#include "mamba/core/match_spec.hpp"
|
||||
#include "mamba/core/package_info.hpp"
|
||||
#include "mamba/core/util_graph.hpp"
|
||||
#include "mamba/util/flat_set.hpp"
|
||||
#include "mamba/util/graph.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
@ -32,11 +33,11 @@ namespace mamba
|
|||
class MPool;
|
||||
|
||||
template <typename T>
|
||||
class conflict_map : private std::unordered_map<T, vector_set<T>>
|
||||
class conflict_map : private std::unordered_map<T, util::flat_set<T>>
|
||||
{
|
||||
public:
|
||||
|
||||
using Base = std::unordered_map<T, vector_set<T>>;
|
||||
using Base = std::unordered_map<T, util::flat_set<T>>;
|
||||
using typename Base::const_iterator;
|
||||
using typename Base::key_type;
|
||||
using typename Base::value_type;
|
||||
|
@ -47,7 +48,7 @@ namespace mamba
|
|||
using Base::empty;
|
||||
using Base::size;
|
||||
bool has_conflict(const key_type& a) const;
|
||||
auto conflicts(const key_type& a) const -> const vector_set<T>&;
|
||||
auto conflicts(const key_type& a) const -> const util::flat_set<T>&;
|
||||
bool in_conflict(const key_type& a, const key_type& b) const;
|
||||
|
||||
using Base::cbegin;
|
||||
|
@ -89,7 +90,7 @@ namespace mamba
|
|||
|
||||
using edge_t = MatchSpec;
|
||||
|
||||
using graph_t = DiGraph<node_t, edge_t>;
|
||||
using graph_t = util::DiGraph<node_t, edge_t>;
|
||||
using node_id = graph_t::node_id;
|
||||
using conflicts_t = conflict_map<node_id>;
|
||||
|
||||
|
@ -142,11 +143,11 @@ namespace mamba
|
|||
* specialization for needed types.
|
||||
*/
|
||||
template <typename T, typename Allocator = std::allocator<T>>
|
||||
class NamedList : private vector_set<T, RoughCompare<T>, Allocator>
|
||||
class NamedList : private util::flat_set<T, RoughCompare<T>, Allocator>
|
||||
{
|
||||
public:
|
||||
|
||||
using Base = vector_set<T, RoughCompare<T>, Allocator>;
|
||||
using Base = util::flat_set<T, RoughCompare<T>, Allocator>;
|
||||
using typename Base::allocator_type;
|
||||
using typename Base::const_iterator;
|
||||
using typename Base::const_reverse_iterator;
|
||||
|
@ -213,7 +214,7 @@ namespace mamba
|
|||
|
||||
using edge_t = NamedList<MatchSpec>;
|
||||
|
||||
using graph_t = DiGraph<node_t, edge_t>;
|
||||
using graph_t = util::DiGraph<node_t, edge_t>;
|
||||
using node_id = graph_t::node_id;
|
||||
using conflicts_t = conflict_map<node_id>;
|
||||
|
||||
|
@ -275,7 +276,7 @@ namespace mamba
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
auto conflict_map<T>::conflicts(const key_type& a) const -> const vector_set<T>&
|
||||
auto conflict_map<T>::conflicts(const key_type& a) const -> const util::flat_set<T>&
|
||||
{
|
||||
return Base::at(a);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "mamba/core/util_compare.hpp"
|
||||
#include "mamba/util/compare.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "util_compare.hpp"
|
||||
#include "mamba/util/compare.hpp"
|
||||
|
||||
namespace mamba::util
|
||||
{
|
|
@ -0,0 +1,309 @@
|
|||
// Copyright (c) 2023, QuantStack and Mamba Contributors
|
||||
//
|
||||
// Distributed under the terms of the BSD 3-Clause License.
|
||||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
|
||||
#ifndef MAMBA_UTILFLAT_SET_HPP
|
||||
#define MAMBA_UTILFLAT_SET_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace mamba::util
|
||||
{
|
||||
|
||||
/**
|
||||
* A sorted vector behaving like a set.
|
||||
*
|
||||
* Like, ``std::set``, uniqueness is determined by using the equivalence relation.
|
||||
* In imprecise terms, two objects ``a`` and ``b`` are considered equivalent if neither
|
||||
* compares less than the other: ``!comp(a, b) && !comp(b, a)``
|
||||
*
|
||||
* @todo C++23 This is implemented in <flat_set>
|
||||
*/
|
||||
template <typename Key, typename Compare = std::less<Key>, typename Allocator = std::allocator<Key>>
|
||||
class flat_set : private std::vector<Key, Allocator>
|
||||
{
|
||||
public:
|
||||
|
||||
using Base = std::vector<Key, Allocator>;
|
||||
using typename Base::allocator_type;
|
||||
using typename Base::const_iterator;
|
||||
using typename Base::const_reverse_iterator;
|
||||
using typename Base::size_type;
|
||||
using typename Base::value_type;
|
||||
using key_compare = Compare;
|
||||
using value_compare = Compare;
|
||||
|
||||
using Base::cbegin;
|
||||
using Base::cend;
|
||||
using Base::crbegin;
|
||||
using Base::crend;
|
||||
|
||||
using Base::clear;
|
||||
using Base::empty;
|
||||
using Base::reserve;
|
||||
using Base::size;
|
||||
|
||||
flat_set() = default;
|
||||
flat_set(
|
||||
std::initializer_list<value_type> il,
|
||||
key_compare compare = key_compare(),
|
||||
const allocator_type& alloc = allocator_type()
|
||||
);
|
||||
template <typename InputIterator>
|
||||
flat_set(
|
||||
InputIterator first,
|
||||
InputIterator last,
|
||||
key_compare compare = key_compare(),
|
||||
const allocator_type& alloc = Allocator()
|
||||
);
|
||||
flat_set(const flat_set&) = default;
|
||||
flat_set(flat_set&&) = default;
|
||||
explicit flat_set(std::vector<Key, Allocator>&& other, key_compare compare = key_compare());
|
||||
explicit flat_set(const std::vector<Key, Allocator>& other, key_compare compare = key_compare());
|
||||
|
||||
flat_set& operator=(const flat_set&) = default;
|
||||
flat_set& operator=(flat_set&&) = default;
|
||||
|
||||
bool contains(const value_type&) const;
|
||||
const value_type& front() const noexcept;
|
||||
const value_type& back() const noexcept;
|
||||
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator end() const noexcept;
|
||||
const_reverse_iterator rbegin() const noexcept;
|
||||
const_reverse_iterator rend() const noexcept;
|
||||
|
||||
/** Insert an element in the set.
|
||||
*
|
||||
* Like std::vector and unlike std::set, inserting an element invalidates iterators.
|
||||
*/
|
||||
std::pair<const_iterator, bool> insert(value_type&& value);
|
||||
std::pair<const_iterator, bool> insert(const value_type& value);
|
||||
template <typename InputIterator>
|
||||
void insert(InputIterator first, InputIterator last);
|
||||
|
||||
const_iterator erase(const_iterator pos);
|
||||
const_iterator erase(const_iterator first, const_iterator last);
|
||||
size_type erase(const value_type& value);
|
||||
|
||||
private:
|
||||
|
||||
key_compare m_compare;
|
||||
|
||||
bool key_eq(const value_type& a, const value_type& b) const;
|
||||
template <typename U>
|
||||
std::pair<const_iterator, bool> insert_impl(U&& value);
|
||||
void sort_and_remove_duplicates();
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
friend bool operator==(const flat_set<K, C, A>& lhs, const flat_set<K, C, A>& rhs);
|
||||
};
|
||||
|
||||
template <class Key, class Compare = std::less<Key>, class Allocator = std::allocator<Key>>
|
||||
flat_set(std::initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
|
||||
-> flat_set<Key, Compare, Allocator>;
|
||||
|
||||
template <
|
||||
class InputIt,
|
||||
class Comp = std::less<typename std::iterator_traits<InputIt>::value_type>,
|
||||
class Alloc = std::allocator<typename std::iterator_traits<InputIt>::value_type>>
|
||||
flat_set(InputIt, InputIt, Comp = Comp(), Alloc = Alloc())
|
||||
-> flat_set<typename std::iterator_traits<InputIt>::value_type, Comp, Alloc>;
|
||||
|
||||
template <class Key, class Compare = std::less<Key>, class Allocator = std::allocator<Key>>
|
||||
flat_set(std::vector<Key, Allocator>&&, Compare compare = Compare())
|
||||
-> flat_set<Key, Compare, Allocator>;
|
||||
|
||||
template <class Key, class Compare = std::less<Key>, class Allocator = std::allocator<Key>>
|
||||
flat_set(const std::vector<Key, Allocator>&, Compare compare = Compare())
|
||||
-> flat_set<Key, Compare, Allocator>;
|
||||
|
||||
template <typename Key, typename Compare, typename Allocator>
|
||||
bool
|
||||
operator==(const flat_set<Key, Compare, Allocator>& lhs, const flat_set<Key, Compare, Allocator>& rhs);
|
||||
|
||||
template <typename Key, typename Compare, typename Allocator>
|
||||
bool
|
||||
operator!=(const flat_set<Key, Compare, Allocator>& lhs, const flat_set<Key, Compare, Allocator>& rhs);
|
||||
|
||||
/*******************************
|
||||
* vector_set Implementation *
|
||||
*******************************/
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
flat_set<K, C, A>::flat_set(
|
||||
std::initializer_list<value_type> il,
|
||||
key_compare compare,
|
||||
const allocator_type& alloc
|
||||
)
|
||||
: Base(std::move(il), alloc)
|
||||
, m_compare(std::move(compare))
|
||||
{
|
||||
sort_and_remove_duplicates();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
template <typename InputIterator>
|
||||
flat_set<K, C, A>::flat_set(
|
||||
InputIterator first,
|
||||
InputIterator last,
|
||||
key_compare compare,
|
||||
const allocator_type& alloc
|
||||
)
|
||||
: Base(first, last, alloc)
|
||||
, m_compare(std::move(compare))
|
||||
{
|
||||
sort_and_remove_duplicates();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
flat_set<K, C, A>::flat_set(std::vector<K, A>&& other, C compare)
|
||||
: Base(std::move(other))
|
||||
, m_compare(std::move(compare))
|
||||
{
|
||||
sort_and_remove_duplicates();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
flat_set<K, C, A>::flat_set(const std::vector<K, A>& other, C compare)
|
||||
: Base(std::move(other))
|
||||
, m_compare(std::move(compare))
|
||||
{
|
||||
sort_and_remove_duplicates();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto flat_set<K, C, A>::contains(const value_type& value) const -> bool
|
||||
{
|
||||
return std::binary_search(begin(), end(), value);
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto flat_set<K, C, A>::front() const noexcept -> const value_type&
|
||||
{
|
||||
return Base::front();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto flat_set<K, C, A>::back() const noexcept -> const value_type&
|
||||
{
|
||||
return Base::back();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto flat_set<K, C, A>::begin() const noexcept -> const_iterator
|
||||
{
|
||||
return Base::begin();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto flat_set<K, C, A>::end() const noexcept -> const_iterator
|
||||
{
|
||||
return Base::end();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto flat_set<K, C, A>::rbegin() const noexcept -> const_reverse_iterator
|
||||
{
|
||||
return Base::rbegin();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto flat_set<K, C, A>::rend() const noexcept -> const_reverse_iterator
|
||||
{
|
||||
return Base::rend();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto flat_set<K, C, A>::insert(const value_type& value) -> std::pair<const_iterator, bool>
|
||||
{
|
||||
return insert_impl(value);
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto flat_set<K, C, A>::insert(value_type&& value) -> std::pair<const_iterator, bool>
|
||||
{
|
||||
return insert_impl(std::move(value));
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
bool flat_set<K, C, A>::key_eq(const value_type& a, const value_type& b) const
|
||||
{
|
||||
return !m_compare(a, b) && !m_compare(b, a);
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
void flat_set<K, C, A>::sort_and_remove_duplicates()
|
||||
{
|
||||
std::sort(Base::begin(), Base::end(), m_compare);
|
||||
auto is_eq = [this](const value_type& a, const value_type& b) { return key_eq(a, b); };
|
||||
Base::erase(std::unique(Base::begin(), Base::end(), is_eq), Base::end());
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
template <typename InputIterator>
|
||||
void flat_set<K, C, A>::insert(InputIterator first, InputIterator last)
|
||||
{
|
||||
Base::insert(Base::end(), first, last);
|
||||
sort_and_remove_duplicates();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
template <typename U>
|
||||
auto flat_set<K, C, A>::insert_impl(U&& value) -> std::pair<const_iterator, bool>
|
||||
{
|
||||
auto it = std::lower_bound(begin(), end(), value, m_compare);
|
||||
if ((it != end()) && (key_eq(*it, value)))
|
||||
{
|
||||
return { it, false };
|
||||
}
|
||||
it = Base::insert(it, std::forward<U>(value));
|
||||
return { it, true };
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto flat_set<K, C, A>::erase(const_iterator pos) -> const_iterator
|
||||
{
|
||||
// No need to sort or remove duplicates again
|
||||
return Base::erase(pos);
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto flat_set<K, C, A>::erase(const_iterator first, const_iterator last) -> const_iterator
|
||||
{
|
||||
// No need to sort or remove duplicates again
|
||||
return Base::erase(first, last);
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto flat_set<K, C, A>::erase(const value_type& value) -> size_type
|
||||
{
|
||||
auto it = std::lower_bound(begin(), end(), value, m_compare);
|
||||
if ((it == end()) || (!(key_eq(*it, value))))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
erase(it);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
bool operator==(const flat_set<K, C, A>& lhs, const flat_set<K, C, A>& rhs)
|
||||
{
|
||||
auto is_eq = [&lhs](const auto& a, const auto& b) { return lhs.key_eq(a, b); };
|
||||
return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), is_eq);
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
bool operator!=(const flat_set<K, C, A>& lhs, const flat_set<K, C, A>& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
|
@ -4,8 +4,8 @@
|
|||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#ifndef MAMBA_CORE_GRAPH_UTIL_HPP
|
||||
#define MAMBA_CORE_GRAPH_UTIL_HPP
|
||||
#ifndef MAMBA_UTIL_GRAPH_HPP
|
||||
#define MAMBA_UTIL_GRAPH_HPP
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
@ -14,127 +14,10 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace mamba
|
||||
#include "flat_set.hpp"
|
||||
|
||||
namespace mamba::util
|
||||
{
|
||||
|
||||
/**
|
||||
* A sorted vector behaving like a set.
|
||||
*
|
||||
* Like, ``std::set``, uniqueness is determined by using the equivalence relation.
|
||||
* In imprecise terms, two objects ``a`` and ``b`` are considered equivalent if neither
|
||||
* compares less than the other: ``!comp(a, b) && !comp(b, a)``
|
||||
*/
|
||||
template <typename Key, typename Compare = std::less<Key>, typename Allocator = std::allocator<Key>>
|
||||
class vector_set : private std::vector<Key, Allocator>
|
||||
{
|
||||
public:
|
||||
|
||||
using Base = std::vector<Key, Allocator>;
|
||||
using typename Base::allocator_type;
|
||||
using typename Base::const_iterator;
|
||||
using typename Base::const_reverse_iterator;
|
||||
using typename Base::size_type;
|
||||
using typename Base::value_type;
|
||||
using key_compare = Compare;
|
||||
using value_compare = Compare;
|
||||
|
||||
using Base::cbegin;
|
||||
using Base::cend;
|
||||
using Base::crbegin;
|
||||
using Base::crend;
|
||||
|
||||
using Base::clear;
|
||||
using Base::empty;
|
||||
using Base::reserve;
|
||||
using Base::size;
|
||||
|
||||
vector_set() = default;
|
||||
vector_set(
|
||||
std::initializer_list<value_type> il,
|
||||
key_compare compare = key_compare(),
|
||||
const allocator_type& alloc = allocator_type()
|
||||
);
|
||||
template <typename InputIterator>
|
||||
vector_set(
|
||||
InputIterator first,
|
||||
InputIterator last,
|
||||
key_compare compare = key_compare(),
|
||||
const allocator_type& alloc = Allocator()
|
||||
);
|
||||
vector_set(const vector_set&) = default;
|
||||
vector_set(vector_set&&) = default;
|
||||
explicit vector_set(std::vector<Key, Allocator>&& other, key_compare compare = key_compare());
|
||||
explicit vector_set(const std::vector<Key, Allocator>& other, key_compare compare = key_compare());
|
||||
|
||||
vector_set& operator=(const vector_set&) = default;
|
||||
vector_set& operator=(vector_set&&) = default;
|
||||
|
||||
bool contains(const value_type&) const;
|
||||
const value_type& front() const noexcept;
|
||||
const value_type& back() const noexcept;
|
||||
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator end() const noexcept;
|
||||
const_reverse_iterator rbegin() const noexcept;
|
||||
const_reverse_iterator rend() const noexcept;
|
||||
|
||||
/** Insert an element in the set.
|
||||
*
|
||||
* Like std::vector and unlike std::set, inserting an element invalidates iterators.
|
||||
*/
|
||||
std::pair<const_iterator, bool> insert(value_type&& value);
|
||||
std::pair<const_iterator, bool> insert(const value_type& value);
|
||||
template <typename InputIterator>
|
||||
void insert(InputIterator first, InputIterator last);
|
||||
|
||||
const_iterator erase(const_iterator pos);
|
||||
const_iterator erase(const_iterator first, const_iterator last);
|
||||
size_type erase(const value_type& value);
|
||||
|
||||
private:
|
||||
|
||||
key_compare m_compare;
|
||||
|
||||
bool key_eq(const value_type& a, const value_type& b) const;
|
||||
template <typename U>
|
||||
std::pair<const_iterator, bool> insert_impl(U&& value);
|
||||
void sort_and_remove_duplicates();
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
friend bool operator==(const vector_set<K, C, A>& lhs, const vector_set<K, C, A>& rhs);
|
||||
};
|
||||
|
||||
template <class Key, class Compare = std::less<Key>, class Allocator = std::allocator<Key>>
|
||||
vector_set(std::initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
|
||||
-> vector_set<Key, Compare, Allocator>;
|
||||
|
||||
template <
|
||||
class InputIt,
|
||||
class Comp = std::less<typename std::iterator_traits<InputIt>::value_type>,
|
||||
class Alloc = std::allocator<typename std::iterator_traits<InputIt>::value_type>>
|
||||
vector_set(InputIt, InputIt, Comp = Comp(), Alloc = Alloc())
|
||||
-> vector_set<typename std::iterator_traits<InputIt>::value_type, Comp, Alloc>;
|
||||
|
||||
template <class Key, class Compare = std::less<Key>, class Allocator = std::allocator<Key>>
|
||||
vector_set(std::vector<Key, Allocator>&&, Compare compare = Compare())
|
||||
-> vector_set<Key, Compare, Allocator>;
|
||||
|
||||
template <class Key, class Compare = std::less<Key>, class Allocator = std::allocator<Key>>
|
||||
vector_set(const std::vector<Key, Allocator>&, Compare compare = Compare())
|
||||
-> vector_set<Key, Compare, Allocator>;
|
||||
|
||||
template <typename Key, typename Compare, typename Allocator>
|
||||
bool operator==(
|
||||
const vector_set<Key, Compare, Allocator>& lhs,
|
||||
const vector_set<Key, Compare, Allocator>& rhs
|
||||
);
|
||||
|
||||
template <typename Key, typename Compare, typename Allocator>
|
||||
bool operator!=(
|
||||
const vector_set<Key, Compare, Allocator>& lhs,
|
||||
const vector_set<Key, Compare, Allocator>& rhs
|
||||
);
|
||||
|
||||
// Simplified implementation of a directed graph
|
||||
template <typename Node, typename Derived>
|
||||
class DiGraphBase
|
||||
|
@ -144,7 +27,7 @@ namespace mamba
|
|||
using node_t = Node;
|
||||
using node_id = std::size_t;
|
||||
using node_map = std::map<node_id, node_t>;
|
||||
using node_id_list = vector_set<node_id>;
|
||||
using node_id_list = flat_set<node_id>;
|
||||
using adjacency_list = std::vector<node_id_list>;
|
||||
|
||||
node_id add_node(const node_t& value);
|
||||
|
@ -337,180 +220,6 @@ namespace mamba
|
|||
{
|
||||
};
|
||||
|
||||
/*******************************
|
||||
* vector_set Implementation *
|
||||
*******************************/
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
vector_set<K, C, A>::vector_set(
|
||||
std::initializer_list<value_type> il,
|
||||
key_compare compare,
|
||||
const allocator_type& alloc
|
||||
)
|
||||
: Base(std::move(il), alloc)
|
||||
, m_compare(std::move(compare))
|
||||
{
|
||||
sort_and_remove_duplicates();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
template <typename InputIterator>
|
||||
vector_set<K, C, A>::vector_set(
|
||||
InputIterator first,
|
||||
InputIterator last,
|
||||
key_compare compare,
|
||||
const allocator_type& alloc
|
||||
)
|
||||
: Base(first, last, alloc)
|
||||
, m_compare(std::move(compare))
|
||||
{
|
||||
sort_and_remove_duplicates();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
vector_set<K, C, A>::vector_set(std::vector<K, A>&& other, C compare)
|
||||
: Base(std::move(other))
|
||||
, m_compare(std::move(compare))
|
||||
{
|
||||
sort_and_remove_duplicates();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
vector_set<K, C, A>::vector_set(const std::vector<K, A>& other, C compare)
|
||||
: Base(std::move(other))
|
||||
, m_compare(std::move(compare))
|
||||
{
|
||||
sort_and_remove_duplicates();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto vector_set<K, C, A>::contains(const value_type& value) const -> bool
|
||||
{
|
||||
return std::binary_search(begin(), end(), value);
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto vector_set<K, C, A>::front() const noexcept -> const value_type&
|
||||
{
|
||||
return Base::front();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto vector_set<K, C, A>::back() const noexcept -> const value_type&
|
||||
{
|
||||
return Base::back();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto vector_set<K, C, A>::begin() const noexcept -> const_iterator
|
||||
{
|
||||
return Base::begin();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto vector_set<K, C, A>::end() const noexcept -> const_iterator
|
||||
{
|
||||
return Base::end();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto vector_set<K, C, A>::rbegin() const noexcept -> const_reverse_iterator
|
||||
{
|
||||
return Base::rbegin();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto vector_set<K, C, A>::rend() const noexcept -> const_reverse_iterator
|
||||
{
|
||||
return Base::rend();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto vector_set<K, C, A>::insert(const value_type& value) -> std::pair<const_iterator, bool>
|
||||
{
|
||||
return insert_impl(value);
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto vector_set<K, C, A>::insert(value_type&& value) -> std::pair<const_iterator, bool>
|
||||
{
|
||||
return insert_impl(std::move(value));
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
bool vector_set<K, C, A>::key_eq(const value_type& a, const value_type& b) const
|
||||
{
|
||||
return !m_compare(a, b) && !m_compare(b, a);
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
void vector_set<K, C, A>::sort_and_remove_duplicates()
|
||||
{
|
||||
std::sort(Base::begin(), Base::end(), m_compare);
|
||||
auto is_eq = [this](const value_type& a, const value_type& b) { return key_eq(a, b); };
|
||||
Base::erase(std::unique(Base::begin(), Base::end(), is_eq), Base::end());
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
template <typename InputIterator>
|
||||
void vector_set<K, C, A>::insert(InputIterator first, InputIterator last)
|
||||
{
|
||||
Base::insert(Base::end(), first, last);
|
||||
sort_and_remove_duplicates();
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
template <typename U>
|
||||
auto vector_set<K, C, A>::insert_impl(U&& value) -> std::pair<const_iterator, bool>
|
||||
{
|
||||
auto it = std::lower_bound(begin(), end(), value, m_compare);
|
||||
if ((it != end()) && (key_eq(*it, value)))
|
||||
{
|
||||
return { it, false };
|
||||
}
|
||||
it = Base::insert(it, std::forward<U>(value));
|
||||
return { it, true };
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto vector_set<K, C, A>::erase(const_iterator pos) -> const_iterator
|
||||
{
|
||||
// No need to sort or remove duplicates again
|
||||
return Base::erase(pos);
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto vector_set<K, C, A>::erase(const_iterator first, const_iterator last) -> const_iterator
|
||||
{
|
||||
// No need to sort or remove duplicates again
|
||||
return Base::erase(first, last);
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
auto vector_set<K, C, A>::erase(const value_type& value) -> size_type
|
||||
{
|
||||
auto it = std::lower_bound(begin(), end(), value, m_compare);
|
||||
if ((it == end()) || (!(key_eq(*it, value))))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
erase(it);
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
bool operator==(const vector_set<K, C, A>& lhs, const vector_set<K, C, A>& rhs)
|
||||
{
|
||||
auto is_eq = [&lhs](const auto& a, const auto& b) { return lhs.key_eq(a, b); };
|
||||
return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), is_eq);
|
||||
}
|
||||
|
||||
template <typename K, typename C, typename A>
|
||||
bool operator!=(const vector_set<K, C, A>& lhs, const vector_set<K, C, A>& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/********************************
|
||||
* DiGraphBase Implementation *
|
||||
********************************/
|
||||
|
@ -950,7 +659,5 @@ namespace mamba
|
|||
{
|
||||
return edge({ from, to });
|
||||
}
|
||||
|
||||
} // namespace mamba
|
||||
|
||||
#endif // INCLUDE_GRAPH_UTIL_HPP
|
||||
}
|
||||
#endif
|
|
@ -20,9 +20,9 @@ extern "C" // Incomplete header
|
|||
#include "mamba/core/context.hpp"
|
||||
#include "mamba/core/output.hpp"
|
||||
#include "mamba/core/pool.hpp"
|
||||
#include "mamba/core/util_cast.hpp"
|
||||
#include "mamba/core/util_compare.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
#include "mamba/util/cast.hpp"
|
||||
#include "mamba/util/compare.hpp"
|
||||
#include "solv-cpp/queue.hpp"
|
||||
|
||||
namespace mamba
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
#include "mamba/core/context.hpp"
|
||||
#include "mamba/core/execution.hpp"
|
||||
#include "mamba/core/util_compare.hpp"
|
||||
#include "mamba/util/compare.hpp"
|
||||
|
||||
#include "progress_bar_impl.hpp"
|
||||
|
||||
|
|
|
@ -582,11 +582,11 @@ namespace mamba
|
|||
using node_id = ProblemsGraph::node_id;
|
||||
const auto& g = pbs.graph();
|
||||
auto is_leaf = [&g](node_id n) -> bool { return g.successors(n).size() == 0; };
|
||||
auto leaves_from = [&g](node_id n) -> vector_set<node_id>
|
||||
auto leaves_from = [&g](node_id n) -> util::flat_set<node_id>
|
||||
{
|
||||
auto leaves = std::vector<node_id>();
|
||||
g.for_each_leaf_id_from(n, [&leaves](node_id m) { leaves.push_back(m); });
|
||||
return vector_set(std::move(leaves));
|
||||
return util::flat_set(std::move(leaves));
|
||||
};
|
||||
return (node_name(g.node(n1)) == node_name(g.node(n2)))
|
||||
// Merging conflicts would be counter-productive in explaining problems
|
||||
|
@ -1126,7 +1126,7 @@ namespace mamba
|
|||
using TreeNodeList = std::vector<TreeNode>;
|
||||
using TreeNodeIter = typename TreeNodeList::iterator;
|
||||
|
||||
vector_set<node_id> leaf_installables = {};
|
||||
util::flat_set<node_id> leaf_installables = {};
|
||||
std::map<node_id, std::optional<Status>> m_node_visited = {};
|
||||
const CompressedProblemsGraph& m_pbs;
|
||||
|
||||
|
|
|
@ -51,10 +51,10 @@ extern "C"
|
|||
#include "mamba/core/thread_utils.hpp"
|
||||
#include "mamba/core/url.hpp"
|
||||
#include "mamba/core/util.hpp"
|
||||
#include "mamba/core/util_compare.hpp"
|
||||
#include "mamba/core/util_os.hpp"
|
||||
#include "mamba/core/util_random.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
#include "mamba/util/compare.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
|
|
@ -12,9 +12,9 @@
|
|||
#include <tuple>
|
||||
|
||||
#include "mamba/core/error_handling.hpp"
|
||||
#include "mamba/core/util_cast.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
#include "mamba/specs/version.hpp"
|
||||
#include "mamba/util/cast.hpp"
|
||||
|
||||
namespace mamba::specs
|
||||
{
|
||||
|
|
|
@ -13,6 +13,11 @@ mamba_target_add_compile_warnings(testing_libmamba_lock WARNING_AS_ERROR ${MAMBA
|
|||
set(LIBMAMBA_TEST_SRCS
|
||||
# C++ wrapping of libsolv
|
||||
src/solv-cpp/test_queue.cpp
|
||||
# Utility library
|
||||
src/util/test_flat_set.cpp
|
||||
src/util/test_graph.cpp
|
||||
src/util/test_compare.cpp
|
||||
src/util/test_cast.cpp
|
||||
# Implementation of version and matching specs
|
||||
src/specs/test_version.cpp
|
||||
|
||||
|
@ -35,10 +40,7 @@ set(LIBMAMBA_TEST_SRCS
|
|||
src/core/test_validate.cpp
|
||||
src/core/test_virtual_packages.cpp
|
||||
src/core/test_util.cpp
|
||||
src/core/test_util_cast.cpp
|
||||
src/core/test_util_compare.cpp
|
||||
src/core/test_util_string.cpp
|
||||
src/core/test_util_graph.cpp
|
||||
src/core/test_env_lockfile.cpp
|
||||
src/core/test_execution.cpp
|
||||
src/core/test_invoke.cpp
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
// Copyright (c) 2023, QuantStack and Mamba Contributors
|
||||
//
|
||||
// Distributed under the terms of the BSD 3-Clause License.
|
||||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "mamba/core/util_cast.hpp"
|
||||
|
||||
namespace mamba::util
|
||||
{
|
||||
template <typename T>
|
||||
struct cast_valid : ::testing::Test
|
||||
{
|
||||
using First = typename T::first_type;
|
||||
using Second = typename T::second_type;
|
||||
};
|
||||
using WidenTypes = ::testing::Types<
|
||||
// integers
|
||||
std::pair<char, int>,
|
||||
std::pair<unsigned char, int>,
|
||||
std::pair<unsigned char, unsigned int>,
|
||||
std::pair<int, long long int>,
|
||||
std::pair<unsigned int, long long int>,
|
||||
std::pair<unsigned int, unsigned long long int>,
|
||||
// floats
|
||||
std::pair<float, double>,
|
||||
// Mixed
|
||||
std::pair<char, float>,
|
||||
std::pair<unsigned char, float>,
|
||||
std::pair<int, double>,
|
||||
std::pair<unsigned int, double>>;
|
||||
TYPED_TEST_SUITE(cast_valid, WidenTypes);
|
||||
|
||||
TYPED_TEST(cast_valid, checked_exact_num_cast_widen)
|
||||
{
|
||||
using From = typename TestFixture::First;
|
||||
using To = typename TestFixture::Second;
|
||||
static constexpr auto from_lowest = std::numeric_limits<From>::lowest();
|
||||
static constexpr auto from_max = std::numeric_limits<From>::max();
|
||||
|
||||
EXPECT_EQ(safe_num_cast<To>(From(0)), To(0));
|
||||
EXPECT_EQ(safe_num_cast<To>(From(1)), To(1));
|
||||
EXPECT_EQ(safe_num_cast<To>(from_lowest), static_cast<To>(from_lowest));
|
||||
EXPECT_EQ(safe_num_cast<To>(from_max), static_cast<To>(from_max));
|
||||
}
|
||||
|
||||
TYPED_TEST(cast_valid, checked_exact_num_cast_narrow)
|
||||
{
|
||||
using From = typename TestFixture::Second; // inversed
|
||||
using To = typename TestFixture::First; // inversed
|
||||
EXPECT_EQ(safe_num_cast<To>(From(0)), To(0));
|
||||
EXPECT_EQ(safe_num_cast<To>(From(1)), To(1));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct cast_overflow_lowest : ::testing::Test
|
||||
{
|
||||
using First = typename T::first_type;
|
||||
using Second = typename T::second_type;
|
||||
};
|
||||
using OverflowLowestTypes = ::testing::Types<
|
||||
// integers
|
||||
std::pair<char, unsigned char>,
|
||||
std::pair<char, unsigned int>,
|
||||
std::pair<int, char>,
|
||||
std::pair<int, unsigned long long int>,
|
||||
// floats
|
||||
std::pair<double, float>,
|
||||
// mixed
|
||||
std::pair<double, int>,
|
||||
std::pair<float, char>>;
|
||||
TYPED_TEST_SUITE(cast_overflow_lowest, OverflowLowestTypes);
|
||||
|
||||
TYPED_TEST(cast_overflow_lowest, checked_exact_num_cast)
|
||||
{
|
||||
using From = typename TestFixture::First;
|
||||
using To = typename TestFixture::Second;
|
||||
static constexpr auto from_lowest = std::numeric_limits<From>::lowest();
|
||||
|
||||
EXPECT_THROW(safe_num_cast<To>(from_lowest), std::overflow_error);
|
||||
}
|
||||
|
||||
TEST(cast, precision)
|
||||
{
|
||||
EXPECT_THROW(safe_num_cast<int>(1.1), std::runtime_error);
|
||||
EXPECT_THROW(safe_num_cast<float>(std::nextafter(double(1), 2)), std::runtime_error);
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
// Copyright (c) 2023, QuantStack and Mamba Contributors
|
||||
//
|
||||
// Distributed under the terms of the BSD 3-Clause License.
|
||||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "mamba/core/util_compare.hpp"
|
||||
|
||||
namespace mamba::util
|
||||
{
|
||||
TEST(compare, equal)
|
||||
{
|
||||
EXPECT_TRUE(cmp_equal(char{ 0 }, char{ 0 }));
|
||||
EXPECT_TRUE(cmp_equal(char{ 1 }, char{ 1 }));
|
||||
EXPECT_TRUE(cmp_equal(char{ -1 }, char{ -1 }));
|
||||
EXPECT_TRUE(cmp_equal(int{ 0 }, int{ 0 }));
|
||||
EXPECT_TRUE(cmp_equal(int{ 1 }, int{ 1 }));
|
||||
EXPECT_TRUE(cmp_equal(int{ -1 }, int{ -1 }));
|
||||
EXPECT_TRUE(cmp_equal(std::size_t{ 0 }, std::size_t{ 0 }));
|
||||
EXPECT_TRUE(cmp_equal(std::size_t{ 1 }, std::size_t{ 1 }));
|
||||
|
||||
EXPECT_TRUE(cmp_equal(char{ 0 }, int{ 0 }));
|
||||
EXPECT_TRUE(cmp_equal(char{ 1 }, int{ 1 }));
|
||||
EXPECT_TRUE(cmp_equal(char{ -1 }, int{ -1 }));
|
||||
EXPECT_TRUE(cmp_equal(std::size_t{ 0 }, char{ 0 }));
|
||||
EXPECT_TRUE(cmp_equal(std::size_t{ 1 }, char{ 1 }));
|
||||
EXPECT_TRUE(cmp_equal(std::size_t{ 0 }, int{ 0 }));
|
||||
EXPECT_TRUE(cmp_equal(std::size_t{ 1 }, int{ 1 }));
|
||||
|
||||
EXPECT_FALSE(cmp_equal(char{ 0 }, char{ 1 }));
|
||||
EXPECT_FALSE(cmp_equal(char{ 1 }, char{ -1 }));
|
||||
EXPECT_FALSE(cmp_equal(int{ 0 }, int{ 1 }));
|
||||
EXPECT_FALSE(cmp_equal(int{ -1 }, int{ 1 }));
|
||||
EXPECT_FALSE(cmp_equal(std::size_t{ 0 }, std::size_t{ 1 }));
|
||||
|
||||
EXPECT_FALSE(cmp_equal(char{ 0 }, int{ 1 }));
|
||||
EXPECT_FALSE(cmp_equal(char{ 1 }, int{ -1 }));
|
||||
EXPECT_FALSE(cmp_equal(char{ -1 }, int{ 1 }));
|
||||
EXPECT_FALSE(cmp_equal(std::size_t{ 1 }, int{ -1 }));
|
||||
EXPECT_FALSE(cmp_equal(static_cast<std::size_t>(-1), int{ -1 }));
|
||||
EXPECT_FALSE(cmp_equal(std::size_t{ 1 }, int{ 0 }));
|
||||
EXPECT_FALSE(cmp_equal(std::numeric_limits<std::size_t>::max(), int{ 0 }));
|
||||
}
|
||||
|
||||
TEST(compare, less)
|
||||
{
|
||||
EXPECT_TRUE(cmp_less(char{ 0 }, char{ 1 }));
|
||||
EXPECT_TRUE(cmp_less(char{ -1 }, char{ 0 }));
|
||||
EXPECT_TRUE(cmp_less(int{ 0 }, int{ 1 }));
|
||||
EXPECT_TRUE(cmp_less(int{ -1 }, int{ 1 }));
|
||||
EXPECT_TRUE(cmp_less(std::size_t{ 0 }, std::size_t{ 1 }));
|
||||
|
||||
EXPECT_TRUE(cmp_less(char{ 0 }, int{ 1 }));
|
||||
EXPECT_TRUE(cmp_less(char{ -1 }, int{ 0 }));
|
||||
EXPECT_TRUE(cmp_less(char{ -1 }, int{ 1 }));
|
||||
EXPECT_TRUE(cmp_less(char{ -1 }, std::size_t{ 1 }));
|
||||
EXPECT_TRUE(cmp_less(std::size_t{ 0 }, int{ 1 }));
|
||||
EXPECT_TRUE(cmp_less(std::numeric_limits<int>::min(), char{ 0 }));
|
||||
EXPECT_TRUE(cmp_less(std::numeric_limits<int>::min(), std::size_t{ 0 }));
|
||||
EXPECT_TRUE(cmp_less(int{ -1 }, std::numeric_limits<std::size_t>::max()));
|
||||
EXPECT_TRUE(cmp_less(std::size_t{ 1 }, std::numeric_limits<int>::max()));
|
||||
|
||||
EXPECT_FALSE(cmp_less(char{ 1 }, char{ 0 }));
|
||||
EXPECT_FALSE(cmp_less(char{ 1 }, char{ 1 }));
|
||||
EXPECT_FALSE(cmp_less(char{ 0 }, char{ -1 }));
|
||||
EXPECT_FALSE(cmp_less(int{ 1 }, int{ 0 }));
|
||||
EXPECT_FALSE(cmp_less(int{ 1 }, int{ -1 }));
|
||||
EXPECT_FALSE(cmp_less(std::size_t{ 1 }, std::size_t{ 0 }));
|
||||
|
||||
EXPECT_FALSE(cmp_less(char{ 1 }, int{ 1 }));
|
||||
EXPECT_FALSE(cmp_less(char{ 1 }, int{ 0 }));
|
||||
EXPECT_FALSE(cmp_less(char{ 0 }, int{ -1 }));
|
||||
EXPECT_FALSE(cmp_less(char{ 1 }, int{ -11 }));
|
||||
EXPECT_FALSE(cmp_less(std::size_t{ 1 }, char{ -1 }));
|
||||
EXPECT_FALSE(cmp_less(int{ 1 }, std::size_t{ 0 }));
|
||||
EXPECT_FALSE(cmp_less(char{ 0 }, std::numeric_limits<int>::min()));
|
||||
EXPECT_FALSE(cmp_less(std::size_t{ 0 }, std::numeric_limits<int>::min()));
|
||||
EXPECT_FALSE(cmp_less(std::numeric_limits<std::size_t>::max(), int{ -1 }));
|
||||
EXPECT_FALSE(cmp_less(std::numeric_limits<int>::max(), std::size_t{ 1 }));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,425 +0,0 @@
|
|||
#include <type_traits>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "mamba/core/util_graph.hpp"
|
||||
|
||||
namespace mamba
|
||||
{
|
||||
|
||||
TEST(vector_set, constructor)
|
||||
{
|
||||
const auto s1 = vector_set<int>();
|
||||
EXPECT_EQ(s1.size(), 0);
|
||||
auto s2 = vector_set<int>({ 1, 2 });
|
||||
EXPECT_EQ(s2.size(), 2);
|
||||
const auto s3 = vector_set<int>{ s2 };
|
||||
EXPECT_EQ(s3.size(), 2);
|
||||
const auto s4 = vector_set<int>{ std::move(s2) };
|
||||
EXPECT_EQ(s4.size(), 2);
|
||||
// CTAD
|
||||
auto s5 = vector_set({ 1, 2 });
|
||||
EXPECT_EQ(s5.size(), 2);
|
||||
static_assert(std::is_same_v<decltype(s5)::value_type, int>);
|
||||
auto s6 = vector_set(s5.begin(), s5.end(), std::greater{});
|
||||
EXPECT_EQ(s6.size(), s5.size());
|
||||
static_assert(std::is_same_v<decltype(s6)::value_type, decltype(s5)::value_type>);
|
||||
}
|
||||
|
||||
TEST(vector_set, equality)
|
||||
{
|
||||
EXPECT_EQ(vector_set<int>(), vector_set<int>());
|
||||
EXPECT_EQ(vector_set<int>({ 1, 2 }), vector_set<int>({ 1, 2 }));
|
||||
EXPECT_EQ(vector_set<int>({ 1, 2 }), vector_set<int>({ 2, 1 }));
|
||||
EXPECT_EQ(vector_set<int>({ 1, 2, 1 }), vector_set<int>({ 2, 2, 1 }));
|
||||
EXPECT_NE(vector_set<int>({ 1, 2 }), vector_set<int>({ 1, 2, 3 }));
|
||||
EXPECT_NE(vector_set<int>({ 2 }), vector_set<int>({}));
|
||||
}
|
||||
|
||||
TEST(vector_set, insert)
|
||||
{
|
||||
auto s = vector_set<int>();
|
||||
s.insert(33);
|
||||
EXPECT_EQ(s, vector_set<int>({ 33 }));
|
||||
s.insert(33);
|
||||
s.insert(17);
|
||||
EXPECT_EQ(s, vector_set<int>({ 17, 33 }));
|
||||
s.insert(22);
|
||||
EXPECT_EQ(s, vector_set<int>({ 17, 22, 33 }));
|
||||
s.insert(33);
|
||||
EXPECT_EQ(s, vector_set<int>({ 17, 22, 33 }));
|
||||
auto v = std::vector<int>({ 33, 22, 17, 0 });
|
||||
s.insert(v.begin(), v.end());
|
||||
EXPECT_EQ(s, vector_set<int>({ 0, 17, 22, 33 }));
|
||||
}
|
||||
|
||||
TEST(vector_set, erase)
|
||||
{
|
||||
auto s = vector_set<int>{ 4, 3, 2, 1 };
|
||||
EXPECT_EQ(s.erase(4), 1);
|
||||
EXPECT_EQ(s, vector_set<int>({ 1, 2, 3 }));
|
||||
EXPECT_EQ(s.erase(4), 0);
|
||||
EXPECT_EQ(s, vector_set<int>({ 1, 2, 3 }));
|
||||
|
||||
const auto it = s.erase(s.begin());
|
||||
EXPECT_EQ(it, s.begin());
|
||||
EXPECT_EQ(s, vector_set<int>({ 2, 3 }));
|
||||
}
|
||||
|
||||
TEST(vector_set, contains)
|
||||
{
|
||||
const auto s = vector_set<int>({ 1, 3, 4, 5 });
|
||||
EXPECT_FALSE(s.contains(0));
|
||||
EXPECT_TRUE(s.contains(1));
|
||||
EXPECT_FALSE(s.contains(2));
|
||||
EXPECT_TRUE(s.contains(3));
|
||||
EXPECT_TRUE(s.contains(4));
|
||||
EXPECT_TRUE(s.contains(5));
|
||||
EXPECT_FALSE(s.contains(6));
|
||||
}
|
||||
|
||||
TEST(vector_set, key_compare)
|
||||
{
|
||||
auto s = vector_set({ 1, 3, 4, 5 }, std::greater{});
|
||||
EXPECT_EQ(s.front(), 5);
|
||||
EXPECT_EQ(s.back(), 1);
|
||||
s.insert(6);
|
||||
EXPECT_EQ(s.front(), 6);
|
||||
}
|
||||
|
||||
DiGraph<double> build_graph()
|
||||
{
|
||||
DiGraph<double> g;
|
||||
const auto n0 = g.add_node(0.5);
|
||||
const auto n1 = g.add_node(1.5);
|
||||
const auto n2 = g.add_node(2.5);
|
||||
const auto n3 = g.add_node(3.5);
|
||||
const auto n4 = g.add_node(4.5);
|
||||
const auto n5 = g.add_node(5.5);
|
||||
const auto n6 = g.add_node(6.5);
|
||||
|
||||
g.add_edge(n0, n1);
|
||||
g.add_edge(n0, n2);
|
||||
g.add_edge(n1, n3);
|
||||
g.add_edge(n1, n4);
|
||||
g.add_edge(n2, n3);
|
||||
g.add_edge(n2, n5);
|
||||
g.add_edge(n3, n6);
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
DiGraph<double> build_cyclic_graph()
|
||||
{
|
||||
DiGraph<double> g;
|
||||
const auto n0 = g.add_node(0.5);
|
||||
const auto n1 = g.add_node(1.5);
|
||||
const auto n2 = g.add_node(2.5);
|
||||
const auto n3 = g.add_node(3.5);
|
||||
const auto n4 = g.add_node(4.5);
|
||||
|
||||
g.add_edge(n0, n1);
|
||||
g.add_edge(n0, n3);
|
||||
g.add_edge(n1, n2);
|
||||
g.add_edge(n2, n0);
|
||||
g.add_edge(n3, n4);
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
DiGraph<double, const char*> build_edge_data_graph()
|
||||
{
|
||||
auto g = DiGraph<double, const char*>{};
|
||||
const auto n0 = g.add_node(0.5);
|
||||
const auto n1 = g.add_node(1.5);
|
||||
const auto n2 = g.add_node(2.5);
|
||||
g.add_edge(n0, n1, "n0->n1");
|
||||
g.add_edge(n1, n2, "n1->n2");
|
||||
return g;
|
||||
}
|
||||
|
||||
template <class G>
|
||||
class test_visitor : private default_visitor<G>
|
||||
{
|
||||
public:
|
||||
|
||||
using base_type = default_visitor<G>;
|
||||
using node_id = typename base_type::node_id;
|
||||
using predecessor_map = std::map<node_id, node_id>;
|
||||
using edge_map = std::map<node_id, node_id>;
|
||||
|
||||
using base_type::finish_edge;
|
||||
using base_type::finish_node;
|
||||
using base_type::start_edge;
|
||||
using base_type::start_node;
|
||||
using base_type::tree_edge;
|
||||
|
||||
void back_edge(node_id from, node_id to, const G&)
|
||||
{
|
||||
m_back_edges[from] = to;
|
||||
}
|
||||
|
||||
void forward_or_cross_edge(node_id from, node_id to, const G&)
|
||||
{
|
||||
m_cross_edges[from] = to;
|
||||
}
|
||||
|
||||
const edge_map& get_back_edge_map() const
|
||||
{
|
||||
return m_back_edges;
|
||||
}
|
||||
|
||||
const edge_map get_cross_edge_map() const
|
||||
{
|
||||
return m_cross_edges;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
edge_map m_back_edges;
|
||||
edge_map m_cross_edges;
|
||||
};
|
||||
|
||||
TEST(graph, build_simple)
|
||||
{
|
||||
const auto g = build_graph();
|
||||
using node_map = decltype(g)::node_map;
|
||||
using node_id_list = decltype(g)::node_id_list;
|
||||
EXPECT_EQ(g.number_of_nodes(), 7ul);
|
||||
EXPECT_EQ(g.number_of_edges(), 7ul);
|
||||
EXPECT_EQ(
|
||||
g.nodes(),
|
||||
node_map(
|
||||
{ { 0, 0.5 }, { 1, 1.5 }, { 2, 2.5 }, { 3, 3.5 }, { 4, 4.5 }, { 5, 5.5 }, { 6, 6.5 } }
|
||||
)
|
||||
);
|
||||
EXPECT_EQ(g.successors(0u), node_id_list({ 1u, 2u }));
|
||||
EXPECT_EQ(g.successors(1u), node_id_list({ 3u, 4u }));
|
||||
EXPECT_EQ(g.successors(2u), node_id_list({ 3u, 5u }));
|
||||
EXPECT_EQ(g.successors(3u), node_id_list({ 6u }));
|
||||
EXPECT_EQ(g.predecessors(0u), node_id_list());
|
||||
EXPECT_EQ(g.predecessors(1u), node_id_list({ 0u }));
|
||||
EXPECT_EQ(g.predecessors(2u), node_id_list({ 0u }));
|
||||
EXPECT_EQ(g.predecessors(3u), node_id_list({ 1u, 2u }));
|
||||
}
|
||||
|
||||
TEST(graph, build_edge_data)
|
||||
{
|
||||
const auto g = build_edge_data_graph();
|
||||
using node_map = decltype(g)::node_map;
|
||||
using node_id_list = decltype(g)::node_id_list;
|
||||
EXPECT_EQ(g.number_of_nodes(), 3ul);
|
||||
EXPECT_EQ(g.number_of_edges(), 2ul);
|
||||
EXPECT_EQ(g.nodes(), node_map({ { 0, 0.5 }, { 1, 1.5 }, { 2, 2.5 } }));
|
||||
EXPECT_EQ(g.successors(0ul), node_id_list({ 1ul }));
|
||||
EXPECT_EQ(g.successors(1ul), node_id_list({ 2ul }));
|
||||
EXPECT_EQ(g.successors(2ul), node_id_list());
|
||||
EXPECT_EQ(g.predecessors(0ul), node_id_list());
|
||||
EXPECT_EQ(g.predecessors(1ul), node_id_list({ 0ul }));
|
||||
EXPECT_EQ(g.predecessors(2ul), node_id_list({ 1ul }));
|
||||
|
||||
using edge_map = decltype(g)::edge_map;
|
||||
EXPECT_EQ(g.edges(), edge_map({ { { 0ul, 1ul }, "n0->n1" }, { { 1ul, 2ul }, "n1->n2" } }));
|
||||
}
|
||||
|
||||
TEST(graph, has_node_edge)
|
||||
{
|
||||
const auto g = build_graph();
|
||||
EXPECT_TRUE(g.has_node(1ul));
|
||||
EXPECT_TRUE(g.has_node(4ul));
|
||||
EXPECT_FALSE(g.has_node(g.number_of_nodes()));
|
||||
EXPECT_TRUE(g.has_edge(1ul, 4ul));
|
||||
EXPECT_FALSE(g.has_edge(4ul, 1ul));
|
||||
EXPECT_TRUE(g.has_edge(0ul, 2ul));
|
||||
EXPECT_FALSE(g.has_edge(0ul, 5ul));
|
||||
EXPECT_FALSE(g.has_edge(0ul, g.number_of_nodes()));
|
||||
EXPECT_FALSE(g.has_edge(g.number_of_nodes(), 1ul));
|
||||
}
|
||||
|
||||
TEST(graph, data_modifier)
|
||||
{
|
||||
auto g = build_edge_data_graph();
|
||||
|
||||
static constexpr auto new_node_val = -1.5;
|
||||
EXPECT_NE(g.node(0ul), new_node_val);
|
||||
g.node(0ul) = new_node_val;
|
||||
EXPECT_EQ(g.node(0ul), new_node_val);
|
||||
|
||||
static constexpr auto new_edge_val = "data";
|
||||
EXPECT_NE(g.edge(0ul, 1ul), new_edge_val);
|
||||
g.edge(0ul, 1ul) = new_edge_val;
|
||||
EXPECT_EQ(g.edge(0ul, 1ul), new_edge_val);
|
||||
}
|
||||
|
||||
TEST(graph, remove_edge)
|
||||
{
|
||||
auto g = build_edge_data_graph();
|
||||
const auto n_edges_init = g.number_of_edges();
|
||||
|
||||
ASSERT_FALSE(g.has_edge(1, 0));
|
||||
ASSERT_TRUE(g.has_edge(0, 1));
|
||||
EXPECT_FALSE(g.remove_edge(1, 0));
|
||||
EXPECT_EQ(g.number_of_edges(), n_edges_init);
|
||||
EXPECT_FALSE(g.has_edge(1, 0));
|
||||
EXPECT_TRUE(g.has_edge(0, 1));
|
||||
|
||||
ASSERT_TRUE(g.has_edge(0, 1));
|
||||
EXPECT_TRUE(g.remove_edge(0, 1));
|
||||
EXPECT_EQ(g.number_of_edges(), n_edges_init - 1u);
|
||||
EXPECT_FALSE(g.has_edge(0, 1));
|
||||
EXPECT_EQ(g.edges().count({ 0, 1 }), 0);
|
||||
}
|
||||
|
||||
TEST(graph, remove_node)
|
||||
{
|
||||
auto g = build_edge_data_graph();
|
||||
|
||||
ASSERT_TRUE(g.has_node(0));
|
||||
ASSERT_TRUE(g.has_node(1));
|
||||
ASSERT_TRUE(g.has_node(2));
|
||||
ASSERT_TRUE(g.has_edge(0, 1));
|
||||
ASSERT_TRUE(g.has_edge(1, 2));
|
||||
|
||||
const auto n_edges_init = g.number_of_edges();
|
||||
const auto n_nodes_init = g.number_of_nodes();
|
||||
const auto node_1_degree = g.in_degree(1) + g.out_degree(1);
|
||||
|
||||
EXPECT_TRUE(g.remove_node(1));
|
||||
EXPECT_EQ(g.number_of_nodes(), n_nodes_init - 1u);
|
||||
EXPECT_EQ(g.number_of_edges(), n_edges_init - node_1_degree);
|
||||
EXPECT_EQ(g.number_of_edges(), g.edges().size());
|
||||
EXPECT_TRUE(g.has_node(0));
|
||||
EXPECT_FALSE(g.has_node(1));
|
||||
EXPECT_TRUE(g.has_node(2));
|
||||
EXPECT_EQ(g.in_degree(1), 0);
|
||||
EXPECT_EQ(g.out_degree(1), 0);
|
||||
EXPECT_FALSE(g.has_edge(0, 1));
|
||||
EXPECT_FALSE(g.has_edge(1, 2));
|
||||
g.for_each_node_id([&](auto id) { EXPECT_TRUE(g.has_node(id)); });
|
||||
|
||||
EXPECT_FALSE(g.remove_node(1));
|
||||
EXPECT_EQ(g.number_of_nodes(), n_nodes_init - 1u);
|
||||
EXPECT_EQ(g.number_of_edges(), n_edges_init - node_1_degree);
|
||||
EXPECT_EQ(g.number_of_edges(), g.edges().size());
|
||||
|
||||
const auto new_id = g.add_node(.7);
|
||||
EXPECT_EQ(new_id, n_nodes_init); // Ids are not invalidated so new id is used
|
||||
EXPECT_FALSE(g.has_node(1)); // Old id is not being confused
|
||||
EXPECT_EQ(g.number_of_nodes(), n_nodes_init);
|
||||
}
|
||||
|
||||
TEST(graph, degree)
|
||||
{
|
||||
const auto g = build_graph();
|
||||
EXPECT_EQ(g.out_degree(0), 2);
|
||||
EXPECT_EQ(g.out_degree(1), 2);
|
||||
EXPECT_EQ(g.out_degree(6), 0);
|
||||
EXPECT_EQ(g.in_degree(0), 0);
|
||||
EXPECT_EQ(g.in_degree(3), 2);
|
||||
EXPECT_EQ(g.in_degree(6), 1);
|
||||
}
|
||||
|
||||
TEST(graph, for_each_node)
|
||||
{
|
||||
const auto g = build_graph();
|
||||
using node_id = decltype(g)::node_id;
|
||||
std::size_t n_nodes = 0;
|
||||
g.for_each_node_id(
|
||||
[&](node_id id)
|
||||
{
|
||||
EXPECT_TRUE(g.has_node(id));
|
||||
++n_nodes;
|
||||
}
|
||||
);
|
||||
EXPECT_EQ(n_nodes, g.number_of_nodes());
|
||||
}
|
||||
|
||||
TEST(graph, for_each_edge)
|
||||
{
|
||||
const auto g = build_graph();
|
||||
using node_id = decltype(g)::node_id;
|
||||
std::size_t n_edges = 0;
|
||||
g.for_each_edge_id(
|
||||
[&g, &n_edges](node_id from, node_id to)
|
||||
{
|
||||
EXPECT_TRUE(g.has_edge(from, to));
|
||||
++n_edges;
|
||||
}
|
||||
);
|
||||
EXPECT_EQ(n_edges, g.number_of_edges());
|
||||
}
|
||||
|
||||
TEST(graph, for_each_leaf)
|
||||
{
|
||||
const auto g = build_graph();
|
||||
using node_id = decltype(g)::node_id;
|
||||
using node_id_list = decltype(g)::node_id_list;
|
||||
auto leaves = node_id_list();
|
||||
g.for_each_leaf_id([&leaves](node_id leaf) { leaves.insert(leaf); });
|
||||
EXPECT_EQ(leaves, node_id_list({ 4ul, 5ul, 6ul }));
|
||||
}
|
||||
|
||||
TEST(graph, for_each_leaf_from)
|
||||
{
|
||||
const auto g = build_graph();
|
||||
using node_id = decltype(g)::node_id;
|
||||
using node_id_list = decltype(g)::node_id_list;
|
||||
auto leaves = node_id_list();
|
||||
g.for_each_leaf_id_from(2ul, [&leaves](node_id leaf) { leaves.insert(leaf); });
|
||||
EXPECT_EQ(leaves, node_id_list({ 5ul, 6ul }));
|
||||
}
|
||||
|
||||
TEST(graph, for_each_root)
|
||||
{
|
||||
const auto g = build_graph();
|
||||
using node_id = decltype(g)::node_id;
|
||||
using node_id_list = decltype(g)::node_id_list;
|
||||
auto roots = node_id_list();
|
||||
g.for_each_root_id([&roots](node_id root) { roots.insert(root); });
|
||||
EXPECT_EQ(roots, node_id_list({ 0ul }));
|
||||
}
|
||||
|
||||
TEST(graph, for_each_root_from)
|
||||
{
|
||||
const auto g = build_graph();
|
||||
using node_id = decltype(g)::node_id;
|
||||
using node_id_list = decltype(g)::node_id_list;
|
||||
auto leaves = node_id_list();
|
||||
g.for_each_root_id_from(2ul, [&leaves](node_id leaf) { leaves.insert(leaf); });
|
||||
EXPECT_EQ(leaves, node_id_list({ 0ul }));
|
||||
}
|
||||
|
||||
TEST(graph, depth_first_search)
|
||||
{
|
||||
const auto g = build_graph();
|
||||
test_visitor<DiGraph<double>> vis;
|
||||
g.depth_first_search(vis);
|
||||
EXPECT_TRUE(vis.get_back_edge_map().empty());
|
||||
EXPECT_EQ(vis.get_cross_edge_map().find(2u)->second, 3u);
|
||||
}
|
||||
|
||||
TEST(graph, dfs_cyclic)
|
||||
{
|
||||
const auto g = build_cyclic_graph();
|
||||
test_visitor<DiGraph<double>> vis;
|
||||
g.depth_first_search(vis);
|
||||
EXPECT_EQ(vis.get_back_edge_map().find(2u)->second, 0u);
|
||||
EXPECT_TRUE(vis.get_cross_edge_map().empty());
|
||||
}
|
||||
|
||||
TEST(graph, dfs_empty)
|
||||
{
|
||||
DiGraph<int> g;
|
||||
test_visitor<DiGraph<int>> vis;
|
||||
g.depth_first_search(vis);
|
||||
EXPECT_TRUE(vis.get_back_edge_map().empty());
|
||||
EXPECT_TRUE(vis.get_cross_edge_map().empty());
|
||||
}
|
||||
|
||||
TEST(graph_algorithm, is_reachable)
|
||||
{
|
||||
auto graph = build_graph();
|
||||
EXPECT_TRUE(is_reachable(graph, 0, 6));
|
||||
EXPECT_FALSE(is_reachable(graph, 6, 0));
|
||||
}
|
||||
} // namespace mamba
|
|
@ -0,0 +1,93 @@
|
|||
// Copyright (c) 2023, QuantStack and Mamba Contributors
|
||||
//
|
||||
// Distributed under the terms of the BSD 3-Clause License.
|
||||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "mamba/util/cast.hpp"
|
||||
|
||||
using namespace mamba::util;
|
||||
|
||||
template <typename T>
|
||||
struct cast_valid : ::testing::Test
|
||||
{
|
||||
using First = typename T::first_type;
|
||||
using Second = typename T::second_type;
|
||||
};
|
||||
using WidenTypes = ::testing::Types<
|
||||
// integers
|
||||
std::pair<char, int>,
|
||||
std::pair<unsigned char, int>,
|
||||
std::pair<unsigned char, unsigned int>,
|
||||
std::pair<int, long long int>,
|
||||
std::pair<unsigned int, long long int>,
|
||||
std::pair<unsigned int, unsigned long long int>,
|
||||
// floats
|
||||
std::pair<float, double>,
|
||||
// Mixed
|
||||
std::pair<char, float>,
|
||||
std::pair<unsigned char, float>,
|
||||
std::pair<int, double>,
|
||||
std::pair<unsigned int, double>>;
|
||||
TYPED_TEST_SUITE(cast_valid, WidenTypes);
|
||||
|
||||
TYPED_TEST(cast_valid, checked_exact_num_cast_widen)
|
||||
{
|
||||
using From = typename TestFixture::First;
|
||||
using To = typename TestFixture::Second;
|
||||
static constexpr auto from_lowest = std::numeric_limits<From>::lowest();
|
||||
static constexpr auto from_max = std::numeric_limits<From>::max();
|
||||
|
||||
EXPECT_EQ(safe_num_cast<To>(From(0)), To(0));
|
||||
EXPECT_EQ(safe_num_cast<To>(From(1)), To(1));
|
||||
EXPECT_EQ(safe_num_cast<To>(from_lowest), static_cast<To>(from_lowest));
|
||||
EXPECT_EQ(safe_num_cast<To>(from_max), static_cast<To>(from_max));
|
||||
}
|
||||
|
||||
TYPED_TEST(cast_valid, checked_exact_num_cast_narrow)
|
||||
{
|
||||
using From = typename TestFixture::Second; // inversed
|
||||
using To = typename TestFixture::First; // inversed
|
||||
EXPECT_EQ(safe_num_cast<To>(From(0)), To(0));
|
||||
EXPECT_EQ(safe_num_cast<To>(From(1)), To(1));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct cast_overflow_lowest : ::testing::Test
|
||||
{
|
||||
using First = typename T::first_type;
|
||||
using Second = typename T::second_type;
|
||||
};
|
||||
using OverflowLowestTypes = ::testing::Types<
|
||||
// integers
|
||||
std::pair<char, unsigned char>,
|
||||
std::pair<char, unsigned int>,
|
||||
std::pair<int, char>,
|
||||
std::pair<int, unsigned long long int>,
|
||||
// floats
|
||||
std::pair<double, float>,
|
||||
// mixed
|
||||
std::pair<double, int>,
|
||||
std::pair<float, char>>;
|
||||
TYPED_TEST_SUITE(cast_overflow_lowest, OverflowLowestTypes);
|
||||
|
||||
TYPED_TEST(cast_overflow_lowest, checked_exact_num_cast)
|
||||
{
|
||||
using From = typename TestFixture::First;
|
||||
using To = typename TestFixture::Second;
|
||||
static constexpr auto from_lowest = std::numeric_limits<From>::lowest();
|
||||
|
||||
EXPECT_THROW(safe_num_cast<To>(from_lowest), std::overflow_error);
|
||||
}
|
||||
|
||||
TEST(cast, precision)
|
||||
{
|
||||
EXPECT_THROW(safe_num_cast<int>(1.1), std::runtime_error);
|
||||
EXPECT_THROW(safe_num_cast<float>(std::nextafter(double(1), 2)), std::runtime_error);
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
// Copyright (c) 2023, QuantStack and Mamba Contributors
|
||||
//
|
||||
// Distributed under the terms of the BSD 3-Clause License.
|
||||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "mamba/util/compare.hpp"
|
||||
|
||||
using namespace mamba::util;
|
||||
|
||||
|
||||
TEST(compare, equal)
|
||||
{
|
||||
EXPECT_TRUE(cmp_equal(char{ 0 }, char{ 0 }));
|
||||
EXPECT_TRUE(cmp_equal(char{ 1 }, char{ 1 }));
|
||||
EXPECT_TRUE(cmp_equal(char{ -1 }, char{ -1 }));
|
||||
EXPECT_TRUE(cmp_equal(int{ 0 }, int{ 0 }));
|
||||
EXPECT_TRUE(cmp_equal(int{ 1 }, int{ 1 }));
|
||||
EXPECT_TRUE(cmp_equal(int{ -1 }, int{ -1 }));
|
||||
EXPECT_TRUE(cmp_equal(std::size_t{ 0 }, std::size_t{ 0 }));
|
||||
EXPECT_TRUE(cmp_equal(std::size_t{ 1 }, std::size_t{ 1 }));
|
||||
|
||||
EXPECT_TRUE(cmp_equal(char{ 0 }, int{ 0 }));
|
||||
EXPECT_TRUE(cmp_equal(char{ 1 }, int{ 1 }));
|
||||
EXPECT_TRUE(cmp_equal(char{ -1 }, int{ -1 }));
|
||||
EXPECT_TRUE(cmp_equal(std::size_t{ 0 }, char{ 0 }));
|
||||
EXPECT_TRUE(cmp_equal(std::size_t{ 1 }, char{ 1 }));
|
||||
EXPECT_TRUE(cmp_equal(std::size_t{ 0 }, int{ 0 }));
|
||||
EXPECT_TRUE(cmp_equal(std::size_t{ 1 }, int{ 1 }));
|
||||
|
||||
EXPECT_FALSE(cmp_equal(char{ 0 }, char{ 1 }));
|
||||
EXPECT_FALSE(cmp_equal(char{ 1 }, char{ -1 }));
|
||||
EXPECT_FALSE(cmp_equal(int{ 0 }, int{ 1 }));
|
||||
EXPECT_FALSE(cmp_equal(int{ -1 }, int{ 1 }));
|
||||
EXPECT_FALSE(cmp_equal(std::size_t{ 0 }, std::size_t{ 1 }));
|
||||
|
||||
EXPECT_FALSE(cmp_equal(char{ 0 }, int{ 1 }));
|
||||
EXPECT_FALSE(cmp_equal(char{ 1 }, int{ -1 }));
|
||||
EXPECT_FALSE(cmp_equal(char{ -1 }, int{ 1 }));
|
||||
EXPECT_FALSE(cmp_equal(std::size_t{ 1 }, int{ -1 }));
|
||||
EXPECT_FALSE(cmp_equal(static_cast<std::size_t>(-1), int{ -1 }));
|
||||
EXPECT_FALSE(cmp_equal(std::size_t{ 1 }, int{ 0 }));
|
||||
EXPECT_FALSE(cmp_equal(std::numeric_limits<std::size_t>::max(), int{ 0 }));
|
||||
}
|
||||
|
||||
TEST(compare, less)
|
||||
{
|
||||
EXPECT_TRUE(cmp_less(char{ 0 }, char{ 1 }));
|
||||
EXPECT_TRUE(cmp_less(char{ -1 }, char{ 0 }));
|
||||
EXPECT_TRUE(cmp_less(int{ 0 }, int{ 1 }));
|
||||
EXPECT_TRUE(cmp_less(int{ -1 }, int{ 1 }));
|
||||
EXPECT_TRUE(cmp_less(std::size_t{ 0 }, std::size_t{ 1 }));
|
||||
|
||||
EXPECT_TRUE(cmp_less(char{ 0 }, int{ 1 }));
|
||||
EXPECT_TRUE(cmp_less(char{ -1 }, int{ 0 }));
|
||||
EXPECT_TRUE(cmp_less(char{ -1 }, int{ 1 }));
|
||||
EXPECT_TRUE(cmp_less(char{ -1 }, std::size_t{ 1 }));
|
||||
EXPECT_TRUE(cmp_less(std::size_t{ 0 }, int{ 1 }));
|
||||
EXPECT_TRUE(cmp_less(std::numeric_limits<int>::min(), char{ 0 }));
|
||||
EXPECT_TRUE(cmp_less(std::numeric_limits<int>::min(), std::size_t{ 0 }));
|
||||
EXPECT_TRUE(cmp_less(int{ -1 }, std::numeric_limits<std::size_t>::max()));
|
||||
EXPECT_TRUE(cmp_less(std::size_t{ 1 }, std::numeric_limits<int>::max()));
|
||||
|
||||
EXPECT_FALSE(cmp_less(char{ 1 }, char{ 0 }));
|
||||
EXPECT_FALSE(cmp_less(char{ 1 }, char{ 1 }));
|
||||
EXPECT_FALSE(cmp_less(char{ 0 }, char{ -1 }));
|
||||
EXPECT_FALSE(cmp_less(int{ 1 }, int{ 0 }));
|
||||
EXPECT_FALSE(cmp_less(int{ 1 }, int{ -1 }));
|
||||
EXPECT_FALSE(cmp_less(std::size_t{ 1 }, std::size_t{ 0 }));
|
||||
|
||||
EXPECT_FALSE(cmp_less(char{ 1 }, int{ 1 }));
|
||||
EXPECT_FALSE(cmp_less(char{ 1 }, int{ 0 }));
|
||||
EXPECT_FALSE(cmp_less(char{ 0 }, int{ -1 }));
|
||||
EXPECT_FALSE(cmp_less(char{ 1 }, int{ -11 }));
|
||||
EXPECT_FALSE(cmp_less(std::size_t{ 1 }, char{ -1 }));
|
||||
EXPECT_FALSE(cmp_less(int{ 1 }, std::size_t{ 0 }));
|
||||
EXPECT_FALSE(cmp_less(char{ 0 }, std::numeric_limits<int>::min()));
|
||||
EXPECT_FALSE(cmp_less(std::size_t{ 0 }, std::numeric_limits<int>::min()));
|
||||
EXPECT_FALSE(cmp_less(std::numeric_limits<std::size_t>::max(), int{ -1 }));
|
||||
EXPECT_FALSE(cmp_less(std::numeric_limits<int>::max(), std::size_t{ 1 }));
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
// Copyright (c) 2023, QuantStack and Mamba Contributors
|
||||
//
|
||||
// Distributed under the terms of the BSD 3-Clause License.
|
||||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "mamba/util/flat_set.hpp"
|
||||
|
||||
using namespace mamba::util;
|
||||
|
||||
TEST(flat_set, constructor)
|
||||
{
|
||||
const auto s1 = flat_set<int>();
|
||||
EXPECT_EQ(s1.size(), 0);
|
||||
auto s2 = flat_set<int>({ 1, 2 });
|
||||
EXPECT_EQ(s2.size(), 2);
|
||||
const auto s3 = flat_set<int>{ s2 };
|
||||
EXPECT_EQ(s3.size(), 2);
|
||||
const auto s4 = flat_set<int>{ std::move(s2) };
|
||||
EXPECT_EQ(s4.size(), 2);
|
||||
// CTAD
|
||||
auto s5 = flat_set({ 1, 2 });
|
||||
EXPECT_EQ(s5.size(), 2);
|
||||
static_assert(std::is_same_v<decltype(s5)::value_type, int>);
|
||||
auto s6 = flat_set(s5.begin(), s5.end(), std::greater{});
|
||||
EXPECT_EQ(s6.size(), s5.size());
|
||||
static_assert(std::is_same_v<decltype(s6)::value_type, decltype(s5)::value_type>);
|
||||
}
|
||||
|
||||
TEST(flat_set, equality)
|
||||
{
|
||||
EXPECT_EQ(flat_set<int>(), flat_set<int>());
|
||||
EXPECT_EQ(flat_set<int>({ 1, 2 }), flat_set<int>({ 1, 2 }));
|
||||
EXPECT_EQ(flat_set<int>({ 1, 2 }), flat_set<int>({ 2, 1 }));
|
||||
EXPECT_EQ(flat_set<int>({ 1, 2, 1 }), flat_set<int>({ 2, 2, 1 }));
|
||||
EXPECT_NE(flat_set<int>({ 1, 2 }), flat_set<int>({ 1, 2, 3 }));
|
||||
EXPECT_NE(flat_set<int>({ 2 }), flat_set<int>({}));
|
||||
}
|
||||
|
||||
TEST(flat_set, insert)
|
||||
{
|
||||
auto s = flat_set<int>();
|
||||
s.insert(33);
|
||||
EXPECT_EQ(s, flat_set<int>({ 33 }));
|
||||
s.insert(33);
|
||||
s.insert(17);
|
||||
EXPECT_EQ(s, flat_set<int>({ 17, 33 }));
|
||||
s.insert(22);
|
||||
EXPECT_EQ(s, flat_set<int>({ 17, 22, 33 }));
|
||||
s.insert(33);
|
||||
EXPECT_EQ(s, flat_set<int>({ 17, 22, 33 }));
|
||||
auto v = std::vector<int>({ 33, 22, 17, 0 });
|
||||
s.insert(v.begin(), v.end());
|
||||
EXPECT_EQ(s, flat_set<int>({ 0, 17, 22, 33 }));
|
||||
}
|
||||
|
||||
TEST(flat_set, erase)
|
||||
{
|
||||
auto s = flat_set<int>{ 4, 3, 2, 1 };
|
||||
EXPECT_EQ(s.erase(4), 1);
|
||||
EXPECT_EQ(s, flat_set<int>({ 1, 2, 3 }));
|
||||
EXPECT_EQ(s.erase(4), 0);
|
||||
EXPECT_EQ(s, flat_set<int>({ 1, 2, 3 }));
|
||||
|
||||
const auto it = s.erase(s.begin());
|
||||
EXPECT_EQ(it, s.begin());
|
||||
EXPECT_EQ(s, flat_set<int>({ 2, 3 }));
|
||||
}
|
||||
|
||||
TEST(flat_set, contains)
|
||||
{
|
||||
const auto s = flat_set<int>({ 1, 3, 4, 5 });
|
||||
EXPECT_FALSE(s.contains(0));
|
||||
EXPECT_TRUE(s.contains(1));
|
||||
EXPECT_FALSE(s.contains(2));
|
||||
EXPECT_TRUE(s.contains(3));
|
||||
EXPECT_TRUE(s.contains(4));
|
||||
EXPECT_TRUE(s.contains(5));
|
||||
EXPECT_FALSE(s.contains(6));
|
||||
}
|
||||
|
||||
TEST(flat_set, key_compare)
|
||||
{
|
||||
auto s = flat_set({ 1, 3, 4, 5 }, std::greater{});
|
||||
EXPECT_EQ(s.front(), 5);
|
||||
EXPECT_EQ(s.back(), 1);
|
||||
s.insert(6);
|
||||
EXPECT_EQ(s.front(), 6);
|
||||
}
|
|
@ -0,0 +1,348 @@
|
|||
// Copyright (c) 2023, QuantStack and Mamba Contributors
|
||||
//
|
||||
// Distributed under the terms of the BSD 3-Clause License.
|
||||
//
|
||||
// The full license is in the file LICENSE, distributed with this software.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "mamba/util/graph.hpp"
|
||||
|
||||
using namespace mamba::util;
|
||||
|
||||
auto
|
||||
build_graph() -> DiGraph<double>
|
||||
{
|
||||
DiGraph<double> g;
|
||||
const auto n0 = g.add_node(0.5);
|
||||
const auto n1 = g.add_node(1.5);
|
||||
const auto n2 = g.add_node(2.5);
|
||||
const auto n3 = g.add_node(3.5);
|
||||
const auto n4 = g.add_node(4.5);
|
||||
const auto n5 = g.add_node(5.5);
|
||||
const auto n6 = g.add_node(6.5);
|
||||
|
||||
g.add_edge(n0, n1);
|
||||
g.add_edge(n0, n2);
|
||||
g.add_edge(n1, n3);
|
||||
g.add_edge(n1, n4);
|
||||
g.add_edge(n2, n3);
|
||||
g.add_edge(n2, n5);
|
||||
g.add_edge(n3, n6);
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
auto
|
||||
build_cyclic_graph() -> DiGraph<double>
|
||||
{
|
||||
DiGraph<double> g;
|
||||
const auto n0 = g.add_node(0.5);
|
||||
const auto n1 = g.add_node(1.5);
|
||||
const auto n2 = g.add_node(2.5);
|
||||
const auto n3 = g.add_node(3.5);
|
||||
const auto n4 = g.add_node(4.5);
|
||||
|
||||
g.add_edge(n0, n1);
|
||||
g.add_edge(n0, n3);
|
||||
g.add_edge(n1, n2);
|
||||
g.add_edge(n2, n0);
|
||||
g.add_edge(n3, n4);
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
auto
|
||||
build_edge_data_graph() -> DiGraph<double, const char*>
|
||||
{
|
||||
auto g = DiGraph<double, const char*>{};
|
||||
const auto n0 = g.add_node(0.5);
|
||||
const auto n1 = g.add_node(1.5);
|
||||
const auto n2 = g.add_node(2.5);
|
||||
g.add_edge(n0, n1, "n0->n1");
|
||||
g.add_edge(n1, n2, "n1->n2");
|
||||
return g;
|
||||
}
|
||||
|
||||
template <class G>
|
||||
class test_visitor : private default_visitor<G>
|
||||
{
|
||||
public:
|
||||
|
||||
using base_type = default_visitor<G>;
|
||||
using node_id = typename base_type::node_id;
|
||||
using predecessor_map = std::map<node_id, node_id>;
|
||||
using edge_map = std::map<node_id, node_id>;
|
||||
|
||||
using base_type::finish_edge;
|
||||
using base_type::finish_node;
|
||||
using base_type::start_edge;
|
||||
using base_type::start_node;
|
||||
using base_type::tree_edge;
|
||||
|
||||
void back_edge(node_id from, node_id to, const G&)
|
||||
{
|
||||
m_back_edges[from] = to;
|
||||
}
|
||||
|
||||
void forward_or_cross_edge(node_id from, node_id to, const G&)
|
||||
{
|
||||
m_cross_edges[from] = to;
|
||||
}
|
||||
|
||||
auto get_back_edge_map() const -> const edge_map&
|
||||
{
|
||||
return m_back_edges;
|
||||
}
|
||||
|
||||
auto get_cross_edge_map() const -> const edge_map
|
||||
{
|
||||
return m_cross_edges;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
edge_map m_back_edges;
|
||||
edge_map m_cross_edges;
|
||||
};
|
||||
|
||||
TEST(graph, build_simple)
|
||||
{
|
||||
const auto g = build_graph();
|
||||
using node_map = decltype(g)::node_map;
|
||||
using node_id_list = decltype(g)::node_id_list;
|
||||
EXPECT_EQ(g.number_of_nodes(), 7ul);
|
||||
EXPECT_EQ(g.number_of_edges(), 7ul);
|
||||
EXPECT_EQ(
|
||||
g.nodes(),
|
||||
node_map({ { 0, 0.5 }, { 1, 1.5 }, { 2, 2.5 }, { 3, 3.5 }, { 4, 4.5 }, { 5, 5.5 }, { 6, 6.5 } })
|
||||
);
|
||||
EXPECT_EQ(g.successors(0u), node_id_list({ 1u, 2u }));
|
||||
EXPECT_EQ(g.successors(1u), node_id_list({ 3u, 4u }));
|
||||
EXPECT_EQ(g.successors(2u), node_id_list({ 3u, 5u }));
|
||||
EXPECT_EQ(g.successors(3u), node_id_list({ 6u }));
|
||||
EXPECT_EQ(g.predecessors(0u), node_id_list());
|
||||
EXPECT_EQ(g.predecessors(1u), node_id_list({ 0u }));
|
||||
EXPECT_EQ(g.predecessors(2u), node_id_list({ 0u }));
|
||||
EXPECT_EQ(g.predecessors(3u), node_id_list({ 1u, 2u }));
|
||||
}
|
||||
|
||||
TEST(graph, build_edge_data)
|
||||
{
|
||||
const auto g = build_edge_data_graph();
|
||||
using node_map = decltype(g)::node_map;
|
||||
using node_id_list = decltype(g)::node_id_list;
|
||||
EXPECT_EQ(g.number_of_nodes(), 3ul);
|
||||
EXPECT_EQ(g.number_of_edges(), 2ul);
|
||||
EXPECT_EQ(g.nodes(), node_map({ { 0, 0.5 }, { 1, 1.5 }, { 2, 2.5 } }));
|
||||
EXPECT_EQ(g.successors(0ul), node_id_list({ 1ul }));
|
||||
EXPECT_EQ(g.successors(1ul), node_id_list({ 2ul }));
|
||||
EXPECT_EQ(g.successors(2ul), node_id_list());
|
||||
EXPECT_EQ(g.predecessors(0ul), node_id_list());
|
||||
EXPECT_EQ(g.predecessors(1ul), node_id_list({ 0ul }));
|
||||
EXPECT_EQ(g.predecessors(2ul), node_id_list({ 1ul }));
|
||||
|
||||
using edge_map = decltype(g)::edge_map;
|
||||
EXPECT_EQ(g.edges(), edge_map({ { { 0ul, 1ul }, "n0->n1" }, { { 1ul, 2ul }, "n1->n2" } }));
|
||||
}
|
||||
|
||||
TEST(graph, has_node_edge)
|
||||
{
|
||||
const auto g = build_graph();
|
||||
EXPECT_TRUE(g.has_node(1ul));
|
||||
EXPECT_TRUE(g.has_node(4ul));
|
||||
EXPECT_FALSE(g.has_node(g.number_of_nodes()));
|
||||
EXPECT_TRUE(g.has_edge(1ul, 4ul));
|
||||
EXPECT_FALSE(g.has_edge(4ul, 1ul));
|
||||
EXPECT_TRUE(g.has_edge(0ul, 2ul));
|
||||
EXPECT_FALSE(g.has_edge(0ul, 5ul));
|
||||
EXPECT_FALSE(g.has_edge(0ul, g.number_of_nodes()));
|
||||
EXPECT_FALSE(g.has_edge(g.number_of_nodes(), 1ul));
|
||||
}
|
||||
|
||||
TEST(graph, data_modifier)
|
||||
{
|
||||
auto g = build_edge_data_graph();
|
||||
|
||||
static constexpr auto new_node_val = -1.5;
|
||||
EXPECT_NE(g.node(0ul), new_node_val);
|
||||
g.node(0ul) = new_node_val;
|
||||
EXPECT_EQ(g.node(0ul), new_node_val);
|
||||
|
||||
static constexpr auto new_edge_val = "data";
|
||||
EXPECT_NE(g.edge(0ul, 1ul), new_edge_val);
|
||||
g.edge(0ul, 1ul) = new_edge_val;
|
||||
EXPECT_EQ(g.edge(0ul, 1ul), new_edge_val);
|
||||
}
|
||||
|
||||
TEST(graph, remove_edge)
|
||||
{
|
||||
auto g = build_edge_data_graph();
|
||||
const auto n_edges_init = g.number_of_edges();
|
||||
|
||||
ASSERT_FALSE(g.has_edge(1, 0));
|
||||
ASSERT_TRUE(g.has_edge(0, 1));
|
||||
EXPECT_FALSE(g.remove_edge(1, 0));
|
||||
EXPECT_EQ(g.number_of_edges(), n_edges_init);
|
||||
EXPECT_FALSE(g.has_edge(1, 0));
|
||||
EXPECT_TRUE(g.has_edge(0, 1));
|
||||
|
||||
ASSERT_TRUE(g.has_edge(0, 1));
|
||||
EXPECT_TRUE(g.remove_edge(0, 1));
|
||||
EXPECT_EQ(g.number_of_edges(), n_edges_init - 1u);
|
||||
EXPECT_FALSE(g.has_edge(0, 1));
|
||||
EXPECT_EQ(g.edges().count({ 0, 1 }), 0);
|
||||
}
|
||||
|
||||
TEST(graph, remove_node)
|
||||
{
|
||||
auto g = build_edge_data_graph();
|
||||
|
||||
ASSERT_TRUE(g.has_node(0));
|
||||
ASSERT_TRUE(g.has_node(1));
|
||||
ASSERT_TRUE(g.has_node(2));
|
||||
ASSERT_TRUE(g.has_edge(0, 1));
|
||||
ASSERT_TRUE(g.has_edge(1, 2));
|
||||
|
||||
const auto n_edges_init = g.number_of_edges();
|
||||
const auto n_nodes_init = g.number_of_nodes();
|
||||
const auto node_1_degree = g.in_degree(1) + g.out_degree(1);
|
||||
|
||||
EXPECT_TRUE(g.remove_node(1));
|
||||
EXPECT_EQ(g.number_of_nodes(), n_nodes_init - 1u);
|
||||
EXPECT_EQ(g.number_of_edges(), n_edges_init - node_1_degree);
|
||||
EXPECT_EQ(g.number_of_edges(), g.edges().size());
|
||||
EXPECT_TRUE(g.has_node(0));
|
||||
EXPECT_FALSE(g.has_node(1));
|
||||
EXPECT_TRUE(g.has_node(2));
|
||||
EXPECT_EQ(g.in_degree(1), 0);
|
||||
EXPECT_EQ(g.out_degree(1), 0);
|
||||
EXPECT_FALSE(g.has_edge(0, 1));
|
||||
EXPECT_FALSE(g.has_edge(1, 2));
|
||||
g.for_each_node_id([&](auto id) { EXPECT_TRUE(g.has_node(id)); });
|
||||
|
||||
EXPECT_FALSE(g.remove_node(1));
|
||||
EXPECT_EQ(g.number_of_nodes(), n_nodes_init - 1u);
|
||||
EXPECT_EQ(g.number_of_edges(), n_edges_init - node_1_degree);
|
||||
EXPECT_EQ(g.number_of_edges(), g.edges().size());
|
||||
|
||||
const auto new_id = g.add_node(.7);
|
||||
EXPECT_EQ(new_id, n_nodes_init); // Ids are not invalidated so new id is used
|
||||
EXPECT_FALSE(g.has_node(1)); // Old id is not being confused
|
||||
EXPECT_EQ(g.number_of_nodes(), n_nodes_init);
|
||||
}
|
||||
|
||||
TEST(graph, degree)
|
||||
{
|
||||
const auto g = build_graph();
|
||||
EXPECT_EQ(g.out_degree(0), 2);
|
||||
EXPECT_EQ(g.out_degree(1), 2);
|
||||
EXPECT_EQ(g.out_degree(6), 0);
|
||||
EXPECT_EQ(g.in_degree(0), 0);
|
||||
EXPECT_EQ(g.in_degree(3), 2);
|
||||
EXPECT_EQ(g.in_degree(6), 1);
|
||||
}
|
||||
|
||||
TEST(graph, for_each_node)
|
||||
{
|
||||
const auto g = build_graph();
|
||||
using node_id = decltype(g)::node_id;
|
||||
std::size_t n_nodes = 0;
|
||||
g.for_each_node_id(
|
||||
[&](node_id id)
|
||||
{
|
||||
EXPECT_TRUE(g.has_node(id));
|
||||
++n_nodes;
|
||||
}
|
||||
);
|
||||
EXPECT_EQ(n_nodes, g.number_of_nodes());
|
||||
}
|
||||
|
||||
TEST(graph, for_each_edge)
|
||||
{
|
||||
const auto g = build_graph();
|
||||
using node_id = decltype(g)::node_id;
|
||||
std::size_t n_edges = 0;
|
||||
g.for_each_edge_id(
|
||||
[&g, &n_edges](node_id from, node_id to)
|
||||
{
|
||||
EXPECT_TRUE(g.has_edge(from, to));
|
||||
++n_edges;
|
||||
}
|
||||
);
|
||||
EXPECT_EQ(n_edges, g.number_of_edges());
|
||||
}
|
||||
|
||||
TEST(graph, for_each_leaf)
|
||||
{
|
||||
const auto g = build_graph();
|
||||
using node_id = decltype(g)::node_id;
|
||||
using node_id_list = decltype(g)::node_id_list;
|
||||
auto leaves = node_id_list();
|
||||
g.for_each_leaf_id([&leaves](node_id leaf) { leaves.insert(leaf); });
|
||||
EXPECT_EQ(leaves, node_id_list({ 4ul, 5ul, 6ul }));
|
||||
}
|
||||
|
||||
TEST(graph, for_each_leaf_from)
|
||||
{
|
||||
const auto g = build_graph();
|
||||
using node_id = decltype(g)::node_id;
|
||||
using node_id_list = decltype(g)::node_id_list;
|
||||
auto leaves = node_id_list();
|
||||
g.for_each_leaf_id_from(2ul, [&leaves](node_id leaf) { leaves.insert(leaf); });
|
||||
EXPECT_EQ(leaves, node_id_list({ 5ul, 6ul }));
|
||||
}
|
||||
|
||||
TEST(graph, for_each_root)
|
||||
{
|
||||
const auto g = build_graph();
|
||||
using node_id = decltype(g)::node_id;
|
||||
using node_id_list = decltype(g)::node_id_list;
|
||||
auto roots = node_id_list();
|
||||
g.for_each_root_id([&roots](node_id root) { roots.insert(root); });
|
||||
EXPECT_EQ(roots, node_id_list({ 0ul }));
|
||||
}
|
||||
|
||||
TEST(graph, for_each_root_from)
|
||||
{
|
||||
const auto g = build_graph();
|
||||
using node_id = decltype(g)::node_id;
|
||||
using node_id_list = decltype(g)::node_id_list;
|
||||
auto leaves = node_id_list();
|
||||
g.for_each_root_id_from(2ul, [&leaves](node_id leaf) { leaves.insert(leaf); });
|
||||
EXPECT_EQ(leaves, node_id_list({ 0ul }));
|
||||
}
|
||||
|
||||
TEST(graph, depth_first_search)
|
||||
{
|
||||
const auto g = build_graph();
|
||||
test_visitor<DiGraph<double>> vis;
|
||||
g.depth_first_search(vis);
|
||||
EXPECT_TRUE(vis.get_back_edge_map().empty());
|
||||
EXPECT_EQ(vis.get_cross_edge_map().find(2u)->second, 3u);
|
||||
}
|
||||
|
||||
TEST(graph, dfs_cyclic)
|
||||
{
|
||||
const auto g = build_cyclic_graph();
|
||||
test_visitor<DiGraph<double>> vis;
|
||||
g.depth_first_search(vis);
|
||||
EXPECT_EQ(vis.get_back_edge_map().find(2u)->second, 0u);
|
||||
EXPECT_TRUE(vis.get_cross_edge_map().empty());
|
||||
}
|
||||
|
||||
TEST(graph, dfs_empty)
|
||||
{
|
||||
DiGraph<int> g;
|
||||
test_visitor<DiGraph<int>> vis;
|
||||
g.depth_first_search(vis);
|
||||
EXPECT_TRUE(vis.get_back_edge_map().empty());
|
||||
EXPECT_TRUE(vis.get_cross_edge_map().empty());
|
||||
}
|
||||
|
||||
TEST(graph_algorithm, is_reachable)
|
||||
{
|
||||
auto graph = build_graph();
|
||||
EXPECT_TRUE(is_reachable(graph, 0, 6));
|
||||
EXPECT_FALSE(is_reachable(graph, 6, 0));
|
||||
}
|
|
@ -30,10 +30,10 @@
|
|||
#include "mamba/core/subdirdata.hpp"
|
||||
#include "mamba/core/transaction.hpp"
|
||||
#include "mamba/core/url.hpp"
|
||||
#include "mamba/core/util_graph.hpp"
|
||||
#include "mamba/core/util_string.hpp"
|
||||
#include "mamba/core/validate.hpp"
|
||||
#include "mamba/core/virtual_packages.hpp"
|
||||
#include "mamba/util/flat_set.hpp"
|
||||
|
||||
namespace py = pybind11;
|
||||
|
||||
|
@ -54,8 +54,8 @@ namespace PYBIND11_NAMESPACE
|
|||
namespace detail
|
||||
{
|
||||
template <typename Key, typename Compare, typename Allocator>
|
||||
struct type_caster<mamba::vector_set<Key, Compare, Allocator>>
|
||||
: set_caster<mamba::vector_set<Key, Compare, Allocator>, Key>
|
||||
struct type_caster<mamba::util::flat_set<Key, Compare, Allocator>>
|
||||
: set_caster<mamba::util::flat_set<Key, Compare, Allocator>, Key>
|
||||
{
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue