Commit 2b92cee3 by Maarten L. Hekkelman

some documentation and cleanup of cif::item

parent 80717685
......@@ -34,9 +34,14 @@
#include <memory>
#include <optional>
#include <cif++/forward_decl.hpp>
#include <cif++/text.hpp>
#include <cif++/forward_decl.hpp>
/// \file item.hpp
/// This file contains the declaration of \class item but
/// also the \class item_value and \class item_handle
/// These handle the storage of and access to the data
/// for a single data field.
namespace cif
{
......@@ -45,12 +50,15 @@ extern int VERBOSE;
// --------------------------------------------------------------------
/// \brief item is a transient class that is used to pass data into rows
/// but it also takes care of formatting data
/// but it also takes care of formatting data.
class item
{
public:
/// \brief Default constructor, empty item
item() = default;
/// \brief constructor for an item with name \a name and as
/// content a single character string with content \a value
item(std::string_view name, char value)
: m_name(name)
, m_value(m_buffer, 1)
......@@ -59,6 +67,9 @@ class item
m_buffer[1] = 0;
}
/// \brief constructor for an item with name \a name and as
/// content a the formatted floating point value \a value with
/// precision \a precision
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)
: m_name(name)
......@@ -72,6 +83,9 @@ class item
m_value = std::string_view(m_buffer, r.ptr - m_buffer);
}
/// \brief constructor for an item with name \a name and as
/// content a formatted floating point value \a value with
/// so-called general formatting
template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
item(const std::string_view name, const T &value)
: m_name(name)
......@@ -85,6 +99,8 @@ class item
m_value = std::string_view(m_buffer, r.ptr - m_buffer);
}
/// \brief constructor for an item with name \a name and as
/// content a the formatted integral value \a value
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)
......@@ -98,6 +114,8 @@ class item
m_value = std::string_view(m_buffer, r.ptr - m_buffer);
}
/// \brief constructor for an item with name \a name and as
/// content value \a value
item(const std::string_view name, const std::string_view value)
: m_name(name)
, m_value(value)
......@@ -115,7 +133,8 @@ class item
std::string_view name() const { return m_name; }
std::string_view value() const { return m_value; }
void value(const std::string &v) { m_value = v; }
/// \brief replace the content of the stored value with \a v
void value(std::string_view v) { m_value = v; }
/// \brief empty means either null or unknown
bool empty() const { return m_value.empty(); }
......@@ -126,8 +145,8 @@ class item
/// \brief returns true if the field contains '?'
bool is_unknown() const { return m_value == "?"; }
/// \brief the length of the value string
size_t length() const { return m_value.length(); }
// const char *c_str() const { return m_value.c_str(); }
private:
std::string_view m_name;
......@@ -145,6 +164,7 @@ class item
struct item_value
{
/// \brief constructor
item_value(uint16_t column_ix, uint16_t length)
: m_next(nullptr)
, m_column_ix(column_ix)
......@@ -167,14 +187,11 @@ struct item_value
static constexpr size_t kBufferSize = sizeof(m_local_data);
// By using std::string_view instead of c_str we obain a
// nice performance gain since we avoid many calls to strlen.
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;
return { m_length >= kBufferSize ? m_data : m_local_data, m_length };
}
};
......@@ -183,6 +200,9 @@ static_assert(sizeof(item_value) == 24, "sizeof(item_value) should be 24 bytes")
// --------------------------------------------------------------------
// Transient object to access stored data
/// \brief This is \class item_handle, it is used to access
/// the data stored in \class item_value.
struct item_handle
{
public:
......@@ -193,7 +213,7 @@ struct item_handle
template <typename T>
item_handle &operator=(const T &value)
{
item v{"", value};
item v{ "", value };
assign_value(v);
return *this;
}
......@@ -266,17 +286,6 @@ struct item_handle
return txt.length() == 1 and txt.front() == '?';
}
// const char *c_str() const
// {
// for (auto iv = m_row_handle.m_head; iv != nullptr; iv = iv->m_next)
// {
// if (iv->m_column_ix == m_column)
// return iv->m_text;
// }
// return s_empty_result;
// }
std::string_view text() const;
// bool operator!=(const std::string &s) const { return s != c_str(); }
......@@ -293,8 +302,6 @@ struct item_handle
row_handle &m_row_handle;
void assign_value(const item &value);
static constexpr const char *s_empty_result = "";
};
// So sad that the gcc implementation of from_chars does not support floats yet...
......@@ -465,7 +472,7 @@ struct item_handle::item_value_as<T, std::enable_if_t<std::is_same_v<T, std::str
{
if (ref.empty())
return {};
return {ref.text().data(), ref.text().size()};
return { ref.text().data(), ref.text().size() };
}
static int compare(const item_handle &ref, const std::string &value, bool icase)
......
......@@ -1291,22 +1291,22 @@ void category::update_value(row *row, size_t column, std::string_view value, boo
auto &col = m_columns[column];
const char *oldValue = nullptr;
std::string_view oldValue;
for (auto iv = row->m_head; iv != nullptr; iv = iv->m_next)
{
assert(iv != iv->m_next and (iv->m_next == nullptr or iv != iv->m_next->m_next));
if (iv->m_column_ix == column)
{
oldValue = iv->c_str();
oldValue = iv->text();
break;
}
}
if (oldValue != nullptr and value == oldValue) // no need to update
if (value == oldValue) // no need to update
return;
std::string oldStrValue = oldValue ? oldValue : "";
std::string oldStrValue{ oldValue };
// check the value
if (col.m_validator and validate)
......
......@@ -31,8 +31,8 @@
#include <cif++.hpp>
#include <cif++/parser.hpp>
#include <cif++/dictionary_parser.hpp>
#include <cif++/parser.hpp>
namespace tt = boost::test_tools;
......@@ -78,23 +78,23 @@ bool init_unit_test()
BOOST_AUTO_TEST_CASE(cc_1)
{
std::tuple<std::string_view, float, char> tests[] = {
{"1.0", 1.0, 0},
{"1.0e10", 1.0e10, 0},
{"-1.1e10", -1.1e10, 0},
{"-.2e11", -.2e11, 0},
{"1.3e-10", 1.3e-10, 0},
{"1.0 ", 1.0, ' '},
{"1.0e10 ", 1.0e10, ' '},
{"-1.1e10 ", -1.1e10, ' '},
{"-.2e11 ", -.2e11, ' '},
{"1.3e-10 ", 1.3e-10, ' '},
{"3.0", 3.0, 0},
{"3.0 ", 3.0, ' '},
{"3.000000", 3.0, 0},
{"3.000000 ", 3.0, ' '},
{ "1.0", 1.0, 0 },
{ "1.0e10", 1.0e10, 0 },
{ "-1.1e10", -1.1e10, 0 },
{ "-.2e11", -.2e11, 0 },
{ "1.3e-10", 1.3e-10, 0 },
{ "1.0 ", 1.0, ' ' },
{ "1.0e10 ", 1.0e10, ' ' },
{ "-1.1e10 ", -1.1e10, ' ' },
{ "-.2e11 ", -.2e11, ' ' },
{ "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)
......@@ -157,9 +157,9 @@ BOOST_AUTO_TEST_CASE(r_1)
{
cif::category c("foo");
c.emplace({
{"f-1", 1},
{"f-2", "two"},
{"f-3", 3.0, 3},
{ "f-1", 1 },
{ "f-2", "two" },
{ "f-3", 3.0, 3 },
});
auto row = c.front();
......@@ -167,7 +167,7 @@ BOOST_AUTO_TEST_CASE(r_1)
BOOST_CHECK_EQUAL(row["f-2"].compare("two"), 0);
BOOST_CHECK_EQUAL(row["f-3"].compare(3.0), 0); // This fails when running in valgrind... sigh
const auto &[f1, f2, f3] = row.get<int,std::string,float>("f-1", "f-2", "f-3");
const auto &[f1, f2, f3] = row.get<int, std::string, float>("f-1", "f-2", "f-3");
BOOST_CHECK_EQUAL(f1, 1);
BOOST_CHECK_EQUAL(f2, "two");
......@@ -194,8 +194,8 @@ BOOST_AUTO_TEST_CASE(r_2)
for (size_t i = 1; i < 256; ++i)
{
c.emplace({{"id", i},
{"txt", std::string(i, 'x')}});
c.emplace({ { "id", i },
{ "txt", std::string(i, 'x') } });
}
}
......@@ -203,13 +203,13 @@ BOOST_AUTO_TEST_CASE(c_1)
{
cif::category c("foo");
c.emplace({{"id", 1}, {"s", "aap"}});
c.emplace({{"id", 2}, {"s", "noot"}});
c.emplace({{"id", 3}, {"s", "mies"}});
c.emplace({ { "id", 1 }, { "s", "aap" } });
c.emplace({ { "id", 2 }, { "s", "noot" } });
c.emplace({ { "id", 3 }, { "s", "mies" } });
int n = 1;
const char *ts[] = {"aap", "noot", "mies"};
const char *ts[] = { "aap", "noot", "mies" };
for (auto r : c)
{
......@@ -244,16 +244,16 @@ BOOST_AUTO_TEST_CASE(c_1)
BOOST_AUTO_TEST_CASE(c_2)
{
std::tuple<int,const char*> D[] = {
{1, "aap"},
{2, "noot"},
{3, "mies"}
std::tuple<int, const char *> D[] = {
{ 1, "aap" },
{ 2, "noot" },
{ 3, "mies" }
};
cif::category c("foo");
for (const auto &[id, s] : D)
c.emplace({ {"id", id}, { "s", s} });
c.emplace({ { "id", id }, { "s", s } });
BOOST_CHECK(not c.empty());
BOOST_CHECK_EQUAL(c.size(), 3);
......@@ -284,22 +284,22 @@ BOOST_AUTO_TEST_CASE(c_2)
BOOST_AUTO_TEST_CASE(c_3)
{
std::tuple<int,const char*> D[] = {
{1, "aap"},
{2, "noot"},
{3, "mies"}
std::tuple<int, const char *> D[] = {
{ 1, "aap" },
{ 2, "noot" },
{ 3, "mies" }
};
cif::category c("foo");
for (const auto &[id, s] : D)
c.emplace({ {"id", id}, { "s", s} });
c.emplace({ { "id", id }, { "s", s } });
cif::category c2("bar");
for (auto r : c)
c2.emplace(r);
// BOOST_CHECK(c == c2);
}
......@@ -307,9 +307,9 @@ BOOST_AUTO_TEST_CASE(ci_1)
{
cif::category c("foo");
c.emplace({{"id", 1}, {"s", "aap"}});
c.emplace({{"id", 2}, {"s", "noot"}});
c.emplace({{"id", 3}, {"s", "mies"}});
c.emplace({ { "id", 1 }, { "s", "aap" } });
c.emplace({ { "id", 2 }, { "s", "noot" } });
c.emplace({ { "id", 3 }, { "s", "mies" } });
cif::category::iterator i1 = c.begin();
cif::category::const_iterator i2 = c.cbegin();
......@@ -324,6 +324,37 @@ BOOST_AUTO_TEST_CASE(ci_1)
BOOST_CHECK(i1 == i5);
}
BOOST_AUTO_TEST_CASE(os_1)
{
using namespace cif::literals;
using namespace std::literals;
std::tuple<int, const char *> D[] = {
{ 1, "aap" },
{ 2, "noot" },
{ 3, "mies" }
};
cif::category c("foo");
for (const auto &[id, s] : D)
c.emplace({ { "id", id }, { "s", s } });
for (auto rh : c)
{
rh["o"].os(1, ',', 2, ": ", rh.get<std::string>("s"));
}
for (const auto &[id, s] : D)
{
auto rh = c.find1("id"_key == id);
BOOST_CHECK_EQUAL(rh.get<int>("id"), id);
BOOST_CHECK_EQUAL(rh.get<std::string>("s"), s);
BOOST_CHECK_EQUAL(rh.get<std::string>("o"), "1,2: "s + s);
}
}
// --------------------------------------------------------------------
BOOST_AUTO_TEST_CASE(get_1)
......@@ -383,7 +414,7 @@ _test.name
auto &test = db["test"];
BOOST_CHECK_EQUAL(test.size(), 3);
const char *ts[] = {"aap", "noot", "mies"};
const char *ts[] = { "aap", "noot", "mies" };
int n = 1;
for (const auto &[i, s] : test.rows<int, std::string>("id", "name"))
......@@ -405,6 +436,20 @@ _test.name
test.clear();
BOOST_CHECK(test.empty());
// fill again.
test.emplace({ { "id", "1" }, { "name", "aap" } });
test.emplace({ { "id", "2" }, { "name", "noot" } });
test.emplace({ { "id", "3" }, { "name", "mies" } });
n = 1;
for (const auto &[i, s] : test.rows<int, std::string>("id", "name"))
{
BOOST_CHECK_EQUAL(i, n);
BOOST_CHECK_EQUAL(s.compare(ts[n - 1]), 0);
++n;
}
}
// --------------------------------------------------------------------
......@@ -637,10 +682,9 @@ _cat_2.desc
// { "desc", "moet fout gaan" }
// }), std::exception);
BOOST_CHECK_THROW(cat2.emplace({
{"id", "vijf"}, // <- invalid value
{"parent_id", 2},
{"desc", "moet fout gaan"}}),
BOOST_CHECK_THROW(cat2.emplace({ { "id", "vijf" }, // <- invalid value
{ "parent_id", 2 },
{ "desc", "moet fout gaan" } }),
std::exception);
}
......@@ -755,19 +799,16 @@ mies Mies
BOOST_CHECK_EQUAL(cat1.size(), 2);
// should fail with duplicate key:
BOOST_CHECK_THROW(cat1.emplace({
{"id", "aap"},
{"c", "2e-aap"}
}), std::exception);
BOOST_CHECK_THROW(cat1.emplace({ { "id", "aap" },
{ "c", "2e-aap" } }),
std::exception);
cat1.erase(cif::key("id") == "aap");
BOOST_CHECK_EQUAL(cat1.size(), 1);
cat1.emplace({
{"id", "aap"},
{"c", "2e-aap"}
});
cat1.emplace({ { "id", "aap" },
{ "c", "2e-aap" } });
BOOST_CHECK_EQUAL(cat1.size(), 2);
}
......@@ -965,12 +1006,12 @@ _cat_2.desc
cat1.erase(cif::key("id") == 10);
BOOST_CHECK_EQUAL(cat1.size(), 2);
BOOST_CHECK_EQUAL(cat2.size(), 3); // TODO: Is this really what we want?
BOOST_CHECK_EQUAL(cat2.size(), 3); // TODO: Is this really what we want?
cat1.erase(cif::key("id") == 20);
BOOST_CHECK_EQUAL(cat1.size(), 1);
BOOST_CHECK_EQUAL(cat2.size(), 2); // TODO: Is this really what we want?
BOOST_CHECK_EQUAL(cat2.size(), 2); // TODO: Is this really what we want?
}
// --------------------------------------------------------------------
......@@ -1364,7 +1405,7 @@ _cat_2.parent_id3
std::transform(CR2set.begin(), CR2set.end(), std::back_inserter(CRids), [](cif::row_handle r)
{ return r["id"].as<int>(); });
std::sort(CRids.begin(), CRids.end());
BOOST_CHECK(CRids == std::vector<int>({4, 5, 6}));
BOOST_CHECK(CRids == std::vector<int>({ 4, 5, 6 }));
// check a rename in parent and child
......@@ -2098,7 +2139,8 @@ boo.data_.whatever
auto &db1 = data1.front();
auto &test1 = db1["test"];
struct T {
struct T
{
const char *s;
bool q;
} kS[] = {
......@@ -2154,13 +2196,15 @@ There it was!
auto &db1 = data1.front();
auto &test1 = db1["test"];
struct T {
struct T
{
const char *s;
bool q;
} kS[] = {
{ "A very, very loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong line", false },
{ R"(A line with a newline, look:
There it was!)", false}
There it was!)",
false }
};
BOOST_CHECK_EQUAL(test1.size(), sizeof(kS) / sizeof(T));
......@@ -2192,7 +2236,6 @@ There it was!)", false}
}
}
BOOST_AUTO_TEST_CASE(trim_test)
{
BOOST_CHECK_EQUAL(cif::trim_copy("aap"), "aap");
......@@ -2215,24 +2258,53 @@ BOOST_AUTO_TEST_CASE(trim_test)
std::string s;
s = "aap"; cif::trim(s); BOOST_CHECK_EQUAL(s, "aap");
s = " aap"; cif::trim(s); BOOST_CHECK_EQUAL(s, "aap");
s = " aap "; cif::trim(s); BOOST_CHECK_EQUAL(s, "aap");
s = "aap "; cif::trim(s); BOOST_CHECK_EQUAL(s, "aap");
s = " aap "; cif::trim(s); BOOST_CHECK_EQUAL(s, "aap");
s = "aap"; cif::trim_left(s); BOOST_CHECK_EQUAL(s, "aap");
s = " aap"; cif::trim_left(s); BOOST_CHECK_EQUAL(s, "aap");
s = " aap "; cif::trim_left(s); BOOST_CHECK_EQUAL(s, "aap ");
s = "aap "; cif::trim_left(s); BOOST_CHECK_EQUAL(s, "aap ");
s = "aap "; cif::trim_left(s); BOOST_CHECK_EQUAL(s, "aap ");
s = "aap"; cif::trim_right(s); BOOST_CHECK_EQUAL(s, "aap");
s = " aap"; cif::trim_right(s); BOOST_CHECK_EQUAL(s, " aap");
s = " aap "; cif::trim_right(s); BOOST_CHECK_EQUAL(s, " aap");
s = "aap "; cif::trim_right(s); BOOST_CHECK_EQUAL(s, "aap");
s = " aap "; cif::trim_right(s); BOOST_CHECK_EQUAL(s, " aap");
s = "aap";
cif::trim(s);
BOOST_CHECK_EQUAL(s, "aap");
s = " aap";
cif::trim(s);
BOOST_CHECK_EQUAL(s, "aap");
s = " aap ";
cif::trim(s);
BOOST_CHECK_EQUAL(s, "aap");
s = "aap ";
cif::trim(s);
BOOST_CHECK_EQUAL(s, "aap");
s = " aap ";
cif::trim(s);
BOOST_CHECK_EQUAL(s, "aap");
s = "aap";
cif::trim_left(s);
BOOST_CHECK_EQUAL(s, "aap");
s = " aap";
cif::trim_left(s);
BOOST_CHECK_EQUAL(s, "aap");
s = " aap ";
cif::trim_left(s);
BOOST_CHECK_EQUAL(s, "aap ");
s = "aap ";
cif::trim_left(s);
BOOST_CHECK_EQUAL(s, "aap ");
s = "aap ";
cif::trim_left(s);
BOOST_CHECK_EQUAL(s, "aap ");
s = "aap";
cif::trim_right(s);
BOOST_CHECK_EQUAL(s, "aap");
s = " aap";
cif::trim_right(s);
BOOST_CHECK_EQUAL(s, " aap");
s = " aap ";
cif::trim_right(s);
BOOST_CHECK_EQUAL(s, " aap");
s = "aap ";
cif::trim_right(s);
BOOST_CHECK_EQUAL(s, "aap");
s = " aap ";
cif::trim_right(s);
BOOST_CHECK_EQUAL(s, " aap");
}
BOOST_AUTO_TEST_CASE(split_test)
......@@ -2241,30 +2313,30 @@ BOOST_AUTO_TEST_CASE(split_test)
v = cif::split<>("aap;noot;mies", ";");
t = std::vector<std::string_view>{ "aap", "noot", "mies" };
BOOST_CHECK(v == t);
v = cif::split("aap;noot,mies", ";,");
// t = std::vector<std::string>{ "aap", "noot", "mies" };
BOOST_CHECK(v == t);
v = cif::split(";aap;noot,mies;", ";,");
t = std::vector<std::string_view>{ "", "aap", "noot", "mies", "" };
BOOST_CHECK(v == t);
v = cif::split(";aap;noot,mies;", ";,", true);
t = std::vector<std::string_view>{ "aap", "noot", "mies" };
BOOST_CHECK(v == t);
}
BOOST_AUTO_TEST_CASE(join_test)
{
BOOST_CHECK_EQUAL(cif::join(std::vector<std::string>{"aap"}, ", "), "aap");
BOOST_CHECK_EQUAL(cif::join(std::vector<std::string>{"aap", "noot"}, ", "), "aap, noot");
BOOST_CHECK_EQUAL(cif::join(std::vector<std::string>{"aap", "noot", "mies"}, ", "), "aap, noot, mies");
BOOST_CHECK_EQUAL(cif::join(std::vector<std::string>{ "aap" }, ", "), "aap");
BOOST_CHECK_EQUAL(cif::join(std::vector<std::string>{ "aap", "noot" }, ", "), "aap, noot");
BOOST_CHECK_EQUAL(cif::join(std::vector<std::string>{ "aap", "noot", "mies" }, ", "), "aap, noot, mies");
}
BOOST_AUTO_TEST_CASE(replace_all_test)
......@@ -2387,9 +2459,9 @@ _cat_1.name
int n = 1;
const char *ts[] = {"Aap", "Noot", "Mies"};
const char *ts[] = { "Aap", "Noot", "Mies" };
for (const auto &[id, name] : cat1.rows<int,std::string>("id", "name"))
for (const auto &[id, name] : cat1.rows<int, std::string>("id", "name"))
{
BOOST_CHECK_EQUAL(id, n);
BOOST_CHECK_EQUAL(name, ts[n - 1]);
......
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