diff --git a/include/lsst/afw/table/AliasMap.h b/include/lsst/afw/table/AliasMap.h index 5b835a874a..75131a8313 100644 --- a/include/lsst/afw/table/AliasMap.h +++ b/include/lsst/afw/table/AliasMap.h @@ -5,6 +5,8 @@ #include #include +#include "lsst/afw/table/fwd.h" + namespace lsst { namespace afw { namespace table { diff --git a/include/lsst/afw/table/Field.h b/include/lsst/afw/table/Field.h index 05fd20a545..402586602b 100644 --- a/include/lsst/afw/table/Field.h +++ b/include/lsst/afw/table/Field.h @@ -2,6 +2,7 @@ #ifndef AFW_TABLE_Field_h_INCLUDED #define AFW_TABLE_Field_h_INCLUDED +#include #include #include "lsst/afw/table/FieldBase.h" diff --git a/include/lsst/afw/table/FieldBase.h b/include/lsst/afw/table/FieldBase.h index 227ac1cc3f..d9df577a5f 100644 --- a/include/lsst/afw/table/FieldBase.h +++ b/include/lsst/afw/table/FieldBase.h @@ -2,19 +2,13 @@ #ifndef AFW_TABLE_FieldBase_h_INCLUDED #define AFW_TABLE_FieldBase_h_INCLUDED -#include +#include #include -#include "boost/mpl/vector.hpp" -#include "boost/preprocessor/punctuation/paren.hpp" -#include "Eigen/Core" +#include "ndarray.h" -#include "lsst/base.h" #include "lsst/pex/exceptions.h" -#include "ndarray.h" #include "lsst/afw/table/misc.h" -#include "lsst/afw/table/KeyBase.h" -#include "lsst/afw/table/types.h" namespace lsst { namespace afw { @@ -291,6 +285,47 @@ struct FieldBase { private: int _size; }; + +/** + * Specialization for Flag fields. + * + * Flag fields are handled specially in many places, because their keys have both an offset into an + * integer element and the bit in that element; while other fields have one or more elements per field, + * Flags have multiple fields per element. This means we can't put all the custom code for Flag in + * FieldBase, and because Flags have an explicit Key specialization, we put the record access + * implementation in Key. + */ +template <> +struct FieldBase { + typedef bool Value; ///< the type returned by BaseRecord::get + typedef std::int64_t Element; ///< the actual storage type (shared by multiple flag fields) + + /// Return the number of subfield elements (always one for scalars). + int getElementCount() const { return 1; } + + /// Return a string description of the field type. + static std::string getTypeString() { return "Flag"; } + + // Only the first of these constructors is valid for this specializations, but + // it's convenient to be able to instantiate both, since the other is used + // by other specializations. + FieldBase() = default; + FieldBase(int) { + throw LSST_EXCEPT(lsst::pex::exceptions::LogicError, + "Constructor disabled (this Field type is not sized)."); + } + + FieldBase(FieldBase const &) = default; + FieldBase(FieldBase &&) = default; + FieldBase &operator=(FieldBase const &) = default; + FieldBase &operator=(FieldBase &&) = default; + ~FieldBase() = default; + +protected: + /// Defines how fields are printed. + void stream(std::ostream &os) const {} +}; + } // namespace table } // namespace afw } // namespace lsst diff --git a/include/lsst/afw/table/Flag.h b/include/lsst/afw/table/Flag.h index ddb8895321..344c8c29f0 100644 --- a/include/lsst/afw/table/Flag.h +++ b/include/lsst/afw/table/Flag.h @@ -2,195 +2,14 @@ #ifndef LSST_AFW_TABLE_Flag_h_INCLUDED #define LSST_AFW_TABLE_Flag_h_INCLUDED -#include +// This is a backwards-compatibility header; the template specializations for +// flag have now been included in the same headers as the default definitions +// of those templates (included below). This guards against implicit +// instantiation of the default templates for Flag, which would be a violation +// of the One Definition Rule. -#include "lsst/utils/hashCombine.h" - -#include "lsst/afw/table/misc.h" #include "lsst/afw/table/FieldBase.h" #include "lsst/afw/table/KeyBase.h" - -namespace lsst { -namespace afw { -namespace table { - -namespace detail { - -class Access; - -} // namespace detail - -/** - * Specialization for Flag fields. - * - * Flag fields are handled specially in many places, because their keys have both an offset into an - * integer element and the bit in that element; while other fields have one or more elements per field, - * Flags have multiple fields per element. This means we can't put all the custom code for Flag in - * FieldBase, and because Flags have an explicit Key specialization, we put the record access - * implementation in Key. - */ -template <> -struct FieldBase { - typedef bool Value; ///< the type returned by BaseRecord::get - typedef std::int64_t Element; ///< the actual storage type (shared by multiple flag fields) - - /// Return the number of subfield elements (always one for scalars). - int getElementCount() const { return 1; } - - /// Return a string description of the field type. - static std::string getTypeString() { return "Flag"; } - - // Only the first of these constructors is valid for this specializations, but - // it's convenient to be able to instantiate both, since the other is used - // by other specializations. - FieldBase() = default; - FieldBase(int) { - throw LSST_EXCEPT(lsst::pex::exceptions::LogicError, - "Constructor disabled (this Field type is not sized)."); - } - - FieldBase(FieldBase const &) = default; - FieldBase(FieldBase &&) = default; - FieldBase &operator=(FieldBase const &) = default; - FieldBase &operator=(FieldBase &&) = default; - ~FieldBase() = default; - -protected: - /// Defines how fields are printed. - void stream(std::ostream &os) const {} -}; - -/** - * A base class for Key that allows the underlying storage field to be extracted. - */ -template <> -class KeyBase { -public: - static bool const HAS_NAMED_SUBFIELDS = false; - - /// Return a key corresponding to the integer element where this field's bit is packed. - Key::Element> getStorage() const; - - KeyBase() = default; - KeyBase(KeyBase const &) = default; - KeyBase(KeyBase &&) = default; - KeyBase &operator=(KeyBase const &) = default; - KeyBase &operator=(KeyBase &&) = default; - ~KeyBase() = default; -}; - -/** - * Key specialization for Flag. - * - * Flag fields are special; their keys need to contain not only the offset to the - * integer element they share with other Flag fields, but also their position - * in that shared field. - * - * Flag fields operate mostly like a bool field, but they do not support reference - * access, and internally they are packed into an integer shared by multiple fields - * so the marginal cost of each Flag field is only one bit. - */ -template <> -class Key : public KeyBase, public FieldBase { -public: - //@{ - /** - * Equality comparison. - * - * Two keys with different types are never equal. Keys with the same type - * are equal if they point to the same location in a table, regardless of - * what Schema they were constructed from (for instance, if a field has a - * different name in one Schema than another, but is otherwise the same, - * the two keys will be equal). - */ - template - bool operator==(Key const &other) const { - return false; - } - template - bool operator!=(Key const &other) const { - return true; - } - - bool operator==(Key const &other) const { return _offset == other._offset && _bit == other._bit; } - bool operator!=(Key const &other) const { return !this->operator==(other); } - //@} - - /// Return a hash of this object. - std::size_t hash_value() const noexcept { - // Completely arbitrary seed - return utils::hashCombine(17, _offset, _bit); - } - - /// Return the offset in bytes of the integer element that holds this field's bit. - int getOffset() const { return _offset; } - - /// The index of this field's bit within the integer it shares with other Flag fields. - int getBit() const { return _bit; } - - /** - * Return true if the key was initialized to valid offset. - * - * This does not guarantee that a key is valid with any particular schema, or even - * that any schemas still exist in which this key is valid. - * - * A key that is default constructed will always be invalid. - */ - bool isValid() const { return _offset >= 0; } - - /** - * Default construct a field. - * - * The new field will be invalid until a valid Key is assigned to it. - */ - Key() : FieldBase(), _offset(-1), _bit(0) {} - - Key(Key const &) = default; - Key(Key &&) = default; - Key &operator=(Key const &) = default; - Key &operator=(Key &&) = default; - ~Key() = default; - - /// Stringification. - inline friend std::ostream &operator<<(std::ostream &os, Key const &key) { - return os << "Key['" << Key::getTypeString() << "'](offset=" << key.getOffset() - << ", bit=" << key.getBit() << ")"; - } - -private: - friend class detail::Access; - friend class BaseRecord; - - /// Used to implement BaseRecord::get. - Value getValue(Element const *p, ndarray::Manager::Ptr const &) const { - return (*p) & (Element(1) << _bit); - } - - /// Used to implement BaseRecord::set. - void setValue(Element *p, ndarray::Manager::Ptr const &, Value v) const { - if (v) { - *p |= (Element(1) << _bit); - } else { - *p &= ~(Element(1) << _bit); - } - } - - explicit Key(int offset, int bit) : _offset(offset), _bit(bit) {} - - int _offset; - int _bit; -}; -} // namespace table -} // namespace afw -} // namespace lsst - -namespace std { -template <> -struct hash> { - using argument_type = lsst::afw::table::Key; - using result_type = size_t; - size_t operator()(argument_type const &obj) const noexcept { return obj.hash_value(); } -}; -} // namespace std +#include "lsst/afw/table/Key.h" #endif // !LSST_AFW_TABLE_Flag_h_INCLUDED diff --git a/include/lsst/afw/table/Key.h b/include/lsst/afw/table/Key.h index bdabaee410..b96d5be4ab 100644 --- a/include/lsst/afw/table/Key.h +++ b/include/lsst/afw/table/Key.h @@ -2,10 +2,11 @@ #ifndef AFW_TABLE_Key_h_INCLUDED #define AFW_TABLE_Key_h_INCLUDED +#include + #include "lsst/utils/hashCombine.h" #include "lsst/afw/table/FieldBase.h" -#include "lsst/afw/table/Flag.h" #include "lsst/afw/table/KeyBase.h" namespace lsst { @@ -124,6 +125,109 @@ class Key : public KeyBase, public FieldBase { int _offset; }; + +/** + * Key specialization for Flag. + * + * Flag fields are special; their keys need to contain not only the offset to the + * integer element they share with other Flag fields, but also their position + * in that shared field. + * + * Flag fields operate mostly like a bool field, but they do not support reference + * access, and internally they are packed into an integer shared by multiple fields + * so the marginal cost of each Flag field is only one bit. + */ +template <> +class Key : public KeyBase, public FieldBase { +public: + //@{ + /** + * Equality comparison. + * + * Two keys with different types are never equal. Keys with the same type + * are equal if they point to the same location in a table, regardless of + * what Schema they were constructed from (for instance, if a field has a + * different name in one Schema than another, but is otherwise the same, + * the two keys will be equal). + */ + template + bool operator==(Key const &other) const { + return false; + } + template + bool operator!=(Key const &other) const { + return true; + } + + bool operator==(Key const &other) const { return _offset == other._offset && _bit == other._bit; } + bool operator!=(Key const &other) const { return !this->operator==(other); } + //@} + + /// Return a hash of this object. + std::size_t hash_value() const noexcept { + // Completely arbitrary seed + return utils::hashCombine(17, _offset, _bit); + } + + /// Return the offset in bytes of the integer element that holds this field's bit. + int getOffset() const { return _offset; } + + /// The index of this field's bit within the integer it shares with other Flag fields. + int getBit() const { return _bit; } + + /** + * Return true if the key was initialized to valid offset. + * + * This does not guarantee that a key is valid with any particular schema, or even + * that any schemas still exist in which this key is valid. + * + * A key that is default constructed will always be invalid. + */ + bool isValid() const { return _offset >= 0; } + + /** + * Default construct a field. + * + * The new field will be invalid until a valid Key is assigned to it. + */ + Key() : FieldBase(), _offset(-1), _bit(0) {} + + Key(Key const &) = default; + Key(Key &&) = default; + Key &operator=(Key const &) = default; + Key &operator=(Key &&) = default; + ~Key() = default; + + /// Stringification. + inline friend std::ostream &operator<<(std::ostream &os, Key const &key) { + return os << "Key['" << Key::getTypeString() << "'](offset=" << key.getOffset() + << ", bit=" << key.getBit() << ")"; + } + +private: + friend class detail::Access; + friend class BaseRecord; + + /// Used to implement BaseRecord::get. + Value getValue(Element const *p, ndarray::Manager::Ptr const &) const { + return (*p) & (Element(1) << _bit); + } + + /// Used to implement BaseRecord::set. + void setValue(Element *p, ndarray::Manager::Ptr const &, Value v) const { + if (v) { + *p |= (Element(1) << _bit); + } else { + *p &= ~(Element(1) << _bit); + } + } + + explicit Key(int offset, int bit) : _offset(offset), _bit(bit) {} + + int _offset; + int _bit; +}; + } // namespace table } // namespace afw } // namespace lsst @@ -135,6 +239,14 @@ struct hash> { using result_type = size_t; size_t operator()(argument_type const& obj) const noexcept { return obj.hash_value(); } }; + +template <> +struct hash> { + using argument_type = lsst::afw::table::Key; + using result_type = size_t; + size_t operator()(argument_type const &obj) const noexcept { return obj.hash_value(); } +}; + } // namespace std #endif // !AFW_TABLE_Key_h_INCLUDED diff --git a/include/lsst/afw/table/KeyBase.h b/include/lsst/afw/table/KeyBase.h index 3a1ade65ab..25acba7c72 100644 --- a/include/lsst/afw/table/KeyBase.h +++ b/include/lsst/afw/table/KeyBase.h @@ -5,6 +5,7 @@ #include #include "lsst/afw/table/misc.h" +#include "lsst/afw/table/FieldBase.h" namespace lsst { namespace afw { @@ -12,14 +13,18 @@ namespace table { class BaseRecord; -template -class Key; - /// A base class for Key that allows subfield keys to be extracted for some field types. template class KeyBase { public: static bool const HAS_NAMED_SUBFIELDS = false; + + KeyBase() = default; + KeyBase(KeyBase const &) = default; + KeyBase(KeyBase &&) = default; + KeyBase &operator=(KeyBase const &) = default; + KeyBase &operator=(KeyBase &&) = default; + ~KeyBase() = default; }; /// KeyBase specialization for Arrays. @@ -28,6 +33,13 @@ class KeyBase > { public: static bool const HAS_NAMED_SUBFIELDS = false; + KeyBase() = default; + KeyBase(KeyBase const &) = default; + KeyBase(KeyBase &&) = default; + KeyBase &operator=(KeyBase const &) = default; + KeyBase &operator=(KeyBase &&) = default; + ~KeyBase() = default; + std::vector extractVector(BaseRecord const& record) const; void assignVector(BaseRecord& record, std::vector const& values) const; @@ -36,6 +48,25 @@ class KeyBase > { Key > slice(int begin, int end) const; ///< Return a key for a range of elements }; + +/// KeyBase specialization for Flags. +template <> +class KeyBase { +public: + static bool const HAS_NAMED_SUBFIELDS = false; + + KeyBase() = default; + KeyBase(KeyBase const &) = default; + KeyBase(KeyBase &&) = default; + KeyBase &operator=(KeyBase const &) = default; + KeyBase &operator=(KeyBase &&) = default; + ~KeyBase() = default; + + /// Return a key corresponding to the integer element where this field's bit is packed. + Key::Element> getStorage() const; + +}; + } // namespace table } // namespace afw } // namespace lsst diff --git a/include/lsst/afw/table/Schema.h b/include/lsst/afw/table/Schema.h index c03b9e9bf8..adf86c7c01 100644 --- a/include/lsst/afw/table/Schema.h +++ b/include/lsst/afw/table/Schema.h @@ -12,7 +12,6 @@ #include "lsst/afw/table/Key.h" #include "lsst/afw/table/Field.h" #include "lsst/afw/table/detail/SchemaImpl.h" -#include "lsst/afw/table/Flag.h" #include "lsst/afw/table/AliasMap.h" namespace lsst { diff --git a/include/lsst/afw/table/SchemaMapper.h b/include/lsst/afw/table/SchemaMapper.h index 742dc24c32..4da45db6ec 100644 --- a/include/lsst/afw/table/SchemaMapper.h +++ b/include/lsst/afw/table/SchemaMapper.h @@ -4,6 +4,9 @@ #include +#include "lsst/afw/table/Key.h" +#include "lsst/afw/table/Field.h" +#include "lsst/afw/table/Schema.h" #include "lsst/afw/table/detail/SchemaMapperImpl.h" namespace lsst { diff --git a/include/lsst/afw/table/aggregates.h b/include/lsst/afw/table/aggregates.h index e9f4c282c2..9c9329d82b 100644 --- a/include/lsst/afw/table/aggregates.h +++ b/include/lsst/afw/table/aggregates.h @@ -23,11 +23,15 @@ #ifndef AFW_TABLE_aggregates_h_INCLUDED #define AFW_TABLE_aggregates_h_INCLUDED +#include +#include +#include "Eigen/Core" + #include "lsst/utils/hashCombine.h" +#include "lsst/geom.h" #include "lsst/afw/table/FunctorKey.h" #include "lsst/afw/table/Schema.h" -#include "lsst/geom.h" namespace lsst { namespace afw { @@ -36,6 +40,7 @@ namespace geom { namespace ellipses { class Quadrupole; +class Ellipse; } // namespace ellipses } // namespace geom diff --git a/include/lsst/afw/table/arrays.h b/include/lsst/afw/table/arrays.h index 2f8fccb77d..9127af0155 100644 --- a/include/lsst/afw/table/arrays.h +++ b/include/lsst/afw/table/arrays.h @@ -23,6 +23,10 @@ #ifndef AFW_TABLE_arrays_h_INCLUDED #define AFW_TABLE_arrays_h_INCLUDED +#include +#include +#include "ndarray.h" + #include "lsst/utils/hashCombine.h" #include "lsst/afw/table/FunctorKey.h" diff --git a/include/lsst/afw/table/detail/Access.h b/include/lsst/afw/table/detail/Access.h index b6ddaca7f3..c0dbbe4ac8 100644 --- a/include/lsst/afw/table/detail/Access.h +++ b/include/lsst/afw/table/detail/Access.h @@ -2,12 +2,13 @@ #ifndef AFW_TABLE_DETAIL_Access_h_INCLUDED #define AFW_TABLE_DETAIL_Access_h_INCLUDED -#include +#include #include "ndarray/Manager.h" -#include "lsst/afw/table/FieldBase.h" +#include "lsst/afw/table/misc.h" +#include "lsst/afw/table/KeyBase.h" +#include "lsst/afw/table/Key.h" #include "lsst/afw/table/Schema.h" -#include "lsst/afw/table/detail/SchemaImpl.h" namespace lsst { namespace afw { diff --git a/include/lsst/afw/table/detail/SchemaImpl.h b/include/lsst/afw/table/detail/SchemaImpl.h index 160c3b2286..cdccf26f08 100644 --- a/include/lsst/afw/table/detail/SchemaImpl.h +++ b/include/lsst/afw/table/detail/SchemaImpl.h @@ -5,11 +5,14 @@ #include #include #include -#include #include "boost/variant.hpp" #include "boost/mpl/transform.hpp" +#include "lsst/afw/table/Key.h" +#include "lsst/afw/table/Field.h" +#include "lsst/afw/table/types.h" + namespace lsst { namespace afw { namespace table { diff --git a/include/lsst/afw/table/detail/SchemaMapperImpl.h b/include/lsst/afw/table/detail/SchemaMapperImpl.h index 1bed0b06d9..fed6f4ca9e 100644 --- a/include/lsst/afw/table/detail/SchemaMapperImpl.h +++ b/include/lsst/afw/table/detail/SchemaMapperImpl.h @@ -8,6 +8,8 @@ #include "boost/variant.hpp" #include "boost/mpl/transform.hpp" +#include "lsst/afw/table/Key.h" +#include "lsst/afw/table/types.h" #include "lsst/afw/table/Schema.h" namespace lsst { diff --git a/include/lsst/afw/table/fwd.h b/include/lsst/afw/table/fwd.h index 45c16e77bc..bacf427a98 100644 --- a/include/lsst/afw/table/fwd.h +++ b/include/lsst/afw/table/fwd.h @@ -41,10 +41,9 @@ namespace lsst { namespace afw { namespace table { -template -class Key; -template -struct Field; +// Some schema primitives (Key, Field, KeyBase, FieldBase) are forward-declared +// in misc.h, along with their explicit specializations. + template struct SchemaItem; class Schema; diff --git a/include/lsst/afw/table/misc.h b/include/lsst/afw/table/misc.h index bb79096141..567a0bc82f 100644 --- a/include/lsst/afw/table/misc.h +++ b/include/lsst/afw/table/misc.h @@ -3,8 +3,7 @@ #define AFW_TABLE_misc_h_INCLUDED #include - -#include "boost/mpl/if.hpp" +#include #include "lsst/geom/Angle.h" #include "lsst/geom/SpherePoint.h" @@ -34,6 +33,25 @@ class Flag; typedef lsst::geom::Angle Angle; typedef lsst::geom::SpherePoint SpherePoint; //@} + + +// Forward-declare schema primitives, and then forward-declare all +// explicit specializations, to guard against code implicitly instantiating +// the default template for any of those. + +template class KeyBase; +template class FieldBase; +template class Key; +template class Field; + +template <> class KeyBase; +template <> class FieldBase; +template <> class Key; + +template class KeyBase>; +template class FieldBase>; +template <> class FieldBase; + } // namespace table } // namespace afw } // namespace lsst diff --git a/include/lsst/afw/table/types.h b/include/lsst/afw/table/types.h index f8e9a4507b..14c18d398c 100644 --- a/include/lsst/afw/table/types.h +++ b/include/lsst/afw/table/types.h @@ -8,16 +8,8 @@ #include "boost/mpl/vector.hpp" #include "boost/preprocessor/punctuation/paren.hpp" -#include "Eigen/Core" - -#include "lsst/base.h" -#include "lsst/pex/exceptions.h" -#include "ndarray.h" -#include "lsst/geom.h" -#include "lsst/afw/geom/ellipses.h" -#include "lsst/afw/coord.h" + #include "lsst/afw/table/misc.h" -#include "lsst/afw/table/KeyBase.h" /* * This file contains macros and MPL vectors that list the types that can be used for fields. diff --git a/src/table/FieldBase.cc b/src/table/FieldBase.cc index 319006465e..7bd7760237 100644 --- a/src/table/FieldBase.cc +++ b/src/table/FieldBase.cc @@ -8,7 +8,7 @@ #include "boost/preprocessor/tuple/to_seq.hpp" #include "lsst/afw/table/FieldBase.h" -#include "lsst/afw/table/Flag.h" +#include "lsst/afw/table/types.h" namespace lsst { namespace afw { diff --git a/src/table/aggregates.cc b/src/table/aggregates.cc index 8af5fdd9c9..082236d676 100644 --- a/src/table/aggregates.cc +++ b/src/table/aggregates.cc @@ -22,7 +22,7 @@ */ #include "lsst/afw/geom/ellipses/Quadrupole.h" -#include "lsst/geom/Box.h" +#include "lsst/afw/geom/ellipses/Ellipse.h" #include "lsst/afw/table/aggregates.h" #include "lsst/afw/table/BaseRecord.h" diff --git a/src/table/io/FitsSchemaInputMapper.cc b/src/table/io/FitsSchemaInputMapper.cc index 44a9cd636d..8577085a01 100644 --- a/src/table/io/FitsSchemaInputMapper.cc +++ b/src/table/io/FitsSchemaInputMapper.cc @@ -17,6 +17,7 @@ #include "lsst/log/Log.h" #include "lsst/geom.h" +#include "lsst/afw/geom/ellipses/Quadrupole.h" #include "lsst/afw/table/io/FitsSchemaInputMapper.h" #include "lsst/afw/table/aggregates.h"