1 /*
2     SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
3     SPDX-FileContributor: 2010 Stephen Kelly <stephen@kdab.com>
4 
5     SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #ifndef KVOIDPOINTERFACTORY_P_H
9 #define KVOIDPOINTERFACTORY_P_H
10 
11 #include <cstddef>
12 #include <cstdlib>
13 #include <vector>
14 
15 #define DEFAULT_BLOCK_SIZE 256
16 
17 /**
18  * @brief A Class for managing void pointers for use in QModelIndexes.
19  *
20  * This class creates void pointers pointing to individual blocks of memory.
21  * The pointed-to memory contains zeros.
22  *
23  * Memory is allocated in blocks of size @p blockSize times sizeof(void*) at a time. The used
24  * memory is automatically freed and can be cleared manually.
25  *
26  * The void pointers should not be dereferenced, but only used as a unique
27  * identifier suitable for use with createIndex() and for comparison with other void pointers.
28  */
29 template<std::size_t blockSize = DEFAULT_BLOCK_SIZE>
30 class KVoidPointerFactory
31 {
32     // a class with size 1.
33     class Bit
34     {
35         bool bit;
36     };
37 
38 public:
KVoidPointerFactory()39     KVoidPointerFactory()
40         : m_previousPointer(nullptr)
41         , m_finalPointer(nullptr)
42     {
43     }
44 
KVoidPointerFactory(const KVoidPointerFactory<blockSize> & other)45     KVoidPointerFactory(const KVoidPointerFactory<blockSize> &other)
46     {
47         *this = other;
48     }
49 
50     KVoidPointerFactory<blockSize> &operator=(const KVoidPointerFactory<blockSize> &other)
51     {
52         m_previousPointer = other.m_previousPointer;
53         m_finalPointer = other.m_finalPointer;
54         m_blocks = other.m_blocks;
55         return *this;
56     }
57 
~KVoidPointerFactory()58     ~KVoidPointerFactory()
59     {
60         clear();
61     }
62 
clear()63     void clear()
64     {
65         typename std::vector<Bit *>::const_iterator it = m_blocks.begin();
66         const typename std::vector<Bit *>::const_iterator end = m_blocks.end();
67         for (; it != end; ++it) {
68             free(*it);
69         }
70         m_blocks.clear();
71         m_finalPointer = nullptr;
72         m_previousPointer = nullptr;
73     }
74 
createPointer()75     void *createPointer() const
76     {
77         if (m_previousPointer == m_finalPointer) {
78             static const std::size_t pointer_size = sizeof(Bit *);
79             Bit *const bit = static_cast<Bit *>(calloc(blockSize, pointer_size));
80             m_blocks.push_back(bit);
81             m_finalPointer = bit + (blockSize * pointer_size) - 1;
82             m_previousPointer = bit;
83             return bit;
84         }
85         return ++m_previousPointer;
86     }
87 
88 private:
89     mutable std::vector<Bit *> m_blocks;
90     mutable Bit *m_previousPointer;
91     mutable Bit *m_finalPointer;
92 };
93 
94 // Disable factory with 0 blockSize
95 template<>
96 class KVoidPointerFactory<0>
97 {
98 public:
99     KVoidPointerFactory();
100 
101     void clear();
102     void *createPointer();
103 };
104 
105 #endif
106