// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "sync/syncable/parent_child_index.h" #include "base/stl_util.h" #include "sync/syncable/entry_kernel.h" #include "sync/syncable/syncable_id.h" namespace syncer { namespace syncable { bool ChildComparator::operator()( const syncable::EntryKernel* a, const syncable::EntryKernel* b) const { const UniquePosition& a_pos = a->ref(UNIQUE_POSITION); const UniquePosition& b_pos = b->ref(UNIQUE_POSITION); if (a_pos.IsValid() && b_pos.IsValid()) { // Position is important to this type. return a_pos.LessThan(b_pos); } else if (a_pos.IsValid() && !b_pos.IsValid()) { // TODO(rlarocque): Remove this case. // An item with valid position as sibling of one with invalid position. // We should not support this, but the tests rely on it. For now, just // move all invalid position items to the right. return true; } else if (!a_pos.IsValid() && b_pos.IsValid()) { // TODO(rlarocque): Remove this case. // Mirror of the above case. return false; } else { // Position doesn't matter. DCHECK(!a->ref(UNIQUE_POSITION).IsValid()); DCHECK(!b->ref(UNIQUE_POSITION).IsValid()); return a->ref(ID) < b->ref(ID); } } ParentChildIndex::ParentChildIndex() { } ParentChildIndex::~ParentChildIndex() { STLDeleteContainerPairSecondPointers( parent_children_map_.begin(), parent_children_map_.end()); } bool ParentChildIndex::ShouldInclude(const EntryKernel* entry) { // This index excludes deleted items and the root item. The root // item is excluded so that it doesn't show up as a child of itself. return !entry->ref(IS_DEL) && !entry->ref(ID).IsRoot(); } bool ParentChildIndex::Insert(EntryKernel* entry) { DCHECK(ShouldInclude(entry)); const syncable::Id& parent_id = entry->ref(PARENT_ID); OrderedChildSet* children = NULL; ParentChildrenMap::iterator i = parent_children_map_.find(parent_id); if (i != parent_children_map_.end()) { children = i->second; } else { children = new OrderedChildSet(); parent_children_map_.insert(std::make_pair(parent_id, children)); } return children->insert(entry).second; } // Like the other containers used to help support the syncable::Directory, this // one does not own any EntryKernels. This function removes references to the // given EntryKernel but does not delete it. void ParentChildIndex::Remove(EntryKernel* e) { ParentChildrenMap::iterator parent = parent_children_map_.find(e->ref(PARENT_ID)); DCHECK(parent != parent_children_map_.end()); OrderedChildSet* children = parent->second; OrderedChildSet::iterator j = children->find(e); DCHECK(j != children->end()); children->erase(j); if (children->empty()) { delete children; parent_children_map_.erase(parent); } } bool ParentChildIndex::Contains(EntryKernel *e) const { const syncable::Id& parent_id = e->ref(PARENT_ID); ParentChildrenMap::const_iterator parent = parent_children_map_.find(parent_id); if (parent == parent_children_map_.end()) { return false; } const OrderedChildSet* children = parent->second; DCHECK(children && !children->empty()); return children->count(e) > 0; } const OrderedChildSet* ParentChildIndex::GetChildren(const syncable::Id& id) { ParentChildrenMap::iterator parent = parent_children_map_.find(id); if (parent == parent_children_map_.end()) { return NULL; } // A successful lookup implies at least some children exist. DCHECK(!parent->second->empty()); return parent->second; } } // namespace syncable } // namespace syncer