Skip to content

Commit d58e5fa

Browse files
committed
Merge pull request #82 from mpsonntag/refactorWriteValues
Create Property with Values
2 parents e22d44b + 3a99829 commit d58e5fa

File tree

10 files changed

+278
-27
lines changed

10 files changed

+278
-27
lines changed

+nix/Property.m

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@
2828
[obj.valuesCache, retVals] = nix.Utils.fetchPropList(obj.updatedAt, ...
2929
'Property::values', obj.nix_handle, obj.valuesCache);
3030
end
31+
32+
function [] = set.values(obj, val)
33+
nix_mx('Property::updateValues', obj.nix_handle, val);
34+
obj.valuesCache.lastUpdate = 0;
35+
36+
dispStr = 'Note: nix only supports updating the actual value at the moment.';
37+
dispStr = [dispStr, char(10), 'Attributes like uncertainty or checksum cannot be set at the moment.'];
38+
disp(dispStr);
39+
end
3140
end
3241

3342
end

+nix/Section.m

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
properties(Dependent)
1212
allProperties
13-
allPropertiesMap
13+
%allPropertiesMap
1414
end;
1515

1616
methods
@@ -95,6 +95,12 @@
9595
obj.propsCache.lastUpdate = 0;
9696
end;
9797

98+
function p = create_property_with_value(obj, name, val)
99+
p = nix.Property(nix_mx('Section::createPropertyWithValue', ...
100+
obj.nix_handle, name, val));
101+
obj.propsCache.lastUpdate = 0;
102+
end;
103+
98104
function delCheck = delete_property(obj, del)
99105
if(isstruct(del) && isfield(del, 'id'))
100106
delID = del.id;
@@ -117,14 +123,19 @@
117123
'Section::properties', obj.nix_handle, obj.propsCache);
118124
end
119125

120-
function p_map = get.allPropertiesMap(obj)
121-
p_map = containers.Map();
122-
props = obj.allProperties;
126+
%-- values has been removed from section.properties due to
127+
%-- stale entries in the section.properties cache when the acutal
128+
%-- properties values are updated. therefore the current mapping
129+
%-- function cannot be used at the moment.
130+
%-- could be refactored at a later moment in time
131+
%function p_map = get.allPropertiesMap(obj)
132+
% p_map = containers.Map();
133+
% props = obj.allProperties;
123134

124-
for i=1:length(props)
125-
p_map(props{i}.name) = cell2mat(props{i}.values);
126-
end
127-
end
135+
% for i=1:length(props)
136+
% p_map(props{i}.name) = cell2mat(props{i}.values);
137+
% end
138+
%end
128139

129140
end
130141

nix_mx.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ void mexFunction(int nlhs,
235235
.reg("deleteProperty", REMOVER(nix::Property, nix::Section, deleteProperty));
236236
methods->add("Section::properties", nixsection::properties);
237237
methods->add("Section::createProperty", nixsection::create_property);
238+
methods->add("Section::createPropertyWithValue", nixsection::create_property_with_value);
238239

239240
classdef<nix::Feature>("Feature", methods)
240241
.desc(&nixfeature::describe)
@@ -249,6 +250,7 @@ void mexFunction(int nlhs,
249250
.reg("set_mapping", SETTER(const std::string&, nix::Property, mapping))
250251
.reg("set_none_mapping", SETTER(const boost::none_t, nix::Property, mapping));
251252
methods->add("Property::values", nixproperty::values);
253+
methods->add("Property::updateValues", nixproperty::update_values);
252254

253255
mexAtExit(on_exit);
254256
});

src/nixproperty.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,12 @@ namespace nixproperty {
5151
output.set(0, lst);
5252
}
5353

54+
void update_values(const extractor &input, infusor &output)
55+
{
56+
nix::Property prop = input.entity<nix::Property>(1);
57+
prop.deleteValues();
58+
std::vector<nix::Value> getVals = input.extractFromStruct(2);
59+
prop.values(getVals);
60+
}
61+
5462
} // namespace nixproperty

src/nixproperty.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ namespace nixproperty {
99

1010
void values(const extractor &input, infusor &output);
1111

12+
void update_values(const extractor &input, infusor &output);
13+
1214
} // namespace nixproperty
1315

1416
#endif

src/nixsection.cc

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,16 @@ void properties(const extractor &input, infusor &output)
3838
for (size_t i = 0; i < properties.size(); i++) {
3939

4040
nix::Property pr = properties[i];
41-
std::vector<nix::Value> values = pr.values();
42-
43-
mxArray *mx_values = make_mx_array(values);
4441

4542
struct_builder sb({ 1 }, {
46-
"name", "id", "definition", "mapping", "unit", "values"
43+
"name", "id", "definition", "mapping", "unit"
4744
});
4845

4946
sb.set(pr.name());
5047
sb.set(pr.id());
5148
sb.set(pr.definition());
5249
sb.set(pr.mapping());
5350
sb.set(pr.unit());
54-
sb.set(mx_values);
5551

5652
mxSetCell(lst, i, sb.array());
5753
}
@@ -69,4 +65,13 @@ void create_property(const extractor &input, infusor &output)
6965
output.set(0, handle(p));
7066
}
7167

68+
void create_property_with_value(const extractor &input, infusor &output)
69+
{
70+
nix::Section currObj = input.entity<nix::Section>(1);
71+
std::vector<nix::Value> currVec = input.extractFromCells(3);
72+
73+
nix::Property p = currObj.createProperty(input.str(2), currVec);
74+
output.set(0, handle(p));
75+
}
76+
7277
} // namespace nixsection

src/nixsection.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ namespace nixsection {
1111

1212
void create_property(const extractor &input, infusor &output);
1313

14+
void create_property_with_value(const extractor &input, infusor &output);
15+
1416
} // namespace nixfile
1517

16-
#endif
18+
#endif

src/utils/arguments.h

Lines changed: 167 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,172 @@ class extractor : public argument_helper<const mxArray> {
193193
return mxGetPr(array[pos]);
194194
}
195195

196+
std::vector<nix::Value> extractFromCells(size_t pos) const {
197+
198+
std::vector<nix::Value> vals;
199+
200+
mwSize total_num_of_cells = mxGetNumberOfElements(array[pos]);
201+
for (mwIndex index = 0; index<total_num_of_cells; index++) {
202+
const mxArray *cell_element_ptr = mxGetCell(array[pos], index);
203+
204+
nix::Value currVal;
205+
206+
switch (mxGetClassID(cell_element_ptr)) {
207+
case mxLOGICAL_CLASS:
208+
{
209+
const mxLogical *curr = mxGetLogicals(cell_element_ptr);
210+
currVal.set(curr[0]); break; }
211+
case mxDOUBLE_CLASS:
212+
{
213+
double curr;
214+
const void *data = mxGetData(cell_element_ptr);
215+
memcpy(&curr, data, sizeof(double));
216+
currVal.set(curr); break; }
217+
case mxUINT32_CLASS:
218+
{
219+
uint32_t curr;
220+
const void *data = mxGetData(cell_element_ptr);
221+
memcpy(&curr, data, sizeof(uint32_t));
222+
currVal.set(curr); break; }
223+
case mxINT32_CLASS:
224+
{
225+
int32_t curr;
226+
const void *data = mxGetData(cell_element_ptr);
227+
memcpy(&curr, data, sizeof(int32_t));
228+
currVal.set(curr); break; }
229+
case mxUINT64_CLASS:
230+
{
231+
uint64_t curr;
232+
const void *data = mxGetData(cell_element_ptr);
233+
memcpy(&curr, data, sizeof(uint64_t));
234+
currVal.set(curr); break; }
235+
case mxINT64_CLASS:
236+
{
237+
int64_t curr;
238+
const void *data = mxGetData(cell_element_ptr);
239+
memcpy(&curr, data, sizeof(int64_t));
240+
currVal.set(curr); break; }
241+
242+
case mxCHAR_CLASS:
243+
{
244+
char *tmp = mxArrayToString(cell_element_ptr);
245+
std::string curr_string = tmp;
246+
currVal.set(curr_string);
247+
mxFree(tmp);
248+
break;
249+
}
250+
case mxUNKNOWN_CLASS:
251+
{ mexWarnMsgTxt("Unknown class."); break; }
252+
default:
253+
{ mexWarnMsgTxt("Unsupported class."); break; }
254+
}
255+
vals.push_back(currVal);
256+
}
257+
return vals;
258+
}
259+
260+
std::vector<nix::Value> extractFromStruct(size_t pos) const {
261+
262+
// Note: nix::Value is not able to its attributes "uncertainty"
263+
// "checksum", "filename", "encoder" or "reference" at the moment.
264+
// The setters are implemented and the attribute values are
265+
// correctly set to the nix::Value entity, but they will not
266+
// actually be written to the nix file. Once this issue has been
267+
// fixed on the nix side, the current implementation should work
268+
// fine.
269+
270+
std::vector<nix::Value> vals;
271+
272+
mwSize total_num_of_cells = mxGetNumberOfElements(array[pos]);
273+
for (mwIndex index = 0; index<total_num_of_cells; index++) {
274+
const mxArray *cell_element_ptr = mxGetCell(array[pos], index);
275+
276+
if (mxGetClassID(cell_element_ptr) == mxSTRUCT_CLASS){
277+
278+
nix::Value currVal;
279+
280+
mwSize total_num_of_elements = mxGetNumberOfElements(cell_element_ptr);
281+
int number_of_fields = mxGetNumberOfFields(cell_element_ptr);
282+
283+
for (mwIndex struct_idx = 0; struct_idx < total_num_of_elements; struct_idx++) {
284+
for (int field_index = 0; field_index < number_of_fields; field_index++) {
285+
const char *field_name = mxGetFieldNameByNumber(cell_element_ptr, field_index);
286+
const mxArray *field_array_ptr = mxGetFieldByNumber(cell_element_ptr, struct_idx, field_index);
287+
288+
if (field_array_ptr != nullptr) {
289+
if (strcmp(field_name, "value") == 0){
290+
if (mxGetClassID(field_array_ptr) == mxDOUBLE_CLASS){
291+
double curr;
292+
const void *data = mxGetData(field_array_ptr);
293+
memcpy(&curr, data, sizeof(double));
294+
currVal.set(curr);
295+
}
296+
else if (mxGetClassID(field_array_ptr) == mxLOGICAL_CLASS){
297+
const mxLogical *curr = mxGetLogicals(field_array_ptr);
298+
currVal.set(curr[0]);
299+
}
300+
else if (mxGetClassID(field_array_ptr) == mxCHAR_CLASS){
301+
char *tmp = mxArrayToString(field_array_ptr);
302+
std::string curr_string = tmp;
303+
currVal.set(curr_string);
304+
mxFree(tmp);
305+
}
306+
else { mexPrintf("Unsupported value data type\n"); }
307+
308+
}
309+
else if (strcmp(field_name, "uncertainty") == 0){
310+
if (mxGetClassID(field_array_ptr) == mxDOUBLE_CLASS){
311+
double curr;
312+
const void *data = mxGetData(field_array_ptr);
313+
memcpy(&curr, data, sizeof(double));
314+
currVal.uncertainty = curr;
315+
}
316+
}
317+
else if (strcmp(field_name, "checksum") == 0){
318+
if (mxGetClassID(field_array_ptr) == mxCHAR_CLASS){
319+
char *tmp = mxArrayToString(field_array_ptr);
320+
std::string curr_string = tmp;
321+
currVal.checksum = curr_string;
322+
mxFree(tmp);
323+
}
324+
}
325+
else if (strcmp(field_name, "encoder") == 0){
326+
if (mxGetClassID(field_array_ptr) == mxCHAR_CLASS){
327+
char *tmp = mxArrayToString(field_array_ptr);
328+
std::string curr_string = tmp;
329+
currVal.encoder = curr_string;
330+
mxFree(tmp);
331+
}
332+
}
333+
else if (strcmp(field_name, "filename") == 0){
334+
if (mxGetClassID(field_array_ptr) == mxCHAR_CLASS){
335+
char *tmp = mxArrayToString(field_array_ptr);
336+
std::string curr_string = tmp;
337+
currVal.filename = curr_string;
338+
mxFree(tmp);
339+
}
340+
}
341+
else if (strcmp(field_name, "reference") == 0){
342+
if (mxGetClassID(field_array_ptr) == mxCHAR_CLASS){
343+
char *tmp = mxArrayToString(field_array_ptr);
344+
std::string curr_string(tmp);
345+
currVal.reference = tmp;
346+
mxFree(tmp);
347+
}
348+
}
349+
}
350+
}
351+
}
352+
vals.push_back(currVal);
353+
}
354+
else
355+
{
356+
mexWarnMsgTxt("Unsupported value wrapper data type");
357+
}
358+
}
359+
return vals;
360+
}
361+
196362
private:
197363
};
198364

@@ -214,4 +380,4 @@ class infusor : public argument_helper<mxArray> {
214380
private:
215381
};
216382

217-
#endif
383+
#endif

tests/TestProperty.m

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
funcs = {};
66
funcs{end+1} = @test_attrs;
7+
funcs{end+1} = @test_update_values;
78
funcs{end+1} = @test_values;
89
end
910

@@ -42,17 +43,39 @@
4243

4344
%% Test: Access values
4445
function [] = test_values( varargin )
45-
f = nix.File(fullfile(pwd, 'tests', 'test.h5'), nix.FileMode.ReadOnly);
46-
trial = f.sections{2}.sections{2}.sections{1};
47-
currProp = trial.open_property(trial.allProperties{1}.id);
46+
f = nix.File(fullfile(pwd,'tests','testRW.h5'), nix.FileMode.Overwrite);
47+
s = f.createSection('mainSection', 'nixSection');
48+
currProp = s.create_property_with_value('booleanProperty', {true, false, true});
4849

49-
assert(size(currProp.values, 1) == 1);
50-
assert(currProp.values{1}.value == 1);
50+
assert(size(currProp.values, 1) == 3);
51+
assert(currProp.values{1}.value);
5152
assert(currProp.values{1}.uncertainty == 0);
5253
assert(isempty(currProp.values{1}.checksum));
5354
assert(isempty(currProp.values{1}.encoder));
5455
assert(isempty(currProp.values{1}.filename));
5556
assert(isempty(currProp.values{1}.reference));
56-
57-
disp('Test Property: access values ... TODO (multiple property values)');
57+
end
58+
59+
%% Test: Update values
60+
function [] = test_update_values( varargin )
61+
f = nix.File(fullfile(pwd,'tests','testRW.h5'), nix.FileMode.Overwrite);
62+
s = f.createSection('mainSection', 'nixSection');
63+
64+
%-- test update boolean
65+
updateBool = s.create_property_with_value('booleanProperty', {true, false, true});
66+
assert(updateBool.values{1}.value);
67+
updateBool.values{1}.value = false;
68+
assert(~updateBool.values{1}.value);
69+
70+
%-- test update string
71+
updateString = s.create_property_with_value('stringProperty', {'this', 'has', 'strings'});
72+
assert(strcmp(updateString.values{3}.value, 'strings'));
73+
updateString.values{3}.value = 'more strings';
74+
assert(strcmp(updateString.values{3}.value, 'more strings'));
75+
76+
%-- test update double
77+
updateDouble = s.create_property_with_value('doubleProperty', {2, 3, 4, 5});
78+
assert(updateDouble.values{1}.value == 2);
79+
updateDouble.values{1}.value = 2.2;
80+
assert(updateDouble.values{1}.value == 2.2);
5881
end

0 commit comments

Comments
 (0)