2018-03-26 20:39:10 +00:00
|
|
|
#pragma once
|
|
|
|
#include "FieldBase.h"
|
|
|
|
#include "Field.h"
|
|
|
|
|
|
|
|
namespace ki
|
|
|
|
{
|
|
|
|
namespace dml
|
|
|
|
{
|
2018-03-30 20:34:06 +00:00
|
|
|
/**
|
|
|
|
* An ordered collection of DML fields.
|
|
|
|
*/
|
2018-03-29 15:06:20 +00:00
|
|
|
class Record final : public util::Serializable
|
2018-03-26 20:39:10 +00:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
Record();
|
|
|
|
Record(const Record &record);
|
2018-03-29 15:06:20 +00:00
|
|
|
virtual ~Record();
|
2018-03-26 20:39:10 +00:00
|
|
|
|
2018-03-30 20:34:06 +00:00
|
|
|
/**
|
|
|
|
* Returns true if a field of any type has the name
|
|
|
|
* specified.
|
|
|
|
*/
|
2018-03-26 20:39:10 +00:00
|
|
|
bool has_field(std::string name) const;
|
|
|
|
|
2018-03-30 20:34:06 +00:00
|
|
|
/**
|
|
|
|
* Returns true if a field exists with the specified
|
|
|
|
* name and type.
|
|
|
|
*/
|
2018-03-26 20:39:10 +00:00
|
|
|
template <typename ValueT>
|
|
|
|
bool has_field(std::string name) const
|
|
|
|
{
|
|
|
|
if (!has_field(name))
|
|
|
|
return false;
|
2018-03-29 15:06:20 +00:00
|
|
|
return m_field_map.at(name)->is_type<ValueT>();
|
2018-03-26 20:39:10 +00:00
|
|
|
}
|
|
|
|
|
2018-04-04 03:08:06 +00:00
|
|
|
FieldBase *get_field(std::string name) const;
|
|
|
|
|
2018-03-30 20:34:06 +00:00
|
|
|
/**
|
|
|
|
* Returns a previously added field with the specified name
|
|
|
|
* and type.
|
|
|
|
*
|
|
|
|
* If the field was not previously added, then a nullptr is
|
|
|
|
* returned.
|
|
|
|
*/
|
2018-03-26 20:39:10 +00:00
|
|
|
template <typename ValueT>
|
2018-03-29 15:06:20 +00:00
|
|
|
Field<ValueT> *get_field(std::string name) const
|
2018-03-26 20:39:10 +00:00
|
|
|
{
|
|
|
|
if (has_field<ValueT>(name))
|
2018-03-29 15:06:20 +00:00
|
|
|
return dynamic_cast<Field<ValueT> *>(m_field_map.at(name));
|
2018-03-26 20:39:10 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-03-30 20:34:06 +00:00
|
|
|
/**
|
|
|
|
* Adds a new field to the record with the specified name, type,
|
|
|
|
* and transferability, and returns the newly created field.
|
|
|
|
*
|
|
|
|
* If a field already exists with the specified name and type,
|
|
|
|
* then the previously added field is returned.
|
|
|
|
*
|
|
|
|
* If a field already exists with the specified name, but the type
|
|
|
|
* differs, then a nullptr is returned.
|
|
|
|
*/
|
2018-03-26 20:39:10 +00:00
|
|
|
template <typename ValueT>
|
2018-03-29 15:06:20 +00:00
|
|
|
Field<ValueT> *add_field(std::string name, bool transferable = true)
|
2018-03-26 20:39:10 +00:00
|
|
|
{
|
2018-03-29 15:06:20 +00:00
|
|
|
// Does this field already exist?
|
2018-03-30 15:37:17 +00:00
|
|
|
if (has_field(name))
|
|
|
|
{
|
|
|
|
// Return nullptr if the type is not the same
|
|
|
|
auto *field = m_field_map.at(name);
|
|
|
|
if (!field->is_type<ValueT>())
|
|
|
|
return nullptr;
|
|
|
|
return dynamic_cast<Field<ValueT> *>(field);
|
|
|
|
}
|
2018-03-29 15:06:20 +00:00
|
|
|
|
|
|
|
// Create the field
|
2018-04-02 01:54:13 +00:00
|
|
|
auto *field = new Field<ValueT>(name);
|
2018-03-29 15:06:20 +00:00
|
|
|
field->m_transferable = transferable;
|
|
|
|
add_field(field);
|
2018-03-26 20:39:10 +00:00
|
|
|
return field;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t get_field_count() const;
|
|
|
|
|
2018-03-29 15:06:20 +00:00
|
|
|
FieldList::const_iterator fields_begin() const;
|
|
|
|
FieldList::const_iterator fields_end() const;
|
2018-03-26 20:39:10 +00:00
|
|
|
|
2018-04-03 16:11:34 +00:00
|
|
|
void write_to(std::ostream &ostream) const override final;
|
|
|
|
void read_from(std::istream &istream) override final;
|
|
|
|
size_t get_size() const override final;
|
2018-03-31 19:22:42 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates an XML node from this record's data.
|
|
|
|
*
|
|
|
|
* The document is only used to allocate necessary resources, and
|
|
|
|
* so the returned node has not been appended to the document.
|
|
|
|
*/
|
|
|
|
rapidxml::xml_node<> *as_xml(rapidxml::xml_document<> &doc) const;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Loads data from an XML Record node into this record.
|
|
|
|
*
|
|
|
|
* If a Field already exists, and the type is the same,
|
|
|
|
* then the new value is copied into the original Field.
|
|
|
|
* If the type is not the same, then the original Field
|
|
|
|
* is deleted, and replaced with the new one.
|
|
|
|
*/
|
|
|
|
void from_xml(rapidxml::xml_node<> *node);
|
2018-03-26 20:39:10 +00:00
|
|
|
private:
|
|
|
|
FieldList m_fields;
|
|
|
|
FieldNameMap m_field_map;
|
2018-03-29 15:06:20 +00:00
|
|
|
|
|
|
|
void add_field(FieldBase *field);
|
2018-03-26 20:39:10 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|