#if !defined HAVE_BIT_SL_GRAY_H__
#define      HAVE_BIT_SL_GRAY_H__
// This file is part of the FXT library.
// Copyright (C) 2012 Joerg Arndt
// License: GNU General Public License version 3 or later,
// see the file COPYING.txt in the main directory.

#include "fxttypes.h"


// Cf. comb/binary-sl-gray.h for generation in an array.
// Cf. bits/bitlex.h for subset-lex order.


class bit_sl_gray
// Binary words in a minimal-change order
// related so subset-lex order ("SL-Gray" order).
// Successive transitions are mostly adjacent (on-close),
// and otherwise have distance 3 (three-close).
{
public:
    bool dt_;  // direction to which track tries to move: true== try move right
    ulong x_;  // Gray code word
    ulong tr_; // current track (a one-bit word)
    ulong h_;  // highest allowed track

public:
    bit_sl_gray(ulong ldn)  { init(ldn); }
    ~bit_sl_gray()  { ; }

    void init(ulong ldn)
    {
        tr_ = 1UL << (ldn-1);
        h_ = tr_;
        dt_ = true;
        x_ = 0;
        if ( ldn == 0 )  // make things work for ldn==0
        {
            h_ = 0;
            dt_ = false;
        }
    }

    ulong data()  const  { return x_; }

    ulong next()
    {
        if ( dt_ )  // try to append trailing ones
        {
            if ( (x_ & tr_) == 0 )  // can append
            {
                x_ ^= tr_;
                if ( tr_>>1 )  tr_ >>= 1;
            }
            else  // change one track left
            {
                dt_ = false;
                tr_ = 1;
                if ( tr_ >= h_ )  return false; // current is last (only for n_ <= 1)
                x_ ^= (tr_ << 1);
            }
        }
        else // try to remove trailing ones
        {
            if ( (x_ & (tr_<<1)) != 0 )  // can remove
            {
                x_ ^= tr_;
                tr_ <<= 1;
            }
            else  // change three tracks left
            {
                if ( h_ <= tr_<<1 )  { x_ = 0;  return 0; }  // current is last
                dt_ = true;
                x_ ^= (tr_ << 2);
                if ( tr_>>1 )  tr_ >>= 1;
            }
        }

        return x_;
    }
};
// -------------------------


#endif // !defined HAVE_BIT_SL_GRAY_H__
