
// Copyright {Jagger Software Limited} 2003

#include "grammar/bound.hpp"

#include "container/compare.hpp"
#include <iostream>

using namespace ::std;

namespace grammar // bound - 'tors
{
    bound::bound(size_t initially)
        : value(initially)
        , is_infinity(false)
    {
    }

    bound::bound(infinity_type)
        : value(static_cast<size_t>(~0))
        , is_infinity(true)
    {
        // value must be initialized to ensure all infinities compare equal
    }
}

namespace grammar // bound - increment
{      
    bound & bound::operator++()
    {
        // Don't change infinite values. If you do 
        // two infinities won't compare equal.

        if (!is_infinity)
        {
            ++value; // don't check for overflow
        }

        return *this;
    }

    const bound bound::operator++(int)
    {
        const bound old_self = *this;
        operator++();
        return old_self;
    }
}


namespace grammar // bound - primitives
{
    int bound::compare(const bound & other) const
    {
        int result;

        if (is_infinity == other.is_infinity)
        {
            result = ::container::compare(value, other.value);
        }
        else
        {
            using namespace ::container;        
            result = is_infinity ? greater : less;
        }

        return result;
    }

    void bound::write(ostream & out) const
    {
        // Don't implement as
        //
        //     out << (is_infinity ? '*' : value);
        //
        // because it coerces '*' into a size_t.

        if (is_infinity)
        {
            out << '*';
        }
        else
        {
            out << value;
        }
    }
}

namespace grammar // bound - idiomatic operators
{
    bool operator==(const bound & lhs, const bound & rhs)
    {
        return lhs.compare(rhs) == 0;
    }
    
    bool operator!=(const bound & lhs, const bound & rhs)
    {
        return lhs.compare(rhs) != 0;
    }
    
    bool operator< (const bound & lhs, const bound & rhs)
    {
        return lhs.compare(rhs) < 0;
    }
    
    bool operator<=(const bound & lhs, const bound & rhs)
    {
        return lhs.compare(rhs) <= 0;
    }
    
    bool operator> (const bound & lhs, const bound & rhs)
    {
        return lhs.compare(rhs) > 0;
    }
    
    bool operator>=(const bound & lhs, const bound & rhs)
    {
        return lhs.compare(rhs) >= 0;
    }
    
    ostream & operator<<(ostream & out, const bound & to_write)
    {
        to_write.write(out);
        return out;
    }
}

