/
githubmirror
/
cmssw
Обзор
Документация
Войти
/
githubmirror
/
cmssw
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
FWCore/SOA/interface/Table.h
455 строк
16 KB
W. David Dagenhart
Changes from scram build code-format-all
03 май 2019, 18:48
03 май 2019, 18:48
22c28dc
Код
Авторство
О чём код?
#ifndef FWCore_SOA_Table_h #define FWCore_SOA_Table_h // -*- C++ -*- // // Package: FWCore/SOA // Class : Table // /**\class Table Table.h "Table.h" Description: A Table which is a 'structure of arrays' Usage: A Table provides a 'structure of arrays' using a spreadsheet metaphor. The template arguments of a Table should be edm::soa::Column<> types which declare the type of the column and a label. \code constexpr char kEta[] = "eta"; using Eta = edm::soa::Column<double,kEta>; constexpr char kPhi[] = "phi"; using Phi = edm::soa::Column<double,kPhi>; using SphereTable = edm::soa::Table<Eta,Phi>; \endcode The same declaration of a column should be shared by different tables in order to allow the functions to be reused across tables. [See TableView] Accessing data within a Table is done by specifying the column and row to be used. The column is identified by the edm::soa::Column<> type and the row by an integer. \code SphereTable sphereTable{...}; ... auto eta1 = sphereTable.get<Eta>(1); \endcode One can iterate over all rows of a Table and get the values of interest \code SphereTable sphereTable{...}; ... for(auto const& row: sphereTable) { std::cout<<row.get<Eta>()<<std::endl; } \encode If only some of the columns are of interest, the optimizer of the compiler is very good at removing code associated with non-used columns and providing a highly optimized access to just the data of interest. On can also explicitly iterate over a single column of interest \code SphereTable sphereTable{...}; ... for(auto eta: sphereTable.column<Eta>()) { std::cout<<eta<<std::endl; } \encode Usually the optimizer on the compiler is able to make iteration over the entire row and iterating over just one column compile down to exactly the same machine instructions. A Table can be constructed either by 1) passing as many containers as their are columns \code std::array<double, 4> eta = {...}; std::array<double, 4> phi = {...}; SphereTable sphereTable{eta,phi}; \endcode 2) passing a single container of objects where the objects hold the value of interests and where appropriate 'value_for_column' functions are defined [See ColumnFillers.h] \code class Vector { ... double eta() const; double phi() const; ... }; double value_for_column(Vector const& iV, Eta*) { return iV.eta(); } double value_for_column(Vector const& iV, Phi*) { return iV.phi(); } ... std::vector<Vector> vectors{...}; ... SphereTable sphereTable{ vectors }; \endcode Functions which operate over Tables should not take Tables are arguments. Instead, they should take an edm::soa::TableView<>. This will allow the function to operate on any Table that uses the edm::soa::Column<> type needed by the function. \code SphereTable sphericalAngles(edm::soa::TableView<X,Y,Z>); \endcode New Table declarations can be created based on existing Table declarations. E.g. say you want a new Table based on an existing Table but with an additional column. \code using ATable = edm::soa::Table<...>; using MyLabel = edm::soa::Column<...>; using MyATable = AddColumns_t<ATable, MyLabel>; \endcode It is also possible to declare a new Table by removing columns from an existing declaration \code using MyBTable = RemoveColumn_t<BTable, Phi>; //Phi is a previously defined Column \endcode */ // // Original Author: Chris Jones // Created: Thu, 24 Aug 2017 16:18:05 GMT // // system include files #include <memory> #include <tuple> #include <array> // user include files #include "FWCore/SOA/interface/TableItr.h" #include "FWCore/SOA/interface/tablehelpers.h" #include "FWCore/SOA/interface/ColumnFillers.h" #include "FWCore/SOA/interface/ColumnValues.h" #include "FWCore/SOA/interface/RowView.h" //The following is needed for edm::Wrapper #include "FWCore/SOA/interface/TableExaminer.h" // forward declarations namespace edm { namespace soa { template <typename... Args> class Table { public: static constexpr const unsigned int kNColumns = sizeof...(Args); using Layout = std::tuple<Args...>; using const_iterator = ConstTableItr<Args...>; using iterator = TableItr<Args...>; template <typename T, typename... CArgs> Table(T const& iContainer, CArgs... iArgs) : m_size(iContainer.size()) { if constexpr (sizeof...(CArgs) == 0) { CtrFillerFromAOS::fill(m_values, iContainer); } else { CtrFillerFromContainers::fill(m_values, iContainer, std::forward<CArgs>(iArgs)...); } } template <typename T, typename... CArgs> Table(T const& iContainer, ColumnFillers<CArgs...> iFiller) { m_size = iContainer.size(); CtrFillerFromAOS::fillUsingFiller(iFiller, m_values, iContainer); } Table(Table<Args...> const& iOther) : m_size(iOther.m_size), m_values{{nullptr}} { copyFromToWithResizeAll(m_size, iOther.m_values, m_values, std::make_index_sequence<sizeof...(Args)>{}); } Table(Table<Args...>&& iOther) : m_size(0), m_values{{nullptr}} { std::swap(m_size, iOther.m_size); std::swap(m_values, iOther.m_values); } Table() : m_size(0) {} ~Table() { dtr<0>(m_values); } Table<Args...>& operator=(Table<Args...>&& iOther) { Table<Args...> cp(std::move(iOther)); std::swap(m_size, cp.m_size); std::swap(m_values, cp.m_values); return *this; } Table<Args...>& operator=(Table<Args...> const& iOther) { return operator=(Table<Args...>(iOther)); } unsigned int size() const { return m_size; } void resize(unsigned int iNewSize) { if (m_size == iNewSize) { return; } resizeFromTo<0>(m_size, iNewSize, m_values); if (m_size < iNewSize) { //initialize the extra values resetStartingAt<0>(m_size, iNewSize, m_values); } m_size = iNewSize; } template <typename U> typename U::type const& get(size_t iRow) const { return *(static_cast<typename U::type const*>(columnAddress<U>()) + iRow); } template <typename U> typename U::type& get(size_t iRow) { return *(static_cast<typename U::type*>(columnAddress<U>()) + iRow); } template <typename U> ColumnValues<typename U::type> column() const { return ColumnValues<typename U::type>{static_cast<typename U::type*>(columnAddress<U>()), m_size}; } template <typename U> MutableColumnValues<typename U::type> column() { return MutableColumnValues<typename U::type>{static_cast<typename U::type*>(columnAddress<U>()), m_size}; } RowView<Args...> row(size_t iRow) const { return *(begin() + iRow); } MutableRowView<Args...> row(size_t iRow) { return *(begin() + iRow); } const_iterator begin() const { std::array<void const*, sizeof...(Args)> t; for (size_t i = 0; i < t.size(); ++i) { t[i] = m_values[i]; } return const_iterator{t}; } const_iterator end() const { std::array<void const*, sizeof...(Args)> t; for (size_t i = 0; i < t.size(); ++i) { t[i] = m_values[i]; } return const_iterator{t, size()}; } iterator begin() { return iterator{m_values}; } iterator end() { return iterator{m_values, size()}; } template <typename U> void const* columnAddressWorkaround(U const*) const { return columnAddress<U>(); } void const* columnAddressByIndex(unsigned int iIndex) const { return m_values[iIndex]; } private: // Member data unsigned int m_size = 0; std::array<void*, sizeof...(Args)> m_values = {{nullptr}}; //! keep ROOT from trying to store this template <typename U> void const* columnAddress() const { return m_values[impl::GetIndex<0, U, Layout>::index]; } template <typename U> void* columnAddress() { return m_values[impl::GetIndex<0, U, Layout>::index]; } //Recursive destructor handling template <int I> static void dtr(std::array<void*, sizeof...(Args)>& iArray) { if constexpr (I < sizeof...(Args)) { using Type = typename std::tuple_element<I, Layout>::type::type; delete[] static_cast<Type*>(iArray[I]); dtr<I + 1>(iArray); } } //Construct the Table using a container per column struct CtrFillerFromContainers { template <typename T, typename... U> static size_t fill(std::array<void*, sizeof...(Args)>& oValues, T const& iContainer, U... iArgs) { static_assert(sizeof...(Args) == sizeof...(U) + 1, "Wrong number of arguments passed to Table constructor"); ctrFiller<0>(oValues, iContainer.size(), iContainer, std::forward<U>(iArgs)...); return iContainer.size(); } private: template <int I, typename T, typename... U> static void ctrFiller(std::array<void*, sizeof...(Args)>& oValues, size_t iSize, T const& iContainer, U... iU) { assert(iContainer.size() == iSize); using Type = typename std::tuple_element<I, Layout>::type::type; Type* temp = new Type[iSize]; unsigned int index = 0; for (auto const& v : iContainer) { temp[index] = v; ++index; } oValues[I] = temp; ctrFiller<I + 1>(oValues, iSize, std::forward<U>(iU)...); } template <int I> static void ctrFiller(std::array<void*, sizeof...(Args)>&, size_t) {} }; //Construct the Table using one container with each entry representing a row struct CtrFillerFromAOS { template <typename T> static size_t fill(std::array<void*, sizeof...(Args)>& oValues, T const& iContainer) { presize<0>(oValues, iContainer.size()); unsigned index = 0; for (auto&& item : iContainer) { fillElement<0>(item, index, oValues); ++index; } return iContainer.size(); } template <typename T, typename F> static size_t fillUsingFiller(F& iFiller, std::array<void*, sizeof...(Args)>& oValues, T const& iContainer) { presize<0>(oValues, iContainer.size()); unsigned index = 0; for (auto&& item : iContainer) { fillElementUsingFiller<0>(iFiller, item, index, oValues); ++index; } return iContainer.size(); } private: template <int I> static void presize(std::array<void*, sizeof...(Args)>& oValues, size_t iSize) { if constexpr (I < sizeof...(Args)) { using Layout = std::tuple<Args...>; using Type = typename std::tuple_element<I, Layout>::type::type; oValues[I] = new Type[iSize]; presize<I + 1>(oValues, iSize); } } template <int I, typename E> static void fillElement(E const& iItem, size_t iIndex, std::array<void*, sizeof...(Args)>& oValues) { if constexpr (I < sizeof...(Args)) { using Layout = std::tuple<Args...>; using ColumnType = typename std::tuple_element<I, Layout>::type; using Type = typename ColumnType::type; Type* pElement = static_cast<Type*>(oValues[I]) + iIndex; *pElement = value_for_column(iItem, static_cast<ColumnType*>(nullptr)); fillElement<I + 1>(iItem, iIndex, oValues); } } template <int I, typename E, typename F> static void fillElementUsingFiller(F& iFiller, E const& iItem, size_t iIndex, std::array<void*, sizeof...(Args)>& oValues) { if constexpr (I < sizeof...(Args)) { using Layout = std::tuple<Args...>; using ColumnType = typename std::tuple_element<I, Layout>::type; using Type = typename ColumnType::type; Type* pElement = static_cast<Type*>(oValues[I]) + iIndex; *pElement = iFiller.value(iItem, static_cast<ColumnType*>(nullptr)); fillElementUsingFiller<I + 1>(iFiller, iItem, iIndex, oValues); } } }; template <size_t... I> static void copyFromToWithResizeAll(size_t iNElements, std::array<void*, sizeof...(Args)> const& iFrom, std::array<void*, sizeof...(Args)>& oTo, std::index_sequence<I...>) { (copyFromToWithResize<I>(iNElements, iFrom, oTo), ...); } template <int I> static void copyFromToWithResize(size_t iNElements, std::array<void*, sizeof...(Args)> const& iFrom, std::array<void*, sizeof...(Args)>& oTo) { using Layout = std::tuple<Args...>; using Type = typename std::tuple_element<I, Layout>::type::type; Type* oldPtr = static_cast<Type*>(oTo[I]); Type* ptr = new Type[iNElements]; oTo[I] = ptr; std::copy(static_cast<Type const*>(iFrom[I]), static_cast<Type const*>(iFrom[I]) + iNElements, ptr); delete[] oldPtr; } template <int I> static void resizeFromTo(size_t iOldSize, size_t iNewSize, std::array<void*, sizeof...(Args)>& ioArray) { if constexpr (I < sizeof...(Args)) { using Layout = std::tuple<Args...>; using Type = typename std::tuple_element<I, Layout>::type::type; Type* oldPtr = static_cast<Type*>(ioArray[I]); auto ptr = new Type[iNewSize]; auto nToCopy = std::min(iOldSize, iNewSize); std::copy(static_cast<Type const*>(ioArray[I]), static_cast<Type const*>(ioArray[I]) + nToCopy, ptr); resizeFromTo<I + 1>(iOldSize, iNewSize, ioArray); delete[] oldPtr; ioArray[I] = ptr; } } template <int I> static void resetStartingAt(size_t iStartIndex, size_t iEndIndex, std::array<void*, sizeof...(Args)>& ioArray) { if constexpr (I < sizeof...(Args)) { using Layout = std::tuple<Args...>; using Type = typename std::tuple_element<I, Layout>::type::type; auto ptr = static_cast<Type*>(ioArray[I]); auto temp = Type{}; std::fill(ptr + iStartIndex, ptr + iEndIndex, temp); resetStartingAt<I + 1>(iStartIndex, iEndIndex, ioArray); } } }; /* Table Type Manipulation */ template <typename T1, typename T2> struct AddColumns; template <typename... T1, typename... T2> struct AddColumns<Table<T1...>, std::tuple<T2...>> { using type = Table<T1..., T2...>; }; template <typename T1, typename T2> using AddColumns_t = typename AddColumns<T1, T2>::type; namespace impl { template <typename LHS, typename E, typename RHS> struct RemoveColumnCheck; template <typename LHS, typename E, typename T, typename... U> struct RemoveColumnCheck<LHS, E, std::tuple<T, U...>> { using type = typename std::conditional< std::is_same<E, T>::value, typename AddColumns<LHS, std::tuple<U...>>::type, typename RemoveColumnCheck<typename AddColumns<LHS, std::tuple<T>>::type, E, std::tuple<U...>>::type>::type; }; template <typename LHS, typename E> struct RemoveColumnCheck<LHS, E, std::tuple<>> { using type = LHS; }; } // namespace impl template <typename TABLE, typename E> struct RemoveColumn { using type = typename impl::RemoveColumnCheck<Table<>, E, typename TABLE::Layout>::type; }; template <typename TABLE, typename E> using RemoveColumn_t = typename RemoveColumn<TABLE, E>::type; //This is used by edm::Wrapper template <typename T> struct MakeTableExaminer; template <typename... Args> struct MakeTableExaminer<Table<Args...>> { static std::unique_ptr<TableExaminerBase> make(const Table<Args...>* iTable) { return std::make_unique<TableExaminer<Table<Args...>>>(iTable); } }; } // namespace soa } // namespace edm #endif