added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / core / realm / link_view.hpp
diff --git a/iOS/Pods/Realm/include/core/realm/link_view.hpp b/iOS/Pods/Realm/include/core/realm/link_view.hpp
new file mode 100644 (file)
index 0000000..14be525
--- /dev/null
@@ -0,0 +1,397 @@
+/*************************************************************************
+ *
+ * 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_LINK_VIEW_HPP
+#define REALM_LINK_VIEW_HPP
+
+#include <realm/column.hpp>
+#include <realm/column_linklist.hpp>
+#include <realm/link_view_fwd.hpp>
+#include <realm/table.hpp>
+
+namespace realm {
+
+class LinkListColumn;
+
+namespace _impl {
+class LinkListFriend;
+class TransactLogConvenientEncoder;
+}
+
+
+/// The effect of calling most of the link list functions on a detached accessor
+/// is unspecified and may lead to general corruption, or even a crash. The
+/// exceptions are is_attached() and the destructor.
+///
+/// FIXME: Rename this class to `LinkList`.
+class LinkView : public RowIndexes, public std::enable_shared_from_this<LinkView> {
+public:
+    ~LinkView() noexcept;
+    bool is_attached() const noexcept;
+
+    /// This method will return true if the LinkView is detached (no assert).
+    bool is_empty() const noexcept;
+
+    /// This method will return 0 if the LinkView is detached (no assert).
+    size_t size() const noexcept override;
+
+    bool operator==(const LinkView&) const noexcept;
+    bool operator!=(const LinkView&) const noexcept;
+
+    // Getting links
+    Table::ConstRowExpr operator[](size_t link_ndx) const noexcept;
+    Table::RowExpr operator[](size_t link_ndx) noexcept;
+    Table::ConstRowExpr get(size_t link_ndx) const noexcept;
+    Table::RowExpr get(size_t link_ndx) noexcept;
+
+    // Modifiers
+    void add(size_t target_row_ndx);
+    void insert(size_t link_ndx, size_t target_row_ndx);
+    void set(size_t link_ndx, size_t target_row_ndx);
+    /// Move the link at \a from_ndx such that it ends up at \a to_ndx. Other
+    /// links are shifted as necessary in such a way that their order is
+    /// preserved.
+    ///
+    /// Note that \a to_ndx is the desired final index of the moved link,
+    /// therefore, `move(1,1)` is a no-op, while `move(1,2)` moves the link at
+    /// index 1 by one position, such that it ends up at index 2. A side-effect
+    /// of that, is that the link, that was originally at index 2, is moved to
+    /// index 1.
+    void move(size_t from_ndx, size_t to_ndx);
+    void swap(size_t link1_ndx, size_t link2_ndx);
+    void remove(size_t link_ndx);
+    void clear();
+
+    void sort(size_t column, bool ascending = true);
+    void sort(SortDescriptor&& order);
+
+    TableView get_sorted_view(size_t column_index, bool ascending = true) const;
+    TableView get_sorted_view(SortDescriptor order) const;
+
+    /// Remove the target row of the specified link from the target table. This
+    /// also removes the specified link from this link list, and any other link
+    /// pointing to that row. This is merely a shorthand for
+    /// `get_target_table.move_last_over(get(link_ndx))`.
+    void remove_target_row(size_t link_ndx);
+
+    /// Remove all target rows pointed to by links in this link list, and clear
+    /// this link list.
+    void remove_all_target_rows();
+
+    /// Search this list for a link to the specified target table row (specified
+    /// by its index in the target table). If found, the index of the link to
+    /// that row within this list is returned, otherwise `realm::not_found` is
+    /// returned.
+    size_t find(size_t target_row_ndx, size_t start = 0) const noexcept;
+
+    const ColumnBase& get_column_base(size_t index)
+        const override; // FIXME: `ColumnBase` is not part of the public API, so this function must be made private.
+    const Table& get_origin_table() const noexcept;
+    Table& get_origin_table() noexcept;
+
+    size_t get_origin_row_index() const noexcept;
+
+    const Table& get_target_table() const noexcept;
+    Table& get_target_table() noexcept;
+
+    // No-op because LinkViews are always kept in sync.
+    uint_fast64_t sync_if_needed() const override;
+    bool is_in_sync() const override
+    {
+        return true;
+    }
+
+private:
+    struct ctor_cookie {
+    };
+
+    TableRef m_origin_table;
+    LinkListColumn* m_origin_column;
+
+    using HandoverPatch = LinkViewHandoverPatch;
+    static void generate_patch(const ConstLinkViewRef& ref, std::unique_ptr<HandoverPatch>& patch);
+    static LinkViewRef create_from_and_consume_patch(std::unique_ptr<HandoverPatch>& patch, Group& group);
+
+    void detach();
+    void set_origin_row_index(size_t row_ndx) noexcept;
+
+    void do_insert(size_t link_ndx, size_t target_row_ndx);
+    size_t do_set(size_t link_ndx, size_t target_row_ndx);
+    size_t do_remove(size_t link_ndx);
+    void do_clear(bool broken_reciprocal_backlinks);
+
+    void do_nullify_link(size_t old_target_row_ndx);
+    void do_update_link(size_t old_target_row_ndx, size_t new_target_row_ndx);
+    void do_swap_link(size_t target_row_ndx_1, size_t target_row_ndx_2);
+
+    void refresh_accessor_tree(size_t new_row_ndx) noexcept;
+
+    void update_from_parent(size_t old_baseline) noexcept;
+
+    Replication* get_repl() noexcept;
+    void repl_unselect() noexcept;
+    friend class _impl::TransactLogConvenientEncoder;
+
+#ifdef REALM_DEBUG
+    void verify(size_t row_ndx) const;
+#endif
+    // allocate using make_shared:
+    static std::shared_ptr<LinkView> create(Table* origin_table, LinkListColumn&, size_t row_ndx);
+    static std::shared_ptr<LinkView> create_detached();
+
+    friend class _impl::LinkListFriend;
+    friend class LinkListColumn;
+    friend class LangBindHelper;
+    friend class SharedGroup;
+    friend class Query;
+    friend class TableViewBase;
+
+    // must be public for use by make_shared, but cannot be called from outside,
+    // because ctor_cookie is private
+public:
+    LinkView(const ctor_cookie&, Table* origin_table, LinkListColumn&, size_t row_ndx);
+    LinkView(const ctor_cookie&);
+};
+
+
+// Implementation
+
+inline LinkView::LinkView(const ctor_cookie&, Table* origin_table, LinkListColumn& column, size_t row_ndx)
+    : RowIndexes(IntegerColumn::unattached_root_tag(), column.get_alloc()) // Throws
+    , m_origin_table(origin_table->get_table_ref())
+    , m_origin_column(&column)
+{
+    m_row_indexes.set_parent(m_origin_column, row_ndx);
+    m_row_indexes.init_from_parent();
+}
+
+// create a detached LinkView. Only partially initialized, as it will never be used for
+// anything, but indicating that it is detached.
+inline LinkView::LinkView(const ctor_cookie&)
+    : RowIndexes(IntegerColumn::unattached_root_tag(), Allocator::get_default()) // Throws
+    , m_origin_table(TableRef())
+    , m_origin_column(nullptr)
+{
+}
+
+inline std::shared_ptr<LinkView> LinkView::create(Table* origin_table, LinkListColumn& column, size_t row_ndx)
+{
+    return std::make_shared<LinkView>(ctor_cookie(), origin_table, column, row_ndx);
+}
+
+inline std::shared_ptr<LinkView> LinkView::create_detached()
+{
+    return std::make_shared<LinkView>(ctor_cookie());
+}
+
+inline LinkView::~LinkView() noexcept
+{
+    if (is_attached()) {
+        repl_unselect();
+        m_origin_column->unregister_linkview();
+    }
+}
+
+inline void LinkView::detach()
+{
+    REALM_ASSERT(is_attached());
+    repl_unselect();
+    m_origin_table.reset();
+    m_row_indexes.detach();
+}
+
+inline bool LinkView::is_attached() const noexcept
+{
+    return static_cast<bool>(m_origin_table);
+}
+
+inline bool LinkView::is_empty() const noexcept
+{
+    if (!is_attached())
+        return true;
+
+    if (!m_row_indexes.is_attached())
+        return true;
+
+    return m_row_indexes.is_empty();
+}
+
+inline size_t LinkView::size() const noexcept
+{
+    if (!is_attached())
+        return 0;
+
+    if (!m_row_indexes.is_attached())
+        return 0;
+
+    return m_row_indexes.size();
+}
+
+inline bool LinkView::operator==(const LinkView& link_list) const noexcept
+{
+    Table& target_table_1 = m_origin_column->get_target_table();
+    Table& target_table_2 = link_list.m_origin_column->get_target_table();
+    if (target_table_1.get_index_in_group() != target_table_2.get_index_in_group())
+        return false;
+    if (!m_row_indexes.is_attached() || m_row_indexes.is_empty()) {
+        return !link_list.m_row_indexes.is_attached() || link_list.m_row_indexes.is_empty();
+    }
+    return link_list.m_row_indexes.is_attached() && m_row_indexes.compare(link_list.m_row_indexes);
+}
+
+inline bool LinkView::operator!=(const LinkView& link_list) const noexcept
+{
+    return !(*this == link_list);
+}
+
+inline Table::ConstRowExpr LinkView::get(size_t link_ndx) const noexcept
+{
+    return const_cast<LinkView*>(this)->get(link_ndx);
+}
+
+inline Table::RowExpr LinkView::get(size_t link_ndx) noexcept
+{
+    REALM_ASSERT(is_attached());
+    REALM_ASSERT(m_row_indexes.is_attached());
+    REALM_ASSERT_3(link_ndx, <, m_row_indexes.size());
+
+    Table& target_table = m_origin_column->get_target_table();
+    size_t target_row_ndx = to_size_t(m_row_indexes.get(link_ndx));
+    return target_table[target_row_ndx];
+}
+
+inline Table::ConstRowExpr LinkView::operator[](size_t link_ndx) const noexcept
+{
+    return get(link_ndx);
+}
+
+inline Table::RowExpr LinkView::operator[](size_t link_ndx) noexcept
+{
+    return get(link_ndx);
+}
+
+inline void LinkView::add(size_t target_row_ndx)
+{
+    REALM_ASSERT(is_attached());
+    size_t ins_pos = (m_row_indexes.is_attached()) ? m_row_indexes.size() : 0;
+    insert(ins_pos, target_row_ndx);
+}
+
+inline size_t LinkView::find(size_t target_row_ndx, size_t start) const noexcept
+{
+    REALM_ASSERT(is_attached());
+    REALM_ASSERT_3(target_row_ndx, <, m_origin_column->get_target_table().size());
+    REALM_ASSERT_3(start, <=, size());
+
+    if (!m_row_indexes.is_attached())
+        return not_found;
+
+    return m_row_indexes.find_first(target_row_ndx, start);
+}
+
+inline const ColumnBase& LinkView::get_column_base(size_t index) const
+{
+    return get_target_table().get_column_base(index);
+}
+
+inline const Table& LinkView::get_origin_table() const noexcept
+{
+    return *m_origin_table;
+}
+
+inline Table& LinkView::get_origin_table() noexcept
+{
+    return *m_origin_table;
+}
+
+inline size_t LinkView::get_origin_row_index() const noexcept
+{
+    REALM_ASSERT(is_attached());
+    return m_row_indexes.get_root_array()->get_ndx_in_parent();
+}
+
+inline void LinkView::set_origin_row_index(size_t row_ndx) noexcept
+{
+    REALM_ASSERT(is_attached());
+    m_row_indexes.get_root_array()->set_ndx_in_parent(row_ndx);
+}
+
+inline const Table& LinkView::get_target_table() const noexcept
+{
+    return m_origin_column->get_target_table();
+}
+
+inline Table& LinkView::get_target_table() noexcept
+{
+    return m_origin_column->get_target_table();
+}
+
+inline void LinkView::refresh_accessor_tree(size_t new_row_ndx) noexcept
+{
+    set_origin_row_index(new_row_ndx);
+    m_row_indexes.init_from_parent();
+}
+
+inline void LinkView::update_from_parent(size_t old_baseline) noexcept
+{
+    if (m_row_indexes.is_attached())
+        m_row_indexes.update_from_parent(old_baseline);
+}
+
+inline Replication* LinkView::get_repl() noexcept
+{
+    typedef _impl::TableFriend tf;
+    return tf::get_repl(*m_origin_table);
+}
+
+
+// The purpose of this class is to give internal access to some, but not all of
+// the non-public parts of LinkView.
+class _impl::LinkListFriend {
+public:
+    static void do_set(LinkView& list, size_t link_ndx, size_t target_row_ndx)
+    {
+        list.do_set(link_ndx, target_row_ndx);
+    }
+
+    static void do_remove(LinkView& list, size_t link_ndx)
+    {
+        list.do_remove(link_ndx);
+    }
+
+    static void do_clear(LinkView& list)
+    {
+        bool broken_reciprocal_backlinks = false;
+        list.do_clear(broken_reciprocal_backlinks);
+    }
+
+    static void do_insert(LinkView& list, size_t link_ndx, size_t target_row_ndx)
+    {
+        list.do_insert(link_ndx, target_row_ndx);
+    }
+
+    static const LinkListColumn& get_origin_column(const LinkView& list)
+    {
+        REALM_ASSERT(list.is_attached());
+        return *list.m_origin_column;
+    }
+};
+
+} // namespace realm
+
+#endif // REALM_LINK_VIEW_HPP