history_types.cc revision dc0f95d653279beabeb9817299e2902918ba123e
1// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/history/history_types.h"
6
7#include <limits>
8
9#include "base/logging.h"
10#include "base/stl_util-inl.h"
11
12namespace history {
13
14// URLRow ----------------------------------------------------------------------
15
16URLRow::URLRow() {
17  Initialize();
18}
19
20URLRow::URLRow(const GURL& url) : url_(url) {
21  // Initialize will not set the URL, so our initialization above will stay.
22  Initialize();
23}
24
25URLRow::URLRow(const GURL& url, URLID id) : url_(url) {
26  // Initialize will not set the URL, so our initialization above will stay.
27  Initialize();
28  // Initialize will zero the id_, so set it here.
29  id_ = id;
30}
31
32URLRow::~URLRow() {
33}
34
35URLRow& URLRow::operator=(const URLRow& other) {
36  id_ = other.id_;
37  url_ = other.url_;
38  title_ = other.title_;
39  visit_count_ = other.visit_count_;
40  typed_count_ = other.typed_count_;
41  last_visit_ = other.last_visit_;
42  hidden_ = other.hidden_;
43  favicon_id_ = other.favicon_id_;
44  return *this;
45}
46
47void URLRow::Swap(URLRow* other) {
48  std::swap(id_, other->id_);
49  url_.Swap(&other->url_);
50  title_.swap(other->title_);
51  std::swap(visit_count_, other->visit_count_);
52  std::swap(typed_count_, other->typed_count_);
53  std::swap(last_visit_, other->last_visit_);
54  std::swap(hidden_, other->hidden_);
55  std::swap(favicon_id_, other->favicon_id_);
56}
57
58void URLRow::Initialize() {
59  id_ = 0;
60  visit_count_ = 0;
61  typed_count_ = 0;
62  last_visit_ = base::Time();
63  hidden_ = false;
64  favicon_id_ = 0;
65}
66
67// VisitRow --------------------------------------------------------------------
68
69VisitRow::VisitRow()
70    : visit_id(0),
71      url_id(0),
72      referring_visit(0),
73      transition(PageTransition::LINK),
74      segment_id(0),
75      is_indexed(false) {
76}
77
78VisitRow::VisitRow(URLID arg_url_id,
79                   base::Time arg_visit_time,
80                   VisitID arg_referring_visit,
81                   PageTransition::Type arg_transition,
82                   SegmentID arg_segment_id)
83    : visit_id(0),
84      url_id(arg_url_id),
85      visit_time(arg_visit_time),
86      referring_visit(arg_referring_visit),
87      transition(arg_transition),
88      segment_id(arg_segment_id),
89      is_indexed(false) {
90}
91
92VisitRow::~VisitRow() {
93}
94
95// Favicons -------------------------------------------------------------------
96
97ImportedFavIconUsage::ImportedFavIconUsage() {
98}
99
100ImportedFavIconUsage::~ImportedFavIconUsage() {
101}
102
103// StarredEntry ----------------------------------------------------------------
104
105StarredEntry::StarredEntry()
106    : id(0),
107      parent_group_id(0),
108      group_id(0),
109      visual_order(0),
110      type(URL),
111      url_id(0) {
112}
113
114StarredEntry::~StarredEntry() {
115}
116
117void StarredEntry::Swap(StarredEntry* other) {
118  std::swap(id, other->id);
119  title.swap(other->title);
120  std::swap(date_added, other->date_added);
121  std::swap(parent_group_id, other->parent_group_id);
122  std::swap(group_id, other->group_id);
123  std::swap(visual_order, other->visual_order);
124  std::swap(type, other->type);
125  url.Swap(&other->url);
126  std::swap(url_id, other->url_id);
127  std::swap(date_group_modified, other->date_group_modified);
128}
129
130// URLResult -------------------------------------------------------------------
131
132URLResult::URLResult() {
133}
134
135URLResult::URLResult(const GURL& url, base::Time visit_time)
136    : URLRow(url),
137      visit_time_(visit_time) {
138}
139
140URLResult::URLResult(const GURL& url,
141                     const Snippet::MatchPositions& title_matches)
142    : URLRow(url) {
143  title_match_positions_ = title_matches;
144}
145
146URLResult::~URLResult() {
147}
148
149void URLResult::SwapResult(URLResult* other) {
150  URLRow::Swap(other);
151  std::swap(visit_time_, other->visit_time_);
152  snippet_.Swap(&other->snippet_);
153  title_match_positions_.swap(other->title_match_positions_);
154}
155
156// QueryResults ----------------------------------------------------------------
157
158QueryResults::QueryResults() : reached_beginning_(false) {
159}
160
161QueryResults::~QueryResults() {
162  // Free all the URL objects.
163  STLDeleteContainerPointers(results_.begin(), results_.end());
164}
165
166const size_t* QueryResults::MatchesForURL(const GURL& url,
167                                          size_t* num_matches) const {
168  URLToResultIndices::const_iterator found = url_to_results_.find(url);
169  if (found == url_to_results_.end()) {
170    if (num_matches)
171      *num_matches = 0;
172    return NULL;
173  }
174
175  // All entries in the map should have at least one index, otherwise it
176  // shouldn't be in the map.
177  DCHECK(!found->second->empty());
178  if (num_matches)
179    *num_matches = found->second->size();
180  return &found->second->front();
181}
182
183void QueryResults::Swap(QueryResults* other) {
184  std::swap(first_time_searched_, other->first_time_searched_);
185  std::swap(reached_beginning_, other->reached_beginning_);
186  results_.swap(other->results_);
187  url_to_results_.swap(other->url_to_results_);
188}
189
190void QueryResults::AppendURLBySwapping(URLResult* result) {
191  URLResult* new_result = new URLResult;
192  new_result->SwapResult(result);
193
194  results_.push_back(new_result);
195  AddURLUsageAtIndex(new_result->url(), results_.size() - 1);
196}
197
198void QueryResults::AppendResultsBySwapping(QueryResults* other,
199                                           bool remove_dupes) {
200  if (remove_dupes) {
201    // Delete all entries in the other array that are already in this one.
202    for (size_t i = 0; i < results_.size(); i++)
203      other->DeleteURL(results_[i]->url());
204  }
205
206  if (first_time_searched_ > other->first_time_searched_)
207    std::swap(first_time_searched_, other->first_time_searched_);
208
209  if (reached_beginning_ != other->reached_beginning_)
210    std::swap(reached_beginning_, other->reached_beginning_);
211
212  for (size_t i = 0; i < other->results_.size(); i++) {
213    // Just transfer pointer ownership.
214    results_.push_back(other->results_[i]);
215    AddURLUsageAtIndex(results_.back()->url(), results_.size() - 1);
216  }
217
218  // We just took ownership of all the results in the input vector.
219  other->results_.clear();
220  other->url_to_results_.clear();
221}
222
223void QueryResults::DeleteURL(const GURL& url) {
224  // Delete all instances of this URL. We re-query each time since each
225  // mutation will cause the indices to change.
226  while (const size_t* match_indices = MatchesForURL(url, NULL))
227    DeleteRange(*match_indices, *match_indices);
228}
229
230void QueryResults::DeleteRange(size_t begin, size_t end) {
231  DCHECK(begin <= end && begin < size() && end < size());
232
233  // First delete the pointers in the given range and store all the URLs that
234  // were modified. We will delete references to these later.
235  std::set<GURL> urls_modified;
236  for (size_t i = begin; i <= end; i++) {
237    urls_modified.insert(results_[i]->url());
238    delete results_[i];
239    results_[i] = NULL;
240  }
241
242  // Now just delete that range in the vector en masse (the STL ending is
243  // exclusive, while ours is inclusive, hence the +1).
244  results_.erase(results_.begin() + begin, results_.begin() + end + 1);
245
246  // Delete the indicies referencing the deleted entries.
247  for (std::set<GURL>::const_iterator url = urls_modified.begin();
248       url != urls_modified.end(); ++url) {
249    URLToResultIndices::iterator found = url_to_results_.find(*url);
250    if (found == url_to_results_.end()) {
251      NOTREACHED();
252      continue;
253    }
254
255    // Need a signed loop type since we do -- which may take us to -1.
256    for (int match = 0; match < static_cast<int>(found->second->size());
257         match++) {
258      if (found->second[match] >= begin && found->second[match] <= end) {
259        // Remove this referece from the list.
260        found->second->erase(found->second->begin() + match);
261        match--;
262      }
263    }
264
265    // Clear out an empty lists if we just made one.
266    if (found->second->empty())
267      url_to_results_.erase(found);
268  }
269
270  // Shift all other indices over to account for the removed ones.
271  AdjustResultMap(end + 1, std::numeric_limits<size_t>::max(),
272                  -static_cast<ptrdiff_t>(end - begin + 1));
273}
274
275void QueryResults::AddURLUsageAtIndex(const GURL& url, size_t index) {
276  URLToResultIndices::iterator found = url_to_results_.find(url);
277  if (found != url_to_results_.end()) {
278    // The URL is already in the list, so we can just append the new index.
279    found->second->push_back(index);
280    return;
281  }
282
283  // Need to add a new entry for this URL.
284  StackVector<size_t, 4> new_list;
285  new_list->push_back(index);
286  url_to_results_[url] = new_list;
287}
288
289void QueryResults::AdjustResultMap(size_t begin, size_t end, ptrdiff_t delta) {
290  for (URLToResultIndices::iterator i = url_to_results_.begin();
291       i != url_to_results_.end(); ++i) {
292    for (size_t match = 0; match < i->second->size(); match++) {
293      size_t match_index = i->second[match];
294      if (match_index >= begin && match_index <= end)
295        i->second[match] += delta;
296    }
297  }
298}
299
300// QueryOptions ----------------------------------------------------------------
301
302QueryOptions::QueryOptions() : max_count(0) {}
303
304void QueryOptions::SetRecentDayRange(int days_ago) {
305  end_time = base::Time::Now();
306  begin_time = end_time - base::TimeDelta::FromDays(days_ago);
307}
308
309// KeywordSearchTermVisit -----------------------------------------------------
310
311KeywordSearchTermVisit::KeywordSearchTermVisit() {}
312
313KeywordSearchTermVisit::~KeywordSearchTermVisit() {}
314
315// KeywordSearchTermRow --------------------------------------------------------
316
317KeywordSearchTermRow::KeywordSearchTermRow() : keyword_id(0), url_id(0) {}
318
319KeywordSearchTermRow::~KeywordSearchTermRow() {}
320
321// MostVisitedURL --------------------------------------------------------------
322
323MostVisitedURL::MostVisitedURL() {}
324
325MostVisitedURL::MostVisitedURL(const GURL& in_url,
326                               const GURL& in_favicon_url,
327                               const string16& in_title)
328    : url(in_url),
329      favicon_url(in_favicon_url),
330      title(in_title) {
331}
332
333MostVisitedURL::~MostVisitedURL() {}
334
335// Images ---------------------------------------------------------------------
336
337Images::Images() {}
338
339Images::~Images() {}
340
341// TopSitesDelta --------------------------------------------------------------
342
343TopSitesDelta::TopSitesDelta() {}
344
345TopSitesDelta::~TopSitesDelta() {}
346
347// HistoryAddPageArgs ---------------------------------------------------------
348
349HistoryAddPageArgs::HistoryAddPageArgs(
350    const GURL& arg_url,
351    base::Time arg_time,
352    const void* arg_id_scope,
353    int32 arg_page_id,
354    const GURL& arg_referrer,
355    const history::RedirectList& arg_redirects,
356    PageTransition::Type arg_transition,
357    VisitSource arg_source,
358    bool arg_did_replace_entry)
359      : url(arg_url),
360        time(arg_time),
361        id_scope(arg_id_scope),
362        page_id(arg_page_id),
363        referrer(arg_referrer),
364        redirects(arg_redirects),
365        transition(arg_transition),
366        visit_source(arg_source),
367        did_replace_entry(arg_did_replace_entry) {
368}
369
370HistoryAddPageArgs::~HistoryAddPageArgs() {}
371
372HistoryAddPageArgs* HistoryAddPageArgs::Clone() const {
373  return new HistoryAddPageArgs(
374      url, time, id_scope, page_id, referrer, redirects, transition,
375      visit_source, did_replace_entry);
376}
377
378ThumbnailMigration::ThumbnailMigration() {}
379
380ThumbnailMigration::~ThumbnailMigration() {}
381
382MostVisitedThumbnails::MostVisitedThumbnails() {}
383
384MostVisitedThumbnails::~MostVisitedThumbnails() {}
385
386// Autocomplete thresholds -----------------------------------------------------
387
388const int kLowQualityMatchTypedLimit = 1;
389const int kLowQualityMatchVisitLimit = 3;
390const int kLowQualityMatchAgeLimitInDays = 3;
391
392base::Time AutocompleteAgeThreshold() {
393  return (base::Time::Now() -
394          base::TimeDelta::FromDays(kLowQualityMatchAgeLimitInDays));
395}
396
397bool RowQualifiesAsSignificant(const URLRow& row,
398                               const base::Time& threshold) {
399  const base::Time& real_threshold =
400      threshold.is_null() ? AutocompleteAgeThreshold() : threshold;
401  return (row.typed_count() > kLowQualityMatchTypedLimit) ||
402         (row.visit_count() > kLowQualityMatchVisitLimit) ||
403         (row.last_visit() >= real_threshold);
404}
405
406}  // namespace history
407