GCC Code Coverage Report


source/XpertMassCore/src/
File: source/XpertMassCore/src/Sequence.cpp
Date: 2025-11-20 01:41:33
Lines:
372/492
75.6%
Functions:
42/48
87.5%
Branches:
325/792
41.0%

Line Branch Exec Source
1 /* BEGIN software license
2 *
3 * MsXpertSuite - mass spectrometry software suite
4 * -----------------------------------------------
5 * Copyright(C) 2009, ..., 2018 Filippo Rusconi
6 *
7 * http://www.msxpertsuite.org
8 *
9 * This file is part of the MsXpertSuite project.
10 *
11 * The MsXpertSuite project is the successor of the massXpert project. This
12 * project now includes various independent modules:
13 *
14 * - massXpert, model polymer chemistries and simulate mass spectrometric data;
15 * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner;
16 *
17 * This program is free software: you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation, either version 3 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29 *
30 * END software license
31 */
32
33
34 ////////////////////////////// Stdlib includes
35
36
37 /////////////////////// Qt includes
38 #include <QByteArrayView>
39 #include <QUuid>
40
41
42 /////////////////////// Local includes
43 #include "MsXpS/libXpertMassCore/Sequence.hpp"
44 #include "MsXpS/libXpertMassCore/PolChemDef.hpp"
45 #include "MsXpS/libXpertMassCore/IndexRangeCollection.hpp"
46
47 namespace MsXpS
48 {
49 namespace libXpertMassCore
50 {
51
52
53 /*!
54
55 \class MsXpS::libXpertMassCore::Sequence
56 \inmodule libXpertMassCore
57 \ingroup PolChemDefBuildingdBlocks
58 \inheaderfile Sequence.hpp
59
60 \brief The Sequence class provides abstractions to work with
61 a simple sequence of \l{Monomer}s.
62
63 A sequence of monomer is a vector of fully qualified \l{Monomer} instances
64 allocated on the heap.
65 */
66
67
68 /*!
69 \variable MsXpS::libXpertMassCore::Sequence::mcsp_polChemDef
70
71 \brief The \l PolChemDef polymer chemistry definition that is the context in
72 which the Sequence exists.
73 */
74
75 /*!
76 \variable MsXpS::libXpertMassCore::Sequence::m_monomers
77
78 \brief Vector of allocated \l Monomer instances.
79 */
80
81 /*!
82 \variable MsXpS::libXpertMassCore::Sequence::m_isValid
83
84 \brief The validity status of this Sequence instance.
85 */
86
87
88 /*!
89 \brief Constructs a totally empty Sequence as an invalid object.
90 */
91 5 Sequence::Sequence()
92 {
93 5 }
94
95 /*!
96 \brief Constructs a Sequence in the context of the \a
97 pol_chem_def_csp polymer chemistry definition using the \a sequence_text
98 representation of a Monomer sequence.
99
100 The \a sequence_text is a concatenation of monomer codes. That text sequence is
101 immediately converted into Monomer instances using \a pol_chem_def_csp as the
102 reference PolChemDef. The Monomer instances (actually newly allocated Monomer
103 shared pointers) are stored in the member container keeping the order of the
104 Monomer codes in \a sequence_text.
105
106 If all the Monomer codes in the \a sequence_text were correct, the status of the
107 Sequence is set to valid, otherwise it is set to invalid (query with
108 isValid()).
109
110 \sa makeMonomers()
111 */
112 180 Sequence::Sequence(PolChemDefCstSPtr pol_chem_def_csp,
113 180 const QString &sequence_text)
114
1/2
✓ Branch 2 taken 180 times.
✗ Branch 3 not taken.
180 : mcsp_polChemDef(pol_chem_def_csp)
115 {
116 // qDebug() << "The sequence_text:" << sequence_text;
117
118 180 std::vector<std::size_t> failing_indices;
119
120
1/2
✓ Branch 1 taken 180 times.
✗ Branch 2 not taken.
180 makeMonomers(sequence_text, /*reset*/ true, failing_indices);
121
122
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 177 times.
180 if(failing_indices.size())
123 {
124 3 QString indices_text;
125
126
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 for(std::size_t index : failing_indices)
127
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
6 indices_text += QString("%1, ").arg(index);
128
129
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 qCritical()
130
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 << "There were errors making the monomers at the following indices:"
131
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 << indices_text;
132 3 }
133 else
134 177 m_isValid = true;
135
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
180 }
136
137 /*!
138 \brief Constructs this Sequence instance as a copy of \a other.
139
140 The copying is deep with the Monomer instances in the member container being
141 reinstantiated into this Sequence.
142 */
143 15 Sequence::Sequence(const Sequence &other)
144 {
145 15 mcsp_polChemDef = other.mcsp_polChemDef;
146
147
2/2
✓ Branch 0 taken 1779 times.
✓ Branch 1 taken 15 times.
1794 for(const MonomerSPtr &monomer_sp : other.m_monomers)
148
1/2
✓ Branch 1 taken 1779 times.
✗ Branch 2 not taken.
3558 storeMonomer(monomer_sp);
149
150 // qDebug() << "The number of Monomer instances:" << m_monomers.size();
151
152 15 ErrorList error_list;
153
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 m_isValid = validate(&error_list);
154
155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if(!m_isValid)
156 {
157 qCritical() << "The copy-constructed Sequence is not valid, with errors:"
158 << Utils::joinErrorList(error_list, ", ");
159 }
160
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
15 }
161
162 /*!
163 \brief Destructs this sequence.
164 */
165 366 Sequence::~Sequence()
166 {
167 366 m_monomers.clear();
168
2/2
✓ Branch 2 taken 180 times.
✓ Branch 3 taken 3 times.
366 }
169
170 //////////////// POLYMER CHEMISTRY DEFINTIION /////////////////////
171
172
173 /*!
174 \brief Sets the polymer chemistry definition to \a pol_chem_def_csp.
175 */
176 void
177 1 Sequence::setPolChemDefCstSPtr(PolChemDefCstSPtr pol_chem_def_csp)
178 {
179 1 mcsp_polChemDef = pol_chem_def_csp;
180 1 }
181
182 /*!
183 \brief Returns the polymer chemistry definition.
184 */
185 PolChemDefCstSPtr
186 2 Sequence::getPolChemDef() const
187 {
188 2 return mcsp_polChemDef;
189 }
190
191 //////////////// MONOMERS TEXT / INSTANCES /////////////////////
192
193 /*!
194 \brief Sets the \a sequence of Monomer codes to this Sequence.
195
196 No verification is performed on \a sequence. The codes are immediately
197 converted into newly allocated Monomer instances appended in order to the member
198 container of Monomer instances.
199
200 The member Monomer container is first cleared.
201
202 If there are indices of the \a sequence that failed converting to Monomer
203 instances, they are stored in \a failing_indices.
204
205 After setting the member data, the instance is validated and the result is set
206 to m_isValid.
207
208 Returns -1 if an error occurred, or the count of Monomer instances actually
209 set to the sequence.
210 */
211 int
212 7 Sequence::setSequence(const QString &sequence,
213 std::vector<std::size_t> &failing_indices)
214 {
215
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr)
216 {
217 qFatalStream() << "Programming error. The PolChemDef pointer is nullptr.";
218 }
219
220
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
7 if(!mcsp_polChemDef->isValid())
221 {
222 qFatalStream() << "Programming error. The PolChemDef is not valid.";
223 }
224
225 7 m_monomers.clear();
226
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
7 m_uuidMonomerPairs.clear();
227
228 7 int result = appendSequence(sequence, failing_indices);
229
230 7 ErrorList error_list;
231
232
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 m_isValid = validate(&error_list);
233 7 {
234
2/4
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
7 qCritical() << "The Sequence is not valid, with errors:"
235
3/6
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
14 << Utils::joinErrorList(error_list, ", ");
236 }
237
238 7 return result;
239 7 }
240
241 /*!
242 \brief Appends the \a sequence of Monomer codes to this Sequence.
243
244 No verification is performed on \a sequence. The codes are immediately
245 converted into newly allocated Monomer instances appended in order to the
246 m_monomers container. If there are indices of the \a sequence that failed
247 converting to Monomer instances, they are stored in \a failing_indices.
248
249 After setting the member data, the instance is validated and the result is set
250 to m_isValid.
251
252 Returns -1 if an error occurred, or the count of Monomer instances actually
253 added to the sequence.
254 */
255 int
256 141 Sequence::appendSequence(const QString &sequence,
257 std::vector<std::size_t> &failing_indices)
258 {
259
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 141 times.
141 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr)
260 qFatalStream() << "The PolChemDef pointer is nullptr!";
261
262
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 141 times.
141 if(!mcsp_polChemDef->isValid())
263 qFatalStream() << "The PolChemDef is not valid!";
264
265
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 3 times.
141 if(sequence.isEmpty())
266 return 0;
267
268 138 QString unspacified_sequence = unspacifySequence(sequence);
269
270 138 int result =
271
1/2
✓ Branch 1 taken 138 times.
✗ Branch 2 not taken.
138 makeMonomers(unspacified_sequence, /*reset*/ false, failing_indices);
272
273
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 138 times.
138 if(result <= 0)
274 {
275 qCritical() << "The sequence could not be converted into Monomer "
276 "instances (error or empty sequence).";
277 }
278
279 138 ErrorList error_list;
280
281
1/2
✓ Branch 1 taken 138 times.
✗ Branch 2 not taken.
138 m_isValid = validate(&error_list);
282 138 {
283
2/4
✓ Branch 1 taken 138 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 138 times.
✗ Branch 5 not taken.
138 qCritical() << "The Sequence is not valid, with errors:"
284
3/6
✓ Branch 1 taken 138 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 138 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 138 times.
✗ Branch 8 not taken.
276 << Utils::joinErrorList(error_list, ", ");
285 }
286
287 138 return result;
288 138 }
289
290 /*!
291 \brief Returns a string with all the codes of the Monomer instances found in the
292 member container concatenated in order.
293 */
294 QString
295 42 Sequence::getSequence() const
296 {
297 42 QString sequence;
298
299
2/2
✓ Branch 0 taken 6438 times.
✓ Branch 1 taken 42 times.
6480 for(const MonomerSPtr &monomer_sp : m_monomers)
300
1/2
✓ Branch 1 taken 6438 times.
✗ Branch 2 not taken.
12876 sequence += monomer_sp->getCode();
301
302 42 return sequence;
303 }
304
305 /*!
306 \brief Returns a string with all the codes of the Monomer instances found in the
307 member container concatenated in order.
308
309 The returned string only contains the sequence of monomer codes for Monomer
310 instances included in the indices range [\a start_index -- \a stop_index]
311 (inclusively) in this Sequence's container of Monomer instances.
312
313 If \a stop_index is > size(), then it is set to size().
314
315 If \a with_modif is true, the Modif instances associated to \l{Monomer}s are
316 also output to the string. The form of the string is, in this case,
317
318 \code
319 Thr<Phosphorylation>
320 \endcode
321
322 */
323 QString
324 13 Sequence::getSequence(std::size_t start_index,
325 std::size_t stop_index,
326 bool with_modif) const
327 {
328
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
13 if(!size())
329 {
330 return QString();
331 }
332
333
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if(start_index > stop_index)
334 qFatalStream() << "Programming error, please order the indices: ["
335 << start_index << "-" << stop_index << "]";
336
337 // We want the last index to be included in the range.
338 13 std::size_t local_stop = stop_index + 1;
339
340
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
13 if(local_stop > size())
341 local_stop = size();
342
343 13 QString text;
344
345
2/2
✓ Branch 0 taken 1033 times.
✓ Branch 1 taken 13 times.
1046 for(std::size_t iter = start_index; iter < local_stop; ++iter)
346 {
347
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1033 times.
1033 MonomerSPtr monomer_sp = m_monomers.at(iter);
348
349 // qDebug() << "Iterating in Monomer:" << monomer_sp->getCode();
350
351
5/6
✓ Branch 0 taken 510 times.
✓ Branch 1 taken 523 times.
✓ Branch 3 taken 510 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 506 times.
1033 if(with_modif && monomer_sp->isModified())
352 {
353
3/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 4 times.
8 for(const ModifSPtr &modif_sp : monomer_sp->getModifsCstRef())
354
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 text += QString("%1<%2>")
355
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
8 .arg(monomer_sp->getCode())
356
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
12 .arg(modif_sp->getName());
357 }
358 else
359
1/4
✓ Branch 1 taken 1029 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
2058 text += monomer_sp->getCode();
360 1033 }
361
362 13 return text;
363 13 }
364
365 /*!
366 \brief Returns a string with all the codes of the Monomer instances found in the
367 member container concatenated in order.
368
369 The returned string only contains the sequence of monomer codes for Monomer
370 instances contained in the \l{IndexRange} instances contained in \a
371 index_ranges.
372
373 If \a with_modif is true, the modification(s) associated to \l{Monomer}s are
374 also output to the string. The form of the string is, in this case,
375
376 \code
377 Thr<Phosphorylation>
378 \endcode
379
380 If \a delimited_regions is true, the sequence of Monomer codes belonging to each
381 sequence range will be delimited using the IndexRange positions (not the
382 indices).
383
384 \sa IndexRange::positionsAsText()
385 */
386 QString
387 4 Sequence::getSequence(const IndexRangeCollection &index_ranges,
388 bool with_modif,
389 bool delimited_regions) const
390 {
391 4 QString text;
392
393
3/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 4 times.
8 for(const IndexRange *item : index_ranges.getRangesCstRef())
394 {
395 4 QString sequence_string =
396
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 getSequence(item->m_start, item->m_stop, with_modif);
397
398
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if(delimited_regions)
399
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 text += QString("Region [%1-%2]: %3\n")
400
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 .arg(item->m_start + 1)
401
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 .arg(item->m_stop + 1)
402
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
3 .arg(sequence_string);
403 else
404
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
4 text += sequence_string;
405 4 }
406
407 // Removed because this is unnecessary.
408 // text += QString("\n");
409
410 4 return text;
411 }
412
413 /*!
414 \brief Allocates all the Monomer instances to describe this Sequence's string
415 representation of monomer codes.
416
417 This function parses the \a sequence_text Monomer codes string and, for
418 each encountered code, creates a \l Monomer instance and adds it to the member
419 container of Monomer instances.
420
421 If \a reset is true, the member container of Monomer instances is reset before
422 the work is done. Any error that might occur is stored as the index of the
423 failing Monomer code in the \a failing_indices container.
424
425 The allocation of each Monomer instance based on its code is performed by
426 looking at the reference Monomer in the member polymer chemistry definition..
427
428 Because the m_monomerText member string of Monomer codes does not document any
429 monomer modification, no modifications are handled in this function.
430
431 Returns the count of Monomer instances set to the list or -1 if an error
432 occurred.
433 */
434 int
435 318 Sequence::makeMonomers(const QString &sequence_text,
436 bool reset,
437 std::vector<std::size_t> &failing_indices)
438 {
439
3/4
✓ Branch 0 taken 313 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 313 times.
631 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr ||
440 313 !mcsp_polChemDef->isValid())
441 {
442
1/2
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
5 qCritical() << "The PolChemDef pointer is nullptr or not valid!";
443 5 m_isValid = false;
444 5 return -1;
445 }
446
447
2/2
✓ Branch 0 taken 175 times.
✓ Branch 1 taken 138 times.
313 if(reset)
448 175 m_monomers.clear();
449
450
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 313 times.
313 failing_indices.clear();
451
452 313 QString local_sequence_text = unspacifySequence(sequence_text);
453
454 // qDebug() << "Sequence:" << local_sequence_text;
455
456 313 std::size_t index = 0;
457 313 int ret = -1;
458 313 QString err;
459 313 QString code;
460
461
1/2
✓ Branch 1 taken 313 times.
✗ Branch 2 not taken.
313 ret = nextCode(local_sequence_text, code, index, err);
462
463 25904 while(true)
464 {
465
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 25901 times.
25904 if(ret < 0)
466 {
467 // There was an error in the parsed code. Store the index.
468
469
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 failing_indices.push_back(index);
470 3 ++index;
471
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 ret = nextCode(local_sequence_text, code, index, err);
472
473 3 continue;
474 }
475
476
2/2
✓ Branch 0 taken 25588 times.
✓ Branch 1 taken 313 times.
25901 if(ret == 0)
477 break;
478
479
2/4
✓ Branch 1 taken 25588 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 25588 times.
✗ Branch 6 not taken.
51176 Monomer monomer(mcsp_polChemDef, "", code);
480
481 25588 MonomerSPtr pol_chem_def_monomer_csp =
482
1/2
✓ Branch 1 taken 25588 times.
✗ Branch 2 not taken.
25588 mcsp_polChemDef->getMonomerCstSPtrByCode(code);
483
484
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25588 times.
25588 if(pol_chem_def_monomer_csp == nullptr)
485 {
486 qWarning() << "Monomer:" << code
487 << "was not found in the monomer reference list.";
488
489 failing_indices.push_back(index);
490 ++index;
491 ret = nextCode(local_sequence_text, code, index, err);
492 continue;
493 }
494 else
495 {
496 // Fully initialize the monomer with that found in the PolChemDef.
497
1/2
✓ Branch 1 taken 25588 times.
✗ Branch 2 not taken.
25588 monomer = *pol_chem_def_monomer_csp;
498
3/8
✓ Branch 1 taken 25588 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 25588 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 25588 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
51176 storeMonomer(std::make_shared<Monomer>(monomer));
499
500 // qDebug() << "The newly created Monomer has masses:"
501 // << monomer.getMass(Enums::MassType::MONO) << "-"
502 // << monomer.getMass(Enums::MassType::AVG);
503 }
504
505 25588 ++index;
506
2/4
✓ Branch 1 taken 25588 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 25588 times.
✗ Branch 4 not taken.
25588 ret = nextCode(local_sequence_text, code, index, err);
507 25588 }
508 // End of
509 // while(true)
510
511
2/2
✓ Branch 0 taken 310 times.
✓ Branch 1 taken 3 times.
313 if(failing_indices.size())
512 return -1;
513
514 310 if(ret == -1)
515 return -1;
516
517 310 return m_monomers.size();
518 313 }
519
520 /*!
521 \brief Returns a const reference to the Monomer container.
522 */
523 const std::vector<MonomerSPtr> &
524 258 Sequence::getMonomersCstRef() const
525 {
526 258 return m_monomers;
527 }
528
529 /*!
530 \brief Returns a reference to the Monomer container.
531 */
532 std::vector<MonomerSPtr> &
533 Sequence::getMonomersRef()
534 {
535 return m_monomers;
536 }
537
538 // /*!
539 // \brief Returns a reference to this Sequence's container of \l Monomer
540 // instances.
541 // */
542 // std::vector<MonomerSPtr> &
543 // Sequence::getMonomersRef()
544 // {
545 // return m_monomers;
546 // }
547
548 //////////////// MONOMER ACCESSING FUNCTIONS /////////////////////
549
550 /*!
551 \brief Returns the Monomer instance at \a index in this Sequence's
552 container of Monomer instances as a const raw pointer.
553
554 An index that is out of bounds is fatal.
555 */
556 MonomerCstRPtr
557 36 Sequence::getMonomerCstRPtrAt(std::size_t index) const
558 {
559
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 if(index >= m_monomers.size())
560 qFatalStream() << "Index is out of bounds.";
561
562
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 return m_monomers.at(index).get();
563 }
564
565 /*!
566 \brief Returns the Monomer instance at \a index in this Sequence's
567 container of Monomer instances as a raw pointer.
568
569 An index that is out of bounds is fatal.
570 */
571 MonomerRPtr
572 Sequence::getMonomerRPtrAt(std::size_t index)
573 {
574 if(index >= m_monomers.size())
575 qFatalStream() << "Index is out of bounds.";
576
577 return m_monomers.at(index).get();
578 }
579
580 /*!
581 \brief Returns the Monomer instance at \a index in this Sequence's
582 container of Monomer instances as a const shared pointer.
583
584 An index that is out of bounds is fatal.
585 */
586 MonomerSPtr
587 40635 Sequence::getMonomerCstSPtrAt(std::size_t index) const
588 {
589
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40635 times.
40635 if(index >= m_monomers.size())
590 qFatalStream() << "Programming error. Index is out of bounds:" << index
591 << "with monomer count:" << m_monomers.size();
592
593
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40635 times.
40635 return m_monomers.at(index);
594 }
595
596 /*!
597 \brief Returns the Monomer instance at \a index in this Sequence's
598 container of Monomer instances as a shared pointer.
599
600 An index that is out of bounds is fatal.
601 */
602 MonomerSPtr
603 2 Sequence::getMonomerSPtrAt(std::size_t index)
604 {
605
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if(index >= m_monomers.size())
606 qFatalStream() << "Index is out of bounds.";
607
608
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 return m_monomers.at(index);
609 }
610
611 /*!
612 \brief Returns the index of \a monomer_sp in this Sequence's container of
613 Monomer instances.
614
615 The search is based on comparison of the pointers, that is, the returned
616 index is for the \e same Monomer object (pointer-wise). If the Monomer was
617 found, the returned value is certain to be correct and \a ok is set to true. If
618 the Monomer was not found, the returned value is 0 and ok is set to false.
619 */
620 std::size_t
621 1 Sequence::monomerIndex(MonomerSPtr monomer_sp, bool &ok) const
622 {
623 1 std::vector<MonomerSPtr>::const_iterator the_iterator_cst =
624 2 std::find_if(m_monomers.cbegin(),
625 m_monomers.cend(),
626
3/6
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
3 [monomer_sp](const MonomerSPtr &iter_monomer_sp) {
627
5/14
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 39 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 39 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 39 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 1 times.
40 return iter_monomer_sp == monomer_sp;
628 });
629
630
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(the_iterator_cst != m_monomers.cend())
631 {
632 ok = true;
633 return std::distance(m_monomers.cbegin(), the_iterator_cst);
634 }
635
636 1 ok = false;
637 1 return 0;
638 }
639
640 /*!
641 \brief Returns the index of \a monomer_csp in this Sequence's container of
642 Monomer instances.
643
644 The search is based on comparison of the pointers, that is, the returned
645 index is for the \e same Monomer object (pointer-wise). If the Monomer was
646 found, the returned value is certain to be correct and \a ok is set to true. If
647 the Monomer was not found, the returned value is 0 and ok is set to false.
648 */
649 std::size_t
650 8 Sequence::monomerIndex(MonomerCstSPtr monomer_csp, bool &ok) const
651 {
652 8 std::vector<MonomerSPtr>::const_iterator the_iterator_cst =
653 16 std::find_if(m_monomers.cbegin(),
654 m_monomers.cend(),
655
3/6
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
24 [monomer_csp](const MonomerSPtr &iter_monomer_sp) {
656
6/14
✗ Branch 0 not taken.
✓ Branch 1 taken 136 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 136 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 132 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 128 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
136 return iter_monomer_sp == monomer_csp;
657 });
658
659
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if(the_iterator_cst != m_monomers.cend())
660 {
661 8 ok = true;
662 8 return std::distance(m_monomers.cbegin(), the_iterator_cst);
663 }
664
665 ok = false;
666 return 0;
667 }
668
669 /*!
670 \brief Returns the index of \a monomer_crp in this Sequence's list of Monomer
671 instances.
672
673 The search is based on comparison of the pointers, that is, the returned
674 index is for the \e same Monomer object (pointer-wise). If the Monomer was
675 found, the returned value is certain to be correct and \a ok is set to true. If
676 the Monomer was not found, the returned value is 0 and ok is set to false.
677 */
678 std::size_t
679 7028 Sequence::monomerIndex(MonomerCstRPtr monomer_crp, bool &ok) const
680 {
681
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7028 times.
7028 if(monomer_crp == nullptr)
682 qFatalStream() << "Programming error. Pointer cannot be nullptr.";
683
684 7028 std::vector<MonomerSPtr>::const_iterator the_iterator_cst =
685
1/2
✓ Branch 0 taken 7028 times.
✗ Branch 1 not taken.
7028 std::find_if(m_monomers.cbegin(),
686 m_monomers.cend(),
687 1830111 [monomer_crp](const MonomerSPtr &iter_monomer_sp) {
688
7/14
✓ Branch 0 taken 1780 times.
✓ Branch 1 taken 457503 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 457503 times.
✓ Branch 4 taken 1681 times.
✓ Branch 5 taken 455822 times.
✓ Branch 6 taken 3567 times.
✓ Branch 7 taken 452255 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
459283 return iter_monomer_sp.get() == monomer_crp;
689 });
690
691
1/2
✓ Branch 0 taken 7028 times.
✗ Branch 1 not taken.
7028 if(the_iterator_cst != m_monomers.cend())
692 {
693 7028 ok = true;
694 7028 return std::distance(m_monomers.cbegin(), the_iterator_cst);
695 }
696
697 ok = false;
698 return 0;
699 }
700
701 /*!
702 \brief Seeks the next code occurring in the \a sequence string of Monomer
703 codes.
704
705 This function starts looking in \a sequence at \a index. The next found
706 Monomer code is stored in \a code. If \a sequence is not a monomer code, it is
707 set to \a err.
708
709 Returns the count of characters that make \a code. This count can be used
710 to search for the next code by setting its value incremented by 1 to \a index
711 for a next function call.
712 */
713 std::size_t
714 25910 Sequence::nextCode(const QString &sequence,
715 QString &code,
716 std::size_t &index,
717 QString &err)
718 {
719
2/4
✓ Branch 0 taken 25910 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 25910 times.
51820 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr ||
720 25910 !mcsp_polChemDef->isValid())
721 qFatalStream()
722 << "Programming error. It is not possible that the PolChemDef be "
723 "undefined or invalid.";
724
725 25910 QString new_code;
726 25910 std::size_t iter = 0;
727
728 // We get a sequence of monomer codes(like "LysArgGlu" for example)
729 // and we have to return the next code starting from *index. Note
730 // that the sequence must not contain invalid characters. The
731 // invalid characters might be placed in err for further scrutiny by
732 // the caller.
733
734 // Returns the count of actually parsed characters in the string
735 // newCode(copied to 'code' param). If an error occurs -1 is
736 // returned and the faulty character is copied in 'err'. 'index' is
737 // updated with the index of the last valid character parsed for
738 // current code.
739
740 25910 code.clear();
741 25910 err.clear();
742
743 25910 std::size_t sequence_length = sequence.length();
744
745 77806 while(1)
746 {
747
3/4
✓ Branch 1 taken 51858 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 25594 times.
✓ Branch 4 taken 26264 times.
51858 if(iter >= static_cast<std::size_t>(mcsp_polChemDef->getCodeLength()))
748 {
749 // Because we have progressed farther than authorized by
750 // the number of characters allowed in the monomer codes
751 // of this polymer chemistry definition, we decrement iter
752 // and break the loop... Later in this function, we'll set
753 // the proper index in the sequence where next parsing run
754 // should occurs (the calling function will increment
755 // index by one).
756
757 25594 --iter;
758 25594 break;
759 }
760
761
2/2
✓ Branch 0 taken 25951 times.
✓ Branch 1 taken 313 times.
26264 if(iter + index >= sequence_length)
762 break;
763
764
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 25948 times.
25951 QChar curChar = sequence.at(iter + index);
765
766
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 25948 times.
25951 if(!curChar.isLetter())
767 {
768 // qDebug() << __FILE__ << __LINE__
769 // << "The character is not a letter:"
770 // << curChar;
771
772
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 err = curChar;
773
774 // The non-Letter character might be '/', which would be
775 // perfectly fine, as we use it to symbolize the actual
776 // cleavage site. Which means that we will continue
777 // parsing the rest of the string : we have to give the
778 // current position back to the caller in the index
779 // variable for the next call to this function to start at
780 // next character (not falling back to '/', which would
781 // make us enter in an infinite loop).
782
783 3 index = index + iter;
784
785 25913 return -1;
786 }
787
788
2/2
✓ Branch 0 taken 25594 times.
✓ Branch 1 taken 354 times.
25948 bool isLower = (curChar.category() == QChar::Letter_Lowercase);
789
790
2/2
✓ Branch 0 taken 25594 times.
✓ Branch 1 taken 354 times.
25948 if(iter == 0)
791 {
792
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25594 times.
25594 if(isLower)
793 {
794 // qDebug() << __FILE__ << __LINE__
795 // << "First character of monomer code might not be"
796 // << "lower case; sequence is"
797 // << m_monomerText;
798
799 err = curChar;
800
801 return -1;
802 }
803 else
804 {
805 // Good, first char is uppercase.
806
1/2
✓ Branch 1 taken 25594 times.
✗ Branch 2 not taken.
25594 new_code += curChar;
807 }
808 }
809 else //(iter != 0)
810 {
811 // We are not in our first iteration. So either the current
812 // character is lowercase and we are just continuing to
813 // iterate into a multi-char monomer code, or the current
814 // character is uppercase, in which case we are starting to
815 // iterate in a new monomer code.
816
817
1/2
✓ Branch 0 taken 354 times.
✗ Branch 1 not taken.
354 if(isLower)
818
1/2
✓ Branch 1 taken 354 times.
✗ Branch 2 not taken.
354 new_code += curChar;
819 else
820 {
821 // Decrement iter, because this round was for nothing:
822 // we had "invaded" the next monomer code in sequence,
823 // which we must not do.
824
825 --iter;
826 break;
827 }
828 }
829
830 25948 ++iter;
831 25948 }
832
833 // We finished parsing at most codeLength characters out of
834 // sequence, so we have a valid code in the 'code' variable. We
835 // can also compute a new index position in the sequence and return
836 // the number of characters that we effectively parsed. Note that
837 // the caller will be responsible for incrementing the 'index' value
838 // by one character unit so as not to reparse the last characters of
839 // the sent 'code' object.
840
841 25907 index = index + iter;
842 25907 code = new_code;
843 25907 err.clear();
844
845 25907 return code.length();
846 25910 }
847
848 //////////////// MONOMER HANDLING FUNCTIONS /////////////////////
849
850 /*!
851 \brief Inserts \a monomer at index \a index.
852
853 If the index value is equal to the size of the Monomer container,
854 then, the \a monomer is added to the bottom of the container.
855
856 If the index value is greater than the size of the Monomer container, that is
857 fatal.
858
859 Returns the Uuid string corresponding to the new Monomer.
860 */
861 QString
862 10 Sequence::insertMonomerAt(const Monomer &monomer, std::size_t index)
863 {
864
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 if(index > size())
865 qFatalStream() << "Programming error. Index is out of bounds:" << index;
866
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 8 times.
10 else if(index == size())
867
1/2
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 return storeMonomer(std::make_shared<Monomer>(monomer));
868 else
869
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
16 return storeMonomer(std::make_shared<Monomer>(monomer), index);
870
871 // Should never reach this point.
872 return QString();
873 }
874
875 /*!
876 \brief Removes the Monomer instance at index \a index from this Sequence's list
877 of Monomer instances.
878
879 An index that is out of bounds is fatal.
880
881 Returns true.
882 */
883 bool
884 4 Sequence::removeMonomerAt(std::size_t index)
885 {
886 // qDebug() << "Asking to remove Monomer at index" << index;
887
888
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if(index >= size())
889 qFatalStream() << "Programming error. Index is out of bounds.";
890
891 // Some controls are in order: we have to check that at index, there is
892 // a MonomerSPtr that is present both in m_monomers and in
893 // m_uuidMonomerPairs.
894
895
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 MonomerSPtr monomer_sp = m_monomers.at(index);
896
897 // qDebug() << "The Monomer being removed at index:" << index
898 // << "is:" << monomer_sp->getName()
899 // << "with modification status:" << monomer_sp->isModified();
900
901
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 QString uuid = getUuidForMonomer(monomer_sp);
902
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if(uuid.isEmpty())
903 qFatalStream()
904 << "Inconsistency between m_monomers and m_uuidMonomerPairs.";
905
906
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 std::vector<UuidMonomerWPtrPair>::const_iterator the_iterator_cst =
907 8 std::find_if(m_uuidMonomerPairs.cbegin(),
908 m_uuidMonomerPairs.cend(),
909
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
20 [uuid](const UuidMonomerWPtrPair &the_pair) {
910 // Do not query the monomer_sp managed object because it can
911 // be nullptr!
912
5/14
✗ Branch 0 not taken.
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 80 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 76 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 76 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
80 return the_pair.first == uuid;
913 });
914
915
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if(the_iterator_cst == m_uuidMonomerPairs.cend())
916 qFatalStream()
917 << "Inconsistency between m_monomers and m_uuidMonomerPairs.";
918
919 4 m_uuidMonomerPairs.erase(the_iterator_cst);
920 4 m_monomers.erase(m_monomers.begin() + index);
921
922 // qDebug() << "Done removing Monomer.";
923
924 4 return true;
925
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
8 }
926
927 /*!
928 \brief Modifies the Monomer instance at index \a index with a Modif instance
929 that is created on the basis of \a modif_name.
930
931 If \a override is set to true, then the modification occurs even if the Monomer
932 at \index was already modified max count times.
933
934 An index that is out of bounds is fatal.
935
936 Returns true.
937
938 \sa Modif::m_maxCount
939 */
940 bool
941 2 Sequence::modifyMonomer(std::size_t index,
942 const QString modif_name,
943 bool override)
944 {
945
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if(index >= size())
946 qFatalStream() << "Programming error. Index is out of bounds.";
947
948 2 MonomerSPtr monomer_sp = getMonomerSPtrAt(index);
949
950 2 ErrorList error_list;
951
952
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 QString uuid = monomer_sp->modify(modif_name, override, &error_list);
953
954
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if(uuid.isEmpty() || error_list.size())
955 {
956 qCritical() << "Monomer modification with Modif:" << modif_name
957 << "failed";
958 return false;
959 }
960
961 return true;
962
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
4 }
963
964 /*!
965 \brief Returns true if this Sequence instance, between Monomer indices \a
966 left_index and \a right_index, has at least one modified Monomer instance.
967
968 If no Monomer is modified, returns false.
969 */
970 bool
971 36 Sequence::hasModifiedMonomer(std::size_t left_index,
972 std::size_t right_index) const
973 {
974
2/4
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 36 times.
36 if(left_index >= size() || right_index >= size())
975 qFatal("Programming error. Indices out of bounds.");
976
977
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 if(left_index > right_index)
978 qFatal("Programming error. Indices are not correct.");
979
980
1/2
✓ Branch 0 taken 468 times.
✗ Branch 1 not taken.
468 for(std::size_t iter = left_index; iter <= right_index; ++iter)
981 {
982
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 468 times.
✓ Branch 3 taken 432 times.
✓ Branch 4 taken 36 times.
468 if(m_monomers.at(iter)->isModified())
983 return true;
984 }
985
986 return false;
987 }
988
989 /*!
990 \brief Returns a container holding all the indices corresponding to modified
991 Monomer instances in the member Monomer container.
992
993 The search is performed only between Monomer indices \a left_index and \a
994 right_index.
995
996 If no Monomer is modified, returns an empty container.
997 */
998 std::vector<std::size_t>
999 36 Sequence::modifiedMonomerIndices(std::size_t left_index,
1000 std::size_t right_index) const
1001 {
1002
2/4
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 36 times.
36 if(left_index >= size() || right_index >= size())
1003 qFatal("Programming error. Indices out of bounds.");
1004
1005
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 if(left_index > right_index)
1006 qFatal("Programming error. Indices are not correct.");
1007
1008 36 std::vector<std::size_t> indices;
1009
1010
2/2
✓ Branch 0 taken 5652 times.
✓ Branch 1 taken 36 times.
5688 for(std::size_t iter = left_index; iter <= right_index; ++iter)
1011 {
1012
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 5652 times.
✓ Branch 3 taken 5652 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 36 times.
✓ Branch 6 taken 5616 times.
5652 if(m_monomers.at(iter)->isModified())
1013
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
5688 indices.push_back(iter);
1014 }
1015
1016 36 return indices;
1017 }
1018
1019 //////////////// SEQUENCE SEARCH FUNCTIONS /////////////////////
1020
1021 /*!
1022 \brief Searches for a Sequence textual \a sequence_motif in this Sequence's
1023 container of Monomer instances, starting at \a index.
1024
1025 \a sequence_motif, a text string is first converted to a container of Monomer
1026 instances (using the reference list of Monomer instances in the member polymer
1027 chemistry definition). Then, this Sequence's container of Monomer instances is
1028 searched for a Monomer stretch that matches that created for \a sequence_motif.
1029
1030 As soon as a Monomer code stretch is found, the index in this Sequence's
1031 container of Monomer instances is set to \a index.
1032
1033 Returns -1 if an error occurred, 1 if \a sequence_motif was found in this
1034 Sequence, 0 otherwise.
1035 */
1036 int
1037 26 Sequence::findForwardMotif(const Sequence &sequence_motif,
1038 std::size_t &index) const
1039 {
1040 // qDebug() << "This sequence:" << getSequence();
1041 // qDebug() << "The motif sequence:" << sequence_motif.getSequence();
1042
1043
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if(!m_isValid)
1044 {
1045 qCritical() << "The Sequence is not valid.";
1046 return -1;
1047 }
1048
1049
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
26 if(!size())
1050 {
1051 qCritical() << "The Sequence is empty.";
1052 return 0;
1053 }
1054
1055 // qDebug() << "motif:" << *(sequence_motif.monomerText()) << "index :" <<
1056 // index;
1057
1058
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
26 if(!sequence_motif.isValid())
1059 {
1060 qCritical() << "The sequence motif to search for is not valid.";
1061 return -1;
1062 }
1063
1064
2/2
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 2 times.
26 if(index >= size())
1065 return -1;
1066
1067 24 int sequence_motif_size = sequence_motif.size();
1068
1069 // qDebug() << "The sequence motif has size:" << sequence_motif_size;
1070
1071 // If motif's length is 0, then nothing to search for, return
1072 // unmodified 'index'.
1073
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 23 times.
24 if(!sequence_motif_size)
1074 return 0;
1075
1076 // Simple optimization, if index + size of motif is greater then
1077 // size of sequence, return right away.
1078
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 22 times.
23 if(index + sequence_motif_size > size())
1079 return 0;
1080
1081 // Compare *this sequence with the one in 'motif', starting at index
1082 // 'index' in *this sequence and 0 in 'motif'.
1083
1084 22 bool matched = false;
1085 22 int matchIndex = 0;
1086
1087
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1419 times.
1421 for(std::size_t iter = index; iter < size(); ++iter)
1088 {
1089 1419 std::size_t jter = 0;
1090
1091 1419 const MonomerSPtr monomer_sp = getMonomerCstSPtrAt(iter);
1092 1419 const MonomerSPtr motif_monomer_sp =
1093
1/2
✓ Branch 1 taken 1419 times.
✗ Branch 2 not taken.
1419 sequence_motif.getMonomerCstSPtrAt(jter);
1094
1095 // qDebug() << "At sequence iter" << iter << monomer_p->getCode()
1096 // << "and at motif jter:" << jter << motif_monomer_p->getCode();
1097
1098 // We do not compare with operator == because that comparison
1099 // would involve the comparison of modifications inside the
1100 // monomers, which would not work here.
1101
4/8
✓ Branch 1 taken 1419 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1419 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 1292 times.
✓ Branch 9 taken 127 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
1419 if(monomer_sp->getCode() != motif_monomer_sp->getCode())
1102 1292 continue;
1103
1104 // An easy check is to see if the number of remaining monomers
1105 // in the polymer sequence is compatible with the number of
1106 // monomers still to be matched in the find array. Imagine the
1107 // sequence of the polymer ends like this: ==========JTOUTVU and
1108 // the sequence to be searched for is : TVUL What we see is that
1109 // the T of the TVU of the sequence matches; however we can stop
1110 // the search right away because there is a 'L' in the search
1111 // pattern that is not present in the end part of the
1112 // sequence. This is exactly what is checked below. Note that
1113 // this check makes SURE that at the end of the second inner
1114 // loop, when we get out of it, the sole reason we may not
1115 // consider that the match did not occur is because actually two
1116 // monomers differred and not because anybody came out of the
1117 // borders of the sequence in neither the array of the sequence
1118 // to be searched, nor the array of the polymer sequence. This
1119 // makes it very easy to assess if a match occurred or not.
1120
1121
4/6
✓ Branch 1 taken 127 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 127 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 126 times.
127 if(size() - iter < sequence_motif.size() - jter)
1122 {
1123 // Note that if it were ==, then it would have been possible
1124 // that the sequence "just-in-time" match prior to ending of
1125 // the polymer sequence array. Do not forget that we are in
1126 // forward mode, thus we can break immediately, because we
1127 // are certain that we won't have any chance to find the
1128 // sequence downstream of current index.
1129
1130 1 matched = false;
1131
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 break;
1132 }
1133
1134 // qDebug() << monomer_p->getCode()
1135 // << "found at sequence iter index: " << iter;
1136
1137 126 matchIndex = iter;
1138
1139 // We have to set the matched boolean to true, because if the
1140 // motif to find is one monomer-long, then the loop below will
1141 // not be entered, and we'll fail to know that the match
1142 // occurred later on.
1143 126 matched = true;
1144
1145 // Now that we have our anchoring point in the *this sequence,
1146 // let's iterate in the motif, and check if the identity in
1147 // sequence goes along.
1148
1149
3/4
✓ Branch 1 taken 263 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 244 times.
✓ Branch 4 taken 19 times.
263 for(std::size_t kter = jter + 1; kter < sequence_motif.size(); ++kter)
1150 {
1151 // At first run in this loop, we are in the second cell of
1152 // the find list, which means that we should have jter ==
1153 // 1. And we should compare its contents with those of the
1154 // cell in the sequence list at index(iter + jter).
1155
1156
1/2
✓ Branch 1 taken 244 times.
✗ Branch 2 not taken.
244 const MonomerSPtr monomer_sp = getMonomerCstSPtrAt(iter + kter);
1157 244 const MonomerSPtr motif_monomer_sp =
1158
1/2
✓ Branch 1 taken 244 times.
✗ Branch 2 not taken.
244 sequence_motif.getMonomerCstSPtrAt(kter);
1159
1160 // qDebug() << "At sequence iter + kter" << iter + kter
1161 // << monomer_p->getCode() << "and at motif kter:" << kter
1162 // << motif_monomer_p->getCode();
1163
1164 // We compare codes and not monomers because that
1165 // comparison would involve the comparison of modifications
1166 // inside the monomers, which would not work here.
1167
4/8
✓ Branch 1 taken 244 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 244 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 137 times.
✓ Branch 9 taken 107 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
244 if(monomer_sp->getCode() == motif_monomer_sp->getCode())
1168 {
1169 // The monomers still match.
1170 137 matched = true;
1171 // qDebug() << "still matching";
1172
1/2
✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
137 continue;
1173 }
1174 else
1175 {
1176 107 matched = false;
1177 // qDebug() << "not matching anymore";
1178
1/2
✓ Branch 0 taken 107 times.
✗ Branch 1 not taken.
107 break;
1179 }
1180
2/4
✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 107 times.
✗ Branch 3 not taken.
381 }
1181 // End of
1182 // for (int kter = jter + 1 ; kter < motif->size() ; ++kter)
1183
1184 // At this point, we either have normally extinguished the run
1185 // in the inner loop, or we have gone out of it before its
1186 // normal termination. In either case, we have to test if the
1187 // match occurred or not.
1188
1189 // Check if the match did NOT occur:
1190
1191 126 if(!matched)
1192 {
1193 // We just continue with the outer loop, that is, we continue
1194 // searching in this sequence for a match with the
1195 // first monomer in the motif.
1196
1197 107 continue;
1198 }
1199 else
1200 {
1201 // The match indeed occurred.
1202
1203 19 index = matchIndex;
1204
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 return 1;
1205 }
1206
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1399 times.
✗ Branch 5 not taken.
2838 }
1207 // End of
1208 // for (int iter = index; iter < size(); ++iter)
1209
1210 // No match could be achieved, we have to let the caller function
1211 // know this in a durable manner : returning 0.
1212
1213 return 0;
1214 }
1215
1216 //////////////// DIAGNOSTICS FUNCTIONS /////////////////////
1217
1218 /*!
1219 \brief Returns the size of this Sequence as the size of the container of Monomer
1220 instances.
1221 */
1222 std::size_t
1223 7075 Sequence::size() const
1224 {
1225
0/32
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
7075 return m_monomers.size();
1226 }
1227
1228 /*!
1229 \brief Returns true if \a index is valid as an index of a Monomer instance in
1230 this Sequence's container of \l{Monomer} instances, false otherwise.
1231 */
1232 bool
1233 4 Sequence::isInBound(std::size_t index)
1234 {
1235
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
4 if(index < size())
1236 3 return true;
1237
1238 return false;
1239 }
1240
1241 //////////////// OPERATORS /////////////////////
1242
1243 /*!
1244 \brief Assigns \a other to this Sequence.
1245
1246 The copying is deep with the instances in the \a other container of Monomer
1247 instances being reinstantiated anew into this Sequence's container of Monomer
1248 instances.
1249
1250 Returns a reference to this Sequence.
1251 */
1252 Sequence &
1253 17 Sequence::operator=(const Sequence &other)
1254 {
1255
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 4 times.
17 if(&other == this)
1256 return *this;
1257
1258 13 mcsp_polChemDef = other.mcsp_polChemDef;
1259
1260 13 m_monomers.clear();
1261
1262
2/2
✓ Branch 0 taken 1766 times.
✓ Branch 1 taken 13 times.
1779 for(const MonomerSPtr &monomer_sp : other.m_monomers)
1263 3532 storeMonomer(monomer_sp);
1264
1265 return *this;
1266 }
1267
1268 /*!
1269 \brief Returns true if the \c this Sequence is identical to \a other, false
1270 otherwise.
1271
1272 The comparison of the Monomer instances is deep and is not based on merely
1273 comparing the pointers.
1274 */
1275 bool
1276 32 Sequence::operator==(const Sequence &other)
1277 {
1278
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 27 times.
32 if(&other == this)
1279 return true;
1280
1281
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
27 if(mcsp_polChemDef != other.mcsp_polChemDef)
1282 {
1283 qInfo() << "Differing PolChemDef.";
1284 return false;
1285 }
1286
1287
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 23 times.
27 if(m_monomers.size() != other.m_monomers.size())
1288 {
1289
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 qInfo() << "Differing Monomer container size.";
1290 4 return false;
1291 }
1292
1293
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 1885 times.
1904 for(std::size_t iter = 0; iter < other.m_monomers.size(); ++iter)
1294 {
1295
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1885 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 1881 times.
1885 if(*m_monomers.at(iter) != *other.m_monomers.at(iter))
1296 return false;
1297 }
1298
1299 return true;
1300 }
1301
1302 /*!
1303 \brief Returns true if the \c this Sequence is different than \a other, false
1304 otherwise.
1305
1306 Returns the negation of operator==(other).
1307 */
1308 bool
1309 13 Sequence::operator!=(const Sequence &other)
1310 {
1311
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1 times.
13 if(&other == this)
1312 return false;
1313
1314 12 return !operator==(other);
1315 }
1316
1317 //////////////// VALIDATIONS /////////////////////
1318 /*!
1319 \brief Validates this Sequence using the member polymer chemistry definition as
1320 the reference polymer chemistry definition and sets m_isValid to the result of
1321 this validation.
1322
1323 Returns true if all the Monomer instances in the member container could be found
1324 in the polymer chemistry definition's container of reference Monomer instances.
1325
1326 Any error is documented by storing a message to \a error_list_p.
1327
1328 \sa makeMonomers()
1329 */
1330 bool
1331 299 Sequence::validate(ErrorList *error_list_p) const
1332 {
1333
2/2
✓ Branch 0 taken 275 times.
✓ Branch 1 taken 24 times.
299 qsizetype error_count = error_list_p->size();
1334
1335
3/4
✓ Branch 0 taken 275 times.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 275 times.
574 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr ||
1336 275 !mcsp_polChemDef->isValid())
1337 {
1338
1/2
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
24 qCritical() << "The PolChemDef is not available.";
1339 48 error_list_p->push_back(
1340 "The PolChemDef is not available, cannot validate the Sequence "
1341 "instance.");
1342 }
1343
1344
2/2
✓ Branch 0 taken 40063 times.
✓ Branch 1 taken 299 times.
40362 for(const MonomerSPtr &monomer_sp : m_monomers)
1345 {
1346
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 40063 times.
40063 if(monomer_sp->isKnownByCodeInPolChemDef() !=
1347 Enums::PolChemDefEntityStatus::ENTITY_KNOWN)
1348 {
1349 qCritical()
1350 << "At least one Monomer was not found in the PolChemDef.";
1351 error_list_p->push_back(
1352 "At least one Monomer was not found in the PolChemDef");
1353 }
1354 }
1355
1356 299 m_isValid = (error_list_p->size() > error_count ? false : true);
1357 299 return m_isValid;
1358 }
1359
1360 /*!
1361 \brief Returns the validity status of this Sequence instance.
1362 */
1363 bool
1364 33 Sequence::isValid() const
1365 {
1366
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
33 return m_isValid;
1367 }
1368
1369 //////////////// UTILS /////////////////////
1370
1371 /*!
1372 \brief Removes all spaces, tabulations, carriage returns and linefeeds from the
1373 \a monomer_text sequence of Monomer codes.
1374 */
1375 QString
1376 451 Sequence::unspacifySequence(const QString &monomer_text)
1377 {
1378 // Removal of all spaces, carriage returns and linefeeds:
1379
1380
2/2
✓ Branch 0 taken 361 times.
✓ Branch 1 taken 90 times.
451 QString local_monomer_text = monomer_text;
1381
1382
2/2
✓ Branch 0 taken 43558 times.
✓ Branch 1 taken 451 times.
44009 for(int iter = local_monomer_text.length() - 1; iter >= 0; --iter)
1383 {
1384
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 43558 times.
43558 QChar curChar = local_monomer_text.at(iter);
1385
1386
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 43558 times.
43558 if(curChar == QChar::Tabulation || curChar == QChar::LineFeed ||
1387 curChar == QChar::FormFeed || curChar == QChar::CarriageReturn ||
1388 curChar == QChar::Space || curChar == QChar::Nbsp ||
1389 curChar == QChar::SoftHyphen)
1390 local_monomer_text.remove(iter, 1);
1391 }
1392
1393 451 return local_monomer_text;
1394 }
1395
1396 /*!
1397 \brief Stores the Monomer instance pointer \a monomer_sp in the member container
1398 and returns the Uuid string associated to it.
1399 */
1400 QString
1401 29184 Sequence::storeMonomer(const MonomerSPtr &monomer_sp)
1402 {
1403
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29184 times.
29184 if(monomer_sp == nullptr)
1404 qFatalStream() << "The provided MonomerSPtr is nullptr.";
1405
1406 // qDebug() << "Right before storage, there are currently" <<
1407 // m_monomers.size()
1408 // << "monomers.";
1409
1410 // Do not store an item twice.
1411
3/6
✓ Branch 1 taken 29184 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 29184 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 29184 times.
58368 if(hasMonomer(monomer_sp) || !getUuidForMonomer(monomer_sp).isEmpty())
1412 qFatalStream()
1413 << "It is prohibited to store the same MonomerCstSPtr more than once.";
1414
1415 // Even if we get a ref to shared_ptr, the reference count increment will
1416 // occur.
1417 29184 m_monomers.push_back(monomer_sp);
1418
1419 29184 QString uuid = QUuid::createUuid().toString();
1420
1421
1/2
✓ Branch 2 taken 29184 times.
✗ Branch 3 not taken.
29184 m_uuidMonomerPairs.push_back(UuidMonomerWPtrPair(uuid, monomer_sp));
1422
1423 // qDebug() << "Right after storage, there are currently" << m_monomers.size()
1424 // << "monomers.";
1425
1426 29184 return uuid;
1427 }
1428
1429 /*!
1430 \brief Stores the Monomer instance pointer in the member container and returns
1431 the Uuid string associated to it.
1432 */
1433 QString
1434 8 Sequence::storeMonomer(const MonomerSPtr &monomer_sp, std::size_t index)
1435 {
1436
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if(monomer_sp == nullptr)
1437 qFatalStream() << "The provided MonomerSPtr is nullptr.";
1438
1439 // qDebug() << "Right before storage, there are currently" <<
1440 // m_monomers.size()
1441 // << "monomers.";
1442
1443 // Do not store an item twice.
1444
3/6
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 8 times.
16 if(hasMonomer(monomer_sp) || !getUuidForMonomer(monomer_sp).isEmpty())
1445 qFatalStream()
1446 << "It is prohibited to store the same MonomerCstSPtr more than once.";
1447
1448 // Even if we get a ref to shared_ptr, the reference count increment will
1449 // occur.
1450 8 m_monomers.emplace(m_monomers.begin() + index, monomer_sp);
1451 8 QString uuid = QUuid::createUuid().toString();
1452
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 m_uuidMonomerPairs.emplace(m_uuidMonomerPairs.begin() + index,
1453 16 UuidMonomerWPtrPair(uuid, monomer_sp));
1454
1455 // qDebug() << "Right after storage, there are currently" << m_monomers.size()
1456 // << "monomers.";
1457
1458 8 return uuid;
1459 }
1460
1461 /*!
1462 \brief Returns true if \a monomer_sp was found in the member container of
1463 Monomer instances, false otherwise.
1464 */
1465 bool
1466 58415 Sequence::hasMonomer(const MonomerSPtr &monomer_sp) const
1467 {
1468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58415 times.
58415 if(monomer_sp == nullptr)
1469 qFatalStream() << "Pointer cannot be nullptr.";
1470
1471 58415 std::vector<MonomerSPtr>::const_iterator the_iterator_cst =
1472 116830 std::find_if(m_monomers.cbegin(),
1473 m_monomers.cend(),
1474
5/10
✓ Branch 1 taken 58415 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 58415 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 58415 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 58415 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 58415 times.
✗ Branch 15 not taken.
350490 [monomer_sp](const MonomerSPtr &the_monomer_csp) {
1475
13/14
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1418587 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1418584 times.
✓ Branch 4 taken 7 times.
✓ Branch 5 taken 1418577 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 1418574 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 14488 times.
✓ Branch 10 taken 7 times.
✓ Branch 11 taken 29005 times.
✓ Branch 12 taken 8 times.
✓ Branch 13 taken 43564 times.
1505662 return the_monomer_csp == monomer_sp;
1476 });
1477
1478
2/2
✓ Branch 0 taken 58384 times.
✓ Branch 1 taken 31 times.
58415 if(the_iterator_cst == m_monomers.cend())
1479 58384 return false;
1480
1481 // No sanity checks with getMonomerFromUuid() or getUuidForMonomer()
1482 // because that makes circular calls (these functions make sanity
1483 // checks by calling this hasMonomer().)
1484
1485 return true;
1486 }
1487
1488 /*!
1489 \brief Returns true if \a monomer_sp was found in the member container of
1490 Uuid-Monomer pairs, false otherwise.
1491 */
1492 bool
1493 Sequence::hasUuid(const MonomerSPtr &monomer_sp) const
1494 {
1495 if(monomer_sp == nullptr)
1496 qFatalStream() << "Pointer cannot be nullptr.";
1497
1498 std::vector<UuidMonomerWPtrPair>::const_iterator the_iterator_cst =
1499 std::find_if(m_uuidMonomerPairs.cbegin(),
1500 m_uuidMonomerPairs.cend(),
1501 [monomer_sp](const UuidMonomerWPtrPair &the_pair) {
1502 return the_pair.second.lock() == monomer_sp;
1503 });
1504
1505 if(the_iterator_cst == m_uuidMonomerPairs.cend())
1506 return false;
1507
1508 // Sanity check
1509 if(!hasMonomer(monomer_sp))
1510 qFatalStream()
1511 << "Inconsistency between m_monomers and m_uuidMonomerPairs.";
1512
1513 return true;
1514 }
1515
1516 /*!
1517 \brief Returns the Monomer instance pointer in the member container that is
1518 associated to the \a uuid Uuid string.
1519
1520 If no such Monomer instance pointer is found, nullptr is returned.
1521 */
1522 MonomerSPtr
1523 Sequence::getMonomerForUuid(const QString &uuid) const
1524 {
1525 // qDebug() << "There are currently" << m_monomers.size()
1526 // << "monomers. The uuid that is asked for:" << uuid;
1527
1528 std::vector<std::pair<QString, MonomerWPtr>>::const_iterator
1529 the_iterator_cst =
1530 std::find_if(m_uuidMonomerPairs.cbegin(),
1531 m_uuidMonomerPairs.cend(),
1532 [uuid](const UuidMonomerWPtrPair &the_pair) {
1533 return the_pair.first == uuid;
1534 });
1535
1536 if(the_iterator_cst == m_uuidMonomerPairs.cend())
1537 return nullptr;
1538
1539 MonomerSPtr monomer_csp = (*the_iterator_cst).second.lock();
1540
1541 // Sanity check
1542
1543 if(!hasMonomer(monomer_csp))
1544 qFatalStream()
1545 << "Inconsistency between m_monomers and m_uuidMonomerPairs.";
1546
1547 // qDebug() << "Found Monomer:" << monomer_csp->getCode()
1548 // << "with modification status:" << monomer_csp->isModified();
1549
1550 return monomer_csp;
1551 }
1552
1553 /*!
1554 \brief Returns the UUID string identifying \a monomer_sp in the member
1555 container.
1556
1557 If no such Monomer is found, an empty string is returned.
1558 */
1559 QString
1560 29196 Sequence::getUuidForMonomer(const MonomerSPtr &monomer_sp) const
1561 {
1562
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29196 times.
29196 if(monomer_sp == nullptr)
1563 qFatalStream() << "Programming error. Pointer cannot be nullptr.";
1564
1565 29196 std::vector<UuidMonomerWPtrPair>::const_iterator the_iterator_cst =
1566 58392 std::find_if(m_uuidMonomerPairs.cbegin(),
1567 m_uuidMonomerPairs.cend(),
1568
5/10
✓ Branch 2 taken 29196 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 29196 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 29196 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 29196 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 29196 times.
✗ Branch 16 not taken.
175176 [monomer_sp](const UuidMonomerWPtrPair &the_pair) {
1569 // Do not query the monomer_sp managed object because it can
1570 // be nullptr!
1571
1/2
✓ Branch 1 taken 2885076 times.
✗ Branch 2 not taken.
2885076 return the_pair.second.lock() == monomer_sp;
1572 });
1573
1574
2/2
✓ Branch 0 taken 29192 times.
✓ Branch 1 taken 4 times.
29196 if(the_iterator_cst == m_uuidMonomerPairs.cend())
1575 {
1576 // Sanity check
1577
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 29192 times.
29192 if(hasMonomer(monomer_sp))
1578 qFatalStream() << "Inconsistency between the m_monomers and the "
1579 "m_uuidMonomerPairs vectors.";
1580
1581 29192 return QString();
1582 }
1583
1584 // Sanity check
1585
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if(!hasMonomer(monomer_sp))
1586 qFatalStream() << "Inconsistency between the m_monomers and the "
1587 "m_uuidMonomerPairs vectors.";
1588
1589
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
29200 return (*the_iterator_cst).first;
1590 }
1591
1592 /*!
1593 \brief Returns a container of QString instances that correspond to the UUID
1594 strings that identify all the Monomer instances involved in this Sequence.
1595
1596 If no Monomer is found, an empty container is returned.
1597 */
1598 std::vector<QString>
1599 Sequence::getAllMonomerUuids() const
1600 {
1601 std::vector<QString> the_uuid_strings;
1602
1603 for(const UuidMonomerWPtrPair &pair : m_uuidMonomerPairs)
1604 the_uuid_strings.push_back(pair.first);
1605
1606 // Sanity check
1607 if(the_uuid_strings.size() != m_monomers.size())
1608 qFatalStream()
1609 << "Inconsistency between the <object>_s and <uuid-object> pairs.";
1610
1611 return the_uuid_strings;
1612 }
1613
1614 /*!
1615 \brief Removes from the member container all the Monomer instance pointers that
1616 are not found to still be alive.
1617 */
1618 void
1619 8 Sequence::cleanupMonomers()
1620 {
1621 // qDebug() << "At beginning, count of UUID-Monomer pairs:"
1622 // << m_uuidMonomerPairs.size();
1623
1624 8 std::vector<UuidMonomerWPtrPair>::iterator the_iterator =
1625 8 m_uuidMonomerPairs.begin();
1626 8 std::vector<UuidMonomerWPtrPair>::iterator the_end_iterator =
1627 8 m_uuidMonomerPairs.end();
1628
1629
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 8 times.
35 while(the_iterator != the_end_iterator)
1630 {
1631 135 if((*the_iterator).second.expired() ||
1632
5/10
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 27 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 27 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 27 times.
81 (*the_iterator).second.lock() == nullptr ||
1633
2/6
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
54 !hasMonomer((*the_iterator).second.lock()))
1634 the_iterator = m_uuidMonomerPairs.erase(the_iterator);
1635 else
1636 27 ++the_iterator;
1637 }
1638
1639 // qDebug() << "At end, count of UUID-Monomer pairs:"
1640 // << m_uuidMonomerPairs.size();
1641 8 }
1642
1643 /*!
1644 \brief Returns a checksum calculated on this Sequence's portion contained in
1645 [\a index_start -- \a index_stop].
1646
1647 The sequence matching the [\a index_start -- \a index_stop] range is extracted
1648 from m_monomerText, with (\a with_modifs is true) or without (\a with_modifs is
1649 false) the monomer modifications. The checksum is computed on that extracted
1650 string.
1651
1652 Returns the checksum.
1653 */
1654 quint16
1655 6 Sequence::checksum(int index_start, int index_stop, bool with_modifs) const
1656 {
1657 // qDebug() << "index_start:" << index_start << "index_stop" << index_stop;
1658
1659
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if(!size())
1660 return 0;
1661
1662
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if(index_start > index_stop)
1663 std::swap(index_start, index_stop);
1664
1665 6 QString text = getSequence(index_start, index_stop, with_modifs);
1666
1667
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 QByteArray bytes = text.toUtf8();
1668
1669
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 quint16 checksum = qChecksum(QByteArrayView(bytes));
1670
1671 // qDebug() << __FILE__ << __LINE__
1672 // << "checksum:" << checksum;
1673
1674 6 return checksum;
1675 6 }
1676
1677 /*!
1678 \brief Reset this Sequence instance to default values.
1679 */
1680 void
1681 2 Sequence::clear()
1682 {
1683 2 m_monomers.clear();
1684
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 m_uuidMonomerPairs.clear();
1685
1686 2 m_isValid = false;
1687 2 }
1688
1689
1690 } // namespace libXpertMassCore
1691 } // namespace MsXpS
1692