-
Notifications
You must be signed in to change notification settings - Fork 130
/
Copy pathsimple_dom_impl.h
145 lines (123 loc) · 4.53 KB
/
simple_dom_impl.h
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
Copyright 2022 The Photon Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#pragma once
#include <inttypes.h>
#include <assert.h>
#include <memory>
#include <math.h>
#include <atomic>
#include <photon/common/object.h>
#include <photon/common/estring.h>
#include <photon/common/enumerable.h>
#include <photon/common/stream.h>
namespace photon {
namespace SimpleDOM {
using str = estring_view;
// the interface for internal implementations
class NodeImpl : public Object {
protected:
NodeImpl() = default;
const static uint8_t FLAG_IS_ROOT = 1;
const static uint8_t FLAG_IS_LAST = 2;
const static uint8_t FLAG_TEXT_OWNERSHIP= 4;
const static size_t MAX_NODE_SIZE = 256;
const static size_t MAX_NCHILDREN = UINT16_MAX;
const static size_t MAX_KEY_OFFSET = UINT32_MAX;
const static size_t MAX_KEY_LENGTH = 4095;
const static size_t MAX_VALUE_OFFSET = 4095;
const static size_t MAX_VALUE_LENGTH = MAX_KEY_OFFSET;
union { struct { // for non-root nodes
struct {
uint8_t _flags;
uint16_t _k_len : 12; // key length (12 bits)
uint16_t _v_off : 12; // value offset (12 bits) to key end
}__attribute__((packed));
uint32_t _k_off; // key offset to _text_begin
const NodeImpl* _root; // root node
uint32_t _v_len; // value length
} ; // packed as 20 bytes
struct { // for the root node
uint8_t _flags_; // the same as _flags
uint8_t _node_size; // sizeof(the node implementation)
mutable uint16_t _refcnt; // reference counter of the document
uint32_t _k_off_;
const char* _text_begin;
uint32_t _v_len_;
}; };
uint16_t _nchildren; // for all nodes
using AT16 = std::atomic<uint16_t>;
static_assert(sizeof(AT16) == sizeof(_refcnt), "...");
void add_doc_ref() const {
assert(is_root());
auto refcnt = (AT16*)&_refcnt;
++*refcnt;
}
void del_doc_ref() const {
assert(is_root());
auto refcnt = (AT16*)&_refcnt;
if (--*refcnt == 0)
delete this;
}
friend class Node;
public:
size_t num_children() const {
return _nchildren;
}
// get the i-th child node
// for an array object, it gets the i-th element (doc type determines the starting value)
// for an object, it gets the i-th element in implementation defined order (same-key
// nodes are garanteed adjacent)
virtual const NodeImpl* get(size_t i) const __attribute__((pure)) = 0;
// get the first child node with a specified `key`
// XML attributes are treated as a special child node with key "__attributes__"
virtual const NodeImpl* get(str key) const __attribute__((pure)) = 0;
bool is_root() const {
return _flags & FLAG_IS_ROOT;
}
const NodeImpl* get_root() const {
return is_root() ? this : _root;
}
str get_key() const {
return {get_root()->_text_begin + _k_off, _k_len};
}
str get_value() const {
return {get_key().end() + _v_off, _v_len};
}
str get_key(const char* text_begin) const {
return {text_begin + _k_off, _k_len};
}
str get_value(const char* text_begin) const {
return {get_key(text_begin).end() + _v_off, _v_len};
}
bool has_next_sibling() const {
return !(_flags & FLAG_IS_LAST);
}
const NodeImpl* next_sibling() const { // assuming consecutive placement
if (!has_next_sibling()) return nullptr;
assert(!is_root());
auto next = (char*)this + _root->_node_size;
return (NodeImpl*)next;
}
bool operator < (const NodeImpl& rhs) const {
assert(!is_root());
assert(_root == rhs._root);
return get_key() < rhs.get_key();
}
bool operator < (str key) const {
return get_key() < key;
}
int init_root(const char* text_begin, uint32_t node_size, bool text_ownership);
int init_non_root(str key, str value, const NodeImpl* root, uint32_t flags);
};
}
}