|
|
@@ -3,13 +3,10 @@
|
|
|
|
|
|
#include <cstddef>
|
|
|
#include <iterator>
|
|
|
-#include <memory>
|
|
|
#include <tuple>
|
|
|
#include <type_traits>
|
|
|
#include <utility>
|
|
|
-#include <vector>
|
|
|
#include "../config/config.h"
|
|
|
-#include "../core/compressed_pair.hpp"
|
|
|
#include "../core/iterator.hpp"
|
|
|
#include "fwd.hpp"
|
|
|
|
|
|
@@ -146,44 +143,46 @@ template<typename... Lhs, typename... Rhs>
|
|
|
* no guarantees that objects are returned in the insertion order when iterate
|
|
|
* a table. Do not make assumption on the order in any case.
|
|
|
*
|
|
|
- * @tparam Row Element types.
|
|
|
- * @tparam Allocator Type of allocator used to manage memory and elements.
|
|
|
+ * @tparam Container Sequence container row types.
|
|
|
*/
|
|
|
-template<typename... Row, typename Allocator>
|
|
|
-class basic_table<type_list<Row...>, Allocator> {
|
|
|
- using alloc_traits = std::allocator_traits<Allocator>;
|
|
|
- static_assert(sizeof...(Row) != 0u, "Empty tables not allowed");
|
|
|
-
|
|
|
- template<typename Type>
|
|
|
- using container_for = std::vector<Type, typename alloc_traits::template rebind_alloc<Type>>;
|
|
|
-
|
|
|
- using container_type = std::tuple<container_for<Row>...>;
|
|
|
+template<typename... Container>
|
|
|
+class basic_table {
|
|
|
+ using container_type = std::tuple<Container...>;
|
|
|
|
|
|
public:
|
|
|
- /*! @brief Allocator type. */
|
|
|
- using allocator_type = Allocator;
|
|
|
/*! @brief Unsigned integer type. */
|
|
|
using size_type = std::size_t;
|
|
|
/*! @brief Input iterator type. */
|
|
|
- using iterator = internal::table_iterator<typename container_for<Row>::iterator...>;
|
|
|
+ using iterator = internal::table_iterator<typename Container::iterator...>;
|
|
|
/*! @brief Constant input iterator type. */
|
|
|
- using const_iterator = internal::table_iterator<typename container_for<Row>::const_iterator...>;
|
|
|
+ using const_iterator = internal::table_iterator<typename Container::const_iterator...>;
|
|
|
/*! @brief Reverse iterator type. */
|
|
|
- using reverse_iterator = internal::table_iterator<typename container_for<Row>::reverse_iterator...>;
|
|
|
+ using reverse_iterator = internal::table_iterator<typename Container::reverse_iterator...>;
|
|
|
/*! @brief Constant reverse iterator type. */
|
|
|
- using const_reverse_iterator = internal::table_iterator<typename container_for<Row>::const_reverse_iterator...>;
|
|
|
+ using const_reverse_iterator = internal::table_iterator<typename Container::const_reverse_iterator...>;
|
|
|
|
|
|
/*! @brief Default constructor. */
|
|
|
basic_table()
|
|
|
- : basic_table{allocator_type{}} {
|
|
|
+ : payload{} {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * @brief Constructs an empty table with a given allocator.
|
|
|
- * @param allocator The allocator to use.
|
|
|
+ * @brief Copy constructs the underlying containers.
|
|
|
+ * @param container The containers to copy from.
|
|
|
+ */
|
|
|
+ explicit basic_table(const Container &...container) noexcept
|
|
|
+ : payload{container...} {
|
|
|
+ ENTT_ASSERT((((std::get<Container>(payload).size() * sizeof...(Container)) == (std::get<Container>(payload).size() + ...)) && ...), "Unexpected container size");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Move constructs the underlying containers.
|
|
|
+ * @param container The containers to move from.
|
|
|
*/
|
|
|
- explicit basic_table(const allocator_type &allocator)
|
|
|
- : payload{container_type{container_for<Row>{allocator}...}, allocator} {}
|
|
|
+ explicit basic_table(Container &&...container) noexcept
|
|
|
+ : payload{std::move(container)...} {
|
|
|
+ ENTT_ASSERT((((std::get<Container>(payload).size() * sizeof...(Container)) == (std::get<Container>(payload).size() + ...)) && ...), "Unexpected container size");
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* @brief Move constructor.
|
|
|
@@ -192,15 +191,48 @@ public:
|
|
|
basic_table(basic_table &&other) noexcept
|
|
|
: payload{std::move(other.payload)} {}
|
|
|
|
|
|
+ /**
|
|
|
+ * @brief Constructs the underlying containers using a given allocator.
|
|
|
+ * @tparam Allocator Type of allocator.
|
|
|
+ * @param allocator A valid allocator.
|
|
|
+ */
|
|
|
+ template<typename Allocator>
|
|
|
+ explicit basic_table(const Allocator &allocator)
|
|
|
+ : payload{Container{allocator}...} {}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Copy constructs the underlying containers using a given allocator.
|
|
|
+ * @tparam Allocator Type of allocator.
|
|
|
+ * @param container The containers to copy from.
|
|
|
+ * @param allocator A valid allocator.
|
|
|
+ */
|
|
|
+ template<class Allocator>
|
|
|
+ basic_table(const Container &...container, const Allocator &allocator) noexcept
|
|
|
+ : payload{Container{container, allocator}...} {
|
|
|
+ ENTT_ASSERT((((std::get<Container>(payload).size() * sizeof...(Container)) == (std::get<Container>(payload).size() + ...)) && ...), "Unexpected container size");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Move constructs the underlying containers using a given allocator.
|
|
|
+ * @tparam Allocator Type of allocator.
|
|
|
+ * @param container The containers to move from.
|
|
|
+ * @param allocator A valid allocator.
|
|
|
+ */
|
|
|
+ template<class Allocator>
|
|
|
+ basic_table(Container &&...container, const Allocator &allocator) noexcept
|
|
|
+ : payload{Container{std::move(container), allocator}...} {
|
|
|
+ ENTT_ASSERT((((std::get<Container>(payload).size() * sizeof...(Container)) == (std::get<Container>(payload).size() + ...)) && ...), "Unexpected container size");
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* @brief Allocator-extended move constructor.
|
|
|
+ * @tparam Allocator Type of allocator.
|
|
|
* @param other The instance to move from.
|
|
|
* @param allocator The allocator to use.
|
|
|
*/
|
|
|
- basic_table(basic_table &&other, const allocator_type &allocator) noexcept
|
|
|
- : payload{container_type{container_for<Row>{std::move(std::get<container_for<Row>>(other.payload.first())), allocator}...}, allocator} {
|
|
|
- ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a table is not allowed");
|
|
|
- }
|
|
|
+ template<class Allocator>
|
|
|
+ basic_table(basic_table &&other, const Allocator &allocator) noexcept
|
|
|
+ : payload{Container{std::move(std::get<Container>(other.payload)), allocator}...} {}
|
|
|
|
|
|
/**
|
|
|
* @brief Move assignment operator.
|
|
|
@@ -208,7 +240,6 @@ public:
|
|
|
* @return This table.
|
|
|
*/
|
|
|
basic_table &operator=(basic_table &&other) noexcept {
|
|
|
- ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a table is not allowed");
|
|
|
payload = std::move(other.payload);
|
|
|
return *this;
|
|
|
}
|
|
|
@@ -222,14 +253,6 @@ public:
|
|
|
swap(payload, other.payload);
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * @brief Returns the associated allocator.
|
|
|
- * @return The associated allocator.
|
|
|
- */
|
|
|
- [[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
|
|
|
- return payload.second();
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* @brief Increases the capacity of a table.
|
|
|
*
|
|
|
@@ -239,7 +262,7 @@ public:
|
|
|
* @param cap Desired capacity.
|
|
|
*/
|
|
|
void reserve(const size_type cap) {
|
|
|
- (std::get<container_for<Row>>(payload.first()).reserve(cap), ...);
|
|
|
+ (std::get<Container>(payload).reserve(cap), ...);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -248,12 +271,12 @@ public:
|
|
|
* @return Capacity of the table.
|
|
|
*/
|
|
|
[[nodiscard]] size_type capacity() const noexcept {
|
|
|
- return std::get<0>(payload.first()).capacity();
|
|
|
+ return std::get<0>(payload).capacity();
|
|
|
}
|
|
|
|
|
|
/*! @brief Requests the removal of unused capacity. */
|
|
|
void shrink_to_fit() {
|
|
|
- (std::get<container_for<Row>>(payload.first()).shrink_to_fit(), ...);
|
|
|
+ (std::get<Container>(payload).shrink_to_fit(), ...);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -261,7 +284,7 @@ public:
|
|
|
* @return Number of rows.
|
|
|
*/
|
|
|
[[nodiscard]] size_type size() const noexcept {
|
|
|
- return std::get<0>(payload.first()).size();
|
|
|
+ return std::get<0>(payload).size();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -269,7 +292,7 @@ public:
|
|
|
* @return True if the table is empty, false otherwise.
|
|
|
*/
|
|
|
[[nodiscard]] bool empty() const noexcept {
|
|
|
- return std::get<0>(payload.first()).empty();
|
|
|
+ return std::get<0>(payload).empty();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -280,7 +303,7 @@ public:
|
|
|
* @return An iterator to the first row of the table.
|
|
|
*/
|
|
|
[[nodiscard]] const_iterator cbegin() const noexcept {
|
|
|
- return {std::get<container_for<Row>>(payload.first()).cbegin()...};
|
|
|
+ return {std::get<Container>(payload).cbegin()...};
|
|
|
}
|
|
|
|
|
|
/*! @copydoc cbegin */
|
|
|
@@ -290,7 +313,7 @@ public:
|
|
|
|
|
|
/*! @copydoc begin */
|
|
|
[[nodiscard]] iterator begin() noexcept {
|
|
|
- return {std::get<container_for<Row>>(payload.first()).begin()...};
|
|
|
+ return {std::get<Container>(payload).begin()...};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -298,7 +321,7 @@ public:
|
|
|
* @return An iterator to the element following the last row of the table.
|
|
|
*/
|
|
|
[[nodiscard]] const_iterator cend() const noexcept {
|
|
|
- return {std::get<container_for<Row>>(payload.first()).cend()...};
|
|
|
+ return {std::get<Container>(payload).cend()...};
|
|
|
}
|
|
|
|
|
|
/*! @copydoc cend */
|
|
|
@@ -308,7 +331,7 @@ public:
|
|
|
|
|
|
/*! @copydoc end */
|
|
|
[[nodiscard]] iterator end() noexcept {
|
|
|
- return {std::get<container_for<Row>>(payload.first()).end()...};
|
|
|
+ return {std::get<Container>(payload).end()...};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -319,7 +342,7 @@ public:
|
|
|
* @return An iterator to the first row of the reversed table.
|
|
|
*/
|
|
|
[[nodiscard]] const_reverse_iterator crbegin() const noexcept {
|
|
|
- return {std::get<container_for<Row>>(payload.first()).crbegin()...};
|
|
|
+ return {std::get<Container>(payload).crbegin()...};
|
|
|
}
|
|
|
|
|
|
/*! @copydoc crbegin */
|
|
|
@@ -329,7 +352,7 @@ public:
|
|
|
|
|
|
/*! @copydoc rbegin */
|
|
|
[[nodiscard]] reverse_iterator rbegin() noexcept {
|
|
|
- return {std::get<container_for<Row>>(payload.first()).rbegin()...};
|
|
|
+ return {std::get<Container>(payload).rbegin()...};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -338,7 +361,7 @@ public:
|
|
|
* table.
|
|
|
*/
|
|
|
[[nodiscard]] const_reverse_iterator crend() const noexcept {
|
|
|
- return {std::get<container_for<Row>>(payload.first()).crend()...};
|
|
|
+ return {std::get<Container>(payload).crend()...};
|
|
|
}
|
|
|
|
|
|
/*! @copydoc crend */
|
|
|
@@ -348,7 +371,7 @@ public:
|
|
|
|
|
|
/*! @copydoc rend */
|
|
|
[[nodiscard]] reverse_iterator rend() noexcept {
|
|
|
- return {std::get<container_for<Row>>(payload.first()).rend()...};
|
|
|
+ return {std::get<Container>(payload).rend()...};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -358,11 +381,11 @@ public:
|
|
|
* @return A reference to the newly created row data.
|
|
|
*/
|
|
|
template<typename... Args>
|
|
|
- std::tuple<Row &...> emplace(Args &&...args) {
|
|
|
+ std::tuple<typename Container::value_type &...> emplace(Args &&...args) {
|
|
|
if constexpr(sizeof...(Args) == 0u) {
|
|
|
- return std::forward_as_tuple(std::get<container_for<Row>>(payload.first()).emplace_back()...);
|
|
|
+ return std::forward_as_tuple(std::get<Container>(payload).emplace_back()...);
|
|
|
} else {
|
|
|
- return std::forward_as_tuple(std::get<container_for<Row>>(payload.first()).emplace_back(std::forward<Args>(args))...);
|
|
|
+ return std::forward_as_tuple(std::get<Container>(payload).emplace_back(std::forward<Args>(args))...);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -373,7 +396,7 @@ public:
|
|
|
*/
|
|
|
iterator erase(const_iterator pos) {
|
|
|
const auto diff = pos - begin();
|
|
|
- return {std::get<container_for<Row>>(payload.first()).erase(std::get<container_for<Row>>(payload.first()).begin() + diff)...};
|
|
|
+ return {std::get<Container>(payload).erase(std::get<Container>(payload).begin() + diff)...};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -390,26 +413,36 @@ public:
|
|
|
* @param pos The row for which to return the data.
|
|
|
* @return The row data at specified location.
|
|
|
*/
|
|
|
- [[nodiscard]] std::tuple<const Row &...> operator[](const size_type pos) const {
|
|
|
+ [[nodiscard]] std::tuple<const typename Container::value_type &...> operator[](const size_type pos) const {
|
|
|
ENTT_ASSERT(pos < size(), "Index out of bounds");
|
|
|
- return std::forward_as_tuple(std::get<container_for<Row>>(payload.first())[pos]...);
|
|
|
+ return std::forward_as_tuple(std::get<Container>(payload)[pos]...);
|
|
|
}
|
|
|
|
|
|
/*! @copydoc operator[] */
|
|
|
- [[nodiscard]] std::tuple<Row &...> operator[](const size_type pos) {
|
|
|
+ [[nodiscard]] std::tuple<typename Container::value_type &...> operator[](const size_type pos) {
|
|
|
ENTT_ASSERT(pos < size(), "Index out of bounds");
|
|
|
- return std::forward_as_tuple(std::get<container_for<Row>>(payload.first())[pos]...);
|
|
|
+ return std::forward_as_tuple(std::get<Container>(payload)[pos]...);
|
|
|
}
|
|
|
|
|
|
/*! @brief Clears a table. */
|
|
|
void clear() {
|
|
|
- (std::get<container_for<Row>>(payload.first()).clear(), ...);
|
|
|
+ (std::get<Container>(payload).clear(), ...);
|
|
|
}
|
|
|
|
|
|
private:
|
|
|
- compressed_pair<container_type, allocator_type> payload;
|
|
|
+ container_type payload;
|
|
|
};
|
|
|
|
|
|
} // namespace entt
|
|
|
|
|
|
+/*! @cond TURN_OFF_DOXYGEN */
|
|
|
+namespace std {
|
|
|
+
|
|
|
+template<typename... Container, typename Allocator>
|
|
|
+struct uses_allocator<entt::basic_table<Container...>, Allocator>
|
|
|
+ : std::bool_constant<(std::uses_allocator_v<Container, Allocator> && ...)> {};
|
|
|
+
|
|
|
+} // namespace std
|
|
|
+/*! @endcond */
|
|
|
+
|
|
|
#endif
|