##// END OF EJS Templates
Inits merge method of two items
Alexandre Leroux -
r1031:b92faa6e4b21
parent child
Show More
@@ -0,0 +1,15
1 #ifndef SCIQLOP_DATASOURCEITEMMERGEHELPER_H
2 #define SCIQLOP_DATASOURCEITEMMERGEHELPER_H
3
4 class DataSourceItem;
5
6 /**
7 * @brief The DataSourceItemMergeHelper struct is used to merge two data source items
8 * @sa DataSourceItem::merge()
9 */
10 struct DataSourceItemMergeHelper {
11 /// Merges source item into dest item
12 static void merge(const DataSourceItem &source, DataSourceItem &dest);
13 };
14
15 #endif // SCIQLOP_DATASOURCEITEMMERGEHELPER_H
@@ -0,0 +1,8
1 #include "DataSource/DataSourceItemMergeHelper.h"
2
3 #include <DataSource/DataSourceItem.h>
4
5 void DataSourceItemMergeHelper::merge(const DataSourceItem &source, DataSourceItem &dest)
6 {
7 /// @todo ALX
8 }
@@ -1,110 +1,150
1 #ifndef SCIQLOP_DATASOURCEITEM_H
1 #ifndef SCIQLOP_DATASOURCEITEM_H
2 #define SCIQLOP_DATASOURCEITEM_H
2 #define SCIQLOP_DATASOURCEITEM_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <Common/spimpl.h>
6 #include <Common/spimpl.h>
7
7
8 #include <QVariant>
8 #include <QVariant>
9 #include <QVector>
9 #include <QVector>
10
10
11 class DataSourceItemAction;
11 class DataSourceItemAction;
12
12
13 /**
13 /**
14 * Possible types of an item
14 * Possible types of an item
15 */
15 */
16 enum class DataSourceItemType { NODE, PRODUCT, COMPONENT };
16 enum class DataSourceItemType { NODE, PRODUCT, COMPONENT };
17
17
18 /**
18 /**
19 * @brief The DataSourceItem class aims to represent a structure element of a data source.
19 * @brief The DataSourceItem class aims to represent a structure element of a data source.
20 * A data source has a tree structure that is made up of a main DataSourceItem object (root)
20 * A data source has a tree structure that is made up of a main DataSourceItem object (root)
21 * containing other DataSourceItem objects (children).
21 * containing other DataSourceItem objects (children).
22 * For each DataSourceItem can be associated a set of data representing it.
22 * For each DataSourceItem can be associated a set of data representing it.
23 */
23 */
24 class SCIQLOP_CORE_EXPORT DataSourceItem {
24 class SCIQLOP_CORE_EXPORT DataSourceItem {
25 public:
25 public:
26 /// Key associated with the name of the item
26 /// Key associated with the name of the item
27 static const QString NAME_DATA_KEY;
27 static const QString NAME_DATA_KEY;
28
28
29 explicit DataSourceItem(DataSourceItemType type, const QString &name);
29 explicit DataSourceItem(DataSourceItemType type, const QString &name);
30 explicit DataSourceItem(DataSourceItemType type, QVariantHash data = {});
30 explicit DataSourceItem(DataSourceItemType type, QVariantHash data = {});
31
31
32 /// @return the actions of the item as a vector
32 /// @return the actions of the item as a vector
33 QVector<DataSourceItemAction *> actions() const noexcept;
33 QVector<DataSourceItemAction *> actions() const noexcept;
34
34
35 /**
35 /**
36 * Adds an action to the item. The item takes ownership of the action, and the action is
36 * Adds an action to the item. The item takes ownership of the action, and the action is
37 * automatically associated to the item
37 * automatically associated to the item
38 * @param action the action to add
38 * @param action the action to add
39 */
39 */
40 void addAction(std::unique_ptr<DataSourceItemAction> action) noexcept;
40 void addAction(std::unique_ptr<DataSourceItemAction> action) noexcept;
41
41
42 /**
42 /**
43 * Adds a child to the item. The item takes ownership of the child.
43 * Adds a child to the item. The item takes ownership of the child.
44 * @param child the child to add
44 * @param child the child to add
45 */
45 */
46 void appendChild(std::unique_ptr<DataSourceItem> child) noexcept;
46 void appendChild(std::unique_ptr<DataSourceItem> child) noexcept;
47
47
48 /**
48 /**
49 * Returns the item's child associated to an index
49 * Returns the item's child associated to an index
50 * @param childIndex the index to search
50 * @param childIndex the index to search
51 * @return a pointer to the child if index is valid, nullptr otherwise
51 * @return a pointer to the child if index is valid, nullptr otherwise
52 */
52 */
53 DataSourceItem *child(int childIndex) const noexcept;
53 DataSourceItem *child(int childIndex) const noexcept;
54
54
55 int childCount() const noexcept;
55 int childCount() const noexcept;
56
56
57 /**
57 /**
58 * Get the data associated to a key
58 * Get the data associated to a key
59 * @param key the key to search
59 * @param key the key to search
60 * @return the data found if key is valid, default QVariant otherwise
60 * @return the data found if key is valid, default QVariant otherwise
61 */
61 */
62 QVariant data(const QString &key) const noexcept;
62 QVariant data(const QString &key) const noexcept;
63
63
64 /// Gets all data
64 /// Gets all data
65 QVariantHash data() const noexcept;
65 QVariantHash data() const noexcept;
66
66
67 /**
68 * Merge in the item the source item passed as parameter.
69 *
70 * The merge is done by adding as child of the item the complete tree represented by the source
71 * item. If a part of the tree already exists in the item (based on the name of the nodes), it
72 * is merged by completing the existing tree by items "leaves" (products, components or nodes
73 * with no child).
74 *
75 * For example, with item representing the tree:
76 * R (root node)
77 * - N1 (node)
78 * -- N11 (node)
79 * --- P1 (product)
80 * --- P2 (product)
81 * - N2 (node)
82 *
83 * and the source item representing the tree:
84 * N1 (root node)
85 * - N11 (node)
86 * -- P3 (product)
87 * - N12 (node)
88 *
89 * The leaves of the source item to merge into the item are N1/N11/P3 and N1/N12 => we therefore
90 * have the following merge result:
91 * R
92 * - N1
93 * -- N11
94 * --- P1
95 * --- P2
96 * --- P3 (added leaf)
97 * -- N12 (added leaf)
98 *
99 * @param item the source item
100 * @remarks No control is performed on products or components that are merged into the same tree
101 * part (two products or components may have the same name)
102 * @remarks the merge is made by copy (source item is not changed and still exists after the
103 * operation)
104 */
105 void merge(const DataSourceItem &item);
106
67 bool isRoot() const noexcept;
107 bool isRoot() const noexcept;
68
108
69 QString name() const noexcept;
109 QString name() const noexcept;
70
110
71 /**
111 /**
72 * Get the item's parent
112 * Get the item's parent
73 * @return a pointer to the parent if it exists, nullptr if the item is a root
113 * @return a pointer to the parent if it exists, nullptr if the item is a root
74 */
114 */
75 DataSourceItem *parentItem() const noexcept;
115 DataSourceItem *parentItem() const noexcept;
76
116
77 /**
117 /**
78 * Gets the item's root
118 * Gets the item's root
79 * @return the top parent, the item itself if it's the root item
119 * @return the top parent, the item itself if it's the root item
80 */
120 */
81 const DataSourceItem &rootItem() const noexcept;
121 const DataSourceItem &rootItem() const noexcept;
82
122
83 /**
123 /**
84 * Sets or appends a value to a key
124 * Sets or appends a value to a key
85 * @param key the key
125 * @param key the key
86 * @param value the value
126 * @param value the value
87 * @param append if true, the value is added to the values already existing for the key,
127 * @param append if true, the value is added to the values already existing for the key,
88 * otherwise it replaces the existing values
128 * otherwise it replaces the existing values
89 */
129 */
90 void setData(const QString &key, const QVariant &value, bool append = false) noexcept;
130 void setData(const QString &key, const QVariant &value, bool append = false) noexcept;
91
131
92 DataSourceItemType type() const noexcept;
132 DataSourceItemType type() const noexcept;
93
133
94 /**
134 /**
95 * @brief Searches the first child matching the specified data.
135 * @brief Searches the first child matching the specified data.
96 * @param data The data to search.
136 * @param data The data to search.
97 * @param recursive So the search recursively.
137 * @param recursive So the search recursively.
98 * @return the item matching the data or nullptr if it was not found.
138 * @return the item matching the data or nullptr if it was not found.
99 */
139 */
100 DataSourceItem *findItem(const QVariantHash &data, bool recursive);
140 DataSourceItem *findItem(const QVariantHash &data, bool recursive);
101
141
102 bool operator==(const DataSourceItem &other);
142 bool operator==(const DataSourceItem &other);
103 bool operator!=(const DataSourceItem &other);
143 bool operator!=(const DataSourceItem &other);
104
144
105 private:
145 private:
106 class DataSourceItemPrivate;
146 class DataSourceItemPrivate;
107 spimpl::unique_impl_ptr<DataSourceItemPrivate> impl;
147 spimpl::unique_impl_ptr<DataSourceItemPrivate> impl;
108 };
148 };
109
149
110 #endif // SCIQLOP_DATASOURCEITEMMODEL_H
150 #endif // SCIQLOP_DATASOURCEITEMMODEL_H
@@ -1,65 +1,66
1
1
2 core_moc_headers = [
2 core_moc_headers = [
3 'include/Data/IDataProvider.h',
3 'include/Data/IDataProvider.h',
4 'include/DataSource/DataSourceController.h',
4 'include/DataSource/DataSourceController.h',
5 'include/DataSource/DataSourceItemAction.h',
5 'include/DataSource/DataSourceItemAction.h',
6 'include/Network/NetworkController.h',
6 'include/Network/NetworkController.h',
7 'include/Time/TimeController.h',
7 'include/Time/TimeController.h',
8 'include/Variable/Variable.h',
8 'include/Variable/Variable.h',
9 'include/Variable/VariableCacheController.h',
9 'include/Variable/VariableCacheController.h',
10 'include/Variable/VariableController.h',
10 'include/Variable/VariableController.h',
11 'include/Variable/VariableAcquisitionWorker.h',
11 'include/Variable/VariableAcquisitionWorker.h',
12 'include/Variable/VariableSynchronizationGroup.h',
12 'include/Variable/VariableSynchronizationGroup.h',
13 'include/Variable/VariableModel.h',
13 'include/Variable/VariableModel.h',
14 'include/Visualization/VisualizationController.h'
14 'include/Visualization/VisualizationController.h'
15 ]
15 ]
16
16
17
17
18 core_moc_files = qt5.preprocess(moc_headers : core_moc_headers)
18 core_moc_files = qt5.preprocess(moc_headers : core_moc_headers)
19
19
20 core_sources = [
20 core_sources = [
21 'src/Common/DateUtils.cpp',
21 'src/Common/DateUtils.cpp',
22 'src/Common/StringUtils.cpp',
22 'src/Common/StringUtils.cpp',
23 'src/Common/MimeTypesDef.cpp',
23 'src/Common/MimeTypesDef.cpp',
24 'src/Data/ScalarSeries.cpp',
24 'src/Data/ScalarSeries.cpp',
25 'src/Data/SpectrogramSeries.cpp',
25 'src/Data/SpectrogramSeries.cpp',
26 'src/Data/DataSeriesIterator.cpp',
26 'src/Data/DataSeriesIterator.cpp',
27 'src/Data/ArrayDataIterator.cpp',
27 'src/Data/ArrayDataIterator.cpp',
28 'src/Data/VectorSeries.cpp',
28 'src/Data/VectorSeries.cpp',
29 'src/Data/OptionalAxis.cpp',
29 'src/Data/OptionalAxis.cpp',
30 'src/Data/DataSeriesUtils.cpp',
30 'src/Data/DataSeriesUtils.cpp',
31 'src/DataSource/DataSourceController.cpp',
31 'src/DataSource/DataSourceController.cpp',
32 'src/DataSource/DataSourceItem.cpp',
32 'src/DataSource/DataSourceItem.cpp',
33 'src/DataSource/DataSourceItemAction.cpp',
33 'src/DataSource/DataSourceItemAction.cpp',
34 'src/DataSource/DataSourceItemMergeHelper.cpp',
34 'src/Network/NetworkController.cpp',
35 'src/Network/NetworkController.cpp',
35 'src/Plugin/PluginManager.cpp',
36 'src/Plugin/PluginManager.cpp',
36 'src/Settings/SqpSettingsDefs.cpp',
37 'src/Settings/SqpSettingsDefs.cpp',
37 'src/Time/TimeController.cpp',
38 'src/Time/TimeController.cpp',
38 'src/Variable/Variable.cpp',
39 'src/Variable/Variable.cpp',
39 'src/Variable/VariableCacheController.cpp',
40 'src/Variable/VariableCacheController.cpp',
40 'src/Variable/VariableController.cpp',
41 'src/Variable/VariableController.cpp',
41 'src/Variable/VariableAcquisitionWorker.cpp',
42 'src/Variable/VariableAcquisitionWorker.cpp',
42 'src/Variable/VariableSynchronizationGroup.cpp',
43 'src/Variable/VariableSynchronizationGroup.cpp',
43 'src/Variable/VariableModel.cpp',
44 'src/Variable/VariableModel.cpp',
44 'src/Visualization/VisualizationController.cpp'
45 'src/Visualization/VisualizationController.cpp'
45 ]
46 ]
46
47
47 core_inc = include_directories(['include', '../plugin/include'])
48 core_inc = include_directories(['include', '../plugin/include'])
48
49
49 sciqlop_core_lib = library('sciqlopcore',
50 sciqlop_core_lib = library('sciqlopcore',
50 core_sources,
51 core_sources,
51 core_moc_files,
52 core_moc_files,
52 cpp_args : '-DCORE_LIB',
53 cpp_args : '-DCORE_LIB',
53 include_directories : core_inc,
54 include_directories : core_inc,
54 dependencies : [qt5core, qt5network],
55 dependencies : [qt5core, qt5network],
55 install : true
56 install : true
56 )
57 )
57
58
58
59
59 sciqlop_core = declare_dependency(link_with : sciqlop_core_lib,
60 sciqlop_core = declare_dependency(link_with : sciqlop_core_lib,
60 include_directories : core_inc,
61 include_directories : core_inc,
61 dependencies : [qt5core, qt5network])
62 dependencies : [qt5core, qt5network])
62
63
63
64
64 subdir('tests')
65 subdir('tests')
65
66
@@ -1,162 +1,168
1 #include <DataSource/DataSourceItem.h>
1 #include <DataSource/DataSourceItem.h>
2 #include <DataSource/DataSourceItemAction.h>
2 #include <DataSource/DataSourceItemAction.h>
3 #include <DataSource/DataSourceItemMergeHelper.h>
3
4
4 #include <QVector>
5 #include <QVector>
5
6
6 const QString DataSourceItem::NAME_DATA_KEY = QStringLiteral("name");
7 const QString DataSourceItem::NAME_DATA_KEY = QStringLiteral("name");
7
8
8 struct DataSourceItem::DataSourceItemPrivate {
9 struct DataSourceItem::DataSourceItemPrivate {
9 explicit DataSourceItemPrivate(DataSourceItemType type, QVariantHash data)
10 explicit DataSourceItemPrivate(DataSourceItemType type, QVariantHash data)
10 : m_Parent{nullptr}, m_Children{}, m_Type{type}, m_Data{std::move(data)}, m_Actions{}
11 : m_Parent{nullptr}, m_Children{}, m_Type{type}, m_Data{std::move(data)}, m_Actions{}
11 {
12 {
12 }
13 }
13
14
14 DataSourceItem *m_Parent;
15 DataSourceItem *m_Parent;
15 std::vector<std::unique_ptr<DataSourceItem> > m_Children;
16 std::vector<std::unique_ptr<DataSourceItem> > m_Children;
16 DataSourceItemType m_Type;
17 DataSourceItemType m_Type;
17 QVariantHash m_Data;
18 QVariantHash m_Data;
18 std::vector<std::unique_ptr<DataSourceItemAction> > m_Actions;
19 std::vector<std::unique_ptr<DataSourceItemAction> > m_Actions;
19 };
20 };
20
21
21 DataSourceItem::DataSourceItem(DataSourceItemType type, const QString &name)
22 DataSourceItem::DataSourceItem(DataSourceItemType type, const QString &name)
22 : DataSourceItem{type, QVariantHash{{NAME_DATA_KEY, name}}}
23 : DataSourceItem{type, QVariantHash{{NAME_DATA_KEY, name}}}
23 {
24 {
24 }
25 }
25
26
26 DataSourceItem::DataSourceItem(DataSourceItemType type, QVariantHash data)
27 DataSourceItem::DataSourceItem(DataSourceItemType type, QVariantHash data)
27 : impl{spimpl::make_unique_impl<DataSourceItemPrivate>(type, std::move(data))}
28 : impl{spimpl::make_unique_impl<DataSourceItemPrivate>(type, std::move(data))}
28 {
29 {
29 }
30 }
30
31
31 QVector<DataSourceItemAction *> DataSourceItem::actions() const noexcept
32 QVector<DataSourceItemAction *> DataSourceItem::actions() const noexcept
32 {
33 {
33 auto result = QVector<DataSourceItemAction *>{};
34 auto result = QVector<DataSourceItemAction *>{};
34
35
35 std::transform(std::cbegin(impl->m_Actions), std::cend(impl->m_Actions),
36 std::transform(std::cbegin(impl->m_Actions), std::cend(impl->m_Actions),
36 std::back_inserter(result), [](const auto &action) { return action.get(); });
37 std::back_inserter(result), [](const auto &action) { return action.get(); });
37
38
38 return result;
39 return result;
39 }
40 }
40
41
41 void DataSourceItem::addAction(std::unique_ptr<DataSourceItemAction> action) noexcept
42 void DataSourceItem::addAction(std::unique_ptr<DataSourceItemAction> action) noexcept
42 {
43 {
43 action->setDataSourceItem(this);
44 action->setDataSourceItem(this);
44 impl->m_Actions.push_back(std::move(action));
45 impl->m_Actions.push_back(std::move(action));
45 }
46 }
46
47
47 void DataSourceItem::appendChild(std::unique_ptr<DataSourceItem> child) noexcept
48 void DataSourceItem::appendChild(std::unique_ptr<DataSourceItem> child) noexcept
48 {
49 {
49 child->impl->m_Parent = this;
50 child->impl->m_Parent = this;
50 impl->m_Children.push_back(std::move(child));
51 impl->m_Children.push_back(std::move(child));
51 }
52 }
52
53
53 DataSourceItem *DataSourceItem::child(int childIndex) const noexcept
54 DataSourceItem *DataSourceItem::child(int childIndex) const noexcept
54 {
55 {
55 if (childIndex < 0 || childIndex >= childCount()) {
56 if (childIndex < 0 || childIndex >= childCount()) {
56 return nullptr;
57 return nullptr;
57 }
58 }
58 else {
59 else {
59 return impl->m_Children.at(childIndex).get();
60 return impl->m_Children.at(childIndex).get();
60 }
61 }
61 }
62 }
62
63
63 int DataSourceItem::childCount() const noexcept
64 int DataSourceItem::childCount() const noexcept
64 {
65 {
65 return impl->m_Children.size();
66 return impl->m_Children.size();
66 }
67 }
67
68
68 QVariant DataSourceItem::data(const QString &key) const noexcept
69 QVariant DataSourceItem::data(const QString &key) const noexcept
69 {
70 {
70 return impl->m_Data.value(key);
71 return impl->m_Data.value(key);
71 }
72 }
72
73
73 QVariantHash DataSourceItem::data() const noexcept
74 QVariantHash DataSourceItem::data() const noexcept
74 {
75 {
75 return impl->m_Data;
76 return impl->m_Data;
76 }
77 }
77
78
79 void DataSourceItem::merge(const DataSourceItem &item)
80 {
81 DataSourceItemMergeHelper::merge(item, *this);
82 }
83
78 bool DataSourceItem::isRoot() const noexcept
84 bool DataSourceItem::isRoot() const noexcept
79 {
85 {
80 return impl->m_Parent == nullptr;
86 return impl->m_Parent == nullptr;
81 }
87 }
82
88
83 QString DataSourceItem::name() const noexcept
89 QString DataSourceItem::name() const noexcept
84 {
90 {
85 return data(NAME_DATA_KEY).toString();
91 return data(NAME_DATA_KEY).toString();
86 }
92 }
87
93
88 DataSourceItem *DataSourceItem::parentItem() const noexcept
94 DataSourceItem *DataSourceItem::parentItem() const noexcept
89 {
95 {
90 return impl->m_Parent;
96 return impl->m_Parent;
91 }
97 }
92
98
93 const DataSourceItem &DataSourceItem::rootItem() const noexcept
99 const DataSourceItem &DataSourceItem::rootItem() const noexcept
94 {
100 {
95 return isRoot() ? *this : parentItem()->rootItem();
101 return isRoot() ? *this : parentItem()->rootItem();
96 }
102 }
97
103
98 void DataSourceItem::setData(const QString &key, const QVariant &value, bool append) noexcept
104 void DataSourceItem::setData(const QString &key, const QVariant &value, bool append) noexcept
99 {
105 {
100 auto it = impl->m_Data.constFind(key);
106 auto it = impl->m_Data.constFind(key);
101 if (append && it != impl->m_Data.constEnd()) {
107 if (append && it != impl->m_Data.constEnd()) {
102 // Case of an existing value to which we want to add to the new value
108 // Case of an existing value to which we want to add to the new value
103 if (it->canConvert<QVariantList>()) {
109 if (it->canConvert<QVariantList>()) {
104 auto variantList = it->value<QVariantList>();
110 auto variantList = it->value<QVariantList>();
105 variantList.append(value);
111 variantList.append(value);
106
112
107 impl->m_Data.insert(key, variantList);
113 impl->m_Data.insert(key, variantList);
108 }
114 }
109 else {
115 else {
110 impl->m_Data.insert(key, QVariantList{*it, value});
116 impl->m_Data.insert(key, QVariantList{*it, value});
111 }
117 }
112 }
118 }
113 else {
119 else {
114 // Other cases :
120 // Other cases :
115 // - new value in map OR
121 // - new value in map OR
116 // - replacement of an existing value (not appending)
122 // - replacement of an existing value (not appending)
117 impl->m_Data.insert(key, value);
123 impl->m_Data.insert(key, value);
118 }
124 }
119 }
125 }
120
126
121 DataSourceItemType DataSourceItem::type() const noexcept
127 DataSourceItemType DataSourceItem::type() const noexcept
122 {
128 {
123 return impl->m_Type;
129 return impl->m_Type;
124 }
130 }
125
131
126 DataSourceItem *DataSourceItem::findItem(const QVariantHash &data, bool recursive)
132 DataSourceItem *DataSourceItem::findItem(const QVariantHash &data, bool recursive)
127 {
133 {
128 for (const auto &child : impl->m_Children) {
134 for (const auto &child : impl->m_Children) {
129 if (child->impl->m_Data == data) {
135 if (child->impl->m_Data == data) {
130 return child.get();
136 return child.get();
131 }
137 }
132
138
133 if (recursive) {
139 if (recursive) {
134 if (auto foundItem = child->findItem(data, true)) {
140 if (auto foundItem = child->findItem(data, true)) {
135 return foundItem;
141 return foundItem;
136 }
142 }
137 }
143 }
138 }
144 }
139
145
140 return nullptr;
146 return nullptr;
141 }
147 }
142
148
143 bool DataSourceItem::operator==(const DataSourceItem &other)
149 bool DataSourceItem::operator==(const DataSourceItem &other)
144 {
150 {
145 // Compares items' attributes
151 // Compares items' attributes
146 if (std::tie(impl->m_Type, impl->m_Data) == std::tie(other.impl->m_Type, other.impl->m_Data)) {
152 if (std::tie(impl->m_Type, impl->m_Data) == std::tie(other.impl->m_Type, other.impl->m_Data)) {
147 // Compares contents of items' children
153 // Compares contents of items' children
148 return std::equal(std::cbegin(impl->m_Children), std::cend(impl->m_Children),
154 return std::equal(std::cbegin(impl->m_Children), std::cend(impl->m_Children),
149 std::cbegin(other.impl->m_Children),
155 std::cbegin(other.impl->m_Children),
150 [](const auto &itemChild, const auto &otherChild) {
156 [](const auto &itemChild, const auto &otherChild) {
151 return *itemChild == *otherChild;
157 return *itemChild == *otherChild;
152 });
158 });
153 }
159 }
154 else {
160 else {
155 return false;
161 return false;
156 }
162 }
157 }
163 }
158
164
159 bool DataSourceItem::operator!=(const DataSourceItem &other)
165 bool DataSourceItem::operator!=(const DataSourceItem &other)
160 {
166 {
161 return !(*this == other);
167 return !(*this == other);
162 }
168 }
General Comments 0
You need to be logged in to leave comments. Login now