• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

realm / realm-core / 2213

10 Apr 2024 11:21PM UTC coverage: 91.792% (-0.8%) from 92.623%
2213

push

Evergreen

web-flow
Add missing availability checks for SecCopyErrorMessageString (#7577)

This requires iOS 11.3 and we currently target iOS 11.

94842 of 175770 branches covered (53.96%)

7 of 22 new or added lines in 2 files covered. (31.82%)

1861 existing lines in 82 files now uncovered.

242866 of 264583 relevant lines covered (91.79%)

5593111.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.71
/src/realm/object-store/c_api/notifications.cpp
1
#include <realm/object-store/c_api/types.hpp>
2
#include <realm/object-store/c_api/util.hpp>
3
#include <realm/object-store/keypath_helpers.hpp>
4

5
namespace realm::c_api {
6
namespace {
7
struct ObjectNotificationsCallback {
8
    UserdataPtr m_userdata;
9
    realm_on_object_change_func_t m_on_change = nullptr;
10

11
    ObjectNotificationsCallback() = default;
6✔
12
    ObjectNotificationsCallback(ObjectNotificationsCallback&& other)
13
        : m_userdata(std::exchange(other.m_userdata, nullptr))
14
        , m_on_change(std::exchange(other.m_on_change, nullptr))
15
    {
24✔
16
    }
24✔
17

18
    void operator()(const CollectionChangeSet& changes)
19
    {
12✔
20
        if (m_on_change) {
12✔
21
            realm_object_changes_t c{changes};
12✔
22
            m_on_change(m_userdata.get(), &c);
12✔
23
        }
12✔
24
    }
12✔
25
};
26

27
struct CollectionNotificationsCallback {
28
    UserdataPtr m_userdata;
29
    realm_on_collection_change_func_t m_on_change = nullptr;
30

31
    CollectionNotificationsCallback() = default;
24✔
32
    CollectionNotificationsCallback(CollectionNotificationsCallback&& other)
33
        : m_userdata(std::exchange(other.m_userdata, nullptr))
34
        , m_on_change(std::exchange(other.m_on_change, nullptr))
35
    {
96✔
36
    }
96✔
37

38
    void operator()(const CollectionChangeSet& changes)
39
    {
46✔
40
        if (m_on_change) {
46✔
41
            realm_collection_changes_t c{changes};
46✔
42
            m_on_change(m_userdata.get(), &c);
46✔
43
        }
46✔
44
    }
46✔
45
};
46

47
struct DictionaryNotificationsCallback {
48
    UserdataPtr m_userdata;
49
    realm_on_dictionary_change_func_t m_on_change = nullptr;
50

51
    DictionaryNotificationsCallback() = default;
6✔
52
    DictionaryNotificationsCallback(DictionaryNotificationsCallback&& other)
53
        : m_userdata(std::exchange(other.m_userdata, nullptr))
54
        , m_on_change(std::exchange(other.m_on_change, nullptr))
55
    {
6✔
56
    }
6✔
57

58
    void operator()(const DictionaryChangeSet& changes)
59
    {
12✔
60
        if (m_on_change) {
12✔
61
            realm_dictionary_changes_t c{changes};
12✔
62
            m_on_change(m_userdata.get(), &c);
12✔
63
        }
12✔
64
    }
12✔
65
};
66

67
std::optional<KeyPathArray> build_key_path_array(realm_key_path_array_t* key_path_array)
68
{
36✔
69
    std::optional<KeyPathArray> ret;
36✔
70
    if (key_path_array && key_path_array->size()) {
36✔
71
        ret.emplace(std::move(*key_path_array));
10✔
72
    }
10✔
73
    return ret;
36✔
74
}
36✔
75

76
} // namespace
77

78
RLM_API realm_key_path_array_t* realm_create_key_path_array(const realm_t* realm,
79
                                                            const realm_class_key_t object_class_key,
80
                                                            size_t num_key_paths, const char** user_key_paths)
81
{
14✔
82
    return wrap_err([&]() {
14✔
83
        KeyPathArray ret;
14✔
84
        if (user_key_paths) {
14✔
85
            ret = (*realm)->create_key_path_array(TableKey(object_class_key), num_key_paths, user_key_paths);
14✔
86
        }
14✔
87
        return new realm_key_path_array_t(std::move(ret));
14✔
88
    });
14✔
89
}
14✔
90

91
RLM_API realm_notification_token_t* realm_object_add_notification_callback(realm_object_t* obj,
92
                                                                           realm_userdata_t userdata,
93
                                                                           realm_free_userdata_func_t free,
94
                                                                           realm_key_path_array_t* key_path_array,
95
                                                                           realm_on_object_change_func_t on_change)
96
{
6✔
97
    return wrap_err([&]() {
6✔
98
        ObjectNotificationsCallback cb;
6✔
99
        cb.m_userdata = UserdataPtr{userdata, free};
6✔
100
        cb.m_on_change = on_change;
6✔
101
        auto token = obj->add_notification_callback(std::move(cb), build_key_path_array(key_path_array));
6✔
102
        return new realm_notification_token_t{std::move(token)};
6✔
103
    });
6✔
104
}
6✔
105

106
RLM_API bool realm_object_changes_is_deleted(const realm_object_changes_t* changes)
107
{
4✔
108
    return !changes->deletions.empty();
4✔
109
}
4✔
110

111
RLM_API size_t realm_object_changes_get_num_modified_properties(const realm_object_changes_t* changes)
112
{
2✔
113
    return changes->columns.size();
2✔
114
}
2✔
115

116
RLM_API size_t realm_object_changes_get_modified_properties(const realm_object_changes_t* changes,
117
                                                            realm_property_key_t* out_properties, size_t max)
118
{
8✔
119
    if (!out_properties)
8✔
120
        return changes->columns.size();
2✔
121

3✔
122
    size_t i = 0;
6✔
123
    for (const auto& [col_key_val, index_set] : changes->columns) {
8✔
124
        if (i >= max) {
8✔
125
            break;
2✔
126
        }
2✔
127
        out_properties[i] = col_key_val;
6✔
128
        ++i;
6✔
129
    }
6✔
130
    return i;
6✔
131
}
6✔
132

133
RLM_API realm_notification_token_t* realm_list_add_notification_callback(realm_list_t* list,
134
                                                                         realm_userdata_t userdata,
135
                                                                         realm_free_userdata_func_t free,
136
                                                                         realm_key_path_array_t* key_path_array,
137
                                                                         realm_on_collection_change_func_t on_change)
138
{
18✔
139
    return wrap_err([&]() {
18✔
140
        CollectionNotificationsCallback cb;
18✔
141
        cb.m_userdata = UserdataPtr{userdata, free};
18✔
142
        cb.m_on_change = on_change;
18✔
143
        auto token = list->add_notification_callback(std::move(cb), build_key_path_array(key_path_array));
18✔
144
        return new realm_notification_token_t{std::move(token)};
18✔
145
    });
18✔
146
}
18✔
147

148
RLM_API realm_notification_token_t* realm_set_add_notification_callback(realm_set_t* set, realm_userdata_t userdata,
149
                                                                        realm_free_userdata_func_t free,
150
                                                                        realm_key_path_array_t* key_path_array,
151
                                                                        realm_on_collection_change_func_t on_change)
152
{
4✔
153
    return wrap_err([&]() {
4✔
154
        CollectionNotificationsCallback cb;
4✔
155
        cb.m_userdata = UserdataPtr{userdata, free};
4✔
156
        cb.m_on_change = on_change;
4✔
157
        auto token = set->add_notification_callback(std::move(cb), build_key_path_array(key_path_array));
4✔
158
        return new realm_notification_token_t{std::move(token)};
4✔
159
    });
4✔
160
}
4✔
161

162
RLM_API realm_notification_token_t*
163
realm_dictionary_add_notification_callback(realm_dictionary_t* dict, realm_userdata_t userdata,
164
                                           realm_free_userdata_func_t free, realm_key_path_array_t* key_path_array,
165
                                           realm_on_dictionary_change_func_t on_change)
166
{
6✔
167
    return wrap_err([&]() {
6✔
168
        DictionaryNotificationsCallback cb;
6✔
169
        cb.m_userdata = UserdataPtr{userdata, free};
6✔
170
        cb.m_on_change = on_change;
6✔
171
        auto token = dict->add_key_based_notification_callback(std::move(cb), build_key_path_array(key_path_array));
6✔
172
        return new realm_notification_token_t{std::move(token)};
6✔
173
    });
6✔
174
}
6✔
175

176
RLM_API realm_notification_token_t*
177
realm_results_add_notification_callback(realm_results_t* results, realm_userdata_t userdata,
178
                                        realm_free_userdata_func_t free, realm_key_path_array_t* key_path_array,
179
                                        realm_on_collection_change_func_t on_change)
180
{
2✔
181
    return wrap_err([&]() {
2✔
182
        CollectionNotificationsCallback cb;
2✔
183
        cb.m_userdata = UserdataPtr{userdata, free};
2✔
184
        cb.m_on_change = on_change;
2✔
185
        auto token = results->add_notification_callback(std::move(cb), build_key_path_array(key_path_array));
2✔
186
        return new realm_notification_token_t{std::move(token)};
2✔
187
    });
2✔
188
}
2✔
189

190
RLM_API void realm_collection_changes_get_num_ranges(const realm_collection_changes_t* changes,
191
                                                     size_t* out_num_deletion_ranges,
192
                                                     size_t* out_num_insertion_ranges,
193
                                                     size_t* out_num_modification_ranges, size_t* out_num_moves)
194
{
6✔
195
    // FIXME: `std::distance()` has O(n) performance here, which seems ridiculous.
3✔
196

3✔
197
    if (out_num_deletion_ranges)
6✔
198
        *out_num_deletion_ranges = std::distance(changes->deletions.begin(), changes->deletions.end());
6✔
199
    if (out_num_insertion_ranges)
6✔
200
        *out_num_insertion_ranges = std::distance(changes->insertions.begin(), changes->insertions.end());
6✔
201
    if (out_num_modification_ranges)
6✔
202
        *out_num_modification_ranges = std::distance(changes->modifications.begin(), changes->modifications.end());
6✔
203
    if (out_num_moves)
6✔
204
        *out_num_moves = changes->moves.size();
6✔
205
}
6✔
206

207
RLM_API void realm_collection_changes_get_num_changes(const realm_collection_changes_t* changes,
208
                                                      size_t* out_num_deletions, size_t* out_num_insertions,
209
                                                      size_t* out_num_modifications, size_t* out_num_moves,
210
                                                      bool* out_collection_was_cleared,
211
                                                      bool* out_collection_was_deleted)
212
{
16✔
213
    if (out_num_deletions)
16✔
214
        *out_num_deletions = changes->deletions.count();
16✔
215
    if (out_num_insertions)
16✔
216
        *out_num_insertions = changes->insertions.count();
16✔
217
    if (out_num_modifications)
16✔
218
        *out_num_modifications = changes->modifications.count();
16✔
219
    if (out_num_moves)
16✔
220
        *out_num_moves = changes->moves.size();
6✔
221
    if (out_collection_was_cleared)
16✔
222
        *out_collection_was_cleared = changes->collection_was_cleared;
6✔
223
    if (out_collection_was_deleted)
16✔
224
        *out_collection_was_deleted = changes->collection_root_was_deleted;
10✔
225
}
16✔
226

227
static inline void copy_index_ranges(const IndexSet& index_set, realm_index_range_t* out_ranges, size_t max)
228
{
14✔
229
    size_t i = 0;
14✔
230
    for (auto [from, to] : index_set) {
14✔
231
        if (i >= max)
14✔
UNCOV
232
            return;
×
233
        out_ranges[i++] = realm_index_range_t{from, to};
14✔
234
    }
14✔
235
}
14✔
236

237
RLM_API void realm_collection_changes_get_ranges(
238
    const realm_collection_changes_t* changes, realm_index_range_t* out_deletion_ranges, size_t max_deletion_ranges,
239
    realm_index_range_t* out_insertion_ranges, size_t max_insertion_ranges,
240
    realm_index_range_t* out_modification_ranges, size_t max_modification_ranges,
241
    realm_index_range_t* out_modification_ranges_after, size_t max_modification_ranges_after,
242
    realm_collection_move_t* out_moves, size_t max_moves)
243
{
6✔
244
    if (out_deletion_ranges) {
6✔
245
        copy_index_ranges(changes->deletions, out_deletion_ranges, max_deletion_ranges);
4✔
246
    }
4✔
247
    if (out_insertion_ranges) {
6✔
248
        copy_index_ranges(changes->insertions, out_insertion_ranges, max_insertion_ranges);
6✔
249
    }
6✔
250
    if (out_modification_ranges) {
6✔
251
        copy_index_ranges(changes->modifications, out_modification_ranges, max_modification_ranges);
2✔
252
    }
2✔
253
    if (out_modification_ranges_after) {
6✔
254
        copy_index_ranges(changes->modifications_new, out_modification_ranges_after, max_modification_ranges_after);
2✔
255
    }
2✔
256
    if (out_moves) {
6✔
257
        size_t i = 0;
2✔
258
        for (auto [from, to] : changes->moves) {
1✔
UNCOV
259
            if (i >= max_moves)
×
UNCOV
260
                break;
×
261
            out_moves[i] = realm_collection_move_t{from, to};
×
262
            ++i;
×
263
        }
×
264
    }
2✔
265
}
6✔
266

267
RLM_API void realm_dictionary_get_changes(const realm_dictionary_changes_t* changes, size_t* out_deletions_size,
268
                                          size_t* out_insertion_size, size_t* out_modification_size,
269
                                          bool* out_was_deleted)
270
{
8✔
271
    if (out_deletions_size)
8✔
272
        *out_deletions_size = changes->deletions.size();
8✔
273
    if (out_insertion_size)
8✔
274
        *out_insertion_size = changes->insertions.size();
8✔
275
    if (out_modification_size)
8✔
276
        *out_modification_size = changes->modifications.size();
8✔
277
    if (out_was_deleted)
8✔
278
        *out_was_deleted = changes->collection_root_was_deleted;
6✔
279
}
8✔
280

281
RLM_API void realm_dictionary_get_changed_keys(const realm_dictionary_changes_t* changes,
282
                                               realm_value_t* deletion_keys, size_t* deletions_size,
283
                                               realm_value_t* insertion_keys, size_t* insertions_size,
284
                                               realm_value_t* modification_keys, size_t* modifications_size,
285
                                               bool* collection_was_cleared)
286
{
4✔
287
    auto fill = [](const auto& collection, realm_value_t* out, size_t* n) {
12✔
288
        if (!out || !n)
12✔
289
            return;
4✔
290
        if (collection.size() == 0 || *n < collection.size()) {
8✔
291
            *n = 0;
4✔
292
            return;
4✔
293
        }
4✔
294
        size_t i = 0;
4✔
295
        for (auto val : collection)
4✔
296
            out[i++] = to_capi(val);
6✔
297
        *n = i;
4✔
298
    };
4✔
299

2✔
300
    fill(changes->deletions, deletion_keys, deletions_size);
4✔
301
    fill(changes->insertions, insertion_keys, insertions_size);
4✔
302
    fill(changes->modifications, modification_keys, modifications_size);
4✔
303
    if (collection_was_cleared)
4✔
304
        *collection_was_cleared = changes->collection_was_cleared;
4✔
305
}
4✔
306

307
static inline void copy_indices(const IndexSet& index_set, size_t* out_indices, size_t max)
308
{
8✔
309
    size_t i = 0;
8✔
310
    for (auto index : index_set.as_indexes()) {
10✔
311
        if (i >= max)
10✔
UNCOV
312
            return;
×
313
        out_indices[i] = index;
10✔
314
        ++i;
10✔
315
    }
10✔
316
}
8✔
317

318
RLM_API void realm_collection_changes_get_changes(const realm_collection_changes_t* changes, size_t* out_deletions,
319
                                                  size_t max_deletions, size_t* out_insertions, size_t max_insertions,
320
                                                  size_t* out_modifications, size_t max_modifications,
321
                                                  size_t* out_modifications_after, size_t max_modifications_after,
322
                                                  realm_collection_move_t* out_moves, size_t max_moves)
323
{
2✔
324
    if (out_deletions) {
2✔
325
        copy_indices(changes->deletions, out_deletions, max_deletions);
2✔
326
    }
2✔
327
    if (out_insertions) {
2✔
328
        copy_indices(changes->insertions, out_insertions, max_insertions);
2✔
329
    }
2✔
330
    if (out_modifications) {
2✔
331
        copy_indices(changes->modifications, out_modifications, max_modifications);
2✔
332
    }
2✔
333
    if (out_modifications_after) {
2✔
334
        copy_indices(changes->modifications_new, out_modifications_after, max_modifications_after);
2✔
335
    }
2✔
336
    if (out_moves) {
2✔
337
        size_t i = 0;
2✔
338
        for (auto [from, to] : changes->moves) {
1✔
UNCOV
339
            if (i >= max_moves)
×
UNCOV
340
                break;
×
341
            out_moves[i] = realm_collection_move_t{from, to};
×
342
            ++i;
×
343
        }
×
344
    }
2✔
345
}
2✔
346

347
} // namespace realm::c_api
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc