qTox  Version: nightly | Commit: bc751c8e1cac455f9690654fcfe0f560d2d7dfdd
chatlinestorage.cpp
Go to the documentation of this file.
1 /*
2  Copyright © 2020-2021 by The qTox Project Contributors
3 
4  This file is part of qTox, a Qt-based graphical interface for Tox.
5 
6  qTox is libre software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  qTox is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with qTox. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "chatlinestorage.h"
21 
22 #include <QDebug>
23 
25 {
26  if (idxInfoMap.find(idx) != idxInfoMap.end()) {
27  qWarning() << "Index is already rendered, not updating";
28  return lines.end();
29  }
30 
31  auto linePosIncrementIt = infoIteratorForIdx(idx);
32 
33  auto insertionPoint = equivalentLineIterator(linePosIncrementIt);
34  insertionPoint = adjustItForDate(insertionPoint, timestamp);
35 
36  insertionPoint = lines.insert(insertionPoint, line);
37 
38  // All indexes after the insertion have to be incremented by one
39  incrementLinePosAfter(linePosIncrementIt);
40 
41  // Newly inserted index is insertinPoint - start
42  IdxInfo info;
43  info.linePos = std::distance(lines.begin(), insertionPoint);
44  info.timestamp = timestamp;
45  idxInfoMap[idx] = info;
46 
47  return insertionPoint;
48 }
49 
51 {
52  // Assume we only need to render one date line per date. I.e. this does
53  // not handle the case of
54  // * Message inserted Jan 3
55  // * Message inserted Jan 4
56  // * Message inserted Jan 3
57  // In this case the second "Jan 3" message will appear to have been sent
58  // on Jan 4
59  // As of right now this should not be a problem since all items should
60  // be sent/received in order. If we ever implement sender timestamps and
61  // the sender screws us by changing their time we may need to revisit this
62  auto idxMapIt = std::find_if(idxInfoMap.begin(), idxInfoMap.end(), [&] (const IdxInfoMap_t::value_type& v) {
63  return timestamp <= v.second.timestamp;
64  });
65 
66  auto insertionPoint = equivalentLineIterator(idxMapIt);
67  insertionPoint = adjustItForDate(insertionPoint, timestamp);
68 
69  insertionPoint = lines.insert(insertionPoint, line);
70 
71  // All indexes after the insertion have to be incremented by one
72  incrementLinePosAfter(idxMapIt);
73 
74  dateMap[line] = timestamp;
75 
76  return insertionPoint;
77 }
78 
79 bool ChatLineStorage::contains(QDateTime timestamp) const
80 {
81  auto it = std::find_if(dateMap.begin(), dateMap.end(), [&] (DateLineMap_t::value_type v) {
82  return v.second == timestamp;
83  });
84 
85  return it != dateMap.end();
86 }
87 
89 {
90  auto infoIt = infoIteratorForIdx(idx);
91  if (infoIt == idxInfoMap.end()) {
92  return lines.end();
93  }
94 
95  return lines.begin() + infoIt->second.linePos;
96 
97 }
98 
100 {
101  return std::find(lines.begin(), lines.end(), line);
102 }
103 
105 {
106  auto linePosDecrementIt = infoIteratorForIdx(idx);
107  auto lineIt = equivalentLineIterator(linePosDecrementIt);
108 
109  erase(lineIt);
110 }
111 
113 {
114  iterator prevIt = it;
115 
116  do {
117  it = prevIt;
118 
119  auto infoIterator = equivalentInfoIterator(it);
120  auto dateMapIt = dateMap.find(*it);
121 
122  if (dateMapIt != dateMap.end()) {
123  dateMap.erase(dateMapIt);
124  }
125 
126  if (infoIterator != idxInfoMap.end()) {
127  infoIterator = idxInfoMap.erase(infoIterator);
128  decrementLinePosAfter(infoIterator);
129  }
130 
131  it = lines.erase(it);
132 
133  if (it > lines.begin()) {
134  prevIt = std::prev(it);
135  } else {
136  prevIt = lines.end();
137  }
138  } while (shouldRemovePreviousLine(prevIt, it));
139 
140  return it;
141 }
142 
144 {
145  if (it == idxInfoMap.end()) {
146  return lines.end();
147  }
148 
149  return std::next(lines.begin(), it->second.linePos);
150 }
151 
152 ChatLineStorage::IdxInfoMap_t::iterator ChatLineStorage::equivalentInfoIterator(iterator it)
153 {
154  auto idx = static_cast<size_t>(std::distance(lines.begin(), it));
155  auto equivalentIt = std::find_if(idxInfoMap.begin(), idxInfoMap.end(), [&](const IdxInfoMap_t::value_type& v) {
156  return v.second.linePos >= idx;
157  });
158 
159  return equivalentIt;
160 }
161 
162 ChatLineStorage::IdxInfoMap_t::iterator ChatLineStorage::infoIteratorForIdx(ChatLogIdx idx)
163 {
164  // If lower_bound proves to be expensive for appending we can try
165  // special casing when idx > idxToLineMap.rbegin()->first
166 
167  // If we find an exact match we return that index, otherwise we return
168  // the first item after it. It's up to the caller to check if there's an
169  // exact match first
170  auto it = std::lower_bound(idxInfoMap.begin(), idxInfoMap.end(), idx, [](const IdxInfoMap_t::value_type& v, ChatLogIdx idx) {
171  return v.first < idx;
172  });
173 
174  return it;
175 }
176 
178 {
179  // Continuously move back until either
180  // 1. The dateline found is earlier than our timestamp
181  // 2. There are no more datelines
182  while (it > lines.begin()) {
183  auto possibleDateIt = it - 1;
184  auto dateIt = dateMap.find(*possibleDateIt);
185  if (dateIt == dateMap.end()) {
186  break;
187  }
188 
189  if (dateIt->second > timestamp) {
190  it = possibleDateIt;
191  } else {
192  break;
193  }
194  }
195 
196  return it;
197 }
198 
199 void ChatLineStorage::incrementLinePosAfter(IdxInfoMap_t::iterator inputIt)
200 {
201  for (auto it = inputIt; it != idxInfoMap.end(); ++it) {
202  it->second.linePos++;
203  }
204 }
205 
206 void ChatLineStorage::decrementLinePosAfter(IdxInfoMap_t::iterator inputIt)
207 {
208  // All indexes after the insertion have to be incremented by one
209  for (auto it = inputIt; it != idxInfoMap.end(); ++it) {
210  it->second.linePos--;
211  }
212 }
213 
215 {
216  return prevIt != lines.end() && // Previous iterator is valid
217  dateMap.find(*prevIt) != dateMap.end() && // Previous iterator is a date line
218  (
219  it == lines.end() || // Previous iterator is the last line
220  dateMap.find(*it) != dateMap.end() // Adjacent date lines
221  );
222 }
ChatLineStorage::adjustItForDate
iterator adjustItForDate(iterator it, QDateTime timestamp)
Definition: chatlinestorage.cpp:177
ChatLineStorage::decrementLinePosAfter
void decrementLinePosAfter(IdxInfoMap_t::iterator it)
Definition: chatlinestorage.cpp:206
chatlinestorage.h
ChatLineStorage::IdxInfo
Definition: chatlinestorage.h:56
ChatLineStorage::insertChatMessage
iterator insertChatMessage(ChatLogIdx idx, QDateTime timestamp, ChatLine::Ptr line)
Definition: chatlinestorage.cpp:24
ChatLineStorage::insertDateLine
iterator insertDateLine(QDateTime timestamp, ChatLine::Ptr line)
Definition: chatlinestorage.cpp:50
ChatLineStorage::shouldRemovePreviousLine
bool shouldRemovePreviousLine(iterator prevIt, iterator it)
Definition: chatlinestorage.cpp:214
ChatLineStorage::find
iterator find(ChatLogIdx idx)
Definition: chatlinestorage.cpp:88
ChatLineStorage::equivalentLineIterator
iterator equivalentLineIterator(IdxInfoMap_t::iterator it)
Definition: chatlinestorage.cpp:143
ChatLineStorage::IdxInfo::timestamp
QDateTime timestamp
Definition: chatlinestorage.h:59
ChatLineStorage::lines
std::vector< ChatLine::Ptr > lines
Definition: chatlinestorage.h:128
ChatLineStorage::erase
void erase(ChatLogIdx idx)
Definition: chatlinestorage.cpp:104
ChatLineStorage::idxInfoMap
IdxInfoMap_t idxInfoMap
Definition: chatlinestorage.h:130
ChatLogIdx
NamedType< size_t, struct ChatLogIdxTag, Orderable, UnderlyingAddable, UnitlessDifferencable, Incrementable > ChatLogIdx
Definition: ichatlog.h:38
ChatLineStorage::infoIteratorForIdx
IdxInfoMap_t::iterator infoIteratorForIdx(ChatLogIdx idx)
Definition: chatlinestorage.cpp:162
ChatLineStorage::dateMap
std::map< ChatLine::Ptr, QDateTime > dateMap
Definition: chatlinestorage.h:129
ChatLineStorage::incrementLinePosAfter
void incrementLinePosAfter(IdxInfoMap_t::iterator it)
Definition: chatlinestorage.cpp:199
ChatLineStorage::contains
bool contains(ChatLogIdx idx) const
Definition: chatlinestorage.h:82
ChatLineStorage::IdxInfo::linePos
size_t linePos
Definition: chatlinestorage.h:58
ChatLineStorage::iterator
Lines_t::iterator iterator
Definition: chatlinestorage.h:71
ChatLine::Ptr
std::shared_ptr< ChatLine > Ptr
Definition: chatline.h:68
ChatLineStorage::equivalentInfoIterator
IdxInfoMap_t::iterator equivalentInfoIterator(iterator it)
Definition: chatlinestorage.cpp:152