Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:13:09

0001 #ifndef FWCore_SOA_Table_h
0002 #define FWCore_SOA_Table_h
0003 // -*- C++ -*-
0004 //
0005 // Package:     FWCore/SOA
0006 // Class  :     Table
0007 //
0008 /**\class Table Table.h "Table.h"
0009 
0010  Description: A Table which is a 'structure of arrays'
0011 
0012  Usage:
0013     A Table provides a 'structure of arrays' using a spreadsheet metaphor.
0014  The template arguments of a Table should be edm::soa::Column<> types which 
0015  declare the type of the column and a label.
0016  \code
0017  constexpr char kEta[] = "eta";
0018  using Eta = edm::soa::Column<double,kEta>;
0019 
0020  constexpr char kPhi[] = "phi";
0021  using Phi = edm::soa::Column<double,kPhi>;
0022 
0023  using SphereTable = edm::soa::Table<Eta,Phi>;
0024  \endcode
0025 
0026  The same declaration of a column should be shared by different tables
0027  in order to allow the functions to be reused across tables. [See TableView]
0028  
0029  Accessing data within a Table is done by specifying the column and row
0030  to be used. The column is identified by the edm::soa::Column<> type and 
0031  the row by an integer.
0032  
0033  \code
0034  SphereTable sphereTable{...};
0035  ...
0036  auto eta1 = sphereTable.get<Eta>(1);
0037  \endcode
0038  
0039  One can iterate over all rows of a Table and get the values of interest
0040  \code
0041  SphereTable sphereTable{...};
0042  ...
0043  for(auto const& row: sphereTable) {
0044     std::cout<<row.get<Eta>()<<std::endl;
0045  }
0046  \encode
0047  If only some of the columns are of interest, the optimizer of the compiler
0048  is very good at removing code associated with non-used columns and providing
0049  a highly optimized access to just the data of interest.
0050  
0051  On can also explicitly iterate over a single column of interest
0052  \code
0053  SphereTable sphereTable{...};
0054  ...
0055  for(auto eta: sphereTable.column<Eta>()) {
0056     std::cout<<eta<<std::endl;
0057  }
0058  \encode
0059  Usually the optimizer on the compiler is able to make iteration over the entire
0060  row and iterating over just one column compile down to exactly the same machine
0061  instructions.
0062  
0063  A Table can be constructed either by
0064  1) passing as many containers as their are columns
0065  \code
0066    std::array<double, 4> eta = {...};
0067    std::array<double, 4> phi = {...};
0068    SphereTable sphereTable{eta,phi};
0069  \endcode
0070  2) passing a single container of objects where the objects hold the value of interests
0071  and where appropriate 'value_for_column' functions are defined [See ColumnFillers.h]
0072  \code
0073    class Vector {
0074      ...
0075      double eta() const;
0076      double phi() const;
0077      ...
0078    };
0079  
0080    double value_for_column(Vector const& iV, Eta*) { return iV.eta(); }
0081    double value_for_column(Vector const& iV, Phi*) { return iV.phi(); }
0082    ...
0083  
0084    std::vector<Vector> vectors{...};
0085    ...
0086    SphereTable sphereTable{ vectors };
0087  \endcode
0088  
0089  Functions which operate over Tables should not take Tables are arguments.
0090  Instead, they should take an edm::soa::TableView<>. This will allow the function
0091  to operate on any Table that uses the edm::soa::Column<> type needed by the function.
0092  \code
0093     SphereTable sphericalAngles(edm::soa::TableView<X,Y,Z>);
0094  \endcode
0095 
0096  
0097  New Table declarations can be created based on existing Table declarations.
0098  E.g. say you want a new Table based on an existing Table but with an additional column.
0099  \code
0100    using ATable = edm::soa::Table<...>;
0101  
0102    using MyLabel = edm::soa::Column<...>;
0103    using MyATable = AddColumns_t<ATable, MyLabel>;
0104  \endcode
0105  
0106  It is also possible to declare a new Table by removing columns from an existing declaration
0107  \code
0108    using MyBTable = RemoveColumn_t<BTable, Phi>; //Phi is a previously defined Column
0109  \endcode
0110  */
0111 //
0112 // Original Author:  Chris Jones
0113 //         Created:  Thu, 24 Aug 2017 16:18:05 GMT
0114 //
0115 
0116 // system include files
0117 #include <memory>
0118 #include <tuple>
0119 #include <array>
0120 
0121 // user include files
0122 #include "FWCore/SOA/interface/TableItr.h"
0123 #include "FWCore/SOA/interface/tablehelpers.h"
0124 #include "FWCore/SOA/interface/ColumnFillers.h"
0125 #include "FWCore/SOA/interface/ColumnValues.h"
0126 #include "FWCore/SOA/interface/RowView.h"
0127 
0128 //The following is needed for edm::Wrapper
0129 #include "FWCore/SOA/interface/TableExaminer.h"
0130 
0131 // forward declarations
0132 
0133 namespace edm {
0134   namespace soa {
0135 
0136     template <typename... Args>
0137     class Table {
0138     public:
0139       static constexpr const unsigned int kNColumns = sizeof...(Args);
0140       using Layout = std::tuple<Args...>;
0141       using const_iterator = ConstTableItr<Args...>;
0142       using iterator = TableItr<Args...>;
0143 
0144       template <typename T, typename... CArgs>
0145       Table(T const& iContainer, CArgs... iArgs) : m_size(iContainer.size()) {
0146         if constexpr (sizeof...(CArgs) == 0) {
0147           CtrFillerFromAOS::fill(m_values, iContainer);
0148         } else {
0149           CtrFillerFromContainers::fill(m_values, iContainer, std::forward<CArgs>(iArgs)...);
0150         }
0151       }
0152 
0153       template <typename T, typename... CArgs>
0154       Table(T const& iContainer, ColumnFillers<CArgs...> iFiller) {
0155         m_size = iContainer.size();
0156         CtrFillerFromAOS::fillUsingFiller(iFiller, m_values, iContainer);
0157       }
0158 
0159       Table(Table<Args...> const& iOther) : m_size(iOther.m_size), m_values{{nullptr}} {
0160         copyFromToWithResizeAll(m_size, iOther.m_values, m_values, std::make_index_sequence<sizeof...(Args)>{});
0161       }
0162 
0163       Table(Table<Args...>&& iOther) : m_size(0), m_values{{nullptr}} {
0164         std::swap(m_size, iOther.m_size);
0165         std::swap(m_values, iOther.m_values);
0166       }
0167 
0168       Table() : m_size(0) {}
0169 
0170       ~Table() { dtr<0>(m_values); }
0171 
0172       Table<Args...>& operator=(Table<Args...>&& iOther) {
0173         Table<Args...> cp(std::move(iOther));
0174         std::swap(m_size, cp.m_size);
0175         std::swap(m_values, cp.m_values);
0176         return *this;
0177       }
0178       Table<Args...>& operator=(Table<Args...> const& iOther) { return operator=(Table<Args...>(iOther)); }
0179 
0180       unsigned int size() const { return m_size; }
0181 
0182       void resize(unsigned int iNewSize) {
0183         if (m_size == iNewSize) {
0184           return;
0185         }
0186         resizeFromTo<0>(m_size, iNewSize, m_values);
0187         if (m_size < iNewSize) {
0188           //initialize the extra values
0189           resetStartingAt<0>(m_size, iNewSize, m_values);
0190         }
0191         m_size = iNewSize;
0192       }
0193 
0194       template <typename U>
0195       typename U::type const& get(size_t iRow) const {
0196         return *(static_cast<typename U::type const*>(columnAddress<U>()) + iRow);
0197       }
0198       template <typename U>
0199       typename U::type& get(size_t iRow) {
0200         return *(static_cast<typename U::type*>(columnAddress<U>()) + iRow);
0201       }
0202 
0203       template <typename U>
0204       ColumnValues<typename U::type> column() const {
0205         return ColumnValues<typename U::type>{static_cast<typename U::type*>(columnAddress<U>()), m_size};
0206       }
0207       template <typename U>
0208       MutableColumnValues<typename U::type> column() {
0209         return MutableColumnValues<typename U::type>{static_cast<typename U::type*>(columnAddress<U>()), m_size};
0210       }
0211 
0212       RowView<Args...> row(size_t iRow) const { return *(begin() + iRow); }
0213       MutableRowView<Args...> row(size_t iRow) { return *(begin() + iRow); }
0214 
0215       const_iterator begin() const {
0216         std::array<void const*, sizeof...(Args)> t;
0217         for (size_t i = 0; i < t.size(); ++i) {
0218           t[i] = m_values[i];
0219         }
0220         return const_iterator{t};
0221       }
0222       const_iterator end() const {
0223         std::array<void const*, sizeof...(Args)> t;
0224         for (size_t i = 0; i < t.size(); ++i) {
0225           t[i] = m_values[i];
0226         }
0227         return const_iterator{t, size()};
0228       }
0229 
0230       iterator begin() { return iterator{m_values}; }
0231       iterator end() { return iterator{m_values, size()}; }
0232 
0233       template <typename U>
0234       void const* columnAddressWorkaround(U const*) const {
0235         return columnAddress<U>();
0236       }
0237 
0238       void const* columnAddressByIndex(unsigned int iIndex) const { return m_values[iIndex]; }
0239 
0240     private:
0241       // Member data
0242       unsigned int m_size = 0;
0243       std::array<void*, sizeof...(Args)> m_values = {{nullptr}};  //! keep ROOT from trying to store this
0244 
0245       template <typename U>
0246       void const* columnAddress() const {
0247         return m_values[impl::GetIndex<0, U, Layout>::index];
0248       }
0249 
0250       template <typename U>
0251       void* columnAddress() {
0252         return m_values[impl::GetIndex<0, U, Layout>::index];
0253       }
0254 
0255       //Recursive destructor handling
0256       template <int I>
0257       static void dtr(std::array<void*, sizeof...(Args)>& iArray) {
0258         if constexpr (I < sizeof...(Args)) {
0259           using Type = typename std::tuple_element<I, Layout>::type::type;
0260           delete[] static_cast<Type*>(iArray[I]);
0261           dtr<I + 1>(iArray);
0262         }
0263       }
0264 
0265       //Construct the Table using a container per column
0266       struct CtrFillerFromContainers {
0267         template <typename T, typename... U>
0268         static size_t fill(std::array<void*, sizeof...(Args)>& oValues, T const& iContainer, U... iArgs) {
0269           static_assert(sizeof...(Args) == sizeof...(U) + 1, "Wrong number of arguments passed to Table constructor");
0270           ctrFiller<0>(oValues, iContainer.size(), iContainer, std::forward<U>(iArgs)...);
0271           return iContainer.size();
0272         }
0273 
0274       private:
0275         template <int I, typename T, typename... U>
0276         static void ctrFiller(std::array<void*, sizeof...(Args)>& oValues, size_t iSize, T const& iContainer, U... iU) {
0277           assert(iContainer.size() == iSize);
0278           using Type = typename std::tuple_element<I, Layout>::type::type;
0279           Type* temp = new Type[iSize];
0280           unsigned int index = 0;
0281           for (auto const& v : iContainer) {
0282             temp[index] = v;
0283             ++index;
0284           }
0285           oValues[I] = temp;
0286 
0287           ctrFiller<I + 1>(oValues, iSize, std::forward<U>(iU)...);
0288         }
0289 
0290         template <int I>
0291         static void ctrFiller(std::array<void*, sizeof...(Args)>&, size_t) {}
0292       };
0293 
0294       //Construct the Table using one container with each entry representing a row
0295       struct CtrFillerFromAOS {
0296         template <typename T>
0297         static size_t fill(std::array<void*, sizeof...(Args)>& oValues, T const& iContainer) {
0298           presize<0>(oValues, iContainer.size());
0299           unsigned index = 0;
0300           for (auto&& item : iContainer) {
0301             fillElement<0>(item, index, oValues);
0302             ++index;
0303           }
0304           return iContainer.size();
0305         }
0306 
0307         template <typename T, typename F>
0308         static size_t fillUsingFiller(F& iFiller, std::array<void*, sizeof...(Args)>& oValues, T const& iContainer) {
0309           presize<0>(oValues, iContainer.size());
0310           unsigned index = 0;
0311           for (auto&& item : iContainer) {
0312             fillElementUsingFiller<0>(iFiller, item, index, oValues);
0313             ++index;
0314           }
0315           return iContainer.size();
0316         }
0317 
0318       private:
0319         template <int I>
0320         static void presize(std::array<void*, sizeof...(Args)>& oValues, size_t iSize) {
0321           if constexpr (I < sizeof...(Args)) {
0322             using Layout = std::tuple<Args...>;
0323             using Type = typename std::tuple_element<I, Layout>::type::type;
0324             oValues[I] = new Type[iSize];
0325             presize<I + 1>(oValues, iSize);
0326           }
0327         }
0328 
0329         template <int I, typename E>
0330         static void fillElement(E const& iItem, size_t iIndex, std::array<void*, sizeof...(Args)>& oValues) {
0331           if constexpr (I < sizeof...(Args)) {
0332             using Layout = std::tuple<Args...>;
0333             using ColumnType = typename std::tuple_element<I, Layout>::type;
0334             using Type = typename ColumnType::type;
0335             Type* pElement = static_cast<Type*>(oValues[I]) + iIndex;
0336             *pElement = value_for_column(iItem, static_cast<ColumnType*>(nullptr));
0337             fillElement<I + 1>(iItem, iIndex, oValues);
0338           }
0339         }
0340 
0341         template <int I, typename E, typename F>
0342         static void fillElementUsingFiller(F& iFiller,
0343                                            E const& iItem,
0344                                            size_t iIndex,
0345                                            std::array<void*, sizeof...(Args)>& oValues) {
0346           if constexpr (I < sizeof...(Args)) {
0347             using Layout = std::tuple<Args...>;
0348             using ColumnType = typename std::tuple_element<I, Layout>::type;
0349             using Type = typename ColumnType::type;
0350             Type* pElement = static_cast<Type*>(oValues[I]) + iIndex;
0351             *pElement = iFiller.value(iItem, static_cast<ColumnType*>(nullptr));
0352             fillElementUsingFiller<I + 1>(iFiller, iItem, iIndex, oValues);
0353           }
0354         }
0355       };
0356 
0357       template <size_t... I>
0358       static void copyFromToWithResizeAll(size_t iNElements,
0359                                           std::array<void*, sizeof...(Args)> const& iFrom,
0360                                           std::array<void*, sizeof...(Args)>& oTo,
0361                                           std::index_sequence<I...>) {
0362         (copyFromToWithResize<I>(iNElements, iFrom, oTo), ...);
0363       }
0364 
0365       template <int I>
0366       static void copyFromToWithResize(size_t iNElements,
0367                                        std::array<void*, sizeof...(Args)> const& iFrom,
0368                                        std::array<void*, sizeof...(Args)>& oTo) {
0369         using Layout = std::tuple<Args...>;
0370         using Type = typename std::tuple_element<I, Layout>::type::type;
0371         Type* oldPtr = static_cast<Type*>(oTo[I]);
0372         Type* ptr = new Type[iNElements];
0373         oTo[I] = ptr;
0374         std::copy(static_cast<Type const*>(iFrom[I]), static_cast<Type const*>(iFrom[I]) + iNElements, ptr);
0375         delete[] oldPtr;
0376       }
0377 
0378       template <int I>
0379       static void resizeFromTo(size_t iOldSize, size_t iNewSize, std::array<void*, sizeof...(Args)>& ioArray) {
0380         if constexpr (I < sizeof...(Args)) {
0381           using Layout = std::tuple<Args...>;
0382           using Type = typename std::tuple_element<I, Layout>::type::type;
0383           Type* oldPtr = static_cast<Type*>(ioArray[I]);
0384           auto ptr = new Type[iNewSize];
0385           auto nToCopy = std::min(iOldSize, iNewSize);
0386           std::copy(static_cast<Type const*>(ioArray[I]), static_cast<Type const*>(ioArray[I]) + nToCopy, ptr);
0387           resizeFromTo<I + 1>(iOldSize, iNewSize, ioArray);
0388 
0389           delete[] oldPtr;
0390           ioArray[I] = ptr;
0391         }
0392       }
0393 
0394       template <int I>
0395       static void resetStartingAt(size_t iStartIndex, size_t iEndIndex, std::array<void*, sizeof...(Args)>& ioArray) {
0396         if constexpr (I < sizeof...(Args)) {
0397           using Layout = std::tuple<Args...>;
0398           using Type = typename std::tuple_element<I, Layout>::type::type;
0399           auto ptr = static_cast<Type*>(ioArray[I]);
0400           auto temp = Type{};
0401           std::fill(ptr + iStartIndex, ptr + iEndIndex, temp);
0402           resetStartingAt<I + 1>(iStartIndex, iEndIndex, ioArray);
0403         }
0404       }
0405     };
0406 
0407     /* Table Type Manipulation */
0408     template <typename T1, typename T2>
0409     struct AddColumns;
0410     template <typename... T1, typename... T2>
0411     struct AddColumns<Table<T1...>, std::tuple<T2...>> {
0412       using type = Table<T1..., T2...>;
0413     };
0414 
0415     template <typename T1, typename T2>
0416     using AddColumns_t = typename AddColumns<T1, T2>::type;
0417 
0418     namespace impl {
0419       template <typename LHS, typename E, typename RHS>
0420       struct RemoveColumnCheck;
0421       template <typename LHS, typename E, typename T, typename... U>
0422       struct RemoveColumnCheck<LHS, E, std::tuple<T, U...>> {
0423         using type = typename std::conditional<
0424             std::is_same<E, T>::value,
0425             typename AddColumns<LHS, std::tuple<U...>>::type,
0426             typename RemoveColumnCheck<typename AddColumns<LHS, std::tuple<T>>::type, E, std::tuple<U...>>::type>::type;
0427       };
0428 
0429       template <typename LHS, typename E>
0430       struct RemoveColumnCheck<LHS, E, std::tuple<>> {
0431         using type = LHS;
0432       };
0433     }  // namespace impl
0434 
0435     template <typename TABLE, typename E>
0436     struct RemoveColumn {
0437       using type = typename impl::RemoveColumnCheck<Table<>, E, typename TABLE::Layout>::type;
0438     };
0439 
0440     template <typename TABLE, typename E>
0441     using RemoveColumn_t = typename RemoveColumn<TABLE, E>::type;
0442 
0443     //This is used by edm::Wrapper
0444     template <typename T>
0445     struct MakeTableExaminer;
0446 
0447     template <typename... Args>
0448     struct MakeTableExaminer<Table<Args...>> {
0449       static std::unique_ptr<TableExaminerBase> make(const Table<Args...>* iTable) {
0450         return std::make_unique<TableExaminer<Table<Args...>>>(iTable);
0451       }
0452     };
0453   }  // namespace soa
0454 }  // namespace edm
0455 #endif