Quick Interface Overview

 Now that we have a general overview of the offices, we can start to look at how we build them.  But first we need to look at the interfaces which drive the principal substantive constructors.

IHoursInfo

Let's start with IHoursInfo.  In principle, it gathers together the values applying to the entire day:

class IHoursInfo

{

public:

  virtual ~IHoursInfo();

  virtual std::string getHymn(const Days inDay,

      const OfficeNames inOffice) const = 0;

  virtual std::string getCollect() const = 0;

  virtual Grades grade() const = 0;

  virtual bool followRomanUse() const = 0;

  virtual std::unique_ptr<FerialPetitions>

  generateFerialPetitions(const OfficeNames inOffice) const = 0;

  virtual HymnSeasons getSeason() const = 0;

};

Most of these derive from the nature of the day in question, the exception being followRomanUse() which passes on a user preference which will be applied to the entire session. All of them affect all or most of the hours ("most" for Prime and Compline, which don't care about the collect of the day).

In many cases this will be data parsed in from the XML configuration.  But there are some more limited implementations.

The most basic is FerialOfficeInfo and its descendants.  This is meant to provide overall data for a day which will be extended by a collect read in from the XML configuration for the week. FerialOfficeInfo is an abstract class, managing the data common to the differing days of the week and providing template methods which will be specialized for each day in its children.

class FerialHoursInfo : public IHoursInfo

{

public:

  FerialHoursInfo(const HymnSeasons inSeason, const Grades inGrade,

                  const bool inRomanUse):

      m_season(inSeason),

      m_grade(inGrade), m_romanUse(inRomanUse)

  { }

  ~FerialHoursInfo() override;

  std::string getCollect() const override { return {}; }

  Grades grade() const override { return m_grade; }

  bool followRomanUse() const override { return m_romanUse; }

  HymnSeasons getSeason() const override { return m_season; }

  std::unique_ptr<FerialPetitions>

  generateFerialPetitions(const OfficeNames inOffice) const override;


  std::string getHymn(const Days inDay,

                      const OfficeNames inOffice) const override;

protected:

  virtual Days getDay() const = 0;

  virtual std::string getPreLentenVespersHymn() const = 0;

  virtual std::string getPostLentenVespersHymn() const = 0;

  virtual std::string getPreLentenLaudsHymn() const = 0;

  virtual std::string getPostLentenLaudsHymn() const = 0;

private:

  HymnSeasons m_season;

  Grades m_grade;

  bool m_romanUse;

};

The main piece of real logic in the class is getHymn (really just for getting the hymn name):

std::string

FerialHoursInfo::getHymn([[maybe_unused]] const Days inDay, const OfficeNames inOffice) const

{

  switch (inOffice)

    {

      using enum OfficeNames;

    case COMPLINE:

      return ComplineChapter::GetHymnName(grade(), getSeason(),

                                          followRomanUse());

    case TERCE:

      return Terce::GetHymnName(getSeason());

    case PRIME:

      return "Iam lucis ordo sidere";

    case SEXT:

      return "Rector potens, verax Deus";

    case NONE:

      return "Rerum Deus tenax vigor";

    case VESPERS:

      switch (getSeason())

        {

          using enum HymnSeasons;

        case SEPTUAGESIMA:

  return getPreLentenVespersHymn();

          break;

        case NORMAL:

  return getPostLentenVespersHymn();

          break;

        case ADVENT:

          return "Conditor alme siderum";

        case INCARNATION:

          return "Veni, Redemptor gentium";

        case LENT:

          return "Ex more docti mystico";

        case MID_LENT:

          return "Ecce tempus idoneum";

        case PASSIONTIDE:

          return "Vexilla Regis prodeunt";

        case EASTER:

          return "Ad coenam agni providi";

        case ASCENSION:

          return "Aeternae Rex altissime";

        case PENTECOST:

          return "Beata nobis gaudia";

        }

      break;

    case LAUDS:

      switch (getSeason())

        {

          using enum HymnSeasons;

        case SEPTUAGESIMA:

    return getPreLentenLaudsHymn();

  break;

        case NORMAL:

    return getPostLentenLaudsHymn();

          break;

        case ADVENT:

          return "Vox clara ecce intonat";

        case INCARNATION:

          return "A solis ortus cardine";

        case LENT:

          return "Audi benigne Conditor";

        case MID_LENT:

          return "Iesu, quadragesinarie";

        case PASSIONTIDE:

          return "Lustra sex qui iam peracta";

        case EASTER:

          return "Sermone blando angelus";

        case ASCENSION:

          return "Te, Christe, nostrum gaudium";

        case PENTECOST:

          return "Impleta gaudent viscera";

        }

    }

  return {};

}

(Note that in this case the inDay parameter is not used: that does get used in other implementations, but this implementation effectively defers that to the concrete implementations.)

Here's a concrete implementation, for Monday:

class MondayHoursInfo : public FerialHoursInfo

{

public:

  MondayHoursInfo(const HymnSeasons inSeason, const Grades inGrade,

                  const bool inRomanUse):

      FerialHoursInfo(inSeason, inGrade, inRomanUse)

  { }

  ~MondayHoursInfo() override;


private:

  Days getDay() const override { return Days::MONDAY; }


  std::string getPreLentenVespersHymn() const override

  {

    return "Immense caeli Conditor";

  }

  std::string getPostLentenVespersHymn() const override

  {

    if (!followRomanUse())

      {

        return "Lucis creator optime";

      }

    else

      {

        return "Immense caeli Conditor";

      }

  }

  std::string getPreLentenLaudsHymn() const override

  {

    return "Splendor Paternae gloriae";

  }

  std::string getPostLentenLaudsHymn() const override

  {

    if (!followRomanUse())

      {

        return "Ecce iam noctis";

      }

    else

      {

        return "Splendor Paternae gloriae";

      }

  }

};

The other implementations are similar. (FerialOfficeInfo is a bit of a misnomer; there is in fact a SundayOfficeInfo derived from it, so there is one child for each day of the week,)

Saint Mary On Saturday

On any Saturday of the year which does not have a proper mass (which excludes everything in Lent) there is a Marian mass and office which is said (in the Roman Use) in preference to the default Saturday ordo (except for Second Vespers, which always reflects the Sunday).  There is a specialized hardcoded class representing the data for this set of propers:

class SaintMaryOnSaturdayHoursInfo : public IHoursInfo

{

public:

  explicit SaintMaryOnSaturdayHoursInfo(const MarianSeasons inSeason):

      m_marianSeason(inSeason)

  { }

  ~SaintMaryOnSaturdayHoursInfo() override {}

  std::string getHymn(const Days inDay, OfficeNames inOffice) const override;

  std::string getCollect() const override;

  Grades grade() const override { return Grades::DOMINICA; }

  bool followRomanUse() const override { return true; }

  std::unique_ptr<FerialPetitions>

  generateFerialPetitions(const OfficeNames inOffice) const override;

  HymnSeasons getSeason() const override

  {

    if (m_marianSeason == MarianSeasons::EASTERTIDE)

      return HymnSeasons::EASTER;

    return HymnSeasons::NORMAL;

  }

private:

  MarianSeasons m_marianSeason;

};

(The Marian year has four seasons, corresponding to the four Marian Anthemsm, and there is  aspcial enum to represent them:

enum class MarianSeasons {

  INCARNATION,

  POST_CANDLEMAS,

  EASTERTIDE,

  TRINITY

};

)

The implementations essentially just wrap hardcoded special-case data:

std::string SaintMaryOnSaturdayHoursInfo::getHymn(const Days inDay,

                                                  OfficeNames inOffice) const

{

  switch (m_marianSeason)

    {

      using enum MarianSeasons;

    case INCARNATION:

      return "Enixa est puerpera";

      break;

    case POST_CANDLEMAS:

      [[fallthrough]];

    case EASTERTIDE:

      [[fallthrough]];

    case TRINITY:

      {

        if (inOffice == OfficeNames::VESPERS)

          return "Ave maris stella";

        else if (inOffice == OfficeNames::LAUDS)

          return "O gloriosa femina";

      }

      break;

    }

  return "";

}

std::string SaintMaryOnSaturdayHoursInfo::getCollect() const

{

  switch (m_marianSeason)

    {

      using enum MarianSeasons;

    case INCARNATION:

      return "O GOD, who by the child-bearing of a pure Virgin hast bestowed upon all mankind the rewards of everlasting life : grant, we beseech thee; that we may know the succour of her intercession, through whom we have been found worthy to receive the Author of life, even Jesus Christ thy Son our Lord.";

      break;

    case POST_CANDLEMAS:

      [[fallthrough]];

    case EASTERTIDE:

      return "O Lord God Almighty, we beseech you to keep us you servants both outwardly in our bodies and inwardly in our souls: that by the glorious intercession of blessed Mary Ever-Virgin, we may be delivered from our present heaviness and attain in the end to everlasting gladness. Through Christ our Lord.";

      break;

    case TRINITY:

      [[fallthrough]];

    default:

      return "Grant, we beseech Thee, O Lord God, unto us Thy servants, that we may rejoice in continual health of mind and body; and by the glorious intercession of blessed Mary, ever Virgin, may be delivered from present sadness and enter into the joy of Thine eternal gladness, through Christ Our Lord.";

      break;

    }

}

Delegated forms

As noted above, there are cases where almost complete data has to be either completed or overridden by certain very specific values.  One of these cases is offices which are complete except for the collect of the week (the various Ferial versions canvassed above).  To handle that we have a letter/envelope class using a delegate:

class DelegatedHoursInfoWithCollect : public IHoursInfo

{

public:

  DelegatedHoursInfoWithCollect(const IHoursInfo &inDelegate,

                                const std::string &inCollect):

      m_delegate(inDelegate),

      m_collect(inCollect)

  { }

  ~DelegatedHoursInfoWithCollect() override;

  std::string getHymn(const Days inDay,

                      const OfficeNames inOffice) const override

  {

    return m_delegate.getHymn(inDay, inOffice);

  }

  std::string getCollect() const override { return m_collect; }

  Grades grade() const override { return m_delegate.grade(); }

  bool followRomanUse() const override { return m_delegate.followRomanUse(); }

  std::unique_ptr<FerialPetitions>

  generateFerialPetitions(const OfficeNames inOffice) const override

  {

    return m_delegate.generateFerialPetitions(inOffice);

  }

  HymnSeasons getSeason() const override { return m_delegate.getSeason(); }

private:

  const IHoursInfo &m_delegate;

  std::string m_collect;

};

Likewise, there are some cases where a day's grade has to be adjusted (mainly for handling octaves of feats).  So we also have:

class DelegatedHoursInfoWithGrade : public IHoursInfo

{

public:

  DelegatedHoursInfoWithGrade(const IHoursInfo &inDelegate,

                              const Grades inGrade):

      m_delegate(inDelegate),

      m_grade(inGrade)

  { }

  ~DelegatedHoursInfoWithGrade() override;

  std::string getHymn(const Days inDay,

                      const OfficeNames inOffice) const override

  {

    return m_delegate.getHymn(inDay, inOffice);

  }

  std::string getCollect() const override { return m_delegate.getCollect(); }

  Grades grade() const override { return m_grade; }

  bool followRomanUse() const override { return m_delegate.followRomanUse(); }

  std::unique_ptr<FerialPetitions>

  generateFerialPetitions(const OfficeNames inOffice) const override

  {

    return m_delegate.generateFerialPetitions(inOffice);

  }

  HymnSeasons getSeason() const override { return m_delegate.getSeason(); }

private:

  const IHoursInfo &m_delegate;

  Grades m_grade;

};

All the other implementations extend the wider class IFullDayInfo.

IFullDayInfo includes not only the overall day information, but a different interface handling the infividual hours, IOfficeInfoSource.  We'll leave that for the moment -- it generates other interfaces

class IOfficeInfoSource

{

public:

  virtual ~IOfficeInfoSource();

  virtual const IPartialOfficeInfo &getPartialInfo() const = 0;

  virtual const IOfficeInfoHolder &getStandardInfo() const = 0;

  virtual bool isPartial() const = 0;

  virtual bool hasFirstVespers() const = 0;

};

which are used in building the individual hours.  An instance of IOfficeInfoSource will be either partial or complete, and based on which one it is, it gets queried for an object holding the relevant information.

For partial information:

class IPartialOfficeInfo

{

public:


  using HourInfo = PartialOfficeHourInfo;


  virtual ~IPartialOfficeInfo();

  virtual const std::string &getBase() const = 0;

  virtual const std::string &getName() const = 0;

  virtual const std::string &getCollect() const = 0;

  virtual Grades getGrade() const = 0;

  virtual const HourInfo &getHourInfo(const OfficeNames inName, const bool inIsFirstVespers = false) const = 0;

  virtual std::pair<std::string, std::string> getMajorHourAntiphons() const = 0;

  virtual bool isEmpty(const OfficeNames inName, const bool inIsFirstVespers = false) const = 0;

  virtual void overrideGrade(const Grades inGrade) = 0;

};

For full information:

class IOfficeInfoHolder

{

public:

  struct PrimeInfo

  {

    std::string antiphon;

    bool isMarian = false;

  };

  virtual ~IOfficeInfoHolder();

  virtual const ILaudsInfo &getLaudsInfo() const = 0;

  virtual const PrimeInfo &getPrimeInfo() const = 0;

  virtual const ITerceInfo &getTerceInfo() const = 0;

  virtual const IMinorHoursVariableData & getTerceVariableData() const = 0;

  virtual const ISextInfo &getSextInfo() const = 0;

  virtual const IMinorHoursVariableData & getSextVariableData() const = 0;

  virtual const INoneInfo &getNoneInfo() const = 0;

  virtual const IMinorHoursVariableData & getNoneVariableData() const = 0;

  virtual const IVespersInfo &getFirstVespersInfo() const = 0;

  virtual const IVespersInfo &getSecondVespersInfo() const = 0;

  virtual Grades getGrade() const = 0;

  virtual void overrideGrade(const Grades inGrade) { }

  virtual Days getDay() const = 0;

  virtual const std::string &getName() const = 0;

  virtual void setLaudsInfo(std::unique_ptr<ILaudsInfo> &&inInfo) = 0;

  virtual void setTerceInfo(std::unique_ptr<ITerceInfo> &&inInfo) = 0;

  virtual void setSextInfo(std::unique_ptr<ISextInfo> &&inInfo) = 0;

  virtual void setNoneInfo(std::unique_ptr<INoneInfo> &&inInfo) = 0;

  virtual void setFirstVespersInfo(std::unique_ptr<IVespersInfo> &&inInfo) = 0;

  virtual void setSecondVespersInfo(std::unique_ptr<IVespersInfo> &&inInfo)

      = 0;

};

All of the abstractions above will be expanded on when we look at the parsing which accumulates the relevant data.

IFullDayInfo also has some extra functions needed in the context of the final bits of assembly of the offices:

class IFullDayInfo : public IHoursInfo, public IOfficeInfoSource

{

public:

  virtual ~IFullDayInfo();

  virtual bool hasPartialParent() const = 0;

  virtual void overrideGrade(const Grades inGrade) = 0;

  virtual const std::string& getParent() const = 0;

  virtual bool isEmpty() const = 0;

};

Most of these have meaning only within the context of the XML parsing, which will be our next topic. (The primary implementation of IFullDayInfo is the DayElement which is at the top of the XML parse tree.)

Comments

Popular posts from this blog

Boundaries

State Machines

Considerations on an Optimization