1 /*************************************************************************
3 * Copyright 2016 Realm Inc.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 **************************************************************************/
19 #ifndef REALM_COLUMN_TIMESTAMP_HPP
20 #define REALM_COLUMN_TIMESTAMP_HPP
22 #include <realm/column.hpp>
23 #include <realm/timestamp.hpp>
27 // Inherits from ColumnTemplate to get a compare_values() that can be called without knowing the
29 class TimestampColumn : public ColumnBaseSimple {
31 TimestampColumn(bool nullable, Allocator& alloc, ref_type ref, size_t col_ndx = npos);
33 static ref_type create(Allocator& alloc, size_t size, bool nullable);
34 static size_t get_size_from_ref(ref_type root_ref, Allocator& alloc) noexcept;
36 /// Get the number of entries in this column. This operation is relatively
38 size_t size() const noexcept override;
39 /// Whether or not this column is nullable.
40 bool is_nullable() const noexcept override;
41 /// Whether or not the value at \a row_ndx is NULL. If the column is not
42 /// nullable, always returns false.
43 bool is_null(size_t row_ndx) const noexcept override;
44 /// Sets the value at \a row_ndx to be NULL.
45 /// \throw LogicError Thrown if this column is not nullable.
46 void set_null(size_t row_ndx) override;
47 void insert_rows(size_t row_ndx, size_t num_rows_to_insert, size_t prior_num_rows, bool nullable) override;
48 void erase_rows(size_t row_ndx, size_t num_rows_to_erase, size_t prior_num_rows,
49 bool broken_reciprocal_backlinks) override;
50 void move_last_row_over(size_t row_ndx, size_t prior_num_rows, bool broken_reciprocal_backlinks) override;
51 void clear(size_t num_rows, bool broken_reciprocal_backlinks) override;
52 void swap_rows(size_t row_ndx_1, size_t row_ndx_2) override;
53 void destroy() noexcept override;
55 bool has_search_index() const noexcept final
57 return bool(m_search_index);
59 StringIndex* get_search_index() noexcept final
61 return m_search_index.get();
63 StringIndex* get_search_index() const noexcept final
65 return m_search_index.get();
67 void destroy_search_index() noexcept override;
68 void set_search_index_ref(ref_type ref, ArrayParent* parent, size_t ndx_in_parent) final;
69 void populate_search_index();
70 StringIndex* create_search_index() override;
71 bool supports_search_index() const noexcept final
76 StringData get_index_data(size_t, StringIndex::StringConversionBuffer& buffer) const noexcept override;
77 ref_type write(size_t slice_offset, size_t slice_size, size_t table_size, _impl::OutputStream&) const override;
78 void update_from_parent(size_t old_baseline) noexcept override;
79 void set_ndx_in_parent(size_t ndx) noexcept override;
80 void refresh_accessor_tree(size_t new_col_ndx, const Spec&) override;
82 void verify() const override;
83 void to_dot(std::ostream&, StringData title = StringData()) const override;
84 void do_dump_node_structure(std::ostream&, int level) const override;
85 void leaf_to_dot(MemRef, ArrayParent*, size_t ndx_in_parent, std::ostream&) const override;
87 void add(const Timestamp& ts = Timestamp{});
88 Timestamp get(size_t row_ndx) const noexcept;
89 void set(size_t row_ndx, const Timestamp& ts);
90 bool compare(const TimestampColumn& c) const noexcept;
91 int compare_values(size_t row1, size_t row2) const noexcept override;
93 Timestamp maximum(size_t* result_index) const;
94 Timestamp minimum(size_t* result_index) const;
95 size_t count(Timestamp) const;
96 void erase(size_t row_ndx, bool is_last);
98 template <class Condition>
99 size_t find(Timestamp value, size_t begin, size_t end) const noexcept
101 // FIXME: Here we can do all sorts of clever optimizations. Use bithack-search on seconds, then for each match
102 // check nanoseconds, etc. Lots of possibilities. Below code is naive and slow but works.
105 for (size_t t = begin; t < end; t++) {
106 Timestamp ts = get(t);
107 if (cond(ts, value, ts.is_null(), value.is_null()))
113 typedef Timestamp value_type;
116 std::unique_ptr<BpTree<util::Optional<int64_t>>> m_seconds;
117 std::unique_ptr<BpTree<int64_t>> m_nanoseconds;
119 std::unique_ptr<StringIndex> m_search_index;
125 template <class Condition>
126 Timestamp minmax(size_t* result_index) const noexcept
128 // Condition is realm::Greater for maximum and realm::Less for minimum. Any non-null value is both larger
129 // and smaller than a null value.
132 *result_index = npos;
136 Timestamp best = get(0);
137 size_t best_index = best.is_null() ? npos : 0;
139 for (size_t i = 1; i < size(); ++i) {
140 Timestamp candidate = get(i);
141 // Condition() will return false if any of the two values are null.
142 if ((best.is_null() && !candidate.is_null()) || Condition()(candidate, best, candidate.is_null(), best.is_null())) {
148 *result_index = best_index;
155 #endif // REALM_COLUMN_TIMESTAMP_HPP