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