Classes | Namespaces | Typedefs | Functions
CollectionView.h File Reference

Provides the features of a collections, from begin and end iterators. More...

#include <stdexcept>
#include <iterator>
#include <string>
#include <type_traits>
#include <cstddef>

Go to the source code of this file.

Classes

class  lar::CollectionView< Range >
 Provides features of a collections, from begin and end iterators. More...
 
struct  lar::details::RangeTraits< Range >
 
class  lar::details::CollectionExtremes< BeginIter, EndIter >
 Class storing a begin and a end iterator. More...
 
struct  lar::details::CollectionExtremes< BeginIter, EndIter >::FromContainerTag
 
class  lar::CollectionView< Range >
 Provides features of a collections, from begin and end iterators. More...
 

Namespaces

 lar
 LArSoft-specific namespace.
 
 lar::details
 Namespace hiding implementation details.
 

Typedefs

template<typename BeginIter , typename EndIter = BeginIter>
using lar::RangeAsCollection_t = decltype(makeCollectionView(std::declval< BeginIter >(), std::declval< EndIter >()))
 Type of collection view owning the two range boundary iterators. More...
 

Functions

template<typename BeginIter , typename EndIter >
auto lar::details::makeCollectionExtremes (BeginIter const &b, EndIter const &e)
 Helper to create a CollectionExtremes object from two iterators. More...
 
template<typename Range >
auto lar::details::makeCollectionExtremes (Range const &range)
 Helper to create a CollectionExtremes object from a range object. More...
 
template<typename Range >
CollectionView< Rangelar::details::makeCollectionView (Range &&)
 
template<typename Range >
CollectionView< Range > const & lar::wrapCollectionIntoView (Range const &c)
 Returns the specified container, wrapped in the view. More...
 
template<typename BeginIter , typename EndIter >
auto lar::makeCollectionView (BeginIter const &b, EndIter const &e)
 Creates a CollectionView from the specified iterators. More...
 

Detailed Description

Provides the features of a collections, from begin and end iterators.

Author
Gianluca Petrillo (petri.nosp@m.llo@.nosp@m.fnal..nosp@m.gov)
Date
August 3rd, 2017

This library is header-only.

Note
It is likely that a skilful use of Nibbler's range library will provide the same functionality (and loads more).

Interface substitution technique

A technique that is used in this implementation is to replace (or extend) the interface of an existing object. A key requirement is that the new interface object must not have any additional state.

The interface class is superimposed to the existing data without replication by reinterpreting its content. This is achieved deriving the new interface class from the data class:

class Data {
double chiSq;
double NDF;
public:
Data(double chiSq, double NDF): chiSq(chiSq), NDF(NDF) {}
double chiSquare() const { return chiSq; }
double DegreesOfFreedom() const { return NDF; }
}; // class Data
class DataInterface: private Data {
Data const& asData() const { return static_cast<Data const&>(*this); }
public:
double normalizedChiSquare() const
{ return asData().chiSquare() / asData().DegreesOfFreedom(); }
protected:
DataInterface(Data const& from): Data(data) {}
friend DataInterface const& makeDataInterface(Data const&);
}; // class DataInterface
DataInterface const& makeDataInterface(Data const& data)
{ return static_const<DataInterface const&>(data); }

With this pattern, an interface object can be obtained only by calling makeDataInterface() on the base object, and in this way it will be returned only as a reference (in this case, constant). The interface object can't be copied, and it must be passed around as reference. It's not possible to convert it back to Data, because the base class is private. There is a single protected constructor. This choice, compared to deleting all constructors, allows for a derived class to acquire the same interface:

struct DataWithInterface: public DataInterface {
DataWithInterface(Data const& from): DataInterface(from) {}
}; // class DataWithInterface

This simple class provides the storage for Data in addition to exposing DataInterface. There are other ways to achieve the same goal (e.g., multiple inheritance).

The presence of a friend function should raise a warning. Friendship is required because the function is attempting a downcast from a private base class. If it is intended that the full Data interface is exposed, then the inheritance can be public and no special friendship will be needed. Another way is to replace the static_cast with a reinterpret_cast.

Definition in file CollectionView.h.