Commit 26c86282 by Maarten L. Hekkelman

before refactoring item_value based on statistics

parent 0eaeb165
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 NKI/AVL, Netherlands Cancer Institute
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "row.hpp"
#include "validate.hpp"
namespace cif::v2
{
// --------------------------------------------------------------------
template <
typename Alloc = std::allocator<std::byte>>
class category_t
{
public:
using allocator_type = Alloc;
allocator_type get_allocator() const
{
return m_allocator;
}
struct iterator {};
category_t() = default;
category_t(std::string_view name, const allocator_type &alloc = allocator_type())
: m_allocator(alloc)
, m_name(name)
{
}
category_t(const category_t &) = default;
category_t(category_t &&) = default;
template <typename Alloc2>
category_t(const category_t &c, const Alloc2 &a)
: m_allocator(a)
, m_name(c.m_name)
{
}
template <typename Alloc2>
category_t(category_t &&c, const Alloc2 &a)
: m_allocator(a)
, m_name(std::move(c.m_name))
{
}
category_t &operator=(const category_t &) = default;
category_t &operator=(category_t &&) = default;
~category_t()
{
auto r = m_head;
while (r != nullptr)
{
auto t = r->m_next;
delete_row(r);
r = t;
}
}
// --------------------------------------------------------------------
const std::string &name() const { return m_name; }
iterator emplace(std::initializer_list<item> items)
{
return this->emplace(items.begin(), items.end());
}
template <typename ItemIter>
iterator emplace(ItemIter b, ItemIter e)
{
// First, make sure all mandatory fields are supplied
// if (mCatValidator != nullptr and b != e)
// {
// for (auto &col : m_columns)
// {
// auto iv = mCatValidator->getValidatorForItem(col.mName);
// if (iv == nullptr)
// continue;
// bool seen = false;
// for (auto v = b; v != e; ++v)
// {
// if (iequals(v->name(), col.mName))
// {
// seen = true;
// break;
// }
// }
// if (not seen and iv->mMandatory)
// throw std::runtime_error("missing mandatory field " + col.mName + " for Category " + mName);
// }
// if (mIndex != nullptr)
// {
// std::unique_ptr<ItemRow> nr(new ItemRow{nullptr, this, nullptr});
// Row r(nr.get());
// auto keys = keyFields();
// for (auto v = b; v != e; ++v)
// {
// if (keys.count(v->name()))
// r.assign(v->name(), v->value(), true);
// }
// auto test = mIndex->find(nr.get());
// if (test != nullptr)
// {
// if (VERBOSE > 1)
// std::cerr << "Not inserting new record in " << mName << " (duplicate Key)" << std::endl;
// result = test;
// isNew = false;
// }
// }
// }
auto r = create_row(m_head, nullptr);
std::vector<item_value *> item_values;
// std::transform(b, e, std::back_inserter(item_values), [this](Item &i) { return this->create_item(i); });
for (auto i = b; i != e; ++i)
item_values.push_back(this->create_item(*i));
for (auto p : item_values)
delete_item(p);
return {};
// return iterator{ create_row() };
// Row r(nr);
// for (auto v = b; v != e; ++v)
// r.assign(*v, true);
// // if (isOrphan(r))
// // throw std::runtime_error("Cannot insert row in category " + mName + " since it would be an orphan");
// if (mHead == nullptr)
// {
// assert(mTail == nullptr);
// mHead = mTail = nr;
// }
// else
// {
// assert(mTail != nullptr);
// assert(mHead != nullptr);
// mTail->mNext = nr;
// mTail = nr;
// }
// result = r;
// if (mIndex != nullptr)
// mIndex->insert(nr);
}
// void emplace(std::initializer_list<item> items)
// {
// this->emplace_back(value_type{items, this->get_allocator()});
// }
// --------------------------------------------------------------------
/// \brief Return the index number for \a column_name
uint32_t get_column_ix(std::string_view column_name) const
{
uint32_t result;
for (result = 0; result < m_columns.size(); ++result)
{
if (iequals(column_name, m_columns[result].m_name))
break;
}
// if (VERBOSE > 0 and result == m_columns.size() and mCatValidator != nullptr) // validate the name, if it is known at all (since it was not found)
// {
// auto iv = mCatValidator->getValidatorForItem(name);
// if (iv == nullptr)
// std::cerr << "Invalid name used '" << name << "' is not a known column in " + mName << std::endl;
// }
return result;
}
uint32_t add_column(std::string_view column_name)
{
using namespace std::literals;
size_t result = get_column_ix(column_name);
if (result == m_columns.size())
{
const ValidateItem *itemValidator = nullptr;
// if (mCatValidator != nullptr)
// {
// itemValidator = mCatValidator->getValidatorForItem(column_name);
// if (itemValidator == nullptr)
// mValidator->reportError("tag " + std::string(column_name) + " not allowed in Category " + mName, false);
// }
m_columns.emplace_back(column_name, itemValidator);
}
return result;
}
private:
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(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;
};
struct item_column
{
std::string m_name;
ValidateItem *m_validator;
item_column(std::string_view name, ValidateItem *validator)
: m_name(name)
, m_validator(validator)
{
}
};
using row_allocator_type = typename std::allocator_traits<allocator_type>::template rebind_alloc<row>;
using row_allocator_traits = std::allocator_traits<row_allocator_type>;
row_allocator_traits::pointer get_row()
{
row_allocator_type ra(get_allocator());
return row_allocator_traits::allocate(ra, 1);
}
template <typename... Args>
row *create_row(Args... args)
{
auto p = this->get_row();
row_allocator_type ra(get_allocator());
row_allocator_traits::construct(ra, p, std::forward<Args>(args)...);
return p;
}
void delete_row(row *r)
{
row_allocator_type ra(get_allocator());
row_allocator_traits::destroy(ra, r);
row_allocator_traits::deallocate(ra, r, 1);
}
constexpr static size_t calculate_item_size(const char* text)
{
return calculate_item_size(strlen(text));
}
constexpr static size_t calculate_item_size(size_t text_len)
{
size_t raw_size = sizeof(item_value) + text_len + 1 - 4;
return raw_size / sizeof(item_value) + ((raw_size % sizeof(item_value)) ? 1 : 0);
}
using item_allocator_type = typename std::allocator_traits<Alloc>::template rebind_alloc<item_value>;
using item_allocator_traits = std::allocator_traits<item_allocator_type>;
// struct item_allocator_traits : std::allocator_traits<item_allocator_type>
// {
// using base_type = std::allocator_traits<item_allocator_type>;
// static constexpr typename base_type::pointer
// allocate(item_allocator_type &a, typename base_type::size_type n)
// {
// return base_type::allocate(a, n);
// }
// };
item_allocator_traits::pointer get_item(size_t item_size)
{
item_allocator_type ia(get_allocator());
return item_allocator_traits::allocate(ia, item_size);
}
item_value *create_item(uint32_t column_ix, const char *text)
{
auto p = this->get_item(calculate_item_size(text));
item_allocator_type ia(get_allocator());
item_allocator_traits::construct(ia, p, column_ix, text);
return p;
}
item_value *create_item(const item &i)
{
uint32_t ix = get_column_ix(i.name());
return create_item(ix, i.c_str());
}
void delete_item(item_value *iv)
{
item_allocator_type ia(get_allocator());
item_allocator_traits::destroy(ia, iv);
item_allocator_traits::deallocate(ia, iv, 1);
}
allocator_type m_allocator;
std::string m_name;
std::vector<item_column, typename std::allocator_traits<allocator_type>::template rebind_alloc<item_column>> m_columns;
row *m_head = nullptr, *m_tail = nullptr;
};
using category = category_t<>;
} // namespace cif::v2
\ No newline at end of file
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 NKI/AVL, Netherlands Cancer Institute
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "category.hpp"
namespace cif::v2
{
// --------------------------------------------------------------------
template <
typename Category = category,
typename Alloc = std::allocator<Category>>
class datablock_t : public std::list<Category, Alloc>
{
public:
using category_type = Category;
using base_type = std::list<category_type, Alloc>;
using allocator_type = Alloc;
datablock_t(const std::string &name, const allocator_type &alloc = allocator_type())
: base_type(alloc)
, m_name(name)
{
}
datablock_t(const datablock_t &) = default;
datablock_t(datablock_t &&) = default;
template <typename Alloc2>
datablock_t(const datablock_t &db, const Alloc2 &a)
: base_type(db, a)
, m_name(db.m_name)
{
}
template <typename Alloc2>
datablock_t(datablock_t &&db, const Alloc2 &a)
: base_type(std::move(db), a)
, m_name(db.m_name)
{
}
datablock_t &operator=(const datablock_t &) = default;
datablock_t &operator=(datablock_t &&) = default;
// --------------------------------------------------------------------
const std::string &name() const { return m_name; }
// --------------------------------------------------------------------
category_type &operator[](std::string_view name)
{
auto i = std::find_if(this->begin(), this->end(), [name](const category_type &c)
{ return iequals(c.name(), name); });
if (i == this->end())
i = this->emplace(name);
return *i;
}
const category_type &operator[](std::string_view name) const
{
static const category_type s_empty;
auto i = std::find_if(this->begin(), this->end(), [name](const category_type &c)
{ return iequals(c.name(), name); });
return i == this->end() ? s_empty : *i;
}
void write(std::ostream &os) const
{
// std::shared_lock lock(mLock);
os << "data_" << m_name << std::endl
<< "# " << std::endl;
// mmcif support, sort of. First write the 'entry' Category
// and if it exists, _AND_ we have a Validator, write out the
// audit_conform record.
for (auto &cat : *this)
{
if (cat.name() != "entry")
continue;
cat.write(os);
// if (mValidator != nullptr)
// {
// Category auditConform(*this, "audit_conform", nullptr);
// auditConform.emplace({{"dict_name", mValidator->dictName()},
// {"dict_version", mValidator->dictVersion()}});
// auditConform.write(os);
// }
break;
}
for (auto &cat : *this)
{
if (cat.name() != "entry" and cat.name() != "audit_conform")
cat.write(os);
}
}
friend std::ostream &operator<<(std::ostream &os, const datablock_t &db)
{
db.write(os);
return os;
}
private:
std::string m_name;
};
using datablock = datablock_t<>;
}
\ No newline at end of file
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 NKI/AVL, Netherlands Cancer Institute
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "datablock.hpp"
namespace cif::v2
{
// --------------------------------------------------------------------
template <
typename Datablock = datablock,
typename Alloc = std::allocator<Datablock>>
class file_t : public std::list<Datablock, Alloc>
{
public:
using value_type = Datablock;
using base_type = std::list<value_type, Alloc>;
using allocator_type = Alloc;
file_t() = default;
file_t(std::istream &is, const allocator_type &alloc = allocator_type())
{
}
file_t(const file_t &) = default;
file_t(file_t &&) = default;
file_t &operator=(const file_t &) = default;
file_t &operator=(file_t &&) = default;
};
using file = file_t<>;
}
\ No newline at end of file
......@@ -28,6 +28,7 @@
#include <cstring>
#include <iomanip>
#include <memory>
#include <optional>
......@@ -35,6 +36,78 @@ namespace cif::v2
{
// --------------------------------------------------------------------
/// \brief item is a transient class that is used to pass data into rows
class item
{
public:
item() = default;
item(std::string_view name, char value)
: m_name(name)
, m_value({ value })
{
}
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)
#if defined(__cpp_lib_format)
, m_value(std::format(".{}f", value, precision))
#endif
{
#if not defined(__cpp_lib_format)
// TODO: implement
m_value = std::to_string(value);
#endif
}
template <typename T, std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
item(const std::string_view name, const T &value)
: m_name(name)
, m_value(std::to_string(value))
{
}
item(const std::string_view name, const std::string_view value)
: m_name(name)
, m_value(value)
{
}
item(const item &rhs) = default;
item(item &&rhs) noexcept = default;
item &operator=(const item &rhs) = default;
item &operator=(item &&rhs) noexcept = default;
const std::string &name() const { return m_name; }
const std::string &value() const { return m_value; }
void value(const std::string &v) { m_value = v; }
/// \brief empty means either null or unknown
bool empty() const { return m_value.empty(); }
/// \brief returns true if the field contains '.'
bool is_null() const { return m_value == "."; }
/// \brief returns true if the field contains '?'
bool is_unknown() const { return m_value == "?"; }
size_t length() const { return m_value.length(); }
const char *c_str() const { return m_value.c_str(); }
private:
std::string m_name;
std::string m_value;
};
// --------------------------------------------------------------------
// Internal storage, strictly forward linked list with minimal space
// requirements.
......@@ -46,23 +119,13 @@ struct item_value
strcpy(m_text, value);
}
~item_value()
{
// remove recursively (and be paranoid)
while (m_next != nullptr and m_next != this)
{
auto n = m_next;
m_next = n->m_next;
n->m_next = nullptr;
delete n;
}
}
item_value *m_next;
uint32_t m_column_ix;
char m_text[4];
};
static_assert(sizeof(item_value) == 2 * sizeof(void*), "Item value should be two pointers in size...");
// --------------------------------------------------------------------
// Transient object to access stored data
......
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 NKI/AVL, Netherlands Cancer Institute
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "item.hpp"
namespace cif::v2
{
// --------------------------------------------------------------------
/// \brief row_handle is the way to access data in rows
template<typename Category>
class row_handle
{
public:
using category_type = Category;
row_handle(Category &cat)
: m_cat(cat) {}
// item_handle<row_t> operator[](uint32_t column_ix)
// {
// return item_handle<row_t>(column_ix, *this);
// }
// const item_handle<const row_t> operator[](uint32_t column_ix) const
// {
// return item_handle<const row_t>(column_ix, *this);
// }
// item_handle<row_t> operator[](std::string_view column_name)
// {
// return item_handle<row_t>(column_name, get_column_ix(column_name), *this);
// }
// const item_handle<const row_t> operator[](std::string_view column_name) const
// {
// return item_handle<const row_t>(column_name, get_column_ix(column_name), *this);
// }
private:
uint32_t get_column_ix(std::string_view name) const
{
return m_cat.get_column_ix(name);
}
category_type &m_cat;
};
}
\ No newline at end of file
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2022 NKI/AVL, Netherlands Cancer Institute
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
// duh.. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86164
// #include <regex>
#include <boost/regex.hpp>
#include <set>
#include "cif++/CifUtils.hpp"
namespace cif::v2
{
struct ValidateCategory;
class ValidatorFactory;
// --------------------------------------------------------------------
class ValidationError : public std::exception
{
public:
ValidationError(const std::string &msg);
ValidationError(const std::string &cat, const std::string &item,
const std::string &msg);
const char *what() const noexcept { return mMsg.c_str(); }
std::string mMsg;
};
// --------------------------------------------------------------------
enum class DDL_PrimitiveType
{
Char,
UChar,
Numb
};
DDL_PrimitiveType mapToPrimitiveType(std::string_view s);
struct ValidateType
{
std::string mName;
DDL_PrimitiveType mPrimitiveType;
// std::regex mRx;
boost::regex mRx;
bool operator<(const ValidateType &rhs) const
{
return icompare(mName, rhs.mName) < 0;
}
// compare values based on type
// int compare(const std::string& a, const std::string& b) const
// {
// return compare(a.c_str(), b.c_str());
// }
int compare(const char *a, const char *b) const;
};
struct ValidateItem
{
std::string mTag;
bool mMandatory;
const ValidateType *mType;
cif::iset mEnums;
std::string mDefault;
bool mDefaultIsNull;
ValidateCategory *mCategory = nullptr;
// ItemLinked is used for non-key links
struct ItemLinked
{
ValidateItem *mParent;
std::string mParentItem;
std::string mChildItem;
};
std::vector<ItemLinked> mLinked;
bool operator<(const ValidateItem &rhs) const
{
return icompare(mTag, rhs.mTag) < 0;
}
bool operator==(const ValidateItem &rhs) const
{
return iequals(mTag, rhs.mTag);
}
void operator()(std::string value) const;
};
struct ValidateCategory
{
std::string mName;
std::vector<std::string> mKeys;
cif::iset mGroups;
cif::iset mMandatoryFields;
std::set<ValidateItem> mItemValidators;
bool operator<(const ValidateCategory &rhs) const
{
return icompare(mName, rhs.mName) < 0;
}
void addItemValidator(ValidateItem &&v);
const ValidateItem *getValidatorForItem(std::string_view tag) const;
const std::set<ValidateItem> &itemValidators() const
{
return mItemValidators;
}
};
struct ValidateLink
{
int mLinkGroupID;
std::string mParentCategory;
std::vector<std::string> mParentKeys;
std::string mChildCategory;
std::vector<std::string> mChildKeys;
std::string mLinkGroupLabel;
};
// --------------------------------------------------------------------
class Validator
{
public:
Validator(std::string_view name, std::istream &is);
~Validator();
Validator(const Validator &rhs) = delete;
Validator &operator=(const Validator &rhs) = delete;
Validator(Validator &&rhs);
Validator &operator=(Validator &&rhs);
friend class DictParser;
friend class ValidatorFactory;
void addTypeValidator(ValidateType &&v);
const ValidateType *getValidatorForType(std::string_view typeCode) const;
void addCategoryValidator(ValidateCategory &&v);
const ValidateCategory *getValidatorForCategory(std::string_view category) const;
void addLinkValidator(ValidateLink &&v);
std::vector<const ValidateLink *> getLinksForParent(std::string_view category) const;
std::vector<const ValidateLink *> getLinksForChild(std::string_view category) const;
void reportError(const std::string &msg, bool fatal) const;
std::string dictName() const { return mName; }
void dictName(const std::string &name) { mName = name; }
std::string dictVersion() const { return mVersion; }
void dictVersion(const std::string &version) { mVersion = version; }
private:
// name is fully qualified here:
ValidateItem *getValidatorForItem(std::string_view name) const;
std::string mName;
std::string mVersion;
bool mStrict = false;
// std::set<uint32_t> mSubCategories;
std::set<ValidateType> mTypeValidators;
std::set<ValidateCategory> mCategoryValidators;
std::vector<ValidateLink> mLinkValidators;
};
// --------------------------------------------------------------------
class ValidatorFactory
{
public:
static ValidatorFactory &instance()
{
return sInstance;
}
const Validator &operator[](std::string_view dictionary);
private:
static ValidatorFactory sInstance;
ValidatorFactory();
std::mutex mMutex;
std::list<Validator> mValidators;
};
} // namespace cif
// void write(std::ostream &os, const std::vector<size_t> &order, bool includeEmptyColumns)
// {
// if (empty())
// return;
// // If there are multiple rows in this category, we need a _loop
// if (size() == 1)
// {
// os << "loop_" << std::endl;
// std::vector<size_t> columnWidths;
// for (auto cix : order)
// {
// auto &col = mColumns[cix];
// os << '_' << mName << '.' << col.mName << ' ' << std::endl;
// columnWidths.push_back(2);
// }
// for (auto Row = mHead; Row != nullptr; Row = Row->mNext)
// {
// for (auto v = Row->mValues; v != nullptr; v = v->mNext)
// {
// if (strchr(v->mText, '\n') == nullptr)
// {
// size_t l = strlen(v->mText);
// if (not isUnquotedString(v->mText))
// l += 2;
// if (l > 132)
// continue;
// if (columnWidths[v->mColumnIndex] < l + 1)
// columnWidths[v->mColumnIndex] = l + 1;
// }
// }
// }
// for (auto Row = mHead; Row != nullptr; Row = Row->mNext) // loop over rows
// {
// size_t offset = 0;
// for (size_t cix : order)
// {
// size_t w = columnWidths[cix];
// std::string s;
// for (auto iv = Row->mValues; iv != nullptr; iv = iv->mNext)
// {
// if (iv->mColumnIndex == cix)
// {
// s = iv->mText;
// break;
// }
// }
// if (s.empty())
// s = "?";
// size_t l = s.length();
// if (not isUnquotedString(s.c_str()))
// l += 2;
// if (l < w)
// l = w;
// if (offset + l > 132 and offset > 0)
// {
// os << std::endl;
// offset = 0;
// }
// offset = detail::writeValue(os, s, offset, w);
// if (offset > 132)
// {
// os << std::endl;
// offset = 0;
// }
// }
// if (offset > 0)
// os << std::endl;
// }
// }
// else
// {
// // first find the indent level
// size_t l = 0;
// for (auto &col : mColumns)
// {
// std::string tag = '_' + mName + '.' + col.mName;
// if (l < tag.length())
// l = tag.length();
// }
// l += 3;
// for (size_t cix : order)
// {
// auto &col = mColumns[cix];
// os << '_' << mName << '.' << col.mName << std::string(l - col.mName.length() - mName.length() - 2, ' ');
// std::string s;
// for (auto iv = mHead->mValues; iv != nullptr; iv = iv->mNext)
// {
// if (iv->mColumnIndex == cix)
// {
// s = iv->mText;
// break;
// }
// }
// if (s.empty())
// s = "?";
// size_t offset = l;
// if (s.length() + l >= kMaxLineLength)
// {
// os << std::endl;
// offset = 0;
// }
// if (detail::writeValue(os, s, offset, 1) != 0)
// os << std::endl;
// }
// }
// os << "# " << std::endl;
// }
void write(std::ostream &os) const
{
// std::vector<size_t> order(mColumns.size());
// iota(order.begin(), order.end(), 0);
// write(os, order, false);
os << '#' << m_name << std::endl;
for (auto &r : *this)
{
for (auto &f : r)
os << '_' << m_name << '.' << f.name() << ' ' << f.value() << std::endl;
}
}
// void Category::write(std::ostream &os, const std::vector<std::string> &columns)
// {
// // make sure all columns are present
// for (auto &c : columns)
// addColumn(c);
// std::vector<size_t> order;
// order.reserve(mColumns.size());
// for (auto &c : columns)
// order.push_back(getColumnIndex(c));
// for (size_t i = 0; i < mColumns.size(); ++i)
// {
// if (std::find(order.begin(), order.end(), i) == order.end())
// order.push_back(i);
// }
// write(os, order, true);
// }
......@@ -78,17 +78,13 @@ bool init_unit_test()
BOOST_AUTO_TEST_CASE(r_1)
{
cif::v2::row r;
std::cout << r["f1"].value_or("<leeg>") << std::endl;
// cif::v2::category c("foo");
// c.emplace({
// { "f-1", 1 },
// { "f-2", "two" },
// { "f-3", 3.0 },
// // { "f-4", 3.0, 3 }
// });
cif::v2::category c("foo");
c.emplace({
{ "f-1", 1 },
{ "f-2", "two" },
{ "f-3", 3.0 },
// { "f-4", 3.0, 3 }
});
// cif::v2::datablock db("test");
// db.emplace_back(std::move(c));
......
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