GRASS GIS 8 Programmer's Manual  8.5.0dev(2024)-bea8435a9e
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 
67 static int init_gsds(void);
68 static int check_numsets(void);
69 static dataset *get_dataset(int);
70 static int get_type(dataset *);
71 
72 static dataset *Data[MAX_DS];
73 static dataset Ds[MAX_DS]; /* trying to avoid allocation */
74 
75 static int Numsets = 0;
76 
77 static int Cur_id = LUCKY;
78 static int Cur_max;
79 static size_t Tot_mem = 0;
80 
81 /*!
82  \brief Initialize gsds
83  */
84 static 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  */
103 static 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  */
123 static 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  */
144 static 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  */
188 int 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  */
219 int 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  */
281 typbuff *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  */
303 char *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  */
329 int gsds_free_datah(int id)
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];
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  */
369 int 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  */
393 size_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", ds->data_id);
461  G_debug(5, "free_data_buffs(): %.3f Kbytes freed, current total = %.3f",
462  freed / 1000., Tot_mem / 1000.);
463  }
464 
465  return (freed);
466 }
467 
468 /*!
469  \brief Allocates correct buffer according to type, keeps track of total mem
470 
471  \todo add ATTY_CONST
472 
473  \param id dataset id
474  \param dims array of dimensions
475  \param ndims number of dimensions
476  \param type data type
477 
478  \return amount of allocated memory
479  */
480 size_t gsds_alloc_typbuff(int id, int *dims, int ndims, int type)
481 {
482  dataset *ds;
483  int i;
484  size_t siz = 1;
485 
486  if ((ds = get_dataset(id))) {
487  /*
488  free_data_buffs(ds);
489  careful here - allowing > 1 type to coexist (for float -> color
490  conv.) now also use this to allocate a null mask (then if not used,
491  use gsds_free_data_buff(id, ATTY_NULL))
492  */
493 
494  for (i = 0; i < ndims; i++) {
495  ds->dims[i] = dims[i];
496  siz *= dims[i];
497  }
498 
499  switch (type) {
500  case ATTY_NULL:
501  if (ndims != 2) {
502  /* higher dimension bitmaps not supported */
503  return 0;
504  }
505 
506  if (NULL == (ds->databuff.nm = BM_create(dims[1], dims[0]))) {
507  return 0;
508  }
509 
510  siz = BM_get_map_size(ds->databuff.nm);
511 
512  break;
513 
514  case ATTY_MASK:
515  if (ndims != 2) {
516  /* higher dimension bitmaps not supported */
517  return (-1);
518  }
519 
520  if (NULL == (ds->databuff.bm = BM_create(dims[1], dims[0]))) {
521  return 0;
522  }
523 
524  siz = BM_get_map_size(ds->databuff.bm);
525 
526  break;
527 
528  case ATTY_CHAR:
529  siz *= sizeof(char);
530 
531  if (siz) {
532  if (NULL ==
533  (ds->databuff.cb = (unsigned char *)G_malloc(siz))) {
534  return 0;
535  }
536  }
537  else {
538  return 0;
539  }
540 
541  break;
542 
543  case ATTY_SHORT:
544  siz *= sizeof(short);
545 
546  if (siz) {
547  if (NULL == (ds->databuff.sb = (short *)G_malloc(siz))) {
548  return 0;
549  }
550  }
551  else {
552  return 0;
553  }
554 
555  break;
556 
557  case ATTY_INT:
558  siz *= sizeof(int);
559 
560  if (siz) {
561  if (NULL == (ds->databuff.ib = (int *)G_malloc(siz))) {
562  return 0;
563  }
564  }
565  else {
566  return 0;
567  }
568 
569  break;
570 
571  case ATTY_FLOAT:
572  siz *= sizeof(float);
573 
574  if (siz) {
575  if (NULL == (ds->databuff.fb = (float *)G_malloc(siz))) {
576  return 0;
577  }
578  }
579  else {
580  return 0;
581  }
582 
583  break;
584 
585  default:
586  return 0;
587  }
588 
589  ds->changed = 0; /* starting with clean slate */
590  ds->need_reload = 1;
591  ds->numbytes += siz;
592  ds->ndims = ndims;
593  Tot_mem += siz;
594 
595  G_debug(5,
596  "gsds_alloc_typbuff(): %f Kbytes allocated, current total = %f",
597  siz / 1000., Tot_mem / 1000.);
598 
599  return (siz);
600  }
601 
602  return 0;
603 }
604 
605 /*!
606  \brief ADD
607 
608  \param id
609 
610  \return -1 on error
611  \return
612  */
613 int gsds_get_changed(int id)
614 {
615  dataset *ds;
616 
617  if ((ds = get_dataset(id))) {
618  return ((int)ds->changed);
619  }
620 
621  return (-1);
622 }
623 
624 /*!
625  \brief ADD
626 
627  \param id
628  \param reason
629 
630  \return -1 on error
631  \return
632  */
633 int gsds_set_changed(int id, IFLAG reason)
634 {
635  dataset *ds;
636 
637  if ((ds = get_dataset(id))) {
638  ds->changed = reason;
639  }
640 
641  return (-1);
642 }
643 
644 /*!
645  \brief ADD
646 
647  \param id
648 
649  \return
650  */
651 int gsds_get_type(int id)
652 {
653  dataset *ds;
654 
655  ds = get_dataset(id);
656 
657  return (get_type(ds));
658 }
#define NULL
Definition: ccmath.h:32
int BM_destroy(struct BM *)
Destroy bitmap and free all associated memory.
Definition: bitmap.c:89
size_t BM_get_map_size(struct BM *)
Returns size in bytes that bitmap is taking up.
Definition: bitmap.c:241
struct BM * BM_create(int, int)
Create bitmap of dimension x/y and return structure token.
Definition: bitmap.c:58
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
#define G_malloc(n)
Definition: defs/gis.h:94
int G_debug(int, const char *,...) __attribute__((format(printf
char * G_store(const char *)
Copy string to allocated memory.
Definition: strings.c:87
#define GPATH_MAX
Definition: gis.h:194
#define _(str)
Definition: glocale.h:10
#define MAX_DS
Definition: gsds.c:65
int gsds_get_type(int id)
ADD.
Definition: gsds.c:651
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
size_t free_data_buffs(dataset *ds, int typ)
Free data buffer.
Definition: gsds.c:393
char * gsds_get_name(int id)
Get name.
Definition: gsds.c:303
int gsds_set_changed(int id, IFLAG reason)
ADD.
Definition: gsds.c:633
int gsds_free_datah(int id)
Free allocated dataset.
Definition: gsds.c:329
typbuff * gsds_get_typbuff(int id, IFLAG change_flag)
Get data buffer.
Definition: gsds.c:281
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:480
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:613
const char * name
Definition: named_colr.c:6
#define ATTY_SHORT
Definition: ogsf.h:170
#define ATTY_NULL
Definition: ogsf.h:166
#define MAXDIMS
Definition: ogsf.h:177
#define ATTY_ANY
Definition: ogsf.h:172
#define IFLAG
Definition: ogsf.h:71
#define ATTY_FLOAT
Definition: ogsf.h:168
#define ATTY_MASK
Definition: ogsf.h:167
#define ATTY_INT
Definition: ogsf.h:169
#define ATTY_CHAR
Definition: ogsf.h:171
#define strcpy
Definition: parson.c:62
void free(void *)
Definition: ogsf.h:233
IFLAG changed
Definition: ogsf.h:240
typbuff databuff
Definition: ogsf.h:239
int need_reload
Definition: ogsf.h:241
int dims[MAXDIMS]
Definition: ogsf.h:235
int data_id
Definition: ogsf.h:234
size_t numbytes
Definition: ogsf.h:237
int ndims
Definition: ogsf.h:236
char * unique_name
Definition: ogsf.h:238
Definition: ogsf.h:208
float * fb
Definition: ogsf.h:209
struct BM * nm
Definition: ogsf.h:214
unsigned char * cb
Definition: ogsf.h:212
short * sb
Definition: ogsf.h:211
int * ib
Definition: ogsf.h:210
struct BM * bm
Definition: ogsf.h:213