// Work with service instance // static void s_service_destroy (service_t **self_p) { assert (self_p); if (*self_p) { service_t *self = *self_p; ztrie_destroy (&self->get_routes); ztrie_destroy (&self->post_routes); ztrie_destroy (&self->put_routes); ztrie_destroy (&self->delete_routes); zlistx_destroy (&self->queue); free (self); *self_p = NULL; } }
JNIEXPORT void JNICALL Java_org_zeromq_czmq_Ztrie__1_1destroy (JNIEnv *env, jclass c, jlong self) { ztrie_destroy ((ztrie_t **) &self); }
/// // Destroy the ztrie. void QmlZtrieAttached::destruct (QmlZtrie *qmlSelf) { ztrie_destroy (&qmlSelf->self); };
void ztrie_test (bool verbose) { printf (" * ztrie: "); // @selftest // Create a new trie for matching strings that can be tokenized by a slash // (e.g. URLs minus the protocol, address and port). ztrie_t *self = ztrie_new ('/'); assert (self); int ret = 0; // Let's start by inserting a couple of routes into the trie. // This one is for the route '/foo/bar' the slash at the beginning of the // route is important because everything before the first delimiter will be // discarded. A slash at the end of a route is optional though. The data // associated with this node is passed without destroy function which means // it must be destroyed by the caller. int foo_bar_data = 10; ret = ztrie_insert_route (self, "/foo/bar", &foo_bar_data, NULL); assert (ret == 0); // Now suppose we like to match all routes with two tokens that start with // '/foo/' but aren't '/foo/bar'. This is possible by using regular // expressions which are enclosed in an opening and closing curly bracket. // Tokens that contain regular expressions are always match after string // based tokens. // Note: There is no order in which regular expressions are sorted thus // if you enter multiple expressions for a route you will have to make // sure they don't have overlapping results. For example '/foo/{[^/]+}' // and '/foo/{\d+} having could turn out badly. int foo_other_data = 100; ret = ztrie_insert_route (self, "/foo/{[^/]+}", &foo_other_data, NULL); assert (ret == 0); // Regular expression are only matched against tokens of the same level. // This allows us to append to are route with a regular expression as if // it were a string. ret = ztrie_insert_route (self, "/foo/{[^/]+}/gulp", NULL, NULL); assert (ret == 0); // Routes are identified by their endpoint, which is the last token of the route. // It is possible to insert routes for a node that already exists but isn't an // endpoint yet. The delimiter at the end of a route is optional and has no effect. ret = ztrie_insert_route (self, "/foo/", NULL, NULL); assert (ret == 0); // If you try to insert a route which already exists the method will return -1. ret = ztrie_insert_route (self, "/foo", NULL, NULL); assert (ret == -1); // It is not allowed to insert routes with empty tokens. ret = ztrie_insert_route (self, "//foo", NULL, NULL); assert (ret == -1); // Everything before the first delimiter is ignored so 'foo/bar/baz' is equivalent // to '/bar/baz'. ret = ztrie_insert_route (self, "foo/bar/baz", NULL, NULL); assert (ret == 0); ret = ztrie_insert_route (self, "/bar/baz", NULL, NULL); assert (ret == -1); // Of course you are allowed to remove routes, in case there is data associated with a // route and a destroy data function has been supplied that data will be destroyed. ret = ztrie_remove_route (self, "/foo"); assert (ret == 0); // Removing a non existent route will as well return -1. ret = ztrie_remove_route (self, "/foo"); assert (ret == -1); // Removing a route with a regular expression must exactly match the entered one. ret = ztrie_remove_route (self, "/foo/{[^/]+}"); assert (ret == 0); // Next we like to match a path by regular expressions and also extract matched // parts of a route. This can be done by naming the regular expression. The name of a // regular expression is entered at the beginning of the curly brackets and separated // by a colon from the regular expression. The first one in this examples is named // 'name' and names the expression '[^/]'. If there is no capturing group defined in // the expression the whole matched string will be associated with this parameter. In // case you don't like the get the whole matched string use a capturing group, like // it has been done for the 'id' parameter. This is nice but you can even match as // many parameter for a token as you like. Therefore simply put the parameter names // separated by colons in front of the regular expression and make sure to add a // capturing group for each parameter. The first parameter will be associated with // the first capturing and so on. char *data = (char *) malloc (80); sprintf (data, "%s", "Hello World!"); ret = ztrie_insert_route (self, "/baz/{name:[^/]+}/{id:--(\\d+)}/{street:nr:(\\a+)(\\d+)}", data, NULL); assert (ret == 0); // There is a lot you can do with regular expression but matching routes // of arbitrary length wont work. Therefore we make use of the asterisk // operator. Just place it at the end of your route, e.g. '/config/bar/*'. ret = ztrie_insert_route (self, "/config/bar/*", NULL, NULL); assert (ret == 0); // Appending to an asterisk as you would to with a regular expression // isn't valid. ret = ztrie_insert_route (self, "/config/bar/*/bar", NULL, NULL); assert (ret == -1); // The asterisk operator will only work as a leaf in the tree. If you // enter an asterisk in the middle of your route it will simply be // interpreted as a string. ret = ztrie_insert_route (self, "/test/*/bar", NULL, NULL); assert (ret == 0); // If a parent has an asterisk as child it is not allowed to have // other siblings. ret = ztrie_insert_route (self, "/config/bar/foo/glup", NULL, NULL); assert (ret != 0); // Test matches bool hasMatch = false; // The route '/bar/foo' will fail to match as this route has never been inserted. hasMatch = ztrie_matches (self, "/bar/foo"); assert (!hasMatch); // The route '/foo/bar' will match and we can obtain the data associated with it. hasMatch = ztrie_matches (self, "/foo/bar"); assert (hasMatch); int foo_bar_hit_data = *((int *) ztrie_hit_data (self)); assert (foo_bar_data == foo_bar_hit_data); // This route is part of another but is no endpoint itself thus the matches will fail. hasMatch = ztrie_matches (self, "/baz/blub"); assert (!hasMatch); // This route will match our named regular expressions route. Thus we can extract data // from the route by their names. hasMatch = ztrie_matches (self, "/baz/blub/--11/abc23"); assert (hasMatch); char *match_data = (char *) ztrie_hit_data (self); assert (streq ("Hello World!", match_data)); zhashx_t *parameters = ztrie_hit_parameters (self); assert (zhashx_size (parameters) == 4); assert (streq ("blub", (char *) zhashx_lookup (parameters, "name"))); assert (streq ("11", (char *) zhashx_lookup (parameters, "id"))); assert (streq ("abc", (char *) zhashx_lookup (parameters, "street"))); assert (streq ("23", (char *) zhashx_lookup (parameters, "nr"))); zhashx_destroy (¶meters); // This will match our asterisk route '/config/bar/*'. As the result we // can obtain the asterisk matched part of the route. hasMatch = ztrie_matches (self, "/config/bar/foo/bar"); assert (hasMatch); assert (streq (ztrie_hit_asterisk_match (self), "foo/bar")); zstr_free (&data); ztrie_destroy (&self); // @end printf ("OK\n"); }