// bdlt_dayofweekset.h                                                -*-C++-*-
#ifndef INCLUDED_BDLT_DAYOFWEEKSET
#define INCLUDED_BDLT_DAYOFWEEKSET

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide an ordered set of (unique) 'bdlt::DayOfWeek::Enum' values.
//
//@CLASSES:
//  bdlt::DayOfWeekSet: ordered set of (unique) 'bdlt::DayOfWeek::Enum' values
//
//@SEE_ALSO: bdlt_dayofweek
//
//@DESCRIPTION: This component implements an efficient value-semantic, ordered
// set class, 'bdlt::DayOfWeekSet', for elements of the 'bdlt::DayOfWeek::Enum'
// enumeration.  As there are only seven possible element values, asymptotic
// performance characterization is not appropriate; all operations implicitly
// run in constant time and provide the no-throw guarantee.
//
///Supplementary Overloaded Operators
///----------------------------------
// In addition to the standard value-semantic operators '=', '==', '!=', and
// '<<', the following canonical set of binary and unary (free) operators are
// defined on 'bdlt::DayOfWeekSet' objects:
//..
//                   set S: { e_MON, e_TUE, e_WED }
//                   set T: { e_MON, e_WED, e_FRI }
//
//           Union:  S | T  { e_MON, e_TUE, e_WED, e_FRI }
//
//    Intersection:  S & T  { e_MON, e_WED }
//
//    Exclusive Or:  S ^ T  { e_TUE, e_FRI }
//
//     Subtraction:  S - T  { e_TUE }
//                   T - S  { e_FRI }
//
//  Unary Negation:     ~S  { e_SUN, e_THU, e_FRI, e_SAT }
//                      ~T  { e_SUN, e_TUE, e_THU, e_SAT }
//..
// The corresponding assignment (member) operators '|=' , '&=', '^=', and '-='
// (but not '~=') are also provided.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Manipulation and Traversal of Day of Week Sets
///- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// A 'bdlt::DayOfWeekSet' is useful for recording recurring appointments, or
// special days (e.g., weekend days), in a calendar.  The following snippets of
// code illustrate how to create and use a 'bdlt::DayOfWeek' set.
//
// First, we create a couple of commonly useful sets.  First we define the
// 'bdlt::DayOfWeekSet' 'weekendDays':
//..
//  bdlt::DayOfWeekSet weekendDays;
//..
// Then, we notice that this set is initially empty.
//..
//  assert(0 == weekendDays.length());
//..
// Next, we add the days that characterize weekends:
//..
//  weekendDays.add(bdlt::DayOfWeek::e_SUN);
//  assert(1 == weekendDays.length());
//
//  weekendDays.add(bdlt::DayOfWeek::e_SAT);
//  assert(2 == weekendDays.length());
//..
// Then, we observe that 'weekendDays' now contains precisely the days we
// expect it to contain:
//..
//  assert(true  == weekendDays.isMember(bdlt::DayOfWeek::e_SUN));
//  assert(false == weekendDays.isMember(bdlt::DayOfWeek::e_MON));
//  assert(false == weekendDays.isMember(bdlt::DayOfWeek::e_TUE));
//  assert(false == weekendDays.isMember(bdlt::DayOfWeek::e_WED));
//  assert(false == weekendDays.isMember(bdlt::DayOfWeek::e_THU));
//  assert(false == weekendDays.isMember(bdlt::DayOfWeek::e_FRI));
//  assert(true  == weekendDays.isMember(bdlt::DayOfWeek::e_SAT));
//..
// Next, we create the complementary 'bdlt::DayOfWeekSet' 'weekDays' directly
// from 'weekendDays' via a combination of unary negation and copy
// construction:
//..
//  bdlt::DayOfWeekSet weekDays(~weekendDays);
//
//  assert(5 == weekDays.length());
//
//  assert(false == weekDays.isMember(bdlt::DayOfWeek::e_SUN));
//  assert(true  == weekDays.isMember(bdlt::DayOfWeek::e_MON));
//  assert(true  == weekDays.isMember(bdlt::DayOfWeek::e_TUE));
//  assert(true  == weekDays.isMember(bdlt::DayOfWeek::e_WED));
//  assert(true  == weekDays.isMember(bdlt::DayOfWeek::e_THU));
//  assert(true  == weekDays.isMember(bdlt::DayOfWeek::e_FRI));
//  assert(false == weekDays.isMember(bdlt::DayOfWeek::e_SAT));
//..
// Then, to create a set containing all of the days in the week, we do so via
// unary negation of the default constructed value:
//..
//  const bdlt::DayOfWeekSet NO_DAYS;
//  const bdlt::DayOfWeekSet ALL_DAYS(~NO_DAYS);
//
//  assert(7 == ALL_DAYS.length());
//..
// Next, we observe that neither 'weekDays' nor 'weekendDays' represent the
// same value as 'ALL_DAYS', but their union does:
//..
//  assert(ALL_DAYS != weekendDays);
//  assert(ALL_DAYS != weekDays);
//  assert(ALL_DAYS == (weekDays | weekendDays));
//  assert(ALL_DAYS == (weekDays ^ weekendDays));
//
//  assert(weekendDays == ALL_DAYS - weekDays);
//
//  assert(weekDays    == ALL_DAYS - weekendDays);
//
//  assert(weekDays    == ALL_DAYS - weekendDays);
//..
// Then, we observe that similarly, neither 'weekDays' nor 'weekendDays'
// represents the same value as 'NO_DAYS', but their intersection does:
//..
//  assert(NO_DAYS != weekendDays);
//  assert(NO_DAYS != weekDays);
//  assert(NO_DAYS == (weekDays & weekendDays));
//
//  assert(weekendDays == weekendDays - weekDays);
//
//  assert(weekDays    == weekDays - weekendDays);
//..
// Next, we create the corresponding set 'eDays' consisting of the only days of
// the week that have an 'E' in them: 'TUESDAY' and 'WEDNESDAY':
//..
//  bdlt::DayOfWeekSet eDays;                 assert(0 == eDays.length());
//  eDays.add(bdlt::DayOfWeek::e_TUE);     assert(1 == eDays.length());
//  eDays.add(bdlt::DayOfWeek::e_WED);     assert(2 == eDays.length());
//
//  assert(false == eDays.isMember(bdlt::DayOfWeek::e_SUN));
//  assert(false == eDays.isMember(bdlt::DayOfWeek::e_MON));
//  assert(true  == eDays.isMember(bdlt::DayOfWeek::e_TUE));
//  assert(true  == eDays.isMember(bdlt::DayOfWeek::e_WED));
//  assert(false == eDays.isMember(bdlt::DayOfWeek::e_THU));
//  assert(false == eDays.isMember(bdlt::DayOfWeek::e_FRI));
//  assert(false == eDays.isMember(bdlt::DayOfWeek::e_SAT));
//..
// Then, we create a set consisting of days that have an 'n' in them: 'MONDAY',
// 'WEDNESDAY', and 'SUNDAY'.  We create the corresponding set 'nDays' starting
// with the value of 'eDays' by first removing 'TUESDAY', and then adding
// 'SUNDAY' and 'MONDAY':
//..
//  bdlt::DayOfWeekSet nDays(eDays);          assert(2 == nDays.length());
//
//  nDays.remove(bdlt::DayOfWeek::e_TUE);  assert(1 == nDays.length());
//
//  nDays.add(bdlt::DayOfWeek::e_SUN);     assert(2 == nDays.length());
//  nDays.add(bdlt::DayOfWeek::e_MON);     assert(3 == nDays.length());
//
//  assert(true  == nDays.isMember(bdlt::DayOfWeek::e_SUN));
//  assert(true  == nDays.isMember(bdlt::DayOfWeek::e_MON));
//  assert(false == nDays.isMember(bdlt::DayOfWeek::e_TUE));
//  assert(true  == nDays.isMember(bdlt::DayOfWeek::e_WED));
//  assert(false == nDays.isMember(bdlt::DayOfWeek::e_THU));
//  assert(false == nDays.isMember(bdlt::DayOfWeek::e_FRI));
//  assert(false == nDays.isMember(bdlt::DayOfWeek::e_SAT));
//..
// Next, we observe that all 'eDays' are 'weekDays', but that's not true of
// 'nDays':
//..
//  assert(true  == weekDays.areMembers(eDays));
//  assert(false == weekDays.areMembers(nDays));
//..
// Now, we observe that iteration order is defined by increasing enumerated
// 'bdlt::DayOfWeek::Day' value '[ SUN .. SAT ]'.  The following use of the
// *forward* (bi-directional) iterator:
//..
//  for (bdlt::DayOfWeekSet::iterator it  = ALL_DAYS.begin();
//                                    it != ALL_DAYS.end();
//                                    ++it) {
//      bsl::cout << *it << bsl::endl;
//  }
//..
// produces:
//..
//  SUN
//  MON
//  TUE
//  WED
//  THU
//  FRI
//  SAT
//..
// on standard output.
//
// Finally, we observe that, similarly, the following use of the *reverse*
// iterator:
//..
//  for (bdlt::DayOfWeekSet::reverse_iterator it  = weekDays.rbegin();
//                                            it != weekDays.rend();
//                                            ++it) {
//      bsl::cout << *it << bsl::endl;
//  }
//..
// produces:
//..
//  FRI
//  THU
//  WED
//  TUE
//  MON
//..

#include <bdlscm_version.h>

#include <bdlt_dayofweek.h>

#include <bdlb_bitutil.h>

#include <bslh_hash.h>

#include <bslmf_integralconstant.h>
#include <bslmf_isbitwisemoveable.h>

#include <bsls_assert.h>
#include <bsls_libraryfeatures.h>
#include <bsls_review.h>

#include <bsl_cstddef.h>
#include <bsl_iosfwd.h>
#include <bsl_iterator.h>

namespace BloombergLP {
namespace bdlt {

                          // =======================
                          // class DayOfWeekSet_Iter
                          // =======================

class DayOfWeekSet_Iter
#if defined(BSLS_LIBRARYFEATURES_STDCPP_LIBCSTD)
// Sun CC workaround: iterators must be derived from 'std::iterator' to work
// with the native std library algorithms.  However, 'std::iterator' is
// deprecated in C++17, so do not rely on derivation unless required, to avoid
// deprecation warnings on modern compilers.
    : public bsl::iterator<bsl::bidirectional_iterator_tag,
                                               const DayOfWeek::Enum>
#endif  // BSLS_LIBRARYFEATURES_STDCPP_LIBCSTD
{
    // Implementation of standard bidirectional iterator for 'DayOfWeekSet'.
    // Any modification of a 'DayOfWeekSet' will invalidate any iterators
    // referring to that 'DayOfWeekSet'.

  public:
    // PUBLIC TYPES
    typedef bsl::bidirectional_iterator_tag  iterator_category;
    typedef DayOfWeek::Enum                  value_type;
    typedef bsl::ptrdiff_t                   difference_type;
    typedef const DayOfWeek::Enum           *pointer;
    typedef const DayOfWeek::Enum&           reference;

    // CLASS DATA
    static const DayOfWeek::Enum s_dayOfWeekArray[9];  // = { ???, SUN, ...

    // DATA
    unsigned char d_data;       // copy of days of the week from the original
                                // container
    signed char   d_index;      // current position in the iteration; value
                                // '[0 .. 8]'

    // FRIENDS
    friend bool operator==(const DayOfWeekSet_Iter&, const DayOfWeekSet_Iter&);

  public:
    // CREATORS
    DayOfWeekSet_Iter();
        // Create a default (invalid) iterator.

    DayOfWeekSet_Iter(int data, int index);
        // Create an iterator using the specified 'data' and 'index'.  If
        // 'index' is 1, this iterator references the first valid element of
        // 'data'; if 'index' is 8, then this iterator references one past the
        // last possible element in 'data'.  The behavior is undefined unless
        // '0 == (data & 1)', 'index >= 0', and 'index <= 8'.

    DayOfWeekSet_Iter(const DayOfWeekSet_Iter& original);
        // Create an iterator having the value of the specified 'original'
        // iterator.

    ~DayOfWeekSet_Iter();
        // Destroy this iterator.

    // MANIPULATORS
    DayOfWeekSet_Iter& operator=(const DayOfWeekSet_Iter& rhs);
        // Assign to this iterator the value of the specified 'rhs' iterator,
        // and return a reference providing modifiable access to this iterator.

    DayOfWeekSet_Iter& operator++();
        // Advance this iterator to the next valid data element, and return a
        // reference providing modifiable access to this iterator.  If there is
        // no next valid data element, this iterator will be set equal to
        // 'end()'.

    DayOfWeekSet_Iter operator++(int);
        // Advance this iterator to the next valid data element, and return by
        // value the value of this iterator before it was incremented.  If
        // there is no next valid data element, this iterator will be set equal
        // to 'end()'.

    DayOfWeekSet_Iter& operator--();
        // Regress this iterator to the previous valid data element, and return
        // a reference providing modifiable access to this iterator.  If there
        // is no preceding data element, the value of 'reverse_iterator(*this)'
        // will be 'rend()'.

    DayOfWeekSet_Iter operator--(int);
        // Regress this iterator to the previous valid data element, and return
        // by value the value of this iterator before it was decremented.  If
        // there is no preceding data element, the value of
        // 'reverse_iterator(*this)' will be 'rend()'.

    // ACCESSORS
    const DayOfWeek::Enum& operator*() const;
        // Return a reference providing non-modifiable access to the day of
        // week value referenced by this iterator.  The behavior is undefined
        // unless the iterator refers to a valid day of the week, specifically,
        // the behavior is undefined if '*this == end()'.
};

// FREE OPERATORS
bool operator==(const DayOfWeekSet_Iter& lhs, const DayOfWeekSet_Iter& rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' iterators have the same
    // value, and 'false' otherwise.  Two iterators have the same value if they
    // refer to data at the same index position.  The behavior is undefined
    // unless 'lhs' and 'rhs' both reference into the same set of data.

bool operator!=(const DayOfWeekSet_Iter& lhs, const DayOfWeekSet_Iter& rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' iterators do not have the
    // same value, and 'false' otherwise.  Two iterators do not have the same
    // value if they do not refer to data at the same index position.  The
    // behavior is undefined unless 'lhs' and 'rhs' both reference into the
    // same set of data.

                          // ==================
                          // class DayOfWeekSet
                          // ==================

class DayOfWeekSet {
    // This class implements an efficient value-semantic, ordered set of
    // 'DayOfWeek' values.  This set requires a fixed capacity, and all
    // operations operate in constant time, and provide the no-throw guarantee.

    // DATA
    unsigned char d_days;  // bits '1 .. 7' reflect '[ SUN, MON, ..., SAT ]';
                           // bit 0 is unused

    // FRIENDS
    friend bool operator==(const DayOfWeekSet&, const DayOfWeekSet&);
    friend bool operator!=(const DayOfWeekSet&, const DayOfWeekSet&);
    friend DayOfWeekSet operator~(const DayOfWeekSet&);
    template <class HASHALG>
    friend void hashAppend(HASHALG& hashAlg, const DayOfWeekSet&);

  public:
    // TYPES
    typedef DayOfWeekSet_Iter iterator;
        // Standard nested alias for set container's iterator.

    typedef iterator const_iterator;
        // Standard nested alias for set container's constant iterator.

    typedef bsl::reverse_iterator<iterator> reverse_iterator;
        // Standard nested alias for set container's reverse iterator.

    typedef reverse_iterator const_reverse_iterator;
        // Standard nested alias for set container's constant reverse iterator.

    // 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
    DayOfWeekSet();
        // Create an empty set.

    DayOfWeekSet(const DayOfWeekSet& original);
        // Create a set initialized to the value of the specified 'original'
        // set.

    ~DayOfWeekSet();
        // Destroy this object.

    // MANIPULATORS
    DayOfWeekSet& operator=(const DayOfWeekSet& rhs);
        // Assign to this set the value of the specified 'rhs' set, and return
        // a reference providing modifiable access to this set.

    DayOfWeekSet& operator|=(const DayOfWeekSet& rhs);
        // Assign to this set the union of this set with the specified 'rhs'
        // set (i.e., a set containing elements that are in either this set or
        // the 'rhs' set, or in both sets), and return a reference providing
        // modifiable access to this set.

    DayOfWeekSet& operator&=(const DayOfWeekSet& rhs);
        // Assign to this set the intersection of this set with the specified
        // 'rhs' set (i.e., a set containing elements that are in both this
        // set and the 'rhs' set), and return a reference providing modifiable
        // access to this set.

    DayOfWeekSet& operator^=(const DayOfWeekSet& rhs);
        // Assign to this set the exclusive-or of this set with the specified
        // 'rhs' set (i.e., a set containing elements that are either in this
        // set, but not 'rhs', or in 'rhs', but not in this set), and return a
        // reference providing modifiable access to this set.

    DayOfWeekSet& operator-=(const DayOfWeekSet& rhs);
        // Assign to this set the subtraction of the specified 'rhs' set from
        // this set (i.e., a set containing elements that are in this set, but
        // not in the 'rhs' set), and return a reference providing modifiable
        // access to this set.

    void add(DayOfWeek::Enum value);
        // Add the specified 'value' to this set.

    bool remove(DayOfWeek::Enum value);
        // Remove the specified 'value' from this set.  Return 'true' if
        // 'value' was a member of this set, and 'false' otherwise.

    void removeAll();
        // Remove all members of this set.

                                  // 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 'stream'.  If 'stream' is initially invalid, this
        // operation has no effect.  If 'version' is not supported, this object
        // is unaltered and 'stream' is invalidated, but otherwise unmodified.
        // If 'version' is supported but 'stream' becomes invalid during this
        // operation, this object has an undefined, but valid, state.  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.

    // ACCESSORS
    bool areMembers(const DayOfWeekSet& set) const;
        // Return 'true' if this set contains all elements of the specified
        // 'set', and 'false' otherwise.

    iterator begin() const;
        // Return an iterator referencing the first valid element in this set.

    iterator end() const;
        // Return an iterator indicating one position past the last possible
        // element in this set.

    bool isEmpty() const;
        // Return 'true' if there are no elements in this set, and 'false'
        // otherwise.

    bool isMember(DayOfWeek::Enum value) const;
        // Return 'true' if the specified 'value' is an element of this set,
        // and 'false' otherwise.

    int length() const;
        // Return the number of elements in this set.

    reverse_iterator rbegin() const;
        // Return a reverse iterator referencing the last valid element in this
        // set.

    reverse_iterator rend() const;
        // Return a reverse iterator indicating one position before the first
        // possible element in this set.

                                  // Aspects

    template <class STREAM>
    STREAM& bdexStreamOut(STREAM& stream, int version) const;
        // Write the value of this object, using the specified 'version'
        // format, to the specified output 'stream', and return a reference to
        // 'stream'.  If 'stream' is initially invalid, this operation has no
        // effect.  If 'version' is not supported, 'stream' is invalidated, but
        // otherwise 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 '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_OPENSOURCE_PUBLICATION  // pending deprecation

    static int maxSupportedBdexVersion();
        // !DEPRECATED!: Use 'maxSupportedBdexVersion(int)' instead.
        //
        // Return the most current BDEX streaming version number supported by
        // this class.

#endif // BDE_OPENSOURCE_PUBLICATION -- pending deprecation

};

// FREE OPERATORS
DayOfWeekSet operator~(const DayOfWeekSet& set);
    // Return a set containing the complement of the specified 'set' (i.e.,
    // those members *not* contained in 'set').

DayOfWeekSet operator|(const DayOfWeekSet& lhs, const DayOfWeekSet& rhs);
    // Return a set containing the union of the specified 'lhs' and 'rhs' sets
    // (i.e., a set containing elements that are in either 'lhs' or 'rhs' or
    // both).

DayOfWeekSet operator&(const DayOfWeekSet& lhs, const DayOfWeekSet& rhs);
    // Return a set containing the intersection of the specified 'lhs' and
    // 'rhs' sets (i.e., a set containing elements that are in both 'lhs' and
    // 'rhs').

DayOfWeekSet operator^(const DayOfWeekSet& lhs, const DayOfWeekSet& rhs);
    // Return a set containing the exclusive-or of the specified 'lhs' and
    // 'rhs' sets (i.e., a set containing elements that are either in 'lhs',
    // but not 'rhs', or in 'rhs', but not 'lhs').

DayOfWeekSet operator-(const DayOfWeekSet& lhs, const DayOfWeekSet& rhs);
    // Return a set containing the subtraction of the specified 'rhs' set from
    // the specified 'lhs' set (i.e., a set containing elements that are in
    // 'lhs', but not in 'rhs').

bool operator==(const DayOfWeekSet& lhs, const DayOfWeekSet& rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' sets have the same value,
    // and 'false' otherwise.  Two sets have the same value if they have the
    // same length and all the elements of one set are members of the other
    // set.

bool operator!=(const DayOfWeekSet& lhs, const DayOfWeekSet& rhs);
    // Return 'true' if the specified 'lhs' and 'rhs' sets do not have the same
    // value, and 'false' otherwise.  Two sets do not have the same value if
    // they differ in length or there exists an element of one set that is not
    // a member of the other set.

bsl::ostream& operator<<(bsl::ostream& stream, const DayOfWeekSet& rhs);
    // Write the specified 'rhs' set to the specified output 'stream' in some
    // reasonable (single-line) format, and return a reference to 'stream'.

// FREE FUNCTIONS
template <class HASHALG>
void hashAppend(HASHALG& hashAlg, const DayOfWeekSet& 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 'DayOfWeekSet'.

// ============================================================================
//                            INLINE DEFINITIONS
// ============================================================================

                          // -----------------------
                          // class DayOfWeekSet_Iter
                          // -----------------------

// CREATORS
inline
DayOfWeekSet_Iter::DayOfWeekSet_Iter()
: d_data(0)
, d_index(8)
{
}

inline
DayOfWeekSet_Iter::DayOfWeekSet_Iter(const DayOfWeekSet_Iter& original)
: d_data(original.d_data)
, d_index(original.d_index)
{
}

inline
DayOfWeekSet_Iter::~DayOfWeekSet_Iter()
{
    BSLS_ASSERT(0 == (d_data & 1));  // lsb is unused and always 0
    BSLS_ASSERT(d_index >= 0);
    BSLS_ASSERT(d_index <= 8);
}

// MANIPULATORS
inline
DayOfWeekSet_Iter&
DayOfWeekSet_Iter::operator=(const DayOfWeekSet_Iter& rhs)
{
    d_data  = rhs.d_data;
    d_index = rhs.d_index;
    return *this;
}

inline
DayOfWeekSet_Iter DayOfWeekSet_Iter::operator++(int)
{
    DayOfWeekSet_Iter tmp(*this);
    this->operator++();
    return tmp;
}

inline
DayOfWeekSet_Iter DayOfWeekSet_Iter::operator--(int)
{
    DayOfWeekSet_Iter tmp(*this);
    this->operator--();
    return tmp;
}

// ACCESSORS
inline
const DayOfWeek::Enum& DayOfWeekSet_Iter::operator*() const
{
    BSLS_ASSERT_SAFE(d_index >= 1);
    BSLS_ASSERT_SAFE(d_index <= 7);

    return s_dayOfWeekArray[d_index];
}

}  // close package namespace

// FREE OPERATORS
inline
bool bdlt::operator==(const DayOfWeekSet_Iter& lhs,
                      const DayOfWeekSet_Iter& rhs)
{
    BSLS_ASSERT_SAFE(lhs.d_data == rhs.d_data);

    // If the data is not the same, either the objects were not initially the
    // same, or one has subsequently been modified.

    return lhs.d_index == rhs.d_index;
}

inline
bool bdlt::operator!=(const DayOfWeekSet_Iter& lhs,
                      const DayOfWeekSet_Iter& rhs)
{
    return !(lhs == rhs);
}

namespace bdlt {

                             // ------------------
                             // class DayOfWeekSet
                             // ------------------

// CLASS METHODS

                                  // Aspects

inline
int DayOfWeekSet::maxSupportedBdexVersion(int /* versionSelector */)
{
    return 1;
}

// CREATORS
inline
DayOfWeekSet::DayOfWeekSet()
: d_days(0)
{
}

inline
DayOfWeekSet::DayOfWeekSet(const DayOfWeekSet& original)
: d_days(original.d_days)
{
}

inline
DayOfWeekSet::~DayOfWeekSet()
{
    BSLS_ASSERT(!(d_days & 1));
}

// MANIPULATORS
inline
DayOfWeekSet& DayOfWeekSet::operator=(const DayOfWeekSet& rhs)
{
    d_days = rhs.d_days;
    return *this;
}

inline
DayOfWeekSet& DayOfWeekSet::operator|=(const DayOfWeekSet& rhs)
{
    d_days = static_cast<unsigned char>(d_days | rhs.d_days);
    return *this;
}

inline
DayOfWeekSet& DayOfWeekSet::operator&=(const DayOfWeekSet& rhs)
{
    d_days = static_cast<unsigned char>(d_days & rhs.d_days);
    return *this;
}

inline
DayOfWeekSet& DayOfWeekSet::operator^=(const DayOfWeekSet& rhs)
{
    d_days = static_cast<unsigned char>(d_days ^ rhs.d_days);
    return *this;
}

inline
DayOfWeekSet& DayOfWeekSet::operator-=(const DayOfWeekSet& rhs)
{
    const int mask = d_days & rhs.d_days;
    d_days = static_cast<unsigned char>(d_days - mask);
    return *this;
}

inline
void DayOfWeekSet::add(DayOfWeek::Enum value)
{
    d_days = static_cast<unsigned char>(d_days | (1 << value));
}

inline
bool DayOfWeekSet::remove(DayOfWeek::Enum value)
{
    const int  mask = 1 << value;
    const bool rv   = d_days & mask;
    d_days &= static_cast<unsigned char>(~mask);
    return rv;
}

inline
void DayOfWeekSet::removeAll()
{
    d_days = 0;
}

                                  // Aspects

template <class STREAM>
STREAM& DayOfWeekSet::bdexStreamIn(STREAM& stream, int version)
{
    if (stream) {
        switch (version) { // switch on the schema version
          case 1: {
            unsigned char tmp;
            stream.getUint8(tmp);

            if (stream && 0 == (tmp & 1)) {
                d_days = tmp;
            }
            else {
                stream.invalidate();
            }
          } break;
          default: {
            stream.invalidate();  // unrecognized version number
          }
        }
    }
    return stream;
}

// ACCESSORS
inline
bool DayOfWeekSet::areMembers(const DayOfWeekSet& set) const
{
    return set.d_days == (d_days & set.d_days);
}

inline
DayOfWeekSet::iterator DayOfWeekSet::begin() const
{
    return DayOfWeekSet::iterator(DayOfWeekSet_Iter(d_days, 1));
}

inline
DayOfWeekSet::iterator DayOfWeekSet::end() const
{
    return DayOfWeekSet::iterator(DayOfWeekSet_Iter(d_days, 8));
}

inline
bool DayOfWeekSet::isEmpty() const
{
    return 0 == d_days;
}

inline
bool DayOfWeekSet::isMember(DayOfWeek::Enum value) const
{
    const int mask = 1 << value;
    return mask == (d_days & mask);
}

inline
int DayOfWeekSet::length() const
{
    return bdlb::BitUtil::numBitsSet(static_cast<unsigned int>(d_days));
}

inline
DayOfWeekSet::reverse_iterator DayOfWeekSet::rbegin() const
{
    return DayOfWeekSet::reverse_iterator(end());
}

inline
DayOfWeekSet::reverse_iterator DayOfWeekSet::rend() const
{
    return DayOfWeekSet::reverse_iterator(begin());
}

                                  // Aspects

template <class STREAM>
STREAM& DayOfWeekSet::bdexStreamOut(STREAM& stream, int version) const
{
    if (stream) {
        switch (version) { // switch on the schema version
          case 1: {
            stream.putUint8(d_days);
          } break;
          default: {
            stream.invalidate();  // unrecognized version number
          }
        }
    }
    return stream;
}

#ifndef BDE_OPENSOURCE_PUBLICATION  // pending deprecation

inline
int DayOfWeekSet::maxSupportedBdexVersion()
{
    return maxSupportedBdexVersion(0);
}

#endif // BDE_OPENSOURCE_PUBLICATION -- pending deprecation

}  // close package namespace

// FREE OPERATORS
inline
bdlt::DayOfWeekSet bdlt::operator~(const DayOfWeekSet& set)
{
    DayOfWeekSet tmp(set);
    tmp.d_days = static_cast<unsigned char>(~tmp.d_days & 0xfe);
    return tmp;
}

inline
bool bdlt::operator==(const DayOfWeekSet& lhs, const DayOfWeekSet& rhs)
{
    return lhs.d_days == rhs.d_days;
}

inline
bool bdlt::operator!=(const DayOfWeekSet& lhs, const DayOfWeekSet& rhs)
{
    return lhs.d_days != rhs.d_days;
}

inline
bdlt::DayOfWeekSet bdlt::operator|(const DayOfWeekSet& lhs,
                                   const DayOfWeekSet& rhs)
{
    return DayOfWeekSet(lhs) |= rhs;
}

inline
bdlt::DayOfWeekSet bdlt::operator&(const DayOfWeekSet& lhs,
                                   const DayOfWeekSet& rhs)
{
    return DayOfWeekSet(lhs) &= rhs;
}

inline
bdlt::DayOfWeekSet bdlt::operator^(const DayOfWeekSet& lhs,
                                   const DayOfWeekSet& rhs)
{
    return DayOfWeekSet(lhs) ^= rhs;
}

inline
bdlt::DayOfWeekSet bdlt::operator-(const DayOfWeekSet& lhs,
                                   const DayOfWeekSet& rhs)
{
    return DayOfWeekSet(lhs) -= rhs;
}

inline
bsl::ostream& bdlt::operator<<(bsl::ostream& stream, const DayOfWeekSet& rhs)
{
    return rhs.print(stream, 0, -1);
}

// FREE FUNCTIONS
template <class HASHALG>
inline
void bdlt::hashAppend(HASHALG& hashAlg, const DayOfWeekSet& object)
{
    using ::BloombergLP::bslh::hashAppend;
    hashAppend(hashAlg, object.d_days);
}

// TRAITS SPECIALIZATIONS
namespace bslmf {
template <>
struct IsBitwiseMoveable<bdlt::DayOfWeekSet> : ::bsl::true_type {};
}

}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2014 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 ----------------------------------