text: // -*- mode: C++ -*-
  //
  // Copyright (c) 2007, 2008, 2009, 2010, 2011 The University of Utah
  // All rights reserved.
  //
  // This file is part of `csmith', a random generator of C programs.
  //
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are met:
  //
  //   * Redistributions of source code must retain the above copyright notice,
  //     this list of conditions and the following disclaimer.
  //
  //   * Redistributions in binary form must reproduce the above copyright
  //     notice, this list of conditions and the following disclaimer in the
  //     documentation and/or other materials provided with the distribution.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  // ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  // POSSIBILITY OF SUCH DAMAGE.
  #ifdef WIN32 
  #pragma warning(disable : 4786)   /* Disable annoying warning messages */
  #endif
  #include "SimpleDeltaRndNumGenerator.h"
  
  #include <cassert>
  #include <iostream>
  #include <sstream>
  
  #include "CGOptions.h"
  #include "Filter.h"
  #include "SequenceFactory.h"
  #include "Sequence.h"
  #include "Error.h"
  #include "RandomNumber.h"
  #include "DefaultRndNumGenerator.h"
  #include "DeltaMonitor.h"
  
  SimpleDeltaRndNumGenerator *SimpleDeltaRndNumGenerator::impl_ = 0;
  
  SimpleDeltaRndNumGenerator::SimpleDeltaRndNumGenerator(Sequence *concrete_seq)
  	: rand_depth_(0),
  	  random_point_(0),
  	  filter_depth_(0),
  	  trace_string_(""),
  	  seq_(concrete_seq)
  {
  
  }
  
  SimpleDeltaRndNumGenerator::~SimpleDeltaRndNumGenerator()
  {
  	SequenceFactory::destroy_sequences();
  }
  
  /*
   * Singleton
   */
  SimpleDeltaRndNumGenerator*
  SimpleDeltaRndNumGenerator::make_rndnum_generator(const unsigned long /*seed*/)
  {
  	if (impl_)
  		return impl_;
  
  	Sequence *seq = SequenceFactory::make_sequence();
  
  	seq->init_sequence();
  
  	impl_ = new SimpleDeltaRndNumGenerator(seq);
  
  	//srand48(seed);
  
  	impl_->random_point_ = SimpleDeltaRndNumGenerator::pure_rnd_upto(seq->sequence_length());
  
  	assert(impl_);
  	
  	return impl_;
  }
  
  int
  SimpleDeltaRndNumGenerator::random_choice (int bound, const Filter *f, const string *)
  {
  	assert(seq_);
  
          int rv = seq_->get_number(bound);
  	++rand_depth_;
  
          if (rv == -1) {
                  Error::set_error(INVALID_SIMPLE_DELTA_SEQUENCE);
                  return -1;
          }
  
          if (f) {
  		++filter_depth_;
                  if (f->filter(rv)) {
                          Error::set_error(FILTER_ERROR);
                          return -1;
                  }
  		--filter_depth_;
          }
  	switch_to_default_generator();
          return rv;
  }
  
  /*
   *
   */
  void
  SimpleDeltaRndNumGenerator::get_sequence(std::string &sequence)
  {
  	std::ostringstream ss;
  	seq_->get_sequence(ss);
  	sequence = ss.str();
  }
  
  std::string 
  SimpleDeltaRndNumGenerator::get_prefixed_name(const std::string &name)
  {
  	return name;
  }
  
  /*
   * Print the tracing information for debugging.
   */
  std::string &
  SimpleDeltaRndNumGenerator::trace_depth()
  {
  	return trace_string_;
  }
  
  unsigned int
  SimpleDeltaRndNumGenerator::rnd_upto(const unsigned int n, const Filter *f, const std::string *where)
  {
  	int x = random_choice(n, f, where);
  	assert(x == -1 || (x >= 0 && x < static_cast<int>(n)));
  	return x;
  }
  
  bool
  SimpleDeltaRndNumGenerator::rnd_flipcoin(const unsigned int, const Filter *f, const std::string *where)
  {
  	int y = random_choice(2, f, where);
  	assert(y == -1 || (y >= 0 && y < 2));
  	return y;
  }
  
  unsigned long 
  SimpleDeltaRndNumGenerator::genrand(void)
  {
  	return AbsRndNumGenerator::genrand();
  }
  
  std::string
  SimpleDeltaRndNumGenerator::RandomHexDigits( int num )
  {
  	std::string str;
  	const char* hex1 = AbsRndNumGenerator::get_hex1();
  	while (num--) {
  		int x = random_choice(16, NULL, NULL);
  		str += hex1[x];
  	}
  	return str;
  }
  
  std::string
  SimpleDeltaRndNumGenerator::RandomDigits( int num )
  {
  	std::string str;
  	const char* dec1 = AbsRndNumGenerator::get_dec1();
  	while ( num-- )
  	{
  		int x = random_choice(10, NULL, NULL);
  		str += dec1[x];
  	}
  
  	return str;
  }
  
  unsigned int
  SimpleDeltaRndNumGenerator::pure_rnd_upto(const unsigned int bound)
  {
  	assert(impl_);
  	return impl_->genrand() % bound;
  }
  
  bool
  SimpleDeltaRndNumGenerator::pure_rnd_flipcoin(const unsigned int p)
  {
  	assert(impl_);
  	bool rv = (impl_->genrand() % 100) < p;
  	return rv;
  }
  
  void
  SimpleDeltaRndNumGenerator::switch_to_default_generator()
  {
  	if (DeltaMonitor::no_delta_reduction() || rand_depth_ < impl_->random_point_ || impl_->filter_depth_ != 0)
  		return;
  
  	//RNDNUM_GENERATOR old;
      	//old = RandomNumber::SwitchRndNumGenerator(rDefaultRndNumGenerator);
      	RandomNumber::SwitchRndNumGenerator(rDefaultRndNumGenerator);
  	DefaultRndNumGenerator *generator = dynamic_cast<DefaultRndNumGenerator*>(RandomNumber::GetRndNumGenerator());
  	generator->set_rand_depth(impl_->rand_depth_);
  }
  
  void
  SimpleDeltaRndNumGenerator::OutputStatistics(ostream &out)
  {
  	assert(impl_);
  	assert(impl_->seq_);
  	out << "/*" << std::endl;
  	out << "** This program was reduced by the simple delta reduction algorithm" << std::endl;
  #ifdef WIN32
  	out << "** at a random point " << (unsigned int)impl_->random_point_ << " with the sequence of length " << (unsigned int)impl_->seq_->sequence_length() << "." << std::endl;
  #else
  	out << "** at a random point " << impl_->random_point_ << " with the sequence of length " << impl_->seq_->sequence_length() << "." << std::endl;
  #endif
  	out << "*/" << std::endl;
  }
  