// Digit sequence level random number generator.

// General includes.
#include "cl_sysdep.h"

// Specification.
#include "cl_random_impl.h"


// Implementation.

#include "cln/random.h"
#include "cl_DS.h"
#include "cl_low.h"

namespace cln {

void testrandom_UDS (random_state& randomstate, uintD* MSDptr, uintC len)
{
  // Idea from Torbjörn Granlund, see his "random2.c" file in gmp 2.0.
  var uintD* ptr = MSDptr mspop len;
  DS_clear_loop(MSDptr,len,ptr);
  var uintL bit_pos = 0;
  var uint32 ran = 0;
  var uintC ran_bits = 0;
  while (bit_pos < intDsize*(uintL)len)
    { if (ran_bits < log2_intDsize+1)
        { ran = random32(randomstate); ran_bits = 32; }
      var uintL n_bits = (ran >> 1) % intDsize + 1; // number of bits
      if (ran & 1)
        { // put in a bit string of n_bits bits at position bit_pos.
          if (bit_pos + n_bits > intDsize*(uintL)len)
            { n_bits = intDsize*(uintL)len - bit_pos; }
          if (bit_pos / intDsize == (bit_pos + n_bits - 1) / intDsize)
            { // need to modify one digit
              lspref(ptr,bit_pos/intDsize) |= (((uintD)1 << n_bits) - 1) << (bit_pos%intDsize);
            }
            else
            { // need to modify two adjacent digits
              lspref(ptr,bit_pos/intDsize) |= ((uintD)(-1) << (bit_pos%intDsize));
              lspref(ptr,bit_pos/intDsize+1) |= (((uintD)1 << ((bit_pos+n_bits)%intDsize)) - 1);
            }
        }
      bit_pos = bit_pos + n_bits;
      ran = ran >> (log2_intDsize+1); ran_bits -= log2_intDsize+1;
    }
}

}  // namespace cln
