Skip to content

Commit

Permalink
Add CollectionList class
Browse files Browse the repository at this point in the history
  • Loading branch information
jedelbo committed Mar 30, 2023
1 parent da67c04 commit 720e62d
Show file tree
Hide file tree
Showing 12 changed files with 551 additions and 29 deletions.
1 change: 1 addition & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ let notSyncServerSources: [String] = [
"realm/cluster.cpp",
"realm/cluster_tree.cpp",
"realm/collection.cpp",
"realm/collection_list.cpp",
"realm/collection_parent.cpp",
"realm/column_binary.cpp",
"realm/db.cpp",
Expand Down
1 change: 1 addition & 0 deletions src/realm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <realm/list.hpp>
#include <realm/set.hpp>
#include <realm/dictionary.hpp>
#include <realm/collection_list.hpp>
#include <realm/table_view.hpp>
#include <realm/query.hpp>
#include <realm/query_engine.hpp>
Expand Down
2 changes: 2 additions & 0 deletions src/realm/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ set(REALM_SOURCES
chunked_binary.cpp
cluster.cpp
collection.cpp
collection_list.cpp
collection_parent.cpp
cluster_tree.cpp
error_codes.cpp
Expand Down Expand Up @@ -139,6 +140,7 @@ set(REALM_INSTALL_HEADERS
cluster.hpp
cluster_tree.hpp
collection.hpp
collection_list.hpp
collection_parent.hpp
column_binary.hpp
column_fwd.hpp
Expand Down
1 change: 1 addition & 0 deletions src/realm/alloc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ class Allocator {
friend class Obj;
template <class, class>
friend class CollectionBaseImpl;
friend class CollectionList;
friend class Dictionary;
};

Expand Down
9 changes: 7 additions & 2 deletions src/realm/collection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
#include <realm/bplustree.hpp>
#include <realm/array_key.hpp>

namespace realm::_impl {
namespace realm {

namespace _impl {
size_t virtual2real(const std::vector<size_t>& vec, size_t ndx) noexcept
{
for (auto i : vec) {
Expand Down Expand Up @@ -86,4 +87,8 @@ void check_for_last_unresolved(BPlusTree<ObjKey>* tree)
}
}

} // namespace realm::_impl
} // namespace _impl

Collection::~Collection() {}

} // namespace realm
27 changes: 15 additions & 12 deletions src/realm/collection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,29 @@ namespace realm {
template <class L>
struct CollectionIterator;

class Collection {
public:
virtual ~Collection();
/// The size of the collection.
virtual size_t size() const = 0;
/// True if `size()` returns 0.
bool is_empty() const
{
return size() == 0;
}
};

using CollectionPtr = std::shared_ptr<Collection>;

/// Base class for all collection accessors.
///
/// Collections are bound to particular properties of an object. In a
/// collection's public interface, the implementation must take care to keep the
/// object consistent with the persisted state, mindful of the fact that the
/// state may have changed as a consquence of modifications from other instances
/// referencing the same persisted state.
class CollectionBase {
class CollectionBase : public Collection {
public:
virtual ~CollectionBase() {}

/// The size of the collection.
virtual size_t size() const = 0;

/// True if the element at @a ndx is NULL.
virtual bool is_null(size_t ndx) const = 0;

Expand Down Expand Up @@ -70,12 +79,6 @@ class CollectionBase {
// Return index of the first occurrence of 'value'
virtual size_t find_any(Mixed value) const = 0;

/// True if `size()` returns 0.
virtual bool is_empty() const final
{
return size() == 0;
}

/// Get the object that owns this collection.
virtual const Obj& get_obj() const noexcept = 0;

Expand Down
266 changes: 266 additions & 0 deletions src/realm/collection_list.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
/*************************************************************************
*
* Copyright 2023 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.
*
**************************************************************************/

#include <realm/collection_list.hpp>
#include <realm/obj.hpp>
#include <realm/table.hpp>
#include "realm/array_string.hpp"
#include "realm/array_integer.hpp"

namespace realm {

/****************************** CollectionList *******************************/

CollectionList::CollectionList(std::shared_ptr<CollectionParent> parent, ColKey col_key, Index index,
CollectionType coll_type)
: m_parent(parent)
, m_index(index)
, m_level(parent->get_level() + 1)
, m_alloc(&m_parent->get_object().get_alloc())
, m_col_key(col_key)
, m_top(*m_alloc)
, m_refs(*m_alloc)
, m_key_type(coll_type == CollectionType::List ? type_Int : type_String)
{
m_top.set_parent(this, 0);
m_refs.set_parent(&m_top, 1);
}

CollectionList::~CollectionList() {}

bool CollectionList::init_from_parent(bool allow_create) const
{
auto ref = m_parent->get_collection_ref(m_index);
if ((ref || allow_create) && !m_keys) {
switch (m_key_type) {
case type_String: {
m_keys.reset(new BPlusTree<StringData>(*m_alloc));
break;
}
case type_Int: {
m_keys.reset(new BPlusTree<Int>(*m_alloc));
break;
}
default:
break;
}
m_keys->set_parent(&m_top, 0);
}
if (ref) {
m_top.init_from_ref(ref);
m_keys->init_from_parent();
m_refs.init_from_parent();
// All is well
return true;
}

if (!allow_create) {
m_top.detach();
return false;
}

m_top.create(Array::type_HasRefs, false, 2, 0);
m_keys->create();
m_refs.create();
m_top.update_parent();

return true;
}

UpdateStatus CollectionList::update_if_needed_with_status() const
{
auto status = m_parent->update_if_needed_with_status();
switch (status) {
case UpdateStatus::Detached: {
m_top.detach();
return UpdateStatus::Detached;
}
case UpdateStatus::NoChange:
if (m_top.is_attached()) {
auto content_version = m_alloc->get_content_version();
if (content_version == m_content_version) {
return UpdateStatus::NoChange;
}
m_content_version = content_version;
}
// The tree has not been initialized yet for this accessor, so
// perform lazy initialization by treating it as an update.
[[fallthrough]];
case UpdateStatus::Updated: {
bool attached = init_from_parent(false);
return attached ? UpdateStatus::Updated : UpdateStatus::Detached;
}
}
REALM_UNREACHABLE();
}


ref_type CollectionList::get_child_ref(size_t) const noexcept
{
return m_parent->get_collection_ref(m_col_key);
}

void CollectionList::update_child_ref(size_t, ref_type ref)
{
m_parent->set_collection_ref(m_index, ref);
}

CollectionBasePtr CollectionList::insert_collection(size_t ndx)
{
REALM_ASSERT(get_table()->get_nesting_levels(m_col_key) == m_level);
ensure_created();
REALM_ASSERT(m_key_type == type_Int);
auto int_keys = static_cast<BPlusTree<Int>*>(m_keys.get());
int64_t key = 0;
if (auto max = bptree_maximum(*int_keys, nullptr)) {
key = *max + 1;
}
int_keys->insert(ndx, key);
m_refs.insert(ndx, 0);
CollectionBasePtr coll = CollectionParent::get_collection_ptr(m_col_key);
coll->set_owner(shared_from_this(), key);
return coll;
}

CollectionBasePtr CollectionList::insert_collection(StringData key)
{
REALM_ASSERT(get_table()->get_nesting_levels(m_col_key) == m_level);
ensure_created();
REALM_ASSERT(m_key_type == type_String);
auto string_keys = static_cast<BPlusTree<String>*>(m_keys.get());
StringData actual;
IteratorAdapter help(string_keys);
auto it = std::lower_bound(help.begin(), help.end(), key);
if (it.index() < string_keys->size()) {
actual = *it;
}
if (actual != key) {
string_keys->insert(it.index(), key);
m_refs.insert(it.index(), 0);
}
CollectionBasePtr coll = CollectionParent::get_collection_ptr(m_col_key);
coll->set_owner(shared_from_this(), key);

return coll;
}

CollectionBasePtr CollectionList::get_collection(size_t ndx) const
{
REALM_ASSERT(get_table()->get_nesting_levels(m_col_key) == m_level);
CollectionBasePtr coll = CollectionParent::get_collection_ptr(m_col_key);
Index index;
auto sz = size();
if (ndx >= sz) {
throw OutOfBounds("CollectionList::get_collection_ptr()", ndx, sz);
}
if (m_key_type == type_Int) {
auto int_keys = static_cast<BPlusTree<Int>*>(m_keys.get());
index = int_keys->get(ndx);
}
else {
auto string_keys = static_cast<BPlusTree<String>*>(m_keys.get());
index = std::string(string_keys->get(ndx));
}
coll->set_owner(const_cast<CollectionList*>(this)->shared_from_this(), index);
return coll;
}

CollectionListPtr CollectionList::insert_collection_list(size_t ndx)
{
ensure_created();
REALM_ASSERT(m_key_type == type_Int);
auto int_keys = static_cast<BPlusTree<Int>*>(m_keys.get());
int64_t key = 0;
if (auto max = bptree_maximum(*int_keys, nullptr)) {
key = *max + 1;
}
int_keys->insert(ndx, key);
m_refs.insert(ndx, 0);

return get_collection_list(ndx);
}

CollectionListPtr CollectionList::insert_collection_list(StringData key)
{
ensure_created();
REALM_ASSERT(m_key_type == type_String);
auto string_keys = static_cast<BPlusTree<String>*>(m_keys.get());
StringData actual;
IteratorAdapter help(string_keys);
auto it = std::lower_bound(help.begin(), help.end(), key);
if (it.index() < string_keys->size()) {
actual = *it;
}
if (actual != key) {
string_keys->insert(it.index(), key);
m_refs.insert(it.index(), 0);
}
return get_collection_list(it.index());
}

CollectionListPtr CollectionList::get_collection_list(size_t ndx) const
{
REALM_ASSERT(get_table()->get_nesting_levels(m_col_key) > m_level);
Index index;
auto sz = size();
if (ndx >= sz) {
throw OutOfBounds("CollectionList::get_collection_ptr()", ndx, sz);
}
if (m_key_type == type_Int) {
auto int_keys = static_cast<BPlusTree<Int>*>(m_keys.get());
index = int_keys->get(ndx);
}
else {
auto string_keys = static_cast<BPlusTree<String>*>(m_keys.get());
index = std::string(string_keys->get(ndx));
}
auto coll_type = get_table()->get_nested_column_type(m_col_key, m_level);
return CollectionList::create(const_cast<CollectionList*>(this)->shared_from_this(), m_col_key, index, coll_type);
}

ref_type CollectionList::get_collection_ref(Index index) const noexcept
{
size_t ndx;
if (m_key_type == type_Int) {
auto int_keys = static_cast<BPlusTree<Int>*>(m_keys.get());
ndx = int_keys->find_first(mpark::get<int64_t>(index));
}
else {
auto string_keys = static_cast<BPlusTree<String>*>(m_keys.get());
ndx = string_keys->find_first(StringData(mpark::get<std::string>(index)));
}
return ndx == realm::not_found ? 0 : m_refs.get(ndx);
}

void CollectionList::set_collection_ref(Index index, ref_type ref)
{
if (m_key_type == type_Int) {
auto int_keys = static_cast<BPlusTree<Int>*>(m_keys.get());
auto ndx = int_keys->find_first(mpark::get<int64_t>(index));
REALM_ASSERT(ndx != realm::not_found);
return m_refs.set(ndx, ref);
}
else {
auto string_keys = static_cast<BPlusTree<String>*>(m_keys.get());
auto ndx = string_keys->find_first(StringData(mpark::get<std::string>(index)));
REALM_ASSERT(ndx != realm::not_found);
return m_refs.set(ndx, ref);
}
}

} // namespace realm
Loading

0 comments on commit 720e62d

Please sign in to comment.