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