Commit 10442d50 by Maarten L. Hekkelman

structured binding, start

parent 573a695c
...@@ -1368,7 +1368,7 @@ namespace literals ...@@ -1368,7 +1368,7 @@ namespace literals
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// iterators // iterators
template <typename CategoryType, typename... Ts> template <typename Category, typename... Ts>
class iterator_impl class iterator_impl
{ {
public: public:
...@@ -1377,7 +1377,7 @@ class iterator_impl ...@@ -1377,7 +1377,7 @@ class iterator_impl
static constexpr size_t N = sizeof...(Ts); static constexpr size_t N = sizeof...(Ts);
using row_type = std::conditional_t<std::is_const_v<CategoryType>, const Row, Row>; using row_type = std::conditional_t<std::is_const_v<Category>, const Row, Row>;
using iterator_category = std::forward_iterator_tag; using iterator_category = std::forward_iterator_tag;
using value_type = std::conditional_t<N == 0, row_type, std::tuple<Ts...>>; using value_type = std::conditional_t<N == 0, row_type, std::tuple<Ts...>>;
...@@ -1385,8 +1385,6 @@ class iterator_impl ...@@ -1385,8 +1385,6 @@ class iterator_impl
using pointer = value_type *; using pointer = value_type *;
using reference = value_type &; using reference = value_type &;
friend class Category;
// default constructor, equal to end() // default constructor, equal to end()
iterator_impl() {} iterator_impl() {}
...@@ -1510,19 +1508,19 @@ class iterator_impl ...@@ -1510,19 +1508,19 @@ class iterator_impl
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// iterator proxy // iterator proxy
template <typename CategoryType, typename... Ts> template <typename Category, typename... Ts>
class iterator_proxy class iterator_proxy
{ {
public: public:
static constexpr const size_t N = sizeof...(Ts); static constexpr const size_t N = sizeof...(Ts);
using row_type = std::conditional_t<std::is_const_v<CategoryType>, const Row, Row>; using row_type = std::conditional_t<std::is_const_v<Category>, const Row, Row>;
using iterator = iterator_impl<row_type, Ts...>; using iterator = iterator_impl<row_type, Ts...>;
using row_iterator = iterator_impl<row_type>; using row_iterator = iterator_impl<row_type>;
iterator_proxy(CategoryType &cat, row_iterator pos, char const *const columns[N]); iterator_proxy(Category &cat, row_iterator pos, char const *const columns[N]);
iterator_proxy(CategoryType &cat, row_iterator pos, std::initializer_list<char const *> columns); iterator_proxy(Category &cat, row_iterator pos, std::initializer_list<char const *> columns);
iterator_proxy(iterator_proxy &&p); iterator_proxy(iterator_proxy &&p);
iterator_proxy &operator=(iterator_proxy &&p); iterator_proxy &operator=(iterator_proxy &&p);
...@@ -1542,7 +1540,7 @@ class iterator_proxy ...@@ -1542,7 +1540,7 @@ class iterator_proxy
row_type front() { return *begin(); } row_type front() { return *begin(); }
row_type back() { return *(std::prev(end())); } row_type back() { return *(std::prev(end())); }
CategoryType &category() const { return *mCat; } Category &category() const { return *mCat; }
void swap(iterator_proxy &rhs) void swap(iterator_proxy &rhs)
{ {
...@@ -1553,7 +1551,7 @@ class iterator_proxy ...@@ -1553,7 +1551,7 @@ class iterator_proxy
} }
private: private:
CategoryType *mCat; Category *mCat;
row_iterator mCBegin, mCEnd; row_iterator mCBegin, mCEnd;
std::array<size_t, N> mCix; std::array<size_t, N> mCix;
}; };
...@@ -1561,13 +1559,13 @@ class iterator_proxy ...@@ -1561,13 +1559,13 @@ class iterator_proxy
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// conditional iterator proxy // conditional iterator proxy
template <typename CategoryType, typename... Ts> template <typename Category, typename... Ts>
class conditional_iterator_proxy class conditional_iterator_proxy
{ {
public: public:
static constexpr const size_t N = sizeof...(Ts); static constexpr const size_t N = sizeof...(Ts);
using base_iterator = iterator_impl<CategoryType, Ts...>; using base_iterator = iterator_impl<Category, Ts...>;
using value_type = typename base_iterator::value_type; using value_type = typename base_iterator::value_type;
using row_type = typename base_iterator::row_type; using row_type = typename base_iterator::row_type;
using row_iterator = iterator_impl<row_type>; using row_iterator = iterator_impl<row_type>;
...@@ -1581,7 +1579,7 @@ class conditional_iterator_proxy ...@@ -1581,7 +1579,7 @@ class conditional_iterator_proxy
using pointer = value_type *; using pointer = value_type *;
using reference = value_type &; using reference = value_type &;
conditional_iterator_impl(CategoryType &cat, row_iterator pos, const Condition &cond, const std::array<size_t, N> &cix); conditional_iterator_impl(Category &cat, row_iterator pos, const Condition &cond, const std::array<size_t, N> &cix);
conditional_iterator_impl(const conditional_iterator_impl &i) = default; conditional_iterator_impl(const conditional_iterator_impl &i) = default;
conditional_iterator_impl &operator=(const conditional_iterator_impl &i) = default; conditional_iterator_impl &operator=(const conditional_iterator_impl &i) = default;
...@@ -1628,7 +1626,7 @@ class conditional_iterator_proxy ...@@ -1628,7 +1626,7 @@ class conditional_iterator_proxy
bool operator!=(const iterator_impl<IRowType, ITs...> &rhs) const { return mBegin != rhs; } bool operator!=(const iterator_impl<IRowType, ITs...> &rhs) const { return mBegin != rhs; }
private: private:
CategoryType *mCat; Category *mCat;
base_iterator mBegin, mEnd; base_iterator mBegin, mEnd;
const Condition *mCondition; const Condition *mCondition;
}; };
...@@ -1637,7 +1635,7 @@ class conditional_iterator_proxy ...@@ -1637,7 +1635,7 @@ class conditional_iterator_proxy
using reference = typename iterator::reference; using reference = typename iterator::reference;
template <typename... Ns> template <typename... Ns>
conditional_iterator_proxy(CategoryType &cat, row_iterator pos, Condition &&cond, Ns... names); conditional_iterator_proxy(Category &cat, row_iterator pos, Condition &&cond, Ns... names);
conditional_iterator_proxy(conditional_iterator_proxy &&p); conditional_iterator_proxy(conditional_iterator_proxy &&p);
conditional_iterator_proxy &operator=(conditional_iterator_proxy &&p); conditional_iterator_proxy &operator=(conditional_iterator_proxy &&p);
...@@ -1656,12 +1654,12 @@ class conditional_iterator_proxy ...@@ -1656,12 +1654,12 @@ class conditional_iterator_proxy
row_type front() { return *begin(); } row_type front() { return *begin(); }
CategoryType &category() const { return *mCat; } Category &category() const { return *mCat; }
void swap(conditional_iterator_proxy &rhs); void swap(conditional_iterator_proxy &rhs);
private: private:
CategoryType *mCat; Category *mCat;
Condition mCondition; Condition mCondition;
row_iterator mCBegin, mCEnd; row_iterator mCBegin, mCEnd;
std::array<size_t, N> mCix; std::array<size_t, N> mCix;
...@@ -2353,8 +2351,8 @@ inline void swap(cif::detail::ItemReference &a, cif::detail::ItemReference &b) ...@@ -2353,8 +2351,8 @@ inline void swap(cif::detail::ItemReference &a, cif::detail::ItemReference &b)
// -------------------------------------------------------------------- // --------------------------------------------------------------------
template <typename CategoryType, typename... Ts> template <typename Category, typename... Ts>
iterator_proxy<CategoryType, Ts...>::iterator_proxy(CategoryType &cat, row_iterator pos, char const *const columns[N]) iterator_proxy<Category, Ts...>::iterator_proxy(Category &cat, row_iterator pos, char const *const columns[N])
: mCat(&cat) : mCat(&cat)
, mCBegin(pos) , mCBegin(pos)
, mCEnd(cat.end()) , mCEnd(cat.end())
...@@ -2363,8 +2361,8 @@ iterator_proxy<CategoryType, Ts...>::iterator_proxy(CategoryType &cat, row_itera ...@@ -2363,8 +2361,8 @@ iterator_proxy<CategoryType, Ts...>::iterator_proxy(CategoryType &cat, row_itera
mCix[i] = mCat->getColumnIndex(columns[i]); mCix[i] = mCat->getColumnIndex(columns[i]);
} }
template <typename CategoryType, typename... Ts> template <typename Category, typename... Ts>
iterator_proxy<CategoryType, Ts...>::iterator_proxy(CategoryType &cat, row_iterator pos, std::initializer_list<char const *> columns) iterator_proxy<Category, Ts...>::iterator_proxy(Category &cat, row_iterator pos, std::initializer_list<char const *> columns)
: mCat(&cat) : mCat(&cat)
, mCBegin(pos) , mCBegin(pos)
, mCEnd(cat.end()) , mCEnd(cat.end())
...@@ -2378,9 +2376,9 @@ iterator_proxy<CategoryType, Ts...>::iterator_proxy(CategoryType &cat, row_itera ...@@ -2378,9 +2376,9 @@ iterator_proxy<CategoryType, Ts...>::iterator_proxy(CategoryType &cat, row_itera
// -------------------------------------------------------------------- // --------------------------------------------------------------------
template <typename CategoryType, typename... Ts> template <typename Category, typename... Ts>
conditional_iterator_proxy<CategoryType, Ts...>::conditional_iterator_impl::conditional_iterator_impl( conditional_iterator_proxy<Category, Ts...>::conditional_iterator_impl::conditional_iterator_impl(
CategoryType &cat, row_iterator pos, const Condition &cond, const std::array<size_t, N> &cix) Category &cat, row_iterator pos, const Condition &cond, const std::array<size_t, N> &cix)
: mCat(&cat) : mCat(&cat)
, mBegin(pos, cix) , mBegin(pos, cix)
, mEnd(cat.end(), cix) , mEnd(cat.end(), cix)
...@@ -2388,8 +2386,8 @@ conditional_iterator_proxy<CategoryType, Ts...>::conditional_iterator_impl::cond ...@@ -2388,8 +2386,8 @@ conditional_iterator_proxy<CategoryType, Ts...>::conditional_iterator_impl::cond
{ {
} }
template <typename CategoryType, typename... Ts> template <typename Category, typename... Ts>
conditional_iterator_proxy<CategoryType, Ts...>::conditional_iterator_proxy(conditional_iterator_proxy &&p) conditional_iterator_proxy<Category, Ts...>::conditional_iterator_proxy(conditional_iterator_proxy &&p)
: mCat(nullptr) : mCat(nullptr)
, mCBegin(p.mCBegin) , mCBegin(p.mCBegin)
, mCEnd(p.mCEnd) , mCEnd(p.mCEnd)
...@@ -2400,9 +2398,9 @@ conditional_iterator_proxy<CategoryType, Ts...>::conditional_iterator_proxy(cond ...@@ -2400,9 +2398,9 @@ conditional_iterator_proxy<CategoryType, Ts...>::conditional_iterator_proxy(cond
mCondition.swap(p.mCondition); mCondition.swap(p.mCondition);
} }
template <typename CategoryType, typename... Ts> template <typename Category, typename... Ts>
template <typename... Ns> template <typename... Ns>
conditional_iterator_proxy<CategoryType, Ts...>::conditional_iterator_proxy(CategoryType &cat, row_iterator pos, Condition &&cond, Ns... names) conditional_iterator_proxy<Category, Ts...>::conditional_iterator_proxy(Category &cat, row_iterator pos, Condition &&cond, Ns... names)
: mCat(&cat) : mCat(&cat)
, mCondition(std::move(cond)) , mCondition(std::move(cond))
, mCBegin(pos) , mCBegin(pos)
...@@ -2419,33 +2417,33 @@ conditional_iterator_proxy<CategoryType, Ts...>::conditional_iterator_proxy(Cate ...@@ -2419,33 +2417,33 @@ conditional_iterator_proxy<CategoryType, Ts...>::conditional_iterator_proxy(Cate
((mCix[i++] = mCat->getColumnIndex(names)), ...); ((mCix[i++] = mCat->getColumnIndex(names)), ...);
} }
template <typename CategoryType, typename... Ts> template <typename Category, typename... Ts>
conditional_iterator_proxy<CategoryType, Ts...> &conditional_iterator_proxy<CategoryType, Ts...>::operator=(conditional_iterator_proxy &&p) conditional_iterator_proxy<Category, Ts...> &conditional_iterator_proxy<Category, Ts...>::operator=(conditional_iterator_proxy &&p)
{ {
swap(p); swap(p);
return *this; return *this;
} }
template <typename CategoryType, typename... Ts> template <typename Category, typename... Ts>
typename conditional_iterator_proxy<CategoryType, Ts...>::iterator conditional_iterator_proxy<CategoryType, Ts...>::begin() const typename conditional_iterator_proxy<Category, Ts...>::iterator conditional_iterator_proxy<Category, Ts...>::begin() const
{ {
return iterator(*mCat, mCBegin, mCondition, mCix); return iterator(*mCat, mCBegin, mCondition, mCix);
} }
template <typename CategoryType, typename... Ts> template <typename Category, typename... Ts>
typename conditional_iterator_proxy<CategoryType, Ts...>::iterator conditional_iterator_proxy<CategoryType, Ts...>::end() const typename conditional_iterator_proxy<Category, Ts...>::iterator conditional_iterator_proxy<Category, Ts...>::end() const
{ {
return iterator(*mCat, mCEnd, mCondition, mCix); return iterator(*mCat, mCEnd, mCondition, mCix);
} }
template <typename CategoryType, typename... Ts> template <typename Category, typename... Ts>
bool conditional_iterator_proxy<CategoryType, Ts...>::empty() const bool conditional_iterator_proxy<Category, Ts...>::empty() const
{ {
return mCBegin == mCEnd; return mCBegin == mCEnd;
} }
template <typename CategoryType, typename... Ts> template <typename Category, typename... Ts>
void conditional_iterator_proxy<CategoryType, Ts...>::swap(conditional_iterator_proxy &rhs) void conditional_iterator_proxy<Category, Ts...>::swap(conditional_iterator_proxy &rhs)
{ {
std::swap(mCat, rhs.mCat); std::swap(mCat, rhs.mCat);
mCondition.swap(rhs.mCondition); mCondition.swap(rhs.mCondition);
......
...@@ -39,6 +39,50 @@ template < ...@@ -39,6 +39,50 @@ template <
typename Alloc = std::allocator<std::byte>> typename Alloc = std::allocator<std::byte>>
class category_t class category_t
{ {
private:
// --------------------------------------------------------------------
// Internal storage, strictly forward linked list with minimal space
// requirements. Strings of size 7 or shorter are stored internally.
// Typically, more than 99% of the strings in an mmCIF file are less
// than 8 bytes in length.
struct item_value
{
item_value(uint16_t column_ix, uint16_t length)
: m_next(nullptr)
, m_column_ix(column_ix)
, m_length(length)
{
}
item_value() = delete;
item_value(const item_value &) = delete;
item_value &operator=(const item_value &) = delete;
item_value *m_next;
uint16_t m_column_ix;
uint16_t m_length;
union
{
char m_local_data[8];
char *m_data;
};
static constexpr size_t kBufferSize = sizeof(m_local_data);
std::string_view text() const
{
return {m_length >= kBufferSize ? m_data : m_local_data, m_length};
}
const char *c_str() const
{
return m_length >= kBufferSize ? m_data : m_local_data;
}
};
static_assert(sizeof(item_value) == 24, "sizeof(item_value) should be 24 bytes");
public: public:
using allocator_type = Alloc; using allocator_type = Alloc;
...@@ -59,6 +103,42 @@ class category_t ...@@ -59,6 +103,42 @@ class category_t
using iterator = iterator_impl<category_t>; using iterator = iterator_impl<category_t>;
using const_iterator = iterator_impl<const category_t>; using const_iterator = iterator_impl<const category_t>;
class row
{
public:
row()
: m_next(nullptr)
, m_head(nullptr)
, m_tail(nullptr)
{
}
row(row *next, item_value *data)
: m_next(next)
, m_head(data)
, m_tail(data)
{
auto n = m_tail ? m_tail->m_next : nullptr;
while (n != nullptr)
{
m_tail = n;
n = n->m_next;
}
}
private:
template <typename>
friend class item_handle;
template <typename, typename...>
friend class iterator_impl;
friend class category_t;
row *m_next = nullptr;
item_value *m_head = nullptr, *m_tail = nullptr;
};
category_t() = default; category_t() = default;
category_t(std::string_view name, const allocator_type &alloc = allocator_type()) category_t(std::string_view name, const allocator_type &alloc = allocator_type())
...@@ -161,6 +241,24 @@ class category_t ...@@ -161,6 +241,24 @@ class category_t
return {*this, nullptr}; return {*this, nullptr};
} }
// --------------------------------------------------------------------
template <typename... Ts, typename... Ns>
iterator_proxy<const category_t, Ts...> rows(Ns... names) const
{
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
return iterator_proxy<const category_t, Ts...>(*this, begin(), {names...});
}
template <typename... Ts, typename... Ns>
iterator_proxy<category_t, Ts...> rows(Ns... names)
{
static_assert(sizeof...(Ts) == sizeof...(Ns), "The number of column titles should be equal to the number of types to return");
return iterator_proxy<category_t, Ts...>(*this, begin(), {names...});
}
// --------------------------------------------------------------------
iterator emplace(std::initializer_list<item> items) iterator emplace(std::initializer_list<item> items)
{ {
return this->emplace(items.begin(), items.end()); return this->emplace(items.begin(), items.end());
...@@ -243,7 +341,7 @@ class category_t ...@@ -243,7 +341,7 @@ class category_t
else else
m_tail = m_tail->m_next = r; m_tail = m_tail->m_next = r;
return { *this, r }; return {*this, r};
// result = r; // result = r;
...@@ -298,49 +396,6 @@ class category_t ...@@ -298,49 +396,6 @@ class category_t
} }
private: private:
// --------------------------------------------------------------------
// Internal storage, strictly forward linked list with minimal space
// requirements. Strings of size 7 or shorter are stored internally.
// Typically, more than 99% of the strings in an mmCIF file are less
// than 8 bytes in length.
struct item_value
{
item_value(uint16_t column_ix, uint16_t length)
: m_next(nullptr)
, m_column_ix(column_ix)
, m_length(length)
{
}
item_value() = delete;
item_value(const item_value &) = delete;
item_value &operator=(const item_value &) = delete;
item_value *m_next;
uint16_t m_column_ix;
uint16_t m_length;
union
{
char m_local_data[8];
char *m_data;
};
static constexpr size_t kBufferSize = sizeof(m_local_data);
std::string_view text() const
{
return {m_length >= kBufferSize ? m_data : m_local_data, m_length};
}
const char *c_str() const
{
return m_length >= kBufferSize ? m_data : m_local_data;
}
};
static_assert(sizeof(item_value) == 24, "sizeof(item_value) should be 24 bytes");
using char_allocator_type = typename std::allocator_traits<Alloc>::template rebind_alloc<char>; using char_allocator_type = typename std::allocator_traits<Alloc>::template rebind_alloc<char>;
using char_allocator_traits = std::allocator_traits<char_allocator_type>; using char_allocator_traits = std::allocator_traits<char_allocator_type>;
...@@ -397,44 +452,6 @@ class category_t ...@@ -397,44 +452,6 @@ class category_t
item_allocator_traits::deallocate(ia, iv, 1); item_allocator_traits::deallocate(ia, iv, 1);
} }
struct row
{
// row() = default;
// row(const row &) = default;
// row(row &&) = default;
// row &operator=(const row &) = default;
// row &operator=(row &&) = default;
template <typename R>
friend class item_handle;
row()
: m_next(nullptr)
, m_head(nullptr)
, m_tail(nullptr)
{
}
row(row *next, item_value *data)
: m_next(next)
, m_head(data)
, m_tail(data)
{
auto n = m_tail ? m_tail->m_next : nullptr;
while (n != nullptr)
{
m_tail = n;
n = n->m_next;
}
}
row *m_next = nullptr;
item_value *m_head = nullptr, *m_tail = nullptr;
};
using row_allocator_type = typename std::allocator_traits<allocator_type>::template rebind_alloc<row>; using row_allocator_type = typename std::allocator_traits<allocator_type>::template rebind_alloc<row>;
using row_allocator_traits = std::allocator_traits<row_allocator_type>; using row_allocator_traits = std::allocator_traits<row_allocator_type>;
......
...@@ -33,6 +33,12 @@ ...@@ -33,6 +33,12 @@
#include <optional> #include <optional>
#include <limits> #include <limits>
namespace cif
{
extern int VERBOSE;
}
namespace cif::v2 namespace cif::v2
{ {
...@@ -238,7 +244,7 @@ struct item_handle ...@@ -238,7 +244,7 @@ struct item_handle
template <typename Row> template <typename Row>
template <typename T> template <typename T>
struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_integral_v<T>>> struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<T>>>
{ {
using value_type = std::remove_reference_t<std::remove_cv_t<T>>; using value_type = std::remove_reference_t<std::remove_cv_t<T>>;
...@@ -247,25 +253,30 @@ struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_integral_v<T> ...@@ -247,25 +253,30 @@ struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_integral_v<T>
auto txt = ref.text(); auto txt = ref.text();
value_type result = {}; value_type result = {};
auto [ptr, ec] { std::from_chars(txt.data(), txt.data() + txt.size(), result) };
if (ec == std::errc::invalid_argument) std::from_chars_result r;
if constexpr (std::is_floating_point_v<T>)
r = cif::from_chars(txt.data(), txt.data() + txt.size(), result);
else
r = std::from_chars(txt.data(), txt.data() + txt.size(), result);
if (r.ec != std::errc())
{ {
// if (cif::VERBOSE)
// std::cerr << "Attempt to convert " << std::quoted(txt) << " into a number" << std::endl;
result = {}; result = {};
} if (cif::VERBOSE)
else if (ec == std::errc::result_out_of_range)
{ {
// if (cif::VERBOSE) if (r.ec == std::errc::invalid_argument)
// std::cerr << "Conversion of " << std::quoted(txt) << " into a type that is too small" << std::endl; std::cerr << "Attempt to convert " << std::quoted(txt) << " into a number" << std::endl;
result = {}; else if (r.ec == std::errc::result_out_of_range)
std::cerr << "Conversion of " << std::quoted(txt) << " into a type that is too small" << std::endl;
}
} }
return result; return result;
} }
static int compare(const item_handle &ref, double value, bool icase) static int compare(const item_handle &ref, const T& value, bool icase)
{ {
int result = 0; int result = 0;
...@@ -276,64 +287,25 @@ struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_integral_v<T> ...@@ -276,64 +287,25 @@ struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_integral_v<T>
else else
{ {
value_type v = {}; value_type v = {};
auto [ptr, ec] { std::from_chars(txt.data(), txt.data() + txt.size(), v) };
if (ec != std::errc())
result = 1;
else if (v < value)
result = -1;
else if (v > value)
result = 1;
}
return result;
}
};
template <typename Row>
template <typename T>
struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_floating_point_v<T>>>
{
using value_type = std::remove_reference_t<std::remove_cv_t<T>>;
static value_type convert(const item_handle &ref) std::from_chars_result r;
{
auto txt = ref.text();
value_type result = {}; if constexpr (std::is_floating_point_v<T>)
auto [ptr, ec] { cif::from_chars(txt.data(), txt.data() + txt.size(), result) }; r = cif::from_chars(txt.data(), txt.data() + txt.size(), v);
else
r = std::from_chars(txt.data(), txt.data() + txt.size(), v);
if (ec == std::errc::invalid_argument) if (r.ec != std::errc())
{ {
// if (cif::VERBOSE) if (cif::VERBOSE)
// std::cerr << "Attempt to convert " << std::quoted(txt) << " into a number" << std::endl;
result = {};
}
else if (ec == std::errc::result_out_of_range)
{ {
// if (cif::VERBOSE) if (r.ec == std::errc::invalid_argument)
// std::cerr << "Conversion of " << std::quoted(txt) << " into a type that is too small" << std::endl; std::cerr << "Attempt to convert " << std::quoted(txt) << " into a number" << std::endl;
result = {}; else if (r.ec == std::errc::result_out_of_range)
} std::cerr << "Conversion of " << std::quoted(txt) << " into a type that is too small" << std::endl;
return result;
} }
static int compare(const item_handle &ref, double value, bool icase)
{
int result = 0;
auto txt = ref.text();
if (txt.empty())
result = 1;
else
{
value_type v = {};
auto [ptr, ec] { cif::from_chars(txt.data(), txt.data() + txt.size(), v) };
if (ec != std::errc())
result = 1; result = 1;
}
else if (v < value) else if (v < value)
result = -1; result = -1;
else if (v > value) else if (v > value)
...@@ -344,90 +316,6 @@ struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_floating_poin ...@@ -344,90 +316,6 @@ struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_floating_poin
} }
}; };
// template <typename Row>
// template <typename T>
// struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_integral_v<T> and std::is_unsigned_v<T> and not std::is_same_v<T, bool>>>
// {
// static T convert(const item_handle &ref)
// {
// T result = {};
// if (not ref.empty())
// result = static_cast<T>(std::stoul(ref.c_str()));
// return result;
// }
// static int compare(const item_handle &ref, unsigned long value, bool icase)
// {
// int result = 0;
// auto txt = ref.text();
// if (txt.empty())
// result = 1;
// else
// {
// try
// {
// auto v = std::stol(txt);
// if (v < value)
// result = -1;
// else if (v > value)
// result = 1;
// }
// catch (...)
// {
// // if (VERBOSE)
// // std::cerr << "conversion error in compare for '" << ref.c_str() << '\'' << std::endl;
// result = 1;
// }
// }
// return result;
// }
// };
// template <typename Row>
// template <typename T>
// struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_integral_v<T> and std::is_signed_v<T> and not std::is_same_v<T, bool>>>
// {
// static T convert(const item_handle &ref)
// {
// T result = {};
// if (not ref.empty())
// result = static_cast<T>(std::stol(ref.text()));
// return result;
// }
// static int compare(const item_handle &ref, long value, bool icase)
// {
// int result = 0;
// auto txt = ref.text();
// if (txt.empty())
// result = 1;
// else
// {
// try
// {
// auto v = std::stol(txt);
// if (v < value)
// result = -1;
// else if (v > value)
// result = 1;
// }
// catch (...)
// {
// // if (VERBOSE)
// // std::cerr << "conversion error in compare for '" << ref.c_str() << '\'' << std::endl;
// result = 1;
// }
// }
// return result;
// }
// };
template <typename Row> template <typename Row>
template <typename T> template <typename T>
struct item_handle<Row>::item_value_as<std::optional<T>> struct item_handle<Row>::item_value_as<std::optional<T>>
......
...@@ -31,6 +31,85 @@ ...@@ -31,6 +31,85 @@
namespace cif::v2 namespace cif::v2
{ {
template<typename> class row_handle;
namespace detail
{
// some helper classes to help create tuple result types
template <
typename Category,
typename... C
>
struct get_row_result
{
using category_type = Category;
using row_type = category_type::row;
using row_handle_type = row_handle<category_type>;
using item_handle_type = item_handle<row_type>;
static constexpr size_t N = sizeof...(C);
get_row_result(const row_handle_type &r, std::array<size_t, N> &&columns)
: m_row(r)
, m_columns(std::move(columns))
{
}
const item_handle_type operator[](size_t ix) const
{
return m_row[m_columns[ix]];
}
template <typename... Ts, std::enable_if_t<N == sizeof...(Ts), int> = 0>
operator std::tuple<Ts...>() const
{
return get<Ts...>(std::index_sequence_for<Ts...>{});
}
template <typename... Ts, std::size_t... Is>
std::tuple<Ts...> get(std::index_sequence<Is...>) const
{
return std::tuple<Ts...>{m_row[m_columns[Is]].template as<Ts>()...};
}
const row_handle_type &m_row;
std::array<size_t, N> m_columns;
};
// we want to be able to tie some variables to a get_row_result, for this we use tiewraps
template <typename... Ts>
struct tie_wrap
{
tie_wrap(Ts... args)
: m_value(args...)
{
}
template <typename RR>
void operator=(const RR &&rr)
{
// get_row_result will do the conversion, but only if the types
// are compatible. That means the number of parameters to the get()
// of the row should be equal to the number of items in the tuple
// you are trying to tie.
using RType = std::tuple<typename std::remove_reference<Ts>::type...>;
m_value = static_cast<RType>(rr);
}
std::tuple<Ts...> m_value;
};
}
template <typename... Ts>
auto tie(Ts &...v)
{
return detail::tie_wrap<Ts &...>(std::forward<Ts &>(v)...);
}
// -------------------------------------------------------------------- // --------------------------------------------------------------------
/// \brief row_handle is the way to access data in rows /// \brief row_handle is the way to access data in rows
...@@ -40,7 +119,7 @@ class row_handle ...@@ -40,7 +119,7 @@ class row_handle
public: public:
using category_type = Category; using category_type = Category;
using row_type = category_type::row; using row_type = std::conditional_t<std::is_const_v<category_type>, const typename category_type::row, typename category_type::row>;
row_handle(category_type &cat, row_type &row) row_handle(category_type &cat, row_type &row)
: m_cat(cat) : m_cat(cat)
...@@ -66,7 +145,22 @@ class row_handle ...@@ -66,7 +145,22 @@ class row_handle
return item_handle<const row_type>(get_column_ix(column_name), m_row); return item_handle<const row_type>(get_column_ix(column_name), m_row);
} }
template <typename... Ts, size_t N>
std::tuple<Ts...> get(char const *const (&columns)[N]) const
{
static_assert(sizeof...(Ts) == N, "Number of columns should be equal to number of types to return");
std::array<size_t, N> cix;
for (size_t i = 0; i < N; ++i)
cix[i] = get_column_ix(columns[i]);
return detail::get_row_result<category_type, Ts...>(*this, std::move(cix));
}
template <typename... C>
auto get(C... columns) const
{
return detail::get_row_result<category_type, C...>(*this, {get_column_ix(columns)...});
}
private: private:
...@@ -75,8 +169,6 @@ class row_handle ...@@ -75,8 +169,6 @@ class row_handle
return m_cat.get_column_ix(name); return m_cat.get_column_ix(name);
} }
category_type &m_cat; category_type &m_cat;
row_type &m_row; row_type &m_row;
}; };
......
...@@ -91,6 +91,11 @@ BOOST_AUTO_TEST_CASE(cc_1) ...@@ -91,6 +91,11 @@ BOOST_AUTO_TEST_CASE(cc_1)
{ "-.2e11 ", -.2e11, ' ' }, { "-.2e11 ", -.2e11, ' ' },
{ "1.3e-10 ", 1.3e-10, ' ' }, { "1.3e-10 ", 1.3e-10, ' ' },
{ "3.0", 3.0, 0 },
{ "3.0 ", 3.0, ' ' },
{ "3.000000", 3.0, 0 },
{ "3.000000 ", 3.0, ' ' },
}; };
for (const auto &[txt, val, ch] : tests) for (const auto &[txt, val, ch] : tests)
...@@ -123,7 +128,6 @@ BOOST_AUTO_TEST_CASE(r_1) ...@@ -123,7 +128,6 @@ BOOST_AUTO_TEST_CASE(r_1)
BOOST_CHECK_EQUAL(row["f-3"].compare(3.0), 0); BOOST_CHECK_EQUAL(row["f-3"].compare(3.0), 0);
} }
BOOST_AUTO_TEST_CASE(r_2) BOOST_AUTO_TEST_CASE(r_2)
{ {
cif::v2::category c("foo"); cif::v2::category c("foo");
...@@ -156,6 +160,29 @@ BOOST_AUTO_TEST_CASE(c_1) ...@@ -156,6 +160,29 @@ BOOST_AUTO_TEST_CASE(c_1)
BOOST_CHECK_EQUAL(r["s"].compare(ts[n - 1]), 0); BOOST_CHECK_EQUAL(r["s"].compare(ts[n - 1]), 0);
++n; ++n;
} }
n = 1;
for (auto r : c)
{
int i;
std::string s;
cif::v2::tie(i, s) = r.get("id", "s");
BOOST_CHECK_EQUAL(i, n);
BOOST_CHECK_EQUAL(s.compare(ts[n - 1]), 0);
++n;
}
n = 1;
for (const auto &[i, s] : c.rows<int,std::string>("id", "s"))
{
BOOST_CHECK_EQUAL(i, n);
BOOST_CHECK_EQUAL(s.compare(ts[n - 1]), 0);
++n;
}
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment