1

Assuming the following JSON object, an array of [epoch, value] arrays:

[ [0,1], [1912312314,2], [1912312857,5] ]

What's the correct way to remove an element of the array ? The idea is to remove the one with an epoch alder than a given value. I use json-c 0.11.

I tried :

   json_object *jsonHeatmapObj;
   jsonHeatmapObj = json_tokener_parse ( "[ [0,1], [1912312314,2], [1912312857,5] ]" );

    for ( int idx=0 ; idx < json_object_array_length(jsonHeatmapObj) ; idx++ ) {
       json_object *curJsonHeatpointObj = json_object_array_get_idx ( jsonHeatmapObj , idx );
       int x = json_object_get_int ( json_object_array_get_idx ( curJsonHeatpointObj , 0 ) );
       if ( x < time(NULL) - 10 ) {
          json_object_put ( curJsonHeatpointObj );
       }
       printf("\t[%d]=%s\n", idx, json_object_to_json_string(jsonHeatmapObj));
    }

This fails (SIGSEGV) when calling json_object_to_json_string() with the adjusted object.

Thank you

SCO
  • 1,832
  • 1
  • 24
  • 45

1 Answers1

1

I think there are two separate issues with that code: one is that it is using json_object_put as if json_object_array_get_idx had removed the element it returns from the original array (something that is not at all clear from the API documentation), and second that it uses time(NULL) as if it was returning an integer, but it is returning a time_t struct.

The first one can be solved by creating a new JSON array and only including items in it if the condition is met. Here I am avoiding the second issue by using a time that is set to the largest value in the array:

struct json_object *newHeatMap = json_object_new_array();
for ( int idx=0 ; idx < json_object_array_length(jsonHeatmapObj) ; idx++ ) {
    json_object *curJsonHeatpointObj = json_object_array_get_idx ( jsonHeatmapObj , idx );
    int x = json_object_get_int ( json_object_array_get_idx ( curJsonHeatpointObj , 0 ) );
    if ( x < 1912312857 ) {
        json_object_array_add(newHeatMap, curJsonHeatpointObj);
    }
    printf("\t[%d]=%s\n", idx, json_object_to_json_string(newHeatMap));
}

I get the following results, which I hope are what you intend to see:

$ gcc -I/opt/local/include -L/opt/local/lib/ -ljson-c main.c && ./a.out example.json
    [0]=[ [ 0, 1 ] ]
    [1]=[ [ 0, 1 ], [ 1912312314, 2 ] ]
    [2]=[ [ 0, 1 ], [ 1912312314, 2 ] ]

The second problem has already been answered for instance here on SO

Community
  • 1
  • 1
logc
  • 3,813
  • 1
  • 18
  • 29
  • Although this lookes more like a workaround, I'll accept this since I guess there is no better way to do it. I used json_object_array_add() instead of json_object_array_put_idx() to populate newHeatMap though. – SCO Feb 16 '15 at 14:37
  • @SCO: I have edited the post to use the function you mention. Both give the same output. Using `json_object_array_put_idx` would have kept the logic right even if you changed the index loop, but maybe `json_object_array_add` is more intuitive. Otherwise: why does this look like a workaround? Returning a new object instead of mutating one is not a bad pattern, specially if threading is involved. – logc Feb 16 '15 at 15:25
  • From what I remember, the json_object_array_put_idx() segfaulted. I came to the conclusion that json_object_array_put_idx() used idx which was out-of-bounds for newHeatMap. For example, json_object_array_put_idx()'ing curJsonHeatpointObj at index 2 of newHeatMap where neither objects at indexes 0 or 1 were added previously (making newHeatMap array 0-sized) would make it SIGSEGV. I always expect libraries to allow for inplace replacement (you are right regarding MT, in that case, I just mutex' the change when it is acceptable to do so) because the code is more readable, IMHO :). Thank you ! – SCO Feb 16 '15 at 16:22
  • @SCO : you are right about segfaulting if an intermediate element is skipped. I did not take that into account, and now the answer is better. Take care with mutating state, it is the source of all evil :) – logc Feb 16 '15 at 16:26
  • "Take care with mutating state", will remember this ! :) – SCO Feb 17 '15 at 09:12