Coverage Report

Created: 2025-12-03 08:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/netcdf/netcdfsgwriterutil.h
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  netCDF read/write Driver
4
 * Purpose:  GDAL bindings over netCDF library.
5
 * Author:   Winor Chen <wchen329 at wisc.edu>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2019, Winor Chen <wchen329 at wisc.edu>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
#ifndef __NETCDFSGWRITERUTIL_H__
13
#define __NETCDFSGWRITERUTIL_H__
14
#include <cstdio>
15
#include <queue>
16
#include <typeinfo>
17
#include <vector>
18
#include "cpl_vsi.h"
19
#include "ogr_core.h"
20
#include "ogrsf_frmts.h"
21
#include "netcdflayersg.h"
22
#include "netcdfsg.h"
23
#include "netcdfvirtual.h"
24
25
namespace nccfdriver
26
{
27
28
/* OGR_SGeometry_Feature
29
 * Constructs over a OGRFeature
30
 * gives some basic information about that SGeometry Feature such as
31
 * Hold references... limited to scope of its references
32
 * - what's its geometry type
33
 * - how much total points it has
34
 * - how many parts it has
35
 * - a vector of counts of points for each part
36
 */
37
class SGeometry_Feature
38
{
39
    bool hasInteriorRing;
40
    const OGRGeometry *geometry_ref;
41
    geom_t type;
42
    size_t total_point_count;
43
    size_t total_part_count;
44
    std::vector<size_t> ppart_node_count;
45
    std::vector<bool> part_at_ind_interior;  // for use with Multipolygons ONLY
46
    mutable OGRPoint pt_buffer;
47
48
  public:
49
    geom_t getType()
50
0
    {
51
0
        return this->type;
52
0
    }
53
54
    size_t getTotalNodeCount()
55
0
    {
56
0
        return this->total_point_count;
57
0
    }
58
59
    size_t getTotalPartCount()
60
0
    {
61
0
        return this->total_part_count;
62
0
    }
63
64
    std::vector<size_t> &getPerPartNodeCount()
65
0
    {
66
0
        return this->ppart_node_count;
67
0
    }
68
69
    const OGRPoint &getPoint(size_t part_no, int point_index) const;
70
    explicit SGeometry_Feature(OGRFeature &);
71
72
    bool getHasInteriorRing()
73
0
    {
74
0
        return this->hasInteriorRing;
75
0
    }
76
77
    bool IsPartAtIndInteriorRing(size_t ind)
78
0
    {
79
0
        return this->part_at_ind_interior[ind];
80
0
    }  // ONLY used for Multipolygon
81
};
82
83
/* A memory buffer with a soft limit
84
 * Has basic capability of over quota checking, and memory counting
85
 */
86
class WBuffer
87
{
88
    unsigned long long used_mem = 0;
89
90
  public:
91
    /* addCount(...)
92
     * Takes in a size, and directly adds that size to memory count
93
     */
94
    void addCount(unsigned long long memuse);
95
96
    /* subCount(...)
97
     * Directly subtracts the specified size from used_mem
98
     */
99
    void subCount(unsigned long long memfree);
100
101
    unsigned long long &getUsage()
102
0
    {
103
0
        return used_mem;
104
0
    }
105
106
    void reset()
107
0
    {
108
0
        this->used_mem = 0;
109
0
    }
110
111
    WBuffer()
112
45.0k
    {
113
45.0k
    }
114
};
115
116
/* OGR_SGFS_Transaction
117
 * Abstract class for a committable transaction
118
 *
119
 */
120
class OGR_SGFS_Transaction /* non final */
121
{
122
    int varId = INVALID_VAR_ID;
123
124
  public:
125
    /* int commit(...);
126
     * Arguments: int ncid, the dataset to write to
127
     *            int write_loc, the index in which to write to
128
     * Implementation: should write the transaction to netCDF file
129
     *
130
     */
131
    virtual void commit(netCDFVID &n, size_t write_loc) = 0;
132
133
    /* unsigned long long count(...)
134
     * Implementation: supposed to return an approximate count of memory usage
135
     * Most classes will implement with sizeof(*this), except if otherwise
136
     * uncounted for dynamic allocation is involved.
137
     */
138
    virtual unsigned long long count() = 0;
139
140
    /* appendToLog
141
     * Implementation - given a file pointer, a transaction will be written to
142
     * that log file in the format:
143
     * -
144
     * transactionVarId - sizeof(int) bytes
145
     * NC_TYPE - sizeof(int) bytes
146
     * (nc_char only) OP - 1 byte (0 if does not require COUNT or non-zero i.e.
147
     * 1 if does) (nc_char only): SIZE of data - sizeof(size_t) bytes DATA -
148
     * size depends on NC_TYPE
149
     */
150
    virtual void appendToLog(VSILFILE *) = 0;
151
152
    /* ~OGR_SGFS_Transaction()
153
     * Empty. Simply here to stop the compiler from complaining...
154
     */
155
    virtual ~OGR_SGFS_Transaction();
156
157
    /* OGR_SGFS_Transaction()
158
     * Empty. Simply here to stop one of the CI machines from complaining...
159
     */
160
    OGR_SGFS_Transaction()
161
0
    {
162
0
    }
163
164
    /* void getVarId(...);
165
     * Gets the var in which to commit the transaction to.
166
     */
167
    int getVarId()
168
0
    {
169
0
        return this->varId;
170
0
    }
171
172
    /* nc_type getType
173
     * Returns the type of transaction being saved
174
     */
175
    virtual nc_type getType() = 0;
176
177
    /* void setVarId(...);
178
     * Sets the var in which to commit the transaction to.
179
     */
180
    void setVarId(int vId)
181
0
    {
182
0
        this->varId = vId;
183
0
    }
184
};
185
186
typedef std::map<int, void *> NCWMap;
187
typedef std::pair<int, void *> NCWEntry;  // NC Writer Entry
188
typedef std::unique_ptr<OGR_SGFS_Transaction>
189
    MTPtr;  // a.k.a Managed Transaction Ptr
190
191
template <class T_c_type, nc_type T_nc_type>
192
void genericLogAppend(T_c_type r, int vId, VSILFILE *f)
193
0
{
194
0
    T_c_type rep = r;
195
0
    int varId = vId;
196
0
    int type = T_nc_type;
197
0
    VSIFWriteL(&varId, sizeof(int), 1, f);     // write varID data
198
0
    VSIFWriteL(&type, sizeof(int), 1, f);      // write NC type
199
0
    VSIFWriteL(&rep, sizeof(T_c_type), 1, f);  // write data
200
0
}
Unexecuted instantiation: void nccfdriver::genericLogAppend<signed char, 1>(signed char, int, VSIVirtualHandle*)
Unexecuted instantiation: void nccfdriver::genericLogAppend<unsigned char, 7>(unsigned char, int, VSIVirtualHandle*)
Unexecuted instantiation: void nccfdriver::genericLogAppend<short, 3>(short, int, VSIVirtualHandle*)
Unexecuted instantiation: void nccfdriver::genericLogAppend<unsigned short, 8>(unsigned short, int, VSIVirtualHandle*)
Unexecuted instantiation: void nccfdriver::genericLogAppend<int, 4>(int, int, VSIVirtualHandle*)
Unexecuted instantiation: void nccfdriver::genericLogAppend<unsigned int, 9>(unsigned int, int, VSIVirtualHandle*)
Unexecuted instantiation: void nccfdriver::genericLogAppend<long long, 10>(long long, int, VSIVirtualHandle*)
Unexecuted instantiation: void nccfdriver::genericLogAppend<unsigned long long, 11>(unsigned long long, int, VSIVirtualHandle*)
Unexecuted instantiation: void nccfdriver::genericLogAppend<float, 5>(float, int, VSIVirtualHandle*)
Unexecuted instantiation: void nccfdriver::genericLogAppend<double, 6>(double, int, VSIVirtualHandle*)
201
202
template <class T_c_type, class T_r_type>
203
MTPtr genericLogDataRead(int varId, VSILFILE *f)
204
0
{
205
0
    T_r_type data;
206
0
    if (!VSIFReadL(&data, sizeof(T_r_type), 1, f))
207
0
    {
208
0
        return MTPtr(nullptr);  // invalid read case
209
0
    }
210
0
    return MTPtr(new T_c_type(varId, data));
211
0
}
Unexecuted instantiation: std::__1::unique_ptr<nccfdriver::OGR_SGFS_Transaction, std::__1::default_delete<nccfdriver::OGR_SGFS_Transaction> > nccfdriver::genericLogDataRead<nccfdriver::OGR_SGFS_NC_Transaction_Generic<signed char, 1>, signed char>(int, VSIVirtualHandle*)
Unexecuted instantiation: std::__1::unique_ptr<nccfdriver::OGR_SGFS_Transaction, std::__1::default_delete<nccfdriver::OGR_SGFS_Transaction> > nccfdriver::genericLogDataRead<nccfdriver::OGR_SGFS_NC_Transaction_Generic<short, 3>, short>(int, VSIVirtualHandle*)
Unexecuted instantiation: std::__1::unique_ptr<nccfdriver::OGR_SGFS_Transaction, std::__1::default_delete<nccfdriver::OGR_SGFS_Transaction> > nccfdriver::genericLogDataRead<nccfdriver::OGR_SGFS_NC_Transaction_Generic<int, 4>, int>(int, VSIVirtualHandle*)
Unexecuted instantiation: std::__1::unique_ptr<nccfdriver::OGR_SGFS_Transaction, std::__1::default_delete<nccfdriver::OGR_SGFS_Transaction> > nccfdriver::genericLogDataRead<nccfdriver::OGR_SGFS_NC_Transaction_Generic<float, 5>, float>(int, VSIVirtualHandle*)
Unexecuted instantiation: std::__1::unique_ptr<nccfdriver::OGR_SGFS_Transaction, std::__1::default_delete<nccfdriver::OGR_SGFS_Transaction> > nccfdriver::genericLogDataRead<nccfdriver::OGR_SGFS_NC_Transaction_Generic<double, 6>, double>(int, VSIVirtualHandle*)
Unexecuted instantiation: std::__1::unique_ptr<nccfdriver::OGR_SGFS_Transaction, std::__1::default_delete<nccfdriver::OGR_SGFS_Transaction> > nccfdriver::genericLogDataRead<nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned char, 7>, unsigned char>(int, VSIVirtualHandle*)
Unexecuted instantiation: std::__1::unique_ptr<nccfdriver::OGR_SGFS_Transaction, std::__1::default_delete<nccfdriver::OGR_SGFS_Transaction> > nccfdriver::genericLogDataRead<nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned short, 8>, unsigned short>(int, VSIVirtualHandle*)
Unexecuted instantiation: std::__1::unique_ptr<nccfdriver::OGR_SGFS_Transaction, std::__1::default_delete<nccfdriver::OGR_SGFS_Transaction> > nccfdriver::genericLogDataRead<nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned int, 9>, unsigned int>(int, VSIVirtualHandle*)
Unexecuted instantiation: std::__1::unique_ptr<nccfdriver::OGR_SGFS_Transaction, std::__1::default_delete<nccfdriver::OGR_SGFS_Transaction> > nccfdriver::genericLogDataRead<nccfdriver::OGR_SGFS_NC_Transaction_Generic<long long, 10>, long long>(int, VSIVirtualHandle*)
Unexecuted instantiation: std::__1::unique_ptr<nccfdriver::OGR_SGFS_Transaction, std::__1::default_delete<nccfdriver::OGR_SGFS_Transaction> > nccfdriver::genericLogDataRead<nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned long long, 11>, unsigned long long>(int, VSIVirtualHandle*)
212
213
/* OGR_SGFS_NC_Char_Transaction
214
 * Writes to an NC_CHAR variable
215
 */
216
class OGR_SGFS_NC_Char_Transaction final : public OGR_SGFS_Transaction
217
{
218
    std::string char_rep;
219
220
  public:
221
    void commit(netCDFVID &n, size_t write_loc) override
222
0
    {
223
0
        n.nc_put_vvar1_text(OGR_SGFS_Transaction::getVarId(), &write_loc,
224
0
                            char_rep.c_str());
225
0
    }
226
227
    unsigned long long count() override
228
0
    {
229
0
        return char_rep.size() + sizeof(*this);
230
0
    }  // account for actual character representation, this class
231
232
    void appendToLog(VSILFILE *f) override;
233
234
    nc_type getType() override
235
0
    {
236
0
        return NC_CHAR;
237
0
    }
238
239
    OGR_SGFS_NC_Char_Transaction(int i_varId, const char *pszVal)
240
0
        : char_rep(pszVal)
241
0
    {
242
0
        OGR_SGFS_Transaction::setVarId(i_varId);
243
0
    }
244
};
245
246
/* OGR_SGFS_NC_CharA_Transaction
247
 * Writes to an NC_CHAR variable, using vara instead of var1
248
 * Used to store 2D character array values, specifically
249
 */
250
class OGR_SGFS_NC_CharA_Transaction final : public OGR_SGFS_Transaction
251
{
252
    std::string char_rep;
253
    size_t counts[2];
254
255
  public:
256
    void commit(netCDFVID &n, size_t write_loc) override
257
0
    {
258
0
        size_t ind[2] = {write_loc, 0};
259
0
        n.nc_put_vvara_text(OGR_SGFS_Transaction::getVarId(), ind, counts,
260
0
                            char_rep.c_str());
261
0
    }
262
263
    unsigned long long count() override
264
0
    {
265
0
        return char_rep.size() + sizeof(*this);
266
0
    }  // account for actual character representation, this class
267
268
    void appendToLog(VSILFILE *f) override;
269
270
    nc_type getType() override
271
0
    {
272
0
        return NC_CHAR;
273
0
    }
274
275
    OGR_SGFS_NC_CharA_Transaction(int i_varId, const char *pszVal)
276
0
        : char_rep(pszVal), counts{1, char_rep.length()}
277
0
    {
278
0
        OGR_SGFS_Transaction::setVarId(i_varId);
279
0
    }
280
};
281
282
template <class VClass, nc_type ntype>
283
class OGR_SGFS_NC_Transaction_Generic final : public OGR_SGFS_Transaction
284
{
285
    VClass rep;
286
287
  public:
288
    void commit(netCDFVID &n, size_t write_loc) override
289
0
    {
290
0
        n.nc_put_vvar_generic<VClass>(OGR_SGFS_Transaction::getVarId(),
291
0
                                      &write_loc, &rep);
292
0
    }
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<signed char, 1>::commit(nccfdriver::netCDFVID&, unsigned long)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned char, 7>::commit(nccfdriver::netCDFVID&, unsigned long)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<short, 3>::commit(nccfdriver::netCDFVID&, unsigned long)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned short, 8>::commit(nccfdriver::netCDFVID&, unsigned long)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<int, 4>::commit(nccfdriver::netCDFVID&, unsigned long)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned int, 9>::commit(nccfdriver::netCDFVID&, unsigned long)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<long long, 10>::commit(nccfdriver::netCDFVID&, unsigned long)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned long long, 11>::commit(nccfdriver::netCDFVID&, unsigned long)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<float, 5>::commit(nccfdriver::netCDFVID&, unsigned long)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<double, 6>::commit(nccfdriver::netCDFVID&, unsigned long)
293
294
    unsigned long long count() override
295
0
    {
296
0
        return sizeof(*this);
297
0
    }
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<signed char, 1>::count()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned char, 7>::count()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<short, 3>::count()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned short, 8>::count()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<int, 4>::count()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned int, 9>::count()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<long long, 10>::count()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned long long, 11>::count()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<float, 5>::count()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<double, 6>::count()
298
299
    void appendToLog(VSILFILE *f) override
300
0
    {
301
0
        genericLogAppend<VClass, ntype>(rep, OGR_SGFS_Transaction::getVarId(),
302
0
                                        f);
303
0
    }
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<signed char, 1>::appendToLog(VSIVirtualHandle*)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned char, 7>::appendToLog(VSIVirtualHandle*)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<short, 3>::appendToLog(VSIVirtualHandle*)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned short, 8>::appendToLog(VSIVirtualHandle*)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<int, 4>::appendToLog(VSIVirtualHandle*)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned int, 9>::appendToLog(VSIVirtualHandle*)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<long long, 10>::appendToLog(VSIVirtualHandle*)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned long long, 11>::appendToLog(VSIVirtualHandle*)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<float, 5>::appendToLog(VSIVirtualHandle*)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<double, 6>::appendToLog(VSIVirtualHandle*)
304
305
0
    OGR_SGFS_NC_Transaction_Generic(int i_varId, VClass in) : rep(in)
306
0
    {
307
0
        OGR_SGFS_Transaction::setVarId(i_varId);
308
0
    }
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<signed char, 1>::OGR_SGFS_NC_Transaction_Generic(int, signed char)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned char, 7>::OGR_SGFS_NC_Transaction_Generic(int, unsigned char)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<short, 3>::OGR_SGFS_NC_Transaction_Generic(int, short)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned short, 8>::OGR_SGFS_NC_Transaction_Generic(int, unsigned short)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<int, 4>::OGR_SGFS_NC_Transaction_Generic(int, int)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned int, 9>::OGR_SGFS_NC_Transaction_Generic(int, unsigned int)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<long long, 10>::OGR_SGFS_NC_Transaction_Generic(int, long long)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned long long, 11>::OGR_SGFS_NC_Transaction_Generic(int, unsigned long long)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<float, 5>::OGR_SGFS_NC_Transaction_Generic(int, float)
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<double, 6>::OGR_SGFS_NC_Transaction_Generic(int, double)
309
310
    VClass getData()
311
0
    {
312
0
        return rep;
313
0
    }
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<signed char, 1>::getData()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<short, 3>::getData()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<int, 4>::getData()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<float, 5>::getData()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<double, 6>::getData()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned int, 9>::getData()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned long long, 11>::getData()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<long long, 10>::getData()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned char, 7>::getData()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned short, 8>::getData()
314
315
    nc_type getType() override
316
0
    {
317
0
        return ntype;
318
0
    }
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<signed char, 1>::getType()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned char, 7>::getType()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<short, 3>::getType()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned short, 8>::getType()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<int, 4>::getType()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned int, 9>::getType()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<long long, 10>::getType()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<unsigned long long, 11>::getType()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<float, 5>::getType()
Unexecuted instantiation: nccfdriver::OGR_SGFS_NC_Transaction_Generic<double, 6>::getType()
319
};
320
321
typedef OGR_SGFS_NC_Transaction_Generic<signed char, NC_BYTE>
322
    OGR_SGFS_NC_Byte_Transaction;
323
typedef OGR_SGFS_NC_Transaction_Generic<short, NC_SHORT>
324
    OGR_SGFS_NC_Short_Transaction;
325
typedef OGR_SGFS_NC_Transaction_Generic<int, NC_INT>
326
    OGR_SGFS_NC_Int_Transaction;
327
typedef OGR_SGFS_NC_Transaction_Generic<float, NC_FLOAT>
328
    OGR_SGFS_NC_Float_Transaction;
329
typedef OGR_SGFS_NC_Transaction_Generic<double, NC_DOUBLE>
330
    OGR_SGFS_NC_Double_Transaction;
331
typedef OGR_SGFS_NC_Transaction_Generic<unsigned, NC_UINT>
332
    OGR_SGFS_NC_UInt_Transaction;
333
typedef OGR_SGFS_NC_Transaction_Generic<unsigned long long, NC_UINT64>
334
    OGR_SGFS_NC_UInt64_Transaction;
335
typedef OGR_SGFS_NC_Transaction_Generic<long long, NC_INT64>
336
    OGR_SGFS_NC_Int64_Transaction;
337
typedef OGR_SGFS_NC_Transaction_Generic<unsigned char, NC_UBYTE>
338
    OGR_SGFS_NC_UByte_Transaction;
339
typedef OGR_SGFS_NC_Transaction_Generic<unsigned short, NC_USHORT>
340
    OGR_SGFS_NC_UShort_Transaction;
341
342
/* OGR_SGFS_NC_String_Transaction
343
 * Writes to an NC_STRING variable, in a similar manner as NC_Char
344
 */
345
class OGR_SGFS_NC_String_Transaction final : public OGR_SGFS_Transaction
346
{
347
    std::string char_rep;
348
349
  public:
350
    void commit(netCDFVID &n, size_t write_loc) override
351
0
    {
352
0
        const char *writable = char_rep.c_str();
353
0
        n.nc_put_vvar1_string(OGR_SGFS_Transaction::getVarId(), &write_loc,
354
0
                              &(writable));
355
0
    }
356
357
    unsigned long long count() override
358
0
    {
359
0
        return char_rep.size() + sizeof(*this);
360
0
    }  // account for actual character representation, this class
361
362
    nc_type getType() override
363
0
    {
364
0
        return NC_STRING;
365
0
    }
366
367
    void appendToLog(VSILFILE *f) override;
368
369
    OGR_SGFS_NC_String_Transaction(int i_varId, const char *pszVal)
370
0
        : char_rep(pszVal)
371
0
    {
372
0
        OGR_SGFS_Transaction::setVarId(i_varId);
373
0
    }
374
};
375
376
/* WTransactionLog
377
 * -
378
 * A temporary file which contains transactions to be written to a netCDF file.
379
 * Once the transaction log is created it is set on write mode, it can only be
380
 * read to after startRead() is called
381
 */
382
class WTransactionLog
383
{
384
    bool readMode = false;
385
    std::string wlogName;  // name of the temporary file, should be unique
386
    VSILFILE *log = nullptr;
387
388
    WTransactionLog(WTransactionLog &);  // avoid possible undefined behavior
389
    WTransactionLog operator=(const WTransactionLog &);
390
391
  public:
392
    bool logIsNull()
393
0
    {
394
0
        return log == nullptr;
395
0
    }
396
397
    void startLog();   // always call this first to open the file
398
    void startRead();  // then call this before reading it
399
    void push(MTPtr);
400
401
    // read mode
402
    MTPtr
403
    pop();  // to test for EOF, test to see if pointer returned is null ptr
404
405
    // construction, destruction
406
    explicit WTransactionLog(const std::string &logName);
407
    ~WTransactionLog();
408
};
409
410
/* OGR_NCScribe
411
 * Buffers several netCDF transactions in memory or in a log.
412
 * General scribe class
413
 */
414
class OGR_NCScribe
415
{
416
    netCDFVID &ncvd;
417
    WBuffer buf;
418
    WTransactionLog wl;
419
    bool singleDatumMode = false;
420
421
    std::queue<MTPtr> transactionQueue;
422
    std::map<int, size_t> varWriteInds;
423
    std::map<int, size_t> varMaxInds;
424
425
  public:
426
    /* size_t getWriteCount()
427
     * Return the total write count (happened + pending) of certain variable
428
     */
429
    size_t getWriteCount(int varId)
430
0
    {
431
0
        return this->varMaxInds.at(varId);
432
0
    }
433
434
    /* void commit_transaction()
435
     * Replays all transactions to disk (according to fs stipulations)
436
     */
437
    void commit_transaction();
438
439
    /* MTPtr pop()
440
     * Get the next transaction, if it exists.
441
     * If not, it will just return a shared_ptr with nullptr inside
442
     */
443
    MTPtr pop();
444
445
    /* void log_transacion()
446
     * Saves the current queued transactions to a log.
447
     */
448
    void log_transaction();
449
450
    /* void enqueue_transaction()
451
     * Add a transaction to perform
452
     * Once a transaction is enqueued, it will only be dequeued on commit
453
     */
454
    void enqueue_transaction(MTPtr transactionAdd);
455
456
    WBuffer &getMemBuffer()
457
45.0k
    {
458
45.0k
        return buf;
459
45.0k
    }
460
461
    /* OGR_SGeometry_Field_Scribe()
462
     * Constructs a Field Scribe over a dataset
463
     */
464
45.0k
    OGR_NCScribe(netCDFVID &ncd, const std::string &name) : ncvd(ncd), wl(name)
465
45.0k
    {
466
45.0k
    }
467
468
    /* setSingleDatumMode(...)
469
     * Enables or disables single datum mode
470
     * DO NOT use this when a commit is taking place, otherwise
471
     * corruption may occur...
472
     */
473
    void setSingleDatumMode(bool sdm)
474
0
    {
475
0
        this->singleDatumMode = sdm;
476
0
    }
477
};
478
479
class ncLayer_SG_Metadata
480
{
481
    int &ncID;  // ncid REF. which tracks ncID changes that may be made upstream
482
483
    netCDFVID &vDataset;
484
    OGR_NCScribe &ncb;
485
    geom_t writableType = NONE;
486
    std::string containerVarName;
487
    int containerVar_realID = INVALID_VAR_ID;
488
    bool interiorRingDetected =
489
        false;  // flips on when an interior ring polygon has been detected
490
    std::vector<int>
491
        node_coordinates_varIDs;  // ids in X, Y (and then possibly Z) order
492
    int node_coordinates_dimID = INVALID_DIM_ID;  // dim of all node_coordinates
493
    int node_count_dimID = INVALID_DIM_ID;        // node count dim
494
    int node_count_varID = INVALID_DIM_ID;
495
    int pnc_dimID =
496
        INVALID_DIM_ID;  // part node count dim AND interior ring dim
497
    int pnc_varID = INVALID_VAR_ID;
498
    int intring_varID = INVALID_VAR_ID;
499
    size_t next_write_pos_node_coord = 0;
500
    size_t next_write_pos_node_count = 0;
501
    size_t next_write_pos_pnc = 0;
502
503
  public:
504
    geom_t getWritableType()
505
0
    {
506
0
        return this->writableType;
507
0
    }
508
509
    void writeSGeometryFeature(SGeometry_Feature &ft);
510
511
    int get_containerRealID()
512
0
    {
513
0
        return this->containerVar_realID;
514
0
    }
515
516
    std::string get_containerName()
517
0
    {
518
0
        return this->containerVarName;
519
0
    }
520
521
    int get_node_count_dimID()
522
0
    {
523
0
        return this->node_count_dimID;
524
0
    }
525
526
    int get_node_coord_dimID()
527
0
    {
528
0
        return this->node_coordinates_dimID;
529
0
    }
530
531
    int get_pnc_dimID()
532
0
    {
533
0
        return this->pnc_dimID;
534
0
    }
535
536
    int get_pnc_varID()
537
0
    {
538
0
        return this->pnc_varID;
539
0
    }
540
541
    int get_intring_varID()
542
0
    {
543
0
        return this->intring_varID;
544
0
    }
545
546
    std::vector<int> &get_nodeCoordVarIDs()
547
0
    {
548
0
        return this->node_coordinates_varIDs;
549
0
    }
550
551
    size_t get_next_write_pos_node_coord()
552
0
    {
553
0
        return this->next_write_pos_node_coord;
554
0
    }
555
556
    size_t get_next_write_pos_node_count()
557
0
    {
558
0
        return this->next_write_pos_node_count;
559
0
    }
560
561
    size_t get_next_write_pos_pnc()
562
0
    {
563
0
        return this->next_write_pos_pnc;
564
0
    }
565
566
    bool getInteriorRingDetected()
567
0
    {
568
0
        return this->interiorRingDetected;
569
0
    }
570
571
    void initializeNewContainer(int containerVID);
572
    ncLayer_SG_Metadata(int &i_ncID, geom_t geo, netCDFVID &ncdf,
573
                        OGR_NCScribe &scribe);
574
};
575
576
/* WBufferManager
577
 * -
578
 * Simply takes a collection of buffers in and a quota limit and sums all the
579
 * usages up to establish if buffers are over the soft limit (collectively)
580
 *
581
 * The buffers added, however, are not memory managed by WBufferManager
582
 */
583
class WBufferManager
584
{
585
    unsigned long long buffer_soft_limit = 0;
586
    std::vector<WBuffer *> bufs;
587
588
  public:
589
    bool isOverQuota();
590
591
    void adjustLimit(unsigned long long lim)
592
0
    {
593
0
        this->buffer_soft_limit = lim;
594
0
    }
595
596
    void addBuffer(WBuffer *b)
597
45.0k
    {
598
45.0k
        this->bufs.push_back(b);
599
45.0k
    }
600
601
22.5k
    explicit WBufferManager(unsigned long long lim) : buffer_soft_limit(lim)
602
22.5k
    {
603
22.5k
    }
604
};
605
606
// Exception Classes
607
class SGWriter_Exception /* non final */ : public SG_Exception
608
{
609
  public:
610
    SGWriter_Exception()
611
0
        : SG_Exception("A general error occurred when writing a netCDF dataset")
612
0
    {
613
0
    }
614
615
0
    explicit SGWriter_Exception(const std::string &s) : SG_Exception(s)
616
0
    {
617
0
    }
618
};
619
620
class SGWriter_Exception_NCWriteFailure final : public SGWriter_Exception
621
{
622
  public:
623
    SGWriter_Exception_NCWriteFailure(const char *layer_name,
624
                                      const char *failure_name,
625
                                      const char *failure_type);
626
};
627
628
class SGWriter_Exception_NCInqFailure final : public SGWriter_Exception
629
{
630
  public:
631
    SGWriter_Exception_NCInqFailure(const char *layer_name,
632
                                    const char *failure_name,
633
                                    const char *failure_type);
634
};
635
636
class SGWriter_Exception_NCDefFailure final : public SGWriter_Exception
637
{
638
  public:
639
    SGWriter_Exception_NCDefFailure(const char *layer_name,
640
                                    const char *failure_name,
641
                                    const char *failure_type);
642
};
643
644
class SGWriter_Exception_NullGeometry final : public SGWriter_Exception
645
{
646
  public:
647
    SGWriter_Exception_NullGeometry()
648
0
        : SGWriter_Exception(
649
0
              "A null  geometry was detected when writing a netCDF file. "
650
0
              "Empty geometries are not allowed.")
651
0
    {
652
0
    }
653
};
654
655
class SGWriter_Exception_NCDelFailure final : public SGWriter_Exception
656
{
657
  public:
658
    SGWriter_Exception_NCDelFailure(const char *layer, const char *what)
659
0
        : SGWriter_Exception("[" + std::string(layer) +
660
0
                             "] Failed to delete: " + std::string(what))
661
0
    {
662
0
    }
663
};
664
665
// Helper Functions that for writing
666
667
/* std::vector<..> writeGeometryContainer(...)
668
 * Writes a geometry container of a given geometry type given the following
669
 * arguments: int ncID - ncid as used in netcdf.h, group or file id std::string
670
 * name - what to name this container geom_t geometry_type - the geometry type
671
 * of the container std::vector<..> node_coordinate_names - variable names
672
 * corresponding to each axis Only writes attributes that are for sure required.
673
 * i.e. does NOT required interior ring for anything or part node count for
674
 * Polygons
675
 *
676
 * Returns: geometry container variable ID
677
 */
678
int write_Geometry_Container(
679
    int ncID, const std::string &name, geom_t geometry_type,
680
    const std::vector<std::string> &node_coordinate_names);
681
682
template <class W_type>
683
inline void NCWMapAllocIfNeeded(int varid, NCWMap &mapAdd, size_t numEntries,
684
                                std::vector<int> &v)
685
0
{
686
0
    if (mapAdd.count(varid) < 1)
687
0
    {
688
0
        mapAdd.insert(NCWEntry(varid, CPLMalloc(sizeof(W_type) * numEntries)));
689
0
        v.push_back(varid);
690
0
    }
691
0
}
Unexecuted instantiation: void nccfdriver::NCWMapAllocIfNeeded<signed char>(int, std::__1::map<int, void*, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, void*> > >&, unsigned long, std::__1::vector<int, std::__1::allocator<int> >&)
Unexecuted instantiation: void nccfdriver::NCWMapAllocIfNeeded<short>(int, std::__1::map<int, void*, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, void*> > >&, unsigned long, std::__1::vector<int, std::__1::allocator<int> >&)
Unexecuted instantiation: void nccfdriver::NCWMapAllocIfNeeded<int>(int, std::__1::map<int, void*, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, void*> > >&, unsigned long, std::__1::vector<int, std::__1::allocator<int> >&)
Unexecuted instantiation: void nccfdriver::NCWMapAllocIfNeeded<float>(int, std::__1::map<int, void*, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, void*> > >&, unsigned long, std::__1::vector<int, std::__1::allocator<int> >&)
Unexecuted instantiation: void nccfdriver::NCWMapAllocIfNeeded<double>(int, std::__1::map<int, void*, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, void*> > >&, unsigned long, std::__1::vector<int, std::__1::allocator<int> >&)
Unexecuted instantiation: void nccfdriver::NCWMapAllocIfNeeded<unsigned int>(int, std::__1::map<int, void*, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, void*> > >&, unsigned long, std::__1::vector<int, std::__1::allocator<int> >&)
Unexecuted instantiation: void nccfdriver::NCWMapAllocIfNeeded<unsigned long long>(int, std::__1::map<int, void*, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, void*> > >&, unsigned long, std::__1::vector<int, std::__1::allocator<int> >&)
Unexecuted instantiation: void nccfdriver::NCWMapAllocIfNeeded<long long>(int, std::__1::map<int, void*, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, void*> > >&, unsigned long, std::__1::vector<int, std::__1::allocator<int> >&)
Unexecuted instantiation: void nccfdriver::NCWMapAllocIfNeeded<unsigned char>(int, std::__1::map<int, void*, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, void*> > >&, unsigned long, std::__1::vector<int, std::__1::allocator<int> >&)
Unexecuted instantiation: void nccfdriver::NCWMapAllocIfNeeded<unsigned short>(int, std::__1::map<int, void*, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, void*> > >&, unsigned long, std::__1::vector<int, std::__1::allocator<int> >&)
692
693
template <class W_type>
694
inline void NCWMapWriteAndCommit(int varid, NCWMap &mapAdd, size_t currentEntry,
695
                                 size_t numEntries, W_type data,
696
                                 netCDFVID &vcdf)
697
0
{
698
0
    W_type *ptr = static_cast<W_type *>(mapAdd.at(varid));
699
0
    ptr[currentEntry] = data;
700
0
    static const size_t BEGIN = 0;
701
702
    // If all items are ready, write the array, and free it, delete the pointer
703
0
    if (currentEntry == (numEntries - 1))
704
0
    {
705
0
        try
706
0
        {
707
            // Write the whole array at once
708
0
            vcdf.nc_put_vvara_generic<W_type>(varid, &BEGIN, &numEntries, ptr);
709
0
        }
710
0
        catch (SG_Exception_VWrite_Failure &e)
711
0
        {
712
0
            CPLError(CE_Warning, CPLE_FileIO, "%s", e.get_err_msg());
713
0
        }
714
715
0
        CPLFree(mapAdd.at(varid));
716
0
        mapAdd.erase(varid);
717
0
    }
718
0
}
Unexecuted instantiation: void nccfdriver::NCWMapWriteAndCommit<signed char>(int, std::__1::map<int, void*, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, void*> > >&, unsigned long, unsigned long, signed char, nccfdriver::netCDFVID&)
Unexecuted instantiation: void nccfdriver::NCWMapWriteAndCommit<short>(int, std::__1::map<int, void*, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, void*> > >&, unsigned long, unsigned long, short, nccfdriver::netCDFVID&)
Unexecuted instantiation: void nccfdriver::NCWMapWriteAndCommit<int>(int, std::__1::map<int, void*, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, void*> > >&, unsigned long, unsigned long, int, nccfdriver::netCDFVID&)
Unexecuted instantiation: void nccfdriver::NCWMapWriteAndCommit<float>(int, std::__1::map<int, void*, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, void*> > >&, unsigned long, unsigned long, float, nccfdriver::netCDFVID&)
Unexecuted instantiation: void nccfdriver::NCWMapWriteAndCommit<double>(int, std::__1::map<int, void*, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, void*> > >&, unsigned long, unsigned long, double, nccfdriver::netCDFVID&)
Unexecuted instantiation: void nccfdriver::NCWMapWriteAndCommit<unsigned int>(int, std::__1::map<int, void*, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, void*> > >&, unsigned long, unsigned long, unsigned int, nccfdriver::netCDFVID&)
Unexecuted instantiation: void nccfdriver::NCWMapWriteAndCommit<unsigned long long>(int, std::__1::map<int, void*, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, void*> > >&, unsigned long, unsigned long, unsigned long long, nccfdriver::netCDFVID&)
Unexecuted instantiation: void nccfdriver::NCWMapWriteAndCommit<long long>(int, std::__1::map<int, void*, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, void*> > >&, unsigned long, unsigned long, long long, nccfdriver::netCDFVID&)
Unexecuted instantiation: void nccfdriver::NCWMapWriteAndCommit<unsigned char>(int, std::__1::map<int, void*, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, void*> > >&, unsigned long, unsigned long, unsigned char, nccfdriver::netCDFVID&)
Unexecuted instantiation: void nccfdriver::NCWMapWriteAndCommit<unsigned short>(int, std::__1::map<int, void*, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, void*> > >&, unsigned long, unsigned long, unsigned short, nccfdriver::netCDFVID&)
719
}  // namespace nccfdriver
720
721
#endif