summaryrefslogtreecommitdiffstats
path: root/sync/syncable/parent_child_index.cc
blob: 71fb92e41117b35c18863c73eeabe82e9aa16daf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// 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