<commit_before>#include "confidence_bounds_strategy_evaluator.h"
#include "estimator.h"
#include "error_calculation.h"
#include "debug.h"

#include <math.h>
#include <assert.h>

#include <limits>
#include <fstream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <iomanip>
using std::ifstream; using std::ofstream;
using std::ostringstream; using std::runtime_error;
using std::string; using std::setprecision; using std::endl;

#include <boost/math/distributions/students_t.hpp>
using namespace boost::math;

class ConfidenceBoundsStrategyEvaluator::ErrorConfidenceBounds {
  public:
    ErrorConfidenceBounds(Estimator *estimator_=NULL);
    void observationAdded(double value);
    double getBound(BoundType type);
    void saveToFile(ofstream& out);
    string restoreFromFile(ifstream& in);

    void setEstimator(Estimator *estimator_);
  private:
    static const double CONFIDENCE_ALPHA;

    Estimator *estimator;

    // let's try making these log-transformed.
    double error_mean;
    double error_variance;
    double M2; // for running variance algorithm

    size_t num_samples;

    // these are not log-transformed; they are inverse-transformed
    //  before being stored.
    double error_bounds[UPPER + 1];

    double getBoundDistance();
};

const double ConfidenceBoundsStrategyEvaluator::ErrorConfidenceBounds::CONFIDENCE_ALPHA = 0.05;

ConfidenceBoundsStrategyEvaluator::ErrorConfidenceBounds::ErrorConfidenceBounds(Estimator *estimator_)
    : estimator(estimator_)
{
    error_mean = 0.0;
    error_variance = 0.0;
    M2 = 0.0;
    num_samples = 0;
}

void
ConfidenceBoundsStrategyEvaluator::ErrorConfidenceBounds::setEstimator(Estimator *estimator_)
{
    estimator = estimator_;
}

static double get_chebyshev_bound(double alpha, double variance)
{
    // Chebyshev interval for error bounds, as described in my proposal.
    return sqrt(variance / alpha);
}

static double get_t_value(double alpha, size_t df)
{
    //http://www.boost.org/doc/libs/1_39_0/libs/math/doc/sf_and_dist/html/
    //       math_toolkit/dist/stat_tut/weg/st_eg/tut_mean_intervals.html
    return quantile(complement(students_t(df), alpha / 2));
}

static double get_confidence_interval_width(double alpha, double variance, size_t num_samples)
{
    // student's-t-based confidence interval
    if (num_samples <= 1) {
        return 0.0;
    } else {
        double t = get_t_value(alpha, num_samples - 1);
        return t * sqrt(variance / num_samples);
    }
}

static double get_prediction_interval_width(double alpha, double variance, size_t num_samples)
{
    // student's-t-based prediction interval
    // http://en.wikipedia.org/wiki/Prediction_interval#Unknown_mean.2C_unknown_variance
    if (num_samples <= 1) {
        return 0.0;
    } else {
        double t = get_t_value(alpha, num_samples - 1);
        return t * sqrt(variance * (1 + (1 / num_samples)));
    }
}

double
ConfidenceBoundsStrategyEvaluator::ErrorConfidenceBounds::getBoundDistance()
{
    if (false) {
        return get_chebyshev_bound(CONFIDENCE_ALPHA, error_variance);
    } else if (false) {
        return get_confidence_interval_width(CONFIDENCE_ALPHA, error_variance, num_samples);
    } else {
        return get_prediction_interval_width(CONFIDENCE_ALPHA, error_variance, num_samples);
    }
}

void
ConfidenceBoundsStrategyEvaluator::ErrorConfidenceBounds::observationAdded(double value)
{
    dbgprintf("Getting error sample from estimator %p\n", estimator);

    /*
     * Algorithm borrowed from
     * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#On-line_algorithm
     * which cites Knuth's /The Art of Computer Programming/, Volume 1.
     */
    ++num_samples;
    double estimate = estimator->getEstimate();
    double error = calculate_error(estimate, value);
    error = log(error); // natural logarithm

    double delta = error - error_mean;
    error_mean += delta / num_samples;
    M2 += delta * (error - error_mean);
    if (num_samples > 1) {
        error_variance = M2 / (num_samples-1);
    }

    double bound_distance = getBoundDistance();
    double bounds[2];

    bounds[0] = exp(error_mean - bound_distance);
    bounds[1] = exp(error_mean + bound_distance);
    if (adjusted_estimate(estimate, bounds[0]) < adjusted_estimate(estimate, bounds[1])) {
        error_bounds[LOWER] = bounds[0];
        error_bounds[UPPER] = bounds[1];
    } else {
        error_bounds[LOWER] = bounds[1];
        error_bounds[UPPER] = bounds[0];
    }
    dbgprintf("Adding error sample to estimator %p: %f\n",
              estimator, exp(error));
    dbgprintf("n=%4d; error bounds: [%f, %f]\n",
              num_samples, error_bounds[LOWER], error_bounds[UPPER]);
    if (adjusted_estimate(estimate, error_bounds[LOWER]) < 0.0) {
        // PROBLEMATIC.
        assert(false); // TODO: figure out what to do here.
    }
}

double
ConfidenceBoundsStrategyEvaluator::ErrorConfidenceBounds::getBound(BoundType type)
{
    double error = num_samples > 0 ? error_bounds[type] : no_error_value();
    return adjusted_estimate(estimator->getEstimate(), error);
}

static int PRECISION = 20;

void
ConfidenceBoundsStrategyEvaluator::ErrorConfidenceBounds::saveToFile(ofstream& out)
{
    out << estimator->getName() << " " << setprecision(PRECISION)
        << "num_samples " << num_samples
        << " mean " << error_mean
        << " variance " << error_variance
        << " M2 " << M2
        << " bounds " << error_bounds[LOWER] << " " << error_bounds[UPPER] << endl;
}

string
ConfidenceBoundsStrategyEvaluator::ErrorConfidenceBounds::restoreFromFile(ifstream& in)
{
    string name, tag;
    in >> name >> tag >> num_samples;
    check(tag == "num_samples", "Failed to parse num_samples");

    typedef struct {
        const char *expected_tag;
        double& field;
    } field_t;
    field_t fields[] = {
        { "mean", error_mean },
        { "variance", error_variance },
        { "M2", M2 },
        { "bounds", error_bounds[LOWER] }
    };
    size_t num_fields = sizeof(fields) / sizeof(field_t);
    for (size_t i = 0; i < num_fields; ++i) {
        in >> tag >> fields[i].field;
        check(tag == fields[i].expected_tag, "Failed to parse field");
    }
    in >> error_bounds[UPPER];

    check(in, "Failed to read bounds from file");
    return name;
}

void
ConfidenceBoundsStrategyEvaluator::observationAdded(Estimator *estimator, double value)
{
    dbgprintf("Adding observation %f to estimator %p\n", value, estimator);

    assert(estimator);
    string name = estimator->getName();
    ErrorConfidenceBounds *bounds = NULL;
    if (bounds_by_estimator.count(estimator) == 0) {
        if (placeholders.count(name) > 0) {
            bounds = placeholders[name];
            bounds->setEstimator(estimator);
            placeholders.erase(name);
        } else {
            bounds = new ErrorConfidenceBounds(estimator);
        }
        error_bounds.push_back(bounds);
        bounds_by_estimator[estimator] = error_bounds.back();
    } else {
        bounds = bounds_by_estimator[estimator];
    }

    if (estimators_by_name.count(name) > 0) {
        assert(estimator == estimators_by_name[name]);
    } else {
        estimators_by_name[name] = estimator;
    }

    if (estimator->hasEstimate()) {
        dbgprintf("Adding observation %f to estimator-bounds %p\n",
                  value, bounds);
        bounds->observationAdded(value);
    }
}

ConfidenceBoundsStrategyEvaluator::EvalMode
ConfidenceBoundsStrategyEvaluator::DEFAULT_EVAL_MODE = AGGRESSIVE;

ConfidenceBoundsStrategyEvaluator::ConfidenceBoundsStrategyEvaluator()
    : eval_mode(DEFAULT_EVAL_MODE), // TODO: set as option?
      step(0)
{
}

ConfidenceBoundsStrategyEvaluator::~ConfidenceBoundsStrategyEvaluator()
{
    for (size_t i = 0; i < error_bounds.size(); ++i) {
        delete error_bounds[i];
    }
    error_bounds.clear();
    bounds_by_estimator.clear();
    estimators_by_name.clear();
    placeholders.clear();
}

ConfidenceBoundsStrategyEvaluator::BoundType
ConfidenceBoundsStrategyEvaluator::getBoundType(EvalMode eval_mode, Strategy *strategy,
                                                typesafe_eval_fn_t fn)
{
    if (eval_mode == AGGRESSIVE) {
        // aggressive = upper bound on benefit of redundancy.
        //            = max_time(singular) - min_time(redundant)
        // or:
        // aggressive = lower bound on additional cost of redundancy
        //            = min_cost(redundant) - max_cost(singular)
        // same bound for time and cost.
        return strategy->isRedundant() ? LOWER : UPPER;
    } else {
        assert(eval_mode == CONSERVATIVE);
        // XXX: can these be negative? e.g. is it possible that min_time(singular) < max_time(redundant)?
        // XXX: above, the calculation of net benefit is:
        // XXX:  (best_singular_time - best_redundant_time) - (best_redundant_cost - best_singular_cost)
        // XXX: ...where 'best' always means in terms of time.
        // XXX: and then the redundant strategy is chosen if net_benefit > 0.0.
        // XXX: so, if min_time(singular) < max_time(redundant), we expect no benefit from redundancy.
        // XXX: net benefit will be < 0.0, and the singular strategy will be chosen.
        // XXX: I need to think about this more; I'm not sure yet how much it makes sense.

        // conservative = lower bound on benefit of redundancy
        //              = min_time(singular) - max_time(redundant)
        // or:
        // conservative = upper bound on cost of redundancy
        //              = max_cost(redundant) - min_cost(singular)
        // same bound for time and cost.
        return strategy->isRedundant() ? UPPER : LOWER;
    }
}

double
ConfidenceBoundsStrategyEvaluator::expectedValue(Strategy *strategy, typesafe_eval_fn_t fn,
                                                 void *strategy_arg, void *chooser_arg)
{
    BoundType bound_type = getBoundType(eval_mode, strategy, fn);
    return evaluateBounded(bound_type, fn, strategy_arg, chooser_arg);
}

typedef const double& (*bound_fn_t)(const double&, const double&);

double
ConfidenceBoundsStrategyEvaluator::evaluateBounded(BoundType bound_type, typesafe_eval_fn_t fn,
                                                   void *strategy_arg, void *chooser_arg)
{
    bound_fn_t bound_fns[UPPER + 1] = { &std::min<double>, &std::max<double> };
    bound_fn_t bound_fn = bound_fns[bound_type];

    // opposite fn, for calculating initial value that will
    //  always be replaced
    bound_fn_t bound_init_fn = bound_fns[(bound_type + 1) % (UPPER + 1)];

    // yes, it's a 2^N algorithm, but N is small; e.g. 4 for intnw
    unsigned int finish = 1 << error_bounds.size();
    double val = bound_init_fn(0.0, std::numeric_limits<double>::max());
    for (step = 0; step < finish; ++step) {
        val = bound_fn(val, fn(this, strategy_arg, chooser_arg));
    }
    return val;
}

double
ConfidenceBoundsStrategyEvaluator::getAdjustedEstimatorValue(Estimator *estimator)
{
    // use the low bits of step as selectors for the array of bounds
    //  (i.e. 0 bit = LOWER, 1 bit = UPPER)
    // LSB is used for bounds[0], MSB for bounds[n-1]
    // makes the N-way nested loop simpler

    if (bounds_by_estimator.count(estimator) == 0) {
        return estimator->getEstimate();
    }

    ErrorConfidenceBounds *est_error = bounds_by_estimator[estimator];
    for (size_t i = 0; i < error_bounds.size(); ++i) {
        if (est_error == error_bounds[i]) {
            char bit = (step >> i) & 0x1;
            return est_error->getBound(BoundType(bit));
        }
    }
    __builtin_unreachable();
}

void
ConfidenceBoundsStrategyEvaluator::saveToFile(const char *filename)
{
    ofstream out(filename);
    if (!out) {
        ostringstream oss;
        oss << "Failed to open " << filename;
        throw runtime_error(oss.str());
    }

    out << bounds_by_estimator.size() << " estimator-bounds" << endl;
    for (size_t i = 0; i < error_bounds.size(); ++i) {
        error_bounds[i]->saveToFile(out);
    }
    out.close();
}

void
ConfidenceBoundsStrategyEvaluator::restoreFromFile(const char *filename)
{
    ifstream in(filename);
    if (!in) {
        ostringstream oss;
        oss << "Failed to open " << filename;
        throw runtime_error(oss.str());
    }

    string tag;
    int num_estimators = -1;
    in >> num_estimators >> tag;
    check(num_estimators >= 0, "Failed to read number of estimator bounds");
    check(tag == "estimator-bounds", "Failed to read tag");

    for (size_t i = 0; i < error_bounds.size(); ++i) {
        delete error_bounds[i];
    }
    error_bounds.clear();

    for (int i = 0; i < num_estimators; ++i) {
        ErrorConfidenceBounds *bounds = new ErrorConfidenceBounds(NULL);
        string name = bounds->restoreFromFile(in);
        if (estimators_by_name.count(name) > 0) {
            Estimator *estimator = estimators_by_name[name];
            bounds->setEstimator(estimator);
            error_bounds.push_back(bounds);
            bounds_by_estimator[estimator] = bounds;
        } else {
            assert(placeholders.count(name) == 0);
            placeholders[name] = bounds;
        }
    }

    in.close();
}
<commit_msg>Tweaked the calculation of min-cost.<commit_after>#include "confidence_bounds_strategy_evaluator.h"
#include "estimator.h"
#include "error_calculation.h"
#include "debug.h"

#include <math.h>
#include <assert.h>

#include <limits>
#include <fstream>
#include <sstream>
#include <stdexcept>
#include <string>
#include <iomanip>
using std::ifstream; using std::ofstream;
using std::ostringstream; using std::runtime_error;
using std::string; using std::setprecision; using std::endl;

#include <boost/math/distributions/students_t.hpp>
using namespace boost::math;

class ConfidenceBoundsStrategyEvaluator::ErrorConfidenceBounds {
  public:
    ErrorConfidenceBounds(Estimator *estimator_=NULL);
    void observationAdded(double value);
    double getBound(BoundType type);
    void saveToFile(ofstream& out);
    string restoreFromFile(ifstream& in);

    void setEstimator(Estimator *estimator_);
  private:
    static const double CONFIDENCE_ALPHA;

    Estimator *estimator;

    // let's try making these log-transformed.
    double error_mean;
    double error_variance;
    double M2; // for running variance algorithm

    size_t num_samples;

    // these are not log-transformed; they are inverse-transformed
    //  before being stored.
    double error_bounds[UPPER + 1];

    double getBoundDistance();
};

const double ConfidenceBoundsStrategyEvaluator::ErrorConfidenceBounds::CONFIDENCE_ALPHA = 0.05;

ConfidenceBoundsStrategyEvaluator::ErrorConfidenceBounds::ErrorConfidenceBounds(Estimator *estimator_)
    : estimator(estimator_)
{
    error_mean = 0.0;
    error_variance = 0.0;
    M2 = 0.0;
    num_samples = 0;
}

void
ConfidenceBoundsStrategyEvaluator::ErrorConfidenceBounds::setEstimator(Estimator *estimator_)
{
    estimator = estimator_;
}

static double get_chebyshev_bound(double alpha, double variance)
{
    // Chebyshev interval for error bounds, as described in my proposal.
    return sqrt(variance / alpha);
}

static double get_t_value(double alpha, size_t df)
{
    //http://www.boost.org/doc/libs/1_39_0/libs/math/doc/sf_and_dist/html/
    //       math_toolkit/dist/stat_tut/weg/st_eg/tut_mean_intervals.html
    return quantile(complement(students_t(df), alpha / 2));
}

static double get_confidence_interval_width(double alpha, double variance, size_t num_samples)
{
    // student's-t-based confidence interval
    if (num_samples <= 1) {
        return 0.0;
    } else {
        double t = get_t_value(alpha, num_samples - 1);
        return t * sqrt(variance / num_samples);
    }
}

static double get_prediction_interval_width(double alpha, double variance, size_t num_samples)
{
    // student's-t-based prediction interval
    // http://en.wikipedia.org/wiki/Prediction_interval#Unknown_mean.2C_unknown_variance
    if (num_samples <= 1) {
        return 0.0;
    } else {
        double t = get_t_value(alpha, num_samples - 1);
        return t * sqrt(variance * (1 + (1 / num_samples)));
    }
}

double
ConfidenceBoundsStrategyEvaluator::ErrorConfidenceBounds::getBoundDistance()
{
    if (false) {
        return get_chebyshev_bound(CONFIDENCE_ALPHA, error_variance);
    } else if (false) {
        return get_confidence_interval_width(CONFIDENCE_ALPHA, error_variance, num_samples);
    } else {
        return get_prediction_interval_width(CONFIDENCE_ALPHA, error_variance, num_samples);
    }
}

void
ConfidenceBoundsStrategyEvaluator::ErrorConfidenceBounds::observationAdded(double value)
{
    dbgprintf("Getting error sample from estimator %p\n", estimator);

    /*
     * Algorithm borrowed from
     * http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#On-line_algorithm
     * which cites Knuth's /The Art of Computer Programming/, Volume 1.
     */
    ++num_samples;
    double estimate = estimator->getEstimate();
    double error = calculate_error(estimate, value);
    error = log(error); // natural logarithm

    double delta = error - error_mean;
    error_mean += delta / num_samples;
    M2 += delta * (error - error_mean);
    if (num_samples > 1) {
        error_variance = M2 / (num_samples-1);
    }

    double bound_distance = getBoundDistance();
    double bounds[2];

    bounds[0] = exp(error_mean - bound_distance);
    bounds[1] = exp(error_mean + bound_distance);
    if (adjusted_estimate(estimate, bounds[0]) < adjusted_estimate(estimate, bounds[1])) {
        error_bounds[LOWER] = bounds[0];
        error_bounds[UPPER] = bounds[1];
    } else {
        error_bounds[LOWER] = bounds[1];
        error_bounds[UPPER] = bounds[0];
    }
    dbgprintf("Adding error sample to estimator %p: %f\n",
              estimator, exp(error));
    dbgprintf("n=%4d; error bounds: [%f, %f]\n",
              num_samples, error_bounds[LOWER], error_bounds[UPPER]);
    if (adjusted_estimate(estimate, error_bounds[LOWER]) < 0.0) {
        // PROBLEMATIC.
        assert(false); // TODO: figure out what to do here.
    }
}

double
ConfidenceBoundsStrategyEvaluator::ErrorConfidenceBounds::getBound(BoundType type)
{
    double error = num_samples > 0 ? error_bounds[type] : no_error_value();
    return adjusted_estimate(estimator->getEstimate(), error);
}

static int PRECISION = 20;

void
ConfidenceBoundsStrategyEvaluator::ErrorConfidenceBounds::saveToFile(ofstream& out)
{
    out << estimator->getName() << " " << setprecision(PRECISION)
        << "num_samples " << num_samples
        << " mean " << error_mean
        << " variance " << error_variance
        << " M2 " << M2
        << " bounds " << error_bounds[LOWER] << " " << error_bounds[UPPER] << endl;
}

string
ConfidenceBoundsStrategyEvaluator::ErrorConfidenceBounds::restoreFromFile(ifstream& in)
{
    string name, tag;
    in >> name >> tag >> num_samples;
    check(tag == "num_samples", "Failed to parse num_samples");

    typedef struct {
        const char *expected_tag;
        double& field;
    } field_t;
    field_t fields[] = {
        { "mean", error_mean },
        { "variance", error_variance },
        { "M2", M2 },
        { "bounds", error_bounds[LOWER] }
    };
    size_t num_fields = sizeof(fields) / sizeof(field_t);
    for (size_t i = 0; i < num_fields; ++i) {
        in >> tag >> fields[i].field;
        check(tag == fields[i].expected_tag, "Failed to parse field");
    }
    in >> error_bounds[UPPER];

    check(in, "Failed to read bounds from file");
    return name;
}

void
ConfidenceBoundsStrategyEvaluator::observationAdded(Estimator *estimator, double value)
{
    dbgprintf("Adding observation %f to estimator %p\n", value, estimator);

    assert(estimator);
    string name = estimator->getName();
    ErrorConfidenceBounds *bounds = NULL;
    if (bounds_by_estimator.count(estimator) == 0) {
        if (placeholders.count(name) > 0) {
            bounds = placeholders[name];
            bounds->setEstimator(estimator);
            placeholders.erase(name);
        } else {
            bounds = new ErrorConfidenceBounds(estimator);
        }
        error_bounds.push_back(bounds);
        bounds_by_estimator[estimator] = error_bounds.back();
    } else {
        bounds = bounds_by_estimator[estimator];
    }

    if (estimators_by_name.count(name) > 0) {
        assert(estimator == estimators_by_name[name]);
    } else {
        estimators_by_name[name] = estimator;
    }

    if (estimator->hasEstimate()) {
        dbgprintf("Adding observation %f to estimator-bounds %p\n",
                  value, bounds);
        bounds->observationAdded(value);
    }
}

ConfidenceBoundsStrategyEvaluator::EvalMode
ConfidenceBoundsStrategyEvaluator::DEFAULT_EVAL_MODE = AGGRESSIVE;

ConfidenceBoundsStrategyEvaluator::ConfidenceBoundsStrategyEvaluator()
    : eval_mode(DEFAULT_EVAL_MODE), // TODO: set as option?
      step(0)
{
}

ConfidenceBoundsStrategyEvaluator::~ConfidenceBoundsStrategyEvaluator()
{
    for (size_t i = 0; i < error_bounds.size(); ++i) {
        delete error_bounds[i];
    }
    error_bounds.clear();
    bounds_by_estimator.clear();
    estimators_by_name.clear();
    placeholders.clear();
}

ConfidenceBoundsStrategyEvaluator::BoundType
ConfidenceBoundsStrategyEvaluator::getBoundType(EvalMode eval_mode, Strategy *strategy,
                                                typesafe_eval_fn_t fn)
{
    if (eval_mode == AGGRESSIVE) {
        // aggressive = upper bound on benefit of redundancy.
        //            = max_time(singular) - min_time(redundant)
        // or:
        // //aggressive = lower bound on additional cost of redundancy
        // //           = min_cost(redundant) - max_cost(singular)
        // //same bound for time and cost.
        // PROBLEM WITH THAT: cost diff can now be negative.
        //    could lower-bound at 0, but:
        //    a) This actually isn't what I proposed; and
        //    b) This will probably lead to always-redundant, all the time.
        //    What I proposed was that min-additional cost is
        //      calculated using the min-cost for all singular strategies.
        //    So, let's try that.
        //return strategy->isRedundant() ? LOWER : UPPER;

        if (fn == strategy->getEvalFn(ENERGY_FN) ||
            fn == strategy->getEvalFn(DATA_FN)) {
            return LOWER;
        } else {
            return strategy->isRedundant() ? LOWER : UPPER;
        }
    } else {
        assert(eval_mode == CONSERVATIVE);
        // XXX: can these be negative? e.g. is it possible that min_time(singular) < max_time(redundant)?
        // XXX: above, the calculation of net benefit is:
        // XXX:  (best_singular_time - best_redundant_time) - (best_redundant_cost - best_singular_cost)
        // XXX: ...where 'best' always means in terms of time.
        // XXX: and then the redundant strategy is chosen if net_benefit > 0.0.
        // XXX: so, if min_time(singular) < max_time(redundant), we expect no benefit from redundancy.
        // XXX: net benefit will be < 0.0, and the singular strategy will be chosen.
        // XXX: I need to think about this more; I'm not sure yet how much it makes sense.

        // conservative = lower bound on benefit of redundancy
        //              = min_time(singular) - max_time(redundant)
        // or:
        // conservative = upper bound on cost of redundancy
        //              = max_cost(redundant) - min_cost(singular)
        // same bound for time and cost.
        return strategy->isRedundant() ? UPPER : LOWER;
    }
}

double
ConfidenceBoundsStrategyEvaluator::expectedValue(Strategy *strategy, typesafe_eval_fn_t fn,
                                                 void *strategy_arg, void *chooser_arg)
{
    BoundType bound_type = getBoundType(eval_mode, strategy, fn);
    return evaluateBounded(bound_type, fn, strategy_arg, chooser_arg);
}

typedef const double& (*bound_fn_t)(const double&, const double&);

double
ConfidenceBoundsStrategyEvaluator::evaluateBounded(BoundType bound_type, typesafe_eval_fn_t fn,
                                                   void *strategy_arg, void *chooser_arg)
{
    bound_fn_t bound_fns[UPPER + 1] = { &std::min<double>, &std::max<double> };
    bound_fn_t bound_fn = bound_fns[bound_type];

    // opposite fn, for calculating initial value that will
    //  always be replaced
    bound_fn_t bound_init_fn = bound_fns[(bound_type + 1) % (UPPER + 1)];

    // yes, it's a 2^N algorithm, but N is small; e.g. 4 for intnw
    unsigned int finish = 1 << error_bounds.size();
    double val = bound_init_fn(0.0, std::numeric_limits<double>::max());
    for (step = 0; step < finish; ++step) {
        val = bound_fn(val, fn(this, strategy_arg, chooser_arg));
    }
    return val;
}

double
ConfidenceBoundsStrategyEvaluator::getAdjustedEstimatorValue(Estimator *estimator)
{
    // use the low bits of step as selectors for the array of bounds
    //  (i.e. 0 bit = LOWER, 1 bit = UPPER)
    // LSB is used for bounds[0], MSB for bounds[n-1]
    // makes the N-way nested loop simpler

    if (bounds_by_estimator.count(estimator) == 0) {
        return estimator->getEstimate();
    }

    ErrorConfidenceBounds *est_error = bounds_by_estimator[estimator];
    for (size_t i = 0; i < error_bounds.size(); ++i) {
        if (est_error == error_bounds[i]) {
            char bit = (step >> i) & 0x1;
            return est_error->getBound(BoundType(bit));
        }
    }
    __builtin_unreachable();
}

void
ConfidenceBoundsStrategyEvaluator::saveToFile(const char *filename)
{
    ofstream out(filename);
    if (!out) {
        ostringstream oss;
        oss << "Failed to open " << filename;
        throw runtime_error(oss.str());
    }

    out << bounds_by_estimator.size() << " estimator-bounds" << endl;
    for (size_t i = 0; i < error_bounds.size(); ++i) {
        error_bounds[i]->saveToFile(out);
    }
    out.close();
}

void
ConfidenceBoundsStrategyEvaluator::restoreFromFile(const char *filename)
{
    ifstream in(filename);
    if (!in) {
        ostringstream oss;
        oss << "Failed to open " << filename;
        throw runtime_error(oss.str());
    }

    string tag;
    int num_estimators = -1;
    in >> num_estimators >> tag;
    check(num_estimators >= 0, "Failed to read number of estimator bounds");
    check(tag == "estimator-bounds", "Failed to read tag");

    for (size_t i = 0; i < error_bounds.size(); ++i) {
        delete error_bounds[i];
    }
    error_bounds.clear();

    for (int i = 0; i < num_estimators; ++i) {
        ErrorConfidenceBounds *bounds = new ErrorConfidenceBounds(NULL);
        string name = bounds->restoreFromFile(in);
        if (estimators_by_name.count(name) > 0) {
            Estimator *estimator = estimators_by_name[name];
            bounds->setEstimator(estimator);
            error_bounds.push_back(bounds);
            bounds_by_estimator[estimator] = bounds;
        } else {
            assert(placeholders.count(name) == 0);
            placeholders[name] = bounds;
        }
    }

    in.close();
}
<|endoftext|>


<commit_before>#line 2 "togo/tool_build/compiler_manager.cpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.
*/

#include <togo/tool_build/config.hpp>
#include <togo/tool_build/types.hpp>
#include <togo/log/log.hpp>
#include <togo/memory/memory.hpp>
#include <togo/collection/fixed_array.hpp>
#include <togo/collection/array.hpp>
#include <togo/collection/hash_map.hpp>
#include <togo/tool_build/package_compiler.hpp>
#include <togo/tool_build/compiler_manager.hpp>
#include <togo/tool_build/resource_compiler.hpp>

namespace togo {
namespace tool_build {

CompilerManager::~CompilerManager() {
	compiler_manager::clear_packages(*this);
}

CompilerManager::CompilerManager(Allocator& allocator)
	: _compilers(allocator)
	, _packages(allocator)
{
	hash_map::reserve(_compilers, 16);
	array::reserve(_packages, 8);
}

void compiler_manager::register_compiler(
	CompilerManager& cm,
	ResourceCompiler const& compiler
) {
	TOGO_ASSERT(
		compiler.func_compile,
		"func_compile must be assigned in compiler"
	);
	TOGO_ASSERT(
		!hash_map::has(cm._compilers, compiler.type),
		"type has already been registered"
	);
	hash_map::push(cm._compilers, compiler.type, compiler);
}

void compiler_manager::register_standard_compilers(
	CompilerManager& cm
) {
	resource_compiler::register_test_resource(cm);
}

bool compiler_manager::has_compiler(
	CompilerManager const& cm,
	ResourceType const type
) {
	return hash_map::has(cm._compilers, type);
}

ResourceCompiler const* compiler_manager::get_compiler(
	CompilerManager const& cm,
	ResourceType const type
) {
	return hash_map::get(cm._compilers, type);
}

bool compiler_manager::has_package(
	CompilerManager const& cm,
	ResourcePackageNameHash const name_hash
) {
	for (auto const* pkg : cm._packages) {
		if (pkg->_name_hash == name_hash) {
			return true;
		}
	}
	return false;
}

PackageCompiler* compiler_manager::get_package(
	CompilerManager& cm,
	ResourcePackageNameHash const name_hash
) {
	for (auto* pkg : cm._packages) {
		if (pkg->_name_hash == name_hash) {
			return pkg;
		}
	}
	return nullptr;
}

ResourcePackageNameHash compiler_manager::add_package(
	CompilerManager& cm,
	StringRef const& path
) {
	// NB: PackageCompiler ctor trims path
	Allocator& allocator = *cm._packages._allocator;
	PackageCompiler* const pkg = TOGO_CONSTRUCT(allocator,
		PackageCompiler, path, allocator
	);
	for (auto const* it_pkg : cm._packages) {
		TOGO_ASSERTF(
			!string::compare_equal(it_pkg->_path, pkg->_path),
			"package at '%.*s' has already been added",
			string::size(it_pkg->_path), fixed_array::begin(it_pkg->_path)
		);
	}
	array::push_back(cm._packages, pkg);
	package_compiler::read(*pkg);
	return package_compiler::name_hash(*pkg);
}

void compiler_manager::remove_package(
	CompilerManager& cm,
	ResourcePackageNameHash const name_hash
) {
	Allocator& allocator = *cm._packages._allocator;
	for (unsigned i = 0; i < array::size(cm._packages); ++i) {
		auto* const pkg = cm._packages[i];
		if (pkg->_name_hash == name_hash) {
			// TODO: Unload active resources from the package
			TOGO_DESTROY(allocator, pkg);
			array::remove(cm._packages, i);
			return;
		}
	}
	TOGO_ASSERT(false, "package not found");
}

void compiler_manager::clear_packages(
	CompilerManager& cm
) {
	Allocator& allocator = *cm._packages._allocator;
	for (auto* pkg : cm._packages) {
		TOGO_DESTROY(allocator, pkg);
	}
	array::clear(cm._packages);
}

bool compiler_manager::write_packages(
	CompilerManager& cm
) {
	for (auto* pkg : cm._packages) {
		if (!package_compiler::write(*pkg)) {
			return false;
		}
	}
	return true;
}

bool compiler_manager::has_resource(
	CompilerManager const& cm,
	ResourceType const type,
	ResourceNameHash const name_hash,
	ResourceTagsHash const tags_hash
) {
	for (auto const* pkg : cm._packages) {
		if (package_compiler::find_resource_id(
			*pkg, type, name_hash, tags_hash, false
		) != 0) {
			return true;
		}
	}
	return false;
}

PackageCompiler::LookupNode* compiler_manager::get_node(
	CompilerManager& cm,
	ResourceNameHash const name_hash,
	PackageCompiler*& package
) {
	PackageCompiler::LookupNode* node;
	for (
		auto* it_pkg = array::end(cm._packages) - 1;
		it_pkg >= array::begin(cm._packages);
		--it_pkg
	) {
		node = package_compiler::get_node(**it_pkg, name_hash);
		if (node) {
			package = *it_pkg;
			return node;
		}
	}
	package = nullptr;
	return nullptr;
}

} // namespace tool_build
} // namespace togo
<commit_msg>tool_build/compiler_manager: URC: resource_compiler.<commit_after>#line 2 "togo/tool_build/compiler_manager.cpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.
*/

#include <togo/tool_build/config.hpp>
#include <togo/tool_build/types.hpp>
#include <togo/log/log.hpp>
#include <togo/memory/memory.hpp>
#include <togo/collection/fixed_array.hpp>
#include <togo/collection/array.hpp>
#include <togo/collection/hash_map.hpp>
#include <togo/tool_build/package_compiler.hpp>
#include <togo/tool_build/compiler_manager.hpp>
#include <togo/tool_build/resource_compiler.hpp>

namespace togo {
namespace tool_build {

CompilerManager::~CompilerManager() {
	compiler_manager::clear_packages(*this);
}

CompilerManager::CompilerManager(Allocator& allocator)
	: _compilers(allocator)
	, _packages(allocator)
{
	hash_map::reserve(_compilers, 16);
	array::reserve(_packages, 8);
}

void compiler_manager::register_compiler(
	CompilerManager& cm,
	ResourceCompiler const& compiler
) {
	TOGO_ASSERT(
		compiler.func_compile,
		"func_compile must be assigned in compiler"
	);
	TOGO_ASSERT(
		!hash_map::has(cm._compilers, compiler.type),
		"type has already been registered"
	);
	hash_map::push(cm._compilers, compiler.type, compiler);
}

void compiler_manager::register_standard_compilers(
	CompilerManager& cm
) {
	resource_compiler::register_test(cm);
}

bool compiler_manager::has_compiler(
	CompilerManager const& cm,
	ResourceType const type
) {
	return hash_map::has(cm._compilers, type);
}

ResourceCompiler const* compiler_manager::get_compiler(
	CompilerManager const& cm,
	ResourceType const type
) {
	return hash_map::get(cm._compilers, type);
}

bool compiler_manager::has_package(
	CompilerManager const& cm,
	ResourcePackageNameHash const name_hash
) {
	for (auto const* pkg : cm._packages) {
		if (pkg->_name_hash == name_hash) {
			return true;
		}
	}
	return false;
}

PackageCompiler* compiler_manager::get_package(
	CompilerManager& cm,
	ResourcePackageNameHash const name_hash
) {
	for (auto* pkg : cm._packages) {
		if (pkg->_name_hash == name_hash) {
			return pkg;
		}
	}
	return nullptr;
}

ResourcePackageNameHash compiler_manager::add_package(
	CompilerManager& cm,
	StringRef const& path
) {
	// NB: PackageCompiler ctor trims path
	Allocator& allocator = *cm._packages._allocator;
	PackageCompiler* const pkg = TOGO_CONSTRUCT(allocator,
		PackageCompiler, path, allocator
	);
	for (auto const* it_pkg : cm._packages) {
		TOGO_ASSERTF(
			!string::compare_equal(it_pkg->_path, pkg->_path),
			"package at '%.*s' has already been added",
			string::size(it_pkg->_path), fixed_array::begin(it_pkg->_path)
		);
	}
	array::push_back(cm._packages, pkg);
	package_compiler::read(*pkg);
	return package_compiler::name_hash(*pkg);
}

void compiler_manager::remove_package(
	CompilerManager& cm,
	ResourcePackageNameHash const name_hash
) {
	Allocator& allocator = *cm._packages._allocator;
	for (unsigned i = 0; i < array::size(cm._packages); ++i) {
		auto* const pkg = cm._packages[i];
		if (pkg->_name_hash == name_hash) {
			// TODO: Unload active resources from the package
			TOGO_DESTROY(allocator, pkg);
			array::remove(cm._packages, i);
			return;
		}
	}
	TOGO_ASSERT(false, "package not found");
}

void compiler_manager::clear_packages(
	CompilerManager& cm
) {
	Allocator& allocator = *cm._packages._allocator;
	for (auto* pkg : cm._packages) {
		TOGO_DESTROY(allocator, pkg);
	}
	array::clear(cm._packages);
}

bool compiler_manager::write_packages(
	CompilerManager& cm
) {
	for (auto* pkg : cm._packages) {
		if (!package_compiler::write(*pkg)) {
			return false;
		}
	}
	return true;
}

bool compiler_manager::has_resource(
	CompilerManager const& cm,
	ResourceType const type,
	ResourceNameHash const name_hash,
	ResourceTagsHash const tags_hash
) {
	for (auto const* pkg : cm._packages) {
		if (package_compiler::find_resource_id(
			*pkg, type, name_hash, tags_hash, false
		) != 0) {
			return true;
		}
	}
	return false;
}

PackageCompiler::LookupNode* compiler_manager::get_node(
	CompilerManager& cm,
	ResourceNameHash const name_hash,
	PackageCompiler*& package
) {
	PackageCompiler::LookupNode* node;
	for (
		auto* it_pkg = array::end(cm._packages) - 1;
		it_pkg >= array::begin(cm._packages);
		--it_pkg
	) {
		node = package_compiler::get_node(**it_pkg, name_hash);
		if (node) {
			package = *it_pkg;
			return node;
		}
	}
	package = nullptr;
	return nullptr;
}

} // namespace tool_build
} // namespace togo
<|endoftext|>


<commit_before>#include "exe/main_common.h"

#include <iostream>
#include <memory>

#include "common/common/compiler_requirements.h"
#include "common/common/perf_annotation.h"
#include "common/event/libevent.h"
#include "common/network/utility.h"
#include "common/stats/thread_local_store.h"

#include "server/config_validation/server.h"
#include "server/drain_manager_impl.h"
#include "server/hot_restart_nop_impl.h"
#include "server/options_impl.h"
#include "server/proto_descriptors.h"
#include "server/server.h"
#include "server/test_hooks.h"

#include "absl/strings/str_split.h"

#ifdef ENVOY_HOT_RESTART
#include "server/hot_restart_impl.h"
#endif

#include "ares.h"

namespace Envoy {

Server::DrainManagerPtr ProdComponentFactory::createDrainManager(Server::Instance& server) {
  // The global drain manager only triggers on listener modification, which effectively is
  // hot restart at the global level. The per-listener drain managers decide whether to
  // to include /healthcheck/fail status.
  return std::make_unique<Server::DrainManagerImpl>(server,
                                                    envoy::api::v2::Listener_DrainType_MODIFY_ONLY);
}

Runtime::LoaderPtr ProdComponentFactory::createRuntime(Server::Instance& server,
                                                       Server::Configuration::Initial& config) {
  return Server::InstanceUtil::createRuntime(server, config);
}

MainCommonBase::MainCommonBase(OptionsImpl& options, Event::TimeSystem& time_system,
                               TestHooks& test_hooks, Server::ComponentFactory& component_factory,
                               std::unique_ptr<Runtime::RandomGenerator>&& random_generator)
    : options_(options), component_factory_(component_factory) {
  ares_library_init(ARES_LIB_INIT_ALL);
  Event::Libevent::Global::initialize();
  RELEASE_ASSERT(Envoy::Server::validateProtoDescriptors(), "");

  switch (options_.mode()) {
  case Server::Mode::InitOnly:
  case Server::Mode::Serve: {
#ifdef ENVOY_HOT_RESTART
    if (!options.hotRestartDisabled()) {
      restarter_ = std::make_unique<Server::HotRestartImpl>(options_);
    }
#endif
    if (restarter_ == nullptr) {
      restarter_ = std::make_unique<Server::HotRestartNopImpl>();
    }

    tls_ = std::make_unique<ThreadLocal::InstanceImpl>();
    Thread::BasicLockable& log_lock = restarter_->logLock();
    Thread::BasicLockable& access_log_lock = restarter_->accessLogLock();
    auto local_address = Network::Utility::getLocalAddress(options_.localAddressIpVersion());
    logging_context_ =
        std::make_unique<Logger::Context>(options_.logLevel(), options_.logFormat(), log_lock);

    configureComponentLogLevels();

    stats_store_ = std::make_unique<Stats::ThreadLocalStoreImpl>(options_.statsOptions(),
                                                                 restarter_->statsAllocator());

    server_ = std::make_unique<Server::InstanceImpl>(
        options_, time_system, local_address, test_hooks, *restarter_, *stats_store_,
        access_log_lock, component_factory, std::move(random_generator), *tls_);

    break;
  }
  case Server::Mode::Validate:
    restarter_ = std::make_unique<Server::HotRestartNopImpl>();
    logging_context_ = std::make_unique<Logger::Context>(options_.logLevel(), options_.logFormat(),
                                                         restarter_->logLock());
    break;
  }
}

MainCommonBase::~MainCommonBase() { ares_library_cleanup(); }

void MainCommonBase::configureComponentLogLevels() {
  for (auto& component_log_level : options_.componentLogLevels()) {
    Logger::Logger* logger_to_change = Logger::Registry::logger(component_log_level.first);
    ASSERT(logger_to_change);
    logger_to_change->setLevel(component_log_level.second);
  }
}

bool MainCommonBase::run() {
  switch (options_.mode()) {
  case Server::Mode::Serve:
    server_->run();
    return true;
  case Server::Mode::Validate: {
    auto local_address = Network::Utility::getLocalAddress(options_.localAddressIpVersion());
    return Server::validateConfig(options_, local_address, component_factory_);
  }
  case Server::Mode::InitOnly:
    PERF_DUMP();
    return true;
  }
  NOT_REACHED_GCOVR_EXCL_LINE;
}

void MainCommonBase::adminRequest(absl::string_view path_and_query, absl::string_view method,
                                  const AdminRequestFn& handler) {
  std::string path_and_query_buf = std::string(path_and_query);
  std::string method_buf = std::string(method);
  server_->dispatcher().post([this, path_and_query_buf, method_buf, handler]() {
    Http::HeaderMapImpl response_headers;
    std::string body;
    server_->admin().request(path_and_query_buf, method_buf, response_headers, body);
    handler(response_headers, body);
  });
}

MainCommon::MainCommon(int argc, const char* const* argv)
    : options_(argc, argv, &MainCommon::hotRestartVersion, spdlog::level::info),
      base_(options_, real_time_system_, default_test_hooks_, prod_component_factory_,
            std::make_unique<Runtime::RandomGeneratorImpl>()) {}

std::string MainCommon::hotRestartVersion(uint64_t max_num_stats, uint64_t max_stat_name_len,
                                          bool hot_restart_enabled) {
#ifdef ENVOY_HOT_RESTART
  if (hot_restart_enabled) {
    return Server::HotRestartImpl::hotRestartVersion(max_num_stats, max_stat_name_len);
  }
#else
  UNREFERENCED_PARAMETER(hot_restart_enabled);
  UNREFERENCED_PARAMETER(max_num_stats);
  UNREFERENCED_PARAMETER(max_stat_name_len);
#endif
  return "disabled";
}

// Legacy implementation of main_common.
//
// TODO(jmarantz): Remove this when all callers are removed. At that time, MainCommonBase
// and MainCommon can be merged. The current theory is that only Google calls this.
int main_common(OptionsImpl& options) {
  try {
    Event::RealTimeSystem real_time_system_;
    DefaultTestHooks default_test_hooks_;
    ProdComponentFactory prod_component_factory_;
    MainCommonBase main_common(options, real_time_system_, default_test_hooks_,
                               prod_component_factory_,
                               std::make_unique<Runtime::RandomGeneratorImpl>());
    return main_common.run() ? EXIT_SUCCESS : EXIT_FAILURE;
  } catch (EnvoyException& e) {
    return EXIT_FAILURE;
  }
  return EXIT_SUCCESS;
}

} // namespace Envoy
<commit_msg>remove unreachable code (#5082)<commit_after>#include "exe/main_common.h"

#include <iostream>
#include <memory>

#include "common/common/compiler_requirements.h"
#include "common/common/perf_annotation.h"
#include "common/event/libevent.h"
#include "common/network/utility.h"
#include "common/stats/thread_local_store.h"

#include "server/config_validation/server.h"
#include "server/drain_manager_impl.h"
#include "server/hot_restart_nop_impl.h"
#include "server/options_impl.h"
#include "server/proto_descriptors.h"
#include "server/server.h"
#include "server/test_hooks.h"

#include "absl/strings/str_split.h"

#ifdef ENVOY_HOT_RESTART
#include "server/hot_restart_impl.h"
#endif

#include "ares.h"

namespace Envoy {

Server::DrainManagerPtr ProdComponentFactory::createDrainManager(Server::Instance& server) {
  // The global drain manager only triggers on listener modification, which effectively is
  // hot restart at the global level. The per-listener drain managers decide whether to
  // to include /healthcheck/fail status.
  return std::make_unique<Server::DrainManagerImpl>(server,
                                                    envoy::api::v2::Listener_DrainType_MODIFY_ONLY);
}

Runtime::LoaderPtr ProdComponentFactory::createRuntime(Server::Instance& server,
                                                       Server::Configuration::Initial& config) {
  return Server::InstanceUtil::createRuntime(server, config);
}

MainCommonBase::MainCommonBase(OptionsImpl& options, Event::TimeSystem& time_system,
                               TestHooks& test_hooks, Server::ComponentFactory& component_factory,
                               std::unique_ptr<Runtime::RandomGenerator>&& random_generator)
    : options_(options), component_factory_(component_factory) {
  ares_library_init(ARES_LIB_INIT_ALL);
  Event::Libevent::Global::initialize();
  RELEASE_ASSERT(Envoy::Server::validateProtoDescriptors(), "");

  switch (options_.mode()) {
  case Server::Mode::InitOnly:
  case Server::Mode::Serve: {
#ifdef ENVOY_HOT_RESTART
    if (!options.hotRestartDisabled()) {
      restarter_ = std::make_unique<Server::HotRestartImpl>(options_);
    }
#endif
    if (restarter_ == nullptr) {
      restarter_ = std::make_unique<Server::HotRestartNopImpl>();
    }

    tls_ = std::make_unique<ThreadLocal::InstanceImpl>();
    Thread::BasicLockable& log_lock = restarter_->logLock();
    Thread::BasicLockable& access_log_lock = restarter_->accessLogLock();
    auto local_address = Network::Utility::getLocalAddress(options_.localAddressIpVersion());
    logging_context_ =
        std::make_unique<Logger::Context>(options_.logLevel(), options_.logFormat(), log_lock);

    configureComponentLogLevels();

    stats_store_ = std::make_unique<Stats::ThreadLocalStoreImpl>(options_.statsOptions(),
                                                                 restarter_->statsAllocator());

    server_ = std::make_unique<Server::InstanceImpl>(
        options_, time_system, local_address, test_hooks, *restarter_, *stats_store_,
        access_log_lock, component_factory, std::move(random_generator), *tls_);

    break;
  }
  case Server::Mode::Validate:
    restarter_ = std::make_unique<Server::HotRestartNopImpl>();
    logging_context_ = std::make_unique<Logger::Context>(options_.logLevel(), options_.logFormat(),
                                                         restarter_->logLock());
    break;
  }
}

MainCommonBase::~MainCommonBase() { ares_library_cleanup(); }

void MainCommonBase::configureComponentLogLevels() {
  for (auto& component_log_level : options_.componentLogLevels()) {
    Logger::Logger* logger_to_change = Logger::Registry::logger(component_log_level.first);
    ASSERT(logger_to_change);
    logger_to_change->setLevel(component_log_level.second);
  }
}

bool MainCommonBase::run() {
  switch (options_.mode()) {
  case Server::Mode::Serve:
    server_->run();
    return true;
  case Server::Mode::Validate: {
    auto local_address = Network::Utility::getLocalAddress(options_.localAddressIpVersion());
    return Server::validateConfig(options_, local_address, component_factory_);
  }
  case Server::Mode::InitOnly:
    PERF_DUMP();
    return true;
  }
  NOT_REACHED_GCOVR_EXCL_LINE;
}

void MainCommonBase::adminRequest(absl::string_view path_and_query, absl::string_view method,
                                  const AdminRequestFn& handler) {
  std::string path_and_query_buf = std::string(path_and_query);
  std::string method_buf = std::string(method);
  server_->dispatcher().post([this, path_and_query_buf, method_buf, handler]() {
    Http::HeaderMapImpl response_headers;
    std::string body;
    server_->admin().request(path_and_query_buf, method_buf, response_headers, body);
    handler(response_headers, body);
  });
}

MainCommon::MainCommon(int argc, const char* const* argv)
    : options_(argc, argv, &MainCommon::hotRestartVersion, spdlog::level::info),
      base_(options_, real_time_system_, default_test_hooks_, prod_component_factory_,
            std::make_unique<Runtime::RandomGeneratorImpl>()) {}

std::string MainCommon::hotRestartVersion(uint64_t max_num_stats, uint64_t max_stat_name_len,
                                          bool hot_restart_enabled) {
#ifdef ENVOY_HOT_RESTART
  if (hot_restart_enabled) {
    return Server::HotRestartImpl::hotRestartVersion(max_num_stats, max_stat_name_len);
  }
#else
  UNREFERENCED_PARAMETER(hot_restart_enabled);
  UNREFERENCED_PARAMETER(max_num_stats);
  UNREFERENCED_PARAMETER(max_stat_name_len);
#endif
  return "disabled";
}

// Legacy implementation of main_common.
//
// TODO(jmarantz): Remove this when all callers are removed. At that time, MainCommonBase
// and MainCommon can be merged. The current theory is that only Google calls this.
int main_common(OptionsImpl& options) {
  try {
    Event::RealTimeSystem real_time_system_;
    DefaultTestHooks default_test_hooks_;
    ProdComponentFactory prod_component_factory_;
    MainCommonBase main_common(options, real_time_system_, default_test_hooks_,
                               prod_component_factory_,
                               std::make_unique<Runtime::RandomGeneratorImpl>());
    return main_common.run() ? EXIT_SUCCESS : EXIT_FAILURE;
  } catch (EnvoyException& e) {
    return EXIT_FAILURE;
  }
}

} // namespace Envoy
<|endoftext|>


<commit_before><commit_msg>Ensured Scintilla not in read-only mode before loading from file.<commit_after><|endoftext|>


<commit_before>#include "Surface.h"

#include "OpenGLTexture.h"

#include "Color.h"

#include <cstring>
#include <vector>
#include <cmath>
#include <cassert>
#include <iostream>

using namespace std;
using namespace canvas;

static vector<int> make_kernel(float radius) {
  int r = (int)ceil(radius);
  int rows = 2 * r + 1;
  float sigma = radius / 3;
  float sigma22 = 2.0f * sigma * sigma;
  float sigmaPi2 = 2.0f * float(M_PI) * sigma;
  float sqrtSigmaPi2 = sqrt(sigmaPi2);
  // float radius2 = radius*radius;
  vector<int> kernel;
  kernel.reserve(rows);

  int row = -r;
  float first_value = exp(-row*row/sigma22) / sqrtSigmaPi2;
  kernel.push_back(1);

  for (row++; row <= r; row++) {
    kernel.push_back(int(exp(-row * row / sigma22) / sqrtSigmaPi2 / first_value));
  }
  return kernel;
}

void
Surface::gaussianBlur(float hradius, float vradius) {
  if (!(hradius > 0 || vradius > 0)) {
    return;
  }

  unsigned char * buffer = lockMemory(true);
  assert(buffer);

  unsigned char * tmp = new unsigned char[width * height * 4];
  if (hradius > 0.0f) {
    vector<int> hkernel = make_kernel(hradius);
    unsigned short hsize = hkernel.size();
    int htotal = 0;
    for (vector<int>::iterator it = hkernel.begin(); it != hkernel.end(); it++) {
      htotal += *it;
    }
    memset(tmp, 0, width * height * 4);
    for (unsigned int row = 0; row < height; row++) {
      for (unsigned int col = 0; col + hsize < width; col++) {
	int c0 = 0, c1 = 0, c2 = 0, c3 = 0;
	for (unsigned int i = 0; i < hsize; i++) {
	  unsigned char * ptr = buffer + (row * width + col + i) * 4;
	  c0 += *ptr++ * hkernel[i];
	  c1 += *ptr++ * hkernel[i];
	  c2 += *ptr++ * hkernel[i];
	  c3 += *ptr++ * hkernel[i];
	}
	unsigned char * ptr = tmp + (row * width + col + hsize / 2) * 4;
	*ptr++ = (unsigned char)(c0 / htotal);
	*ptr++ = (unsigned char)(c1 / htotal);
	*ptr++ = (unsigned char)(c2 / htotal);
	*ptr++ = (unsigned char)(c3 / htotal);
      }
    }
  } else {
    memcpy(tmp, buffer, width * height * 4);
  }
  if (vradius > 0) {
    vector<int> vkernel = make_kernel(vradius);
    unsigned short vsize = vkernel.size();
    int vtotal = 0;
    for (vector<int>::iterator it = vkernel.begin(); it != vkernel.end(); it++) {
      vtotal += *it;
    }
    memset(buffer, 0, width * height * 4);
    for (unsigned int col = 0; col < width; col++) {
      for (unsigned int row = 0; row + vsize < height; row++) {
	int c0 = 0, c1 = 0, c2 = 0, c3 = 0;
	for (unsigned int i = 0; i < vsize; i++) {
	  unsigned char * ptr = tmp + ((row + i) * width + col) * 4;
	  c0 += *ptr++ * vkernel[i];
	  c1 += *ptr++ * vkernel[i];
	  c2 += *ptr++ * vkernel[i];
	  c3 += *ptr++ * vkernel[i];
	}
	unsigned char * ptr = buffer + ((row + vsize / 2) * width + col) * 4;
	*ptr++ = (unsigned char)(c0 / vtotal);
	*ptr++ = (unsigned char)(c1 / vtotal);
	*ptr++ = (unsigned char)(c2 / vtotal);
	*ptr++ = (unsigned char)(c3 / vtotal);
      }
    }
  } else {
    memcpy(buffer, tmp, width * height * 4);
  }
  delete[] tmp;

  releaseMemory();
}

static inline unsigned char toByte(float f) {
  int a = int(f * 255);
  if (a < 0) a = 0;
  else if (a > 255) a = 255;
  return (unsigned char)a;
}

void
Surface::colorFill(const Color & color) {
  unsigned char * buffer = lockMemory(true);
  assert(buffer);
  unsigned char red = toByte(color.red * color.alpha);
  unsigned char green = toByte(color.green * color.alpha);
  unsigned char blue = toByte(color.blue * color.alpha);
  unsigned char alpha = toByte(color.alpha);
  for (unsigned int i = 0; i < width * height; i++) {
    unsigned char * ptr = buffer + (i * 4);
    unsigned int dest_alpha = ptr[3];
    *ptr++ = (unsigned char)((dest_alpha * red) / 255);
    *ptr++ = (unsigned char)((dest_alpha * green) / 255);
    *ptr++ = (unsigned char)((dest_alpha * blue) / 255);
    *ptr++ = (unsigned char)((dest_alpha * alpha) / 255);
  }
  releaseMemory();
}

const TextureRef &
Surface::updateTexture() {
  flush();

  // cerr << "updating texture, this = " << this << ", tex = " << texture.getData() << "\n";
#ifdef OPENGL
  if (!texture.isDefined()) {
    texture = OpenGLTexture::createTexture(getWidth(), getHeight(), min_filter, mag_filter);
  }
#endif

  unsigned char * buffer = lockMemory();
  assert(buffer);

  // remove premultiplied alpha
  unsigned char * buffer2 = new unsigned char[getWidth() * getHeight() * 4];
  for (unsigned int i = 0; i < getWidth() * getHeight(); i++) {
    unsigned int red = buffer[4 * i + 0];
    unsigned int green = buffer[4 * i + 1];
    unsigned int blue = buffer[4 * i + 2];
    unsigned int alpha = buffer[4 * i + 3];
    if (alpha >= 1) {
      buffer2[4 * i + 0] = (unsigned char)(255 * red / alpha);
      buffer2[4 * i + 1] = (unsigned char)(255 * green / alpha);
      buffer2[4 * i + 2] = (unsigned char)(255 * blue / alpha);
    } else {
      buffer2[4 * i + 0] = 0;
      buffer2[4 * i + 1] = 0;
      buffer2[4 * i + 2] = 0;
    }
    buffer2[4 * i + 3] = alpha;
  }

  texture.updateData(buffer2);

  delete[] buffer2;

  releaseMemory();

  return texture;
}
<commit_msg>do not remove pre-multiplied alpha<commit_after>#include "Surface.h"

#include "OpenGLTexture.h"

#include "Color.h"

#include <cstring>
#include <vector>
#include <cmath>
#include <cassert>
#include <iostream>

using namespace std;
using namespace canvas;

static vector<int> make_kernel(float radius) {
  int r = (int)ceil(radius);
  int rows = 2 * r + 1;
  float sigma = radius / 3;
  float sigma22 = 2.0f * sigma * sigma;
  float sigmaPi2 = 2.0f * float(M_PI) * sigma;
  float sqrtSigmaPi2 = sqrt(sigmaPi2);
  // float radius2 = radius*radius;
  vector<int> kernel;
  kernel.reserve(rows);

  int row = -r;
  float first_value = exp(-row*row/sigma22) / sqrtSigmaPi2;
  kernel.push_back(1);

  for (row++; row <= r; row++) {
    kernel.push_back(int(exp(-row * row / sigma22) / sqrtSigmaPi2 / first_value));
  }
  return kernel;
}

void
Surface::gaussianBlur(float hradius, float vradius) {
  if (!(hradius > 0 || vradius > 0)) {
    return;
  }

  unsigned char * buffer = lockMemory(true);
  assert(buffer);

  unsigned char * tmp = new unsigned char[width * height * 4];
  if (hradius > 0.0f) {
    vector<int> hkernel = make_kernel(hradius);
    unsigned short hsize = hkernel.size();
    int htotal = 0;
    for (vector<int>::iterator it = hkernel.begin(); it != hkernel.end(); it++) {
      htotal += *it;
    }
    memset(tmp, 0, width * height * 4);
    for (unsigned int row = 0; row < height; row++) {
      for (unsigned int col = 0; col + hsize < width; col++) {
	int c0 = 0, c1 = 0, c2 = 0, c3 = 0;
	for (unsigned int i = 0; i < hsize; i++) {
	  unsigned char * ptr = buffer + (row * width + col + i) * 4;
	  c0 += *ptr++ * hkernel[i];
	  c1 += *ptr++ * hkernel[i];
	  c2 += *ptr++ * hkernel[i];
	  c3 += *ptr++ * hkernel[i];
	}
	unsigned char * ptr = tmp + (row * width + col + hsize / 2) * 4;
	*ptr++ = (unsigned char)(c0 / htotal);
	*ptr++ = (unsigned char)(c1 / htotal);
	*ptr++ = (unsigned char)(c2 / htotal);
	*ptr++ = (unsigned char)(c3 / htotal);
      }
    }
  } else {
    memcpy(tmp, buffer, width * height * 4);
  }
  if (vradius > 0) {
    vector<int> vkernel = make_kernel(vradius);
    unsigned short vsize = vkernel.size();
    int vtotal = 0;
    for (vector<int>::iterator it = vkernel.begin(); it != vkernel.end(); it++) {
      vtotal += *it;
    }
    memset(buffer, 0, width * height * 4);
    for (unsigned int col = 0; col < width; col++) {
      for (unsigned int row = 0; row + vsize < height; row++) {
	int c0 = 0, c1 = 0, c2 = 0, c3 = 0;
	for (unsigned int i = 0; i < vsize; i++) {
	  unsigned char * ptr = tmp + ((row + i) * width + col) * 4;
	  c0 += *ptr++ * vkernel[i];
	  c1 += *ptr++ * vkernel[i];
	  c2 += *ptr++ * vkernel[i];
	  c3 += *ptr++ * vkernel[i];
	}
	unsigned char * ptr = buffer + ((row + vsize / 2) * width + col) * 4;
	*ptr++ = (unsigned char)(c0 / vtotal);
	*ptr++ = (unsigned char)(c1 / vtotal);
	*ptr++ = (unsigned char)(c2 / vtotal);
	*ptr++ = (unsigned char)(c3 / vtotal);
      }
    }
  } else {
    memcpy(buffer, tmp, width * height * 4);
  }
  delete[] tmp;

  releaseMemory();
}

static inline unsigned char toByte(float f) {
  int a = int(f * 255);
  if (a < 0) a = 0;
  else if (a > 255) a = 255;
  return (unsigned char)a;
}

void
Surface::colorFill(const Color & color) {
  unsigned char * buffer = lockMemory(true);
  assert(buffer);
  unsigned char red = toByte(color.red * color.alpha);
  unsigned char green = toByte(color.green * color.alpha);
  unsigned char blue = toByte(color.blue * color.alpha);
  unsigned char alpha = toByte(color.alpha);
  for (unsigned int i = 0; i < width * height; i++) {
    unsigned char * ptr = buffer + (i * 4);
    unsigned int dest_alpha = ptr[3];
    *ptr++ = (unsigned char)((dest_alpha * red) / 255);
    *ptr++ = (unsigned char)((dest_alpha * green) / 255);
    *ptr++ = (unsigned char)((dest_alpha * blue) / 255);
    *ptr++ = (unsigned char)((dest_alpha * alpha) / 255);
  }
  releaseMemory();
}

const TextureRef &
Surface::updateTexture() {
  flush();

  // cerr << "updating texture, this = " << this << ", tex = " << texture.getData() << "\n";
#ifdef OPENGL
  if (!texture.isDefined()) {
    texture = OpenGLTexture::createTexture(getWidth(), getHeight(), min_filter, mag_filter);
  }
#endif

  unsigned char * buffer = lockMemory();
  assert(buffer);

#if 0
  // remove premultiplied alpha
  unsigned char * buffer2 = new unsigned char[getWidth() * getHeight() * 4];
  for (unsigned int i = 0; i < getWidth() * getHeight(); i++) {
    unsigned int red = buffer[4 * i + 0];
    unsigned int green = buffer[4 * i + 1];
    unsigned int blue = buffer[4 * i + 2];
    unsigned int alpha = buffer[4 * i + 3];
    if (alpha >= 1) {
      buffer2[4 * i + 0] = (unsigned char)(255 * red / alpha);
      buffer2[4 * i + 1] = (unsigned char)(255 * green / alpha);
      buffer2[4 * i + 2] = (unsigned char)(255 * blue / alpha);
    } else {
      buffer2[4 * i + 0] = 0;
      buffer2[4 * i + 1] = 0;
      buffer2[4 * i + 2] = 0;
    }
    buffer2[4 * i + 3] = alpha;
  }

  texture.updateData(buffer2);
  delete[] buffer2;
#else
  texture.updateData(buffer);
#endif

  releaseMemory();

  return texture;
}
<|endoftext|>


<commit_before>/******************************************************************************
 ** Copyright (c) 2010 Seed Developers
 ** All rights reserved
 ** Contact: licensing@seedframework.org
 ** Website: http://www.seedframework.org

 ** This file is part of the Seed Framework.

 ** Commercial Usage
 ** Seed Framework is available under proprietary license for those who cannot,
 ** or choose not to, use LGPL and GPL code in their projects (eg. iPhone,
 ** Nintendo Wii and others).

 ** GNU Lesser General Public License Usage
 ** Alternatively, this file may be used under the terms of the GNU Lesser
 ** General Public License version 2.1 as published by the Free Software
 ** Foundation and appearing in the file LICENSE.LGPL included in the
 ** packaging of this file.  Please review the following information to
 ** ensure the GNU Lesser General Public License version 2.1 requirements
 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 **
 ** In addition, as a special exception, Seed developers gives you certain
 ** additional rights. These rights are described in the Seed Framework LGPL
 ** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
 ** package.
 **
 ** If you have questions regarding the use of this file, please contact
 ** Seed developers at licensing@seedframework.org.
 **
 *****************************************************************************/

/*! \file GuiManager.cpp
	\author Danny Angelo Carminati Grein
	\brief GUI Manager
*/

#include "MemoryManager.h"
#include "Input.h"
#include "Screen.h"
#include "Log.h"
#include "gui/GuiManager.h"
#include "Enum.h"

namespace Seed {

SEED_SINGLETON_DEFINE(GuiManager);

GuiManager::GuiManager()
	: pFocused(NULL)
	, cContainer()
	//, vWidget()
{
	//this->Reset();
}

GuiManager::~GuiManager()
{
	this->Reset();
}

INLINE BOOL GuiManager::Initialize()
{
	IModule::Initialize();

	this->Reset();

	pInput->AddPointerListener(this);
	cContainer.SetWidth(1.0f);
	cContainer.SetHeight(1.0f);

	return TRUE;
}

INLINE BOOL GuiManager::Reset()
{
	this->pFocused = NULL;
	return TRUE; // abstract IModule::Reset();
}

INLINE BOOL GuiManager::Shutdown()
{
	pInput->RemovePointerListener(this);
	return IModule::Shutdown();;
}

INLINE BOOL GuiManager::Update(f32 dt)
{
	cContainer.Update(dt);
	return TRUE;
}

INLINE void GuiManager::SetFocus(IWidget *widget)
{
	this->pFocused = widget;
}

INLINE IWidget *GuiManager::GetFocused() const
{
	return this->pFocused;
}

INLINE void GuiManager::Add(IWidget *widget)
{
	cContainer.Add(widget);
}

INLINE void GuiManager::Remove(IWidget *widget)
{
	cContainer.Remove(widget);
}

INLINE void GuiManager::OnInputPointerPress(const EventInputPointer *ev)
{
	cContainer.OnInputPointerPress(ev);
}

INLINE void GuiManager::OnInputPointerRelease(const EventInputPointer *ev)
{
	cContainer.OnInputPointerRelease(ev);
}

INLINE void GuiManager::OnInputPointerMove(const EventInputPointer *ev)
{
	cContainer.OnInputPointerMove(ev);
}

INLINE const char *GuiManager::GetObjectName() const
{
	return "GuiManager";
}

} // namespace
<commit_msg>* GuiManager redundant call to WidgetContainer::Update.<commit_after>/******************************************************************************
 ** Copyright (c) 2010 Seed Developers
 ** All rights reserved
 ** Contact: licensing@seedframework.org
 ** Website: http://www.seedframework.org

 ** This file is part of the Seed Framework.

 ** Commercial Usage
 ** Seed Framework is available under proprietary license for those who cannot,
 ** or choose not to, use LGPL and GPL code in their projects (eg. iPhone,
 ** Nintendo Wii and others).

 ** GNU Lesser General Public License Usage
 ** Alternatively, this file may be used under the terms of the GNU Lesser
 ** General Public License version 2.1 as published by the Free Software
 ** Foundation and appearing in the file LICENSE.LGPL included in the
 ** packaging of this file.  Please review the following information to
 ** ensure the GNU Lesser General Public License version 2.1 requirements
 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 **
 ** In addition, as a special exception, Seed developers gives you certain
 ** additional rights. These rights are described in the Seed Framework LGPL
 ** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
 ** package.
 **
 ** If you have questions regarding the use of this file, please contact
 ** Seed developers at licensing@seedframework.org.
 **
 *****************************************************************************/

/*! \file GuiManager.cpp
	\author Danny Angelo Carminati Grein
	\brief GUI Manager
*/

#include "MemoryManager.h"
#include "Input.h"
#include "Screen.h"
#include "Log.h"
#include "gui/GuiManager.h"
#include "Enum.h"

namespace Seed {

SEED_SINGLETON_DEFINE(GuiManager);

GuiManager::GuiManager()
	: pFocused(NULL)
	, cContainer()
	//, vWidget()
{
	//this->Reset();
}

GuiManager::~GuiManager()
{
	this->Reset();
}

INLINE BOOL GuiManager::Initialize()
{
	IModule::Initialize();

	this->Reset();

	pInput->AddPointerListener(this);
	cContainer.SetWidth(1.0f);
	cContainer.SetHeight(1.0f);

	return TRUE;
}

INLINE BOOL GuiManager::Reset()
{
	this->pFocused = NULL;
	return TRUE; // abstract IModule::Reset();
}

INLINE BOOL GuiManager::Shutdown()
{
	pInput->RemovePointerListener(this);
	return IModule::Shutdown();
}

INLINE BOOL GuiManager::Update(f32 dt)
{
	//cContainer.Update(dt);
	return TRUE;
}

INLINE void GuiManager::SetFocus(IWidget *widget)
{
	this->pFocused = widget;
}

INLINE IWidget *GuiManager::GetFocused() const
{
	return this->pFocused;
}

INLINE void GuiManager::Add(IWidget *widget)
{
	cContainer.Add(widget);
}

INLINE void GuiManager::Remove(IWidget *widget)
{
	cContainer.Remove(widget);
}

INLINE void GuiManager::OnInputPointerPress(const EventInputPointer *ev)
{
	cContainer.OnInputPointerPress(ev);
}

INLINE void GuiManager::OnInputPointerRelease(const EventInputPointer *ev)
{
	cContainer.OnInputPointerRelease(ev);
}

INLINE void GuiManager::OnInputPointerMove(const EventInputPointer *ev)
{
	cContainer.OnInputPointerMove(ev);
}

INLINE const char *GuiManager::GetObjectName() const
{
	return "GuiManager";
}

} // namespace
<|endoftext|>