1 /* Copyright (C) 2012-2020 IBM Corp.
2 * This program is Licensed under the Apache License, Version 2.0
3 * (the "License"); you may not use this file except in compliance
4 * with the License. You may obtain a copy of the License at
5 * http://www.apache.org/licenses/LICENSE-2.0
6 * Unless required by applicable law or agreed to in writing, software
7 * distributed under the License is distributed on an "AS IS" BASIS,
8 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9 * See the License for the specific language governing permissions and
10 * limitations under the License. See accompanying LICENSE file.
11 */
12 #ifndef HELIB_PTRVECTOR_H
13 #define HELIB_PTRVECTOR_H
14 /**
15 * @file PtrVector.h
16 * @brief Convenience class templates providing a unified interface
17 * for a collection of objects, returning pointers to these objects.
18 **/
19 #include <stdexcept>
20 #include <climits>
21 #include <vector>
22 #include <NTL/vector.h>
23
24 #include <helib/assertions.h>
25 #include <helib/apiAttributes.h>
26
27 namespace helib {
28
29 //! @brief Abstract class for an array of objects
30 template <typename T>
31 struct PtrVector
32 {
33 virtual T* operator[](long) const = 0;
34 // NOTE: the PtrVector is const, but the pointer T* is not
35 virtual long size() const = 0;
36
37 virtual void resize(long newSize, UNUSED const PtrVector* another = nullptr)
38 {
39 if (size() != newSize)
40 throw LogicError("Cannot resize a generic PtrVector");
41 }
~PtrVectorPtrVector42 virtual ~PtrVector() {}
43
isSetPtrVector44 bool isSet(long i) const
45 {
46 if (i < 0 || i >= size())
47 return false;
48 return ((*this)[i] != nullptr);
49 }
50
51 // How many non-null entries there are (beginning at startFrom)
52 virtual long numNonNull(long first = 0, long last = LONG_MAX) const
53 {
54 if (first < 0)
55 first = 0;
56 if (last > size())
57 last = size();
58 long count = 0;
59 for (long i = first; i < last; i++)
60 if ((*this)[i] != nullptr)
61 count++;
62 return count;
63 }
64
65 // Return a pointer to some non-Null T, if it can find one.
66 // This is convenient since T may not have an empty constructor
ptr2nonNullPtrVector67 virtual const T* ptr2nonNull() const
68 {
69 for (long i = 0; i < size(); i++) {
70 T* pt = (*this)[i];
71 if (pt != nullptr)
72 return pt;
73 }
74 return nullptr;
75 }
76 };
77
78 // This header provides five implementations of these interfaces, but
79 // users can define their own as needed. The ones defined here are:
80
81 // struct PtrVector_VecT; // constructed as PtrVector_VecT(NTL::Vec<T>)
82 // struct PtrVector_VecPt; // constructed as PtrVector_VecPt(NTL::Vec<T*>)
83 // struct PtrVector_vectorT; // constructed as PtrVector_vectorT(std::vector<T>)
84 // struct PtrVector_vectorPt;// constructed PtrVector_vectorPt(std::vector<T*>)
85
86 // struct PtrVector_slice;// A slice, PtrVector_slice(PtrVector, start, length)
87
88 template <typename T>
lsize(const PtrVector<T> & v)89 long lsize(const PtrVector<T>& v)
90 {
91 return v.size();
92 }
93 template <typename T>
setLengthZero(PtrVector<T> & v)94 void setLengthZero(PtrVector<T>& v)
95 {
96 v.resize(0);
97 }
98 template <typename T>
99 void resize(PtrVector<T>& v, long newSize, const T& val);
100 // implementation of resize function below
101 template <typename T>
resize(PtrVector<T> & v,long newSize,const T * val)102 void resize(PtrVector<T>& v, long newSize, const T* val)
103 {
104 resize<T>(v, newSize, *val);
105 }
106
107 // Templates for element-wise vector-copy
108
109 // Generic version for std::vector, NTL::Vec
110 template <typename V1, typename V2>
111 void vecCopy(V1& v1, const V2& v2, long sizeLimit = 0)
112 {
113 int n = lsize(v2);
114 if (sizeLimit > 0 && sizeLimit < n)
115 n = sizeLimit;
116 if (n == 0)
117 setLengthZero(v1);
118 else {
119 resize(v1, n, v2[0]);
120 for (int i = 0; i < n; i++)
121 v1[i] = v2[i];
122 }
123 }
124
125 // Specializations for PtrVector
126 template <typename V, typename T> // V is either Vec<T> or vector<T>
127 void vecCopy(V& v1, const PtrVector<T>& v2, long sizeLimit = 0)
128 {
129 int n = lsize(v2);
130 if (sizeLimit > 0 && sizeLimit < n)
131 n = sizeLimit;
132 if (n == 0)
133 setLengthZero(v1);
134 else {
135 resize(v1, n, *(v2[0]));
136 for (int i = 0; i < n; i++)
137 v1[i] = *(v2[i]);
138 }
139 }
140 template <typename V, typename T> // V is either Vec<T> or vector<T>
141 void vecCopy(PtrVector<T>& v1, const V& v2, long sizeLimit = 0)
142 {
143 int n = lsize(v2);
144 if (sizeLimit > 0 && sizeLimit < n)
145 n = sizeLimit;
146 if (n == 0)
147 setLengthZero(v1);
148 else {
149 resize(v1, n, v2[0]);
150 for (int i = 0; i < n; i++)
151 *(v1[i]) = v2[i];
152 }
153 }
154 template <typename T> // V is either Vec<T> or vector<T>
155 void vecCopy(PtrVector<T>& v1, const PtrVector<T>& v2, long sizeLimit = 0)
156 {
157 int n = lsize(v2);
158 if (sizeLimit > 0 && sizeLimit < n)
159 n = sizeLimit;
160 if (n == 0)
161 setLengthZero(v1);
162 else {
163 resize(v1, n, *(v2[0]));
164 for (int i = 0; i < n; i++)
165 *(v1[i]) = *(v2[i]);
166 }
167 }
168
169 /*******************************************************************/
170 /* Implementation details: applications should not care about them */
171 /*******************************************************************/
172
173 //! @brief An implementation of PtrVector using Vec<T*>
174 template <typename T>
175 struct PtrVector_VecPt : PtrVector<T>
176 {
177 NTL::Vec<T*>& v;
PtrVector_VecPtPtrVector_VecPt178 PtrVector_VecPt(NTL::Vec<T*>& _v) : v(_v) {}
179 T* operator[](long i) const override { return v[i]; }
sizePtrVector_VecPt180 long size() const override { return v.length(); }
181
182 void resize(long newSize,
183 UNUSED const PtrVector<T>* another = nullptr) override
184 {
185 v.SetLength(newSize, nullptr);
186 }
187 };
188
189 //! @brief An implementation of PtrVector using vector<T*>
190 template <typename T>
191 struct PtrVector_vectorPt : PtrVector<T>
192 {
193 std::vector<T*>& v;
PtrVector_vectorPtPtrVector_vectorPt194 PtrVector_vectorPt(std::vector<T*>& _v) : v(_v) {}
195 T* operator[](long i) const override { return v[i]; }
sizePtrVector_vectorPt196 long size() const override { return long(v.size()); }
197
198 void resize(long newSize,
199 UNUSED const PtrVector<T>* another = nullptr) override
200 {
201 v.resize(newSize, nullptr);
202 }
203 };
204
205 //! @brief An implementation of PtrVector using Vec<T>
206 template <typename T>
207 struct PtrVector_VecT : PtrVector<T>
208 {
209 NTL::Vec<T>& v;
PtrVector_VecTPtrVector_VecT210 PtrVector_VecT(NTL::Vec<T>& _v) : v(_v) {}
211 T* operator[](long i) const override { return &(v[i]); }
sizePtrVector_VecT212 long size() const override { return v.length(); }
213
resizePtrVector_VecT214 void resize(long newSize, const PtrVector<T>* another) override
215 {
216 if (newSize == 0)
217 setLengthZero(v);
218 else {
219 // Try to find a non-null pointer to T that you can give to resize
220 if (another == nullptr)
221 another = this;
222 const T* pt = another->ptr2nonNull();
223 assertNotNull(pt, "another->ptr2nonNull() returned a null ptr");
224 v.SetLength(newSize, *pt); // Do the actual resize
225 }
226 }
227
228 long numNonNull(long first = 0, long last = LONG_MAX) const override
229 {
230 if (first < 0)
231 first = 0;
232 if (last > v.length())
233 last = v.length();
234 return last - first;
235 }
ptr2nonNullPtrVector_VecT236 const T* ptr2nonNull() const override
237 {
238 return ((v.length() > 0) ? &(v[0]) : nullptr);
239 }
240 };
241
242 //! @brief An implementation of PtrVector using vector<T>
243 template <typename T>
244 struct PtrVector_vectorT : PtrVector<T>
245 {
246 std::vector<T>& v;
PtrVector_vectorTPtrVector_vectorT247 PtrVector_vectorT(std::vector<T>& _v) : v(_v) {}
248 T* operator[](long i) const override { return &(v[i]); }
sizePtrVector_vectorT249 long size() const override { return long(v.size()); }
250
resizePtrVector_vectorT251 void resize(long newSize, const PtrVector<T>* another) override
252 {
253 if (newSize == 0)
254 setLengthZero(v);
255 else {
256 // Try to find a non-null pointer to T that you can give to resize
257 if (another == nullptr)
258 another = this;
259 const T* pt = another->ptr2nonNull();
260 assertNotNull(pt, "another->ptr2nonNull() returned a null ptr");
261 v.resize(newSize, *pt); // do the actual resize
262 }
263 }
264 long numNonNull(long first = 0, long last = LONG_MAX) const override
265 {
266 if (first < 0)
267 first = 0;
268 if (last > long(v.size()))
269 last = long(v.size());
270 return last - first;
271 }
272 };
273
274 //! @brief An implementation of PtrVector as a slice of another PtrVector
275 template <typename T>
276 struct PtrVector_slice : PtrVector<T>
277 {
278 const PtrVector<T>& orig;
279 long start, sz;
280 // Special case for a slice of a slice
281 PtrVector_slice(const PtrVector_slice<T>& slice, long from, long _sz = -1) :
282 orig(slice.orig)
283 {
284 if (from < 0)
285 from = 0;
286 if (_sz == 0 || from >= slice.size()) { // empty slice
287 start = slice.orig.size();
288 sz = 0;
289 return;
290 }
291 // If we got here then 0 <= from < slice.size()
292 start = slice.start + from;
293
294 if (_sz < 0 || from + _sz > slice.size()) // slice goes to end of slice
295 _sz = slice.size() - from;
296 sz = _sz;
297 }
298 // The general case: slice of a PtrVector
299 PtrVector_slice(const PtrVector<T>& _orig, long from, long _sz = -1) :
origPtrVector_slice300 orig(_orig), start(from), sz(_sz)
301 {
302 if (start < 0)
303 start = 0;
304 else if (start > _orig.size())
305 start = _orig.size();
306 if (sz < 0 || sz > _orig.size() - start)
307 sz = _orig.size() - start;
308 }
309 T* operator[](long i) const override { return orig[i + start]; }
sizePtrVector_slice310 long size() const override { return sz; }
311
312 long numNonNull(long first = 0, long last = LONG_MAX) const override
313 {
314 return orig.numNonNull(start + first, start + std::min(sz, last));
315 }
ptr2nonNullPtrVector_slice316 const T* ptr2nonNull() const override { return orig.ptr2nonNull(); }
317 };
318
319 //! @brief An implementation of PtrVector from a single T object
320 template <typename T>
321 struct PtrVector_Singleton : PtrVector<T>
322 {
323 const T* v;
PtrVector_SingletonPtrVector_Singleton324 PtrVector_Singleton(const T* _v) : v(_v) {}
325 T* operator[](long i) const override { return (i == 0) ? ((T*)v) : nullptr; }
sizePtrVector_Singleton326 long size() const override { return 1L; }
327 };
328
329 template <typename T>
resize(PtrVector<T> & v,long newSize,const T & val)330 void resize(PtrVector<T>& v, long newSize, const T& val)
331 {
332 PtrVector_Singleton<T> t(&val);
333 v.resize(newSize, &t);
334 }
335
336 } // namespace helib
337
338 #endif // ifndef HELIB_PTRVECTOR_H
339