Forked from
Main Repositories / otb
9210 commits behind the upstream repository.
-
Manuel Grizonnet authoredManuel Grizonnet authored
otbOGRFieldWrapper.txx 16.75 KiB
/*=========================================================================
Program: ORFEO Toolbox
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
See OTBCopyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#ifndef otbOGRFieldWrapper_txx
#define otbOGRFieldWrapper_txx
/*===========================================================================*/
/*===============================[ Includes ]================================*/
/*===========================================================================*/
#include "otbOGRFieldWrapper.h"
#include "otbConfigure.h"
#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>
#include <boost/mpl/assert.hpp>
// #include <boost/mpl/print.hpp>
#include <boost/static_assert.hpp>
#include <boost/range/size.hpp>
#include <boost/type_traits/is_same.hpp>
// #include "boost/type_traits/is_array.hpp"
#include "boost/type_traits/is_contiguous.h" // from OTB actually
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
#include "ogr_feature.h" // OGRFeature::*field_getters
#pragma GCC diagnostic pop
#else
#include "ogr_feature.h" // OGRFeature::*field_getters
#endif
#include "cpl_string.h" // CSLCount
#include "otbOGRHelpers.h"
/*===========================================================================*/
/*================[ Associations C++ types -> OGR functions ]================*/
/*===========================================================================*/
namespace otb { namespace ogr {
/**\ingroup gGeometry
* \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
namespace mpl = boost::mpl;
/**\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.
*/
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> >
#ifdef OTB_USE_GDAL_20
, mpl::pair<GIntBig, mpl::int_<OFTInteger64> >
, mpl::pair<std::vector<GIntBig>, mpl::int_<OFTInteger64List> >
#endif
// 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
, T ( OGRFeature::*ptr_to_function )(int)
, typename FinalReturnType = T
> class MemberGetterPtr
{
public:
static FinalReturnType call(OGRFeature &f, int index)
{
return (f.*ptr_to_function)(index);
}
};
/**\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
* This ITK_OVERRIDE is required because of the particular nature of the
* <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);
FinalReturnType res(sl, sl+CSLCount(sl));
return res;
}
};
/**\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)
, typename ActualParamType = T
> 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
, T const* ( OGRFeature::*ptr_to_function )(int, int*)
, 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);
(f.*ptr_to_function)(index, nb, const_cast <T*>(&container[0]));
}
};
/**\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]);
}
};
/**\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
* This ITK_OVERRIDE is required because of the particular nature of the
* <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)
{
f.SetField(index, StringListConverter(container).to_ogr());
}
};
/**\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
, void ( OGRFeature::*ptr_to_function )(int, int, T*) // not const-correct
, 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
*/
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> > >
#ifdef OTB_USE_GDAL_20
, mpl::pair<mpl::int_<OFTInteger64>, MemberGetterPtr<GIntBig, &OGRFeature::GetFieldAsInteger64> >
, mpl::pair<mpl::int_<OFTInteger64List>, MemberContainerGetterPtr<GIntBig, &OGRFeature::GetFieldAsInteger64List> >
#endif
> 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
*/
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> > >
#ifdef OTB_USE_GDAL_20
, mpl::pair<mpl::int_<OFTInteger64>, MemberSetterPtr<GIntBig, &OGRFeature::SetField> >
, mpl::pair<mpl::int_<OFTInteger64List>, MemberContainerSetterPtr<const GIntBig, &OGRFeature::SetField> >
#endif
> FieldSetters_Map;
/**\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(); }
};
} // namespace internal
} } // end namespace otb::ogr
/*===========================================================================*/
/*=======================[ otb::ogr::Field functions ]=======================*/
/*===========================================================================*/
inline
void otb::ogr::Field::CheckInvariants() const
{
assert(m_Feature && "OGR Fields must be associated to a valid feature");
assert(m_index < m_Feature->GetFieldCount() && "Out-of-range index for a OGR field");
assert(m_Feature->GetFieldDefnRef(m_index) && "No definition available for the OGR field");
}
template <typename T>
inline
void otb::ogr::Field::SetValue(T const& value)
{
CheckInvariants();
typedef internal::CppToOGRConverter_trait<T> Converter;
typedef typename Converter::type InterfaceType;
// 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));
typedef typename boost::mpl::at<internal::FieldType_Map, InterfaceType>::type Kind;
BOOST_MPL_ASSERT_MSG(!(boost::is_same<Kind, boost::mpl::void_>::value), UNEXPECTED_KIND_TYPE, (T, InterfaceType, Kind));
//const int VALUE = Kind::value;
assert(m_Definition.GetType() == Kind::value && "OGR field type mismatches the type of new field value");
typedef typename boost::mpl::at<internal::FieldSetters_Map, Kind>::type SetterType;
// 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.
BOOST_MPL_ASSERT_NOT((boost::is_same<SetterType, boost::mpl::void_>));
SetterType::call(*m_Feature, m_index, Converter::convert(value));
}
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;
//const int VALUE = Kind::value;
BOOST_STATIC_ASSERT(!(boost::is_same<Kind, boost::mpl::void_>::value));
assert(m_Definition.GetType() == Kind::value && "OGR field type mismatches the type of requested field value");
typedef typename boost::mpl::at<internal::FieldGetters_Map, Kind>::type GetterType;
// If you experience a static assertion failure in the line below, it means
// the field cannot be extracted into the type requested.
BOOST_STATIC_ASSERT(!(boost::is_same<GetterType, boost::mpl::void_>::value));
return GetterType::call(*m_Feature, m_index);
}
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();
}
inline
void otb::ogr::Field::Assign(Field const& f)
{
CheckInvariants();
f.CheckInvariants();
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");
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;
}
inline
OGRField & otb::ogr::Field::ogr() const
{
return const_cast <Field*>(this)->ogr();
}
#endif // otbOGRFieldWrapper_txx