GCC Code Coverage Report


source/XpertMassCore/src/
File: source/XpertMassCore/src/MassCollection.cpp
Date: 2025-11-20 01:41:33
Lines:
95/110
86.4%
Functions:
22/22
100.0%
Branches:
36/90
40.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 /////////////////////// Local includes
35 #include "MsXpS/libXpertMassCore/globals.hpp"
36 #include "MsXpS/libXpertMassCore/Utils.hpp"
37 #include "MsXpS/libXpertMassCore/MassCollection.hpp"
38
39
40 namespace MsXpS
41 {
42 namespace libXpertMassCore
43 {
44
45
46 /*!
47 \class MsXpS::libXpertMassCore::MassCollection
48 \inmodule libXpertMassCore
49 \ingroup XpertMassCoreUtilities
50 \inheaderfile MassCollection.hpp
51
52 \brief The MassCollection class provides a container for masses (as double
53 values) and for text representing thoses values.
54
55 The MassCollection class provides a container for masses (as double values) and
56 for text representing thoses values. Methods allow to create numerical mass
57 values starting for a text string representing mass values separated by newline
58 characters and, reciprocally, create a text string starting from all the mass
59 values.
60
61 The mass values are stored in a container (m_masses) and the text string is
62 stored in m_massText.
63 */
64
65
66 /*!
67 \variable MsXpS::libXpertMassCore::MassCollection::m_name
68
69 \brief The name associated to the MassCollection.
70 */
71
72 /*!
73 \variable MsXpS::libXpertMassCore::MassCollection::m_comment
74
75 \brief The comment associated to the MassCollection.
76 */
77
78 /*!
79 \variable MsXpS::libXpertMassCore::MassCollection::m_masses
80
81 \brief The container of mass double values.
82 */
83
84
85 /*!
86 \brief Constructs a MassCollection with \a name.
87
88 The instance is created in an invalid state.
89 */
90 1 MassCollection::MassCollection(const QString &name)
91 {
92 1 m_name = name;
93 1 }
94
95 /*!
96 \brief Constructs a MassCollection with \a name and \a mass_text.
97
98 The \a mass_text is the textual representation of the mass double values that is
99 parsed and converted to mass double values. After the parsing, this instance is
100 validated, and the result is set to m_isValid.
101 */
102 8 MassCollection::MassCollection(const QString &name, const QString &mass_text)
103 {
104 8 m_name = name;
105
106 8 ErrorList error_list;
107
108
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
8 if(textToMasses(mass_text, &error_list) == -1)
109 qCritical() << "Constructing a MassCollection with text not suitable for "
110 "representing mass double values.";
111
112 // Will set m_isValid to the right value.
113
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
8 if(!validate(&error_list))
114 qWarning() << "Constructing a MassCollection that does not validate "
115 "successfully, with errors:"
116 << Utils::joinErrorList(error_list, ", ");
117
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
8 }
118
119 /*!
120 \brief Constructs a MassCollection with \a name and \a masses.
121
122 The masses are copied to the member container without check.
123 If the masses container is non-empty, the m_isValid status is set to true, else
124 to false.
125 */
126 8 MassCollection::MassCollection(const QString &name,
127 8 const std::vector<double> &masses)
128 {
129 8 m_name = name;
130
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 m_masses = masses;
131
132 8 m_isValid = m_masses.size();
133
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
8 }
134
135 /*!
136 \brief Destructs this MassCollection.
137 */
138 18 MassCollection::~MassCollection()
139 {
140
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
36 }
141
142 /*!
143 \brief Constructs a MassCollection as a copy of \a other.
144 If the masses container is non-empty, the m_isValid status is set to true, else
145 to false.
146 */
147 1 MassCollection::MassCollection(const MassCollection &other)
148
3/6
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
3 : m_name(other.m_name), m_comment(other.m_comment), m_masses(other.m_masses)
149 {
150 1 m_isValid = m_masses.size();
151 1 }
152
153 /*!
154 \brief Assigns \a other to this MassCollection and returns a reference to this
155 object. If the masses are non-empty, the m_isValid status is set to true, else
156 to false.
157 */
158 MassCollection &
159 1 MassCollection::operator=(const MassCollection &other)
160 {
161
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(&other == this)
162 return *this;
163
164 1 m_name = other.m_name;
165 1 m_comment = other.m_comment;
166
167 1 m_masses = other.m_masses;
168
169 1 m_isValid = m_masses.size();
170
171 1 return *this;
172 }
173
174 /*!
175 \brief Sets the name to \a name.
176 */
177 void
178 8 MassCollection::setName(const QString &name)
179 {
180 8 m_name = name;
181 8 }
182
183 /*!
184 \brief Returns the name.
185 */
186 const QString &
187 3 MassCollection::getName() const
188 {
189 3 return m_name;
190 }
191
192
193 /*!
194 \brief Sets the comment to \a comment.
195 */
196 void
197 16 MassCollection::setComment(const QString &comment)
198 {
199 16 m_comment = comment;
200 16 }
201
202 /*!
203 \brief Returns the comment.
204 */
205 const QString &
206 3 MassCollection::getComment() const
207 {
208 3 return m_comment;
209 }
210
211 /*!
212 \brief Returns the size of the container of masses.
213 */
214 std::size_t
215 14 MassCollection::size() const
216 {
217 14 return m_masses.size();
218 }
219
220 /*!
221 \brief Returns a const reference to the container of masses.
222 */
223 const std::vector<double> &
224 18 MassCollection::getMassesCstRef() const
225 {
226 18 return m_masses;
227 }
228
229 /*!
230 \brief Returns a reference to the container of masses.
231 */
232 std::vector<double> &
233 4 MassCollection::getMassesRef()
234 {
235 4 return m_masses;
236 }
237
238
239 /*!
240 \brief Returns the mass at the \a index in the container.
241
242 An out of bounds index is fatal.
243 */
244 double
245 8 MassCollection::getMassAtIndex(std::size_t index) const
246 {
247
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if(index >= m_masses.size())
248 qFatalStream() << "Programming error. The index is out of bounds.";
249
250
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 return m_masses.at(index);
251 }
252
253
254 /*!
255 \brief Returns the count of masses successfully obtained by converting the \a
256 text to double values.
257
258 The text is first split at newline characters and each obtained string is
259 converted to a double value that is added to the container.
260
261 The mass container is first emptied and the validity status of the
262 MassCollection is set to false.
263
264 If the \a text is empty, this function returns 0.
265
266 If a conversion error is encountered, the faulty text element is appended to \a
267 error_list_p, the mass container is cleared, m_isValid is set to false and -1 is
268 returned.
269
270 If the container of masses is non-empty at the end of the conversion (without
271 error), then m_isValid is set to true and the container size is returned.
272 */
273 int
274 8 MassCollection::textToMasses(const QString &text, ErrorList *error_list_p)
275 {
276 // qDebug() << "Now converting textual masses to numerical masses:" << text;
277
278
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 qsizetype error_count = error_list_p->size();
279
280
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 m_masses.clear();
281 8 m_isValid = false;
282
283
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if(text.isEmpty())
284 return 0;
285
286
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
8 QStringList lines = text.split("\n", Qt::SkipEmptyParts);
287 8 QString line;
288
289
2/2
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 8 times.
40 foreach(line, lines)
290 {
291 32 bool ok;
292
1/2
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
32 double value = line.toDouble(&ok);
293
294
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 if(!ok)
295 {
296 qCritical() << "This text element failed to convert to double:"
297 << line;
298 error_list_p->push_back(line);
299 break;
300 }
301
302
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 24 times.
64 m_masses.push_back(value);
303 }
304
305
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if(error_list_p->size() - error_count)
306 {
307 m_masses.clear();
308 return -1;
309 }
310
311
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if(m_masses.size())
312 8 m_isValid = true;
313
314 8 qDebug() << "Converted to double " << m_masses.size() << "masses";
315
316 8 return m_masses.size();
317 8 }
318
319 /*!
320 \brief Returns a text string representing the mass double values in the
321 container all separated with a newline character.
322 */
323 QString
324 2 MassCollection::massesToText()
325 {
326 2 QString text;
327
328
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
10 for(double mass : m_masses)
329
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
16 text += QString("%1\n").arg(mass, 0, 'f', OLIGOMER_DEC_PLACES);
330
331 2 return text;
332 }
333
334 /*!
335 \brief Sorts the masses in the container in ascending order.
336 */
337 void
338 2 MassCollection::sortAscending()
339 {
340 2 std::sort(m_masses.begin(), m_masses.end());
341 2 }
342
343 /*!
344 \brief Sorts the masses in the container in descending order.
345 */
346 void
347 3 MassCollection::sortDescending()
348 {
349 3 std::sort(m_masses.begin(), m_masses.end(), std::greater<double>());
350 3 }
351
352 /*!
353 \brief Adds \a mass to each mass in the container.
354 */
355 void
356 1 MassCollection::addMass(double mass)
357 {
358
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for(double &iter_mass : m_masses)
359 4 iter_mass += mass;
360 1 }
361
362 /*!
363 \brief Removes from the container all mass values strictly below \a threshold.
364 */
365 void
366 1 MassCollection::removeLessThan(double threshold)
367 {
368 1 std::vector<double>::iterator the_iterator = m_masses.begin();
369 1 std::vector<double>::iterator the_end_iterator = m_masses.end();
370
371
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
6 while(the_iterator != the_end_iterator)
372 {
373
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 if((*the_iterator) < threshold)
374 1 the_iterator = m_masses.erase(the_iterator);
375 else
376 4 ++the_iterator;
377 }
378 1 }
379
380
381 /*!
382 \brief Validates this MassCollection and returns true if successful or false
383 otherwise.
384
385 Upon validation, error messages are set to \a error_list_p (not emptied).
386
387 If validation is successful, the m_isValid validity status is set to true, to
388 false otherwise.
389 */
390 bool
391 9 MassCollection::validate(ErrorList *error_list_p) const
392 {
393
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 qsizetype error_count = error_list_p->size();
394
395
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if(!m_masses.size())
396 error_list_p->push_back(
397 "This MassCollection does not validate successfully: there are no "
398 "masses.");
399
400 9 m_isValid = error_count != error_list_p->size() ? false : true;
401 9 return m_isValid;
402 }
403
404 /*!
405 \brief Returns the validity status of this MassCollection.
406 */
407 bool
408 3 MassCollection::isValid() const
409 {
410 3 return m_isValid;
411 }
412
413
414 } // namespace libXpertMassCore
415 } // namespace MsXpS
416