added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / core / realm / array_integer.hpp
diff --git a/iOS/Pods/Realm/include/core/realm/array_integer.hpp b/iOS/Pods/Realm/include/core/realm/array_integer.hpp
new file mode 100644 (file)
index 0000000..e460c53
--- /dev/null
@@ -0,0 +1,629 @@
+/*************************************************************************
+ *
+ * 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_ARRAY_INTEGER_HPP
+#define REALM_ARRAY_INTEGER_HPP
+
+#include <realm/array.hpp>
+#include <realm/util/safe_int_ops.hpp>
+#include <realm/util/optional.hpp>
+
+namespace realm {
+
+class ArrayInteger : public Array {
+public:
+    typedef int64_t value_type;
+
+    explicit ArrayInteger(Allocator&) noexcept;
+    ~ArrayInteger() noexcept override
+    {
+    }
+
+    // Disable copying, this is not allowed.
+    ArrayInteger& operator=(const ArrayInteger&) = delete;
+    ArrayInteger(const ArrayInteger&) = delete;
+
+    void create(Type type = type_Normal, bool context_flag = false);
+
+    void add(int64_t value);
+    void set(size_t ndx, int64_t value);
+    void set_uint(size_t ndx, uint_fast64_t value) noexcept;
+    int64_t get(size_t ndx) const noexcept;
+    uint64_t get_uint(size_t ndx) const noexcept;
+    static int64_t get(const char* header, size_t ndx) noexcept;
+    bool compare(const ArrayInteger& a) const noexcept;
+
+    /// Add \a diff to the element at the specified index.
+    void adjust(size_t ndx, int_fast64_t diff);
+
+    /// Add \a diff to all the elements in the specified index range.
+    void adjust(size_t begin, size_t end, int_fast64_t diff);
+
+    /// Add signed \a diff to all elements that are greater than, or equal to \a
+    /// limit.
+    void adjust_ge(int_fast64_t limit, int_fast64_t diff);
+
+    int64_t operator[](size_t ndx) const noexcept
+    {
+        return get(ndx);
+    }
+    int64_t front() const noexcept;
+    int64_t back() const noexcept;
+
+    size_t lower_bound(int64_t value) const noexcept;
+    size_t upper_bound(int64_t value) const noexcept;
+
+    std::vector<int64_t> to_vector() const;
+
+private:
+    template <size_t w>
+    bool minmax(size_t from, size_t to, uint64_t maxdiff, int64_t* min, int64_t* max) const;
+};
+
+class ArrayIntNull : public Array {
+public:
+    using value_type = util::Optional<int64_t>;
+
+    explicit ArrayIntNull(Allocator&) noexcept;
+    ~ArrayIntNull() noexcept override;
+
+    /// Construct an array of the specified type and size, and return just the
+    /// reference to the underlying memory. All elements will be initialized to
+    /// the specified value.
+    static MemRef create_array(Type, bool context_flag, size_t size, value_type value, Allocator&);
+    void create(Type = type_Normal, bool context_flag = false);
+
+    void init_from_ref(ref_type) noexcept;
+    void init_from_mem(MemRef) noexcept;
+    void init_from_parent() noexcept;
+
+    size_t size() const noexcept;
+    bool is_empty() const noexcept;
+
+    void insert(size_t ndx, value_type value);
+    void add(value_type value);
+    void set(size_t ndx, value_type value) noexcept;
+    value_type get(size_t ndx) const noexcept;
+    static value_type get(const char* header, size_t ndx) noexcept;
+    void get_chunk(size_t ndx, value_type res[8]) const noexcept;
+    void set_null(size_t ndx) noexcept;
+    bool is_null(size_t ndx) const noexcept;
+    int64_t null_value() const noexcept;
+
+    value_type operator[](size_t ndx) const noexcept;
+    value_type front() const noexcept;
+    value_type back() const noexcept;
+    void erase(size_t ndx);
+    void erase(size_t begin, size_t end);
+    void truncate(size_t size);
+    void clear();
+    void set_all_to_zero();
+
+    void move(size_t begin, size_t end, size_t dest_begin);
+    void move_backward(size_t begin, size_t end, size_t dest_end);
+
+    size_t lower_bound(int64_t value) const noexcept;
+    size_t upper_bound(int64_t value) const noexcept;
+
+    int64_t sum(size_t start = 0, size_t end = npos) const;
+    size_t count(int64_t value) const noexcept;
+    bool maximum(int64_t& result, size_t start = 0, size_t end = npos, size_t* return_ndx = nullptr) const;
+    bool minimum(int64_t& result, size_t start = 0, size_t end = npos, size_t* return_ndx = nullptr) const;
+
+    bool find(int cond, Action action, value_type value, size_t start, size_t end, size_t baseindex,
+              QueryState<int64_t>* state) const;
+
+    template <class cond, Action action, size_t bitwidth, class Callback>
+    bool find(value_type value, size_t start, size_t end, size_t baseindex, QueryState<int64_t>* state,
+              Callback callback) const;
+
+    // This is the one installed into the m_finder slots.
+    template <class cond, Action action, size_t bitwidth>
+    bool find(int64_t value, size_t start, size_t end, size_t baseindex, QueryState<int64_t>* state) const;
+
+    template <class cond, Action action, class Callback>
+    bool find(value_type value, size_t start, size_t end, size_t baseindex, QueryState<int64_t>* state,
+              Callback callback) const;
+
+    // Optimized implementation for release mode
+    template <class cond, Action action, size_t bitwidth, class Callback>
+    bool find_optimized(value_type value, size_t start, size_t end, size_t baseindex, QueryState<int64_t>* state,
+                        Callback callback) const;
+
+    // Called for each search result
+    template <Action action, class Callback>
+    bool find_action(size_t index, value_type value, QueryState<int64_t>* state, Callback callback) const;
+
+    template <Action action, class Callback>
+    bool find_action_pattern(size_t index, uint64_t pattern, QueryState<int64_t>* state, Callback callback) const;
+
+    // Wrappers for backwards compatibility and for simple use without
+    // setting up state initialization etc
+    template <class cond>
+    size_t find_first(value_type value, size_t start = 0, size_t end = npos) const;
+
+    void find_all(IntegerColumn* result, value_type value, size_t col_offset = 0, size_t begin = 0,
+                  size_t end = npos) const;
+
+
+    size_t find_first(value_type value, size_t begin = 0, size_t end = npos) const;
+
+
+    // Overwrite Array::bptree_leaf_insert to correctly split nodes.
+    ref_type bptree_leaf_insert(size_t ndx, value_type value, TreeInsertBase& state);
+
+    MemRef slice(size_t offset, size_t slice_size, Allocator& target_alloc) const;
+
+    /// Construct a deep copy of the specified slice of this array using the
+    /// specified target allocator. Subarrays will be cloned.
+    MemRef slice_and_clone_children(size_t offset, size_t slice_size, Allocator& target_alloc) const;
+
+protected:
+    void avoid_null_collision(int64_t value);
+
+private:
+    template <bool find_max>
+    bool minmax_helper(int64_t& result, size_t start = 0, size_t end = npos, size_t* return_ndx = nullptr) const;
+
+    int_fast64_t choose_random_null(int64_t incoming) const;
+    void replace_nulls_with(int64_t new_null);
+    bool can_use_as_null(int64_t value) const;
+};
+
+
+// Implementation:
+
+inline ArrayInteger::ArrayInteger(Allocator& allocator) noexcept
+    : Array(allocator)
+{
+    m_is_inner_bptree_node = false;
+}
+
+inline void ArrayInteger::add(int64_t value)
+{
+    Array::add(value);
+}
+
+inline int64_t ArrayInteger::get(size_t ndx) const noexcept
+{
+    return Array::get(ndx);
+}
+
+inline int64_t ArrayInteger::get(const char* header, size_t ndx) noexcept
+{
+    return Array::get(header, ndx);
+}
+
+inline void ArrayInteger::set(size_t ndx, int64_t value)
+{
+    Array::set(ndx, value);
+}
+
+inline void ArrayInteger::set_uint(size_t ndx, uint_fast64_t value) noexcept
+{
+    // When a value of a signed type is converted to an unsigned type, the C++
+    // standard guarantees that negative values are converted from the native
+    // representation to 2's complement, but the effect of conversions in the
+    // opposite direction is left unspecified by the
+    // standard. `realm::util::from_twos_compl()` is used here to perform the
+    // correct opposite unsigned-to-signed conversion, which reduces to a no-op
+    // when 2's complement is the native representation of negative values.
+    set(ndx, util::from_twos_compl<int_fast64_t>(value));
+}
+
+inline bool ArrayInteger::compare(const ArrayInteger& a) const noexcept
+{
+    if (a.size() != size())
+        return false;
+
+    for (size_t i = 0; i < size(); ++i) {
+        if (get(i) != a.get(i))
+            return false;
+    }
+
+    return true;
+}
+
+inline int64_t ArrayInteger::front() const noexcept
+{
+    return Array::front();
+}
+
+inline int64_t ArrayInteger::back() const noexcept
+{
+    return Array::back();
+}
+
+inline void ArrayInteger::adjust(size_t ndx, int_fast64_t diff)
+{
+    Array::adjust(ndx, diff);
+}
+
+inline void ArrayInteger::adjust(size_t begin, size_t end, int_fast64_t diff)
+{
+    Array::adjust(begin, end, diff);
+}
+
+inline void ArrayInteger::adjust_ge(int_fast64_t limit, int_fast64_t diff)
+{
+    Array::adjust_ge(limit, diff);
+}
+
+inline size_t ArrayInteger::lower_bound(int64_t value) const noexcept
+{
+    return lower_bound_int(value);
+}
+
+inline size_t ArrayInteger::upper_bound(int64_t value) const noexcept
+{
+    return upper_bound_int(value);
+}
+
+
+inline ArrayIntNull::ArrayIntNull(Allocator& allocator) noexcept
+    : Array(allocator)
+{
+}
+
+inline ArrayIntNull::~ArrayIntNull() noexcept
+{
+}
+
+inline void ArrayIntNull::create(Type type, bool context_flag)
+{
+    MemRef r = create_array(type, context_flag, 0, util::none, m_alloc);
+    init_from_mem(r);
+}
+
+
+inline size_t ArrayIntNull::size() const noexcept
+{
+    return Array::size() - 1;
+}
+
+inline bool ArrayIntNull::is_empty() const noexcept
+{
+    return size() == 0;
+}
+
+inline void ArrayIntNull::insert(size_t ndx, value_type value)
+{
+    if (value) {
+        avoid_null_collision(*value);
+        Array::insert(ndx + 1, *value);
+    }
+    else {
+        Array::insert(ndx + 1, null_value());
+    }
+}
+
+inline void ArrayIntNull::add(value_type value)
+{
+    if (value) {
+        avoid_null_collision(*value);
+        Array::add(*value);
+    }
+    else {
+        Array::add(null_value());
+    }
+}
+
+inline void ArrayIntNull::set(size_t ndx, value_type value) noexcept
+{
+    if (value) {
+        avoid_null_collision(*value);
+        Array::set(ndx + 1, *value);
+    }
+    else {
+        Array::set(ndx + 1, null_value());
+    }
+}
+
+inline void ArrayIntNull::set_null(size_t ndx) noexcept
+{
+    Array::set(ndx + 1, null_value());
+}
+
+inline ArrayIntNull::value_type ArrayIntNull::get(size_t ndx) const noexcept
+{
+    int64_t value = Array::get(ndx + 1);
+    if (value == null_value()) {
+        return util::none;
+    }
+    return util::some<int64_t>(value);
+}
+
+inline ArrayIntNull::value_type ArrayIntNull::get(const char* header, size_t ndx) noexcept
+{
+    int64_t null_value = Array::get(header, 0);
+    int64_t value = Array::get(header, ndx + 1);
+    if (value == null_value) {
+        return util::none;
+    }
+    else {
+        return util::some<int64_t>(value);
+    }
+}
+
+inline bool ArrayIntNull::is_null(size_t ndx) const noexcept
+{
+    return !get(ndx);
+}
+
+inline int64_t ArrayIntNull::null_value() const noexcept
+{
+    return Array::get(0);
+}
+
+inline ArrayIntNull::value_type ArrayIntNull::operator[](size_t ndx) const noexcept
+{
+    return get(ndx);
+}
+
+inline ArrayIntNull::value_type ArrayIntNull::front() const noexcept
+{
+    return get(0);
+}
+
+inline ArrayIntNull::value_type ArrayIntNull::back() const noexcept
+{
+    return Array::back();
+}
+
+inline void ArrayIntNull::erase(size_t ndx)
+{
+    Array::erase(ndx + 1);
+}
+
+inline void ArrayIntNull::erase(size_t begin, size_t end)
+{
+    Array::erase(begin + 1, end + 1);
+}
+
+inline void ArrayIntNull::truncate(size_t to_size)
+{
+    Array::truncate(to_size + 1);
+}
+
+inline void ArrayIntNull::clear()
+{
+    truncate(0);
+}
+
+inline void ArrayIntNull::set_all_to_zero()
+{
+    // FIXME: Array::set_all_to_zero does something else
+    for (size_t i = 0; i < size(); ++i) {
+        set(i, 0);
+    }
+}
+
+inline void ArrayIntNull::move(size_t begin, size_t end, size_t dest_begin)
+{
+    Array::move(begin + 1, end + 1, dest_begin + 1);
+}
+
+inline void ArrayIntNull::move_backward(size_t begin, size_t end, size_t dest_end)
+{
+    Array::move_backward(begin + 1, end + 1, dest_end + 1);
+}
+
+inline size_t ArrayIntNull::lower_bound(int64_t value) const noexcept
+{
+    // FIXME: Consider this behaviour with NULLs.
+    // Array::lower_bound_int assumes an already sorted array, but
+    // this array could be sorted with nulls first or last.
+    return Array::lower_bound_int(value);
+}
+
+inline size_t ArrayIntNull::upper_bound(int64_t value) const noexcept
+{
+    // FIXME: see lower_bound
+    return Array::upper_bound_int(value);
+}
+
+inline int64_t ArrayIntNull::sum(size_t start, size_t end) const
+{
+    // FIXME: Optimize
+    int64_t sum_of_range = 0;
+    if (end == npos)
+        end = size();
+    for (size_t i = start; i < end; ++i) {
+        value_type x = get(i);
+        if (x) {
+            sum_of_range += *x;
+        }
+    }
+    return sum_of_range;
+}
+
+inline size_t ArrayIntNull::count(int64_t value) const noexcept
+{
+    size_t count_of_value = Array::count(value);
+    if (value == null_value()) {
+        --count_of_value;
+    }
+    return count_of_value;
+}
+
+// FIXME: Optimize
+template <bool find_max>
+inline bool ArrayIntNull::minmax_helper(int64_t& result, size_t start, size_t end, size_t* return_ndx) const
+{
+    size_t best_index = 1;
+
+    if (end == npos) {
+        end = m_size;
+    }
+
+    ++start;
+
+    REALM_ASSERT(start < m_size && end <= m_size && start < end);
+
+    if (m_size == 1) {
+        // empty array
+        return false;
+    }
+
+    if (m_width == 0) {
+        if (return_ndx)
+            *return_ndx = best_index - 1;
+        result = 0;
+        return true;
+    }
+
+    int64_t m = Array::get(start);
+
+    const int64_t null_val = null_value();
+    for (; start < end; ++start) {
+        const int64_t v = Array::get(start);
+        if (find_max ? v > m : v < m) {
+            if (v == null_val) {
+                continue;
+            }
+            m = v;
+            best_index = start;
+        }
+    }
+
+    result = m;
+    if (return_ndx) {
+        *return_ndx = best_index - 1;
+    }
+    return true;
+}
+
+inline bool ArrayIntNull::maximum(int64_t& result, size_t start, size_t end, size_t* return_ndx) const
+{
+    return minmax_helper<true>(result, start, end, return_ndx);
+}
+
+inline bool ArrayIntNull::minimum(int64_t& result, size_t start, size_t end, size_t* return_ndx) const
+{
+    return minmax_helper<false>(result, start, end, return_ndx);
+}
+
+inline bool ArrayIntNull::find(int cond, Action action, value_type value, size_t start, size_t end, size_t baseindex,
+                               QueryState<int64_t>* state) const
+{
+    if (value) {
+        return Array::find(cond, action, *value, start, end, baseindex, state, true /*treat as nullable array*/,
+                           false /*search parameter given in 'value' argument*/);
+    }
+    else {
+        return Array::find(cond, action, 0 /* unused dummy*/, start, end, baseindex, state,
+                           true /*treat as nullable array*/, true /*search for null, ignore value argument*/);
+    }
+}
+
+template <class cond, Action action, size_t bitwidth, class Callback>
+bool ArrayIntNull::find(value_type value, size_t start, size_t end, size_t baseindex, QueryState<int64_t>* state,
+                        Callback callback) const
+{
+    if (value) {
+        return Array::find<cond, action>(*value, start, end, baseindex, state, std::forward<Callback>(callback),
+                                         true /*treat as nullable array*/,
+                                         false /*search parameter given in 'value' argument*/);
+    }
+    else {
+        return Array::find<cond, action>(0 /*ignored*/, start, end, baseindex, state,
+                                         std::forward<Callback>(callback), true /*treat as nullable array*/,
+                                         true /*search for null, ignore value argument*/);
+    }
+}
+
+
+template <class cond, Action action, size_t bitwidth>
+bool ArrayIntNull::find(int64_t value, size_t start, size_t end, size_t baseindex, QueryState<int64_t>* state) const
+{
+    return Array::find<cond, action>(value, start, end, baseindex, state, true /*treat as nullable array*/,
+                                     false /*search parameter given in 'value' argument*/);
+}
+
+
+template <class cond, Action action, class Callback>
+bool ArrayIntNull::find(value_type value, size_t start, size_t end, size_t baseindex, QueryState<int64_t>* state,
+                        Callback callback) const
+{
+    if (value) {
+        return Array::find<cond, action>(*value, start, end, baseindex, state, std::forward<Callback>(callback),
+                                         true /*treat as nullable array*/,
+                                         false /*search parameter given in 'value' argument*/);
+    }
+    else {
+        return Array::find<cond, action>(0 /*ignored*/, start, end, baseindex, state,
+                                         std::forward<Callback>(callback), true /*treat as nullable array*/,
+                                         true /*search for null, ignore value argument*/);
+    }
+}
+
+
+template <Action action, class Callback>
+bool ArrayIntNull::find_action(size_t index, value_type value, QueryState<int64_t>* state, Callback callback) const
+{
+    if (value) {
+        return Array::find_action<action, Callback>(index, *value, state, callback, true /*treat as nullable array*/,
+                                                    false /*search parameter given in 'value' argument*/);
+    }
+    else {
+        return Array::find_action<action, Callback>(index, 0 /* ignored */, state, callback,
+                                                    true /*treat as nullable array*/,
+                                                    true /*search for null, ignore value argument*/);
+    }
+}
+
+
+template <Action action, class Callback>
+bool ArrayIntNull::find_action_pattern(size_t index, uint64_t pattern, QueryState<int64_t>* state,
+                                       Callback callback) const
+{
+    return Array::find_action_pattern<action, Callback>(index, pattern, state, callback,
+                                                        true /*treat as nullable array*/,
+                                                        false /*search parameter given in 'value' argument*/);
+}
+
+
+template <class cond>
+size_t ArrayIntNull::find_first(value_type value, size_t start, size_t end) const
+{
+    QueryState<int64_t> state;
+    state.init(act_ReturnFirst, nullptr, 1);
+    if (value) {
+        Array::find<cond, act_ReturnFirst>(*value, start, end, 0, &state, Array::CallbackDummy(),
+                                           true /*treat as nullable array*/,
+                                           false /*search parameter given in 'value' argument*/);
+    }
+    else {
+        Array::find<cond, act_ReturnFirst>(0 /*ignored*/, start, end, 0, &state, Array::CallbackDummy(),
+                                           true /*treat as nullable array*/,
+                                           true /*search for null, ignore value argument*/);
+    }
+
+    if (state.m_match_count > 0)
+        return to_size_t(state.m_state);
+    else
+        return not_found;
+}
+
+inline size_t ArrayIntNull::find_first(value_type value, size_t begin, size_t end) const
+{
+    return find_first<Equal>(value, begin, end);
+}
+}
+
+#endif // REALM_ARRAY_INTEGER_HPP