• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 16038479760

03 Jul 2025 12:12AM UTC coverage: 71.106% (-0.004%) from 71.11%
16038479760

Pull #12692

github

web-flow
Merge efeee3602 into b5d2a80d4
Pull Request #12692: C/C++/Python band algebra: add gdal.abs(), sqrt(), log(), log10() and pow()

80 of 87 new or added lines in 3 files covered. (91.95%)

8848 existing lines in 54 files now uncovered.

574863 of 808463 relevant lines covered (71.11%)

255001.94 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.25
/gcore/gdalarraybandblockcache.cpp
1
/******************************************************************************
2
 *
3
 * Project:  GDAL Core
4
 * Purpose:  Store cached blocks in a array or a two-level array
5
 * Author:   Even Rouault, <even dot rouault at spatialys dot org>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 1998, Frank Warmerdam
9
 * Copyright (c) 2007-2015, Even Rouault <even dot rouault at spatialys dot org>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13

14
#include "cpl_port.h"
15
#include "gdal_priv.h"
16

17
#include <cassert>
18
#include <climits>
19
#include <cstddef>
20
#include <new>
21

22
#include "cpl_conv.h"
23
#include "cpl_error.h"
24
#include "cpl_multiproc.h"
25
#include "cpl_vsi.h"
26

27
//! @cond Doxygen_Suppress
28

29
constexpr int SUBBLOCK_SIZE = 64;
30
#define TO_SUBBLOCK(x) ((x) >> 6)
31
#define WITHIN_SUBBLOCK(x) ((x)&0x3f)
32

33
/* ******************************************************************** */
34
/*                        GDALArrayBandBlockCache                       */
35
/* ******************************************************************** */
36

37
class GDALArrayBandBlockCache final : public GDALAbstractBandBlockCache
38
{
39
    bool bSubBlockingActive = false;
40
    int nSubBlocksPerRow = 0;
41
    int nSubBlocksPerColumn = 0;
42

43
    union u
44
    {
45
        GDALRasterBlock **papoBlocks;
46
        GDALRasterBlock ***papapoBlocks;
47

48
        u() : papoBlocks(nullptr)
236,042✔
49
        {
50
        }
236,042✔
51
    } u{};
52

53
    CPL_DISALLOW_COPY_ASSIGN(GDALArrayBandBlockCache)
54

55
  public:
56
    explicit GDALArrayBandBlockCache(GDALRasterBand *poBand);
57
    ~GDALArrayBandBlockCache() override;
58

59
    bool Init() override;
60
    bool IsInitOK() override;
61
    CPLErr FlushCache() override;
62
    CPLErr AdoptBlock(GDALRasterBlock *) override;
63
    GDALRasterBlock *TryGetLockedBlockRef(int nXBlockOff,
64
                                          int nYBlockYOff) override;
65
    CPLErr UnreferenceBlock(GDALRasterBlock *poBlock) override;
66
    CPLErr FlushBlock(int nXBlockOff, int nYBlockOff,
67
                      int bWriteDirtyBlock) override;
68
};
69

70
/************************************************************************/
71
/*                     GDALArrayBandBlockCacheCreate()                 */
72
/************************************************************************/
73

74
GDALAbstractBandBlockCache *
75
GDALArrayBandBlockCacheCreate(GDALRasterBand *poBand)
236,051✔
76
{
77
    return new (std::nothrow) GDALArrayBandBlockCache(poBand);
236,051✔
78
}
79

80
/************************************************************************/
81
/*                       GDALArrayBandBlockCache()                      */
82
/************************************************************************/
83

84
GDALArrayBandBlockCache::GDALArrayBandBlockCache(GDALRasterBand *poBandIn)
236,051✔
85
    : GDALAbstractBandBlockCache(poBandIn)
236,051✔
86
{
87
}
236,048✔
88

89
/************************************************************************/
90
/*                      ~GDALArrayBandBlockCache()                     */
91
/************************************************************************/
92

93
GDALArrayBandBlockCache::~GDALArrayBandBlockCache()
472,102✔
94
{
95
    GDALArrayBandBlockCache::FlushCache();
236,051✔
96

97
    if (!bSubBlockingActive)
236,051✔
98
        CPLFree(u.papoBlocks);
235,932✔
99
    else
100
        CPLFree(u.papapoBlocks);
119✔
101
}
472,102✔
102

103
/************************************************************************/
104
/*                                  Init()                              */
105
/************************************************************************/
106

107
bool GDALArrayBandBlockCache::Init()
236,035✔
108
{
109
    if (poBand->nBlocksPerRow < SUBBLOCK_SIZE / 2)
236,035✔
110
    {
111
        bSubBlockingActive = false;
235,919✔
112

113
        if (poBand->nBlocksPerRow < INT_MAX / poBand->nBlocksPerColumn)
235,919✔
114
        {
115
            u.papoBlocks = static_cast<GDALRasterBlock **>(VSICalloc(
235,920✔
116
                sizeof(void *), cpl::fits_on<int>(poBand->nBlocksPerRow *
235,916✔
117
                                                  poBand->nBlocksPerColumn)));
235,916✔
118
            if (u.papoBlocks == nullptr)
235,921✔
119
            {
120
                poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
×
121
                                    "Out of memory in InitBlockInfo().");
122
                return false;
×
123
            }
124
        }
125
        else
126
        {
127
            poBand->ReportError(
3✔
128
                CE_Failure, CPLE_NotSupported, "Too many blocks : %d x %d",
129
                poBand->nBlocksPerRow, poBand->nBlocksPerColumn);
3✔
130
            return false;
×
131
        }
132
    }
133
    else
134
    {
135
        bSubBlockingActive = true;
116✔
136

137
        nSubBlocksPerRow = DIV_ROUND_UP(poBand->nBlocksPerRow, SUBBLOCK_SIZE);
116✔
138
        nSubBlocksPerColumn =
116✔
139
            DIV_ROUND_UP(poBand->nBlocksPerColumn, SUBBLOCK_SIZE);
116✔
140

141
        if (nSubBlocksPerRow < INT_MAX / nSubBlocksPerColumn)
116✔
142
        {
143
            u.papapoBlocks = static_cast<GDALRasterBlock ***>(VSICalloc(
119✔
144
                sizeof(void *),
145
                cpl::fits_on<int>(nSubBlocksPerRow * nSubBlocksPerColumn)));
119✔
146
            if (u.papapoBlocks == nullptr)
123✔
147
            {
148
                poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
×
149
                                    "Out of memory in InitBlockInfo().");
150
                return false;
×
151
            }
152
        }
153
        else
154
        {
UNCOV
155
            poBand->ReportError(CE_Failure, CPLE_NotSupported,
×
156
                                "Too many subblocks : %d x %d",
157
                                nSubBlocksPerRow, nSubBlocksPerColumn);
158
            return false;
×
159
        }
160
    }
161

162
    return true;
236,044✔
163
}
164

165
/************************************************************************/
166
/*                             IsInitOK()                               */
167
/************************************************************************/
168

169
bool GDALArrayBandBlockCache::IsInitOK()
9,699,890✔
170
{
171
    return (!bSubBlockingActive) ? u.papoBlocks != nullptr
9,699,890✔
172
                                 : u.papapoBlocks != nullptr;
9,699,890✔
173
}
174

175
/************************************************************************/
176
/*                            AdoptBlock()                              */
177
/************************************************************************/
178

179
CPLErr GDALArrayBandBlockCache::AdoptBlock(GDALRasterBlock *poBlock)
1,344,860✔
180

181
{
182
    const int nXBlockOff = poBlock->GetXOff();
1,344,860✔
183
    const int nYBlockOff = poBlock->GetYOff();
1,344,840✔
184

185
    FreeDanglingBlocks();
1,344,850✔
186

187
    /* -------------------------------------------------------------------- */
188
    /*      Simple case without subblocking.                                */
189
    /* -------------------------------------------------------------------- */
190

191
    if (!bSubBlockingActive)
1,344,840✔
192
    {
193
        const int nBlockIndex = nXBlockOff + nYBlockOff * poBand->nBlocksPerRow;
1,287,360✔
194

195
        CPLAssert(u.papoBlocks[nBlockIndex] == nullptr);
1,287,360✔
196
        u.papoBlocks[nBlockIndex] = poBlock;
1,287,360✔
197
    }
198
    else
199
    {
200
        /* --------------------------------------------------------------------
201
         */
202
        /*      Identify the subblock in which our target occurs, and create */
203
        /*      it if necessary. */
204
        /* --------------------------------------------------------------------
205
         */
206
        const int nSubBlock = TO_SUBBLOCK(nXBlockOff) +
57,476✔
207
                              TO_SUBBLOCK(nYBlockOff) * nSubBlocksPerRow;
57,476✔
208

209
        if (u.papapoBlocks[nSubBlock] == nullptr)
57,476✔
210
        {
211
            const int nSubGridSize =
161✔
212
                sizeof(GDALRasterBlock *) * SUBBLOCK_SIZE * SUBBLOCK_SIZE;
213

214
            u.papapoBlocks[nSubBlock] =
322✔
215
                static_cast<GDALRasterBlock **>(VSICalloc(1, nSubGridSize));
161✔
216
            if (u.papapoBlocks[nSubBlock] == nullptr)
161✔
217
            {
218
                poBand->ReportError(CE_Failure, CPLE_OutOfMemory,
×
219
                                    "Out of memory in AdoptBlock().");
220
                return CE_Failure;
×
221
            }
222
        }
223

224
        /* --------------------------------------------------------------------
225
         */
226
        /*      Check within subblock. */
227
        /* --------------------------------------------------------------------
228
         */
229
        GDALRasterBlock **papoSubBlockGrid = u.papapoBlocks[nSubBlock];
57,476✔
230

231
        const int nBlockInSubBlock =
57,476✔
232
            WITHIN_SUBBLOCK(nXBlockOff) +
57,476✔
233
            WITHIN_SUBBLOCK(nYBlockOff) * SUBBLOCK_SIZE;
57,476✔
234

235
        CPLAssert(papoSubBlockGrid[nBlockInSubBlock] == nullptr);
57,476✔
236
        papoSubBlockGrid[nBlockInSubBlock] = poBlock;
57,476✔
237
    }
238

239
    return CE_None;
1,344,840✔
240
}
241

242
/************************************************************************/
243
/*                            FlushCache()                              */
244
/************************************************************************/
245

246
CPLErr GDALArrayBandBlockCache::FlushCache()
992,448✔
247
{
248
    FreeDanglingBlocks();
992,448✔
249

250
    CPLErr eGlobalErr = poBand->eFlushBlockErr;
992,448✔
251

252
    StartDirtyBlockFlushingLog();
992,448✔
253

254
    /* -------------------------------------------------------------------- */
255
    /*      Flush all blocks in memory ... this case is without subblocking.*/
256
    /* -------------------------------------------------------------------- */
257
    if (!bSubBlockingActive && u.papoBlocks != nullptr)
992,445✔
258
    {
259
        const int nBlocksPerColumn = poBand->nBlocksPerColumn;
992,038✔
260
        const int nBlocksPerRow = poBand->nBlocksPerRow;
992,038✔
261
        for (int iY = 0; iY < nBlocksPerColumn; iY++)
90,038,900✔
262
        {
263
            for (int iX = 0; iX < nBlocksPerRow; iX++)
178,430,000✔
264
            {
265
                if (u.papoBlocks[iX + iY * nBlocksPerRow] != nullptr)
89,383,100✔
266
                {
267
                    CPLErr eErr = FlushBlock(iX, iY, eGlobalErr == CE_None);
1,258,160✔
268

269
                    if (eErr != CE_None)
1,258,160✔
270
                        eGlobalErr = eErr;
5✔
271
                }
272
            }
273
        }
992,041✔
274
    }
275

276
    /* -------------------------------------------------------------------- */
277
    /*      With subblocking.  We can short circuit missing subblocks.      */
278
    /* -------------------------------------------------------------------- */
279
    else if (u.papapoBlocks != nullptr)
407✔
280
    {
281
        for (int iSBY = 0; iSBY < nSubBlocksPerColumn; iSBY++)
876✔
282
        {
283
            for (int iSBX = 0; iSBX < nSubBlocksPerRow; iSBX++)
1,483✔
284
            {
285
                const int nSubBlock = iSBX + iSBY * nSubBlocksPerRow;
1,015✔
286

287
                GDALRasterBlock **papoSubBlockGrid = u.papapoBlocks[nSubBlock];
1,015✔
288

289
                if (papoSubBlockGrid == nullptr)
1,015✔
290
                    continue;
854✔
291

292
                for (int iY = 0; iY < SUBBLOCK_SIZE; iY++)
10,465✔
293
                {
294
                    for (int iX = 0; iX < SUBBLOCK_SIZE; iX++)
669,760✔
295
                    {
296
                        if (papoSubBlockGrid[iX + iY * SUBBLOCK_SIZE] !=
659,456✔
297
                            nullptr)
298
                        {
299
                            CPLErr eErr = FlushBlock(iX + iSBX * SUBBLOCK_SIZE,
111,594✔
300
                                                     iY + iSBY * SUBBLOCK_SIZE,
55,797✔
301
                                                     eGlobalErr == CE_None);
302
                            if (eErr != CE_None)
55,797✔
303
                                eGlobalErr = eErr;
2✔
304
                        }
305
                    }
306
                }
307

308
                // We might as well get rid of this grid chunk since we know
309
                // it is now empty.
310
                u.papapoBlocks[nSubBlock] = nullptr;
161✔
311
                CPLFree(papoSubBlockGrid);
161✔
312
            }
313
        }
314
    }
315

316
    EndDirtyBlockFlushingLog();
992,448✔
317

318
    WaitCompletionPendingTasks();
992,449✔
319

320
    return (eGlobalErr);
992,448✔
321
}
322

323
/************************************************************************/
324
/*                        UnreferenceBlock()                            */
325
/************************************************************************/
326

327
CPLErr GDALArrayBandBlockCache::UnreferenceBlock(GDALRasterBlock *poBlock)
29,322✔
328
{
329
    const int nXBlockOff = poBlock->GetXOff();
29,322✔
330
    const int nYBlockOff = poBlock->GetYOff();
29,322✔
331

332
    UnreferenceBlockBase();
29,322✔
333

334
    /* -------------------------------------------------------------------- */
335
    /*      Simple case for single level caches.                            */
336
    /* -------------------------------------------------------------------- */
337
    if (!bSubBlockingActive)
29,322✔
338
    {
339
        const int nBlockIndex = nXBlockOff + nYBlockOff * poBand->nBlocksPerRow;
27,645✔
340

341
        u.papoBlocks[nBlockIndex] = nullptr;
27,645✔
342
    }
343

344
    /* -------------------------------------------------------------------- */
345
    /*      Identify our subblock.                                          */
346
    /* -------------------------------------------------------------------- */
347
    else
348
    {
349
        const int nSubBlock = TO_SUBBLOCK(nXBlockOff) +
1,677✔
350
                              TO_SUBBLOCK(nYBlockOff) * nSubBlocksPerRow;
1,677✔
351

352
        /* --------------------------------------------------------------------
353
         */
354
        /*      Check within subblock. */
355
        /* --------------------------------------------------------------------
356
         */
357
        GDALRasterBlock **papoSubBlockGrid = u.papapoBlocks[nSubBlock];
1,677✔
358
        if (papoSubBlockGrid == nullptr)
1,677✔
359
            return CE_None;
×
360

361
        const int nBlockInSubBlock =
1,677✔
362
            WITHIN_SUBBLOCK(nXBlockOff) +
1,677✔
363
            WITHIN_SUBBLOCK(nYBlockOff) * SUBBLOCK_SIZE;
1,677✔
364

365
        papoSubBlockGrid[nBlockInSubBlock] = nullptr;
1,677✔
366
    }
367

368
    return CE_None;
29,322✔
369
}
370

371
/************************************************************************/
372
/*                            FlushBlock()                              */
373
/************************************************************************/
374

375
CPLErr GDALArrayBandBlockCache::FlushBlock(int nXBlockOff, int nYBlockOff,
1,316,260✔
376
                                           int bWriteDirtyBlock)
377

378
{
379
    GDALRasterBlock *poBlock = nullptr;
1,316,260✔
380

381
    /* -------------------------------------------------------------------- */
382
    /*      Simple case for single level caches.                            */
383
    /* -------------------------------------------------------------------- */
384
    if (!bSubBlockingActive)
1,316,260✔
385
    {
386
        const int nBlockIndex = nXBlockOff + nYBlockOff * poBand->nBlocksPerRow;
1,260,460✔
387

388
        assert(u.papoBlocks);
1,260,460✔
389
        poBlock = u.papoBlocks[nBlockIndex];
1,260,460✔
390
        u.papoBlocks[nBlockIndex] = nullptr;
1,260,460✔
391
    }
392

393
    /* -------------------------------------------------------------------- */
394
    /*      Identify our subblock.                                          */
395
    /* -------------------------------------------------------------------- */
396
    else
397
    {
398
        const int nSubBlock = TO_SUBBLOCK(nXBlockOff) +
55,799✔
399
                              TO_SUBBLOCK(nYBlockOff) * nSubBlocksPerRow;
55,799✔
400

401
        /* --------------------------------------------------------------------
402
         */
403
        /*      Check within subblock. */
404
        /* --------------------------------------------------------------------
405
         */
406
        GDALRasterBlock **papoSubBlockGrid = u.papapoBlocks[nSubBlock];
55,799✔
407
        if (papoSubBlockGrid == nullptr)
55,799✔
408
            return CE_None;
×
409

410
        const int nBlockInSubBlock =
55,799✔
411
            WITHIN_SUBBLOCK(nXBlockOff) +
55,799✔
412
            WITHIN_SUBBLOCK(nYBlockOff) * SUBBLOCK_SIZE;
55,799✔
413

414
        poBlock = papoSubBlockGrid[nBlockInSubBlock];
55,799✔
415
        papoSubBlockGrid[nBlockInSubBlock] = nullptr;
55,799✔
416
    }
417

418
    if (poBlock == nullptr)
1,316,260✔
419
        return CE_None;
701✔
420

421
    if (!poBlock->DropLockForRemovalFromStorage())
1,315,560✔
422
        return CE_None;
2✔
423

424
    /* -------------------------------------------------------------------- */
425
    /*      Is the target block dirty?  If so we need to write it.          */
426
    /* -------------------------------------------------------------------- */
427
    poBlock->Detach();
1,315,550✔
428

429
    CPLErr eErr = CE_None;
1,315,550✔
430

431
    if (!m_nWriteDirtyBlocksDisabled && bWriteDirtyBlock && poBlock->GetDirty())
1,315,550✔
432
    {
433
        UpdateDirtyBlockFlushingLog();
193,340✔
434

435
        eErr = poBlock->Write();
193,340✔
436
    }
437

438
    /* -------------------------------------------------------------------- */
439
    /*      Deallocate the block;                                           */
440
    /* -------------------------------------------------------------------- */
441
    delete poBlock;
1,315,550✔
442

443
    return eErr;
1,315,550✔
444
}
445

446
/************************************************************************/
447
/*                        TryGetLockedBlockRef()                        */
448
/************************************************************************/
449

450
GDALRasterBlock *GDALArrayBandBlockCache::TryGetLockedBlockRef(int nXBlockOff,
7,497,500✔
451
                                                               int nYBlockOff)
452

453
{
454
    /* -------------------------------------------------------------------- */
455
    /*      Simple case for single level caches.                            */
456
    /* -------------------------------------------------------------------- */
457
    if (!bSubBlockingActive)
7,497,500✔
458
    {
459
        const int nBlockIndex = nXBlockOff + nYBlockOff * poBand->nBlocksPerRow;
6,715,030✔
460

461
        GDALRasterBlock *poBlock = u.papoBlocks[nBlockIndex];
6,715,030✔
462
        if (poBlock == nullptr || !poBlock->TakeLock())
6,715,030✔
463
            return nullptr;
1,235,540✔
464
        return poBlock;
5,480,920✔
465
    }
466
    else
467
    {
468
        /* --------------------------------------------------------------------
469
         */
470
        /*      Identify our subblock. */
471
        /* --------------------------------------------------------------------
472
         */
473
        const int nSubBlock = TO_SUBBLOCK(nXBlockOff) +
782,463✔
474
                              TO_SUBBLOCK(nYBlockOff) * nSubBlocksPerRow;
782,463✔
475

476
        /* --------------------------------------------------------------------
477
         */
478
        /*      Check within subblock. */
479
        /* --------------------------------------------------------------------
480
         */
481
        GDALRasterBlock **papoSubBlockGrid = u.papapoBlocks[nSubBlock];
782,463✔
482
        if (papoSubBlockGrid == nullptr)
782,463✔
483
            return nullptr;
50✔
484

485
        const int nBlockInSubBlock =
782,413✔
486
            WITHIN_SUBBLOCK(nXBlockOff) +
782,413✔
487
            WITHIN_SUBBLOCK(nYBlockOff) * SUBBLOCK_SIZE;
782,413✔
488

489
        GDALRasterBlock *poBlock = papoSubBlockGrid[nBlockInSubBlock];
782,413✔
490
        if (poBlock == nullptr || !poBlock->TakeLock())
782,413✔
491
            return nullptr;
57,322✔
492
        return poBlock;
725,091✔
493
    }
494
}
495

496
//! @endcond
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc