Blame view

Pods/Realm/include/core/realm/spec.hpp 7.83 KB
75d24c15   yangbin   123
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
  /*************************************************************************
   *
   * Copyright 2016 Realm Inc.
   *
   * 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.
   *
   **************************************************************************/
  
  #ifndef REALM_SPEC_HPP
  #define REALM_SPEC_HPP
  
  #include <realm/util/features.h>
  #include <realm/array.hpp>
  #include <realm/array_string_short.hpp>
  #include <realm/data_type.hpp>
  #include <realm/column_type.hpp>
  #include <realm/keys.hpp>
  
  namespace realm {
  
  class Table;
  class Group;
  
  class Spec {
  public:
      ~Spec() noexcept;
  
      Allocator& get_alloc() const noexcept;
  
      // insert column at index
      void insert_column(size_t column_ndx, ColKey column_key, ColumnType type, StringData name,
                         int attr = col_attr_None);
      ColKey get_key(size_t column_ndx) const;
      void rename_column(size_t column_ndx, StringData new_name);
  
      /// Erase the column at the specified index.
      ///
      /// This function is guaranteed to *never* throw if the spec is
      /// used in a non-transactional context, or if the spec has
      /// already been successfully modified within the current write
      /// transaction.
      void erase_column(size_t column_ndx);
  
      // Column info
      size_t get_column_count() const noexcept;
      size_t get_public_column_count() const noexcept;
      ColumnType get_column_type(size_t column_ndx) const noexcept;
      StringData get_column_name(size_t column_ndx) const noexcept;
  
      /// Returns size_t(-1) if the specified column is not found.
      size_t get_column_index(StringData name) const noexcept;
  
      // Column Attributes
      ColumnAttrMask get_column_attr(size_t column_ndx) const noexcept;
      void set_dictionary_key_type(size_t column_ndx, DataType key_type);
      DataType get_dictionary_key_type(size_t column_ndx) const;
  
      // Auto Enumerated string columns
      void upgrade_string_to_enum(size_t column_ndx, ref_type keys_ref);
      size_t _get_enumkeys_ndx(size_t column_ndx) const noexcept;
      bool is_string_enum_type(size_t column_ndx) const noexcept;
      ref_type get_enumkeys_ref(size_t column_ndx, ArrayParent*& keys_parent) noexcept;
  
      //@{
      /// Compare two table specs for equality.
      bool operator==(const Spec&) const noexcept;
      bool operator!=(const Spec&) const noexcept;
      //@}
  
      void detach() noexcept;
      void destroy() noexcept;
  
      size_t get_ndx_in_parent() const noexcept;
      void set_ndx_in_parent(size_t) noexcept;
  
      void verify() const;
  
  private:
      // Underlying array structure.
      //
      Array m_top;
      Array m_types;            // 1st slot in m_top
      ArrayStringShort m_names; // 2nd slot in m_top
      Array m_attr;             // 3rd slot in m_top
      // 4th slot in m_top is vacant
      Array m_enumkeys; // 5th slot in m_top
      Array m_keys;     // 6th slot in m_top
      size_t m_num_public_columns;
  
      Spec(Allocator&) noexcept; // Unattached
  
      bool init(ref_type) noexcept;
      void init(MemRef) noexcept;
      void update_internals() noexcept;
  
      // Returns true in case the ref has changed.
      bool init_from_parent() noexcept;
  
      ref_type get_ref() const noexcept;
  
      /// Called in the context of Group::commit() to ensure that
      /// attached table accessors stay valid across a commit. Please
      /// note that this works only for non-transactional commits. Table
      /// accessors obtained during a transaction are always detached
      /// when the transaction ends.
      void update_from_parent() noexcept;
  
      void set_parent(ArrayParent*, size_t ndx_in_parent) noexcept;
  
      void set_column_attr(size_t column_ndx, ColumnAttrMask attr);
  
      // Migration
      bool convert_column_attributes();
      bool convert_column_keys(TableKey table_key);
      void fix_column_keys(TableKey table_key);
      bool has_subspec()
      {
          return m_top.get(3) != 0;
      }
      void destroy_subspec()
      {
          Node::destroy(m_top.get_as_ref(3), m_top.get_alloc());
          m_top.set(3, 0);
      }
      TableKey get_opposite_link_table_key(size_t column_ndx) const noexcept;
      size_t get_origin_column_ndx(size_t backlink_col_ndx) const noexcept;
      ColKey find_backlink_column(TableKey origin_table_key, size_t spec_ndx) const noexcept;
  
  
      // Generate a column key only from state in the spec.
      ColKey update_colkey(ColKey existing_key, size_t spec_ndx, TableKey table_key);
      /// Construct an empty spec and return just the reference to the
      /// underlying memory.
      static MemRef create_empty_spec(Allocator&);
  
      size_t get_subspec_ndx(size_t column_ndx) const noexcept;
  
      friend class Group;
      friend class Table;
  };
  
  // Implementation:
  
  inline Allocator& Spec::get_alloc() const noexcept
  {
      return m_top.get_alloc();
  }
  
  // Uninitialized Spec (call init() to init)
  inline Spec::Spec(Allocator& alloc) noexcept
      : m_top(alloc)
      , m_types(alloc)
      , m_names(alloc)
      , m_attr(alloc)
      , m_enumkeys(alloc)
      , m_keys(alloc)
  {
      m_types.set_parent(&m_top, 0);
      m_names.set_parent(&m_top, 1);
      m_attr.set_parent(&m_top, 2);
      m_enumkeys.set_parent(&m_top, 4);
      m_keys.set_parent(&m_top, 5);
  }
  
  inline bool Spec::init_from_parent() noexcept
  {
      ref_type ref = m_top.get_ref_from_parent();
      return init(ref);
  }
  
  inline void Spec::destroy() noexcept
  {
      m_top.destroy_deep();
  }
  
  inline size_t Spec::get_ndx_in_parent() const noexcept
  {
      return m_top.get_ndx_in_parent();
  }
  
  inline void Spec::set_ndx_in_parent(size_t ndx) noexcept
  {
      m_top.set_ndx_in_parent(ndx);
  }
  
  inline ref_type Spec::get_ref() const noexcept
  {
      return m_top.get_ref();
  }
  
  inline void Spec::set_parent(ArrayParent* parent, size_t ndx_in_parent) noexcept
  {
      m_top.set_parent(parent, ndx_in_parent);
  }
  
  inline void Spec::rename_column(size_t column_ndx, StringData new_name)
  {
      REALM_ASSERT(column_ndx < m_types.size());
      m_names.set(column_ndx, new_name);
  }
  
  inline size_t Spec::get_column_count() const noexcept
  {
      // This is the total count of columns, including backlinks (not public)
      return m_types.size();
  }
  
  inline size_t Spec::get_public_column_count() const noexcept
  {
      return m_num_public_columns;
  }
  
  inline ColumnType Spec::get_column_type(size_t ndx) const noexcept
  {
      REALM_ASSERT(ndx < get_column_count());
      return ColumnType(int(m_types.get(ndx) & 0xFFFF));
  }
  
  inline ColumnAttrMask Spec::get_column_attr(size_t ndx) const noexcept
  {
      REALM_ASSERT(ndx < get_column_count());
      return ColumnAttrMask(m_attr.get(ndx));
  }
  
  inline void Spec::set_dictionary_key_type(size_t ndx, DataType key_type)
  {
      auto type = m_types.get(ndx);
      m_types.set(ndx, (type & 0xFFFF) + (int64_t(key_type) << 16));
  }
  
  inline DataType Spec::get_dictionary_key_type(size_t ndx) const
  {
      REALM_ASSERT(ndx < get_column_count());
      return DataType(int(m_types.get(ndx) >> 16));
  }
  
  inline void Spec::set_column_attr(size_t column_ndx, ColumnAttrMask attr)
  {
      REALM_ASSERT(column_ndx < get_column_count());
  
      // At this point we only allow one attr at a time
      // so setting it will overwrite existing. In the future
      // we will allow combinations.
      m_attr.set(column_ndx, attr.m_value);
  
      update_internals();
  }
  
  inline StringData Spec::get_column_name(size_t ndx) const noexcept
  {
      return m_names.get(ndx);
  }
  
  inline size_t Spec::get_column_index(StringData name) const noexcept
  {
      return m_names.find_first(name);
  }
  
  inline bool Spec::operator!=(const Spec& s) const noexcept
  {
      return !(*this == s);
  }
  
  } // namespace realm
  
  #endif // REALM_SPEC_HPP