aboutsummaryrefslogtreecommitdiffstats
path: root/searchlib/src/vespa/searchlib/query/tree/querybuilder.cpp
blob: 53f0231fcfcef1644857ac2c180bd2de7860822b (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
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "querybuilder.h"
#include "intermediate.h"
#include <vespa/vespalib/util/classname.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <cassert>

using vespalib::string;
using vespalib::make_string;
using vespalib::getClassName;

using namespace search::query;

void QueryBuilderBase::reportError(const string &msg) {
    if (!hasError()) {
        _error_msg = msg;
    }
}


void QueryBuilderBase::reportError(const string &msg, const Node & incomming, const Node & root) {
    reportError(make_string("%s: QueryBuilder got invalid node structure. Incomming node is '%s', while root is non-null('%s')",
                            msg.c_str(), getClassName(incomming).c_str(), getClassName(root).c_str()));
}

QueryBuilderBase::QueryBuilderBase()
    : _root(),
      _nodes(),
      _error_msg() {
}

QueryBuilderBase::~QueryBuilderBase() {
    reset();
}

void QueryBuilderBase::addCompleteNode(Node *n)
{
    Node::UP node(n);

    if (hasError()) {
        return;
    }
    if (_nodes.empty()) {
        if (!_root) {
            _root = std::move(node);
        } else {
            reportError("QueryBuilderBase::addCompleteNode", *node, *_root);
        }
        return;
    }

    assert(_nodes.top().remaining_child_count > 0);
    _nodes.top().node->append(std::move(node));
    if (--_nodes.top().remaining_child_count == 0) {
        Node *completed(_nodes.top().node);
        _nodes.pop();
        addCompleteNode(completed);
    }
}

void QueryBuilderBase::addIntermediateNode(Intermediate *n, int child_count)
{
    Intermediate::UP node(n);
    if (!hasError()) {
        if (_root) {
            reportError("QueryBuilderBase::addIntermediateNode", *node, *_root);
        } else {
            node->reserve(child_count);
            WeightOverride weight_override;
            if (!_nodes.empty()) {
                weight_override = _nodes.top().weight_override;
            }
            _nodes.push(NodeInfo(node.release(), child_count));
            _nodes.top().weight_override = weight_override;
            if (child_count == 0) {
                Node *completed(_nodes.top().node);
                _nodes.pop();
                addCompleteNode(completed);
            }
        }
    }
}

void QueryBuilderBase::setWeightOverride(const Weight &weight) {
    if ( !hasError() ) {
        _nodes.top().weight_override = WeightOverride(weight);
    }
}

Node::UP QueryBuilderBase::build() {
    if (!_nodes.empty()) {
        reportError("QueryBuilderBase::build: QueryBuilder got invalid node structure. _nodes are not empty.");
    } else if (!_root) {
        reportError("QueryBuilderBase::build: Trying to build incomplete query tree.");
    }
    if (hasError()) {
        return Node::UP();
    }
    return std::move(_root);
}

void QueryBuilderBase::reset() {
    while (!_nodes.empty()) {
        delete _nodes.top().node;
        _nodes.pop();
    }
    _root.reset(0);
    _error_msg = "";
}