GCC Code Coverage Report


source/XpertMassCore/src/
File: source/XpertMassCore/src/Sequence.cpp
Date: 2025-11-19 15:26:11
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 15 Sequence::Sequence()
92 {
93 15 }
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 540 Sequence::Sequence(PolChemDefCstSPtr pol_chem_def_csp,
113 540 const QString &sequence_text)
114
1/2
✓ Branch 2 taken 540 times.
✗ Branch 3 not taken.
540 : mcsp_polChemDef(pol_chem_def_csp)
115 {
116 // qDebug() << "The sequence_text:" << sequence_text;
117
118 540 std::vector<std::size_t> failing_indices;
119
120
1/2
✓ Branch 1 taken 540 times.
✗ Branch 2 not taken.
540 makeMonomers(sequence_text, /*reset*/ true, failing_indices);
121
122
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 531 times.
540 if(failing_indices.size())
123 {
124 9 QString indices_text;
125
126
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 for(std::size_t index : failing_indices)
127
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
18 indices_text += QString("%1, ").arg(index);
128
129
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
18 qCritical()
130
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 << "There were errors making the monomers at the following indices:"
131
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 << indices_text;
132 9 }
133 else
134 531 m_isValid = true;
135
0/2
✗ Branch 2 not taken.
✗ Branch 3 not taken.
540 }
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 45 Sequence::Sequence(const Sequence &other)
144 {
145 45 mcsp_polChemDef = other.mcsp_polChemDef;
146
147
2/2
✓ Branch 0 taken 5337 times.
✓ Branch 1 taken 45 times.
5382 for(const MonomerSPtr &monomer_sp : other.m_monomers)
148
1/2
✓ Branch 1 taken 5337 times.
✗ Branch 2 not taken.
10674 storeMonomer(monomer_sp);
149
150 // qDebug() << "The number of Monomer instances:" << m_monomers.size();
151
152 45 ErrorList error_list;
153
1/2
✓ Branch 1 taken 45 times.
✗ Branch 2 not taken.
45 m_isValid = validate(&error_list);
154
155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
45 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.
45 }
161
162 /*!
163 \brief Destructs this sequence.
164 */
165 1098 Sequence::~Sequence()
166 {
167 1098 m_monomers.clear();
168
2/2
✓ Branch 2 taken 540 times.
✓ Branch 3 taken 9 times.
1098 }
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 3 Sequence::setPolChemDefCstSPtr(PolChemDefCstSPtr pol_chem_def_csp)
178 {
179 3 mcsp_polChemDef = pol_chem_def_csp;
180 3 }
181
182 /*!
183 \brief Returns the polymer chemistry definition.
184 */
185 PolChemDefCstSPtr
186 6 Sequence::getPolChemDef() const
187 {
188 6 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 21 Sequence::setSequence(const QString &sequence,
213 std::vector<std::size_t> &failing_indices)
214 {
215
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 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 21 times.
21 if(!mcsp_polChemDef->isValid())
221 {
222 qFatalStream() << "Programming error. The PolChemDef is not valid.";
223 }
224
225 21 m_monomers.clear();
226
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 15 times.
21 m_uuidMonomerPairs.clear();
227
228 21 int result = appendSequence(sequence, failing_indices);
229
230 21 ErrorList error_list;
231
232
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
21 m_isValid = validate(&error_list);
233 21 {
234
2/4
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
21 qCritical() << "The Sequence is not valid, with errors:"
235
3/6
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 21 times.
✗ Branch 8 not taken.
42 << Utils::joinErrorList(error_list, ", ");
236 }
237
238 21 return result;
239 21 }
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 423 Sequence::appendSequence(const QString &sequence,
257 std::vector<std::size_t> &failing_indices)
258 {
259
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 423 times.
423 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 423 times.
423 if(!mcsp_polChemDef->isValid())
263 qFatalStream() << "The PolChemDef is not valid!";
264
265
2/2
✓ Branch 0 taken 414 times.
✓ Branch 1 taken 9 times.
423 if(sequence.isEmpty())
266 return 0;
267
268 414 QString unspacified_sequence = unspacifySequence(sequence);
269
270 414 int result =
271
1/2
✓ Branch 1 taken 414 times.
✗ Branch 2 not taken.
414 makeMonomers(unspacified_sequence, /*reset*/ false, failing_indices);
272
273
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 414 times.
414 if(result <= 0)
274 {
275 qCritical() << "The sequence could not be converted into Monomer "
276 "instances (error or empty sequence).";
277 }
278
279 414 ErrorList error_list;
280
281
1/2
✓ Branch 1 taken 414 times.
✗ Branch 2 not taken.
414 m_isValid = validate(&error_list);
282 414 {
283
2/4
✓ Branch 1 taken 414 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 414 times.
✗ Branch 5 not taken.
414 qCritical() << "The Sequence is not valid, with errors:"
284
3/6
✓ Branch 1 taken 414 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 414 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 414 times.
✗ Branch 8 not taken.
828 << Utils::joinErrorList(error_list, ", ");
285 }
286
287 414 return result;
288 414 }
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 127 Sequence::getSequence() const
296 {
297 127 QString sequence;
298
299
2/2
✓ Branch 0 taken 19471 times.
✓ Branch 1 taken 127 times.
19598 for(const MonomerSPtr &monomer_sp : m_monomers)
300
1/2
✓ Branch 1 taken 19471 times.
✗ Branch 2 not taken.
38942 sequence += monomer_sp->getCode();
301
302 127 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 39 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 39 times.
39 if(!size())
329 {
330 return QString();
331 }
332
333
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 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 39 std::size_t local_stop = stop_index + 1;
339
340
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
39 if(local_stop > size())
341 local_stop = size();
342
343 39 QString text;
344
345
2/2
✓ Branch 0 taken 3099 times.
✓ Branch 1 taken 39 times.
3138 for(std::size_t iter = start_index; iter < local_stop; ++iter)
346 {
347
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3099 times.
3099 MonomerSPtr monomer_sp = m_monomers.at(iter);
348
349 // qDebug() << "Iterating in Monomer:" << monomer_sp->getCode();
350
351
5/6
✓ Branch 0 taken 1530 times.
✓ Branch 1 taken 1569 times.
✓ Branch 3 taken 1530 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
✓ Branch 6 taken 1518 times.
3099 if(with_modif && monomer_sp->isModified())
352 {
353
3/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 12 times.
24 for(const ModifSPtr &modif_sp : monomer_sp->getModifsCstRef())
354
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 text += QString("%1<%2>")
355
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
24 .arg(monomer_sp->getCode())
356
2/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
36 .arg(modif_sp->getName());
357 }
358 else
359
1/4
✓ Branch 1 taken 3087 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
6174 text += monomer_sp->getCode();
360 3099 }
361
362 39 return text;
363 39 }
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 12 Sequence::getSequence(const IndexRangeCollection &index_ranges,
388 bool with_modif,
389 bool delimited_regions) const
390 {
391 12 QString text;
392
393
3/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 12 times.
24 for(const IndexRange *item : index_ranges.getRangesCstRef())
394 {
395 12 QString sequence_string =
396
1/2
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
12 getSequence(item->m_start, item->m_stop, with_modif);
397
398
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 9 times.
12 if(delimited_regions)
399
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 text += QString("Region [%1-%2]: %3\n")
400
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 .arg(item->m_start + 1)
401
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 .arg(item->m_stop + 1)
402
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
9 .arg(sequence_string);
403 else
404
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
12 text += sequence_string;
405 12 }
406
407 // Removed because this is unnecessary.
408 // text += QString("\n");
409
410 12 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 954 Sequence::makeMonomers(const QString &sequence_text,
436 bool reset,
437 std::vector<std::size_t> &failing_indices)
438 {
439
3/4
✓ Branch 0 taken 939 times.
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 939 times.
1893 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr ||
440 939 !mcsp_polChemDef->isValid())
441 {
442
1/2
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 qCritical() << "The PolChemDef pointer is nullptr or not valid!";
443 15 m_isValid = false;
444 15 return -1;
445 }
446
447
2/2
✓ Branch 0 taken 525 times.
✓ Branch 1 taken 414 times.
939 if(reset)
448 525 m_monomers.clear();
449
450
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 939 times.
939 failing_indices.clear();
451
452 939 QString local_sequence_text = unspacifySequence(sequence_text);
453
454 // qDebug() << "Sequence:" << local_sequence_text;
455
456 939 std::size_t index = 0;
457 939 int ret = -1;
458 939 QString err;
459 939 QString code;
460
461
1/2
✓ Branch 1 taken 939 times.
✗ Branch 2 not taken.
939 ret = nextCode(local_sequence_text, code, index, err);
462
463 77712 while(true)
464 {
465
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 77703 times.
77712 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 9 times.
9 failing_indices.push_back(index);
470 9 ++index;
471
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 ret = nextCode(local_sequence_text, code, index, err);
472
473 9 continue;
474 }
475
476
2/2
✓ Branch 0 taken 76764 times.
✓ Branch 1 taken 939 times.
77703 if(ret == 0)
477 break;
478
479
2/4
✓ Branch 1 taken 76764 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 76764 times.
✗ Branch 6 not taken.
153528 Monomer monomer(mcsp_polChemDef, "", code);
480
481 76764 MonomerSPtr pol_chem_def_monomer_csp =
482
1/2
✓ Branch 1 taken 76764 times.
✗ Branch 2 not taken.
76764 mcsp_polChemDef->getMonomerCstSPtrByCode(code);
483
484
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 76764 times.
76764 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 76764 times.
✗ Branch 2 not taken.
76764 monomer = *pol_chem_def_monomer_csp;
498
3/8
✓ Branch 1 taken 76764 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 76764 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 76764 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
153528 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 76764 ++index;
506
2/4
✓ Branch 1 taken 76764 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 76764 times.
✗ Branch 4 not taken.
76764 ret = nextCode(local_sequence_text, code, index, err);
507 76764 }
508 // End of
509 // while(true)
510
511
2/2
✓ Branch 0 taken 930 times.
✓ Branch 1 taken 9 times.
939 if(failing_indices.size())
512 return -1;
513
514 930 if(ret == -1)
515 return -1;
516
517 930 return m_monomers.size();
518 939 }
519
520 /*!
521 \brief Returns a const reference to the Monomer container.
522 */
523 const std::vector<MonomerSPtr> &
524 774 Sequence::getMonomersCstRef() const
525 {
526 774 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 108 Sequence::getMonomerCstRPtrAt(std::size_t index) const
558 {
559
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if(index >= m_monomers.size())
560 qFatalStream() << "Index is out of bounds.";
561
562
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 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 121905 Sequence::getMonomerCstSPtrAt(std::size_t index) const
588 {
589
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 121905 times.
121905 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 121905 times.
121905 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 6 Sequence::getMonomerSPtrAt(std::size_t index)
604 {
605
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if(index >= m_monomers.size())
606 qFatalStream() << "Index is out of bounds.";
607
608
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 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 3 Sequence::monomerIndex(MonomerSPtr monomer_sp, bool &ok) const
622 {
623 3 std::vector<MonomerSPtr>::const_iterator the_iterator_cst =
624 6 std::find_if(m_monomers.cbegin(),
625 m_monomers.cend(),
626
3/6
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
9 [monomer_sp](const MonomerSPtr &iter_monomer_sp) {
627
5/14
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 117 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 117 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 117 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
120 return iter_monomer_sp == monomer_sp;
628 });
629
630
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if(the_iterator_cst != m_monomers.cend())
631 {
632 ok = true;
633 return std::distance(m_monomers.cbegin(), the_iterator_cst);
634 }
635
636 3 ok = false;
637 3 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 24 Sequence::monomerIndex(MonomerCstSPtr monomer_csp, bool &ok) const
651 {
652 24 std::vector<MonomerSPtr>::const_iterator the_iterator_cst =
653 48 std::find_if(m_monomers.cbegin(),
654 m_monomers.cend(),
655
3/6
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 24 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 24 times.
✗ Branch 9 not taken.
72 [monomer_csp](const MonomerSPtr &iter_monomer_sp) {
656
6/14
✗ Branch 0 not taken.
✓ Branch 1 taken 408 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 408 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 396 times.
✓ Branch 6 taken 12 times.
✓ Branch 7 taken 384 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.
408 return iter_monomer_sp == monomer_csp;
657 });
658
659
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if(the_iterator_cst != m_monomers.cend())
660 {
661 24 ok = true;
662 24 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 21084 Sequence::monomerIndex(MonomerCstRPtr monomer_crp, bool &ok) const
680 {
681
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21084 times.
21084 if(monomer_crp == nullptr)
682 qFatalStream() << "Programming error. Pointer cannot be nullptr.";
683
684 21084 std::vector<MonomerSPtr>::const_iterator the_iterator_cst =
685
1/2
✓ Branch 0 taken 21084 times.
✗ Branch 1 not taken.
21084 std::find_if(m_monomers.cbegin(),
686 m_monomers.cend(),
687 5490333 [monomer_crp](const MonomerSPtr &iter_monomer_sp) {
688
7/14
✓ Branch 0 taken 5340 times.
✓ Branch 1 taken 1372509 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1372509 times.
✓ Branch 4 taken 5043 times.
✓ Branch 5 taken 1367466 times.
✓ Branch 6 taken 10701 times.
✓ Branch 7 taken 1356765 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.
1377849 return iter_monomer_sp.get() == monomer_crp;
689 });
690
691
1/2
✓ Branch 0 taken 21084 times.
✗ Branch 1 not taken.
21084 if(the_iterator_cst != m_monomers.cend())
692 {
693 21084 ok = true;
694 21084 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 77730 Sequence::nextCode(const QString &sequence,
715 QString &code,
716 std::size_t &index,
717 QString &err)
718 {
719
2/4
✓ Branch 0 taken 77730 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 77730 times.
155460 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr ||
720 77730 !mcsp_polChemDef->isValid())
721 qFatalStream()
722 << "Programming error. It is not possible that the PolChemDef be "
723 "undefined or invalid.";
724
725 77730 QString new_code;
726 77730 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 77730 code.clear();
741 77730 err.clear();
742
743 77730 std::size_t sequence_length = sequence.length();
744
745 233418 while(1)
746 {
747
3/4
✓ Branch 1 taken 155574 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 76782 times.
✓ Branch 4 taken 78792 times.
155574 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 76782 --iter;
758 76782 break;
759 }
760
761
2/2
✓ Branch 0 taken 77853 times.
✓ Branch 1 taken 939 times.
78792 if(iter + index >= sequence_length)
762 break;
763
764
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 77844 times.
77853 QChar curChar = sequence.at(iter + index);
765
766
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 77844 times.
77853 if(!curChar.isLetter())
767 {
768 // qDebug() << __FILE__ << __LINE__
769 // << "The character is not a letter:"
770 // << curChar;
771
772
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 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 9 index = index + iter;
784
785 77739 return -1;
786 }
787
788
2/2
✓ Branch 0 taken 76782 times.
✓ Branch 1 taken 1062 times.
77844 bool isLower = (curChar.category() == QChar::Letter_Lowercase);
789
790
2/2
✓ Branch 0 taken 76782 times.
✓ Branch 1 taken 1062 times.
77844 if(iter == 0)
791 {
792
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 76782 times.
76782 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 76782 times.
✗ Branch 2 not taken.
76782 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 1062 times.
✗ Branch 1 not taken.
1062 if(isLower)
818
1/2
✓ Branch 1 taken 1062 times.
✗ Branch 2 not taken.
1062 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 77844 ++iter;
831 77844 }
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 77721 index = index + iter;
842 77721 code = new_code;
843 77721 err.clear();
844
845 77721 return code.length();
846 77730 }
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 30 Sequence::insertMonomerAt(const Monomer &monomer, std::size_t index)
863 {
864
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
30 if(index > size())
865 qFatalStream() << "Programming error. Index is out of bounds:" << index;
866
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 24 times.
30 else if(index == size())
867
1/2
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
12 return storeMonomer(std::make_shared<Monomer>(monomer));
868 else
869
1/2
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
48 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 12 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 12 times.
12 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 12 times.
12 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 12 times.
✗ Branch 2 not taken.
12 QString uuid = getUuidForMonomer(monomer_sp);
902
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if(uuid.isEmpty())
903 qFatalStream()
904 << "Inconsistency between m_monomers and m_uuidMonomerPairs.";
905
906
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 std::vector<UuidMonomerWPtrPair>::const_iterator the_iterator_cst =
907 24 std::find_if(m_uuidMonomerPairs.cbegin(),
908 m_uuidMonomerPairs.cend(),
909
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
60 [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 240 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 240 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 228 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 228 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.
240 return the_pair.first == uuid;
913 });
914
915
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if(the_iterator_cst == m_uuidMonomerPairs.cend())
916 qFatalStream()
917 << "Inconsistency between m_monomers and m_uuidMonomerPairs.";
918
919 12 m_uuidMonomerPairs.erase(the_iterator_cst);
920 12 m_monomers.erase(m_monomers.begin() + index);
921
922 // qDebug() << "Done removing Monomer.";
923
924 12 return true;
925
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
24 }
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 6 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 6 times.
6 if(index >= size())
946 qFatalStream() << "Programming error. Index is out of bounds.";
947
948 6 MonomerSPtr monomer_sp = getMonomerSPtrAt(index);
949
950 6 ErrorList error_list;
951
952
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 QString uuid = monomer_sp->modify(modif_name, override, &error_list);
953
954
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 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 6 times.
✗ Branch 2 not taken.
12 }
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 108 Sequence::hasModifiedMonomer(std::size_t left_index,
972 std::size_t right_index) const
973 {
974
2/4
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 108 times.
108 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 108 times.
108 if(left_index > right_index)
978 qFatal("Programming error. Indices are not correct.");
979
980
1/2
✓ Branch 0 taken 1404 times.
✗ Branch 1 not taken.
1404 for(std::size_t iter = left_index; iter <= right_index; ++iter)
981 {
982
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1404 times.
✓ Branch 3 taken 1296 times.
✓ Branch 4 taken 108 times.
1404 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 108 Sequence::modifiedMonomerIndices(std::size_t left_index,
1000 std::size_t right_index) const
1001 {
1002
2/4
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 108 times.
108 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 108 times.
108 if(left_index > right_index)
1006 qFatal("Programming error. Indices are not correct.");
1007
1008 108 std::vector<std::size_t> indices;
1009
1010
2/2
✓ Branch 0 taken 16956 times.
✓ Branch 1 taken 108 times.
17064 for(std::size_t iter = left_index; iter <= right_index; ++iter)
1011 {
1012
4/6
✗ Branch 0 not taken.
✓ Branch 1 taken 16956 times.
✓ Branch 3 taken 16956 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 108 times.
✓ Branch 6 taken 16848 times.
16956 if(m_monomers.at(iter)->isModified())
1013
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
17064 indices.push_back(iter);
1014 }
1015
1016 108 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 78 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 78 times.
78 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 78 times.
78 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 78 times.
78 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 72 times.
✓ Branch 2 taken 6 times.
78 if(index >= size())
1065 return -1;
1066
1067 72 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 3 times.
✓ Branch 1 taken 69 times.
72 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 3 times.
✓ Branch 2 taken 66 times.
69 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 66 bool matched = false;
1085 66 int matchIndex = 0;
1086
1087
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 4257 times.
4263 for(std::size_t iter = index; iter < size(); ++iter)
1088 {
1089 4257 std::size_t jter = 0;
1090
1091 4257 const MonomerSPtr monomer_sp = getMonomerCstSPtrAt(iter);
1092 4257 const MonomerSPtr motif_monomer_sp =
1093
1/2
✓ Branch 1 taken 4257 times.
✗ Branch 2 not taken.
4257 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 4257 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4257 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 3876 times.
✓ Branch 9 taken 381 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
4257 if(monomer_sp->getCode() != motif_monomer_sp->getCode())
1102 3876 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 381 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 381 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 378 times.
381 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 3 matched = false;
1131
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 break;
1132 }
1133
1134 // qDebug() << monomer_p->getCode()
1135 // << "found at sequence iter index: " << iter;
1136
1137 378 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 378 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 789 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 732 times.
✓ Branch 4 taken 57 times.
789 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 732 times.
✗ Branch 2 not taken.
732 const MonomerSPtr monomer_sp = getMonomerCstSPtrAt(iter + kter);
1157 732 const MonomerSPtr motif_monomer_sp =
1158
1/2
✓ Branch 1 taken 732 times.
✗ Branch 2 not taken.
732 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 732 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 732 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 411 times.
✓ Branch 9 taken 321 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
732 if(monomer_sp->getCode() == motif_monomer_sp->getCode())
1168 {
1169 // The monomers still match.
1170 411 matched = true;
1171 // qDebug() << "still matching";
1172
1/2
✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
411 continue;
1173 }
1174 else
1175 {
1176 321 matched = false;
1177 // qDebug() << "not matching anymore";
1178
1/2
✓ Branch 0 taken 321 times.
✗ Branch 1 not taken.
321 break;
1179 }
1180
2/4
✓ Branch 0 taken 411 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 321 times.
✗ Branch 3 not taken.
1143 }
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 378 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 321 continue;
1198 }
1199 else
1200 {
1201 // The match indeed occurred.
1202
1203 57 index = matchIndex;
1204
1/2
✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
57 return 1;
1205 }
1206
3/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 57 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4197 times.
✗ Branch 5 not taken.
8514 }
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 21225 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.
21225 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 12 Sequence::isInBound(std::size_t index)
1234 {
1235
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 3 times.
12 if(index < size())
1236 9 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 51 Sequence::operator=(const Sequence &other)
1254 {
1255
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 12 times.
51 if(&other == this)
1256 return *this;
1257
1258 39 mcsp_polChemDef = other.mcsp_polChemDef;
1259
1260 39 m_monomers.clear();
1261
1262
2/2
✓ Branch 0 taken 5298 times.
✓ Branch 1 taken 39 times.
5337 for(const MonomerSPtr &monomer_sp : other.m_monomers)
1263 10596 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 96 Sequence::operator==(const Sequence &other)
1277 {
1278
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 81 times.
96 if(&other == this)
1279 return true;
1280
1281
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 81 times.
81 if(mcsp_polChemDef != other.mcsp_polChemDef)
1282 {
1283 qInfo() << "Differing PolChemDef.";
1284 return false;
1285 }
1286
1287
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 69 times.
81 if(m_monomers.size() != other.m_monomers.size())
1288 {
1289
1/2
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 qInfo() << "Differing Monomer container size.";
1290 12 return false;
1291 }
1292
1293
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 5655 times.
5712 for(std::size_t iter = 0; iter < other.m_monomers.size(); ++iter)
1294 {
1295
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 5655 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 5643 times.
5655 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 39 Sequence::operator!=(const Sequence &other)
1310 {
1311
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 3 times.
39 if(&other == this)
1312 return false;
1313
1314 36 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 897 Sequence::validate(ErrorList *error_list_p) const
1332 {
1333
2/2
✓ Branch 0 taken 825 times.
✓ Branch 1 taken 72 times.
897 qsizetype error_count = error_list_p->size();
1334
1335
3/4
✓ Branch 0 taken 825 times.
✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 825 times.
1722 if(mcsp_polChemDef == nullptr || mcsp_polChemDef.get() == nullptr ||
1336 825 !mcsp_polChemDef->isValid())
1337 {
1338
1/2
✓ Branch 2 taken 72 times.
✗ Branch 3 not taken.
72 qCritical() << "The PolChemDef is not available.";
1339 144 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 120189 times.
✓ Branch 1 taken 897 times.
121086 for(const MonomerSPtr &monomer_sp : m_monomers)
1345 {
1346
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 120189 times.
120189 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 897 m_isValid = (error_list_p->size() > error_count ? false : true);
1357 897 return m_isValid;
1358 }
1359
1360 /*!
1361 \brief Returns the validity status of this Sequence instance.
1362 */
1363 bool
1364 99 Sequence::isValid() const
1365 {
1366
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
99 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 1353 Sequence::unspacifySequence(const QString &monomer_text)
1377 {
1378 // Removal of all spaces, carriage returns and linefeeds:
1379
1380
2/2
✓ Branch 0 taken 1083 times.
✓ Branch 1 taken 270 times.
1353 QString local_monomer_text = monomer_text;
1381
1382
2/2
✓ Branch 0 taken 130674 times.
✓ Branch 1 taken 1353 times.
132027 for(int iter = local_monomer_text.length() - 1; iter >= 0; --iter)
1383 {
1384
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 130674 times.
130674 QChar curChar = local_monomer_text.at(iter);
1385
1386
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 130674 times.
130674 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 1353 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 87552 Sequence::storeMonomer(const MonomerSPtr &monomer_sp)
1402 {
1403
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 87552 times.
87552 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 87552 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 87552 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 87552 times.
175104 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 87552 m_monomers.push_back(monomer_sp);
1418
1419 87552 QString uuid = QUuid::createUuid().toString();
1420
1421
1/2
✓ Branch 2 taken 87552 times.
✗ Branch 3 not taken.
87552 m_uuidMonomerPairs.push_back(UuidMonomerWPtrPair(uuid, monomer_sp));
1422
1423 // qDebug() << "Right after storage, there are currently" << m_monomers.size()
1424 // << "monomers.";
1425
1426 87552 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 24 Sequence::storeMonomer(const MonomerSPtr &monomer_sp, std::size_t index)
1435 {
1436
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 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 24 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 24 times.
48 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 24 m_monomers.emplace(m_monomers.begin() + index, monomer_sp);
1451 24 QString uuid = QUuid::createUuid().toString();
1452
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 m_uuidMonomerPairs.emplace(m_uuidMonomerPairs.begin() + index,
1453 48 UuidMonomerWPtrPair(uuid, monomer_sp));
1454
1455 // qDebug() << "Right after storage, there are currently" << m_monomers.size()
1456 // << "monomers.";
1457
1458 24 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 175245 Sequence::hasMonomer(const MonomerSPtr &monomer_sp) const
1467 {
1468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 175245 times.
175245 if(monomer_sp == nullptr)
1469 qFatalStream() << "Pointer cannot be nullptr.";
1470
1471 175245 std::vector<MonomerSPtr>::const_iterator the_iterator_cst =
1472 350490 std::find_if(m_monomers.cbegin(),
1473 m_monomers.cend(),
1474
5/10
✓ Branch 1 taken 175245 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 175245 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 175245 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 175245 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 175245 times.
✗ Branch 15 not taken.
1051470 [monomer_sp](const MonomerSPtr &the_monomer_csp) {
1475
13/14
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 4255761 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 4255752 times.
✓ Branch 4 taken 21 times.
✓ Branch 5 taken 4255731 times.
✓ Branch 6 taken 9 times.
✓ Branch 7 taken 4255722 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 43464 times.
✓ Branch 10 taken 21 times.
✓ Branch 11 taken 87015 times.
✓ Branch 12 taken 24 times.
✓ Branch 13 taken 130692 times.
4516986 return the_monomer_csp == monomer_sp;
1476 });
1477
1478
2/2
✓ Branch 0 taken 175152 times.
✓ Branch 1 taken 93 times.
175245 if(the_iterator_cst == m_monomers.cend())
1479 175152 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 87588 Sequence::getUuidForMonomer(const MonomerSPtr &monomer_sp) const
1561 {
1562
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 87588 times.
87588 if(monomer_sp == nullptr)
1563 qFatalStream() << "Programming error. Pointer cannot be nullptr.";
1564
1565 87588 std::vector<UuidMonomerWPtrPair>::const_iterator the_iterator_cst =
1566 175176 std::find_if(m_uuidMonomerPairs.cbegin(),
1567 m_uuidMonomerPairs.cend(),
1568
5/10
✓ Branch 2 taken 87588 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 87588 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 87588 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 87588 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 87588 times.
✗ Branch 16 not taken.
525528 [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 8655228 times.
✗ Branch 2 not taken.
8655228 return the_pair.second.lock() == monomer_sp;
1572 });
1573
1574
2/2
✓ Branch 0 taken 87576 times.
✓ Branch 1 taken 12 times.
87588 if(the_iterator_cst == m_uuidMonomerPairs.cend())
1575 {
1576 // Sanity check
1577
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 87576 times.
87576 if(hasMonomer(monomer_sp))
1578 qFatalStream() << "Inconsistency between the m_monomers and the "
1579 "m_uuidMonomerPairs vectors.";
1580
1581 87576 return QString();
1582 }
1583
1584 // Sanity check
1585
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 if(!hasMonomer(monomer_sp))
1586 qFatalStream() << "Inconsistency between the m_monomers and the "
1587 "m_uuidMonomerPairs vectors.";
1588
1589
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
87600 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 24 Sequence::cleanupMonomers()
1620 {
1621 // qDebug() << "At beginning, count of UUID-Monomer pairs:"
1622 // << m_uuidMonomerPairs.size();
1623
1624 24 std::vector<UuidMonomerWPtrPair>::iterator the_iterator =
1625 24 m_uuidMonomerPairs.begin();
1626 24 std::vector<UuidMonomerWPtrPair>::iterator the_end_iterator =
1627 24 m_uuidMonomerPairs.end();
1628
1629
2/2
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 24 times.
105 while(the_iterator != the_end_iterator)
1630 {
1631 405 if((*the_iterator).second.expired() ||
1632
5/10
✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 81 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 81 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 81 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 81 times.
243 (*the_iterator).second.lock() == nullptr ||
1633
2/6
✓ Branch 2 taken 81 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 81 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
162 !hasMonomer((*the_iterator).second.lock()))
1634 the_iterator = m_uuidMonomerPairs.erase(the_iterator);
1635 else
1636 81 ++the_iterator;
1637 }
1638
1639 // qDebug() << "At end, count of UUID-Monomer pairs:"
1640 // << m_uuidMonomerPairs.size();
1641 24 }
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 18 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 18 times.
✗ Branch 2 not taken.
18 if(!size())
1660 return 0;
1661
1662
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if(index_start > index_stop)
1663 std::swap(index_start, index_stop);
1664
1665 18 QString text = getSequence(index_start, index_stop, with_modifs);
1666
1667
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 QByteArray bytes = text.toUtf8();
1668
1669
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 quint16 checksum = qChecksum(QByteArrayView(bytes));
1670
1671 // qDebug() << __FILE__ << __LINE__
1672 // << "checksum:" << checksum;
1673
1674 18 return checksum;
1675 18 }
1676
1677 /*!
1678 \brief Reset this Sequence instance to default values.
1679 */
1680 void
1681 6 Sequence::clear()
1682 {
1683 6 m_monomers.clear();
1684
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 m_uuidMonomerPairs.clear();
1685
1686 6 m_isValid = false;
1687 6 }
1688
1689
1690 } // namespace libXpertMassCore
1691 } // namespace MsXpS
1692