1 #ifndef INCLUDED_PCRTYPES
2 # define INCLUDED_PCRTYPES
3 
4 #ifndef INCLUDED_CSFTYPES
5 #include "csftypes.h"
6 #define INCLUDED_CSFTYPES
7 #endif
8 
9 #ifndef INCLUDED_STRING
10 #include <string>
11 #define INCLUDED_STRING
12 #endif
13 
14 /* NOTE that this file is included in the PCRaster gdal driver
15  *      it accounts for more compiler issues than we deal with
16  *      normally in PCRaster, such as the VC6 compiler.
17  *      64 bit integer typedefs are only defined for the PCRaster
18  *      source not for the Gdal driver.
19  *      The Gdal PCRaster driver defines USE_IN_GDAL, PCRaster sources
20  *      do not.
21  */
22 
23 // memset
24 // use string.h not cstring
25 // VC6 does not have memset in std
26 // better use Ansi-C string.h to be safe
27 #ifndef INCLUDED_C_STRING
28 #include <string.h>
29 #define INCLUDED_C_STRING
30 #endif
31 
32 #ifndef USE_IN_GDAL
33  // exclude Gdal driver, only for PCRaster sources
34 
35 # ifdef _MSC_VER
36   typedef          __int64    PCR_INT8;
37   typedef unsigned __int64    PCR_UINT8;
38 # else
39   // assume gcc FTTB
40   typedef          long long  PCR_INT8;
41   typedef unsigned long long  PCR_UINT8;
42 # endif
43 /* from gcc manual:
44   ISO C99 supports data types for integers that are at least 64 bits wide,
Mperror(const char * userString)45   and as an extension GCC supports them in C89 mode and in C++. Simply
46   write long long int for a signed integer, or unsigned long long int for
47   an unsigned integer. To make an integer constant of type long long int,
48   add the suffix `LL' to the integer. To make an integer constant of type
49   unsigned long long int, add the suffix `ULL' to the integer.
50 
51   WARNING: macros below are not typesafe, use  pcr::isMV and pcr::setMV instead
52  */
53 #define MV_INT8   ((CSF_IN_GLOBAL_NS PCR_INT8)0x8000000000000000LL)
54 #define MV_UINT8  ((CSF_IN_GLOBAL_NS PCR_UINT8)0xFFFFFFFFFFFFFFFFULL)
55 #define IS_MV_INT8(x) ((*((const CSF_IN_GLOBAL_NS PCR_INT8 *)x)) == MV_INT8)
56 #define IS_MV_UINT8(x) ((*((const CSF_IN_GLOBAL_NS PCR_UINT8 *)x)) == MV_UINT8)
57 #define SET_MV_INT8(x) ( (*((PCR_INT8 *)(x))) = MV_INT8)
58 #define SET_MV_UINT8(x) ( (*((PCR_UINT8 *)(x))) = MV_UINT8)
59 
60 #endif
61 
62 namespace pcr {
63 /*!
64   \brief     Tests if the value v is a missing value.
65   \param     v the value to be tested.
66   \return    True if value \a v is a missing value.
67 
68     The generic isMV(const T& v) is not implemented, only the specializations.
69 
70   TODO: Check translation of todo to English.
71   \todo      Put all things with a certain type, SMF, set Mv isType in a so-called.
72              Struct trait see cast drama as isMV fog INT2 in BandMapTest::Open2.
73              See numeric_limit discussion in Josuttis.
74 */
75   template<typename T> static bool isMV(const T& v);
76 /*!
77   \brief     Tests if the value pointed to by v is a missing value.
78   \param     v Pointer to the value to be tested.
79   \return    True if the value pointed to by v is a missing value.
80 */
81   template<typename T> static bool isMV(T* v) {
82     return isMV(*v);
83   }
84 
85 # define PCR_DEF_ISMV(type)  \
86   template<>                  \
87    inline bool isMV(const type& v) \
88    { return v == MV_##type; }
89    PCR_DEF_ISMV(UINT1)
90    PCR_DEF_ISMV(UINT2)
91    PCR_DEF_ISMV(UINT4)
92    PCR_DEF_ISMV(INT1)
93    PCR_DEF_ISMV(INT2)
94    PCR_DEF_ISMV(INT4)
95 #  ifndef USE_IN_GDAL
96   template<>
97    inline bool isMV(const PCR_UINT8& v)
98    { return v == MV_UINT8; }
99   template<>
100    inline bool isMV(const PCR_INT8& v)
101    { return v == MV_INT8; }
102 #  endif
103 #  undef PCR_DEF_ISMV
104   template<> inline bool isMV(const REAL4& v)
105   { return IS_MV_REAL4(&v); }
106   template<> inline bool isMV(const REAL8& v)
107   { return IS_MV_REAL8(&v); }
108 
109 template<> inline bool isMV(std::string const& string)
110 {
111   return string.empty();
112 }
113 
114  /*!
115     \brief     Sets the value v to a missing value.
116     \param     v value to be set.
117     the generic setMV(T& v) is not implemented, only the specializations
118   */
119   template<typename T> void setMV(T& v);
120  /*!
121     \brief     Sets the value pointed to by v to a missing value.
122     \param     v Pointer to the value to be set.
123   */
124   template<typename T> static void setMV(T *v) {
125     setMV(*v);
126   }
127 
128 # define PCR_DEF_SETMV(type)  \
129   template<>                  \
130    inline void setMV(type& v) \
131    { v = MV_##type; }
132    PCR_DEF_SETMV(UINT1)
133    PCR_DEF_SETMV(UINT2)
134    PCR_DEF_SETMV(UINT4)
135    PCR_DEF_SETMV(INT1)
136    PCR_DEF_SETMV(INT2)
137    PCR_DEF_SETMV(INT4)
138 #  ifndef USE_IN_GDAL
139     template<>
140      inline void setMV(PCR_UINT8& v)
141      { v = MV_UINT8; }
142     template<>
143      inline void setMV(PCR_INT8& v)
144      { v = MV_INT8; }
145 #  endif
146 #  undef PCR_DEF_SETMV
147 
148   template<>
149    inline void setMV(REAL4& v)
150   {
151 #   ifndef __i386__
152      SET_MV_REAL4((&v));
153 #   else
154      // this fixes an optimization problem (release mode), if is v is a single
155      // element variable in function scope (stack-based)
156      // constraint the setting to memory (m)
157      // for correct alignment
158      asm ("movl $-1, %0" : "=m" (v));
159 #   endif
160   }
161   template<>
162    inline void setMV(REAL8& v)
163   {
164 #   ifndef __i386__
165      SET_MV_REAL8((&v));
166 #   else
167     memset(&v,MV_UINT1,sizeof(REAL8));
168     // constraint the setting to memory (m)
169     // this fixes the same optimization problem, as for REAL4
170     // see com_mvoptest.cc, does not work: !
171     // int *v2= (int *)&v;
172     // asm ("movl $-1, %[dest]" : [dest] "=m" (v2[0]));
173     // asm ("movl $-1, %[dest]" : [dest] "=m" (v2[1]));
174 #   endif
175   }
176 
177 template<>
178 inline void setMV(std::string& string)
179 {
180   // VC6 does not have clear
181   // string.clear();
182   string="";
183 }
184 
185 /*! \brief set array \a v of size \a n to all MV's
186  *  the generic setMV(T& v) is implemented, the specializations
187  *  are optimizations
188  * \todo
189  *   check if stdlib has a 'wordsized' memset
190  *   or optimize for I86, for gcc look into include/asm/string
191  */
192 template<typename T>
193 static void setMV(T *v, size_t n)
194 {
195   for(size_t i=0; i<n; i++)
196       pcr::setMV(v[i]);
197 }
198 
199  namespace detail {
200    template<typename T>
201     static void setMVMemSet(T *v, size_t n) {
202       memset(v,MV_UINT1,n*sizeof(T));
203     }
204  }
205 
206 # define PCR_DEF_SETMV_MEMSET(type)    \
207   template<>                           \
208    inline void setMV(type* v,size_t n) \
209    { detail::setMVMemSet(v,n); }
210   PCR_DEF_SETMV_MEMSET(UINT1)
211   PCR_DEF_SETMV_MEMSET(UINT2)
212   PCR_DEF_SETMV_MEMSET(UINT4)
213 # ifndef USE_IN_GDAL
214   PCR_DEF_SETMV_MEMSET(PCR_UINT8)
215 # endif
216   PCR_DEF_SETMV_MEMSET(REAL4)
217   PCR_DEF_SETMV_MEMSET(REAL8)
218 # undef PCR_DEF_SETMV_MEMSET
219   template<>
220     inline void setMV(INT1 *v, size_t n) {
221       memset(v,MV_INT1,n);
222     }
223 
224 //! replace a value equal to \a nonStdMV with the standard MV
225 /*!
226  * \todo
227  *   the isMV test is only needed for floats, to protect NAN evaluation
228  *   what once happened on bcc/win32. Should reevaluate that.
229  */
230 template<typename T>
231   struct AlterToStdMV {
232     T d_nonStdMV;
233     AlterToStdMV(T nonStdMV):
234       d_nonStdMV(nonStdMV) {}
235 
236     void operator()(T& v) {
237       if (!isMV(v) && v == d_nonStdMV)
238         setMV(v);
239     }
240   };
241 
242 //! return the value or the standard missing value if value equal to \a nonStdMV
243 /*!
244  * \todo
245  *   the isMV test is only needed for floats, to protect NAN evaluation
246  *   what once happened on bcc/win32. Should reevaluate that.
247  */
248 template<typename T>
249   struct ToStdMV {
250     T d_nonStdMV;
251     T d_mv;
252     ToStdMV(T nonStdMV):
253       d_nonStdMV(nonStdMV) {
254         setMV(d_mv);
255       }
256 
257     T operator()(T const& v) {
258       if (!isMV(v) && v == d_nonStdMV) {
259         return d_mv;
260       }
261       return v;
262     }
263   };
264 
265 //! replace the standard MV with a value  equal to \a otherMV
266 /*!
267  * \todo
268  *   the isMV test is only needed for floats, to protect NAN evaluation
269  *   what once happened on bcc/win32. Should reevaluate that.
270  */
271 template<typename T>
272   struct AlterFromStdMV {
273     T d_otherMV;
274     AlterFromStdMV(T otherMV):
275       d_otherMV(otherMV) {}
276 
277     void operator()(T& v) {
278       if (isMV(v))
279         v = d_otherMV;
280     }
281   };
282 
283 //! return the value or \a otherMV if value equal to standard MV
284 /*!
285  * \todo
286  *   the isMV test is only needed for floats, to protect NAN evaluation
287  *   what once happened on bcc/win32. Should reevaluate that.
288  */
289 template<typename T>
290   struct FromStdMV {
291     T d_otherMV;
292     FromStdMV(T otherMV):
293       d_otherMV(otherMV) {}
294 
295     T operator()(const T& v) {
296       if (isMV(v))
297         return d_otherMV;
298       return v;
299     }
300   };
301 
302 }
303 
304 
305 #endif
306