<commit_before>#include<unordered_map>
#include "reductions.h"
#include "correctedMath.h"

using namespace std;

namespace MARGINAL
{

  struct expert
  {  float regret;
    float abs_regret;
    float weight;
  };

  typedef pair<double, double> marginal;
  typedef pair<expert, expert> expert_pair;

struct data
{ float initial_numerator;
  float initial_denominator;
  float decay;
  bool update_before_learn;
  bool unweighted_marginals;
  bool id_features[256];
  features temp[256];//temporary storage when reducing.
  unordered_map<uint64_t, marginal > marginals;

  //bookkeeping variables for experts
  bool compete;
  float feature_pred; //the prediction computed from using all the features
  float average_pred; //the prediction of the expert
  float net_weight; //normalizer for expert weights
  float net_feature_weight; //the net weight on the feature-based expert
  float alg_loss; //temporary storage for the loss of the current marginal-based predictor
  unordered_map<uint64_t, expert_pair> expert_state; //pair of weights on marginal and feature based predictors, one per marginal feature

  vw* all;
};

  float get_adanormalhedge_weights(float R, float C) {
    float Rpos = R > 0 ? R : 0.;
    if(C == 0. || Rpos == 0.) return 0;
    return 2*Rpos*correctedExp(Rpos*Rpos / (3*C))/(3*C);
  }

  template <bool is_learn>
  void make_marginal(data& sm, example& ec)
  {
    uint64_t mask = sm.all->weights.mask();
    float label = ec.l.simple.label;
    vw& all = *sm.all;
    sm.alg_loss = 0.;
    sm.net_weight = 0.;
    sm.net_feature_weight = 0.;
    sm.average_pred = 0.;

    for (example::iterator i = ec.begin(); i!= ec.end(); ++i)
      { namespace_index n = i.index();
	if (sm.id_features[n])
	  {
	    std::swap(sm.temp[n],*i);
	    features& f = *i;
	    f.erase();
	    for (features::iterator j = sm.temp[n].begin(); j != sm.temp[n].end(); ++j)
	      { float first_value = j.value();
		uint64_t first_index = j.index() & mask;
		if (++j == sm.temp[n].end())
		  { cout << "warning: id feature namespace has " << sm.temp[n].size() << " features. Should be a multiple of 2" << endl;
		    break;
		  }
		float second_value = j.value();
		uint64_t second_index = j.index() & mask;
		if (first_value != 1. || second_value != 1.)
		  { cout << "warning: bad id features, must have value 1." << endl;
		    continue;
		  }
		uint64_t key = second_index + ec.ft_offset;
		if (sm.marginals.find(key) == sm.marginals.end()) {//need to initialize things.
		  sm.marginals.insert(make_pair(key,make_pair(sm.initial_numerator, sm.initial_denominator)));
		  if(sm.compete) {
		    expert e = {0,0,1.};
		    sm.expert_state.insert(make_pair(key, make_pair(e,e)));
		  }
		}
		float marginal_pred = (float)(sm.marginals[key].first / sm.marginals[key].second);
		f.push_back(marginal_pred, first_index);
		if (!sm.temp[n].space_names.empty())
		  f.space_names.push_back(sm.temp[n].space_names[2*(f.size()-1)]);

		if(sm.compete) { // compute the prediction from the marginals using the weights
		  float weight = sm.expert_state[key].first.weight;
		  sm.average_pred += weight*marginal_pred;
		  sm.net_weight += weight;
		  sm.net_feature_weight += sm.expert_state[key].second.weight;
		  if(is_learn)
		    sm.alg_loss += weight*all.loss->getLoss(all.sd, marginal_pred, label);
		}
	      }
	  }
      }
  }

  void undo_marginal(data& sm, example& ec)
  {
    for (example::iterator i = ec.begin(); i!= ec.end(); ++i)
      { namespace_index n = i.index();
	if (sm.id_features[n])
	  std::swap(sm.temp[n],*i);
      }
  }

  template<bool is_learn>
  void compute_expert_loss(data& sm, example& ec)
  {
    vw& all = *sm.all;
    //add in the feature-based expert and normalize,
    float label = ec.l.simple.label;

    if(sm.net_weight + sm.net_feature_weight > 0.)
      sm.average_pred += sm.net_feature_weight * sm.feature_pred;
    else {
      sm.net_feature_weight = 1.;
      sm.average_pred = sm.feature_pred;
    }
    float inv_weight = 1.0/(sm.net_weight + sm.net_feature_weight);
    sm.average_pred *= inv_weight;
    ec.pred.scalar = sm.average_pred;
    ec.partial_prediction = sm.average_pred;
    if(is_learn) {
      sm.alg_loss += sm.net_feature_weight*all.loss->getLoss(all.sd, sm.feature_pred, label);
      sm.alg_loss *= inv_weight;
    }

  }

  void update_marginal(data& sm, example& ec)
  {
    vw& all = *sm.all;
    uint64_t mask = sm.all->weights.mask();
    float label = ec.l.simple.label;
    float weight = ec.weight;
    if(sm.unweighted_marginals)
      weight = 1.;

    for (example::iterator i = ec.begin(); i!= ec.end(); ++i)
      { namespace_index n = i.index();
	if (sm.id_features[n])
	  for (features::iterator j = sm.temp[n].begin(); j != sm.temp[n].end(); ++j)
	    { if (++j == sm.temp[n].end())
		break;

	      uint64_t second_index = j.index() & mask;
	      uint64_t key = second_index + ec.ft_offset;
	      marginal& m = sm.marginals[key];

	      if(sm.compete) { //now update weights, before updating marginals
		expert_pair& e = sm.expert_state[key];
		float regret1 = sm.alg_loss - all.loss->getLoss(all.sd, m.first/m.second, label);
		float regret2 = sm.alg_loss - all.loss->getLoss(all.sd, sm.feature_pred, label);

		e.first.regret += regret1*weight;
		e.first.abs_regret += regret1*regret1*weight;//fabs(regret1);
		e.first.weight = get_adanormalhedge_weights(e.first.regret, e.first.abs_regret);
		e.second.regret += regret2*weight;
		e.second.abs_regret += regret2*regret2*weight;//fabs(regret2);
		e.second.weight = get_adanormalhedge_weights(e.second.regret, e.second.abs_regret);
	      }

	      m.first = m.first * (1. - sm.decay) + ec.l.simple.label * weight;
	      m.second = m.second * (1. - sm.decay) + weight;

	    }
      }

  }

template <bool is_learn>
void predict_or_learn(data& sm, LEARNER::base_learner& base, example& ec)
{
  make_marginal<is_learn>(sm, ec);
  if (is_learn)
    if (sm.update_before_learn)
      {
	base.predict(ec);
	float pred = ec.pred.scalar;
	if(sm.compete) {
	  sm.feature_pred = pred;
	  compute_expert_loss<is_learn>(sm, ec);
	}
	undo_marginal(sm, ec);
	update_marginal(sm, ec);//update features before learning.
	make_marginal<is_learn>(sm, ec);
	base.learn(ec);
	ec.pred.scalar = pred;
      }
    else
      {
	base.learn(ec);
	if(sm.compete) {
	  sm.feature_pred = ec.pred.scalar;
	  compute_expert_loss<is_learn>(sm, ec);
	}
	update_marginal(sm,ec);
      }
  else {
    base.predict(ec);
    float pred = ec.pred.scalar;
    if(sm.compete) {
      sm.feature_pred = pred;
      compute_expert_loss<is_learn>(sm, ec);
    }
  }

  //undo marginalization
  undo_marginal(sm, ec);
}

void finish(data& sm)
{ sm.marginals.~unordered_map();
  sm.expert_state.~unordered_map();
  for (size_t i =0; i < 256; i++)
    sm.temp[i].delete_v();
}

  void save_load(data& sm, io_buf& io, bool read, bool text)
  {
    uint64_t stride_shift = sm.all->weights.stride_shift();

    if (io.files.size() == 0)
      return;
    stringstream msg;
    uint64_t total_size;
    if (!read)
      { total_size = (uint64_t)sm.marginals.size();
	msg << "marginals size = " << total_size << "\n";
      }
    bin_text_read_write_fixed_validated(io, (char*)&total_size, sizeof(total_size), "", read, msg, text);

    auto iter = sm.marginals.begin();
    for (size_t i = 0; i < total_size; ++i)
      { uint64_t index;
	if (!read)
	  { index = iter->first >> stride_shift;
	    msg << index << ":";
	  }
	bin_text_read_write_fixed(io, (char*)&index, sizeof(index), "", read, msg, text);
	double numerator;
	if (!read)
	  { numerator = iter->second.first;
	    msg << numerator << ":";
	  }
	bin_text_read_write_fixed(io, (char*)&numerator, sizeof(numerator), "", read, msg, text);
	double denominator;
	if (!read)
	  { denominator = iter->second.second;
	    msg << denominator << "\n";
	  }
	bin_text_read_write_fixed(io, (char*)&denominator, sizeof(denominator), "", read, msg, text);
	if (read)
	  sm.marginals.insert(make_pair(index << stride_shift,make_pair(numerator,denominator)));
	else
	  ++iter;
      }

    if (!read)
      { total_size = (uint64_t)sm.expert_state.size();
	msg << "expert_state size = " << total_size << "\n";
      }
    bin_text_read_write_fixed_validated(io, (char*)&total_size, sizeof(total_size), "", read, msg, text);

    auto exp_iter = sm.expert_state.begin();
    for (size_t i = 0; i < total_size; ++i)
      { uint64_t index;
	if (!read)
	  { index = exp_iter->first >> stride_shift;
	    msg << index << ":";
	  }
	bin_text_read_write_fixed(io, (char*)&index, sizeof(index), "", read, msg, text);
	float r1, c1, w1, r2, c2, w2;
	if (!read)
	  { r1 = exp_iter->second.first.regret;
	    c1 = exp_iter->second.first.abs_regret;
	    w1 = exp_iter->second.first.weight;
	    r2 = exp_iter->second.second.regret;
	    c2 = exp_iter->second.second.abs_regret;
	    w2 = exp_iter->second.second.weight;
	    msg<< r1 << ":";
	  }
	bin_text_read_write_fixed(io, (char*)&r1, sizeof(r1), "", read, msg, text);
	if(!read)
	  msg<< c1 << ":";
	bin_text_read_write_fixed(io, (char*)&c1, sizeof(c1), "", read, msg, text);
	if(!read)
	  msg<< w1 << ":";
	bin_text_read_write_fixed(io, (char*)&w1, sizeof(w1), "", read, msg, text);
	if(!read)
	  msg<< r2 << ":";
	bin_text_read_write_fixed(io, (char*)&r2, sizeof(r2), "", read, msg, text);
	if(!read)
	  msg<< c2 << ":";
	bin_text_read_write_fixed(io, (char*)&c2, sizeof(c2), "", read, msg, text);
	if(!read)
	  msg<< w2 << ":";
	bin_text_read_write_fixed(io, (char*)&w2, sizeof(w2), "", read, msg, text);

	if (read) {
	  expert e1 = {r1, c1, w1};
	  expert e2 = {r2, c2, w2};
	  sm.expert_state.insert(make_pair(index << stride_shift,make_pair(e1, e2)));
	}
	else
	  ++exp_iter;
      }
  }
}

using namespace MARGINAL;

LEARNER::base_learner* marginal_setup(vw& all)
{ if (missing_option<string, true>(all, "marginal", "substitute marginal label estimates for ids"))
    return nullptr;
  new_options(all)
    ("initial_denominator", po::value<float>()->default_value(1.f), "initial denominator")
    ("initial_numerator", po::value<float>()->default_value(0.5f), "initial numerator")
    ("compete", "enable competition with marginal features")
    ("update_before_learn",po::value<bool>()->default_value(false), "update marginal values before learning")
    ("unweighted_marginals",po::value<bool>()->default_value(false), "ignore importance weights when computing marginals")
    ("decay", po::value<float>()->default_value(0.f), "decay multiplier per event (1e-3 for example)");
  add_options(all);

  data& d = calloc_or_throw<data>();
  d.initial_numerator = all.vm["initial_numerator"].as<float>();
  d.initial_denominator = all.vm["initial_denominator"].as<float>();
  d.decay = all.vm["decay"].as<float>();
  d.compete = false;
  if(all.vm.count("compete"))
    d.compete = true;
  d.update_before_learn = all.vm["update_before_learn"].as<bool>();
  d.unweighted_marginals = all.vm["unweighted_marginals"].as<bool>();
  d.all = &all;
  string s = (string)all.vm["marginal"].as<string>();

  for (size_t u = 0; u < 256; u++)
    if (s.find((char)u) != string::npos)
      d.id_features[u] = true;
  new(&d.marginals)unordered_map<uint64_t,marginal>();
  if(d.compete)
    new(&d.expert_state)unordered_map<uint64_t,expert_pair>();

  LEARNER::learner<data>& ret =
    init_learner(&d, setup_base(all), predict_or_learn<true>, predict_or_learn<false>);
  ret.set_finish(finish);
  ret.set_save_load(save_load);

  return make_base(ret);
}
<commit_msg>maybe fix heisenbug<commit_after>#include<unordered_map>
#include "reductions.h"
#include "correctedMath.h"

using namespace std;

namespace MARGINAL
{

  struct expert
  {  float regret;
    float abs_regret;
    float weight;
  };

  typedef pair<double, double> marginal;
  typedef pair<expert, expert> expert_pair;

struct data
{ float initial_numerator;
  float initial_denominator;
  float decay;
  bool update_before_learn;
  bool unweighted_marginals;
  bool id_features[256];
  features temp[256];//temporary storage when reducing.
  unordered_map<uint64_t, marginal > marginals;

  //bookkeeping variables for experts
  bool compete;
  float feature_pred; //the prediction computed from using all the features
  float average_pred; //the prediction of the expert
  float net_weight; //normalizer for expert weights
  float net_feature_weight; //the net weight on the feature-based expert
  float alg_loss; //temporary storage for the loss of the current marginal-based predictor
  unordered_map<uint64_t, expert_pair> expert_state; //pair of weights on marginal and feature based predictors, one per marginal feature

  vw* all;
};

  float get_adanormalhedge_weights(float R, float C) {
    float Rpos = R > 0 ? R : 0.;
    if(C == 0. || Rpos == 0.) return 0;
    return 2*Rpos*correctedExp(Rpos*Rpos / (3*C))/(3*C);
  }

  template <bool is_learn>
  void make_marginal(data& sm, example& ec)
  {
    uint64_t mask = sm.all->weights.mask();
    float label = ec.l.simple.label;
    vw& all = *sm.all;
    sm.alg_loss = 0.;
    sm.net_weight = 0.;
    sm.net_feature_weight = 0.;
    sm.average_pred = 0.;

    for (example::iterator i = ec.begin(); i!= ec.end(); ++i)
      { namespace_index n = i.index();
	if (sm.id_features[n])
	  {
	    std::swap(sm.temp[n],*i);
	    features& f = *i;
	    f.erase();
	    for (features::iterator j = sm.temp[n].begin(); j != sm.temp[n].end(); ++j)
	      { float first_value = j.value();
		uint64_t first_index = j.index() & mask;
		if (++j == sm.temp[n].end())
		  { cout << "warning: id feature namespace has " << sm.temp[n].size() << " features. Should be a multiple of 2" << endl;
		    break;
		  }
		float second_value = j.value();
		uint64_t second_index = j.index() & mask;
		if (first_value != 1. || second_value != 1.)
		  { cout << "warning: bad id features, must have value 1." << endl;
		    continue;
		  }
		uint64_t key = second_index + ec.ft_offset;
		if (sm.marginals.find(key) == sm.marginals.end()) {//need to initialize things.
		  sm.marginals.insert(make_pair(key,make_pair(sm.initial_numerator, sm.initial_denominator)));
		  if(sm.compete) {
		    expert e = {0,0,1.};
		    sm.expert_state.insert(make_pair(key, make_pair(e,e)));
		  }
		}
		float marginal_pred = (float)(sm.marginals[key].first / sm.marginals[key].second);
		f.push_back(marginal_pred, first_index);
		if (!sm.temp[n].space_names.empty())
		  f.space_names.push_back(sm.temp[n].space_names[2*(f.size()-1)]);

		if(sm.compete) { // compute the prediction from the marginals using the weights
		  float weight = sm.expert_state[key].first.weight;
		  sm.average_pred += weight*marginal_pred;
		  sm.net_weight += weight;
		  sm.net_feature_weight += sm.expert_state[key].second.weight;
		  if(is_learn)
		    sm.alg_loss += weight*all.loss->getLoss(all.sd, marginal_pred, label);
		}
	      }
	  }
      }
  }

  void undo_marginal(data& sm, example& ec)
  {
    for (example::iterator i = ec.begin(); i!= ec.end(); ++i)
      { namespace_index n = i.index();
	if (sm.id_features[n])
	  std::swap(sm.temp[n],*i);
      }
  }

  template<bool is_learn>
  void compute_expert_loss(data& sm, example& ec)
  {
    vw& all = *sm.all;
    //add in the feature-based expert and normalize,
    float label = ec.l.simple.label;

    if(sm.net_weight + sm.net_feature_weight > 0.)
      sm.average_pred += sm.net_feature_weight * sm.feature_pred;
    else {
      sm.net_feature_weight = 1.;
      sm.average_pred = sm.feature_pred;
    }
    float inv_weight = 1.0/(sm.net_weight + sm.net_feature_weight);
    sm.average_pred *= inv_weight;
    ec.pred.scalar = sm.average_pred;
    ec.partial_prediction = sm.average_pred;
    if(is_learn) {
      sm.alg_loss += sm.net_feature_weight*all.loss->getLoss(all.sd, sm.feature_pred, label);
      sm.alg_loss *= inv_weight;
    }

  }

  void update_marginal(data& sm, example& ec)
  {
    vw& all = *sm.all;
    uint64_t mask = sm.all->weights.mask();
    float label = ec.l.simple.label;
    float weight = ec.weight;
    if(sm.unweighted_marginals)
      weight = 1.;

    for (example::iterator i = ec.begin(); i!= ec.end(); ++i)
      { namespace_index n = i.index();
	if (sm.id_features[n])
	  for (features::iterator j = sm.temp[n].begin(); j != sm.temp[n].end(); ++j)
	    { if (++j == sm.temp[n].end())
		break;

	      uint64_t second_index = j.index() & mask;
	      uint64_t key = second_index + ec.ft_offset;
	      marginal& m = sm.marginals[key];

	      if(sm.compete) { //now update weights, before updating marginals
		expert_pair& e = sm.expert_state[key];
		float regret1 = sm.alg_loss - all.loss->getLoss(all.sd, m.first/m.second, label);
		float regret2 = sm.alg_loss - all.loss->getLoss(all.sd, sm.feature_pred, label);

		e.first.regret += regret1*weight;
		e.first.abs_regret += regret1*regret1*weight;//fabs(regret1);
		e.first.weight = get_adanormalhedge_weights(e.first.regret, e.first.abs_regret);
		e.second.regret += regret2*weight;
		e.second.abs_regret += regret2*regret2*weight;//fabs(regret2);
		e.second.weight = get_adanormalhedge_weights(e.second.regret, e.second.abs_regret);
	      }

	      m.first = m.first * (1. - sm.decay) + ec.l.simple.label * weight;
	      m.second = m.second * (1. - sm.decay) + weight;

	    }
      }

  }

template <bool is_learn>
void predict_or_learn(data& sm, LEARNER::base_learner& base, example& ec)
{
  make_marginal<is_learn>(sm, ec);
  if (is_learn)
    if (sm.update_before_learn)
      {
	base.predict(ec);
	float pred = ec.pred.scalar;
	if(sm.compete) {
	  sm.feature_pred = pred;
	  compute_expert_loss<is_learn>(sm, ec);
	}
	undo_marginal(sm, ec);
	update_marginal(sm, ec);//update features before learning.
	make_marginal<is_learn>(sm, ec);
	base.learn(ec);
	ec.pred.scalar = pred;
      }
    else
      {
	base.learn(ec);
	if(sm.compete) {
	  sm.feature_pred = ec.pred.scalar;
	  compute_expert_loss<is_learn>(sm, ec);
	}
	update_marginal(sm,ec);
      }
  else {
    base.predict(ec);
    float pred = ec.pred.scalar;
    if(sm.compete) {
      sm.feature_pred = pred;
      compute_expert_loss<is_learn>(sm, ec);
    }
  }

  //undo marginalization
  undo_marginal(sm, ec);
}

void finish(data& sm)
{ sm.marginals.~unordered_map();
  sm.expert_state.~unordered_map();
  for (size_t i =0; i < 256; i++)
    sm.temp[i].delete_v();
}

  void save_load(data& sm, io_buf& io, bool read, bool text)
  {
    uint64_t stride_shift = sm.all->weights.stride_shift();

    if (io.files.size() == 0)
      return;
    stringstream msg;
    uint64_t total_size;
    if (!read)
      { total_size = (uint64_t)sm.marginals.size();
	msg << "marginals size = " << total_size << "\n";
      }
    bin_text_read_write_fixed_validated(io, (char*)&total_size, sizeof(total_size), "", read, msg, text);

    auto iter = sm.marginals.begin();
    for (size_t i = 0; i < total_size; ++i)
      { uint64_t index;
	if (!read)
	  { index = iter->first >> stride_shift;
	    msg << index << ":";
	  }
	bin_text_read_write_fixed(io, (char*)&index, sizeof(index), "", read, msg, text);
	double numerator;
	if (!read)
	  { numerator = iter->second.first;
	    msg << numerator << ":";
	  }
	bin_text_read_write_fixed(io, (char*)&numerator, sizeof(numerator), "", read, msg, text);
	double denominator;
	if (!read)
	  { denominator = iter->second.second;
	    msg << denominator << "\n";
	  }
	bin_text_read_write_fixed(io, (char*)&denominator, sizeof(denominator), "", read, msg, text);
	if (read)
	  sm.marginals.insert(make_pair(index << stride_shift,make_pair(numerator,denominator)));
	else
	  ++iter;
      }

    if (!read)
      { total_size = (uint64_t)sm.expert_state.size();
	msg << "expert_state size = " << total_size << "\n";
      }
    bin_text_read_write_fixed_validated(io, (char*)&total_size, sizeof(total_size), "", read, msg, text);

    auto exp_iter = sm.expert_state.begin();
    for (size_t i = 0; i < total_size; ++i)
      { uint64_t index;
	if (!read)
	  { index = exp_iter->first >> stride_shift;
	    msg << index << ":";
	  }
	bin_text_read_write_fixed(io, (char*)&index, sizeof(index), "", read, msg, text);
	float r1, c1, w1, r2, c2, w2;
	if (!read)
	  { r1 = exp_iter->second.first.regret;
	    c1 = exp_iter->second.first.abs_regret;
	    w1 = exp_iter->second.first.weight;
	    r2 = exp_iter->second.second.regret;
	    c2 = exp_iter->second.second.abs_regret;
	    w2 = exp_iter->second.second.weight;
	    msg<< r1 << ":";
	  }
	bin_text_read_write_fixed(io, (char*)&r1, sizeof(r1), "", read, msg, text);
	if(!read)
	  msg<< c1 << ":";
	bin_text_read_write_fixed(io, (char*)&c1, sizeof(c1), "", read, msg, text);
	if(!read)
	  msg<< w1 << ":";
	bin_text_read_write_fixed(io, (char*)&w1, sizeof(w1), "", read, msg, text);
	if(!read)
	  msg<< r2 << ":";
	bin_text_read_write_fixed(io, (char*)&r2, sizeof(r2), "", read, msg, text);
	if(!read)
	  msg<< c2 << ":";
	bin_text_read_write_fixed(io, (char*)&c2, sizeof(c2), "", read, msg, text);
	if(!read)
	  msg<< w2 << ":";
	bin_text_read_write_fixed(io, (char*)&w2, sizeof(w2), "", read, msg, text);

	if (read) {
	  expert e1 = {r1, c1, w1};
	  expert e2 = {r2, c2, w2};
	  sm.expert_state.insert(make_pair(index << stride_shift,make_pair(e1, e2)));
	}
	else
	  ++exp_iter;
      }
  }
}

using namespace MARGINAL;

LEARNER::base_learner* marginal_setup(vw& all)
{ if (missing_option<string, true>(all, "marginal", "substitute marginal label estimates for ids"))
    return nullptr;
  new_options(all)
    ("initial_denominator", po::value<float>()->default_value(1.f), "initial denominator")
    ("initial_numerator", po::value<float>()->default_value(0.5f), "initial numerator")
    ("compete", "enable competition with marginal features")
    ("update_before_learn",po::value<bool>()->default_value(false), "update marginal values before learning")
    ("unweighted_marginals",po::value<bool>()->default_value(false), "ignore importance weights when computing marginals")
    ("decay", po::value<float>()->default_value(0.f), "decay multiplier per event (1e-3 for example)");
  add_options(all);

  data& d = calloc_or_throw<data>();
  d.initial_numerator = all.vm["initial_numerator"].as<float>();
  d.initial_denominator = all.vm["initial_denominator"].as<float>();
  d.decay = all.vm["decay"].as<float>();
  d.compete = false;
  if(all.vm.count("compete"))
    d.compete = true;
  d.update_before_learn = all.vm["update_before_learn"].as<bool>();
  d.unweighted_marginals = all.vm["unweighted_marginals"].as<bool>();
  d.all = &all;
  string s = (string)all.vm["marginal"].as<string>();

  for (size_t u = 0; u < 256; u++)
    if (s.find((char)u) != string::npos)
      d.id_features[u] = true;
  new(&d.marginals)unordered_map<uint64_t,marginal>();
  new(&d.expert_state)unordered_map<uint64_t,expert_pair>();

  LEARNER::learner<data>& ret =
    init_learner(&d, setup_base(all), predict_or_learn<true>, predict_or_learn<false>);
  ret.set_finish(finish);
  ret.set_save_load(save_load);

  return make_base(ret);
}
<|endoftext|>


<commit_before>/***************************************************************************
    copyright            : (C) 2013 by Lukas Krejci
    email                : krejclu6@fel.cvut.cz
 ***************************************************************************/

/***************************************************************************
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Lesser General Public License version   *
 *   2.1 as published by the Free Software Foundation.                     *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful, but   *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA         *
 *   02110-1301  USA                                                       *
 *                                                                         *
 *   Alternatively, this file is available under the Mozilla Public        *
 *   License Version 1.1.  You may obtain a copy of the License at         *
 *   http://www.mozilla.org/MPL/                                           *
 ***************************************************************************/

#include <tbytevectorlist.h>
#include <tpropertymap.h>
#include <tdebug.h>
#include <stdio.h>

#include "chapterframe.h"

using namespace TagLib;
using namespace ID3v2;

class ChapterFrame::ChapterFramePrivate
{
public:
  ChapterFramePrivate() :
    tagHeader(0)
  {
    embeddedFrameList.setAutoDelete(true);
  }

  const ID3v2::Header *tagHeader;
  ByteVector elementID;
  unsigned int startTime;
  unsigned int endTime;
  unsigned int startOffset;
  unsigned int endOffset;
  FrameListMap embeddedFrameListMap;
  FrameList embeddedFrameList;
};

////////////////////////////////////////////////////////////////////////////////
// public methods
////////////////////////////////////////////////////////////////////////////////

ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data) :
    ID3v2::Frame(data)
{
  d = new ChapterFramePrivate;
  d->tagHeader = tagHeader;
  setData(data);
}

ChapterFrame::ChapterFrame(const ByteVector &elementID,
                           unsigned int startTime, unsigned int endTime,
                           unsigned int startOffset, unsigned int endOffset,
                           const FrameList &embeddedFrames) :
    ID3v2::Frame("CHAP")
{
  d = new ChapterFramePrivate;

  // setElementID has a workaround for a previously silly API where you had to
  // specifically include the null byte.

  setElementID(elementID);

  d->startTime = startTime;
  d->endTime = endTime;
  d->startOffset = startOffset;
  d->endOffset = endOffset;

  for(FrameList::ConstIterator it = embeddedFrames.begin();
      it != embeddedFrames.end(); ++it)
    addEmbeddedFrame(*it);
}

ChapterFrame::~ChapterFrame()
{
  delete d;
}

ByteVector ChapterFrame::elementID() const
{
  return d->elementID;
}

unsigned int ChapterFrame::startTime() const
{
  return d->startTime;
}

unsigned int ChapterFrame::endTime() const
{
  return d->endTime;
}

unsigned int ChapterFrame::startOffset() const
{
  return d->startOffset;
}

unsigned int ChapterFrame::endOffset() const
{
  return d->endOffset;
}

void ChapterFrame::setElementID(const ByteVector &eID)
{
  d->elementID = eID;

  if(d->elementID.endsWith(char(0)))
    d->elementID = d->elementID.mid(0, d->elementID.size() - 1);
}

void ChapterFrame::setStartTime(const unsigned int &sT)
{
  d->startTime = sT;
}

void ChapterFrame::setEndTime(const unsigned int &eT)
{
  d->endTime = eT;
}

void ChapterFrame::setStartOffset(const unsigned int &sO)
{
  d->startOffset = sO;
}

void ChapterFrame::setEndOffset(const unsigned int &eO)
{
  d->endOffset = eO;
}

const FrameListMap &ChapterFrame::embeddedFrameListMap() const
{
  return d->embeddedFrameListMap;
}

const FrameList &ChapterFrame::embeddedFrameList() const
{
  return d->embeddedFrameList;
}

const FrameList &ChapterFrame::embeddedFrameList(const ByteVector &frameID) const
{
  return d->embeddedFrameListMap[frameID];
}

void ChapterFrame::addEmbeddedFrame(Frame *frame)
{
  d->embeddedFrameList.append(frame);
  d->embeddedFrameListMap[frame->frameID()].append(frame);
}

void ChapterFrame::removeEmbeddedFrame(Frame *frame, bool del)
{
  // remove the frame from the frame list
  FrameList::Iterator it = d->embeddedFrameList.find(frame);
  d->embeddedFrameList.erase(it);

  // ...and from the frame list map
  it = d->embeddedFrameListMap[frame->frameID()].find(frame);
  d->embeddedFrameListMap[frame->frameID()].erase(it);

  // ...and delete as desired
  if(del)
    delete frame;
}

void ChapterFrame::removeEmbeddedFrames(const ByteVector &id)
{
  FrameList l = d->embeddedFrameListMap[id];
  for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
    removeEmbeddedFrame(*it, true);
}

String ChapterFrame::toString() const
{
  String s = String(d->elementID) +
             ": start time: " + String::number(d->startTime) +
             ", end time: " + String::number(d->endTime);

  if(d->startOffset != 0xFFFFFFFF)
    s += ", start offset: " + String::number(d->startOffset);

  if(d->endOffset != 0xFFFFFFFF)
    s += ", start offset: " + String::number(d->endOffset);

  if(!d->embeddedFrameList.isEmpty()) {
    StringList frameIDs;
    for(FrameList::ConstIterator it = d->embeddedFrameList.begin();
        it != d->embeddedFrameList.end(); ++it)
      frameIDs.append((*it)->frameID());
    s += ", sub-frames: [ " + frameIDs.toString(", ") + " ]";
  }

  return s;
}

PropertyMap ChapterFrame::asProperties() const
{
  PropertyMap map;

  map.unsupportedData().append(frameID() + String("/") + d->elementID);

  return map;
}

ChapterFrame *ChapterFrame::findByElementID(const ID3v2::Tag *tag, const ByteVector &eID) // static
{
  ID3v2::FrameList comments = tag->frameList("CHAP");

  for(ID3v2::FrameList::ConstIterator it = comments.begin();
      it != comments.end();
      ++it)
  {
    ChapterFrame *frame = dynamic_cast<ChapterFrame *>(*it);
    if(frame && frame->elementID() == eID)
      return frame;
  }

  return 0;
}

void ChapterFrame::parseFields(const ByteVector &data)
{
  unsigned int size = data.size();
  if(size < 18) {
    debug("A CHAP frame must contain at least 18 bytes (1 byte element ID "
          "terminated by null and 4x4 bytes for start and end time and offset).");
    return;
  }

  int pos = 0;
  unsigned int embPos = 0;
  d->elementID = readStringField(data, String::Latin1, &pos).data(String::Latin1);
  d->startTime = data.toUInt(pos, true);
  pos += 4;
  d->endTime = data.toUInt(pos, true);
  pos += 4;
  d->startOffset = data.toUInt(pos, true);
  pos += 4;
  d->endOffset = data.toUInt(pos, true);
  pos += 4;
  size -= pos;

  // Embedded frames are optional

  if(size < header()->size())
    return;

  while(embPos < size - header()->size()) {
    Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos), (d->tagHeader != 0));

    if(!frame)
      return;

    // Checks to make sure that frame parsed correctly.
    if(frame->size() <= 0) {
      delete frame;
      return;
    }

    embPos += frame->size() + header()->size();
    addEmbeddedFrame(frame);
  }
}

ByteVector ChapterFrame::renderFields() const
{
  ByteVector data;

  data.append(d->elementID);
  data.append('\0');
  data.append(ByteVector::fromUInt(d->startTime, true));
  data.append(ByteVector::fromUInt(d->endTime, true));
  data.append(ByteVector::fromUInt(d->startOffset, true));
  data.append(ByteVector::fromUInt(d->endOffset, true));
  FrameList l = d->embeddedFrameList;
  for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
    data.append((*it)->render());

  return data;
}

ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h) :
  Frame(h)
{
  d = new ChapterFramePrivate;
  d->tagHeader = tagHeader;
  parseFields(fieldData(data));
}
<commit_msg>Change string to end offset<commit_after>/***************************************************************************
    copyright            : (C) 2013 by Lukas Krejci
    email                : krejclu6@fel.cvut.cz
 ***************************************************************************/

/***************************************************************************
 *   This library is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Lesser General Public License version   *
 *   2.1 as published by the Free Software Foundation.                     *
 *                                                                         *
 *   This library is distributed in the hope that it will be useful, but   *
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the Free Software   *
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA         *
 *   02110-1301  USA                                                       *
 *                                                                         *
 *   Alternatively, this file is available under the Mozilla Public        *
 *   License Version 1.1.  You may obtain a copy of the License at         *
 *   http://www.mozilla.org/MPL/                                           *
 ***************************************************************************/

#include <tbytevectorlist.h>
#include <tpropertymap.h>
#include <tdebug.h>
#include <stdio.h>

#include "chapterframe.h"

using namespace TagLib;
using namespace ID3v2;

class ChapterFrame::ChapterFramePrivate
{
public:
  ChapterFramePrivate() :
    tagHeader(0)
  {
    embeddedFrameList.setAutoDelete(true);
  }

  const ID3v2::Header *tagHeader;
  ByteVector elementID;
  unsigned int startTime;
  unsigned int endTime;
  unsigned int startOffset;
  unsigned int endOffset;
  FrameListMap embeddedFrameListMap;
  FrameList embeddedFrameList;
};

////////////////////////////////////////////////////////////////////////////////
// public methods
////////////////////////////////////////////////////////////////////////////////

ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data) :
    ID3v2::Frame(data)
{
  d = new ChapterFramePrivate;
  d->tagHeader = tagHeader;
  setData(data);
}

ChapterFrame::ChapterFrame(const ByteVector &elementID,
                           unsigned int startTime, unsigned int endTime,
                           unsigned int startOffset, unsigned int endOffset,
                           const FrameList &embeddedFrames) :
    ID3v2::Frame("CHAP")
{
  d = new ChapterFramePrivate;

  // setElementID has a workaround for a previously silly API where you had to
  // specifically include the null byte.

  setElementID(elementID);

  d->startTime = startTime;
  d->endTime = endTime;
  d->startOffset = startOffset;
  d->endOffset = endOffset;

  for(FrameList::ConstIterator it = embeddedFrames.begin();
      it != embeddedFrames.end(); ++it)
    addEmbeddedFrame(*it);
}

ChapterFrame::~ChapterFrame()
{
  delete d;
}

ByteVector ChapterFrame::elementID() const
{
  return d->elementID;
}

unsigned int ChapterFrame::startTime() const
{
  return d->startTime;
}

unsigned int ChapterFrame::endTime() const
{
  return d->endTime;
}

unsigned int ChapterFrame::startOffset() const
{
  return d->startOffset;
}

unsigned int ChapterFrame::endOffset() const
{
  return d->endOffset;
}

void ChapterFrame::setElementID(const ByteVector &eID)
{
  d->elementID = eID;

  if(d->elementID.endsWith(char(0)))
    d->elementID = d->elementID.mid(0, d->elementID.size() - 1);
}

void ChapterFrame::setStartTime(const unsigned int &sT)
{
  d->startTime = sT;
}

void ChapterFrame::setEndTime(const unsigned int &eT)
{
  d->endTime = eT;
}

void ChapterFrame::setStartOffset(const unsigned int &sO)
{
  d->startOffset = sO;
}

void ChapterFrame::setEndOffset(const unsigned int &eO)
{
  d->endOffset = eO;
}

const FrameListMap &ChapterFrame::embeddedFrameListMap() const
{
  return d->embeddedFrameListMap;
}

const FrameList &ChapterFrame::embeddedFrameList() const
{
  return d->embeddedFrameList;
}

const FrameList &ChapterFrame::embeddedFrameList(const ByteVector &frameID) const
{
  return d->embeddedFrameListMap[frameID];
}

void ChapterFrame::addEmbeddedFrame(Frame *frame)
{
  d->embeddedFrameList.append(frame);
  d->embeddedFrameListMap[frame->frameID()].append(frame);
}

void ChapterFrame::removeEmbeddedFrame(Frame *frame, bool del)
{
  // remove the frame from the frame list
  FrameList::Iterator it = d->embeddedFrameList.find(frame);
  d->embeddedFrameList.erase(it);

  // ...and from the frame list map
  it = d->embeddedFrameListMap[frame->frameID()].find(frame);
  d->embeddedFrameListMap[frame->frameID()].erase(it);

  // ...and delete as desired
  if(del)
    delete frame;
}

void ChapterFrame::removeEmbeddedFrames(const ByteVector &id)
{
  FrameList l = d->embeddedFrameListMap[id];
  for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
    removeEmbeddedFrame(*it, true);
}

String ChapterFrame::toString() const
{
  String s = String(d->elementID) +
             ": start time: " + String::number(d->startTime) +
             ", end time: " + String::number(d->endTime);

  if(d->startOffset != 0xFFFFFFFF)
    s += ", start offset: " + String::number(d->startOffset);

  if(d->endOffset != 0xFFFFFFFF)
    s += ", end offset: " + String::number(d->endOffset);

  if(!d->embeddedFrameList.isEmpty()) {
    StringList frameIDs;
    for(FrameList::ConstIterator it = d->embeddedFrameList.begin();
        it != d->embeddedFrameList.end(); ++it)
      frameIDs.append((*it)->frameID());
    s += ", sub-frames: [ " + frameIDs.toString(", ") + " ]";
  }

  return s;
}

PropertyMap ChapterFrame::asProperties() const
{
  PropertyMap map;

  map.unsupportedData().append(frameID() + String("/") + d->elementID);

  return map;
}

ChapterFrame *ChapterFrame::findByElementID(const ID3v2::Tag *tag, const ByteVector &eID) // static
{
  ID3v2::FrameList comments = tag->frameList("CHAP");

  for(ID3v2::FrameList::ConstIterator it = comments.begin();
      it != comments.end();
      ++it)
  {
    ChapterFrame *frame = dynamic_cast<ChapterFrame *>(*it);
    if(frame && frame->elementID() == eID)
      return frame;
  }

  return 0;
}

void ChapterFrame::parseFields(const ByteVector &data)
{
  unsigned int size = data.size();
  if(size < 18) {
    debug("A CHAP frame must contain at least 18 bytes (1 byte element ID "
          "terminated by null and 4x4 bytes for start and end time and offset).");
    return;
  }

  int pos = 0;
  unsigned int embPos = 0;
  d->elementID = readStringField(data, String::Latin1, &pos).data(String::Latin1);
  d->startTime = data.toUInt(pos, true);
  pos += 4;
  d->endTime = data.toUInt(pos, true);
  pos += 4;
  d->startOffset = data.toUInt(pos, true);
  pos += 4;
  d->endOffset = data.toUInt(pos, true);
  pos += 4;
  size -= pos;

  // Embedded frames are optional

  if(size < header()->size())
    return;

  while(embPos < size - header()->size()) {
    Frame *frame = FrameFactory::instance()->createFrame(data.mid(pos + embPos), (d->tagHeader != 0));

    if(!frame)
      return;

    // Checks to make sure that frame parsed correctly.
    if(frame->size() <= 0) {
      delete frame;
      return;
    }

    embPos += frame->size() + header()->size();
    addEmbeddedFrame(frame);
  }
}

ByteVector ChapterFrame::renderFields() const
{
  ByteVector data;

  data.append(d->elementID);
  data.append('\0');
  data.append(ByteVector::fromUInt(d->startTime, true));
  data.append(ByteVector::fromUInt(d->endTime, true));
  data.append(ByteVector::fromUInt(d->startOffset, true));
  data.append(ByteVector::fromUInt(d->endOffset, true));
  FrameList l = d->embeddedFrameList;
  for(FrameList::ConstIterator it = l.begin(); it != l.end(); ++it)
    data.append((*it)->render());

  return data;
}

ChapterFrame::ChapterFrame(const ID3v2::Header *tagHeader, const ByteVector &data, Header *h) :
  Frame(h)
{
  d = new ChapterFramePrivate;
  d->tagHeader = tagHeader;
  parseFields(fieldData(data));
}
<|endoftext|>


<commit_before>#include "window_configuration.h"

const char *kFlutterWindowTitle = "taqo_client";
const unsigned int kFlutterWindowWidth = 1280;
const unsigned int kFlutterWindowHeight = 720;
<commit_msg>Fix window title and initial size<commit_after>#include "window_configuration.h"

const char *kFlutterWindowTitle = "Taqo";
const unsigned int kFlutterWindowWidth = 1024;
const unsigned int kFlutterWindowHeight = 768;
<|endoftext|>


<commit_before>#include "condor_common.h"
#include <iostream.h>
#include "condor_config.h"
#include "condor_classad.h"
#include "condor_debug.h"
#include "condor_attributes.h"

#include "MyString.h"
#include "TimeClass.h"

//------------------------------------------------------------------------

static void displayJobShort(ClassAd *ad);
static void short_header(void);
static void short_print(int,int,const char*,int,int,int,int,int,const char *);
static void short_header (void);
static void displayJobShort (ClassAd *);
static void shorten (char *, int);
static char* format_date( time_t date );
static char* format_time( int tot_secs );
static char encode_status( int status );

//------------------------------------------------------------------------

main()
{
  config( 0 );
  MyString LogFileName=param("SPOOL");
  LogFileName+="/job_history.log";
  FILE* LogFile=fopen(LogFileName,"r");
  if (!LogFile) {
    cerr << "No jobs logged in the history file." << endl;
    exit(1);
  }

  int EndFlag=0;
  short_header();
  while(!EndFlag) {
    ClassAd* ad=new ClassAd(LogFile,"***",EndFlag);
    displayJobShort(ad);
  }

  fclose(LogFile);
  exit(0);
}

//------------------------------------------------------------------------

static void
displayJobShort (ClassAd *ad)
{
        int cluster, proc, date, status, prio, image_size;
        float utime;
        char owner[64], cmd[2048], args[2048];

        if (!ad->EvalInteger (ATTR_CLUSTER_ID, NULL, cluster)           ||
                !ad->EvalInteger (ATTR_PROC_ID, NULL, proc)                             ||
                !ad->EvalInteger (ATTR_Q_DATE, NULL, date)                              ||
                !ad->EvalFloat   (ATTR_JOB_REMOTE_USER_CPU, NULL, utime)||
                !ad->EvalInteger (ATTR_JOB_STATUS, NULL, status)                ||
                !ad->EvalInteger (ATTR_JOB_PRIO, NULL, prio)                    ||
                !ad->EvalInteger (ATTR_IMAGE_SIZE, NULL, image_size)    ||
                !ad->EvalString  (ATTR_OWNER, NULL, owner)                              ||
                !ad->EvalString  (ATTR_JOB_CMD, NULL, cmd) )
        {
                printf (" --- ???? --- \n");
                return;
        }

        shorten (owner, 14);
        if (ad->EvalString ("Args", NULL, args)) strcat (cmd, args);
        shorten (cmd, 18);
        short_print (cluster, proc, owner, date, (int)utime, status, prio,
                                        image_size, cmd);

}

//------------------------------------------------------------------------

static void
short_header (void)
{
    printf( " %-7s %-14s %11s %12s %-2s %-3s %-4s %-18s\n",
        "ID",
        "OWNER",
        "SUBMITTED",
        "CPU_USAGE",
        "ST",
        "PRI",
        "SIZE",
        "CMD"
    );
}

//------------------------------------------------------------------------

static void
shorten (char *buff, int len)
{
    if ((unsigned int)strlen (buff) > (unsigned int)len) buff[len] = '\0';
}

//------------------------------------------------------------------------

/*
  Print a line of data for the "short" display of a PROC structure.  The
  "short" display is the one used by "condor_q".  N.B. the columns used
  by this routine must match those defined by the short_header routine
  defined above.
*/

static void
short_print(
        int cluster,
        int proc,
        const char *owner,
        int date,
        int time,
        int status,
        int prio,
        int image_size,
        const char *cmd
        ) {
        printf( "%4d.%-3d %-14s %-11s %-12s %-2c %-3d %-4.1f %-18s\n",
                cluster,
                proc,
                owner,
                format_date(date),
                format_time(time),
                encode_status(status),
                prio,
                image_size/1024.0,
                cmd
        );
}

//------------------------------------------------------------------------

/*
  Format a date expressed in "UNIX time" into "month/day hour:minute".
*/

static char* format_date( time_t date )
{
        static char     buf[ 12 ];
        struct tm       *tm;

        tm = localtime( &date );
        sprintf( buf, "%2d/%-2d %02d:%02d",
                (tm->tm_mon)+1, tm->tm_mday, tm->tm_hour, tm->tm_min
        );
        return buf;
}

//------------------------------------------------------------------------

/*
  Format a time value which is encoded as seconds since the UNIX
  "epoch".  We return a string in the format dd+hh:mm:ss, indicating
  days, hours, minutes, and seconds.  The string is in static data
  space, and will be overwritten by the next call to this function.
*/

static char     *
format_time( int tot_secs )
{
        int             days;
        int             hours;
        int             min;
        int             secs;
        static char     answer[25];

        days = tot_secs / DAY;
        tot_secs %= DAY;
        hours = tot_secs / HOUR;
        tot_secs %= HOUR;
        min = tot_secs / MINUTE;
        secs = tot_secs % MINUTE;

        (void)sprintf( answer, "%3d+%02d:%02d:%02d", days, hours, min, secs );
        return answer;
}

//------------------------------------------------------------------------

/*
  Encode a status from a PROC structure as a single letter suited for
  printing.
*/

static char
encode_status( int status )
{
        switch( status ) {
          case UNEXPANDED:
                return 'U';
          case IDLE:
                return 'I';
          case RUNNING:
                return 'R';
          case COMPLETED:
                return 'C';
          case REMOVED:
                return 'X';
          default:
                return ' ';
        }
}

<commit_msg>Added -v to condor_history<commit_after>#include "condor_common.h"
#include "condor_config.h"
#include "condor_classad.h"
#include "condor_debug.h"
#include "condor_attributes.h"

#include "MyString.h"
#include "TimeClass.h"

//------------------------------------------------------------------------

static void displayJobShort(ClassAd *ad);
static void short_header(void);
static void short_print(int,int,const char*,int,int,int,int,int,const char *);
static void short_header (void);
static void displayJobShort (ClassAd *);
static void shorten (char *, int);
static char* format_date( time_t date );
static char* format_time( int tot_secs );
static char encode_status( int status );

//------------------------------------------------------------------------

static void Usage(char* name)
{
  printf("Usage: %s [-v]\n",name);
}

//------------------------------------------------------------------------

main(int argc, char* argv[])
{
  if (argc>2 || (argc==2 && strcmp(argv[1],"-v")!=0)) {
    Usage(argv[0]);
    exit(1);
  }

  config( 0 );
  MyString LogFileName=param("SPOOL");
  LogFileName+="/job_history.log";
  FILE* LogFile=fopen(LogFileName,"r");
  if (!LogFile) {
    fprintf(stderr,"No jobs logged in the history file.\n");
    exit(1);
  }

  int EndFlag=0;
  short_header();
  while(!EndFlag) {
    ClassAd* ad=new ClassAd(LogFile,"***",EndFlag);
    if (argc==1) displayJobShort(ad);
    else { ad->fPrint(stdout); printf("\n"); }
  }

  fclose(LogFile);
  exit(0);
}

//------------------------------------------------------------------------

static void
displayJobShort (ClassAd *ad)
{
        int cluster, proc, date, status, prio, image_size;
        float utime;
        char owner[64], cmd[2048], args[2048];

        if (!ad->EvalInteger (ATTR_CLUSTER_ID, NULL, cluster)           ||
                !ad->EvalInteger (ATTR_PROC_ID, NULL, proc)                             ||
                !ad->EvalInteger (ATTR_Q_DATE, NULL, date)                              ||
                !ad->EvalFloat   (ATTR_JOB_REMOTE_USER_CPU, NULL, utime)||
                !ad->EvalInteger (ATTR_JOB_STATUS, NULL, status)                ||
                !ad->EvalInteger (ATTR_JOB_PRIO, NULL, prio)                    ||
                !ad->EvalInteger (ATTR_IMAGE_SIZE, NULL, image_size)    ||
                !ad->EvalString  (ATTR_OWNER, NULL, owner)                              ||
                !ad->EvalString  (ATTR_JOB_CMD, NULL, cmd) )
        {
                printf (" --- ???? --- \n");
                return;
        }

        shorten (owner, 14);
        if (ad->EvalString ("Args", NULL, args)) strcat (cmd, args);
        shorten (cmd, 18);
        short_print (cluster, proc, owner, date, (int)utime, status, prio,
                                        image_size, cmd);

}

//------------------------------------------------------------------------

static void
short_header (void)
{
    printf( " %-7s %-14s %11s %12s %-2s %-3s %-4s %-18s\n",
        "ID",
        "OWNER",
        "SUBMITTED",
        "CPU_USAGE",
        "ST",
        "PRI",
        "SIZE",
        "CMD"
    );
}

//------------------------------------------------------------------------

static void
shorten (char *buff, int len)
{
    if ((unsigned int)strlen (buff) > (unsigned int)len) buff[len] = '\0';
}

//------------------------------------------------------------------------

/*
  Print a line of data for the "short" display of a PROC structure.  The
  "short" display is the one used by "condor_q".  N.B. the columns used
  by this routine must match those defined by the short_header routine
  defined above.
*/

static void
short_print(
        int cluster,
        int proc,
        const char *owner,
        int date,
        int time,
        int status,
        int prio,
        int image_size,
        const char *cmd
        ) {
        printf( "%4d.%-3d %-14s %-11s %-12s %-2c %-3d %-4.1f %-18s\n",
                cluster,
                proc,
                owner,
                format_date(date),
                format_time(time),
                encode_status(status),
                prio,
                image_size/1024.0,
                cmd
        );
}

//------------------------------------------------------------------------

/*
  Format a date expressed in "UNIX time" into "month/day hour:minute".
*/

static char* format_date( time_t date )
{
        static char     buf[ 12 ];
        struct tm       *tm;

        tm = localtime( &date );
        sprintf( buf, "%2d/%-2d %02d:%02d",
                (tm->tm_mon)+1, tm->tm_mday, tm->tm_hour, tm->tm_min
        );
        return buf;
}

//------------------------------------------------------------------------

/*
  Format a time value which is encoded as seconds since the UNIX
  "epoch".  We return a string in the format dd+hh:mm:ss, indicating
  days, hours, minutes, and seconds.  The string is in static data
  space, and will be overwritten by the next call to this function.
*/

static char     *
format_time( int tot_secs )
{
        int             days;
        int             hours;
        int             min;
        int             secs;
        static char     answer[25];

        days = tot_secs / DAY;
        tot_secs %= DAY;
        hours = tot_secs / HOUR;
        tot_secs %= HOUR;
        min = tot_secs / MINUTE;
        secs = tot_secs % MINUTE;

        (void)sprintf( answer, "%3d+%02d:%02d:%02d", days, hours, min, secs );
        return answer;
}

//------------------------------------------------------------------------

/*
  Encode a status from a PROC structure as a single letter suited for
  printing.
*/

static char
encode_status( int status )
{
        switch( status ) {
          case UNEXPANDED:
                return 'U';
          case IDLE:
                return 'I';
          case RUNNING:
                return 'R';
          case COMPLETED:
                return 'C';
          case REMOVED:
                return 'X';
          default:
                return ' ';
        }
}

<|endoftext|>


<commit_before>/* RTcmix  - Copyright (C) 2000  The RTcmix Development Team
   See ``AUTHORS'' for a list of contributors. See ``LICENSE'' for
   the license to this software and for a DISCLAIMER OF ALL WARRANTIES.
*/

/* Originally by Brad Garton and Doug Scott (SGI code) and Dave Topper
   (Linux code). Reworked for v2.3 by John Gibson.
*/
#include <globals.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <errno.h>
#include <assert.h>
#include "../rtstuff/rtdefs.h"

#ifdef LINUX
   #include <sys/types.h>
   #include <sys/stat.h>
   #include <fcntl.h>
   #include <sys/ioctl.h>
   #ifdef ALSA
      #include <sys/soundcard.h>
      #define open_ports()  open_alsa_ports()
   #endif
   #ifdef OSS
      #include <sys/soundcard.h>
      #define open_ports()  open_oss_ports()
   #endif

   #define AUDIO_DATUM_SIZE   (sizeof(short))
   #define BASE_SND_DEVICE    "/dev/dsp"
   #define NUM_OSS_FRAGMENTS   10
#endif /* LINUX */

#ifdef SGI
   #include <dmedia/audio.h>
   #include <ulocks.h>

  /* This macro is only in AL 2.0, so I use it to distinguish 2.0 from 1.0 */
   #ifdef AL_MAX_STRLEN
      #define AL_2_0
   #endif

   #ifndef AL_2_0
      #define alSetSampFmt ALsetsampfmt
      #define alSetFloatMax ALsetfloatmax
      #define alSetWidth ALsetwidth
      #define alSetChannels ALsetchannels
      #define alOpenPort ALopenport
      #define alClosePort ALcloseport
      #define alSetFloatMax ALsetfloatmax
      #define alNewConfig ALnewconfig
      #define alFreeConfig ALfreeconfig
      #define alSetConfig ALsetconfig
      #define alSetQueueSize ALsetqueuesize

      /* this function doesn't exist under 1.0 */
      const char *alGetErrorString(int err) { return ""; }
   #endif /* !AL_2_0 */
   static char *output_port = NULL;
   #ifdef NOTYET
      extern usema_t *audio_sema;      /* in Minc/intraverse.C */
   #endif
#endif /* SGI */

#ifdef LINUX

/* ---------------------------------------------------------- open_device --- */
/* Open the specified audio device, and return its file descriptor.
   If error on open, print error msg and return -1.

   <num> is a number appended to the BASE_SND_DEVICE string.
         If -1, then no number appended.

   <access_type> are the flags passed to open (e.g., O_WRONLY).

   Examples (if BASE_SND_DEVICE is "/dev/dsp"):
      open_device(2, O_RDWR);      ... opens "/dev/dsp2" for read/write access.
      open_device(-1, O_RDONLY);   ... opens "/dev/dsp" for read-only access.
*/
static int
open_device(int num, int access_type)
{
   int   fd;
   char  buf[256];

   if (num == -1)
      strcpy(buf, BASE_SND_DEVICE);
   else
      sprintf(buf, "%s%d", BASE_SND_DEVICE, num);

   fd = open(buf, access_type, 0);
   if (fd == -1) {
      char  str[256];
      sprintf(str, "open_device: (%s)", buf);
      perror(str);
   }

   return fd;
}

#ifdef ALSA

/* ------------------------------------------------------ open_alsa_ports --- */
static int
open_alsa_ports()
{
// FIXME: needs much work  -JGG

   if (out_port) {
      fprintf(stderr, "Audio ports already opened!\n");
      return -1;
   }

#ifdef RME
#else /* !RME */
#endif /* !RME */

   return 0;
err:
   fprintf(stderr, "Could not open audio ports.\n");
   return -1;
}

#endif /* ALSA */

#ifdef OSS

/* ----------------------------------------------------- setup_oss_device --- */
/* Set up the audio device parameters. Return 0 if ok, -1 if error.
*/
static int
setup_oss_device(
      int   fd,             /* file descriptor of device just opened */
      int   nchans,         /* number of chans for this device */
      int   srate,          /* sampling rate */
      int   num_frags,      /* number of buffer fragments */
      int   full_duplex,    /* 1 if you want a full duplex device */
      int   *buffer_size)   /* desired buffer size; actual size returned */
{
   int      format, arg, stereo, tmp, frag_size;
   double   bufexponent;

   assert(fd >= 0);

   // FIXME: Is this really supposed to go before the others?  -JG
   if (full_duplex) {
      if (ioctl(fd, SNDCTL_DSP_SETDUPLEX, &tmp) == -1) {
         perror("SNDCTL_DSP_SETDUPLEX");
         return -1;
      }
   }

   /* Set buffering parameters (number of fragments and fragment size).
      OSS requires this way of specifying things.
   */
   arg = num_frags << 16;
   bufexponent = log((double) *buffer_size) / log(2.0);
   arg += (int) bufexponent;
#ifdef DEBUG
   printf("arg: %#10.8x\n", arg);
#endif
   if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &arg) == -1) {
      perror("SNDCTL_DSP_SETFRAGMENT");
      return -1;
   }

   /* Set sample format */
#ifdef SNDLIB_LITTLE_ENDIAN
   format = AFMT_S16_LE;
#else
   format = AFMT_S16_BE;
#endif
   if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) == -1) {
      perror("SNDCTL_DSP_SETFMT");
      return -1;
   }

   /* Set stereo / mono (1/0) */
   stereo = nchans - 1;
   if (ioctl(fd, SNDCTL_DSP_STEREO, &stereo) == -1) {
      perror("SNDCTL_DSP_STEREO");
      return -1;
   }

   /* Set sample rate */
   if (ioctl(fd, SNDCTL_DSP_SPEED, &srate) == -1) {
      perror("SNDCTL_DSP_SPEED");
      return -1;
   }

   /* Get size of audio buffer. Note that driver computes this optimally. */
   if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) == -1) {
      perror("SNDCTL_DSP_GETBLKSIZE");
      return -1;
   }
#ifdef DEBUG
   printf("Buffer size: %d (requested), %d (actual)\n",
                                                    *buffer_size, frag_size);
#endif

   return 0;
}

/* ------------------------------------------------------- open_oss_ports --- */
static int
open_oss_ports()
{
   int   status, datum_size, buf_bytes;

   if (out_port) {
      fprintf(stderr, "Audio ports already opened!\n");
      return -1;
   }

   datum_size = AUDIO_DATUM_SIZE;

#ifdef RME
#else /* !RME */
   /* This works for Creative/Ensoniq AudioPCI and other consumer cards. */
   if (full_duplex) {
      out_port = open_device(-1, O_RDWR);
      if (out_port == -1)
         goto err;
      in_port = out_port;
   }
   else {
      out_port = open_device(-1, O_WRONLY);
      if (out_port == -1)
         goto err;
   }
   buf_bytes = RTBUFSAMPS * NCHANS * sizeof(short);
   status = setup_oss_device(out_port, NCHANS, (int) SR,
                                 NUM_OSS_FRAGMENTS, full_duplex, &buf_bytes);

   printf("Output buffer:  %d bytes\n", buf_bytes);
   if (full_duplex)
      printf("Input buffer:   %d bytes\n", buf_bytes);
#endif /* !RME */

   /* I think OSS can change our requested buffer size.  -JGG */
   RTBUFSAMPS = (buf_bytes / datum_size) / NCHANS;

   return status;
err:
   fprintf(stderr, "Could not open audio ports.\n");
   return -1;
}
#endif /* OSS */

#endif /* LINUX */

#ifdef SGI

/* ------------------------------------------------------- open_sgi_ports --- */
/* Configure and open output audio port.
   We will write floats directly to the device, letting it know that they
   will be within short integer range so we do not need to limit.  This
   reduces the CPU overhead of the alWriteSamps call.
*/
// FIXME: We don't yet support this float-writing in the
//        Linux-derived SGI port.   -JGG
static int
open_sgi_ports()
{
   long     pvbuf[2], buflen;
   ALconfig out_port_config;

   out_port_config = alNewConfig();

#ifdef AL_2_0
   /* Set output port if we specified one. */
   if (output_port != NULL) {
      int device = alGetResourceByName(AL_SYSTEM, output_port, AL_DEVICE_TYPE);
      if (device > 0)
         alSetDevice(out_port_config, device);
      else {
         fprintf(stderr, "WARNING: The audio port you specified: '%s', "
                         "is invalid\nUsing default port.\n", output_port);
         alSetDevice(out_port_config, AL_DEFAULT_DEVICE);
      }
   }
   alSetLimiting(out_port_config, 0);
#endif

#ifdef SEND_FLOATS_TO_DAC
   alSetSampFmt(out_port_config, AL_SAMPFMT_FLOAT);
   alSetFloatMax(out_port_config, 32768.0);
#else
   alSetSampFmt(out_port_config, AL_SAMPFMT_TWOSCOMP);
   alSetWidth(out_port_config, AL_SAMPLE_16);
#endif

   alSetChannels(out_port_config, NCHANS);

   if (alSetQueueSize(out_port_config, RTBUFSAMPS * 4) == -1) {
      fprintf(stderr, "Could not configure the output audio port queue "
                      "size to %d\n", RTBUFSAMPS * 4);
      alFreeConfig(out_port_config);
      return -1;
   }
   pvbuf[0] = AL_OUTPUT_RATE;
   pvbuf[1] = (long) SR;
   buflen = 2;
   ALsetparams(AL_DEFAULT_DEVICE, pvbuf, buflen);

// FIXME: We can't handle buffer size changing yet.   -JGG
#ifdef NOT_YET
   /* open up thet thar audio port! (if it has not been opened).
      otherwise, attempt to reconfigure the existing port.  If we have
      changed buffer size, we need to close and reopen.
   */
   if (out_port != NULL && newBufSamps != RTBUFSAMPS) {
      if (alClosePort(out_port) < 0) {
         fprintf(stderr,
                 "Could not close output audio port for reconfigure:  %s\n",
                 alGetErrorString(oserror()));
         return -1;
      }
      out_port = NULL;
      RTBUFSAMPS = newBufSamps;
   }
#endif /* NOT_YET */
   if (out_port == NULL)
      out_port = alOpenPort("rtcmixout", "w", out_port_config);
   else if (alSetConfig(out_port, out_port_config) < 0) {
      fprintf(stderr, "Could not reconfigure output audio port:  %s\n",
              alGetErrorString(oserror()));
   }

   alFreeConfig(out_port_config);

   if (!out_port) {
      fprintf(stderr, "Could not open output audio port:  %s\n",
              alGetErrorString(oserror()));
      exit(-1);
   }

   noaudio = 1;
#ifdef NOTYET
   if (audio_sema)
      usvsema(audio_sema);         /* wake up server if in that mode */
#endif

   return 0;
}

#endif /* SGI */

/* ---------------------------------------------------------- rtsetparams --- */
/* Minc function that sets output sampling rate (p0), maximum number of
   output channels (p1), and (optionally) I/O buffer size (p2).

   On SGI, the optional p3 lets you specify the output port as a string
   (e.g., "LINE", "DIGITAL", etc.).

   Based on this information, rtsetparams allocates a mono output buffer
   for each of the output channels, and opens output devices.
*/
double
rtsetparams(float p[], int n_args, double pp[])
{
   int   i, status;

// FIXME: Need better names for NCHANS, RTBUFSAMPS and MAXBUF. Would prefer
//        to get rid of MAXBUF or make it a constant again.  -JGG

   SR = p[0];
   NCHANS = (int) p[1];
   RTBUFSAMPS = n_args > 2 ? (int) p[2] : 8192;

   if (n_args > 3) {
#ifdef SGI
      /* Cast Minc double to char ptr to get string. */
      int iarg = (int) pp[3];
      output_port = (char *) iarg;
      printf("Playing through output port '%s'\n", output_port);
#endif /* SGI */
   }

   if (NCHANS > MAXBUS) {
      fprintf(stderr, "You can only have %d output channels.\n", MAXBUS);
      exit(1);
   }

   /* play_audio is true unless user has called set_option("audio_off") before
      rtsetparams. This would let user run multiple jobs, as long as only one
      needs the audio drivers.  -JGG
   */
   if (play_audio) {
      /* Open audio input and output ports. */
#ifdef LINUX
      status = open_ports();
#endif /* LINUX */
#ifdef SGI
      status = open_sgi_ports();
#endif /* SGI */
      if (status == -1)
         exit(1);
   }

   /* inTraverse waits for this. Set it even if play_audio is false! */
   audio_config = 1;

   printf("Audio set:  %g sampling rate, %d channels\n", SR, NCHANS);

   /* Allocate output buffers. Do this *after* opening audio devices,
      in case OSS changes our buffer size, for example.
   */
   for (i = 0; i < NCHANS; i++) {
      allocate_out_buffer(i, RTBUFSAMPS);
   }

   MAXBUF = (int) NCHANS * RTBUFSAMPS;

   return 0.0;
}

<commit_msg>Use MONO_DEVICES symbol; attempt to support multiple-device cards. Set new rtsetparams_called var, for use by inTraverse. New close_audio_ports function.<commit_after>/* RTcmix  - Copyright (C) 2000  The RTcmix Development Team
   See ``AUTHORS'' for a list of contributors. See ``LICENSE'' for
   the license to this software and for a DISCLAIMER OF ALL WARRANTIES.
*/

/* Originally by Brad Garton and Doug Scott (SGI code) and Dave Topper
   (Linux code). Reworked for v2.3 by John Gibson.
*/
#include <globals.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <errno.h>
#include <assert.h>
#include "../rtstuff/rtdefs.h"

#ifdef LINUX
   #include <sys/types.h>
   #include <sys/stat.h>
   #include <fcntl.h>
   #include <sys/ioctl.h>
   #ifdef ALSA
      #include <sys/soundcard.h>
      #define open_ports()  open_alsa_ports()
   #endif
   #ifdef OSS
      #include <sys/soundcard.h>
      #define open_ports()  open_oss_ports()
   #endif

   #define AUDIO_DATUM_SIZE   (sizeof(short))
   #define BASE_SND_DEVICE    "/dev/dsp"
   #define NUM_OSS_FRAGMENTS   10
#endif /* LINUX */

#ifdef SGI
   #include <dmedia/audio.h>
   #include <ulocks.h>

  /* This macro is only in AL 2.0, so I use it to distinguish 2.0 from 1.0 */
   #ifdef AL_MAX_STRLEN
      #define AL_2_0
   #endif

   #ifndef AL_2_0
      #define alSetSampFmt ALsetsampfmt
      #define alSetFloatMax ALsetfloatmax
      #define alSetWidth ALsetwidth
      #define alSetChannels ALsetchannels
      #define alOpenPort ALopenport
      #define alClosePort ALcloseport
      #define alSetFloatMax ALsetfloatmax
      #define alNewConfig ALnewconfig
      #define alFreeConfig ALfreeconfig
      #define alSetConfig ALsetconfig
      #define alSetQueueSize ALsetqueuesize

      /* this function doesn't exist under 1.0 */
      const char *alGetErrorString(int err) { return ""; }
   #endif /* !AL_2_0 */
   static char *output_port = NULL;
   #ifdef NOTYET
      extern usema_t *audio_sema;      /* in Minc/intraverse.C */
   #endif
#endif /* SGI */

#ifdef LINUX

/* ---------------------------------------------------------- open_device --- */
/* Open the specified audio device, and return its file descriptor.
   If error on open, print error msg and return -1.

   <num> is a number appended to the BASE_SND_DEVICE string.
         If -1, then no number appended.

   <access_type> are the flags passed to open (e.g., O_WRONLY).

   Examples (if BASE_SND_DEVICE is "/dev/dsp"):
      open_device(2, O_RDWR);      ... opens "/dev/dsp2" for read/write access.
      open_device(-1, O_RDONLY);   ... opens "/dev/dsp" for read-only access.
*/
static int
open_device(int num, int access_type)
{
   int   fd;
   char  buf[256];

   if (num == -1)
      strcpy(buf, BASE_SND_DEVICE);
   else
      sprintf(buf, "%s%d", BASE_SND_DEVICE, num);

   fd = open(buf, access_type, 0);
   if (fd == -1) {
      char  str[256];
      sprintf(str, "open_device: (%s)", buf);
      perror(str);
   }

   return fd;
}

#ifdef ALSA

/* ------------------------------------------------------ open_alsa_ports --- */
static int
open_alsa_ports()
{
// FIXME: needs much work  -JGG

   if (out_port) {
      fprintf(stderr, "Audio ports already opened!\n");
      return -1;
   }

#ifdef MONO_DEVICES
#else /* !MONO_DEVICES */
#endif /* !MONO_DEVICES */

   return 0;
err:
   fprintf(stderr, "Could not open audio ports.\n");
   return -1;
}

#endif /* ALSA */

#ifdef OSS

/* ----------------------------------------------------- setup_oss_device --- */
/* Set up the audio device parameters. Return 0 if ok, -1 if error.
*/
static int
setup_oss_device(
      int   fd,             /* file descriptor of device just opened */
      int   nchans,         /* number of chans for this device */
      int   srate,          /* sampling rate */
      int   num_frags,      /* number of buffer fragments */
      int   full_duplex,    /* 1 if you want a full duplex device */
      int   *buffer_size)   /* desired buffer size; actual size returned */
{
   int      format, arg, stereo, tmp, frag_size;
   double   bufexponent;

   assert(fd >= 0);

   // FIXME: Is this really supposed to go before the others?  -JG
   if (full_duplex) {
      if (ioctl(fd, SNDCTL_DSP_SETDUPLEX, &tmp) == -1) {
         perror("SNDCTL_DSP_SETDUPLEX");
         return -1;
      }
   }

   /* Set buffering parameters (number of fragments and fragment size).
      OSS requires this way of specifying things.
   */
   arg = num_frags << 16;
   bufexponent = log((double) *buffer_size) / log(2.0);
   arg += (int) bufexponent;
#ifdef DEBUG
   printf("arg: %#10.8x\n", arg);
#endif
   if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &arg) == -1) {
      perror("SNDCTL_DSP_SETFRAGMENT");
      return -1;
   }

   /* Set sample format */
#ifdef SNDLIB_LITTLE_ENDIAN
   format = AFMT_S16_LE;
#else
   format = AFMT_S16_BE;
#endif
   if (ioctl(fd, SNDCTL_DSP_SETFMT, &format) == -1) {
      perror("SNDCTL_DSP_SETFMT");
      return -1;
   }

   /* Set stereo / mono (1/0) */
   stereo = nchans - 1;
   if (ioctl(fd, SNDCTL_DSP_STEREO, &stereo) == -1) {
      perror("SNDCTL_DSP_STEREO");
      return -1;
   }

   /* Set sample rate */
   if (ioctl(fd, SNDCTL_DSP_SPEED, &srate) == -1) {
      perror("SNDCTL_DSP_SPEED");
      return -1;
   }

   /* Get size of audio buffer. Note that driver computes this optimally. */
   if (ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &frag_size) == -1) {
      perror("SNDCTL_DSP_GETBLKSIZE");
      return -1;
   }
#ifdef DEBUG
   printf("Buffer size: %d (requested), %d (actual)\n",
                                                    *buffer_size, frag_size);
#endif

   return 0;
}

/* ------------------------------------------------------- open_oss_ports --- */
static int
open_oss_ports()
{
   int   n, status, datum_size, buf_bytes;

   datum_size = AUDIO_DATUM_SIZE;

#ifdef MONO_DEVICES

   buf_bytes = RTBUFSAMPS * sizeof(short);

   for (n = 0; n < NCHANS; n++) {
      out_port[n] = open_device(n, O_WRONLY);
      if (out_port[n] == -1)
         goto err;
      status = setup_oss_device(out_port[n], 1, (int) SR,
                                          NUM_OSS_FRAGMENTS, 0, &buf_bytes);
   }

   if (full_duplex) {
//FIXME: But it's NOT necessarily NCHANS!
      for (n = 0; n < NCHANS; n++) {
         in_port[n] = open_device(n, O_RDONLY);
         if (in_port[n] == -1)
            goto err;
         status = setup_oss_device(in_port[n], 1, (int) SR,
                                          NUM_OSS_FRAGMENTS, 0, &buf_bytes);
      }
   }

#else /* !MONO_DEVICES */

   if (out_port[0]) {
      fprintf(stderr, "Audio ports already opened!\n");
      return -1;
   }

   /* This works for Creative/Ensoniq AudioPCI and other consumer cards. */
   if (full_duplex) {
      out_port[0] = open_device(-1, O_RDWR);
      if (out_port[0] == -1)
         goto err;
      in_port[0] = out_port[0];
   }
   else {
      out_port[0] = open_device(-1, O_WRONLY);
      if (out_port[0] == -1)
         goto err;
   }
   buf_bytes = RTBUFSAMPS * NCHANS * sizeof(short);
   status = setup_oss_device(out_port[0], NCHANS, (int) SR,
                                 NUM_OSS_FRAGMENTS, full_duplex, &buf_bytes);

#endif /* !MONO_DEVICES */

   printf("Output buffer:  %d bytes\n", buf_bytes);
   if (full_duplex)
      printf("Input buffer:   %d bytes\n", buf_bytes);

   /* I think OSS can change our requested buffer size.  -JGG */
   RTBUFSAMPS = (buf_bytes / datum_size) / NCHANS;

   return status;
err:
   fprintf(stderr, "Could not open audio ports.\n");
   return -1;
}
#endif /* OSS */

#endif /* LINUX */

#ifdef SGI

/* ------------------------------------------------------- open_sgi_ports --- */
/* Configure and open output audio port.
   We will write floats directly to the device, letting it know that they
   will be within short integer range so we do not need to limit.  This
   reduces the CPU overhead of the alWriteSamps call.
*/
// FIXME: We don't yet support this float-writing in the
//        Linux-derived SGI port.   -JGG
static int
open_sgi_ports()
{
   long     pvbuf[2], buflen;
   ALconfig out_port_config;

   out_port_config = alNewConfig();

#ifdef AL_2_0
   /* Set output port if we specified one. */
   if (output_port != NULL) {
      int device = alGetResourceByName(AL_SYSTEM, output_port, AL_DEVICE_TYPE);
      if (device > 0)
         alSetDevice(out_port_config, device);
      else {
         fprintf(stderr, "WARNING: The audio port you specified: '%s', "
                         "is invalid\nUsing default port.\n", output_port);
         alSetDevice(out_port_config, AL_DEFAULT_DEVICE);
      }
   }
   alSetLimiting(out_port_config, 0);
#endif

#ifdef SEND_FLOATS_TO_DAC
   alSetSampFmt(out_port_config, AL_SAMPFMT_FLOAT);
   alSetFloatMax(out_port_config, 32768.0);
#else
   alSetSampFmt(out_port_config, AL_SAMPFMT_TWOSCOMP);
   alSetWidth(out_port_config, AL_SAMPLE_16);
#endif

   alSetChannels(out_port_config, NCHANS);

   if (alSetQueueSize(out_port_config, RTBUFSAMPS * 4) == -1) {
      fprintf(stderr, "Could not configure the output audio port queue "
                      "size to %d\n", RTBUFSAMPS * 4);
      alFreeConfig(out_port_config);
      return -1;
   }
   pvbuf[0] = AL_OUTPUT_RATE;
   pvbuf[1] = (long) SR;
   buflen = 2;
   ALsetparams(AL_DEFAULT_DEVICE, pvbuf, buflen);

// FIXME: We can't handle buffer size changing yet.   -JGG
#ifdef NOT_YET
   /* open up thet thar audio port! (if it has not been opened).
      otherwise, attempt to reconfigure the existing port.  If we have
      changed buffer size, we need to close and reopen.
   */
   if (out_port != NULL && newBufSamps != RTBUFSAMPS) {
      if (alClosePort(out_port) < 0) {
         fprintf(stderr,
                 "Could not close output audio port for reconfigure:  %s\n",
                 alGetErrorString(oserror()));
         return -1;
      }
      out_port = NULL;
      RTBUFSAMPS = newBufSamps;
   }
#endif /* NOT_YET */
   if (out_port == NULL)
      out_port = alOpenPort("rtcmixout", "w", out_port_config);
   else if (alSetConfig(out_port, out_port_config) < 0) {
      fprintf(stderr, "Could not reconfigure output audio port:  %s\n",
              alGetErrorString(oserror()));
   }

   alFreeConfig(out_port_config);

   if (!out_port) {
      fprintf(stderr, "Could not open output audio port:  %s\n",
              alGetErrorString(oserror()));
      exit(-1);
   }

   noaudio = 1;
#ifdef NOTYET
   if (audio_sema)
      usvsema(audio_sema);         /* wake up server if in that mode */
#endif

   return 0;
}

#endif /* SGI */

/* ---------------------------------------------------------- rtsetparams --- */
/* Minc function that sets output sampling rate (p0), maximum number of
   output channels (p1), and (optionally) I/O buffer size (p2).

   On SGI, the optional p3 lets you specify the output port as a string
   (e.g., "LINE", "DIGITAL", etc.).

   Based on this information, rtsetparams allocates a mono output buffer
   for each of the output channels, and opens output devices.
*/
double
rtsetparams(float p[], int n_args, double pp[])
{
   int   i, status;

// FIXME: Need better names for NCHANS, RTBUFSAMPS and MAXBUF. Would prefer
//        to get rid of MAXBUF or make it a constant again.  -JGG

   SR = p[0];
   NCHANS = (int) p[1];
   RTBUFSAMPS = n_args > 2 ? (int) p[2] : 8192;

   if (n_args > 3) {
#ifdef SGI
      /* Cast Minc double to char ptr to get string. */
      int iarg = (int) pp[3];
      output_port = (char *) iarg;
      printf("Playing through output port '%s'\n", output_port);
#endif /* SGI */
   }

   if (NCHANS > MAXBUS) {
      fprintf(stderr, "You can only have %d output channels.\n", MAXBUS);
      exit(1);
   }

   /* play_audio is true unless user has called set_option("audio_off") before
      rtsetparams. This would let user run multiple jobs, as long as only one
      needs the audio drivers.  -JGG
   */
   if (play_audio) {
      /* Open audio input and output ports. */
#ifdef LINUX
      status = open_ports();
#endif /* LINUX */
#ifdef SGI
      status = open_sgi_ports();
#endif /* SGI */
      if (status == -1)
         exit(1);
   }

   /* inTraverse waits for this. Set it even if play_audio is false! */
   audio_config = 1;

   printf("Audio set:  %g sampling rate, %d channels\n", SR, NCHANS);

   /* Allocate output buffers. Do this *after* opening audio devices,
      in case OSS changes our buffer size, for example.
   */
   for (i = 0; i < NCHANS; i++) {
      allocate_out_buffer(i, RTBUFSAMPS);
   }

   MAXBUF = (int) NCHANS * RTBUFSAMPS;

   rtsetparams_called = 1;

   return 0.0;
}

/* ---------------------------------------------------- close_audio_ports --- */
void
close_audio_ports()
{
   int n;

#ifdef LINUX
 #ifdef MONO_DEVICES
   for (n = 0; n < NCHANS; n++)
      if (out_port[n])
         close(out_port[n]);
   for (n = 0; n < audioNCHANS; n++)
      if (in_port[n])
         close(in_port[n]);
 #else /* !MONO_DEVICES */
   if (out_port[0])
      close(out_port[0]);
   if (in_port[0] && in_port[0] != out_port[0])
      close(in_port[0]);
 #endif /* !MONO_DEVICES */
#endif /* LINUX */

#ifdef SGI
   if (out_port) {
      while (ALgetfilled(out_port) > 0)
         ;
// FIXME: anything else?
   }
#endif /* SGI */
}

<|endoftext|>


<commit_before>#include "bignum_conversions.h"
#include "bignum_types.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/**
 * Returns an binary string representation of a uint32_t. The string returned is
 * of length BITS_PER_WORD.
 * @param  number Number to be converted.
 * @return        String with the binary representation of number.
 */
char* uint32_t_to_string(uint32_t number)
{
    char* str = (char*) calloc(BITS_PER_WORD + 1, sizeof(char));
    str[BITS_PER_WORD] = '\0';

    for (uint32_t i = 0; i < BITS_PER_WORD; i++)
    {
        uint32_t masked_number = number & (1 << i);
        str[BITS_PER_WORD - 1 - i] = (masked_number != 0) ? '1' : '0';
    }

    return str;
}

/**
 * Converts a bignum to a binary string. The returned string will have a length
 * of TOTAL_BIT_LENGTH. The bignum passed as a parameter must not be NULL, or
 * else the function will fail.
 * @param  number Bignum to be converted.
 * @return        Binary string representation of the bignum.
 */
char* bignum_to_string(uint32_t* number)
{
    // make an array of strings which will each contain 1 of the
    // BIGNUM_NUMBER_OF_WORDS words in the bignum
    char** words = (char**) calloc(BIGNUM_NUMBER_OF_WORDS + 1, sizeof(char*));
    words[BIGNUM_NUMBER_OF_WORDS] = NULL;

    for (uint32_t i = 0; i < BIGNUM_NUMBER_OF_WORDS; i++)
    {
        words[i] = (char*) calloc(BITS_PER_WORD + 1, sizeof(char));
        words[i][BITS_PER_WORD] = '\0';

        // convert each bignum element to a string
        words[i] = uint32_t_to_string(number[i]);
    }

    // concatenate the words together to form a TOTAL_BIT_LENGTH long string
    char* final_str = (char*) calloc(TOTAL_BIT_LENGTH + 1, sizeof(char));
    final_str[TOTAL_BIT_LENGTH] = '\0';

    char* src;
    char* dest = final_str;
    for (uint32_t i = 0; i < BIGNUM_NUMBER_OF_WORDS; i++)
    {
        src = words[BIGNUM_NUMBER_OF_WORDS - i - 1];
        strncpy(dest, src, BITS_PER_WORD);

        dest += BITS_PER_WORD;
    }

    free_string_words(&words);

    // return concatenated string
    return final_str;
}

/**
 * Pads the binary string with zeros until it is TOTAL_BIT_LENGTH long.
 * @param old_str String to be padded with zeros.
 */
void pad_string_with_zeros(char** old_str)
{
    char* new_str = (char*) calloc(TOTAL_BIT_LENGTH + 1, sizeof(char));
    new_str[TOTAL_BIT_LENGTH] = '\0';
    for (uint32_t i = 0; i < TOTAL_BIT_LENGTH; i++)
    {
        new_str[i] = '0';
    }

    uint32_t old_str_length = strlen(*old_str);

    for (uint32_t i = 0; i < old_str_length; i++)
    {
        new_str[(TOTAL_BIT_LENGTH - old_str_length) + i] = (*old_str)[i];
    }

    free(*old_str);
    *old_str = new_str;
}

/**
 * Separates a TOTAL_BIT_LENGTH long binary string into an array of binary
 * strings, each of length BITS_PER_WORD. The returned array contains the most
 * significant bits at its last index, and its least significant bits at its
 * first position. Ex: str_words[0] contains bits (BITS_PER_WORD downto 0).
 * @param  str Binary string to be decomposed.
 * @return     Decomposed string.
 */
char** cut_string_to_multiple_words(char* str)
{
    // cut str into BIGNUM_NUMBER_OF_WORDS pieces, each of which is
    // BITS_PER_WORD long

    // array of BITS_PER_WORD length strings
    char** str_words = (char**) calloc(BIGNUM_NUMBER_OF_WORDS + 1, sizeof(char*));
    str_words[BIGNUM_NUMBER_OF_WORDS] = NULL;

    // allocate each one of the strings and fill them up
    for (uint32_t i = 0; i < BIGNUM_NUMBER_OF_WORDS; i++)
    {
        str_words[i] = (char*) calloc(BITS_PER_WORD + 1, sizeof(char));
        str_words[i][BITS_PER_WORD] = '\0';

        for (uint32_t j = 0; j < BITS_PER_WORD; j++)
        {
            str_words[i][j] = str[i * BITS_PER_WORD + j];
        }
    }

    // until now, the strings have been cut in big-endian form, but we want
    // little-endian for indexing, so we have to invert the array.
    char* tmp;
    uint32_t middle_of_array = CEILING(BIGNUM_NUMBER_OF_WORDS, 2);
    for (uint32_t i = 0; i < middle_of_array; i++)
    {
        tmp = str_words[i];
        str_words[i] = str_words[BIGNUM_NUMBER_OF_WORDS - 1 - i];
        str_words[BIGNUM_NUMBER_OF_WORDS - 1 - i] = tmp;
    }

    return str_words;
}

/**
 * Frees an array containing BIGNUM_NUMBER_OF_WORDS strings.
 * @param words Pointer to the array of strings to be freed.
 */
void free_string_words(char*** words)
{
    if (*words != NULL)
    {
        for (uint32_t i = 0; i < BIGNUM_NUMBER_OF_WORDS; i++)
        {
            if ((*words)[i] != NULL)
            {
                free((*words)[i]);
                (*words)[i] = NULL;
            }
        }

        // free the char** pointing to the words
        free(*words);
        *words = NULL;
    }
}

/**
 * Returns a uint32_t representation of the binary string of length
 * BITS_PER_WORD passed as a parameter.
 * @param  str Binary string to be converted.
 * @return     Converted value.
 */
uint32_t string_to_uint32_t(char* str)
{
    uint32_t number = 0;

    for (uint32_t i = 0; i < BITS_PER_WORD; i++)
    {
        uint32_t bit_value = str[BITS_PER_WORD - 1 - i] == '1' ? 1 : 0;
        number |= bit_value << i;
    }

    return number;
}

/**
 * Converts the "str" binary string of length TOTAL_BITS_LENGTH into a bignum
 * and stores the result in the bignum passed as a parameter. The bignum must
 * not be NULL, or else the function will fail.
 * @param str    Binary string to be converted.
 * @param number Number which will be assigned the value of the binary string
 * str.
 */
void string_to_bignum(char* str, uint32_t* number)
{
    char** words = cut_string_to_multiple_words(str);

    // set the number
    for (uint32_t i = 0; i < BIGNUM_NUMBER_OF_WORDS; i++)
    {
        number[i] = string_to_uint32_t(words[i]);
    }

    free_string_words(&words);
}

/**
 * Transforms an array of bignums from its non-coalesced representation to its
 * coalesced representation.
 * @param  in Bignum array to transform from its non-coalesced representation.
 */
void bignum_array_to_coalesced_bignum_array(uint32_t* in)
{
    transpose(in, BIGNUM_NUMBER_OF_WORDS, NUMBER_OF_BIGNUMS);
}

/**
 * Transforms an array of bignums from its coalesced representation to its
 * non-coalesced representation.
 * @param  in Bignum array to transform from its coalesced representation.
 */
void coalesced_bignum_array_to_bignum_array(uint32_t* in)
{
    transpose(in, NUMBER_OF_BIGNUMS, BIGNUM_NUMBER_OF_WORDS);
}

/**
 * Prints a bignum array.
 * @param in Bignum array to be printed.
 */
void print_bignum_array(uint32_t* in)
{
    for (uint32_t i = 0; i < NUMBER_OF_BIGNUMS; i++)
    {
        for (uint32_t j = 0; j < BIGNUM_NUMBER_OF_WORDS; j++)
        {
            printf("%11u    ", in[IDX(i, j)]);
        }

        printf("\n");
    }
}

/**
 * Prints a coalesced bignum array.
 * @param in Coalesced bignum array to be printed.
 */
void print_coalesced_bignum_array(uint32_t* in)
{
    for (uint32_t i = 0; i < BIGNUM_NUMBER_OF_WORDS; i++)
    {
        for (uint32_t j = 0; j < NUMBER_OF_BIGNUMS; j++)
        {
            printf("%11u    ", in[COAL_IDX(i, j)]);
        }

        printf("\n");
    }
}

/**
 * Transposes a 2D matrix of width "w" and height "h" in-place. All credit goes
 * to "http://rosettacode.org/wiki/Matrix_transposition#C" for the following
 * in-place matrix transposition code.
 * @param m Matrix to be transposed.
 * @param w Width of the matrix.
 * @param h Height of the matrix.
 */
void transpose(uint32_t* m, int w, int h)
{
    int start, next, i;
    uint32_t tmp;

    for (start = 0; start <= w * h - 1; start++)
    {
        next = start;
        i = 0;
        do
        {
            i++;
            next = (next % h) * w + next / h;
        }
        while (next > start);

        if (next < start || i == 1)
        {
            continue;
        }

        tmp = m[next = start];

        do
        {
            i = (next % h) * w + next / h;
            m[next] = (i == start) ? tmp : m[i];
            next = i;
        }
        while (next > start);
    }
}
<commit_msg>added error checking code to bignum_conversions.cpp<commit_after>#include "bignum_conversions.h"
#include "bignum_types.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/**
 * Returns an binary string representation of a uint32_t. The string returned is
 * of length BITS_PER_WORD.
 * @param  number Number to be converted.
 * @return        String with the binary representation of number.
 */
char* uint32_t_to_string(uint32_t number)
{
    char* str = (char*) calloc(BITS_PER_WORD + 1, sizeof(char));

    if (str != NULL)
    {
        str[BITS_PER_WORD] = '\0';

        for (uint32_t i = 0; i < BITS_PER_WORD; i++)
        {
            uint32_t masked_number = number & (1 << i);
            str[BITS_PER_WORD - 1 - i] = (masked_number != 0) ? '1' : '0';
        }

        return str;
    }
    else
    {
        printf("Error: could not allocate memory for \"str\"\n");
        exit(EXIT_FAILURE);
    }
}

/**
 * Converts a bignum to a binary string. The returned string will have a length
 * of TOTAL_BIT_LENGTH. The bignum passed as a parameter must not be NULL, or
 * else the function will fail.
 * @param  number Bignum to be converted.
 * @return        Binary string representation of the bignum.
 */
char* bignum_to_string(uint32_t* number)
{
    if (number != NULL)
    {
        // make an array of strings which will each contain 1 of the
        // BIGNUM_NUMBER_OF_WORDS words in the bignum
        char** words = (char**) calloc(BIGNUM_NUMBER_OF_WORDS + 1, sizeof(char*));

        if (words != NULL)
        {
            words[BIGNUM_NUMBER_OF_WORDS] = NULL;

            for (uint32_t i = 0; i < BIGNUM_NUMBER_OF_WORDS; i++)
            {
                words[i] = (char*) calloc(BITS_PER_WORD + 1, sizeof(char));

                if (words[i] != NULL)
                {
                    words[i][BITS_PER_WORD] = '\0';

                    // convert each bignum element to a string
                    words[i] = uint32_t_to_string(number[i]);
                }
                else
                {
                    printf("Error: could not allocate memory for \"words[%u]\"\n", i);
                    exit(EXIT_FAILURE);
                }
            }

            // concatenate the words together to form a TOTAL_BIT_LENGTH long
            // string
            char* final_str = (char*) calloc(TOTAL_BIT_LENGTH + 1, sizeof(char));

            if (final_str != NULL)
            {
                final_str[TOTAL_BIT_LENGTH] = '\0';

                char* src;
                char* dest = final_str;
                for (uint32_t i = 0; i < BIGNUM_NUMBER_OF_WORDS; i++)
                {
                    src = words[BIGNUM_NUMBER_OF_WORDS - i - 1];
                    strncpy(dest, src, BITS_PER_WORD);

                    dest += BITS_PER_WORD;
                }

                free_string_words(&words);

                // return concatenated string
                return final_str;
            }
            else
            {
                printf("Error: could not allocate memory for \"final_str\"\n");
                exit(EXIT_FAILURE);
            }
        }
        else
        {
            printf("Error: could not allocate memory for \"words\"\n");
            exit(EXIT_FAILURE);
        }
    }
    else
    {
        printf("Error: bignum \"number\" is NULL\n");
        exit(EXIT_FAILURE);
    }
}

/**
 * Pads the binary string with zeros until it is TOTAL_BIT_LENGTH long.
 * @param old_str String to be padded with zeros.
 */
void pad_string_with_zeros(char** old_str)
{
    if (old_str != NULL)
    {
        char* new_str = (char*) calloc(TOTAL_BIT_LENGTH + 1, sizeof(char));

        if (new_str != NULL)
        {
            new_str[TOTAL_BIT_LENGTH] = '\0';
            for (uint32_t i = 0; i < TOTAL_BIT_LENGTH; i++)
            {
                new_str[i] = '0';
            }

            uint32_t old_str_length = strlen(*old_str);

            for (uint32_t i = 0; i < old_str_length; i++)
            {
                new_str[(TOTAL_BIT_LENGTH - old_str_length) + i] = (*old_str)[i];
            }

            free(*old_str);
            *old_str = new_str;
        }
        else
        {
            printf("Error: could not allocate memory for \"new_str\"\n");
            exit(EXIT_FAILURE);
        }
    }
    else
    {
        printf("Error: \"old_str\" is NULL");
        exit(EXIT_FAILURE);
    }
}

/**
 * Separates a TOTAL_BIT_LENGTH long binary string into an array of binary
 * strings, each of length BITS_PER_WORD. The returned array contains the most
 * significant bits at its last index, and its least significant bits at its
 * first position. Ex: str_words[0] contains bits (BITS_PER_WORD downto 0).
 * @param  str Binary string to be decomposed.
 * @return     Decomposed string.
 */
char** cut_string_to_multiple_words(char* str)
{
    if (str != NULL)
    {
        // cut str into BIGNUM_NUMBER_OF_WORDS pieces, each of which is
        // BITS_PER_WORD long

        // array of BITS_PER_WORD length strings
        char** str_words = (char**) calloc(BIGNUM_NUMBER_OF_WORDS + 1, sizeof(char*));

        if (str_words != NULL)
        {
            str_words[BIGNUM_NUMBER_OF_WORDS] = NULL;

            // allocate each one of the strings and fill them up
            for (uint32_t i = 0; i < BIGNUM_NUMBER_OF_WORDS; i++)
            {
                str_words[i] = (char*) calloc(BITS_PER_WORD + 1, sizeof(char));

                if (str_words[i] != NULL)
                {
                    str_words[i][BITS_PER_WORD] = '\0';

                    for (uint32_t j = 0; j < BITS_PER_WORD; j++)
                    {
                        str_words[i][j] = str[i * BITS_PER_WORD + j];
                    }
                }
                else
                {
                    printf("Error: could not allocate memory for \"str_words[%u]\"\n", i);
                    exit(EXIT_FAILURE);
                }
            }

            // until now, the strings have been cut in big-endian form, but we
            // want little-endian for indexing, so we have to invert the array.
            char* tmp;
            uint32_t middle_of_array = CEILING(BIGNUM_NUMBER_OF_WORDS, 2);
            for (uint32_t i = 0; i < middle_of_array; i++)
            {
                tmp = str_words[i];
                str_words[i] = str_words[BIGNUM_NUMBER_OF_WORDS - 1 - i];
                str_words[BIGNUM_NUMBER_OF_WORDS - 1 - i] = tmp;
            }

            return str_words;
        }
        else
        {
            printf("Error: could not allocate memory for \"str_words\"\n");
            exit(EXIT_FAILURE);
        }
    }
    else
    {
        printf("Error: \"str\" is NULL");
        exit(EXIT_FAILURE);
    }
}

/**
 * Frees an array containing BIGNUM_NUMBER_OF_WORDS strings.
 * @param words Pointer to the array of strings to be freed.
 */
void free_string_words(char*** words)
{
    if (*words != NULL)
    {
        for (uint32_t i = 0; i < BIGNUM_NUMBER_OF_WORDS; i++)
        {
            if ((*words)[i] != NULL)
            {
                free((*words)[i]);
                (*words)[i] = NULL;
            }
        }

        // free the char** pointing to the words
        free(*words);
        *words = NULL;
    }
}

/**
 * Returns a uint32_t representation of the binary string of length
 * BITS_PER_WORD passed as a parameter.
 * @param  str Binary string to be converted.
 * @return     Converted value.
 */
uint32_t string_to_uint32_t(char* str)
{
    if (str != NULL)
    {
        uint32_t number = 0;

        for (uint32_t i = 0; i < BITS_PER_WORD; i++)
        {
            uint32_t bit_value = str[BITS_PER_WORD - 1 - i] == '1' ? 1 : 0;
            number |= bit_value << i;
        }

        return number;
    }
    else
    {
        printf("Error: \"str\" is NULL\n");
        exit(EXIT_FAILURE);
    }
}

/**
 * Converts the "str" binary string of length TOTAL_BITS_LENGTH into a bignum
 * and stores the result in the bignum passed as a parameter. The bignum must
 * not be NULL, or else the function will fail.
 * @param str    Binary string to be converted.
 * @param number Number which will be assigned the value of the binary string
 * str.
 */
void string_to_bignum(char* str, uint32_t* number)
{
    if (str != NULL && number != NULL)
    {
        char** words = cut_string_to_multiple_words(str);

        // set the number
        for (uint32_t i = 0; i < BIGNUM_NUMBER_OF_WORDS; i++)
        {
            number[i] = string_to_uint32_t(words[i]);
        }

        free_string_words(&words);
    }
    else
    {
        if (str == NULL)
        {
            printf("Error: \"str\" is NULL\n");
        }

        if (number == NULL)
        {
            printf("Error: bignum \"number\" is NULL\n");
        }

        exit(EXIT_FAILURE);
    }
}

/**
 * Transforms an array of bignums from its non-coalesced representation to its
 * coalesced representation.
 * @param  in Bignum array to transform from its non-coalesced representation.
 */
void bignum_array_to_coalesced_bignum_array(uint32_t* in)
{
    if (in != NULL)
    {
        transpose(in, BIGNUM_NUMBER_OF_WORDS, NUMBER_OF_BIGNUMS);
    }
    else
    {
        printf("Error: bignum array \"in\" is NULL\n");
        exit(EXIT_FAILURE);
    }
}

/**
 * Transforms an array of bignums from its coalesced representation to its
 * non-coalesced representation.
 * @param  in Bignum array to transform from its coalesced representation.
 */
void coalesced_bignum_array_to_bignum_array(uint32_t* in)
{
    if (in != NULL)
    {
        transpose(in, NUMBER_OF_BIGNUMS, BIGNUM_NUMBER_OF_WORDS);
    }
    else
    {
        printf("Error: bignum array \"in\" is NULL\n");
        exit(EXIT_FAILURE);
    }
}

/**
 * Prints a bignum array.
 * @param in Bignum array to be printed.
 */
void print_bignum_array(uint32_t* in)
{
    if (in != NULL)
    {
        for (uint32_t i = 0; i < NUMBER_OF_BIGNUMS; i++)
        {
            for (uint32_t j = 0; j < BIGNUM_NUMBER_OF_WORDS; j++)
            {
                printf("%11u    ", in[IDX(i, j)]);
            }

            printf("\n");
        }
    }
    else
    {
        printf("Error: bignum array \"in\" is NULL\n");
        exit(EXIT_FAILURE);
    }
}

/**
 * Prints a coalesced bignum array.
 * @param in Coalesced bignum array to be printed.
 */
void print_coalesced_bignum_array(uint32_t* in)
{
    if (in != NULL)
    {
        for (uint32_t i = 0; i < BIGNUM_NUMBER_OF_WORDS; i++)
        {
            for (uint32_t j = 0; j < NUMBER_OF_BIGNUMS; j++)
            {
                printf("%11u    ", in[COAL_IDX(i, j)]);
            }

            printf("\n");
        }
    }
    else
    {
        printf("Error: bignum array \"in\" is NULL\n");
        exit(EXIT_FAILURE);
    }
}

/**
 * Transposes a 2D matrix of width "w" and height "h" in-place. All credit goes
 * to "http://rosettacode.org/wiki/Matrix_transposition#C" for the following
 * in-place matrix transposition code.
 * @param m Matrix to be transposed.
 * @param w Width of the matrix.
 * @param h Height of the matrix.
 */
void transpose(uint32_t* m, int w, int h)
{
    int start, next, i;
    uint32_t tmp;

    for (start = 0; start <= w * h - 1; start++)
    {
        next = start;
        i = 0;
        do
        {
            i++;
            next = (next % h) * w + next / h;
        }
        while (next > start);

        if (next < start || i == 1)
        {
            continue;
        }

        tmp = m[next = start];

        do
        {
            i = (next % h) * w + next / h;
            m[next] = (i == start) ? tmp : m[i];
            next = i;
        }
        while (next > start);
    }
}
<|endoftext|>