{"action":"created","issue":{"url":"https://api.github.com/repos/camgunz/cmp/issues/5","labels_url":"https://api.github.com/repos/camgunz/cmp/issues/5/labels{/name}","comments_url":"https://api.github.com/repos/camgunz/cmp/issues/5/comments","events_url":"https://api.github.com/repos/camgunz/cmp/issues/5/events","html_url":"https://github.com/camgunz/cmp/issues/5","id":42093379,"number":5,"title":"Add Skipping","user":{"login":"camgunz","id":7122721,"avatar_url":"https://avatars.githubusercontent.com/u/7122721?v=3","gravatar_id":"","url":"https://api.github.com/users/camgunz","html_url":"https://github.com/camgunz","followers_url":"https://api.github.com/users/camgunz/followers","following_url":"https://api.github.com/users/camgunz/following{/other_user}","gists_url":"https://api.github.com/users/camgunz/gists{/gist_id}","starred_url":"https://api.github.com/users/camgunz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/camgunz/subscriptions","organizations_url":"https://api.github.com/users/camgunz/orgs","repos_url":"https://api.github.com/users/camgunz/repos","events_url":"https://api.github.com/users/camgunz/events{/privacy}","received_events_url":"https://api.github.com/users/camgunz/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/camgunz/cmp/labels/enhancement","name":"enhancement","color":"84b6eb"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":6,"created_at":"2014-09-05T21:40:36Z","updated_at":"2015-02-03T15:40:35Z","closed_at":null,"body":"So #3 proposed adding skipping to CMP, and there's some discussion there.\r\n\r\nAfter trying to implement a version, it looks like the only way to fully implement this is by creating a SAX-style state machine.\r\n\r\n\"WHY!?\", you might ask.  Well I'll tell you, hopefully I'm wrong.\r\n\r\nIt's not a backend-support problem.  We can add an optional `skip` callback, and CMP can just set an error whenever `cmp_skip_object` is called on a context where that callback is `NULL`.\r\n\r\nThe problem is nested arrays and maps.  The naive approach is to just have `cmp_skip_object` recursively call itself, but that leaves CMP open to stack overflow attacks via specifically-crafted data.  I absolutely will not do that.\r\n\r\nThe alternative is to have a bunch of state in `cmp_ctx_t` itself and use the heap.  There are a few downsides to this:\r\n\r\n  * It makes heap allocations, and it's doing this for every nested array/map.  This is, therefore, a vector for memory exhaustion given specifically-crafted data.\r\n  * It's a complicated little state machine, in contrast with the rest of CMP, which is extremely clear.\r\n  * It would cause CMP to depend on the C Standard Library, and thus would require a build system.  Not that that's a big deal, but it's still a definite paradigm shift.\r\n\r\n---\r\n\r\nI vote against adding skipping to CMP.  To use the example in #3 of an RPC server, let's say you're getting MessagePack data as a stream and that's your CMP backend (error handling omitted):\r\n\r\n    uint32_t map_size;\r\n\r\n    cmp_read_map(&cmp, &map_size)\r\n\r\n    for (uint32_t i = 0; i < map_size; i++) {\r\n        char *arg_name;\r\n        uint32_t str_size;\r\n\r\n        cmp_read_str_size(&cmp, &str_size);\r\n        read_netstream_string(&arg_name, str_size);\r\n\r\n        if (!rpc_arg_is_valid(arg_name)) {\r\n            cmp_read_str_size(&cmp, &str_size);\r\n            skip_netstream_bytes(str_size);\r\n        }\r\n    }\r\n\r\nThis is pretty simple, and the only thing that would be different if CMP added `cmp_skip_next_object` is `skip_netstream_bytes(str_size)` is replaced with `cmp_skip_next_object(&cmp)`.\r\n\r\nThe problem is that `cmp_skip_next_object` might have to skip a map containing 5000 other arrays, each containing 5000 arrays, each containing 5000 arrays that each contain 5000 entries of the Gettysburg Address.  Skipping an unwanted string is much simpler than skipping the next object, whatever it might be.  Furthermore, skipping can most easily be handled using backend API's designed specifically for that; CMP can add no value there.  Therefore, I think adding skipping to CMP is out of scope.\r\n\r\n---\r\n\r\nThat said, I'm always open to arguments!  :)  If this is a feature you're really needing and you've got a cool idea on how to do it, I'm absolutely happy to work on it (or, even better, merge a PR ;) ).  I just think it's not feasible."},"comment":{"url":"https://api.github.com/repos/camgunz/cmp/issues/comments/72672259","html_url":"https://github.com/camgunz/cmp/issues/5#issuecomment-72672259","issue_url":"https://api.github.com/repos/camgunz/cmp/issues/5","id":72672259,"user":{"login":"beatgammit","id":427337,"avatar_url":"https://avatars.githubusercontent.com/u/427337?v=3","gravatar_id":"","url":"https://api.github.com/users/beatgammit","html_url":"https://github.com/beatgammit","followers_url":"https://api.github.com/users/beatgammit/followers","following_url":"https://api.github.com/users/beatgammit/following{/other_user}","gists_url":"https://api.github.com/users/beatgammit/gists{/gist_id}","starred_url":"https://api.github.com/users/beatgammit/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/beatgammit/subscriptions","organizations_url":"https://api.github.com/users/beatgammit/orgs","repos_url":"https://api.github.com/users/beatgammit/repos","events_url":"https://api.github.com/users/beatgammit/events{/privacy}","received_events_url":"https://api.github.com/users/beatgammit/received_events","type":"User","site_admin":false},"created_at":"2015-02-03T15:40:35Z","updated_at":"2015-02-03T15:40:35Z","body":"> It's probably better to do a while loop; if you're checking for max depth then it's more or less the same\r\n\r\nI suppose you could, bit you'd have to keep track of your iteration index at each level so when you descend, you don't lose your place and forget where you are at an outer array. I suppose this has a smaller impact than recursing though."}}