GRASS GIS 8 Programmer's Manual 8.2.0(2022)-exported
gsds.c
Go to the documentation of this file.
1/*!
2 \file lib/ogsf/gsds.c
3
4 \brief OGSF library - dataset loading and management (lower level functions)
5
6 GRASS OpenGL gsurf OGSF Library
7
8 The idea here is to treat datasets as separate objects, which SHOULD:
9 - allow easier reuse of data for different attributes.
10 - allow a mechanism for changing data and have changes reflected
11 in each attribute using that data.
12 - allow a mechanism to automatically update data when the data source
13 is changed.
14 - allow easier weaning from GRASS.
15 - allow easier use of shared memory between processes.
16
17 These structures are defined in gstypes.h:
18
19 <code>
20 typedef struct{
21 float *fb;
22 int *ib;
23 short *sb;
24 char *cb;
25 struct BM *bm;
26 } typbuff;
27 </code>
28
29 How about adding a transform func here, so GET_MAPATT would do an
30 on-the-fly transformation? Or even a transform func LIST!
31
32 <code>
33 typedef struct{
34 int data_id;
35 int dims[MAXDIMS];
36 int ndims;
37 int numbytes;
38 char unique_name[80];
39 typbuff databuff;
40 int changed;
41 int need_reload;
42 } dataset;
43 </code>
44
45 (C) 1999-2008 by the GRASS Development Team
46
47 This program is free software under the
48 GNU General Public License (>=v2).
49 Read the file COPYING that comes with GRASS
50 for details.
51
52 \author Bill Brown UI GMS Lab
53 \author Doxygenized by Martin Landa <landa.martin gmail.com> (May 2008)
54 */
55
56#include <stdlib.h>
57#include <string.h>
58
59#include <grass/gis.h>
60#include <grass/glocale.h>
61#include <grass/ogsf.h>
62
63#define LUCKY 33
64#define BLOC 20
65#define MAX_DS 100
66
67static int init_gsds(void);
68static int check_numsets(void);
69static dataset *get_dataset(int);
70static int get_type(dataset *);
71
72static dataset *Data[MAX_DS];
73static dataset Ds[MAX_DS]; /* trying to avoid allocation */
74
75static int Numsets = 0;
76
77static int Cur_id = LUCKY;
78static int Cur_max;
79static size_t Tot_mem = 0;
80
81/*!
82 \brief Initialize gsds
83 */
84static int init_gsds(void)
85{
86 int i;
87
88 for (i = 0; i < MAX_DS; i++) {
89 /* avoiding dynamic allocation */
90 Data[i] = &(Ds[i]);
91 }
92
93 Cur_max = MAX_DS;
94
95 return (1);
96}
97
98/*!
99 \brief Check numsets
100
101 \return 0 numset < cur_max
102 */
103static int check_numsets(void)
104{
105 if (Numsets < Cur_max) {
106 return (0);
107 }
108
109 G_fatal_error(_("Maximum number of datasets exceeded"));
110
111 /* This return statement keeps compilers happy, it is never executed */
112 return (0);
113}
114
115/*!
116 \brief Get dataset
117
118 \param id data id
119
120 \return pointer to dataset struct
121 \return NULL dataset not found
122 */
123static dataset *get_dataset(int id)
124{
125 int i;
126
127 for (i = 0; i < Numsets; i++) {
128 if (Data[i]->data_id == id) {
129 return (Data[i]);
130 }
131 }
132
133 return (NULL);
134}
135
136/*!
137 \brief Get type
138
139 \param ds pointer to dataset struct
140
141 \return type code
142 \return -1 unsupported type
143 */
144static int get_type(dataset * ds)
145{
146 if (ds) {
147 if (ds->databuff.bm) {
148 return (ATTY_MASK);
149 }
150
151 if (ds->databuff.cb) {
152 return (ATTY_CHAR);
153 }
154
155 if (ds->databuff.sb) {
156 return (ATTY_SHORT);
157 }
158
159 if (ds->databuff.ib) {
160 return (ATTY_INT);
161 }
162
163 if (ds->databuff.fb) {
164 return (ATTY_FLOAT);
165 }
166 }
167
168 return (-1);
169}
170
171/*!
172 \brief Get handle to gsds.
173
174 Successive calls will continue search until "begin" is set
175 (problem here is, unique_name no longer uniquely identifies
176 dataset, since changes may be made; but unique_name should still
177 be useful for reloading dataset)
178 changes & types are set to actual for dataset if found.
179
180 \param name
181 \param changes,types acceptable changes & types, flags may be or'd
182 not changed is assumed to always be acceptable
183 \param begin flag to indicate search from beginning
184
185 \return data id
186 \return -1 not found
187 */
188int gsds_findh(const char *name, IFLAG * changes, IFLAG * types, int begin)
189{
190 static int i;
191 int start;
192
193 start = begin ? 0 : i + 1;
194
195 for (i = start; i < Numsets; i++) {
196 if (!strcmp(Data[i]->unique_name, name)) {
197 if ((Data[i]->changed & *changes) || !(Data[i]->changed)) {
198 if (get_type(Data[i]) & *types) {
199 *changes = Data[i]->changed;
200 *types = get_type(Data[i]);
201
202 return (Data[i]->data_id);
203 }
204 }
205 }
206 }
207
208 return (-1);
209}
210
211/*!
212 \brief Get handle to gsds
213
214 \param name raster map name
215
216 \return -1 on failure
217 \return data id
218 */
219int gsds_newh(const char *name)
220{
221 dataset *new;
222 static int first = 1;
223 int i;
224
225 if (first) {
226 if (0 > init_gsds()) {
227 return (-1);
228 }
229
230 first = 0;
231 }
232 else if (0 > check_numsets()) {
233 return (-1);
234 }
235
236 if (!name) {
237 return (-1);
238 }
239
240 new = Data[Numsets];
241
242 if (new) {
243 Numsets++;
244 new->data_id = Cur_id++;
245
246 for (i = 0; i < MAXDIMS; i++) {
247 new->dims[i] = 0;
248 }
249
250 new->unique_name = G_store(name);
251 new->databuff.fb = NULL;
252 new->databuff.ib = NULL;
253 new->databuff.sb = NULL;
254 new->databuff.cb = NULL;
255 new->databuff.bm = NULL;
256 new->databuff.nm = NULL;
257 new->databuff.k = 0.0;
258 new->changed = 0;
259 new->ndims = 0;
260 new->need_reload = 1;
261
262 return (new->data_id);
263 }
264
265 return (-1);
266}
267
268/*!
269 \brief Get data buffer
270
271 Doesn't prevent writing a buff thats's been gotten with change_flag
272 == 0 (could return a copy, but willing to trust calling func for
273 now)
274
275 \param id dataset id
276 \param change_flag set changed flag
277
278 \return pointer to typbuff struct
279 \return NULL on failure
280 */
281typbuff *gsds_get_typbuff(int id, IFLAG change_flag)
282{
283 dataset *ds;
284
285 if ((ds = get_dataset(id))) {
286 ds->changed = ds->changed | change_flag;
287 ds->need_reload = 0;
288
289 return (&(ds->databuff));
290 }
291
292 return (NULL);
293}
294
295/*!
296 \brief Get name
297
298 \param id
299
300 \return name
301 \return NULL on failure
302 */
303char *gsds_get_name(int id)
304{
305 int i;
306 dataset *fds;
307 static char retstr[GPATH_MAX];
308
309 for (i = 0; i < Numsets; i++) {
310 if (Data[i]->data_id == id) {
311 fds = Data[i];
312 strcpy(retstr, fds->unique_name);
313
314 return (retstr);
315 }
316 }
317
318 return (NULL);
319}
320
321/*!
322 \brief Free allocated dataset
323
324 \param id
325
326 \return 0 not found
327 \return 1 found
328 */
330{
331 int i, j, found = 0;
332 dataset *fds;
333
334 G_debug(3, "gsds_free_datah");
335
336 for (i = 0; i < Numsets; i++) {
337 if (Data[i]->data_id == id) {
338 found = 1;
339 fds = Data[i];
340 free_data_buffs(fds, ATTY_ANY);
341 G_free((void *)fds->unique_name);
342 fds->unique_name = NULL;
343 fds->data_id = 0;
344
345 for (j = i; j < (Numsets - 1); j++) {
346 Data[j] = Data[j + 1];
347 }
348
349 Data[j] = fds;
350 }
351 }
352
353 if (found) {
354 --Numsets;
355 }
356
357 return (found);
358}
359
360/*!
361 \brief Free allocated buffer
362
363 \param id dataset id
364 \param typ data type
365
366 \return 0 not found
367 \return 1 found
368 */
369int gsds_free_data_buff(int id, int typ)
370{
371 int i, found = 0;
372 dataset *fds;
373
374 for (i = 0; i < Numsets; i++) {
375 if (Data[i]->data_id == id) {
376 found = 1;
377 fds = Data[i];
378 free_data_buffs(fds, typ);
379 }
380 }
381
382 return (found);
383}
384
385/*!
386 \brief Free data buffer
387
388 \param ds pointer to dataset struct
389 \param typ data type
390
391 \return freed size
392 */
393size_t free_data_buffs(dataset * ds, int typ)
394{
395 int i;
396 size_t siz, nsiz = 1, freed = 0;
397
398 for (i = 0; i < ds->ndims; i++) {
399 nsiz *= ds->dims[i];
400 }
401
402 if (typ & ATTY_NULL) {
403 if (ds->databuff.nm) {
404 siz = BM_get_map_size(ds->databuff.nm);
405 BM_destroy(ds->databuff.nm);
406 ds->databuff.nm = NULL;
407 freed += siz;
408 }
409 }
410
411 if (typ & ATTY_MASK) {
412 if (ds->databuff.bm) {
413 siz = BM_get_map_size(ds->databuff.bm);
414 BM_destroy(ds->databuff.bm);
415 ds->databuff.bm = NULL;
416 freed += siz;
417 }
418 }
419
420 if (typ & ATTY_CHAR) {
421 if (ds->databuff.cb) {
422 siz = nsiz * sizeof(char);
423 free(ds->databuff.cb);
424 ds->databuff.cb = NULL;
425 freed += siz;
426 }
427 }
428
429 if (typ & ATTY_SHORT) {
430 if (ds->databuff.sb) {
431 siz = nsiz * sizeof(short);
432 free(ds->databuff.sb);
433 ds->databuff.sb = NULL;
434 freed += siz;
435 }
436 }
437
438 if (typ & ATTY_INT) {
439 if (ds->databuff.ib) {
440 siz = nsiz * sizeof(int);
441 free(ds->databuff.ib);
442 ds->databuff.ib = NULL;
443 freed += siz;
444 }
445 }
446
447 if (typ & ATTY_FLOAT) {
448 if (ds->databuff.fb) {
449 siz = nsiz * sizeof(float);
450 free(ds->databuff.fb);
451 ds->databuff.fb = NULL;
452 freed += siz;
453 }
454 }
455
456 Tot_mem -= freed;
457 ds->numbytes -= freed;
458
459 if (freed) {
460 G_debug(5, "free_data_buffs(): freed data from id no. %d",
461 ds->data_id);
462 G_debug(5,
463 "free_data_buffs(): %.3f Kbytes freed, current total = %.3f",
464 freed / 1000., Tot_mem / 1000.);
465 }
466
467 return (freed);
468}
469
470/*!
471 \brief Allocates correct buffer according to type, keeps track of total mem
472
473 \todo add ATTY_CONST
474
475 \param id dataset id
476 \param dims array of dimensions
477 \param ndims number of dimensions
478 \param type data type
479
480 \return amount of allocated memory
481 */
482size_t gsds_alloc_typbuff(int id, int *dims, int ndims, int type)
483{
484 dataset *ds;
485 int i;
486 size_t siz = 1;
487
488 if ((ds = get_dataset(id))) {
489 /*
490 free_data_buffs(ds);
491 careful here - allowing > 1 type to coexist (for float -> color conv.)
492 now also use this to allocate a null mask
493 (then if not used, use gsds_free_data_buff(id, ATTY_NULL))
494 */
495
496 for (i = 0; i < ndims; i++) {
497 ds->dims[i] = dims[i];
498 siz *= dims[i];
499 }
500
501 switch (type) {
502 case ATTY_NULL:
503 if (ndims != 2) {
504 /* higher dimension bitmaps not supported */
505 return 0;
506 }
507
508 if (NULL == (ds->databuff.nm = BM_create(dims[1], dims[0]))) {
509 return 0;
510 }
511
512 siz = BM_get_map_size(ds->databuff.nm);
513
514 break;
515
516 case ATTY_MASK:
517 if (ndims != 2) {
518 /* higher dimension bitmaps not supported */
519 return (-1);
520 }
521
522 if (NULL == (ds->databuff.bm = BM_create(dims[1], dims[0]))) {
523 return 0;
524 }
525
526 siz = BM_get_map_size(ds->databuff.bm);
527
528 break;
529
530 case ATTY_CHAR:
531 siz *= sizeof(char);
532
533 if (siz) {
534 if (NULL ==
535 (ds->databuff.cb = (unsigned char *)G_malloc(siz))) {
536 return 0;
537 }
538 }
539 else {
540 return 0;
541 }
542
543 break;
544
545 case ATTY_SHORT:
546 siz *= sizeof(short);
547
548 if (siz) {
549 if (NULL == (ds->databuff.sb = (short *)G_malloc(siz))) {
550 return 0;
551 }
552 }
553 else {
554 return 0;
555 }
556
557 break;
558
559 case ATTY_INT:
560 siz *= sizeof(int);
561
562 if (siz) {
563 if (NULL == (ds->databuff.ib = (int *)G_malloc(siz))) {
564 return 0;
565 }
566 }
567 else {
568 return 0;
569 }
570
571 break;
572
573 case ATTY_FLOAT:
574 siz *= sizeof(float);
575
576 if (siz) {
577 if (NULL == (ds->databuff.fb = (float *)G_malloc(siz))) {
578 return 0;
579 }
580 }
581 else {
582 return 0;
583 }
584
585 break;
586
587 default:
588 return 0;
589 }
590
591 ds->changed = 0; /* starting with clean slate */
592 ds->need_reload = 1;
593 ds->numbytes += siz;
594 ds->ndims = ndims;
595 Tot_mem += siz;
596
597 G_debug(5,
598 "gsds_alloc_typbuff(): %f Kbytes allocated, current total = %f",
599 siz / 1000., Tot_mem / 1000.);
600
601 return (siz);
602 }
603
604 return 0;
605}
606
607/*!
608 \brief ADD
609
610 \param id
611
612 \return -1 on error
613 \return
614 */
616{
617 dataset *ds;
618
619 if ((ds = get_dataset(id))) {
620 return ((int)ds->changed);
621 }
622
623 return (-1);
624}
625
626/*!
627 \brief ADD
628
629 \param id
630 \param reason
631
632 \return -1 on error
633 \return
634 */
635int gsds_set_changed(int id, IFLAG reason)
636{
637 dataset *ds;
638
639 if ((ds = get_dataset(id))) {
640 ds->changed = reason;
641 }
642
643 return (-1);
644}
645
646/*!
647 \brief ADD
648
649 \param id
650
651 \return
652 */
653int gsds_get_type(int id)
654{
655 dataset *ds;
656
657 ds = get_dataset(id);
658
659 return (get_type(ds));
660}
void G_free(void *buf)
Free allocated memory.
Definition: alloc.c:149
struct BM * BM_create(int x, int y)
Create bitmap of dimension x/y and return structure token.
Definition: bitmap.c:60
size_t BM_get_map_size(struct BM *map)
Returns size in bytes that bitmap is taking up.
Definition: bitmap.c:248
int BM_destroy(struct BM *map)
Destroy bitmap and free all associated memory.
Definition: bitmap.c:93
#define NULL
Definition: ccmath.h:32
int G_debug(int level, const char *msg,...)
Print debugging message.
Definition: debug.c:65
void G_fatal_error(const char *msg,...)
Print a fatal error message to stderr.
Definition: gis/error.c:160
#define MAX_DS
Definition: gsds.c:65
char * gsds_get_name(int id)
Get name.
Definition: gsds.c:303
int gsds_get_type(int id)
ADD.
Definition: gsds.c:653
int gsds_newh(const char *name)
Get handle to gsds.
Definition: gsds.c:219
int gsds_findh(const char *name, IFLAG *changes, IFLAG *types, int begin)
Get handle to gsds.
Definition: gsds.c:188
#define LUCKY
Definition: gsds.c:63
typbuff * gsds_get_typbuff(int id, IFLAG change_flag)
Get data buffer.
Definition: gsds.c:281
size_t free_data_buffs(dataset *ds, int typ)
Free data buffer.
Definition: gsds.c:393
int gsds_set_changed(int id, IFLAG reason)
ADD.
Definition: gsds.c:635
int gsds_free_datah(int id)
Free allocated dataset.
Definition: gsds.c:329
size_t gsds_alloc_typbuff(int id, int *dims, int ndims, int type)
Allocates correct buffer according to type, keeps track of total mem.
Definition: gsds.c:482
int gsds_free_data_buff(int id, int typ)
Free allocated buffer.
Definition: gsds.c:369
int gsds_get_changed(int id)
ADD.
Definition: gsds.c:615
const char * name
Definition: named_colr.c:7
char * G_store(const char *s)
Copy string to allocated memory.
Definition: strings.c:87