// bdlt_calendar.h -*-C++-*- #ifndef INCLUDED_BDLT_CALENDAR #define INCLUDED_BDLT_CALENDAR #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide fast repository for accessing weekend/holiday information. // //@CLASSES: // bdlt::Calendar: fast repository for accessing weekend/holiday information // //@SEE_ALSO: bdlt_packedcalendar // //@DESCRIPTION: This component provides a value-semantic class, // 'bdlt::Calendar', that represents weekend and holiday information over a // *valid* *range* of dates. A 'bdlt::Calendar' is an approximation to the // same *mathematical* type, and is capable of representing the same subset of // *mathematical* values, as a 'bdlt::PackedCalendar'. A 'bdlt::Calendar' // object (representing the same *mathematical* value) can be constructed // directly from a reference to a non-modifiable 'bdlt::PackedCalendar' object, // and a reference to a non-modifiable 'bdlt::PackedCalendar' is readily // accessible from any 'bdlt::Calendar' object. // // But unlike 'bdlt::PackedCalendar', which is optimized for spatial // efficiency, 'bdlt::Calendar' is designed to be especially efficient at // determining whether a given 'bdlt::Date' value (within the valid range for a // particular 'bdlt::Calendar' object) is a business day -- i.e., not a weekend // day or holiday (see "Usage" below). For example, the cost of determining // whether a given 'bdlt::Date' is a business day, as opposed to a weekend or // holiday, consists of only a few constant-time operations, compared to a // binary search in a 'bdlt::PackedCalendar' representing the same calendar // value. // // Default-constructed calendars are empty, and have an empty valid range. // Calendars can also be constructed with an initial (non-empty) valid range, // implying that all dates within that range are business days. The // 'setValidRange' and 'addDay' methods modify the valid range of a calendar, // and a suite of "add" methods can be used to populate a calendar with // weekend days and holidays. // // The 'addHolidayCode' method associates an integer "holiday code" with a // specific date, and can be called repeatedly with different integers and the // same date to build up a set of holiday codes for that date. Note that // holiday codes are unique integers that, from the perspective of the // calendar, have no particular meaning. Typically, the user will choose // holiday code values that are indices into an auxiliary collection (such as a // 'bsl::vector<bsl::string>') to identify holiday names for end-user display. // // Once a calendar is populated, a rich set of accessor methods can be used to // determine, e.g., if a given date is a business day, or the number of // non-business days within some subrange of the calendar. The holidays // within a calendar can be obtained in increasing (chronological) order using // an iterator identified by the nested 'HolidayConstIterator' 'typedef'. The // set of holiday codes associated with an arbitrary date in a // 'bdlt::Calendar' (or the current holiday referred to by a // 'HolidayConstIterator') can be obtained in increasing (numerical) order // using an iterator identified by the nested 'HolidayCodeConstIterator' // 'typedef' (see below). // // Calendars are value-semantic objects, and, as such, necessarily support all // of the standard value-semantic operations, such as default construction, // copy construction and copy assignment, equality comparison, and // externalization (BDEX streaming, in particular). Calendars also support // the notions of both union and intersection merging operations, whereby a // calendar can change its value to contain the union or intersection of its // own contained weekend days, holidays, and holiday codes with those of // another calendar object. Such merging operations will, in general, also // alter the valid range of the resulting calendar. Note that merged // calendars can be significantly more efficient for certain repeated // "is-common-business-day" determinations among two or more calendars. // ///Weekend Days and Weekend-Days Transitions ///----------------------------------------- // A calendar maintains a set of dates considered to be weekend days. // Typically, a calendar's weekend days fall on the same days of the week for // the entire range of a calendar. For example, the weekend for United States // has consisted of Saturday and Sunday since the year 1940. The // 'addWeekendDay' and 'addWeekendDays' methods can be used to specify the // weekend days for these calendars. // // However, sometimes a calendar's weekend days changes over time. For // example, Bangladesh's weekend consisted of Friday until June 1, 1997 when // Bangladesh changed its weekends to contain both Friday and Saturday. Later, // on October 1, 2001, Bangladesh reverted to a weekend of only Friday, until // on September 9, 2009, Bangladesh again changed its weekends to include both // Friday and Saturday. // // To optimize for space allocation while supporting both consistent and // changing weekend days, a calendar represents weekend information using a // sequence of "weekend-days transitions", each of which comprises a date and a // set of days of the week considered to be the weekend on and after that // date. To represent the weekend days of Bangladesh, a calendar can use a // sequence of four weekend-days transitions: (1) a transition on January 1, // 0001 having a weekend day set containing only Friday, (2) a transition at // June 1, 1997 having a weekend day set containing Friday and Saturday, (3) a // transition at October 1, 2001 having a weekend day set containing only // Friday, and (4) a transition at September 9, 2009 having a weekend day set // containing Friday and Saturday. To represent the weekend days of the United // States, a calendar having a range after 1940 can use a single weekend-days // transition on January 1, 0001 containing Saturday and Sunday. // // On construction, a calendar does not contain any weekend-days transitions. // The 'addWeekendDaysTransition' method adds a new weekend-days transition or // replaces an existing weekend-days transition. The 'addWeekendDay' and // 'addWeekendDays' methods create a weekend-days transition at January 1, // 0001, if one doesn't already exist, and update the set of weekend days for // that transition. 'addWeekendDay' and 'addWeekendDays' should only be used // for calendars having a consistent set of weekend days throughout their // entire range. The use of 'addWeekendDay' and 'addWeekendDays' is intended // to be *mutually* *exclusive* to the use of 'addWeekendDaysTransition'. As // such, the behavior of using these two methods together with // 'addWeekendDaysTransition' is undefined. // ///Nested Iterators ///---------------- // Also provided are several STL-style 'const' bidirectional iterators // accessible as nested 'typedef's. 'HolidayConstIterator', // 'HolidayCodeConstIterator', 'WeekendDaysTransitionConstIterator', and // 'BusinessDayConstIterator', respectively, iterate over a chronologically // ordered sequence of holidays, a numerically ordered sequence of holiday // codes, a sequence of chronologically ordered weekend-days transitions, and a // sequence of chronologically ordered business days. Reverse iterators are // also provided for each of these (forward) iterators. As a general rule, // calling a 'const' method will not invalidate any iterators, and calling a // non-'const' method might invalidate all of them; it is, however, guaranteed // that attempting to add *duplicate* holidays or holiday codes will have no // effect, and therefore will not invalidate any iterators. It is also // guaranteed that adding a new code for an existing holiday will not // invalidate any 'HolidayConstIterator' objects. // // Note that these iterators do *not* meet the requirements for a // 'bsl::forward_iterator' and should not be used in standard algorithms (e.g., // 'bsl::lower_bound'). // ///Iterator Invalidation ///--------------------- // The modification of a 'bdlt::Calendar' will invalidate iterators referring // to the calendar. The following table shows the relationship between a // calendar manipulator and the types of iterators it will invalidate if the // invocation of the manipulator modified the calendar (e.g., using // 'addHoliday' with a date that is not currently a holiday in the calendar): //.. // Manipulator Invalidates // -------------------------- -------------------- // 'operator=' H HC WDT BD // 'addHoliday' H HC BD // 'addHolidayCode' HC // 'addHolidayCodeIfInRange' HC // 'addHolidayIfInRange' H HC BD // 'addWeekendDay' WDT BD // 'addWeekendDays' WDT BD // 'addWeekendDaysTransition' WDT BD // 'intersectBusinessDays' H HC WDT BD // 'intersectNonBusinessDays' H HC WDT BD // 'removeAll' H HC WDT BD // 'removeHoliday' H HC BD // 'removeHolidayCode' HC // 'setValidRange' H HC BD // 'unionBusinessDays' H HC WDT BD // 'unionNonBusinessDays' H HC WDT BD // // where "H" represents the holiday iterators ('HolidayConstIterator' and // 'HolidayConstReverseIterator'), "HC" represents the holiday code iterators // ('HolidayCodeConstIterator' and 'HolidayCodeConstReverseIterator'), "WDT" // represents the weekend-days transition iterators // ('WeekendDaysTransitionConstIterator' and // 'WeekendDaysTransitionConstReverseIterator'), and "BD" represents the // business day iterators ('BusinessDayConstIterator' and // 'BusinessDayConstReverseIterator'). //.. // ///Performance and Exception-Safety Guarantees ///------------------------------------------- // 'bdlt::Calendar' supports 'O[1]' (i.e., constant-time) determination of // whether a given 'bdlt::Date' value is or is not a business day, which is // accomplished by augmenting the implementation of a packed calendar with a // supplementary cache. The invariant that this cache and the data represented // in the underlying 'bdlt::PackedCalendar' be maintained in a consistent // state may add significantly to the cost of performing many manipulator // operations, especially those that affect the calendar's valid range and add // a new weekend-days transition. Moreover, the cost of many of these // operations will now be proportional to the length(s) of the valid range(s), // as well as their respective numbers of holidays and associated holiday codes // and weekend-days transitions. Hence, when populating a calendar, it is // recommended that the desired value be captured first as a // 'bdlt::PackedCalendar', which can then be used efficiently to // *value-construct* the desired 'bdlt::Calendar' object. See the // component-level doc for 'bdlt_packedcalendar' for its performance // guarantees. // // All methods of the 'bdlt::Calendar' are exception-safe, but in general // provide only the basic guarantee (i.e., no guarantee of rollback): If an // exception occurs (i.e., while attempting to allocate memory), the calendar // object is left in a coherent state, but (unless otherwise specified) its // *value* is undefined. // ///Usage ///----- // The two subsections below illustrate various aspects of populating and using // calendars. // ///Example 1: Populating Calendars ///- - - - - - - - - - - - - - - - // 'bdlt::Calendars' can be populated directly, but are often more efficiently // created by first creating a corresponding 'bdlt::PackedCalendar', and then // using that object to construct the calendar. As an example, suppose we // want to provide efficient access to a (high-performance) 'bdlt::Calendar' // for a variety of locales, whose raw information comes from, say, a database. // The latency associated with fetching data for individual calendars on // demand from a typical database can be prohibitively expensive, so it may // make sense to acquire data for all calendars in a single query at start-up. // // First, we declare a 'MyPackedCalendarCache' that, internally, is just a // mapping from (typically short) character string names (such as "NYB", // representing New York Bank settlement days) to 'bdlt::PackedCalendar' // objects, containing densely packed calendar data: //.. // class MyPackedCalendarCache { // // This class maintains a space-efficient repository of calendar data // // associated with a (typically short) name. // // // DATA // bsl::unordered_map<bsl::string, bdlt::PackedCalendar> d_map; // // public: // // CREATORS // MyPackedCalendarCache(bslma::Allocator *basicAllocator = 0); // // Create an empty 'MyPackedCalendarCache'. Optionally specify a // // 'basicAllocator' used to supply memory. If 'basicAllocator' is // // 0, the currently installed default allocator is used. // // // MANIPULATORS // void assign(const bsl::string& name, // const bdlt::PackedCalendar& calendar); // // Associate the value of the specified 'calendar' with the // // specified 'name'. // // // ACCESSORS // const bdlt::PackedCalendar *lookup(const bsl::string& name) const; // // Return the address of calendar data associated with the // // specified 'name', or 0 if no such association exists. // }; // // // CREATORS // MyPackedCalendarCache::MyPackedCalendarCache( // bslma::Allocator *basicAllocator) // : d_map(basicAllocator) // { // } // // // MANIPULATORS // void MyPackedCalendarCache::assign(const bsl::string& name, // const bdlt::PackedCalendar& calendar) // { // d_map[name] = calendar; // } // // // ACCESSORS // const bdlt::PackedCalendar *MyPackedCalendarCache::lookup( // const bsl::string& name) const // { // typedef bsl::unordered_map<bsl::string, bdlt::PackedCalendar> Cache; // Cache::const_iterator iter = d_map.find(name); // // if (iter == d_map.end()) { // return 0; // RETURN // } // return &iter->second; // } //.. // Then, we define an application function, 'loadMyPackedCalendarCache', that // takes the address of a 'MyPackedCalendarCache' and populates it with // up-to-date calendar data for all known locales (which, in the future, will // be from a well-known database location): //.. // int loadMyPackedCalendarCache(MyPackedCalendarCache *result) // // Load, into the specified 'result', up-to-date calendar information // // for every known locale. Return 0 on success, and a non-zero value // // otherwise. // { // bdlt::PackedCalendar calendar; // calendar.setValidRange(bdlt::Date(2000, 1, 1), // bdlt::Date(2020, 12, 31)); // result->assign("NYB", calendar); // return 0; // } //.. // We can imagine that there might be dozens, even hundreds of different // locales, and that most applications will not need efficient access to // calendar data from many, let alone every locale; however, many long-running // applications may well need to obtain efficient access to the same calendar // data repeatedly. // // Next, we create a second-level of cache, 'MyCalendarCache', that maintains // a repository of the more runtime-efficient, but also more space-intensive, // 'bdlt::Calendar' objects, which are instantiated on demand from a // packed-calendar-based data source: //.. // class MyCalendarCache { // // This class maintains a cache of runtime-efficient calendar objects // // created on demand from a compact packed-calendar-based data source, // // whose address is supplied at construction. // // // DATA // MyPackedCalendarCache *d_datasource_p; // bsl::unordered_map<bsl::string, bdlt::Calendar> d_map; // // public: // // CREATORS // MyCalendarCache(MyPackedCalendarCache *dataSource, // bslma::Allocator *basicAllocator = 0); // // Create an empty 'MyCalendarCache' associated with the specified // // 'dataSource'. Optionally specify a 'basicAllocator' used to // // supply memory. If 'basicAllocator' is 0, the currently // // installed default allocator is used. // // // MANIPULATORS // const bdlt::Calendar *lookup(const bsl::string& name); // // Return the address of calendar data associated with the // // specified 'name', or 0 if no such association exists in the data // // source whose address was supplied at construction. Note that // // this method may alter the physical state of this object (and is // // therefore deliberately declared non-'const'). // }; // // MyCalendarCache::MyCalendarCache(MyPackedCalendarCache *dataSource, // bslma::Allocator *basicAllocator) // : d_datasource_p(dataSource) // , d_map(basicAllocator) // { // } // // const bdlt::Calendar *MyCalendarCache::lookup(const bsl::string& name) // { // typedef bsl::unordered_map<bsl::string, bdlt::Calendar> Cache; // Cache::const_iterator iter = d_map.find(name); // if (iter == d_map.end()) { // const bdlt::PackedCalendar *pc = d_datasource_p->lookup(name); // if (!pc) { // // // No such name in the data source. // // return 0; // RETURN // } // // // Create new entry in calendar cache. // // iter = d_map.insert(bsl::make_pair(name, *pc)).first; // } // // // An efficient calendar either already existed or was created. // // return &iter->second; // } //.. // Now, we can create and populate the cache: //.. // MyPackedCalendarCache packedCalendarCache; // MyCalendarCache calendarCache(&packedCalendarCache); // // loadMyPackedCalendarCache(&packedCalendarCache); //.. // Finally, we request the "NYB" calendar and verify the returned value: //.. // const bdlt::Calendar *calendarPtr = calendarCache.lookup("NYB"); // // assert(calendarPtr->firstDate() == bdlt::Date(2000, 1, 1)); // assert(calendarPtr->lastDate() == bdlt::Date(2020, 12, 31)); //.. // ///Example 2: Using Calendars /// - - - - - - - - - - - - - // What makes a 'bdlt::Calendar' substantially different from a // 'bdlt::PackedCalendar' is the speed with which the 'bdlt::Calendar' can // report whether a given date is or is not a business day. An important use // of high-performance calendar objects in financial applications is to quickly // determine the settlement date of a financial instrument. In some // applications (e.g., those that explore the cross product of various // portfolios over several horizons and scenarios), the settlement date may // need to be calculated literally billions of times. The settlement date // will often be determined from a periodic target date, such as the 15th or // 30th of the month, which is then perturbed in some way to arrive at a valid // settlement date. // // One very common algorithm a security may prescribe for finding a valid // settlement date is known as *modified* *following*: Given a target day, the // settlement date for that month is defined as the first valid business day // at or after the given target day in the same month; if no such date exists, // then the settlement date is the closest valid business day before the target // day in that month. // // First, we create a 'struct', 'MyCalendarUtil', that provides the // 'modifiedFollowing' method: //.. // struct MyCalendarUtil { // // // CLASS METHODS // static bdlt::Date modifiedFollowing(int targetDay, // int month, // int year, // const bdlt::Calendar& calendar) // // Return the date of the first business day at or after the // // specified 'targetDay' in the specified 'month' and 'year' // // according to the specified 'calendar', unless the resulting // // date would not fall within 'month', in which case return // // instead the date of the first business day before 'targetDay' // // in 'month'. The behavior is undefined unless all candidate // // dates applied to 'calendar' are within its valid range and // // there exists at least one business day within 'month'. // { // BSLS_ASSERT(bdlt::Date::isValidYearMonthDay(year, // month, // targetDay)); // // // Efficiency is important so we will minimize the number of // // conversions between year/month/day and 'bdlt::Date' objects. // // bdlt::Date date(year, month, targetDay); // // if (0 == calendar.getNextBusinessDay(&date, date - 1) // && month == date.month()) { // return date; // RETURN // } // while (calendar.isNonBusinessDay(--date)) { // // empty // } // return date; // } // }; //.. // Then, we create and populate two calendars, 'cal1' and 'cal2', for testing // the 'modifiedFollowing' method: //.. // bdlt::Calendar cal1(bdlt::Date(2015, 1, 1), bdlt::Date(2015,12, 31)); // cal1.addWeekendDay(bdlt::DayOfWeek::e_SUN); // cal1.addWeekendDay(bdlt::DayOfWeek::e_SAT); // cal1.addHoliday(bdlt::Date(2015, 7, 3)); // // bdlt::Calendar cal2(cal1); // cal2.addHoliday(bdlt::Date(2015, 7, 31)); //.. // Finally, we verify the 'modifiedFollowing' functionality: //.. // assert(bdlt::Date(2015, 7, 2) == // MyCalendarUtil::modifiedFollowing( 2, 7, 2015, cal1)); // assert(bdlt::Date(2015, 7, 6) == // MyCalendarUtil::modifiedFollowing( 3, 7, 2015, cal1)); // assert(bdlt::Date(2015, 7, 31) == // MyCalendarUtil::modifiedFollowing(31, 7, 2015, cal1)); // // assert(bdlt::Date(2015, 7, 2) == // MyCalendarUtil::modifiedFollowing( 2, 7, 2015, cal2)); // assert(bdlt::Date(2015, 7, 6) == // MyCalendarUtil::modifiedFollowing( 3, 7, 2015, cal2)); // assert(bdlt::Date(2015, 7, 30) == // MyCalendarUtil::modifiedFollowing(31, 7, 2015, cal2)); //.. #include <bdlscm_version.h> #include <bdlt_calendarreverseiteratoradapter.h> #include <bdlt_date.h> #include <bdlt_dayofweek.h> #include <bdlt_dayofweekset.h> #include <bdlt_packedcalendar.h> #include <bdlc_bitarray.h> #include <bslalg_swaputil.h> #include <bslh_hash.h> #include <bslma_allocator.h> #include <bslma_usesbslmaallocator.h> #include <bslmf_integralconstant.h> #include <bsls_assert.h> #include <bsls_preconditions.h> #include <bsls_review.h> #include <bsl_iosfwd.h> #include <bsl_iterator.h> namespace BloombergLP { namespace bdlt { class Calendar_BusinessDayConstIter; // ============== // class Calendar // ============== class Calendar { // This class implements a runtime-efficient, value-semantic repository of // weekend and holiday information over a *valid* *range* of dates. This // valid range, '[firstDate() .. lastDate()]', spans the first and last // dates of a calendar's accessible contents. A calendar can be // "populated" with weekend and holiday information via a suite of "add" // methods. Any subset of days of the week may be specified as weekend // (i.e., recurring non-business) days starting from a specified date by // adding a weekend-days transition; holidays within the valid range are // specified individually. When adding a holiday, an arbitrary integer // "holiday code" may be associated with that date. Additional holiday // codes for that date may subsequently be added. Both the holidays and // the set of unique holiday codes associated with each holiday date are // maintained (internally) in order of increasing value. Note that the // behavior of requesting *any* calendar information for a supplied date // whose value is outside the current *valid* *range* for that calendar // (unless otherwise noted, e.g., 'isWeekendDay') is undefined. // DATA PackedCalendar d_packedCalendar; // the packed calendar object, which contains // the weekend day and holiday information bdlc::BitArray d_nonBusinessDays; // cache of non-business days; note that the end // of the valid range is defined by // 'd_packedCalendar.firstDate() + length() - 1' // FRIENDS friend bool operator==(const Calendar&, const Calendar&); friend bool operator!=(const Calendar&, const Calendar&); template <class HASHALG> friend void hashAppend(HASHALG& hashAlg, const Calendar&); private: // PRIVATE MANIPULATORS void synchronizeCache(); // Synchronize this calendar's cache by first clearing the cache, then // repopulating it with the holiday and weekend information from this // calendar's 'd_packedCalendar'. Note that this method is only // *exception*-*neutral*; exception safety and rollback must be // handled by the caller. // PRIVATE ACCESSORS bool isCacheSynchronized() const; // Return 'true' if this calendar's cache correctly represents the // holiday and weekend information stored in this calendar's // 'd_packedCalendar', and 'false' otherwise. public: // TYPES typedef Calendar_BusinessDayConstIter BusinessDayConstIterator; typedef PackedCalendar::HolidayConstIterator HolidayConstIterator; typedef PackedCalendar::HolidayCodeConstIterator HolidayCodeConstIterator; typedef CalendarReverseIteratorAdapter<BusinessDayConstIterator> BusinessDayConstReverseIterator; typedef PackedCalendar::HolidayConstReverseIterator HolidayConstReverseIterator; typedef PackedCalendar::HolidayCodeConstReverseIterator HolidayCodeConstReverseIterator; typedef PackedCalendar::WeekendDaysTransition WeekendDaysTransition; typedef PackedCalendar::WeekendDaysTransitionConstIterator WeekendDaysTransitionConstIterator; typedef PackedCalendar::WeekendDaysTransitionConstReverseIterator WeekendDaysTransitionConstReverseIterator; // CLASS METHODS // Aspects static int maxSupportedBdexVersion(int versionSelector); // Return the maximum valid BDEX format version, as indicated by the // specified 'versionSelector', to be passed to the 'bdexStreamOut' // method. Note that it is highly recommended that 'versionSelector' // be formatted as "YYYYMMDD", a date representation. Also note that // 'versionSelector' should be a *compile*-time-chosen value that // selects a format version supported by both externalizer and // unexternalizer. See the 'bslx' package-level documentation for more // information on BDEX streaming of value-semantic types and // containers. // CREATORS explicit Calendar(bslma::Allocator *basicAllocator = 0); // Create an empty calendar, i.e., a calendar having an empty valid // range. Optionally specify a 'basicAllocator' used to supply memory. // If 'basicAllocator' is 0, the currently installed default allocator // is used. Calendar(const Date& firstDate, const Date& lastDate, bslma::Allocator *basicAllocator = 0); // Create a calendar having a valid range from the specified // 'firstDate' through the specified 'lastDate'. Optionally specify a // 'basicAllocator' used to supply memory. If 'basicAllocator' is 0, // the currently installed default allocator is used. The behavior is // undefined unless 'firstDate <= lastDate'. explicit Calendar(const bdlt::PackedCalendar& packedCalendar, bslma::Allocator *basicAllocator = 0); // Create a calendar having the same value as the specified // 'packedCalendar'. Optionally specify a 'basicAllocator' used to // supply memory. If 'basicAllocator' is 0, the currently installed // default allocator is used. Calendar(const Calendar& original, bslma::Allocator *basicAllocator = 0); // Create a calendar having the value of the specified 'original' // calendar. Optionally specify a 'basicAllocator' used to supply // memory. If 'basicAllocator' is 0, the currently installed default // allocator is used. ~Calendar(); // Destroy this object. // MANIPULATORS Calendar& operator=(const Calendar& rhs); Calendar& operator=(const PackedCalendar& rhs); // Assign to this calendar the value of the specified 'rhs' calendar, // and return a reference providing modifiable access to this calendar. // See {Iterator Invalidation} for information regarding which // iterators are affected by the use of these methods. void addDay(const Date& date); // Extend the valid range (if necessary) of this calendar to include // the specified 'date' value. void addHoliday(const Date& date); // Mark the specified 'date' as a holiday (i.e., a non-business day) // in this calendar. Extend the valid range of this calendar if // necessary. If 'date' is already marked as a holiday, this method // has no effect. See {Iterator Invalidation} for information // regarding which iterators are affected by the use of this method. void addHolidayCode(const Date& date, int holidayCode); // Mark the specified 'date' as a holiday (i.e., a non-business day) in // this calendar and add the specified 'holidayCode' (if not already // present) to the ordered set of codes associated with 'date'. // Extend the valid range of this calendar if necessary. If // 'holidayCode' is already a code for 'date', this method has no // effect. See {Iterator Invalidation} for information regarding // which iterators are affected by the use of this method. Note that // this method may be called repeatedly with the same value for 'date' // to build up a set of holiday codes for that date. int addHolidayCodeIfInRange(const Date& date, int holidayCode); // Mark the specified 'date' as a holiday (i.e., a non-business day) // in this calendar and add the specified 'holidayCode' (if not // already present) to the set of codes associated with 'date', if // 'date' is within the valid range of this calendar. Return 0 if // 'date' is in range, and a non-zero value otherwise. If // 'holidayCode' is already a code for 'date', or if 'date' is not in // the valid range, this method has no effect. See // {Iterator Invalidation} for information regarding which iterators // are affected by the use of this method. Note that this method may, // at the expense of verifying 'isInRange(date)' for each invocation, // be called repeatedly with the same value for 'date' to build up a // set of holiday codes for that date. int addHolidayIfInRange(const Date& date); // Mark the specified 'date' as a holiday (i.e., a non-business day) in // this calendar if 'date' is within the valid range. Return 0 if // 'date' is in range, and a non-zero value otherwise. This method has // no effect if 'date' is already marked as a holiday or is not in the // valid range. See {Iterator Invalidation} for information regarding // which iterators are affected by the use of this method. void addWeekendDay(DayOfWeek::Enum weekendDay); // Add the specified 'weekendDay' to the set of weekend days associated // with the weekend-days transition at January 1, 0001 maintained by // this calendar. Create a transition at January 1, 0001 if one does // not exist. See {Iterator Invalidation} for information regarding // which iterators are affected by the use of this method. The // behavior is undefined unless no weekend-days transitions were added // to this calendar via the 'addWeekendDaysTransition' method. void addWeekendDays(const DayOfWeekSet& weekendDays); // Add the specified 'weekendDays' to the set of weekend days // associated with the weekend-days transition at January 1, 0001 // maintained by this calendar. Create a transition at January 1, 0001 // if one does not exist. See {Iterator Invalidation} for information // regarding which iterators are affected by the use of this method. // The behavior is undefined unless no weekend-days transitions were // added to this calendar via the 'addWeekendDaysTransition' method. void addWeekendDaysTransition(const Date& startDate, const DayOfWeekSet& weekendDays); // Add to this calendar a weekend-days transition on the specified // 'startDate' having the specified 'weekendDays' set. If a // weekend-days transition already exists on 'startDate', replace the // set of weekend days of that transition with 'weekendDays'. See // {Iterator Invalidation} for information regarding which iterators // are affected by the use of this method. Note that this method does // not extend the valid range of the calendar. void intersectBusinessDays(const Calendar& other); void intersectBusinessDays(const PackedCalendar& other); // Merge the specified 'other' calendar into this calendar such that // the valid range of this calendar becomes the *intersection* of the // two calendars' ranges, and the weekend days and holidays for this // calendar become the union of those (non-business) days from the two // calendars -- i.e., the valid business days of this calendar become // the intersection of those of the two original calendar values over // the *intersection* of their ranges. For each holiday that remains, // the resulting holiday codes in this calendar will be the union of // the corresponding original holiday codes. See // {Iterator Invalidation} for information regarding which iterators // are affected by the use of this method. void intersectNonBusinessDays(const Calendar& other); void intersectNonBusinessDays(const PackedCalendar& other); // Merge the specified 'other' calendar into this calendar such that // the valid range of this calendar becomes the *intersection* of the // two calendars' ranges, the weekend days for this calendar become the // intersection of those days from the two calendars, and the holidays // for this calendar become the set of days that are a holiday in one // of the calendars and a non-business day in the other calendar -- // i.e., the valid business days of this calendar become the union of // those of the two original calendars over the *intersection* of their // ranges. For each holiday that remains, the resulting holiday codes // in this calendar will be the union of the corresponding original // holiday codes. See {Iterator Invalidation} for information // regarding which iterators are affected by the use of this method. void removeAll(); // Remove all information from this calendar, leaving it with its // default constructed "empty" value. See {Iterator Invalidation} for // information regarding which iterators are affected by the use of // this method. void removeHoliday(const Date& date); // Remove from this calendar the holiday having the specified 'date' if // such a holiday exists. This operation has no effect if 'date' is // not a holiday in this calendar. See {Iterator Invalidation} for // information regarding which iterators are affected by the use of // this method. Note that this method is defined for all 'date' // values, not just those that fall within the valid range, and may be // invoked even on an empty calendar (i.e., having '0 == length()'). void removeHolidayCode(const Date& date, int holidayCode); // Remove from this calendar the specified 'holidayCode' for the // holiday having the specified 'date' if such a holiday having // 'holidayCode' exists. This operation has no effect if 'date' is not // a holiday in this calendar, or if the holiday at 'date' does not // have 'holidayCode' associated with it. See {Iterator Invalidation} // for information regarding which iterators are affected by the use of // this method. Note that this method is defined for all 'date' // values, not just those that fall within the valid range, and may be // invoked even on an empty calendar (i.e., having '0 == length()'). void reserveHolidayCapacity(int numHolidays); // Reserve enough space to store at least the specified 'numHolidays' // within this calendar. This method has no effect if // 'numHolidays <= numHolidays()'. void reserveHolidayCodeCapacity(int numHolidayCodes); // Reserve enough space to store at least the specified // 'numHolidayCodes' within this calendar assuming no additional // holidays are added to this calendar. This method has no effect if // 'numHolidayCodes <= numHolidayCodesTotal()'. void setValidRange(const Date& firstDate, const Date& lastDate); // Set the range of this calendar using the specified 'firstDate' and // 'lastDate' as, respectively, the first date and the last date of the // calendar. Any holiday that is outside the new range and its holiday // codes are removed. See {Iterator Invalidation} for information // regarding which iterators are affected by the use of this method. // The behavior is undefined unless 'firstDate <= lastDate'. void unionBusinessDays(const Calendar& other); void unionBusinessDays(const PackedCalendar& other); // Merge the specified 'other' calendar into this calendar such that // the valid range of this calendar becomes the *union* of the two // calendars' ranges (or the minimal continuous range spanning the two // ranges, if the ranges are non-overlapping), the weekend days for // this calendar become the intersection of those days from the two // calendars, and the holidays for this calendar become the set of days // that are a holiday in one of the calendars and a non-business day in // the other calendar -- i.e., the valid business days of this calendar // become the union of those of the two original calendar values. For // each holiday that remains, the resulting holiday codes in this // calendar will be the union of the corresponding original holiday // codes. See {Iterator Invalidation} for information regarding which // iterators are affected by the use of this method. void unionNonBusinessDays(const Calendar& other); void unionNonBusinessDays(const PackedCalendar& other); // Merge the specified 'other' calendar into this calendar such that // the valid range of this calendar becomes the *union* of the two // calendars' ranges (or the minimal continuous range spanning the two // ranges, if the ranges are non-overlapping), and the weekend days // and holidays for this calendar become the union of those // (non-business) days from the two calendars -- i.e., the valid // business days of this calendar become the intersection of those of // the two calendars after each range is extended to cover the // resulting one. For each holiday in either calendar, the resulting // holiday codes in this calendar will be the union of the // corresponding original holiday codes. See {Iterator Invalidation} // for information regarding which iterators are affected by the use of // this method. // Aspects template <class STREAM> STREAM& bdexStreamIn(STREAM& stream, int version); // Assign to this object the value read from the specified input // 'stream' using the specified 'version' format and return a reference // to the modifiable 'stream'. If 'stream' is initially invalid, this // operation has no effect. If 'stream' becomes invalid during this // operation or if 'version' is not supported, this object is // unaltered. Note that no version is read from 'stream'. See the // 'bslx' package-level documentation for more information on BDEX // streaming of value-semantic types and containers. void swap(Calendar& other); // Efficiently exchange the value of this object with the value of the // specified 'other' object. This method provides the no-throw // exception-safety guarantee. The behavior is undefined unless this // object was created with the same allocator as 'other'. // ACCESSORS BusinessDayConstIterator beginBusinessDays() const; // Return an iterator providing non-modifiable access to the first // business day in this calendar. If this calendar has no valid // business days, the returned iterator has the same value as that // returned by 'endBusinessDays()'. BusinessDayConstIterator beginBusinessDays(const Date& date) const; // Return an iterator providing non-modifiable access to the first // business day that occurs on or after the specified 'date' in this // calendar. If this calendar has no such business day, the returned // iterator has the same value as that returned by // 'endBusinessDays(date)'. The behavior is undefined unless 'date' is // within the valid range of this calendar. HolidayCodeConstIterator beginHolidayCodes(const Date& date) const; // Return an iterator providing non-modifiable access to the first // holiday code for the specified 'date' in this calendar. If there is // no holiday code associated with 'date', the returned iterator has // the same value as that returned by 'endHolidayCodes(date)'. The // behavior is undefined unless 'date' is marked as a holiday in this // calendar. HolidayCodeConstIterator beginHolidayCodes( const HolidayConstIterator& iter) const; // Return an iterator providing non-modifiable access to the first // holiday code for the holiday referenced by the specified 'iter'. If // there is no holiday code associated with the date referenced by // 'iter', the returned iterator has the same value as that returned by // 'endHolidayCodes(iter)'. The behavior is undefined unless 'iter' // refers to a valid holiday of this calendar. HolidayConstIterator beginHolidays() const; // Return an iterator providing non-modifiable access to the first // holiday in this calendar. If this calendar has no holidays, the // returned iterator has the same value as that returned by // 'endHolidays()'. HolidayConstIterator beginHolidays(const Date& date) const; // Return an iterator providing non-modifiable access to the first // holiday that occurs on or after the specified 'date' in this // calendar. If this calendar has no such holiday, the returned // iterator has the same value as that returned by 'endHolidays(date)'. // The behavior is undefined unless 'date' is within the valid range // of this calendar. WeekendDaysTransitionConstIterator beginWeekendDaysTransitions() const; // Return an iterator providing non-modifiable access to the first // weekend-days transition in the chronological sequence of // weekend-days transitions maintained by this calendar. If this // calendar has no weekend-days transitions, the returned iterator has // the same value as that returned by 'endWeekendDaysTransitions()'. BusinessDayConstIterator endBusinessDays() const; // Return an iterator providing non-modifiable access to the // past-the-end business day in this calendar. BusinessDayConstIterator endBusinessDays(const Date& date) const; // Return an iterator providing non-modifiable access to the first // business day that occurs after the specified 'date' in this // calendar. If this calendar has no such business day, the returned // iterator has the same value as that returned by // 'endBusinessDays()'. The behavior is undefined unless 'date' is // within the valid range of this calendar. HolidayCodeConstIterator endHolidayCodes(const Date& date) const; // Return an iterator providing non-modifiable access to the // past-the-end holiday code associated with the specified 'date'. The // behavior is undefined unless 'date' is marked as a holiday in this // calendar. HolidayCodeConstIterator endHolidayCodes(const HolidayConstIterator& iter) const; // Return an iterator providing non-modifiable access to the // past-the-end holiday code associated with the date referenced by // the specified 'iter'. The behavior is undefined unless 'iter' // references a valid holiday in this calendar. HolidayConstIterator endHolidays() const; // Return an iterator providing non-modifiable access to the // past-the-end holiday in the chronological sequence of holidays // maintained by this calendar. HolidayConstIterator endHolidays(const Date& date) const; // Return an iterator providing non-modifiable access to the first // holiday that occurs after the specified 'date' in this calendar. // If this calendar has no such holiday, the returned iterator has the // same value as that returned by 'endHolidays()'. The behavior is // undefined unless 'date' is within the valid range of this calendar. WeekendDaysTransitionConstIterator endWeekendDaysTransitions() const; // Return an iterator providing non-modifiable access to the // past-the-end weekend-days transition in the chronological sequence // of weekend-days transitions maintained by this calendar. const Date& firstDate() const; // Return a reference providing non-modifiable access to the earliest // date in the valid range of this calendar. The behavior is // undefined unless this calendar is non-empty -- i.e., unless // '1 <= length()'. int getNextBusinessDay(Date *nextBusinessDay, const Date& date) const; // Load, into the specified 'nextBusinessDay', the date of the first // business day in this calendar following the specified 'date'. // Return 0 on success -- i.e., if such a business day exists, and a // non-zero value (with no effect on 'nextBusinessDay') otherwise. The // behavior is undefined unless 'date + 1' is both a valid 'bdlt::Date' // and within the valid range of this calendar. int getNextBusinessDay(Date *nextBusinessDay, const Date& date, int nth) const; // Load, into the specified 'nextBusinessDay', the date of the // specified 'nth' business day in this calendar following the // specified 'date'. Return 0 on success -- i.e., if such a business // day exists, and a non-zero value (with no effect on // 'nextBusinessDay') otherwise. The behavior is undefined unless // 'date + 1' is both a valid 'bdlt::Date' and within the valid range // of this calendar, and '0 < nth'. Date holiday(int index) const; // Return the holiday at the specified 'index' in this calendar. For // all 'index' values from 0 to 'numHolidays() - 1' (inclusive), a // unique holiday is returned. The mapping of 'index' to holiday is // invalidated when the set of holidays is modified by an invocation of // 'addHoliday', 'addHolidayIfInRange', 'intersectBusinessDays', // 'intersectNonBusinessDays', 'removeAll', 'removeHoliday', // 'setValidRange', 'unionBusinessDays', or 'unionNonBusinessDays'. // The behavior is undefined unless '0 <= index < numHolidays()'. int holidayCode(const Date& date, int index) const; // Return, for the holiday at the specified 'date' in this calendar, // the holiday code at the specified 'index'. For all 'index' values // from 0 to 'numHolidayCodes(date) - 1' (inclusive), a unique holiday // code is returned. The mapping of 'index' to holiday code is // invalidated when the set of holidays or holiday codes is modified by // an invocation of 'addHoliday', 'addHolidayCode', // 'addHolidayCodeIfInRange', 'addHolidayIfInRange', // 'intersectBusinessDays', 'intersectNonBusinessDays', 'removeAll', // 'removeHoliday', 'removeHolidayCode', 'setValidRange', // 'unionBusinessDays', or 'unionNonBusinessDays'. The behavior is // undefined unless 'date' is a holiday in this calendar and // '0 <= index < numHolidayCodes(date)'. Note that this method // facilitates testing and generally should not be used by clients; in // particular, using this method to iterate over the holiday codes for // 'date' is less efficient than using a 'HolidayCodeConstIterator'. bool isBusinessDay(const Date& date) const; // Return 'true' if the specified 'date' is a business day (i.e., not // a holiday or weekend day) in this calendar, and 'false' otherwise. // The behavior is undefined unless 'date' is within the valid range of // this calendar. bool isHoliday(const Date& date) const; // Return 'true' if the specified 'date' is a holiday in this calendar, // and 'false' otherwise. The behavior is undefined unless 'date' is // within the valid range of this calendar. bool isInRange(const Date& date) const; // Return 'true' if the specified 'date' is within the valid range of // this calendar (i.e., 'firstDate() <= date <= lastDate()'), and // 'false' otherwise. Note that the valid range for a 'Calendar' is // empty if its length is 0. bool isNonBusinessDay(const Date& date) const; // Return 'true' if the specified 'date' is not a business day (i.e., // is either a holiday or weekend day) in this calendar, and 'false' // otherwise. The behavior is undefined unless 'date' is within the // valid range of this calendar. Note that: //.. // !isBusinessDay(date) //.. // returns the same result. bool isWeekendDay(const Date& date) const; // Return 'true' if the specified 'date' falls on a day of the week // that is considered a weekend day in this calendar, and 'false' // otherwise. Note that this method is defined for all 'date' values, // not just those that fall within the valid range, and may be invoked // even on an empty calendar (i.e., having '0 == length()'). bool isWeekendDay(DayOfWeek::Enum dayOfWeek) const; // Return 'true' if the specified 'dayOfWeek' is a weekend day in this // calendar, and 'false' otherwise. The behavior is undefined unless // no weekend-days transitions were added to this calendar via the // 'addWeekendDaysTransition' method. const Date& lastDate() const; // Return a reference providing non-modifiable access to the latest // date in the valid range of this calendar. The behavior is // undefined unless this calendar is non-empty -- i.e., unless // '1 <= length()'. int length() const; // Return the number of days in the valid range of this calendar, // which is defined to be 0 if this calendar is empty, and // 'lastDate() - firstDate() + 1' otherwise. int numBusinessDays() const; // Return the number of days in the valid range of this calendar that // are considered business days -- i.e., are neither holidays nor // weekend days. Note that // 'numBusinessDays() == length() - numNonBusinessDays()'. int numBusinessDays(const Date& beginDate, const Date& endDate) const; // Return the number of days in the specified range // '[beginDate .. endDate]' of this calendar that are considered // business days -- i.e., are neither holidays nor weekend days. The // behavior is undefined unless 'beginDate' and 'endDate' are within // the valid range of this calendar, and 'beginDate <= endDate'. int numHolidayCodes(const Date& date) const; // Return the number of (unique) holiday codes associated with the // specified 'date' in this calendar if 'date' is a holiday in this // calendar, and 0 otherwise. The behavior is undefined unless 'date' // is within the valid range of this calendar. int numHolidayCodesTotal() const; // Return the total number of holiday codes for all holidays in this // calendar. Note that this function is used primarily in conjunction // with 'reserveHolidayCodeCapacity'. int numHolidays() const; // Return the number of days in the valid range of this calendar that // are individually marked as holidays, irrespective of whether or not // the date is also considered a weekend day. int numNonBusinessDays() const; // Return the number of days in the valid range of this calendar that // are *not* considered business days -- i.e., are either holidays, // weekend days, or both. Note that // 'numNonBusinessDays() == length() - numBusinessDays()'. int numWeekendDaysInRange() const; // Return the number of days in the valid range of this calendar that // are considered weekend days, irrespective of any designated // holidays. int numWeekendDaysTransitions() const; // Return the number of weekend-days transitions maintained by this // calendar. const PackedCalendar& packedCalendar() const; // Return a reference providing non-modifiable access to the underlying // 'PackedCalendar', which represents the same (mathematical) value as // this calendar. BusinessDayConstReverseIterator rbeginBusinessDays() const; // Return an iterator providing non-modifiable access to the last // business day in this calendar. If this calendar has no valid // business days, the returned iterator has the same value as that // returned by 'rendBusinessDays()'. BusinessDayConstReverseIterator rbeginBusinessDays(const Date& date) const; // Return an iterator providing non-modifiable access to the first // business day that occurs on or before the specified 'date' in this // calendar. If this calendar has no such business day, the returned // iterator has the same value as that returned by // 'rendBusinessDays(date)'. The behavior is undefined unless 'date' // is within the valid range of this calendar. HolidayCodeConstReverseIterator rbeginHolidayCodes(const Date& date) const; // Return an iterator providing non-modifiable access to the last // holiday code associated with the specified 'date' in this calendar. // If there are no holiday codes associated with 'date', the returned // iterator has the same value as that returned by // 'rendHolidayCodes(date)'. The behavior is undefined unless 'date' // is marked as a holiday in this calendar. HolidayCodeConstReverseIterator rbeginHolidayCodes(const HolidayConstIterator& iter) const; // Return an iterator providing non-modifiable access to the last // holiday code associated with the holiday referenced by the specified // 'iter'. If there are no holiday codes associated with the date // referenced by 'iter', the returned iterator has the same value as // that returned by 'rendHolidayCodes(iter)'. The behavior is // undefined unless 'iter' refers to a valid holiday of this calendar. HolidayConstReverseIterator rbeginHolidays() const; // Return an iterator providing non-modifiable access to the last // holiday in this calendar. If this calendar has no holidays, the // returned iterator has the same value as that returned by // 'rendHolidays()'. HolidayConstReverseIterator rbeginHolidays(const Date& date) const; // Return an iterator providing non-modifiable access to the first // holiday that occurs on or before the specified 'date' in this // calendar. If this calendar has no such holiday, the returned // iterator has the same value as that returned by // 'rendHolidays(date)'. The behavior is undefined unless 'date' is // within the valid range of this calendar. WeekendDaysTransitionConstReverseIterator rbeginWeekendDaysTransitions() const; // Return an iterator providing non-modifiable access to the last // weekend-days transition in the chronological sequence of // weekend-days transitions maintained by this calendar. If this // calendar has no weekend-days transitions, the returned iterator has // the same value as that returned by 'rendWeekendDaysTransitions()'. BusinessDayConstReverseIterator rendBusinessDays() const; // Return an iterator providing non-modifiable access to the element // one before the first business day in this calendar. BusinessDayConstReverseIterator rendBusinessDays(const Date& date) const; // Return an iterator providing non-modifiable access to the first // business day that occurs before the specified 'date' in this // calendar. If this calendar has no such business day, the returned // iterator has the same value as that returned by // 'rendBusinessDays()'. The behavior is undefined unless 'date' is // within the valid range of this calendar. HolidayCodeConstReverseIterator rendHolidayCodes(const Date& date) const; // Return an iterator providing non-modifiable access to the element // one before the first holiday code associated with the specified // 'date'. The behavior is undefined unless 'date' is marked as a // holiday in this calendar. HolidayCodeConstReverseIterator rendHolidayCodes(const HolidayConstIterator& iter) const; // Return an iterator providing non-modifiable access to the element // one before the first holiday code associated with the holiday // referenced by the specified 'iter'. The behavior is undefined // unless 'iter' references a valid holiday in this calendar. HolidayConstReverseIterator rendHolidays() const; // Return an iterator providing non-modifiable access to the element // one before the first holiday in this calendar. HolidayConstReverseIterator rendHolidays(const Date& date) const; // Return an iterator providing non-modifiable access to the first // holiday that occurs before the specified 'date' in this calendar. // If this calendar has no such holiday, the returned iterator has the // same value as that returned by 'rendHolidays()'. The behavior is // undefined unless 'date' is within the valid range of this calendar. WeekendDaysTransitionConstReverseIterator rendWeekendDaysTransitions() const; // Return an iterator providing non-modifiable access to the element // one before the first weekend-days transition in the chronological // sequence of weekend-days transitions maintained by this calendar. WeekendDaysTransition weekendDaysTransition(int index) const; // Return the weekend-days transition at the specified 'index' in this // calendar. For all 'index' values from 0 to // 'numWeekendDaysTransitions() - 1' (inclusive), a unique weekend-days // transition is returned. The mapping of 'index' to weekend-days // transition is invalidated when the set of weekend-days transitions // is modified by an invocation of 'addWeekendDay', 'addWeekendDays', // 'addWeekendDaysTransition', 'intersectBusinessDays', // 'intersectNonBusinessDays', 'removeAll', 'unionBusinessDays', or // 'unionNonBusinessDays'. The behavior is undefined unless // '0 <= index < numWeekendDaysTransitions()'. // Aspects bslma::Allocator *allocator() const; // Return the allocator used by this object to supply memory. template <class STREAM> STREAM& bdexStreamOut(STREAM& stream, int version) const; // Write this value to the specified output 'stream' using the // specified 'version' format and return a reference to the modifiable // 'stream'. If 'version' is not supported, 'stream' is unmodified. // Note that 'version' is not written to 'stream'. See the 'bslx' // package-level documentation for more information on BDEX streaming // of value-semantic types and containers. bsl::ostream& print(bsl::ostream& stream, int level = 0, int spacesPerLevel = 4) const; // Format this object to the specified output 'stream' at the (absolute // value of) the optionally specified indentation 'level' and return a // reference to the modifiable 'stream'. If 'level' is specified, // optionally specify 'spacesPerLevel', the number of spaces per // indentation level for this and all of its nested objects. If // 'level' is negative, suppress indentation of the first line. If // 'spacesPerLevel' is negative, format the entire output on one line, // suppressing all but the initial indentation (as governed by // 'level'). If 'stream' is not valid on entry, this operation has no // effect. #ifndef BDE_OMIT_INTERNAL_DEPRECATED // BDE2.22 // DEPRECATED METHODS static int maxSupportedBdexVersion(); // !DEPRECATED!: Use 'maxSupportedBdexVersion(int)' instead. // // Return the most current BDEX streaming version number supported by // this class. #endif // BDE_OMIT_INTERNAL_DEPRECATED -- BDE2.22 #ifndef BDE_OMIT_INTERNAL_DEPRECATED // BDE3.0 Date getNextBusinessDay(const Date& initialDate) const; // Return the date of the first business day following the specified // 'initialDate'. For dates outside of the range of this calendar, // only weekend days are considered non-business days. The behavior // is undefined if every day of the week is a weekend day, or if the // resulting date would otherwise exceed the value // 'Date(9999, 12, 31)'. Date getNextBusinessDay(const Date& initialDate, int nth) const; // Return the date of the specified 'nth' business day following the // specified 'initialDate'. For dates outside of the range of this // calendar, only weekend days are considered non-business days. The // behavior is undefined unless 'initialDate' is within the valid // range and '1 <= nth' (or if every day of the week is a weekend day, // or if the resulting date would otherwise exceed the value // 'Date(9999, 12, 31)'). #endif // BDE_OMIT_INTERNAL_DEPRECATED -- BDE3.0 }; // FREE OPERATORS bool operator==(const Calendar& lhs, const Calendar& rhs); // Return 'true' if the specified 'lhs' and 'rhs' calendars have the same // value, and 'false' otherwise. Two calendars have the same value if they // have the same valid range (or are both empty), the same weekend days, // the same holidays, and each corresponding pair of holidays has the same // (ordered) set of associated holiday codes. bool operator!=(const Calendar& lhs, const Calendar& rhs); // Return 'true' if the specified 'lhs' and 'rhs' calendars do not have the // same value, and 'false' otherwise. Two calendars do not have the same // value if they do not have the same valid range (and are not both empty), // do not have the same weekend days, do not have the same holidays, or, // for at least one corresponding pair of holidays, do not have the same // (ordered) set of associated holiday codes. bsl::ostream& operator<<(bsl::ostream& stream, const Calendar& calendar); // Write the value of the specified 'calendar' to the specified output // 'stream', and return a reference to the modifiable 'stream'. // FREE FUNCTIONS template <class HASHALG> void hashAppend(HASHALG& hashAlg, const Calendar& object); // Pass the specified 'object' to the specified 'hashAlg'. This function // integrates with the 'bslh' modular hashing system and effectively // provides a 'bsl::hash' specialization for 'Calendar'. void swap(Calendar& a, Calendar& b); // Exchange the values of the specified 'a' and 'b' objects. This function // provides the no-throw exception-safety guarantee if the two objects were // created with the same allocator and the basic guarantee otherwise. // =================================== // class Calendar_BusinessDayConstIter // =================================== class Calendar_BusinessDayConstIter { // Provide read-only, sequential access in increasing (chronological) order // to the business days in a 'Calendar' object. // DATA const bdlc::BitArray *d_nonBusinessDays_p; // pointer to the non-business // day bit array in the // calendar Date d_firstDate; // first valid date of the // calendar int d_currentOffset; // offset of the date to which // this iterator is pointing // (-1 indicates an 'end' // iterator) // FRIENDS friend class Calendar; friend bool operator==(const Calendar_BusinessDayConstIter&, const Calendar_BusinessDayConstIter&); friend bool operator!=(const Calendar_BusinessDayConstIter&, const Calendar_BusinessDayConstIter&); private: // PRIVATE CREATORS Calendar_BusinessDayConstIter(const bdlc::BitArray& nonBusinessDays, const Date& firstDateOfCalendar, const Date& startDate, bool endIterFlag); // Create a business day iterator for a calendar defined by the // specified 'nonBusinessDays' and 'firstDateOfCalendar'. If the // specified 'endIterFlag' is 'false', then this iterator references // the first business day on or after the specified 'startDate'; // otherwise, this iterator references one business day *past* the // first business day on or after 'startDate'. If no business day // matching the above specification exists, then this iterator // references one day past the end of its range. The behavior is // undefined unless 'startDate' is within the valid range of the // calendar defined by 'nonBusinessDays' and 'firstDateOfCalendar'. public: // PUBLIC TYPES typedef Date value_type; typedef int difference_type; typedef PackedCalendar_DateProxy pointer; typedef PackedCalendar_DateRef reference; // The star operator returns a 'PackedCalendar_DateRef' *by* *value*. typedef bsl::bidirectional_iterator_tag iterator_category; // CREATORS Calendar_BusinessDayConstIter( const Calendar_BusinessDayConstIter& original); // Create an iterator having the value of the specified 'original' // iterator. ~Calendar_BusinessDayConstIter(); // Destroy this object. // MANIPULATORS Calendar_BusinessDayConstIter& operator=( const Calendar_BusinessDayConstIter& rhs); // Assign to this iterator the value of the specified 'rhs' iterator, // and return a reference providing modifiable access to this object. Calendar_BusinessDayConstIter& operator++(); // Advance this iterator to refer to the next business day in the // associated calendar, and return a reference providing modifiable // access to this object. The behavior is undefined unless, on entry, // this iterator references a valid business day. Calendar_BusinessDayConstIter& operator--(); // Regress this iterator to refer to the previous business day in the // associated calendar, and return a reference providing modifiable // access to this object. The behavior is undefined unless, on entry, // this iterator references a valid business day that is not the first // business day for the associated calendar. // ACCESSORS PackedCalendar_DateRef operator*() const; // Return a 'PackedCalendar_DateRef' object that contains the date // value of the business day referenced by this iterator. PackedCalendar_DateProxy operator->() const; // Return a date proxy for the business day referenced by this // iterator. }; // FREE OPERATORS bool operator==(const Calendar_BusinessDayConstIter& lhs, const Calendar_BusinessDayConstIter& rhs); // Return 'true' if the specified 'lhs' and 'rhs' iterators refer to the // same element in the same calendar, and 'false' otherwise. The behavior // is undefined unless 'lhs' and 'rhs' both iterate over the same calendar. bool operator!=(const Calendar_BusinessDayConstIter& lhs, const Calendar_BusinessDayConstIter& rhs); // Return 'true' if the specified 'lhs' and 'rhs' iterators do not refer to // the same element in the same calendar, and 'false' otherwise. The // behavior is undefined unless 'lhs' and 'rhs' both iterate over the same // calendar. Calendar_BusinessDayConstIter operator++( Calendar_BusinessDayConstIter& iterator, int); // Advance the specified 'iterator' to refer to the next business day in // the associated calendar, and return the previous value of 'iterator'. // The behavior is undefined unless, on entry, 'iterator' references a // valid business day. Calendar_BusinessDayConstIter operator--( Calendar_BusinessDayConstIter& iterator, int); // Regress the specified 'iterator' to refer to the previous business day // in the associated calendar, and return the previous value of 'iterator'. // The behavior is undefined unless, on entry, 'iterator' references a // valid business day that is not the first business day for the associated // calendar. // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // -------------- // class Calendar // -------------- // CLASS METHODS // Aspects inline int Calendar::maxSupportedBdexVersion(int versionSelector) { return PackedCalendar::maxSupportedBdexVersion(versionSelector); } // MANIPULATORS inline Calendar& Calendar::operator=(const Calendar& rhs) { Calendar(rhs, d_packedCalendar.allocator()).swap(*this); return *this; } inline Calendar& Calendar::operator=(const PackedCalendar& rhs) { Calendar(rhs, d_packedCalendar.allocator()).swap(*this); return *this; } inline int Calendar::addHolidayCodeIfInRange(const Date& date, int holidayCode) { if (isInRange(date)) { addHolidayCode(date, holidayCode); return 0; // RETURN } return -1; } inline int Calendar::addHolidayIfInRange(const Date& date) { if (isInRange(date)) { addHoliday(date); return 0; // RETURN } return -1; } inline void Calendar::addWeekendDaysTransition(const Date& startDate, const DayOfWeekSet& weekendDays) { d_packedCalendar.addWeekendDaysTransition(startDate, weekendDays); synchronizeCache(); } inline void Calendar::intersectBusinessDays(const PackedCalendar& other) { d_packedCalendar.intersectBusinessDays(other); synchronizeCache(); } inline void Calendar::intersectBusinessDays(const Calendar& other) { intersectBusinessDays(other.d_packedCalendar); } inline void Calendar::intersectNonBusinessDays(const PackedCalendar& other) { d_packedCalendar.intersectNonBusinessDays(other); synchronizeCache(); } inline void Calendar::intersectNonBusinessDays(const Calendar& other) { intersectNonBusinessDays(other.d_packedCalendar); } inline void Calendar::removeAll() { d_packedCalendar.removeAll(); d_nonBusinessDays.removeAll(); } inline void Calendar::removeHoliday(const Date& date) { d_packedCalendar.removeHoliday(date); if (true == isInRange(date) && false == isWeekendDay(date)) { d_nonBusinessDays.assign0(date - firstDate()); } } inline void Calendar::removeHolidayCode(const Date& date, int holidayCode) { d_packedCalendar.removeHolidayCode(date, holidayCode); } inline void Calendar::reserveHolidayCapacity(int numHolidays) { d_packedCalendar.reserveHolidayCapacity(numHolidays); } inline void Calendar::reserveHolidayCodeCapacity(int numHolidayCodes) { d_packedCalendar.reserveHolidayCodeCapacity(numHolidayCodes); } inline void Calendar::setValidRange(const Date& firstDate, const Date& lastDate) { BSLS_PRECONDITIONS_BEGIN(); BSLS_ASSERT(firstDate <= lastDate); BSLS_PRECONDITIONS_END(); if (firstDate <= lastDate) { // For backwards compatibility, 'firstDate > lastDate' results in an // empty calendar (when asserts are not enabled). d_nonBusinessDays.reserveCapacity(lastDate - firstDate + 1); } d_packedCalendar.setValidRange(firstDate, lastDate); synchronizeCache(); } inline void Calendar::unionBusinessDays(const Calendar& other) { unionBusinessDays(other.d_packedCalendar); } inline void Calendar::unionNonBusinessDays(const Calendar& other) { unionNonBusinessDays(other.d_packedCalendar); } // Aspects template <class STREAM> STREAM& Calendar::bdexStreamIn(STREAM& stream, int version) { if (stream) { PackedCalendar inCal(allocator()); inCal.bdexStreamIn(stream, version); if (!stream) { return stream; // RETURN } d_nonBusinessDays.reserveCapacity(inCal.length()); d_packedCalendar.swap(inCal); synchronizeCache(); } return stream; } inline void Calendar::swap(Calendar& other) { // 'swap' is undefined for objects with non-equal allocators. BSLS_PRECONDITIONS_BEGIN(); BSLS_ASSERT(d_packedCalendar.allocator() == other.d_packedCalendar.allocator()); BSLS_PRECONDITIONS_END(); bslalg::SwapUtil::swap(&d_packedCalendar, &other.d_packedCalendar); bslalg::SwapUtil::swap(&d_nonBusinessDays, &other.d_nonBusinessDays); } // ACCESSORS inline Calendar::BusinessDayConstIterator Calendar::beginBusinessDays() const { if (length()) { return Calendar_BusinessDayConstIter(d_nonBusinessDays, firstDate(), firstDate(), false); // RETURN } return endBusinessDays(); } inline Calendar::BusinessDayConstIterator Calendar::beginBusinessDays(const Date& date) const { BSLS_PRECONDITIONS_BEGIN(); BSLS_ASSERT_SAFE(isInRange(date)); BSLS_PRECONDITIONS_END(); return Calendar_BusinessDayConstIter(d_nonBusinessDays, firstDate(), date, false); } inline Calendar::HolidayCodeConstIterator Calendar::beginHolidayCodes(const Date& date) const { return d_packedCalendar.beginHolidayCodes(date); } inline Calendar::HolidayCodeConstIterator Calendar::beginHolidayCodes(const HolidayConstIterator& iter) const { return d_packedCalendar.beginHolidayCodes(iter); } inline Calendar::HolidayConstIterator Calendar::beginHolidays() const { return d_packedCalendar.beginHolidays(); } inline Calendar::HolidayConstIterator Calendar::beginHolidays(const Date& date) const { return d_packedCalendar.beginHolidays(date); } inline Calendar::WeekendDaysTransitionConstIterator Calendar::beginWeekendDaysTransitions() const { return d_packedCalendar.beginWeekendDaysTransitions(); } inline Calendar::BusinessDayConstIterator Calendar::endBusinessDays() const { if (length()) { return BusinessDayConstIterator(d_nonBusinessDays, firstDate(), lastDate(), true); // RETURN } return BusinessDayConstIterator(d_nonBusinessDays, Date() + 1, Date(), true); } inline Calendar::BusinessDayConstIterator Calendar::endBusinessDays(const Date& date) const { BSLS_PRECONDITIONS_BEGIN(); BSLS_ASSERT_SAFE(isInRange(date)); BSLS_PRECONDITIONS_END(); return BusinessDayConstIterator(d_nonBusinessDays, firstDate(), date, true); } inline Calendar::HolidayCodeConstIterator Calendar::endHolidayCodes(const Date& date) const { return d_packedCalendar.endHolidayCodes(date); } inline Calendar::HolidayCodeConstIterator Calendar::endHolidayCodes(const HolidayConstIterator& iter) const { return d_packedCalendar.endHolidayCodes(iter); } inline Calendar::HolidayConstIterator Calendar::endHolidays() const { return d_packedCalendar.endHolidays(); } inline Calendar::HolidayConstIterator Calendar::endHolidays(const Date& date) const { return d_packedCalendar.endHolidays(date); } inline Calendar::WeekendDaysTransitionConstIterator Calendar::endWeekendDaysTransitions() const { return d_packedCalendar.endWeekendDaysTransitions(); } inline const Date& Calendar::firstDate() const { return d_packedCalendar.firstDate(); } inline int Calendar::getNextBusinessDay(Date *nextBusinessDay, const Date& date) const { BSLS_PRECONDITIONS_BEGIN(); BSLS_ASSERT_SAFE(nextBusinessDay); BSLS_ASSERT_SAFE(Date(9999, 12, 31) > date); BSLS_ASSERT_SAFE(isInRange(date + 1)); BSLS_PRECONDITIONS_END(); enum { e_SUCCESS = 0, e_FAILURE = 1 }; int offset = static_cast<int>( d_nonBusinessDays.find0AtMinIndex(date + 1 - firstDate())); if (0 <= offset) { *nextBusinessDay = firstDate() + offset; return e_SUCCESS; // RETURN } return e_FAILURE; } inline Date Calendar::holiday(int index) const { return d_packedCalendar.holiday(index); } inline int Calendar::holidayCode(const Date& date, int index) const { return d_packedCalendar.holidayCode(date, index); } inline bool Calendar::isBusinessDay(const Date& date) const { return !isNonBusinessDay(date); } inline bool Calendar::isHoliday(const Date& date) const { return d_packedCalendar.isHoliday(date); } inline bool Calendar::isInRange(const Date& date) const { return d_packedCalendar.isInRange(date); } inline bool Calendar::isNonBusinessDay(const Date& date) const { BSLS_PRECONDITIONS_BEGIN(); BSLS_ASSERT_SAFE(isInRange(date)); BSLS_PRECONDITIONS_END(); return d_nonBusinessDays[date - firstDate()]; } inline bool Calendar::isWeekendDay(const Date& date) const { return d_packedCalendar.isWeekendDay(date); } inline bool Calendar::isWeekendDay(DayOfWeek::Enum dayOfWeek) const { return d_packedCalendar.isWeekendDay(dayOfWeek); } inline const Date& Calendar::lastDate() const { return d_packedCalendar.lastDate(); } inline int Calendar::length() const { return static_cast<int>(d_nonBusinessDays.length()); } inline int Calendar::numBusinessDays() const { return static_cast<int>(d_nonBusinessDays.num0()); } inline int Calendar::numBusinessDays(const Date& beginDate, const Date& endDate) const { BSLS_PRECONDITIONS_BEGIN(); BSLS_ASSERT_SAFE(isInRange(beginDate)); BSLS_ASSERT_SAFE(isInRange(endDate)); BSLS_ASSERT_SAFE(beginDate <= endDate); BSLS_PRECONDITIONS_END(); return static_cast<int>(d_nonBusinessDays.num0(beginDate - firstDate(), endDate - firstDate() + 1)); } inline int Calendar::numHolidayCodes(const Date& date) const { return d_packedCalendar.numHolidayCodes(date); } inline int Calendar::numHolidayCodesTotal() const { return d_packedCalendar.numHolidayCodesTotal(); } inline int Calendar::numHolidays() const { return d_packedCalendar.numHolidays(); } inline int Calendar::numNonBusinessDays() const { return static_cast<int>(d_nonBusinessDays.num1()); } inline int Calendar::numWeekendDaysInRange() const { return d_packedCalendar.numWeekendDaysInRange(); } inline int Calendar::numWeekendDaysTransitions() const { return d_packedCalendar.numWeekendDaysTransitions(); } inline const PackedCalendar& Calendar::packedCalendar() const { return d_packedCalendar; } inline Calendar::BusinessDayConstReverseIterator Calendar::rbeginBusinessDays() const { return BusinessDayConstReverseIterator(endBusinessDays()); } inline Calendar::BusinessDayConstReverseIterator Calendar::rbeginBusinessDays(const Date& date) const { BSLS_ASSERT_SAFE(isInRange(date)); return BusinessDayConstReverseIterator(endBusinessDays(date)); } inline Calendar::HolidayCodeConstReverseIterator Calendar::rbeginHolidayCodes(const Date& date) const { return d_packedCalendar.rbeginHolidayCodes(date); } inline Calendar::HolidayCodeConstReverseIterator Calendar::rbeginHolidayCodes(const HolidayConstIterator& iter) const { return d_packedCalendar.rbeginHolidayCodes(iter); } inline Calendar::HolidayConstReverseIterator Calendar::rbeginHolidays() const { return d_packedCalendar.rbeginHolidays(); } inline Calendar::HolidayConstReverseIterator Calendar::rbeginHolidays(const Date& date) const { return d_packedCalendar.rbeginHolidays(date); } inline Calendar::WeekendDaysTransitionConstReverseIterator Calendar::rbeginWeekendDaysTransitions() const { return d_packedCalendar.rbeginWeekendDaysTransitions(); } inline Calendar::BusinessDayConstReverseIterator Calendar::rendBusinessDays() const { return BusinessDayConstReverseIterator(beginBusinessDays()); } inline Calendar::BusinessDayConstReverseIterator Calendar::rendBusinessDays(const Date& date) const { BSLS_ASSERT_SAFE(isInRange(date)); return BusinessDayConstReverseIterator(beginBusinessDays(date)); } inline Calendar::HolidayCodeConstReverseIterator Calendar::rendHolidayCodes(const Date& date) const { return d_packedCalendar.rendHolidayCodes(date); } inline Calendar::HolidayCodeConstReverseIterator Calendar::rendHolidayCodes(const HolidayConstIterator& iter) const { return d_packedCalendar.rendHolidayCodes(iter); } inline Calendar::HolidayConstReverseIterator Calendar::rendHolidays() const { return d_packedCalendar.rendHolidays(); } inline Calendar::HolidayConstReverseIterator Calendar::rendHolidays(const Date& date) const { return d_packedCalendar.rendHolidays(date); } inline Calendar::WeekendDaysTransitionConstReverseIterator Calendar::rendWeekendDaysTransitions() const { return d_packedCalendar.rendWeekendDaysTransitions(); } inline Calendar::WeekendDaysTransition Calendar::weekendDaysTransition(int index) const { return d_packedCalendar.weekendDaysTransition(index); } // Aspects inline bslma::Allocator *Calendar::allocator() const { return d_packedCalendar.allocator(); } template <class STREAM> inline STREAM& Calendar::bdexStreamOut(STREAM& stream, int version) const { d_packedCalendar.bdexStreamOut(stream, version); return stream; } inline bsl::ostream& Calendar::print(bsl::ostream& stream, int level, int spacesPerLevel) const { return d_packedCalendar.print(stream, level, spacesPerLevel); } #ifndef BDE_OMIT_INTERNAL_DEPRECATED // BDE2.22 // DEPRECATED METHODS inline int Calendar::maxSupportedBdexVersion() { return 1; } #endif // BDE_OMIT_INTERNAL_DEPRECATED -- BDE2.22 } // close package namespace // FREE OPERATORS inline bool bdlt::operator==(const Calendar& lhs, const Calendar& rhs) { return lhs.d_packedCalendar == rhs.d_packedCalendar; } inline bool bdlt::operator!=(const Calendar& lhs, const Calendar& rhs) { return lhs.d_packedCalendar != rhs.d_packedCalendar; } inline bsl::ostream& bdlt::operator<<(bsl::ostream& stream, const Calendar& calendar) { calendar.print(stream, 0, -1); return stream; } // FREE FUNCTIONS template <class HASHALG> inline void bdlt::hashAppend(HASHALG& hashAlg, const Calendar& object) { using ::BloombergLP::bslh::hashAppend; hashAppend(hashAlg, object.d_packedCalendar); } namespace bdlt { // ----------------------------------- // class Calendar_BusinessDayConstIter // ----------------------------------- // CREATORS inline Calendar_BusinessDayConstIter::Calendar_BusinessDayConstIter( const Calendar_BusinessDayConstIter& original) : d_nonBusinessDays_p(original.d_nonBusinessDays_p) , d_firstDate(original.d_firstDate) , d_currentOffset(original.d_currentOffset) { } inline Calendar_BusinessDayConstIter::~Calendar_BusinessDayConstIter() { } // MANIPULATORS inline Calendar_BusinessDayConstIter& Calendar_BusinessDayConstIter::operator=( const Calendar_BusinessDayConstIter& rhs) { d_nonBusinessDays_p = rhs.d_nonBusinessDays_p; d_firstDate = rhs.d_firstDate; d_currentOffset = rhs.d_currentOffset; return *this; } inline Calendar_BusinessDayConstIter& Calendar_BusinessDayConstIter::operator++() { BSLS_ASSERT_SAFE(d_currentOffset >= 0); d_currentOffset = static_cast<int>( d_nonBusinessDays_p->find0AtMinIndex(d_currentOffset + 1)); return *this; } inline Calendar_BusinessDayConstIter& Calendar_BusinessDayConstIter::operator--() { if (-1 == d_currentOffset) { d_currentOffset = static_cast<int>(d_nonBusinessDays_p-> find0AtMaxIndex(0, d_nonBusinessDays_p->length())); } else { d_currentOffset = static_cast<int>(d_nonBusinessDays_p-> find0AtMaxIndex(0, d_currentOffset)); } BSLS_ASSERT_SAFE(0 <= d_currentOffset); return *this; } inline Calendar_BusinessDayConstIter operator++( Calendar_BusinessDayConstIter& iterator, int) { Calendar_BusinessDayConstIter tmp(iterator); ++iterator; return tmp; } inline Calendar_BusinessDayConstIter operator--( Calendar_BusinessDayConstIter& iterator, int) { Calendar_BusinessDayConstIter tmp(iterator); --iterator; return tmp; } // ACCESSORS inline PackedCalendar_DateRef Calendar_BusinessDayConstIter::operator*() const { return PackedCalendar_DateRef(d_firstDate + d_currentOffset); } inline PackedCalendar_DateProxy Calendar_BusinessDayConstIter::operator->() const { return PackedCalendar_DateProxy(this->operator*()); } } // close package namespace // FREE OPERATORS inline bool bdlt::operator==(const Calendar_BusinessDayConstIter& lhs, const Calendar_BusinessDayConstIter& rhs) { BSLS_ASSERT_SAFE(lhs.d_nonBusinessDays_p == rhs.d_nonBusinessDays_p); return lhs.d_firstDate == rhs.d_firstDate && lhs.d_currentOffset == rhs.d_currentOffset; } inline bool bdlt::operator!=(const Calendar_BusinessDayConstIter& lhs, const Calendar_BusinessDayConstIter& rhs) { BSLS_ASSERT_SAFE(lhs.d_nonBusinessDays_p == rhs.d_nonBusinessDays_p); return lhs.d_firstDate != rhs.d_firstDate || lhs.d_currentOffset != rhs.d_currentOffset; } } // close enterprise namespace // TRAITS namespace BloombergLP { namespace bslma { template <> struct UsesBslmaAllocator<bdlt::Calendar> : bsl::true_type {}; } // close namespace bslma } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2018 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------