otbOGRFieldWrapper.hxx 17.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
Luc Hermitte's avatar
Luc Hermitte committed
20 21


22 23
#ifndef otbOGRFieldWrapper_hxx
#define otbOGRFieldWrapper_hxx
Luc Hermitte's avatar
Luc Hermitte committed
24 25 26 27 28

/*===========================================================================*/
/*===============================[ Includes ]================================*/
/*===========================================================================*/
#include "otbOGRFieldWrapper.h"
29
#include "otbConfigure.h"
Luc Hermitte's avatar
Luc Hermitte committed
30 31 32 33 34 35 36
#include <cassert>
#include <vector>
#include <boost/mpl/map.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/pair.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/at.hpp>
37 38
#include <boost/mpl/assert.hpp>
// #include <boost/mpl/print.hpp>
Luc Hermitte's avatar
Luc Hermitte committed
39 40 41 42

#include <boost/static_assert.hpp>
#include <boost/range/size.hpp>
#include <boost/type_traits/is_same.hpp>
43
// #include "boost/type_traits/is_array.hpp"
Luc Hermitte's avatar
Luc Hermitte committed
44 45
#include "boost/type_traits/is_contiguous.h" // from OTB actually

46
#if defined(__GNUC__) || defined(__clang__)
47 48
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
49
#include "ogr_feature.h"  // OGRFeature::*field_getters
50
#pragma GCC diagnostic pop
51 52 53
#else
#include "ogr_feature.h"  // OGRFeature::*field_getters
#endif
54
#include "cpl_string.h" // CSLCount
Luc Hermitte's avatar
Luc Hermitte committed
55
#include "otbOGRHelpers.h"
Luc Hermitte's avatar
Luc Hermitte committed
56 57


58

Luc Hermitte's avatar
Luc Hermitte committed
59 60 61 62 63
/*===========================================================================*/
/*================[ Associations C++ types -> OGR functions ]================*/
/*===========================================================================*/

namespace otb { namespace ogr {
64
/**\ingroup gGeometry
Luc Hermitte's avatar
Luc Hermitte committed
65 66 67 68 69 70 71 72 73
 * \defgroup GeometryInternals Geometry Internals
 * \since OTB v 3.14.0
 */

/**\ingroup GeometryInternals
 * Namespace used to host internal meta-prog definitions.
 * \since OTB v 3.14.0
 */
namespace internal { // namespace internal
74
namespace mpl = boost::mpl;
Luc Hermitte's avatar
Luc Hermitte committed
75 76 77 78 79 80 81 82

/**\ingroup GeometryInternals
 * Associative map of C++ types to OGR field types (\c OGRFieldType).
 * \internal Relies on Boost.MPL
 * \since OTB v 3.14.0
 * \todo \c OFTBinary, \c OFTDate, \c OFTTime and \c OFTDateTime are not managed
 * yet.
 */
83 84 85 86 87 88 89 90 91
typedef mpl::map
  < mpl::pair<int                     , mpl::int_<OFTInteger> >
  , mpl::pair<std::vector<int>        , mpl::int_<OFTIntegerList> >
  , mpl::pair<double                  , mpl::int_<OFTReal> >
  , mpl::pair<std::vector<double>     , mpl::int_<OFTRealList> >
  , mpl::pair<std::string             , mpl::int_<OFTString> >
  , mpl::pair<char*                   , mpl::int_<OFTString> >
  , mpl::pair<char const*             , mpl::int_<OFTString> >
  , mpl::pair<std::vector<std::string>, mpl::int_<OFTStringList> >
92
  #ifdef OTB_USE_GDAL_20
93 94
    , mpl::pair<GIntBig, mpl::int_<OFTInteger64> >
    , mpl::pair<std::vector<GIntBig>, mpl::int_<OFTInteger64List> >
95
  #endif
Luc Hermitte's avatar
Luc Hermitte committed
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
  // OFTBinary
  // OFTDate
  // OFTTime
  // OFTDateTime
  > FieldType_Map;

/**\ingroup GeometryInternals
 * \class MemberGetterPtr
 * Type for hosting simple member-function pointers to field getters.
 * \tparam T type of field according to OGR API.
 * \tparam ptr_to_function member function pointer to a field getter from \c
 *         OGRFeature.
 * \tparam FinalReturnType type of the field according to OTB wrappers (default
 * <tt> = T</tt>)
 *
 * \internal
 * This is a hack to pass a member function pointer as template-parameter.
 * \since OTB v 3.14.0
 */
template
  < typename T
117 118 119
#if GDAL_VERSION_NUM >= 2030000
  , T ( OGRFeature::*ptr_to_function )(int) const
#else
Luc Hermitte's avatar
Luc Hermitte committed
120
  , T ( OGRFeature::*ptr_to_function )(int)
121
#endif
Luc Hermitte's avatar
Luc Hermitte committed
122 123 124 125 126 127 128 129 130 131
  , typename FinalReturnType = T
  > class MemberGetterPtr
    {
  public:
    static FinalReturnType call(OGRFeature &f, int index)
      {
      return (f.*ptr_to_function)(index);
      }
    };

132 133 134 135 136 137 138
/**\ingroup GeometryInternals
 * \class StringListMemberGetterPtr
 * Type for hosting member-function pointers to string-list field getters.
 * \tparam FinalReturnType type of the field according to OTB wrappers (default
 * <tt> = T</tt>)
 *
 * \internal
139
 * This override is required because of the particular nature of the
140 141 142 143 144 145 146 147 148 149 150 151
 * <tt>char**</tt> type chosen by OGR API, plus the fact this is the only
 * const-correct getter...
 * \since OTB v 3.14.0
 */
template
  < typename FinalReturnType = std::vector<std::string>
  > class StringListMemberGetterPtr
    {
  public:
    static FinalReturnType call(OGRFeature &f, int index)
      {
      char ** sl = f.GetFieldAsStringList(index);
152
      FinalReturnType res(sl, sl+CSLCount(sl));
153 154 155 156
      return res;
      }
    };

Luc Hermitte's avatar
Luc Hermitte committed
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
/**\ingroup GeometryInternals
 * \class MemberSetterPtr
 * Type for hosting simple member-function pointers to field setters.
 * \tparam T type of field according to OGR API.
 * \tparam ptr_to_function member function pointer to a field setter from \c
 *         OGRFeature.
 * <tt> = T</tt>)
 *
 * \internal
 * This is a hack to pass a member function pointer as template-parameter.
 * \since OTB v 3.14.0
 */
template
  < typename T
  , void ( OGRFeature::*ptr_to_function )(int, T value)
172
  , typename ActualParamType = T
Luc Hermitte's avatar
Luc Hermitte committed
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
  > class MemberSetterPtr
    {
  public:
    static void call(OGRFeature &f, int index, T const& value)
      {
      (f.*ptr_to_function)(index, value);
      }
    };

/**\ingroup GeometryInternals
 * \class MemberContainerGetterPtr
 * Type for hosting simple member-function pointers to list-field getters.
 * \tparam T type of field according to OGR API.
 * \tparam ptr_to_function member function pointer to a list-field getter from
 * \c OGRFeature.
 * \tparam FinalReturnType type of the list-field according to OTB wrappers
 * (default <tt> = std::vector<T></tt>)
 *
 * \internal
 * This is a hack to pass a member function pointer as template-parameter.
 * \since OTB v 3.14.0
 */
template
  < typename T
197 198 199
#if GDAL_VERSION_NUM >= 2030000
  , T const* ( OGRFeature::*ptr_to_function )(int, int*) const
#else
Luc Hermitte's avatar
Luc Hermitte committed
200
  , T const* ( OGRFeature::*ptr_to_function )(int, int*)
201
#endif
Luc Hermitte's avatar
Luc Hermitte committed
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
  , typename FinalReturnType = std::vector<T>
  > class MemberContainerGetterPtr
    {
  public:
    static FinalReturnType call(OGRFeature &f, int index)
      {
      int nb = 0;
      T const* raw_container = (f.*ptr_to_function)(index, &nb);
      const FinalReturnType res(raw_container+0, raw_container+nb);
      return res;
      }
    };

/*===========================================================================*/
/**\ingroup GeometryInternals
 * \class TagDispatchMemberContainerSetterPtr
 * \brief Dispatcher function for the Field Setter.
 * The container-field setters from OGR API have a C API. This dispatcher will
 * check whether the parameter container has a contiguous storage. If so it will
 * directly inject the address of the first element of the contiguous container
 * in the OGR C API. If not, the container will be converted into a container
 * with contiguous storage.
 * \since OTB v 3.14.0
 */
template
  < typename T
  , void ( OGRFeature::*ptr_to_function )(int, int, T*) // not const-correct
  , typename ActualParamType = std::vector<T>
  , bool Is_contiguous = boost::is_contiguous<ActualParamType>::value
  > class TagDispatchMemberContainerSetterPtr;

/**\ingroup GeometryInternals
 */
template
  < typename T
  , void ( OGRFeature::*ptr_to_function )(int, int, T*) // not const-correct
  , typename ActualParamType
  > class TagDispatchMemberContainerSetterPtr<T, ptr_to_function, ActualParamType, true>
    {
  public:
    static void call(OGRFeature &f, int index, ActualParamType const& container)
      {
      const int nb = boost::size(container);
245
      (f.*ptr_to_function)(index, nb, const_cast <T*>(&container[0]));
Luc Hermitte's avatar
Luc Hermitte committed
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
      }
    };

/**\ingroup GeometryInternals
 */
template
  < typename T
  , void ( OGRFeature::*ptr_to_function )(int, int, T*) // not const-correct
  , typename ActualParamType
  > class TagDispatchMemberContainerSetterPtr<T, ptr_to_function, ActualParamType, false>
    {
  public:
    static void call(OGRFeature &f, int index, ActualParamType const& container)
      {
      const int nb = boost::size(container);
      std::vector<T> v(boost::begin(container), boost::end(container));
      (f.*ptr_to_function)(index, nb, &v[0]);
      }
    };

266 267 268 269 270 271 272
/**\ingroup GeometryInternals
 * \class StringListMemberSetterPtr
 * Type for hosting member-function pointers to string-list field setters.
 * \tparam ActualParamType type of the field according to OTB wrappers (default
 * <tt> = T</tt>)
 *
 * \internal
273
 * This override is required because of the particular nature of the
274 275 276 277 278 279 280 281 282 283
 * <tt>char**</tt> type chosen by OGR API.
 * \since OTB v 3.14.0
 */
template
  < typename ActualParamType
  > class StringListMemberSetterPtr
    {
  public:
    static void call(OGRFeature &f, int index, ActualParamType const& container)
      {
Luc Hermitte's avatar
Luc Hermitte committed
284
      f.SetField(index, StringListConverter(container).to_ogr());
285 286 287
      }
    };

Luc Hermitte's avatar
Luc Hermitte committed
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
/**\ingroup GeometryInternals
 * \class MemberContainerSetterPtr
 * Type for hosting simple member-function pointers to list-field setters.
 * \tparam T type of field according to OGR API.
 * \tparam ptr_to_function member function pointer to a list-field setter from
 * \c OGRFeature.
 * \tparam FinalReturnType type of the list-field according to OTB wrappers
 * (default <tt> = std::vector<T></tt>)
 *
 * \internal
 * This is a hack to pass a member function pointer as template-parameter.
 * \since OTB v 3.14.0
 */
template
  < typename T
303 304 305
#if GDAL_VERSION_NUM >= 2030000
  , void ( OGRFeature::*ptr_to_function )(int, int, const T*)
#else
Luc Hermitte's avatar
Luc Hermitte committed
306
  , void ( OGRFeature::*ptr_to_function )(int, int, T*) // not const-correct
307
#endif
Luc Hermitte's avatar
Luc Hermitte committed
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
  , typename ActualParamType = std::vector<T>
  > class MemberContainerSetterPtr
    {
  public:
    static void call(OGRFeature &f, int index, ActualParamType const& container)
      {
      TagDispatchMemberContainerSetterPtr<
        T
        ,ptr_to_function
        ,ActualParamType
        , boost::is_contiguous<ActualParamType>::value
        >::call(f, index, container);
      }
    };

/**\ingroup GeometryInternals
 * Associative map of OGR field types (\c OGRFieldType) to their associated
 * getters.
 * \internal Relies on Boost.MPL
 * \since OTB v 3.14.0
 */
329 330 331 332 333 334 335
typedef mpl::map
  < mpl::pair<mpl::int_<OFTInteger>,     MemberGetterPtr<int,             &OGRFeature::GetFieldAsInteger> >
  , mpl::pair<mpl::int_<OFTIntegerList>, MemberContainerGetterPtr<int,    &OGRFeature::GetFieldAsIntegerList> >
  , mpl::pair<mpl::int_<OFTReal>,        MemberGetterPtr<double,          &OGRFeature::GetFieldAsDouble> >
  , mpl::pair<mpl::int_<OFTRealList>,    MemberContainerGetterPtr<double, &OGRFeature::GetFieldAsDoubleList> >
  , mpl::pair<mpl::int_<OFTString>,      MemberGetterPtr<char const*,     &OGRFeature::GetFieldAsString, std::string> >
  , mpl::pair<mpl::int_<OFTStringList>,  StringListMemberGetterPtr<std::vector<std::string> > >
336
  #ifdef OTB_USE_GDAL_20
337 338
  , mpl::pair<mpl::int_<OFTInteger64>, MemberGetterPtr<GIntBig, &OGRFeature::GetFieldAsInteger64> >
  , mpl::pair<mpl::int_<OFTInteger64List>, MemberContainerGetterPtr<GIntBig, &OGRFeature::GetFieldAsInteger64List> >
339
  #endif
Luc Hermitte's avatar
Luc Hermitte committed
340 341 342 343 344 345 346 347
  > FieldGetters_Map;

/**\ingroup GeometryInternals
 * Associative map of OGR field types (\c OGRFieldType) to their associated
 * setters.
 * \internal Relies on Boost.MPL
 * \since OTB v 3.14.0
 */
348 349 350 351 352 353 354
typedef mpl::map
  < mpl::pair<mpl::int_<OFTInteger>,     MemberSetterPtr<int,             &OGRFeature::SetField> >
  , mpl::pair<mpl::int_<OFTIntegerList>, MemberContainerSetterPtr<int,    &OGRFeature::SetField> >
  , mpl::pair<mpl::int_<OFTReal>,        MemberSetterPtr<double,          &OGRFeature::SetField> >
  , mpl::pair<mpl::int_<OFTRealList>,    MemberContainerSetterPtr<double, &OGRFeature::SetField> >
  , mpl::pair<mpl::int_<OFTString>,      MemberSetterPtr<char const*,     &OGRFeature::SetField/*, std::string*/> >
  , mpl::pair<mpl::int_<OFTStringList>,  StringListMemberSetterPtr<std::vector<std::string> > >
355
  #ifdef OTB_USE_GDAL_20
356 357
  , mpl::pair<mpl::int_<OFTInteger64>, MemberSetterPtr<GIntBig, &OGRFeature::SetField> >
  , mpl::pair<mpl::int_<OFTInteger64List>, MemberContainerSetterPtr<const GIntBig, &OGRFeature::SetField> >
358
  #endif
Luc Hermitte's avatar
Luc Hermitte committed
359 360
  > FieldSetters_Map;

361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
/**\ingroup GeometryInternals
 * \class CppToOGRConverter_trait
 * \brief Trait class for converting C++ types into OGR field setter compatible types.
 * \tparam T initial C++ type
 * \return C compatible type for OGR API.
 * \note C static arrays become pointers (in order to support literal strings)
 * \note C++ \c std::string becomes <tt>char const*</tt>
 * \since OTB v 3.14.0
 */
template <typename T> struct CppToOGRConverter_trait
    {
    typedef T type;
    static T const& convert(T const& value) { return value; }
    };

/**\ingroup GeometryInternals
 * \brief Specialisation for C static arrays.
 */
template <typename T, std::size_t N> struct CppToOGRConverter_trait<T[N]>
  {
  typedef T* type;
  static T const* convert(const T value[N]) { return &value[0]; }
  };

/**\ingroup GeometryInternals
 * \brief Specialisation for C++ \c std::string.
 */
template <> struct CppToOGRConverter_trait<std::string>
  {
  typedef char* type;
  static char const* convert(std::string const& value) { return value.c_str(); }
  };

Luc Hermitte's avatar
Luc Hermitte committed
394 395 396 397 398 399 400 401 402 403
} // namespace internal
} } // end namespace otb::ogr

/*===========================================================================*/
/*=======================[ otb::ogr::Field functions ]=======================*/
/*===========================================================================*/

inline
void otb::ogr::Field::CheckInvariants() const
{
404
  assert(m_Feature && "OGR Fields must be associated to a valid feature");
405
  assert(m_index < m_Feature->GetFieldCount() && "Out-of-range index for a OGR field");
406
  assert(m_Feature->GetFieldDefnRef(m_index) && "No definition available for the OGR field");
Luc Hermitte's avatar
Luc Hermitte committed
407 408 409 410 411 412 413
}

template <typename T>
inline
void otb::ogr::Field::SetValue(T const& value)
{
  CheckInvariants();
414
  typedef internal::CppToOGRConverter_trait<T> Converter;
Luc Hermitte's avatar
Luc Hermitte committed
415
  typedef typename Converter::type             InterfaceType;
416 417 418
  // uncomment the next line to debug the InterfaceType computed
  // boost::mpl::print<typename internal::CppToOGRConverter_trait<T>::type> interface_type; (void) interface_type;
  BOOST_MPL_ASSERT_MSG(!boost::is_array<InterfaceType>::value, InterFaceType_Cant_Be_An_array, (T, InterfaceType));
419
  typedef typename boost::mpl::at<internal::FieldType_Map, InterfaceType>::type Kind;
420
  BOOST_MPL_ASSERT_MSG(!(boost::is_same<Kind, boost::mpl::void_>::value), UNEXPECTED_KIND_TYPE, (T, InterfaceType, Kind));
Rashad Kanavath's avatar
Rashad Kanavath committed
421
  //const int VALUE = Kind::value;
422
  assert(m_Definition.GetType() == Kind::value && "OGR field type mismatches the type of new field value");
Luc Hermitte's avatar
Luc Hermitte committed
423
  typedef typename boost::mpl::at<internal::FieldSetters_Map, Kind>::type SetterType;
424 425
  // If you experience a static assertion failure in the line below, it means
  // the type of the parameter is not supported to set a field.
426
  BOOST_MPL_ASSERT_NOT((boost::is_same<SetterType, boost::mpl::void_>));
427
  SetterType::call(*m_Feature, m_index, Converter::convert(value));
Luc Hermitte's avatar
Luc Hermitte committed
428 429 430 431 432 433 434 435 436
}

template <typename T>
inline
T otb::ogr::Field::GetValue() const
{
  CheckInvariants();
  assert(HasBeenSet() && "Cannot access the value of a field that hasn't been set");
  typedef typename boost::mpl::at<internal::FieldType_Map, T>::type Kind;
Rashad Kanavath's avatar
Rashad Kanavath committed
437
  //const int VALUE = Kind::value;
Luc Hermitte's avatar
Luc Hermitte committed
438
  BOOST_STATIC_ASSERT(!(boost::is_same<Kind, boost::mpl::void_>::value));
439
  assert(m_Definition.GetType() == Kind::value && "OGR field type mismatches the type of requested field value");
Luc Hermitte's avatar
Luc Hermitte committed
440
  typedef typename boost::mpl::at<internal::FieldGetters_Map, Kind>::type GetterType;
441 442
  // If you experience a static assertion failure in the line below, it means
  // the field cannot be extracted into the type requested.
Luc Hermitte's avatar
Luc Hermitte committed
443 444 445 446
  BOOST_STATIC_ASSERT(!(boost::is_same<GetterType, boost::mpl::void_>::value));
  return GetterType::call(*m_Feature, m_index);
}

447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
inline
std::ostream & otb::ogr::Field::PrintSelf(
  std::ostream& os, itk::Indent indent) const
{
  CheckInvariants();
  return UncheckedPrintSelf(os, indent);
}

inline
bool otb::ogr::Field::HasBeenSet() const
{
  CheckInvariants();
  return UncheckedHasBeenSet();
}

inline
void otb::ogr::Field::Unset() const
{
  CheckInvariants();
  UncheckedUnset();
}

469 470 471 472 473
inline
void otb::ogr::Field::Assign(Field const& f)
{
  CheckInvariants();
  f.CheckInvariants();
474 475 476 477 478
  assert(f.GetType() == this->GetType() && "Cannot assign from a field that doesn't have the same definition");
  // We can't assume the following as sometimes field names are altered by the
  // datasource driver; for instance, shp driver truncates field names to 8
  // characters.
  // assert(f.GetDefinition() == this->GetDefinition() && "Cannot assign from a field that doesn't have the same definition");
479 480 481 482 483 484 485 486 487 488 489 490 491
  UncheckedAssign(f);
  CheckInvariants();
}

inline
OGRField & otb::ogr::Field::ogr()
{
  CheckInvariants();
  OGRField * f = m_Feature->GetRawFieldRef(m_index);
  assert(f && "The field obtained shall not be null");
  return *f;
}

492 493 494 495 496 497
inline
OGRField & otb::ogr::Field::ogr() const
{
  return const_cast <Field*>(this)->ogr();
}

498
#endif // otbOGRFieldWrapper_hxx