Commit 39b91e74 by Maarten L. Hekkelman

- new item storage

- formatting of numbers using to_chars
parent 6175b7e3
...@@ -209,7 +209,7 @@ inline auto coloured(std::basic_string<CharT, Traits, Alloc> &s, StringColour fo ...@@ -209,7 +209,7 @@ inline auto coloured(std::basic_string<CharT, Traits, Alloc> &s, StringColour fo
// -------------------------------------------------------------------- // --------------------------------------------------------------------
/// std::from_chars for floating point types. /// std::from_chars for floating point types.
template <typename FloatType> template <typename FloatType, std::enable_if_t<std::is_floating_point_v<FloatType>, int> = 0>
std::from_chars_result from_chars(const char *first, const char *last, FloatType &value) std::from_chars_result from_chars(const char *first, const char *last, FloatType &value)
{ {
std::from_chars_result result{first, {}}; std::from_chars_result result{first, {}};
...@@ -329,6 +329,92 @@ std::from_chars_result from_chars(const char *first, const char *last, FloatType ...@@ -329,6 +329,92 @@ std::from_chars_result from_chars(const char *first, const char *last, FloatType
return result; return result;
} }
enum class chars_format
{
scientific = 1,
fixed = 2,
// hex,
general = fixed | scientific
};
template <typename FloatType, std::enable_if_t<std::is_floating_point_v<FloatType>, int> = 0>
std::to_chars_result to_chars(char *first, char *last, FloatType &value, chars_format fmt)
{
int size = last - first;
int r;
switch (fmt)
{
case chars_format::scientific:
if constexpr (std::is_same_v<FloatType, long double>)
r = snprintf(first, last - first, "%le", value);
else
r = snprintf(first, last - first, "%e", value);
break;
case chars_format::fixed:
if constexpr (std::is_same_v<FloatType, long double>)
r = snprintf(first, last - first, "%lf", value);
else
r = snprintf(first, last - first, "%f", value);
break;
case chars_format::general:
if constexpr (std::is_same_v<FloatType, long double>)
r = snprintf(first, last - first, "%lg", value);
else
r = snprintf(first, last - first, "%g", value);
break;
}
std::to_chars_result result;
if (r < 0 or r >= size)
result = { first, std::errc::value_too_large };
else
result = { first + r, std::errc() };
return result;
}
template <typename FloatType, std::enable_if_t<std::is_floating_point_v<FloatType>, int> = 0>
std::to_chars_result to_chars(char *first, char *last, FloatType &value, chars_format fmt, int precision)
{
int size = last - first;
int r;
switch (fmt)
{
case chars_format::scientific:
if constexpr (std::is_same_v<FloatType, long double>)
r = snprintf(first, last - first, "%.*le", precision, value);
else
r = snprintf(first, last - first, "%.*e", precision, value);
break;
case chars_format::fixed:
if constexpr (std::is_same_v<FloatType, long double>)
r = snprintf(first, last - first, "%.*lf", precision, value);
else
r = snprintf(first, last - first, "%.*f", precision, value);
break;
case chars_format::general:
if constexpr (std::is_same_v<FloatType, long double>)
r = snprintf(first, last - first, "%.*lg", precision, value);
else
r = snprintf(first, last - first, "%.*g", precision, value);
break;
}
std::to_chars_result result;
if (r < 0 or r >= size)
result = { first, std::errc::value_too_large };
else
result = { first + r, std::errc() };
return result;
}
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// A progress bar // A progress bar
......
...@@ -147,9 +147,19 @@ class category_t ...@@ -147,9 +147,19 @@ class category_t
{ {
} }
category_t(const category_t &) = default; category_t(const category_t &rhs)
: m_allocator(std::allocator_traits<allocator_type>::select_on_container_copy_construction(rhs.get_allocator()))
, m_name(rhs.m_name)
, m_columns(rhs.m_columns)
{
// for (value_type r : rhs)
// this->emplace(r);
}
category_t(category_t &&)
{
category_t(category_t &&) = default; }
template <typename Alloc2> template <typename Alloc2>
category_t(const category_t &c, const Alloc2 &a) category_t(const category_t &c, const Alloc2 &a)
...@@ -165,8 +175,15 @@ class category_t ...@@ -165,8 +175,15 @@ class category_t
{ {
} }
category_t &operator=(const category_t &) = default; category_t &operator=(const category_t &)
category_t &operator=(category_t &&) = default; {
}
category_t &operator=(category_t &&)
{
}
~category_t() ~category_t()
{ {
...@@ -241,6 +258,16 @@ class category_t ...@@ -241,6 +258,16 @@ class category_t
return {*this, nullptr}; return {*this, nullptr};
} }
size_t size() const
{
return std::distance(cbegin(), cend());
}
bool empty() const
{
return m_head == nullptr;
}
// -------------------------------------------------------------------- // --------------------------------------------------------------------
template <typename... Ts, typename... Ns> template <typename... Ts, typename... Ns>
...@@ -264,6 +291,11 @@ class category_t ...@@ -264,6 +291,11 @@ class category_t
return this->emplace(items.begin(), items.end()); return this->emplace(items.begin(), items.end());
} }
iterator emplace(value_type row)
{
// return
}
template <typename ItemIter> template <typename ItemIter>
iterator emplace(ItemIter b, ItemIter e) iterator emplace(ItemIter b, ItemIter e)
{ {
......
...@@ -26,25 +26,26 @@ ...@@ -26,25 +26,26 @@
#pragma once #pragma once
#include <cstring>
#include <charconv> #include <charconv>
#include <cstring>
#include <iomanip> #include <iomanip>
#include <limits>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <limits>
#include <cif++/CifUtils.hpp>
namespace cif namespace cif
{ {
extern int VERBOSE; extern int VERBOSE;
} }
namespace cif::v2 namespace cif::v2
{ {
// -------------------------------------------------------------------- // --------------------------------------------------------------------
/// \brief item is a transient class that is used to pass data into rows /// \brief item is a transient class that is used to pass data into rows
/// but it also takes care of formatting data
class item class item
{ {
public: public:
...@@ -52,28 +53,51 @@ class item ...@@ -52,28 +53,51 @@ class item
item(std::string_view name, char value) item(std::string_view name, char value)
: m_name(name) : m_name(name)
, m_value({ value }) , m_value(m_buffer, 1)
{ {
m_buffer[0] = value;
m_buffer[1] = 0;
} }
template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0> template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
item(std::string_view name, const T &value, int precision) item(std::string_view name, const T &value, int precision)
: m_name(name) : m_name(name)
#if defined(__cpp_lib_format)
, m_value(std::format(".{}f", value, precision))
#endif
{ {
#if not defined(__cpp_lib_format) auto r = cif::to_chars(m_buffer, m_buffer + sizeof(m_buffer) - 1, value, cif::chars_format::fixed, precision);
// TODO: implement if (r.ec != std::errc())
m_value = std::to_string(value); throw std::runtime_error("Could not format number");
#endif
assert(r.ptr >= m_buffer and r.ptr < m_buffer + sizeof(m_buffer));
*r.ptr = 0;
m_value = std::string_view(m_buffer, r.ptr - m_buffer);
} }
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0> template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
item(const std::string_view name, const T &value) item(const std::string_view name, const T &value)
: m_name(name) : m_name(name)
, m_value(std::to_string(value)) , m_value(std::to_string(value))
{ {
auto r = cif::to_chars(m_buffer, m_buffer + sizeof(m_buffer) - 1, value, cif::chars_format::general);
if (r.ec != std::errc())
throw std::runtime_error("Could not format number");
assert(r.ptr >= m_buffer and r.ptr < m_buffer + sizeof(m_buffer));
*r.ptr = 0;
m_value = std::string_view(m_buffer, r.ptr - m_buffer);
}
template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
item(const std::string_view name, const T &value)
: m_name(name)
, m_value(std::to_string(value))
{
auto r = std::to_chars(m_buffer, m_buffer + sizeof(m_buffer) - 1, value);
if (r.ec != std::errc())
throw std::runtime_error("Could not format number");
assert(r.ptr >= m_buffer and r.ptr < m_buffer + sizeof(m_buffer));
*r.ptr = 0;
m_value = std::string_view(m_buffer, r.ptr - m_buffer);
} }
item(const std::string_view name, const std::string_view value) item(const std::string_view name, const std::string_view value)
...@@ -90,8 +114,8 @@ class item ...@@ -90,8 +114,8 @@ class item
item &operator=(item &&rhs) noexcept = default; item &operator=(item &&rhs) noexcept = default;
const std::string &name() const { return m_name; } std::string_view name() const { return m_name; }
const std::string &value() const { return m_value; } std::string_view value() const { return m_value; }
void value(const std::string &v) { m_value = v; } void value(const std::string &v) { m_value = v; }
...@@ -105,17 +129,18 @@ class item ...@@ -105,17 +129,18 @@ class item
bool is_unknown() const { return m_value == "?"; } bool is_unknown() const { return m_value == "?"; }
size_t length() const { return m_value.length(); } size_t length() const { return m_value.length(); }
const char *c_str() const { return m_value.c_str(); } // const char *c_str() const { return m_value.c_str(); }
private: private:
std::string m_name; std::string_view m_name;
std::string m_value; std::string_view m_value;
char m_buffer[64]; // TODO: optimize this magic number, might be too large
}; };
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// Transient object to access stored data // Transient object to access stored data
template<typename Row> template <typename Row>
struct item_handle struct item_handle
{ {
using row_type = Row; using row_type = Row;
...@@ -232,7 +257,6 @@ struct item_handle ...@@ -232,7 +257,6 @@ struct item_handle
} }
private: private:
uint16_t m_column; uint16_t m_column;
row_type &m_row; row_type &m_row;
// bool mConst = false; // bool mConst = false;
...@@ -276,7 +300,7 @@ struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_arithmetic_v< ...@@ -276,7 +300,7 @@ struct item_handle<Row>::item_value_as<T, std::enable_if_t<std::is_arithmetic_v<
return result; return result;
} }
static int compare(const item_handle &ref, const T& value, bool icase) static int compare(const item_handle &ref, const T &value, bool icase)
{ {
int result = 0; int result = 0;
......
...@@ -121,28 +121,42 @@ class row_handle ...@@ -121,28 +121,42 @@ class row_handle
using category_type = Category; using category_type = Category;
using row_type = std::conditional_t<std::is_const_v<category_type>, const typename category_type::row, typename 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() = default;
row_handle(const row_handle &) = default;
row_handle(row_handle &&) = default;
row_handle &operator=(const row_handle &) = default;
row_handle &operator=(row_handle &&) = default;
row_handle(category_type &cat, row_type &row) row_handle(category_type &cat, row_type &row)
: m_cat(cat) : m_cat(&cat)
, m_row(row) {} , m_row(&row) {}
explicit operator bool() const
{
return m_cat != nullptr and m_row != nullptr;
}
item_handle<row_type> operator[](uint32_t column_ix) item_handle<row_type> operator[](uint32_t column_ix)
{ {
return item_handle<row_type>(column_ix, m_row); return item_handle<row_type>(column_ix, *m_row);
} }
const item_handle<const row_type> operator[](uint32_t column_ix) const const item_handle<const row_type> operator[](uint32_t column_ix) const
{ {
return item_handle<const row_type>(column_ix, m_row); return item_handle<const row_type>(column_ix, *m_row);
} }
item_handle<row_type> operator[](std::string_view column_name) item_handle<row_type> operator[](std::string_view column_name)
{ {
return item_handle<row_type>(get_column_ix(column_name), m_row); return item_handle<row_type>(get_column_ix(column_name), *m_row);
} }
const item_handle<const row_type> operator[](std::string_view column_name) const const item_handle<const row_type> operator[](std::string_view column_name) const
{ {
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> template <typename... Ts, size_t N>
...@@ -166,11 +180,11 @@ class row_handle ...@@ -166,11 +180,11 @@ class row_handle
uint32_t get_column_ix(std::string_view name) const uint32_t get_column_ix(std::string_view name) const
{ {
return m_cat.get_column_ix(name); return m_cat->get_column_ix(name);
} }
category_type &m_cat; category_type *m_cat = nullptr;
row_type &m_row; row_type *m_row = nullptr;
}; };
......
...@@ -78,24 +78,24 @@ bool init_unit_test() ...@@ -78,24 +78,24 @@ bool init_unit_test()
BOOST_AUTO_TEST_CASE(cc_1) BOOST_AUTO_TEST_CASE(cc_1)
{ {
std::tuple<std::string_view,float,char> tests[] = { std::tuple<std::string_view, float, char> tests[] = {
{ "1.0", 1.0, 0 }, {"1.0", 1.0, 0},
{ "1.0e10", 1.0e10, 0 }, {"1.0e10", 1.0e10, 0},
{ "-1.1e10", -1.1e10, 0 }, {"-1.1e10", -1.1e10, 0},
{ "-.2e11", -.2e11, 0 }, {"-.2e11", -.2e11, 0},
{ "1.3e-10", 1.3e-10, 0 }, {"1.3e-10", 1.3e-10, 0},
{ "1.0 ", 1.0, ' ' }, {"1.0 ", 1.0, ' '},
{ "1.0e10 ", 1.0e10, ' ' }, {"1.0e10 ", 1.0e10, ' '},
{ "-1.1e10 ", -1.1e10, ' ' }, {"-1.1e10 ", -1.1e10, ' '},
{ "-.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, 0},
{ "3.0 ", 3.0, ' ' }, {"3.0 ", 3.0, ' '},
{ "3.000000", 3.0, 0 }, {"3.000000", 3.0, 0},
{ "3.000000 ", 3.0, ' ' }, {"3.000000 ", 3.0, ' '},
}; };
for (const auto &[txt, val, ch] : tests) for (const auto &[txt, val, ch] : tests)
...@@ -108,18 +108,36 @@ BOOST_AUTO_TEST_CASE(cc_1) ...@@ -108,18 +108,36 @@ BOOST_AUTO_TEST_CASE(cc_1)
if (ch != 0) if (ch != 0)
BOOST_CHECK_EQUAL(*ptr, ch); BOOST_CHECK_EQUAL(*ptr, ch);
} }
}
BOOST_AUTO_TEST_CASE(cc_2)
{
std::tuple<float, int, std::string_view> tests[] = {
{ 1.1, 1, "1.1" }
};
for (const auto &[val, prec, test] : tests)
{
char buffer[64];
const auto &[ptr, ec] = cif::to_chars(buffer, buffer + sizeof(buffer), val, cif::chars_format::fixed, prec);
BOOST_CHECK(ec == std::errc());
BOOST_CHECK_EQUAL(buffer, test);
}
} }
// -------------------------------------------------------------------- // --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(r_1) BOOST_AUTO_TEST_CASE(r_1)
{ {
cif::v2::category c("foo"); cif::v2::category c("foo");
c.emplace({ c.emplace({
{ "f-1", 1 }, {"f-1", 1},
{ "f-2", "two" }, {"f-2", "two"},
{ "f-3", 3.0 }, {"f-3", 3.0, 3},
}); });
auto row = c.front(); auto row = c.front();
...@@ -134,25 +152,22 @@ BOOST_AUTO_TEST_CASE(r_2) ...@@ -134,25 +152,22 @@ BOOST_AUTO_TEST_CASE(r_2)
for (size_t i = 1; i < 256; ++i) for (size_t i = 1; i < 256; ++i)
{ {
c.emplace({ c.emplace({{"id", i},
{ "id", i }, {"txt", std::string(i, 'x')}});
{ "txt", std::string(i, 'x') }
});
} }
} }
BOOST_AUTO_TEST_CASE(c_1) BOOST_AUTO_TEST_CASE(c_1)
{ {
cif::v2::category c("foo"); cif::v2::category c("foo");
c.emplace({ { "id", 1 }, { "s", "aap" } }); c.emplace({{"id", 1}, {"s", "aap"}});
c.emplace({ { "id", 2 }, { "s", "noot" } }); c.emplace({{"id", 2}, {"s", "noot"}});
c.emplace({ { "id", 3 }, { "s", "mies" } }); c.emplace({{"id", 3}, {"s", "mies"}});
int n = 1; int n = 1;
const char *ts[] = { "aap", "noot", "mies" }; const char *ts[] = {"aap", "noot", "mies"};
for (auto r : c) for (auto r : c)
{ {
...@@ -177,7 +192,7 @@ BOOST_AUTO_TEST_CASE(c_1) ...@@ -177,7 +192,7 @@ BOOST_AUTO_TEST_CASE(c_1)
n = 1; n = 1;
for (const auto &[i, s] : c.rows<int,std::string>("id", "s")) for (const auto &[i, s] : c.rows<int, std::string>("id", "s"))
{ {
BOOST_CHECK_EQUAL(i, n); BOOST_CHECK_EQUAL(i, n);
BOOST_CHECK_EQUAL(s.compare(ts[n - 1]), 0); BOOST_CHECK_EQUAL(s.compare(ts[n - 1]), 0);
...@@ -185,16 +200,29 @@ BOOST_AUTO_TEST_CASE(c_1) ...@@ -185,16 +200,29 @@ BOOST_AUTO_TEST_CASE(c_1)
} }
} }
BOOST_AUTO_TEST_CASE(c_2) BOOST_AUTO_TEST_CASE(c_2)
{ {
std::tuple<int,const char*> D[] = {
{1, "aap"},
{2, "noot"},
{3, "mies"}
};
cif::v2::category c("foo"); cif::v2::category c("foo");
c.emplace({ { "id", 1 }, { "s", "aap" } }); for (const auto &[id, s] : D)
c.emplace({ { "id", 2 }, { "s", "noot" } }); c.emplace({ {"id", id}, { "s", s} });
c.emplace({ { "id", 3 }, { "s", "mies" } });
BOOST_CHECK(not c.empty());
BOOST_CHECK_EQUAL(c.size(), 3);
cif::v2::category c2(c);
for (auto r : c)
c2.emplace(r);
BOOST_CHECK(not c2.empty());
BOOST_CHECK_EQUAL(c2.size(), 3);
} }
...@@ -306,7 +334,6 @@ BOOST_AUTO_TEST_CASE(c_2) ...@@ -306,7 +334,6 @@ BOOST_AUTO_TEST_CASE(c_2)
// auto &test = db["test"]; // auto &test = db["test"];
// BOOST_CHECK(test.size() == 5); // BOOST_CHECK(test.size() == 5);
// BOOST_CHECK(test.exists("value"_key == cif::null)); // BOOST_CHECK(test.exists("value"_key == cif::null));
// BOOST_CHECK(test.find("value"_key == cif::null).size() == 2); // BOOST_CHECK(test.find("value"_key == cif::null).size() == 2);
// } // }
...@@ -2045,4 +2072,3 @@ BOOST_AUTO_TEST_CASE(c_2) ...@@ -2045,4 +2072,3 @@ BOOST_AUTO_TEST_CASE(c_2)
// BOOST_CHECK_EQUAL(text, kS[i++].s); // BOOST_CHECK_EQUAL(text, kS[i++].s);
// } // }
// } // }
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