aboutsummaryrefslogtreecommitdiffstats
path: root/document/src/vespa/document/base/field.cpp
blob: d19e9c372eb82dfa2511ca4f9d1f6912423ba346 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "field.h"
#include <vespa/document/fieldvalue/fieldvalue.h>
#include <vespa/document/datatype/datatype.h>
#include <vespa/document/fieldset/fieldsets.h>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/vespalib/stllike/asciistream.h>
#include <vespa/vespalib/util/bobhash.h>
#include <algorithm>

namespace document {

Field::Set::Set(std::vector<CPtr> fields)
    : _fields(std::move(fields))
{
    std::sort(_fields.begin(), _fields.end(), Field::FieldPtrLess());
    _fields.erase(std::unique(_fields.begin(), _fields.end(), Field::FieldPtrEqual()), _fields.end());
}

bool
Field::Set::contains(const Field & field) const {
    return std::binary_search(_fields.begin(), _fields.end(), &field, Field::FieldPtrLess());
}

bool
Field::Set::contains(const Set & fields) const {
    return std::includes(_fields.begin(), _fields.end(),
                         fields._fields.begin(), fields._fields.end(),
                         Field::FieldPtrLess());
}

Field::Field()
    : Field("", 0, *DataType::INT)
{ }

Field::Field(vespalib::stringref name, int fieldId, const DataType& dataType)
    : FieldSet(),
      _name(name),
      _dataType(&dataType),
      _fieldId(fieldId)
{ }

Field::Field(vespalib::stringref name, const DataType& dataType)
    : FieldSet(),
      _name(name),
      _dataType(&dataType),
      _fieldId(calculateIdV7())
{ }

Field::~Field() = default;

FieldValue::UP
Field::createValue() const {
    return _dataType->createFieldValue();
}

vespalib::string
Field::toString(bool verbose) const
{
    vespalib::asciistream out;
    out << "Field(" << getName();
    if (verbose) {
        out << ", id " << _fieldId;
    }
    out << ", " << _dataType->toString();
    out << ")";
    return out.str();
}

bool
Field::contains(const FieldSet& fields) const
{
    switch (fields.getType()) {
        case Type::FIELD:
            return static_cast<const Field&>(fields).getId() == getId();
        case Type::SET: {
            const auto & set = static_cast<const FieldCollection &>(fields);
            return (set.getFields().size() == 1) && ((*set.getFields().begin())->getId() == getId());
        }
        case Type::NONE:
        case Type::DOCID:
        return true;
        case Type::DOCUMENT_ONLY:
        case Type::ALL:
        return false;
    }

    return false;
}

int
Field::calculateIdV7()
{
    vespalib::asciistream ost;
    ost << getName();
    ost << _dataType->getId();

    int newId = vespalib::BobHash::hash(ost.str().data(), ost.str().length(), 0);
    // Highest bit is reserved to tell 7-bit id's from 31-bit ones
    if (newId < 0) newId = -newId;
    validateId(newId);
    return newId;
}

void
Field::validateId(int newId) {
    if (newId >= 100 && newId <= 127) {
        throw vespalib::IllegalArgumentException(vespalib::make_string(
                    "Attempt to set the id of %s to %d failed, values from "
                    "100 to 127 are reserved for internal use",
                    getName().data(), newId));
    }

    if ((uint32_t(newId) & 0x80000000u) != 0) // Highest bit must not be set
    {
        throw vespalib::IllegalArgumentException(vespalib::make_string(
                    "Attempt to set the id of %s to %d"
                    " failed, negative id values are illegal",
                    getName().data(), newId));
    }
}

} // document