1#ifndef TAG_PARSER_FIELDBASEDTAG_H
2#define TAG_PARSER_FIELDBASEDTAG_H
17template <
typename ImplementationType>
class FieldMapBasedTagTraits {};
30template <
class ImplementationType>
class FieldMapBasedTag :
public Tag {
31 friend class FieldMapBasedTagTraits<ImplementationType>;
54 const std::multimap<IdentifierType, FieldType, Compare> &
fields()
const;
55 std::multimap<IdentifierType, FieldType, Compare> &
fields();
80 std::multimap<IdentifierType, FieldType, Compare> m_fields;
106 return ImplementationType::tagType;
111 return ImplementationType::tagName;
116 return ImplementationType::defaultTextEncoding;
125 auto i = m_fields.find(
id);
133template <
class ImplementationType>
137 if (!field.value().isEmpty()) {
138 values.emplace_back(&field.value());
146template <
class ImplementationType>
149 auto range = m_fields.equal_range(
id);
150 std::vector<const TagValue *> values;
151 for (
auto i = range.first; i != range.second; ++i) {
152 static_cast<const ImplementationType *
>(
this)->internallyGetValuesFromField(i->second, values);
163 return static_cast<const ImplementationType *
>(
this)->internallyGetValue(
id);
168 return value(fieldId(field));
177 return static_cast<const ImplementationType *
>(
this)->internallyGetValues(
id);
182 return static_cast<const ImplementationType *
>(
this)->values(fieldId(field));
187 const auto id = fieldId(field);
188 if constexpr (std::is_arithmetic_v<IdentifierType>) {
197 return setValue(
id, value);
206 auto i = m_fields.find(
id);
207 if (i != m_fields.end()) {
208 i->second.setValue(value);
210 m_fields.insert(std::make_pair(
id,
FieldType(
id, value)));
221template <
class ImplementationType>
224 auto valuesIterator = values.cbegin();
225 auto range = m_fields.equal_range(
id);
227 for (; valuesIterator != values.cend() && range.first != range.second; ++valuesIterator) {
229 if (!valuesIterator->isEmpty()) {
230 auto &field = range.first->second;
232 field.setValue(*valuesIterator);
237 for (; valuesIterator != values.cend(); ++valuesIterator) {
238 if (!valuesIterator->isEmpty()) {
239 m_fields.insert(std::make_pair(
id,
FieldType(
id, *valuesIterator)));
243 for (; range.first != range.second; ++range.first) {
244 range.first->second.clearValue();
255 return static_cast<ImplementationType *
>(
this)->internallySetValue(
id, value);
264template <
class ImplementationType>
267 return static_cast<ImplementationType *
>(
this)->internallySetValues(
id, values);
278 const auto id = fieldId(field);
279 if constexpr (std::is_arithmetic_v<IdentifierType>) {
288 return setValues(
id, values);
293 return hasField(fieldId(field));
302 for (
auto range = m_fields.equal_range(
id); range.first != range.second; ++range.first) {
303 if (!range.first->second.value().isEmpty()) {
315 return static_cast<const ImplementationType *
>(
this)->internallyHasField(
id);
326template <
class ImplementationType>
342 auto count = std::size_t(0);
343 for (
const auto &field : m_fields) {
344 if (!field.second.value().isEmpty()) {
355template <
class ImplementationType>
358 return static_cast<const ImplementationType *
>(
this)->internallyGetFieldId(value);
367 return static_cast<const ImplementationType *
>(
this)->internallyGetKnownField(
id);
373 return fieldId(field) != def;
380template <
class ImplementationType>
391 return static_cast<ImplementationType *
>(
this)->determineProposedDataType(
id);
400template <
class ImplementationType>
403 auto fieldsInserted = std::size_t(0);
404 for (
const auto &pair : from.fields()) {
405 const FieldType &fromField = pair.second;
406 if (fromField.value().isEmpty()) {
409 bool fieldInserted =
false;
410 auto range = fields().equal_range(fromField.id());
411 for (
auto i = range.first; i != range.second; ++i) {
413 if ((fromField.isTypeInfoAssigned() && ownField.isTypeInfoAssigned() && fromField.typeInfo() == ownField.typeInfo())
414 || (!fromField.isTypeInfoAssigned() && !ownField.isTypeInfoAssigned())) {
415 if (overwrite || ownField.value().isEmpty()) {
416 ownField = fromField;
419 fieldInserted =
true;
423 if (!fieldInserted) {
424 fields().insert(std::make_pair(fromField.id(), fromField));
428 return fieldsInserted;
433 if (type() == from.
type()) {
443 for (
auto &field : fields()) {
444 field.second.value().convertDataEncodingForTag(
this);
Defines traits for the specified ImplementationType.
The FieldMapBasedTag provides a generic implementation of Tag which stores the tag fields using std::...
bool hasField(const IdentifierType &id) const
Returns an indication whether the field with the specified id is present.
bool setValue(const IdentifierType &id, const TagValue &value)
Assigns the given value to the field with the specified id.
void ensureTextValuesAreProperlyEncoded()
Ensures the encoding of all assigned text values is supported by the tag by converting the character ...
bool setValue(KnownField field, const TagValue &value)
Assigns the given value to the specified field.
bool hasField(KnownField field) const
Returns an indication whether the specified field is present.
std::vector< const TagValue * > values(KnownField field) const
Returns the values of the specified field.
std::multimap< IdentifierType, FieldType, Compare > & fields()
Returns the fields of the tag by providing direct access to the field map of the tag.
std::vector< const TagValue * > internallyGetValues(const IdentifierType &id) const
Default implementation for values().
typename FieldMapBasedTagTraits< ImplementationType >::Compare Compare
std::string_view typeName() const
Returns the type name of the tag as C-style string.
typename FieldMapBasedTagTraits< ImplementationType >::FieldType::IdentifierType IdentifierType
const TagValue & value(KnownField field) const
Returns the value of the specified field.
FieldMapBasedTag()
Constructs a new FieldMapBasedTag.
TagTextEncoding proposedTextEncoding() const
Returns the proposed text encoding.
const TagValue & value(const IdentifierType &id) const
Returns the value of the field with the specified id.
void removeAllFields()
Removes all fields from the tag.
const std::multimap< IdentifierType, FieldType, Compare > & fields() const
Returns the fields of the tag by providing direct access to the field map of the tag.
TagDataType proposedDataType(const IdentifierType &id) const
Returns the proposed data type for the field with the specified id.
bool internallySetValues(const IdentifierType &id, const std::vector< TagValue > &values)
Default implementation for setValues().
TagType type() const
Returns the type of the tag as TagParser::TagType.
std::size_t insertFields(const FieldMapBasedTag< ImplementationType > &from, bool overwrite)
Inserts all fields from another tag of the same field type and compare function.
typename FieldMapBasedTagTraits< ImplementationType >::FieldType FieldType
TagDataType internallyGetProposedDataType(const IdentifierType &id) const
Default implementation for proposedDataType().
void internallyGetValuesFromField(const FieldType &field, std::vector< const TagValue * > &values) const
Default way to gather values from a field in internallyGetValues().
KnownField knownField(const IdentifierType &id) const
Returns the field for the specified ID.
std::vector< const TagValue * > values(const IdentifierType &id) const
Returns the values of the field with the specified id.
const TagValue & internallyGetValue(const IdentifierType &id) const
Default implementation for value().
bool internallyHasField(const IdentifierType &id) const
Default implementation for hasField().
bool setValues(const IdentifierType &id, const std::vector< TagValue > &values)
Assigns the given values to the field with the specified id.
std::size_t fieldCount() const
Returns the number of present fields.
bool supportsField(KnownField field) const
Returns an indication whether the specified field is supported by the tag.
bool setValues(KnownField field, const std::vector< TagValue > &values)
Assigns the given values to the field with the specified id.
IdentifierType fieldId(KnownField value) const
Returns the ID for the specified field.
std::size_t insertValues(const Tag &from, bool overwrite)
Inserts all compatible values from another Tag.
bool internallySetValue(const IdentifierType &id, const TagValue &value)
Default implementation for setValue().
The TagValue class wraps values of different types.
static const TagValue & empty()
Returns a default-constructed TagValue where TagValue::isNull() and TagValue::isEmpty() both return t...
bool isEmpty() const
Returns whether no or an empty value is assigned.
The Tag class is used to store, read and write tag information.
virtual std::size_t insertValues(const Tag &from, bool overwrite)
Inserts all compatible values from another Tag.
virtual TagType type() const
Returns the type of the tag as TagParser::TagType.
virtual TagDataType proposedDataType(KnownField field) const
Returns the proposed data type for the specified field as TagDataType.
Contains all classes and functions of the TagInfo library.
KnownField
Specifies the field.
TagTextEncoding
Specifies the text encoding.
TagType
Specifies the tag type.
TagDataType
Specifies the data type.