Skip to content

Commit

Permalink
Make Obj trivial and add a separate ObjCollectionParent type
Browse files Browse the repository at this point in the history
  • Loading branch information
tgoyne committed Mar 1, 2024
1 parent ef979fe commit cb6fbc9
Show file tree
Hide file tree
Showing 11 changed files with 268 additions and 267 deletions.
8 changes: 4 additions & 4 deletions src/realm/collection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -577,7 +577,7 @@ class CollectionBaseImpl : public Interface, protected ArrayParent {
using Interface::get_target_table;

protected:
Obj m_obj_mem;
ObjCollectionParent m_obj_mem;
std::shared_ptr<CollectionParent> m_col_parent;
CollectionParent::Index m_index;
mutable size_t m_my_version = 0;
Expand Down Expand Up @@ -735,19 +735,19 @@ class CollectionBaseImpl : public Interface, protected ArrayParent {
void set_backlink(ColKey col_key, ObjLink new_link) const
{
check_parent();
m_parent->set_backlink(col_key, new_link);
m_parent->set_backlink(m_parent->get_object(), col_key, new_link);
}
// Used when replacing a link, return true if CascadeState contains objects to remove
bool replace_backlink(ColKey col_key, ObjLink old_link, ObjLink new_link, CascadeState& state) const
{
check_parent();
return m_parent->replace_backlink(col_key, old_link, new_link, state);
return m_parent->replace_backlink(m_parent->get_object(), col_key, old_link, new_link, state);
}
// Used when removing a backlink, return true if CascadeState contains objects to remove
bool remove_backlink(ColKey col_key, ObjLink old_link, CascadeState& state) const
{
check_parent();
return m_parent->remove_backlink(col_key, old_link, state);
return m_parent->remove_backlink(m_parent->get_object(), col_key, old_link, state);
}

/// Reset the accessor's tracking of the content version. Derived classes
Expand Down
282 changes: 110 additions & 172 deletions src/realm/collection_parent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,7 @@ bool StablePath::is_prefix_of(const StablePath& other) const noexcept
{
if (size() > other.size())
return false;

auto it = other.begin();
for (auto& p : *this) {
if (!(p == *it))
return false;
++it;
}
return true;
return std::equal(other.begin(), other.end(), begin());
}

/***************************** CollectionParent ******************************/
Expand All @@ -86,212 +79,157 @@ void CollectionParent::check_level() const
throw LogicError(ErrorCodes::LimitExceeded, "Max nesting level reached");
}
}
void CollectionParent::set_backlink(ColKey col_key, ObjLink new_link) const
void CollectionParent::set_backlink(const Obj& obj, ColKey col_key, ObjLink new_link)
{
if (new_link && new_link.get_obj_key()) {
auto t = get_table();
auto target_table = t->get_parent_group()->get_table(new_link.get_table_key());
ColKey backlink_col_key;
auto type = col_key.get_type();
if (type == col_type_TypedLink || type == col_type_Mixed || col_key.is_dictionary()) {
// This may modify the target table
backlink_col_key = target_table->find_or_add_backlink_column(col_key, t->get_key());
// it is possible that this was a link to the same table and that adding a backlink column has
// caused the need to update this object as well.
update_if_needed();
}
else {
backlink_col_key = t->get_opposite_column(col_key);
}
auto obj_key = new_link.get_obj_key();
auto target_obj = obj_key.is_unresolved() ? target_table->try_get_tombstone(obj_key)
: target_table->try_get_object(obj_key);
if (!target_obj) {
throw InvalidArgument(ErrorCodes::KeyNotFound, "Target object not found");
}
target_obj.add_backlink(backlink_col_key, get_object().get_key());
if (!new_link) {
return;
}

auto t = obj.get_table();
auto target_table = t->get_parent_group()->get_table(new_link.get_table_key());
ColKey backlink_col_key;
auto type = col_key.get_type();
if (type == col_type_TypedLink || type == col_type_Mixed || col_key.is_dictionary()) {
// This may modify the target table
backlink_col_key = target_table->find_or_add_backlink_column(col_key, t->get_key());
// it is possible that this was a link to the same table and that adding a backlink column has
// caused the need to update this object as well.
obj.update_if_needed();
}
else {
backlink_col_key = t->get_opposite_column(col_key);
}
auto obj_key = new_link.get_obj_key();
auto target_obj =
obj_key.is_unresolved() ? target_table->try_get_tombstone(obj_key) : target_table->try_get_object(obj_key);
if (!target_obj) {
throw InvalidArgument(ErrorCodes::KeyNotFound, "Target object not found");
}
target_obj.add_backlink(backlink_col_key, obj.get_key());
}

bool CollectionParent::replace_backlink(ColKey col_key, ObjLink old_link, ObjLink new_link, CascadeState& state) const
bool CollectionParent::replace_backlink(const Obj& obj, ColKey col_key, ObjLink old_link, ObjLink new_link,
CascadeState& state)
{
bool recurse = remove_backlink(col_key, old_link, state);
set_backlink(col_key, new_link);

bool recurse = remove_backlink(obj, col_key, old_link, state);
set_backlink(obj, col_key, new_link);
return recurse;
}

bool CollectionParent::remove_backlink(ColKey col_key, ObjLink old_link, CascadeState& state) const
bool CollectionParent::remove_backlink(const Obj& obj, ColKey col_key, ObjLink old_link, CascadeState& state)
{
if (old_link && old_link.get_obj_key()) {
auto t = get_table();
REALM_ASSERT(t->valid_column(col_key));
ObjKey old_key = old_link.get_obj_key();
auto target_obj = t->get_parent_group()->get_object(old_link);
TableRef target_table = target_obj.get_table();
ColKey backlink_col_key;
auto type = col_key.get_type();
if (type == col_type_TypedLink || type == col_type_Mixed || col_key.is_dictionary()) {
backlink_col_key = target_table->find_or_add_backlink_column(col_key, t->get_key());
}
else {
backlink_col_key = t->get_opposite_column(col_key);
}
if (!old_link) {
return false;
}

bool strong_links = target_table->is_embedded();
bool is_unres = old_key.is_unresolved();
auto t = obj.get_table();
REALM_ASSERT(t->valid_column(col_key));
ObjKey old_key = old_link.get_obj_key();
auto target_obj = t->get_parent_group()->get_object(old_link);
TableRef target_table = target_obj.get_table();
ColKey backlink_col_key;
auto type = col_key.get_type();
if (type == col_type_TypedLink || type == col_type_Mixed || col_key.is_dictionary()) {
backlink_col_key = target_table->find_or_add_backlink_column(col_key, t->get_key());
}
else {
backlink_col_key = t->get_opposite_column(col_key);
}

bool last_removed = target_obj.remove_one_backlink(backlink_col_key, get_object().get_key()); // Throws
if (is_unres) {
if (last_removed) {
// Check is there are more backlinks
if (!target_obj.has_backlinks(false)) {
// Tombstones can be erased right away - there is no cascading effect
target_table->m_tombstones->erase(old_key, state);
}
bool strong_links = target_table->is_embedded();
bool is_unres = old_key.is_unresolved();

bool last_removed = target_obj.remove_one_backlink(backlink_col_key, obj.get_key()); // Throws
if (is_unres) {
if (last_removed) {
// Check is there are more backlinks
if (!target_obj.has_backlinks(false)) {
// Tombstones can be erased right away - there is no cascading effect
target_table->m_tombstones->erase(old_key, state);
}
}
else {
return state.enqueue_for_cascade(target_obj, strong_links, last_removed);
}
}
else {
return state.enqueue_for_cascade(target_obj, strong_links, last_removed);
}

return false;
}

LstBasePtr CollectionParent::get_listbase_ptr(ColKey col_key) const
template <typename Base, template <typename> typename Collection, typename LinkCol>
std::unique_ptr<Base> create_collection(ColKey col_key, size_t level)
{
auto table = get_table();
auto attr = table->get_column_attr(col_key);
REALM_ASSERT(attr.test(col_attr_List) || attr.test(col_attr_Nullable));
bool nullable = attr.test(col_attr_Nullable);

switch (table->get_column_type(col_key)) {
case type_Int: {
bool nullable = col_key.get_attrs().test(col_attr_Nullable);
switch (col_key.get_type()) {
case col_type_Int:
if (nullable)
return std::make_unique<Lst<util::Optional<Int>>>(col_key);
else
return std::make_unique<Lst<Int>>(col_key);
}
case type_Bool: {
return std::make_unique<Collection<util::Optional<Int>>>(col_key);
return std::make_unique<Collection<Int>>(col_key);
case col_type_Bool:
if (nullable)
return std::make_unique<Lst<util::Optional<Bool>>>(col_key);
else
return std::make_unique<Lst<Bool>>(col_key);
}
case type_Float: {
return std::make_unique<Collection<util::Optional<Bool>>>(col_key);
return std::make_unique<Collection<Bool>>(col_key);
case col_type_Float:
if (nullable)
return std::make_unique<Lst<util::Optional<Float>>>(col_key);
else
return std::make_unique<Lst<Float>>(col_key);
}
case type_Double: {
return std::make_unique<Collection<util::Optional<Float>>>(col_key);
return std::make_unique<Collection<Float>>(col_key);
case col_type_Double:
if (nullable)
return std::make_unique<Lst<util::Optional<Double>>>(col_key);
else
return std::make_unique<Lst<Double>>(col_key);
}
case type_String: {
return std::make_unique<Lst<String>>(col_key);
}
case type_Binary: {
return std::make_unique<Lst<Binary>>(col_key);
}
case type_Timestamp: {
return std::make_unique<Lst<Timestamp>>(col_key);
}
case type_Decimal: {
return std::make_unique<Lst<Decimal128>>(col_key);
}
case type_ObjectId: {
return std::make_unique<Collection<util::Optional<Double>>>(col_key);
return std::make_unique<Collection<Double>>(col_key);
case col_type_String:
return std::make_unique<Collection<String>>(col_key);
case col_type_Binary:
return std::make_unique<Collection<Binary>>(col_key);
case col_type_Timestamp:
return std::make_unique<Collection<Timestamp>>(col_key);
case col_type_Decimal:
return std::make_unique<Collection<Decimal128>>(col_key);
case col_type_ObjectId:
if (nullable)
return std::make_unique<Lst<util::Optional<ObjectId>>>(col_key);
else
return std::make_unique<Lst<ObjectId>>(col_key);
}
case type_UUID: {
return std::make_unique<Collection<util::Optional<ObjectId>>>(col_key);
return std::make_unique<Collection<ObjectId>>(col_key);
case col_type_UUID:
if (nullable)
return std::make_unique<Lst<util::Optional<UUID>>>(col_key);
else
return std::make_unique<Lst<UUID>>(col_key);
}
case type_TypedLink: {
return std::make_unique<Lst<ObjLink>>(col_key);
}
case type_Mixed: {
return std::make_unique<Lst<Mixed>>(col_key, get_level() + 1);
}
case type_Link:
return std::make_unique<LnkLst>(col_key);
return std::make_unique<Collection<util::Optional<UUID>>>(col_key);
return std::make_unique<Collection<UUID>>(col_key);
case col_type_TypedLink:
return std::make_unique<Collection<ObjLink>>(col_key);
case col_type_Mixed:
return std::make_unique<Collection<Mixed>>(col_key, level + 1);
case col_type_Link:
return std::make_unique<LinkCol>(col_key);
default:
REALM_TERMINATE("Unsupported column type.");
}
REALM_TERMINATE("Unsupported column type");
}

SetBasePtr CollectionParent::get_setbase_ptr(ColKey col_key) const
LstBasePtr CollectionParent::get_listbase_ptr(ColKey col_key, size_t level)
{
auto table = get_table();
auto attr = table->get_column_attr(col_key);
REALM_ASSERT(attr.test(col_attr_Set));
bool nullable = attr.test(col_attr_Nullable);
REALM_ASSERT(col_key.get_attrs().test(col_attr_List) || col_key.get_type() == col_type_Mixed);
return create_collection<LstBase, Lst, LnkLst>(col_key, level);
}

switch (table->get_column_type(col_key)) {
case type_Int:
if (nullable)
return std::make_unique<Set<util::Optional<Int>>>(col_key);
return std::make_unique<Set<Int>>(col_key);
case type_Bool:
if (nullable)
return std::make_unique<Set<util::Optional<Bool>>>(col_key);
return std::make_unique<Set<Bool>>(col_key);
case type_Float:
if (nullable)
return std::make_unique<Set<util::Optional<Float>>>(col_key);
return std::make_unique<Set<Float>>(col_key);
case type_Double:
if (nullable)
return std::make_unique<Set<util::Optional<Double>>>(col_key);
return std::make_unique<Set<Double>>(col_key);
case type_String:
return std::make_unique<Set<String>>(col_key);
case type_Binary:
return std::make_unique<Set<Binary>>(col_key);
case type_Timestamp:
return std::make_unique<Set<Timestamp>>(col_key);
case type_Decimal:
return std::make_unique<Set<Decimal128>>(col_key);
case type_ObjectId:
if (nullable)
return std::make_unique<Set<util::Optional<ObjectId>>>(col_key);
return std::make_unique<Set<ObjectId>>(col_key);
case type_UUID:
if (nullable)
return std::make_unique<Set<util::Optional<UUID>>>(col_key);
return std::make_unique<Set<UUID>>(col_key);
case type_TypedLink:
return std::make_unique<Set<ObjLink>>(col_key);
case type_Mixed:
return std::make_unique<Set<Mixed>>(col_key);
case type_Link:
return std::make_unique<LnkSet>(col_key);
}
REALM_TERMINATE("Unsupported column type.");
SetBasePtr CollectionParent::get_setbase_ptr(ColKey col_key, size_t level)
{
REALM_ASSERT(col_key.get_attrs().test(col_attr_Set));
return create_collection<SetBase, Set, LnkSet>(col_key, level);
}

CollectionBasePtr CollectionParent::get_collection_ptr(ColKey col_key) const
CollectionBasePtr CollectionParent::get_collection_ptr(ColKey col_key, size_t level)
{
if (col_key.is_list()) {
return get_listbase_ptr(col_key);
return get_listbase_ptr(col_key, level);
}
else if (col_key.is_set()) {
return get_setbase_ptr(col_key);
return get_setbase_ptr(col_key, level);
}
else if (col_key.is_dictionary()) {
return std::make_unique<Dictionary>(col_key, get_level() + 1);
return std::make_unique<Dictionary>(col_key, level + 1);
}
return {};
}


int64_t CollectionParent::generate_key(size_t sz)
{
static std::mt19937 gen32;
Expand Down
Loading

0 comments on commit cb6fbc9

Please sign in to comment.