1 /*
2  * Copyright (c) 2017 Hanspeter Portner (dev@open-music-kontrollers.ch)
3  *
4  * This is free software: you can redistribute it and/or modify
5  * it under the terms of the Artistic License 2.0 as published by
6  * The Perl Foundation.
7  *
8  * This source is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * Artistic License 2.0 for more details.
12  *
13  * You should have received a copy of the Artistic License 2.0
14  * along the source as a COPYING file. If not, obtain it from
15  * http://www.perlfoundation.org/artistic_license_2_0.
16  */
17 
18 #include <time.h>
19 #include <sratom/sratom.h>
20 
21 #define NETATOM_IMPLEMENTATION
22 #include <netatom.lv2/netatom.h>
23 
24 #define MAX_URIDS 2048
25 #define MAX_BUF 4092
26 
27 typedef struct _urid_t urid_t;
28 typedef struct _store_t store_t;
29 
30 struct _urid_t {
31 	LV2_URID urid;
32 	char *uri;
33 };
34 
35 struct _store_t {
36 	urid_t urids [MAX_URIDS];
37 	LV2_URID urid;
38 };
39 
40 static LV2_URID
_map(LV2_URID_Map_Handle instance,const char * uri)41 _map(LV2_URID_Map_Handle instance, const char *uri)
42 {
43 	store_t *handle = instance;
44 
45 	urid_t *itm;
46 	for(itm=handle->urids; itm->urid; itm++)
47 	{
48 		if(!strcmp(itm->uri, uri))
49 			return itm->urid;
50 	}
51 
52 	assert(handle->urid + 1 < MAX_URIDS);
53 
54 	// create new
55 	itm->urid = ++handle->urid;
56 	itm->uri = strdup(uri);
57 
58 	return itm->urid;
59 }
60 
61 static const char *
_unmap(LV2_URID_Unmap_Handle instance,LV2_URID urid)62 _unmap(LV2_URID_Unmap_Handle instance, LV2_URID urid)
63 {
64 	store_t *handle = instance;
65 
66 	for(urid_t *itm=handle->urids; itm->urid; itm++)
67 	{
68 		if(itm->urid == urid)
69 			return itm->uri;
70 	}
71 
72 	// not found
73 	return NULL;
74 }
75 
76 static void
_freemap(store_t * handle)77 _freemap(store_t *handle)
78 {
79 	for(urid_t *itm = handle->urids; itm->urid; itm++)
80 		free(itm->uri);
81 }
82 
83 static void
_netatom_test(LV2_URID_Map * map,LV2_URID_Unmap * unmap,bool swap,const LV2_Atom * atom,unsigned iterations)84 _netatom_test(LV2_URID_Map *map, LV2_URID_Unmap *unmap, bool swap,
85 	const LV2_Atom *atom, unsigned iterations)
86 {
87 	static uint8_t buf [MAX_BUF];
88 	netatom_t *netatom = netatom_new(map, unmap, swap);
89 	assert(netatom);
90 
91 	for(unsigned i = 0; i < iterations; i++)
92 	{
93 		memcpy(buf, atom, lv2_atom_total_size(atom));
94 
95 		size_t size_tx = 0;
96 		uint8_t *buf_tx = netatom_serialize(netatom, (LV2_Atom *)buf, MAX_BUF, &size_tx);
97 		assert(buf_tx);
98 
99 		if(iterations == 1)
100 		{
101 			fwrite(buf_tx, size_tx, 1, stdout);
102 
103 #if !defined(_WIN32)
104 			const size_t tot_size = lv2_atom_total_size(atom);
105 			fprintf(stderr, "%zu, %zu, %lf\n", tot_size, size_tx,
106 					(double)size_tx / lv2_atom_total_size(atom));
107 #endif
108 		}
109 
110 		const LV2_Atom *atom_rx = netatom_deserialize(netatom, buf_tx, size_tx);
111 		assert(atom_rx);
112 
113 		const uint32_t size_rx = lv2_atom_total_size(atom_rx);
114 
115 		assert(size_rx == lv2_atom_total_size(atom));
116 		assert(memcmp(atom, atom_rx, size_rx) == 0);
117 	}
118 
119 	netatom_free(netatom);
120 }
121 
122 static void
_sratom_test(LV2_URID_Map * map,LV2_URID_Unmap * unmap,bool pretty,const LV2_Atom * atom,unsigned iterations)123 _sratom_test(LV2_URID_Map *map, LV2_URID_Unmap *unmap, bool pretty,
124 	const LV2_Atom *atom, unsigned iterations)
125 {
126 	Sratom *sratom = sratom_new(map);
127 	assert(sratom);
128 	sratom_set_pretty_numbers(sratom, pretty);
129 	const char *base_uri = "file:///tmp/base";
130 	const SerdNode subject = serd_node_from_string(SERD_URI, (const uint8_t *)(""));
131 	const SerdNode predicate = serd_node_from_string(SERD_URI, (const uint8_t *)(LV2_ATOM__atomTransfer));
132 
133 	for(unsigned i = 0; i < iterations; i++)
134 	{
135 		char *ttl = sratom_to_turtle(sratom, unmap, base_uri, &subject, &predicate,
136 			atom->type, atom->size, LV2_ATOM_BODY_CONST(atom));
137 		assert(ttl);
138 
139 		LV2_Atom *clone = sratom_from_turtle(sratom, base_uri, &subject, &predicate, ttl);
140 		assert(clone);
141 
142 		assert(atom->size == clone->size);
143 		assert(atom->type == clone->type);
144 		//assert(memcmp(LV2_ATOM_BODY_CONST(atom), LV2_ATOM_BODY_CONST(clone), atom->size) == 0);
145 
146 		free(clone);
147 		free(ttl);
148 	}
149 
150 	sratom_free(sratom);
151 }
152 
153 #define MAP(O) map.map(map.handle, "urn:netatom:test#"O)
154 
155 int
main(int argc,char ** argv)156 main(int argc, char **argv)
157 {
158 	static store_t handle;
159 
160 	if(argc < 2)
161 		return -1;
162 	const unsigned iterations = atoi(argv[1]);
163 
164 	LV2_URID_Map map = {
165 		.handle = &handle,
166 		.map = _map
167 	};
168 
169 	LV2_URID_Unmap unmap = {
170 		.handle = &handle,
171 		.unmap = _unmap
172 	};
173 
174 	LV2_Atom_Forge forge;
175 	lv2_atom_forge_init(&forge, &map);
176 
177 	union {
178 		LV2_Atom atom;
179 		uint8_t buf [2048];
180 	} un;
181 
182 	lv2_atom_forge_set_buffer(&forge, un.buf, 2048);
183 
184 	LV2_Atom_Forge_Frame obj_frame;
185 	lv2_atom_forge_object(&forge, &obj_frame, 0, MAP("otype"));
186 	{
187 		lv2_atom_forge_key(&forge, forge.Int);
188 		lv2_atom_forge_int(&forge, 12);
189 
190 		lv2_atom_forge_key(&forge, forge.Bool);
191 		lv2_atom_forge_bool(&forge, 1);
192 
193 		lv2_atom_forge_key(&forge, forge.Long);
194 		lv2_atom_forge_long(&forge, 14);
195 
196 		lv2_atom_forge_key(&forge, forge.Float);
197 		lv2_atom_forge_float(&forge, 1.5);
198 
199 		lv2_atom_forge_key(&forge, forge.Double);
200 		lv2_atom_forge_double(&forge, 4.5);
201 
202 		lv2_atom_forge_key(&forge, forge.String);
203 		lv2_atom_forge_string(&forge, "hello", 5);
204 
205 		lv2_atom_forge_key(&forge, forge.Path);
206 		lv2_atom_forge_path(&forge, "/tmp", 4);
207 
208 		lv2_atom_forge_key(&forge, forge.Literal);
209 		lv2_atom_forge_literal(&forge, "hello", 5, MAP("dtype"), MAP("lang"));
210 
211 		/*
212 		lv2_atom_forge_key(&forge, forge.URI);
213 		lv2_atom_forge_uri(&forge, LV2_URID__map, strlen(LV2_URID__map));
214 		*/
215 
216 		lv2_atom_forge_key(&forge, forge.URID);
217 		lv2_atom_forge_urid(&forge, MAP("key"));
218 
219 		const uint8_t m [3] = {0x90, 0x2f, 0x7f};
220 		lv2_atom_forge_key(&forge, map.map(map.handle, LV2_MIDI__MidiEvent));
221 		lv2_atom_forge_atom(&forge, 3, map.map(map.handle, LV2_MIDI__MidiEvent));
222 		lv2_atom_forge_write(&forge, m, 3);
223 
224 		const uint8_t b [8] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7};
225 		lv2_atom_forge_key(&forge, forge.Chunk);
226 		lv2_atom_forge_atom(&forge, 8, forge.Chunk);
227 		lv2_atom_forge_write(&forge, b, 8);
228 
229 		LV2_Atom_Forge_Frame tup_frame;
230 		lv2_atom_forge_key(&forge, forge.Tuple);
231 		lv2_atom_forge_tuple(&forge, &tup_frame);
232 		{
233 			for(unsigned i = 0; i < 16; i++)
234 				lv2_atom_forge_int(&forge, i);
235 		}
236 		lv2_atom_forge_pop(&forge, &tup_frame);
237 
238 		LV2_Atom_Forge_Frame vec_frame;
239 		lv2_atom_forge_key(&forge, forge.Vector);
240 		lv2_atom_forge_vector_head(&forge, &vec_frame, sizeof(int32_t), forge.Int);
241 		{
242 			for(unsigned i = 0; i < 16; i++)
243 				lv2_atom_forge_int(&forge, i);
244 		}
245 		lv2_atom_forge_pop(&forge, &vec_frame);
246 
247 		LV2_Atom_Forge_Frame seq_frame;
248 		lv2_atom_forge_key(&forge, forge.Sequence);
249 		lv2_atom_forge_sequence_head(&forge, &seq_frame, MAP(LV2_ATOM__frameTime));
250 		{
251 			for(unsigned i = 0; i < 16; i++)
252 			{
253 				lv2_atom_forge_frame_time(&forge, i);
254 				lv2_atom_forge_int(&forge, i);
255 			}
256 		}
257 		lv2_atom_forge_pop(&forge, &seq_frame);
258 	}
259 	lv2_atom_forge_pop(&forge, &obj_frame);
260 
261 	// add some dummy URI to hash map
262 	char tmp [32];
263 	for(int i=0; i<1024; i++)
264 	{
265 		snprintf(tmp, 32, "urn:dummy:%i", i);
266 		map.map(map.handle, tmp);
267 	}
268 
269 #if !defined(__APPLE__) && !defined(_WIN32)
270 	struct timespec t0, t1, t2;
271 	clock_gettime(CLOCK_MONOTONIC, &t0);
272 #endif
273 	_netatom_test(&map, &unmap, true, &un.atom, iterations);
274 #if !defined(__APPLE__) && !defined(_WIN32)
275 	clock_gettime(CLOCK_MONOTONIC, &t1);
276 #endif
277 	_sratom_test(&map, &unmap, false, &un.atom, iterations);
278 #if !defined(__APPLE__) && !defined(_WIN32)
279 	clock_gettime(CLOCK_MONOTONIC, &t2);
280 
281 	const double d1 = (t1.tv_sec - t0.tv_sec) + (t1.tv_nsec - t0.tv_nsec) * 1e-9;
282 	const double d2 = (t2.tv_sec - t1.tv_sec) + (t2.tv_nsec - t1.tv_nsec) * 1e-9;
283 	fprintf(stderr, "%lf s, %lf s, x %lf\n", d1, d2, d2/d1);
284 #endif
285 
286 	_freemap(&handle);
287 
288 	return 0;
289 }
290