xref: /6.0.3/subjson/subdoc/operations.h (revision 85ed622c)
1/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3*     Copyright 2015 Couchbase, Inc
4*
5*   Licensed under the Apache License, Version 2.0 (the "License");
6*   you may not use this file except in compliance with the License.
7*   You may obtain a copy of the License at
8*
9*       http://www.apache.org/licenses/LICENSE-2.0
10*
11*   Unless required by applicable law or agreed to in writing, software
12*   distributed under the License is distributed on an "AS IS" BASIS,
13*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*   See the License for the specific language governing permissions and
15*   limitations under the License.
16*/
17
18#include "subdoc-c.h"
19
20#if !defined(SUBDOC_OPERATIONS_H) && defined(__cplusplus)
21#define SUBDOC_OPERATIONS_H
22#include "subdoc-api.h"
23#include "loc.h"
24#include "path.h"
25#include "match.h"
26
27#include <array>
28
29namespace Subdoc {
30
31/**
32 * This class acts as a user-allocated buffer region for the Operation
33 * object to store results.
34 *
35 * This will be treated as an "out" param
36 */
37class Result {
38public:
39    Result() : m_newlen(0) {}
40    Result(const Result&) = delete;
41    Result& operator=(const Result&) = delete;
42
43    /**
44     * Returns the segments of the new document. Note that the underlying
45     * buffer (the one used in Operation::set_doc()) as well as this object
46     * itself (i.e. the Result object) must both still remain valid for
47     * the returned buffer's contents to be considered valid.
48     * @return a Buffer object representing the layout of the new document.
49     */
50    const Buffer<Loc> newdoc() const {
51        return Buffer<Loc>(m_newdoc.data(), m_newlen);
52    }
53
54    /**
55     * For operations which result in a match returned to the user (e.g.
56     * Command::GET, Command::COUNTER), the result is returned here.
57     *
58     * The returned @ref Loc may refer to regions within the input document
59     * (Operation::set_doc()), and thus should be considered invalid when the
60     * buffer passed to Operation::set_doc() has been modified.
61     *
62     * @return The location of the match.
63     */
64    const Loc& matchloc() const { return m_match; }
65
66    /**
67     * For operations that are non-subjson, this method provides a way to
68     * pass around results within the existing infrastructure.
69     *
70     * Care should be taken with this method to ensure that match is a valid Loc
71     *
72     * @param match The match location
73     */
74    void set_matchloc(Loc match) {
75        m_match = match;
76    }
77
78    bool push_newdoc(Loc newLoc) {
79        if (m_newlen >= m_newdoc.size()) {
80            return false;
81        }
82        m_newdoc[m_newlen++] = newLoc;
83        return true;
84    }
85
86    void clear() {
87        m_bkbuf.clear();
88        m_numbuf.clear();
89        m_match.length = 0;
90        m_newlen = 0;
91    }
92private:
93    friend class Operation;
94    std::string m_bkbuf;
95    std::string m_numbuf;
96    std::array<Loc, 8> m_newdoc;
97    size_t m_newlen = 0; // The number of Locs used in m_newdoc
98    Loc m_match;
99};
100
101class Operation {
102public:
103    Operation();
104    void clear();
105    ~Operation();
106    Error op_exec(const char *pth, size_t npth);
107    Error op_exec(const std::string& s) { return op_exec(s.c_str(), s.size()); }
108
109    void set_value(const char *s, size_t n) { m_userval.assign(s, n); }
110    void set_value(const std::string& s) { set_value(s.c_str(), s.size()); }
111    void set_result_buf(Result *res) { m_result = res; }
112    void set_doc(const char *s, size_t n) { m_doc.assign(s, n); }
113    void set_doc(const std::string& s) { set_doc(s.c_str(), s.size()); }
114    void set_code(uint8_t code) { m_optype = code; }
115
116    const Match& match() const { return m_match; }
117    const Path& path() const { return *m_path; }
118    jsonsl_t parser() const { return m_jsn; }
119
120private:
121    /* malloc'd because this block is pretty big (several k) */
122    Path *m_path;
123    /* cached JSON parser */
124    jsonsl_t m_jsn;
125
126    Match m_match;
127
128    /* opcode */
129    Command m_optype;
130
131    /* Location of original document */
132    Loc m_doc;
133
134    /* Location of the user's "Value" (if applicable) */
135    Loc m_userval;
136
137    //! Pointer to result given by user
138    Result *m_result;
139
140    Error do_match_common(Match::SearchOptions options);
141    Error do_get();
142    Error do_store_dict();
143    Error do_remove();
144
145    enum MkdirPMode {
146        MKDIR_P_ARRAY, //!< Insert ... "key": [ value ]
147        MKDIR_P_DICT //!< Insert ... "key":value
148    };
149    Error do_mkdir_p(MkdirPMode mode);
150    Error insert_singleton_element();
151    Error do_list_append();
152    Error do_empty_append();
153    Error do_list_prepend();
154    Error do_arith_op();
155    Error do_insert();
156    Error do_container_size();
157
158    // Wrapper around Validator::validate(), this omits the
159    // passing of arguments we already have (for example, the new object)
160    // and also wraps the error code
161    Error validate(int mode, int depth = -1);
162
163    enum DepthMode {
164        /// Last component of the path is the key for the new item
165        PATH_HAS_NEWKEY,
166        /// Path consists only of parent elements
167        PATH_IS_PARENT
168    };
169    inline int get_maxdepth(DepthMode mode) const;
170
171    //! Equivalent to m_newdoc[n]. This is here so our frequent access
172    //! can occupy less line space.
173    Loc& newdoc_at(size_t n) { return m_result->m_newdoc[n]; }
174};
175}
176
177#endif
178