GRASS GIS 7 Programmer's Manual  7.9.dev(2021)-e5379bbd7
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",
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  */
482 size_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  */
615 int gsds_get_changed(int id)
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  */
635 int 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  */
653 int gsds_get_type(int id)
654 {
655  dataset *ds;
656 
657  ds = get_dataset(id);
658 
659  return (get_type(ds));
660 }
typbuff databuff
Definition: ogsf.h:239
#define G_malloc(n)
Definition: defs/gis.h:112
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
#define ATTY_CHAR
Definition: ogsf.h:168
size_t BM_get_map_size(struct BM *)
Returns size in bytes that bitmap is taking up.
Definition: bitmap.c:245
short * sb
Definition: ogsf.h:208
int gsds_findh(const char *name, IFLAG *changes, IFLAG *types, int begin)
Get handle to gsds.
Definition: gsds.c:188
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 * ib
Definition: ogsf.h:207
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:149
void free(void *)
typbuff * gsds_get_typbuff(int id, IFLAG change_flag)
Get data buffer.
Definition: gsds.c:281
#define NULL
Definition: ccmath.h:32
int BM_destroy(struct BM *)
Destroy bitmap and free all associated memory.
Definition: bitmap.c:90
int gsds_get_type(int id)
ADD.
Definition: gsds.c:653
#define ATTY_SHORT
Definition: ogsf.h:167
#define MAXDIMS
Definition: ogsf.h:173
#define LUCKY
Definition: gsds.c:63
size_t free_data_buffs(dataset *ds, int typ)
Free data buffer.
Definition: gsds.c:393
int ndims
Definition: ogsf.h:236
char * gsds_get_name(int id)
Get name.
Definition: gsds.c:303
#define ATTY_FLOAT
Definition: ogsf.h:165
int gsds_free_data_buff(int id, int typ)
Free allocated buffer.
Definition: gsds.c:369
#define ATTY_INT
Definition: ogsf.h:166
int gsds_get_changed(int id)
ADD.
Definition: gsds.c:615
#define GPATH_MAX
Definition: gis.h:170
#define MAX_DS
Definition: gsds.c:65
struct BM * BM_create(int, int)
Create bitmap of dimension x/y and return structure token.
Definition: bitmap.c:60
size_t numbytes
Definition: ogsf.h:237
#define ATTY_MASK
Definition: ogsf.h:164
char * unique_name
Definition: ogsf.h:238
#define ATTY_ANY
Definition: ogsf.h:169
Definition: ogsf.h:204
#define ATTY_NULL
Definition: ogsf.h:163
#define _(str)
Definition: glocale.h:10
char * G_store(const char *)
Copy string to allocated memory.
Definition: strings.c:87
Definition: ogsf.h:232
const char * name
Definition: named_colr.c:7
int need_reload
Definition: ogsf.h:241
int dims[MAXDIMS]
Definition: ogsf.h:235
int data_id
Definition: ogsf.h:234
IFLAG changed
Definition: ogsf.h:240
int gsds_newh(const char *name)
Get handle to gsds.
Definition: gsds.c:219
struct BM * nm
Definition: ogsf.h:211
int gsds_set_changed(int id, IFLAG reason)
ADD.
Definition: gsds.c:635
float * fb
Definition: ogsf.h:206
int G_debug(int, const char *,...) __attribute__((format(printf
int gsds_free_datah(int id)
Free allocated dataset.
Definition: gsds.c:329
struct BM * bm
Definition: ogsf.h:210
#define IFLAG
Definition: ogsf.h:69
unsigned char * cb
Definition: ogsf.h:209