<commit_before>#include "intnw_instruments_network_chooser.h"
#include "intnw_instruments_net_stats_wrapper.h"
#include "libcmm_net_restriction.h"
#include "debug.h"
#include <assert.h>
#include "libpowertutor.h"

#include <functional>
using std::max;

#include <instruments_private.h>
#include <resource_weights.h>

static const char *strategy_names[NUM_STRATEGIES] = {
    "wifi", "3G", "redundant"
};

struct strategy_args {
    IntNWInstrumentsNetworkChooser *chooser;
    InstrumentsWrappedNetStats **net_stats;
};

double
network_transfer_time(instruments_context_t ctx, void *strategy_arg, void *chooser_arg)
{
    struct strategy_args *args = (struct strategy_args *)strategy_arg;
    int bytelen = (int) chooser_arg;
    assert(args->net_stats);
    return args->chooser->calculateTransferTime(ctx, *args->net_stats,
                                                bytelen);
}

double
network_transfer_energy_cost(instruments_context_t ctx, void *strategy_arg, void *chooser_arg)
{
    struct strategy_args *args = (struct strategy_args *)strategy_arg;
    int bytelen = (int) chooser_arg;
    assert(args->net_stats);

    return args->chooser->calculateTransferEnergy(ctx, *args->net_stats,
                                                  bytelen);
}

double
network_transfer_data_cost(instruments_context_t ctx, void *strategy_arg, void *chooser_arg)
{
    struct strategy_args *args = (struct strategy_args *)strategy_arg;
    int bytelen = (int) chooser_arg;
    assert(args->net_stats);

    return args->chooser->calculateTransferMobileData(*args->net_stats, bytelen);
}

double
IntNWInstrumentsNetworkChooser::calculateTransferTime(instruments_context_t ctx,
                                                      InstrumentsWrappedNetStats *net_stats,
                                                      int bytelen)
{
    assert(net_stats);
    double bw = net_stats->get_bandwidth_up(ctx);
    double rtt_seconds = net_stats->get_rtt(ctx);

    bw = max(1.0, bw); // TODO: revisit.  This is a hack to avoid bogus calculations.
    rtt_seconds = max(0.0, rtt_seconds);
    return (bytelen / bw) + rtt_seconds;
}

double
IntNWInstrumentsNetworkChooser::calculateTransferEnergy(instruments_context_t ctx,
                                                        InstrumentsWrappedNetStats *net_stats,
                                                        int bytelen)
{
    assert(net_stats);

    NetworkType type;
    if (net_stats == wifi_stats) {
        type = TYPE_WIFI;
    } else if (net_stats == cellular_stats) {
        type = TYPE_MOBILE;
    } else assert(0);

    double bw = net_stats->get_bandwidth_up(ctx);
    double rtt_seconds = net_stats->get_rtt(ctx);

    return estimate_energy_cost(type, bytelen, bw, rtt_seconds * 1000.0);
}

double
IntNWInstrumentsNetworkChooser::calculateTransferMobileData(InstrumentsWrappedNetStats *net_stats,
                                                            int bytelen)
{
    if (net_stats == wifi_stats) {
        return 0;
    } else if (net_stats == cellular_stats) {
        return bytelen;
    } else assert(0);
}

IntNWInstrumentsNetworkChooser::IntNWInstrumentsNetworkChooser()
    : wifi_present(false), needs_reevaluation(true), chosen_strategy_type(-1)
{
    dbgprintf("creating InstrumentsNetworkChooser %p\n", this);

    wifi_stats = new InstrumentsWrappedNetStats;
    cellular_stats = new InstrumentsWrappedNetStats;

    for (int i = 0; i < NUM_STRATEGIES - 1; ++i) {
        strategy_args[i] = new struct strategy_args;
        strategy_args[i]->chooser = this;
    }
    strategy_args[NETWORK_CHOICE_WIFI]->net_stats = &wifi_stats;
    strategy_args[NETWORK_CHOICE_CELLULAR]->net_stats = &cellular_stats;

    for (int i = NETWORK_CHOICE_WIFI; i <= NETWORK_CHOICE_CELLULAR; ++i) {
        strategies[i] =
            make_strategy(network_transfer_time,
                          network_transfer_energy_cost,
                          network_transfer_data_cost,
                          (void *)strategy_args[i], (void *) 0);
    }

    strategies[NETWORK_CHOICE_BOTH] = make_redundant_strategy(strategies, 2);

    EvalMethod method = EMPIRICAL_ERROR_ALL_SAMPLES_INTNW;
    //EvalMethod method = EMPIRICAL_ERROR_BINNED_INTNW;
    //EvalMethod method = EMPIRICAL_ERROR_BINNED;

    evaluator = register_strategy_set_with_method(strategies, NUM_STRATEGIES, method);
}

IntNWInstrumentsNetworkChooser::~IntNWInstrumentsNetworkChooser()
{
    dbgprintf("destroying InstrumentsNetworkChooser %p\n", this);

    delete wifi_stats;
    delete cellular_stats;

    free_strategy_evaluator(evaluator);

    for (int i = 0; i < NUM_STRATEGIES; ++i) {
        free_strategy(strategies[i]);
    }
    for (int i = NETWORK_CHOICE_WIFI; i <= NETWORK_CHOICE_CELLULAR; ++i) {
        delete strategy_args[i];
    }
}

bool
IntNWInstrumentsNetworkChooser::
choose_networks(u_long send_label, size_t num_bytes,
                struct net_interface& local_iface,
                struct net_interface& remote_iface)
{
    // XXX:  don't really want to require this, but it's
    // XXX:   true for the redundancy experiments.
    // TODO: make sure that CSockMapping calls the
    // TODO:  right version of choose_networks.
    if (num_bytes == 0) {
        // TODO: can we apply the brute force method
        // TODO:  without knowing the size of the data?
        return label_matcher.choose_networks(send_label, num_bytes,
                                             local_iface, remote_iface);
    }

    assert(has_match);

    if (!wifi_present) {
        local_iface = cellular_local;
        remote_iface = cellular_remote;
        return true;
    }

    if (needs_reevaluation) {
        chosen_strategy_type = chooseNetwork(num_bytes);
        needs_reevaluation = false;
    }

    dbgprintf("chooseNetwork: %s\n", strategy_names[chosen_strategy_type]);

    if (chosen_strategy_type == NETWORK_CHOICE_WIFI ||
        chosen_strategy_type == NETWORK_CHOICE_BOTH) {
        local_iface = wifi_local;
        remote_iface = wifi_remote;
    } else {
        assert(chosen_strategy_type == NETWORK_CHOICE_CELLULAR);
        local_iface = cellular_local;
        remote_iface = cellular_remote;
    }
    return true;
}

void
IntNWInstrumentsNetworkChooser::consider(struct net_interface local_iface,
                                         struct net_interface remote_iface)
{
    // pass it to a delegate matcher in case choose_networks
    //  gets called without knowing how many bytes will be sent
    label_matcher.consider(local_iface, remote_iface);

    has_match = true;
    if (matches_type(NET_TYPE_WIFI, local_iface, remote_iface)) {
        wifi_present = true;
        wifi_local = local_iface;
        wifi_remote = remote_iface;
    } else if (matches_type(NET_TYPE_THREEG, local_iface, remote_iface)) {
        cellular_local = local_iface;
        cellular_remote = remote_iface;
    } else assert(false);
}

void
IntNWInstrumentsNetworkChooser::reset()
{
    NetworkChooserImpl::reset();
    wifi_present = false;
    needs_reevaluation = true;
    chosen_strategy_type = -1;
}

int
IntNWInstrumentsNetworkChooser::chooseNetwork(int bytelen)
{
    instruments_strategy_t chosen = choose_strategy(evaluator, (void *)bytelen);
    return getStrategyIndex(chosen);
}

int IntNWInstrumentsNetworkChooser::getStrategyIndex(instruments_strategy_t strategy)
{
    for (int i = 0; i < NUM_STRATEGIES; ++i) {
        if (strategy == strategies[i]) {
            return i;
        }
    }
    assert(0);
}

void
IntNWInstrumentsNetworkChooser::setFixedResourceWeights(double energyWeight,
                                                        double dataWeight)
{
    set_fixed_resource_weights(energyWeight, dataWeight);
}

static int energy_spent_mJ = 0;
static int data_spent_bytes = 0;

void
IntNWInstrumentsNetworkChooser::setAdaptiveResourceBudgets(double goalTime,
                                                           int energyBudgetMilliJoules,
                                                           int dataBudgetBytes)
{
    struct timeval goaltime_tv;
    goaltime_tv.tv_sec = static_cast<time_t>(goalTime);
    goaltime_tv.tv_usec = (goalTime - goaltime_tv.tv_sec) * 1000000;

    energy_spent_mJ = 0;
    data_spent_bytes = 0;

    set_resource_budgets(goaltime_tv, energyBudgetMilliJoules, dataBudgetBytes);
}

void IntNWInstrumentsNetworkChooser::updateResourceWeights()
{
    int new_energy_spent_mJ = energy_consumed_since_reset();
    int new_data_spent_bytes = mobile_bytes_consumed_since_reset();
    report_spent_energy(new_energy_spent_mJ - energy_spent_mJ);
    report_spent_data(new_data_spent_bytes - data_spent_bytes);
    update_weights_now();

    energy_spent_mJ = new_energy_spent_mJ;
    data_spent_bytes = new_data_spent_bytes;
}

double IntNWInstrumentsNetworkChooser::getEnergyWeight()
{
    return get_energy_cost_weight();
}

double IntNWInstrumentsNetworkChooser::getDataWeight()
{
    return get_data_cost_weight();
}

void
IntNWInstrumentsNetworkChooser::reportNetStats(int network_type,
                                               double new_bw,
                                               double new_bw_estimate,
                                               double new_latency_seconds,
                                               double new_latency_estimate)
{
    InstrumentsWrappedNetStats *stats = NULL;
    switch (network_type) {
    case NET_TYPE_WIFI:
        stats = wifi_stats;
        break;
    case NET_TYPE_THREEG:
        stats = cellular_stats;
        break;
    default:
        assert(false);
        break;
    }

    dbgprintf("Adding new stats to %s network estimator:"
              "   bandwidth: obs %f est %f  latency: obs %f est %f\n",
              net_type_name(network_type),
              new_bw, new_bw_estimate, new_latency_seconds, new_latency_estimate);
    stats->update(new_bw, new_bw_estimate,
                  new_latency_seconds, new_latency_estimate);
    needs_reevaluation = true;
}

void
IntNWInstrumentsNetworkChooser::setRedundancyStrategy()
{
    dbgprintf("setting IntNWInstrumentsNetworkChooser::RedundancyStrategy\n");
    assert(redundancyStrategy == NULL);
    redundancyStrategy =
        new IntNWInstrumentsNetworkChooser::RedundancyStrategy(this);
}

IntNWInstrumentsNetworkChooser::RedundancyStrategy::
RedundancyStrategy(IntNWInstrumentsNetworkChooser *chooser_)
    : chooser(chooser_)
{
}

bool
IntNWInstrumentsNetworkChooser::RedundancyStrategy::
shouldTransmitRedundantly(PendingSenderIROB *psirob)
{
    // BUG: this is never called.  WHY NOT?  virtual issues?

    assert(chooser->has_match);
    assert(chooser->chosen_strategy_type != -1);
    dbgprintf("shouldTransmitRedundantly: Chosen network strategy: %s\n",
              strategy_names[chooser->chosen_strategy_type]);
    return (chooser->chosen_strategy_type == NETWORK_CHOICE_BOTH);
}
<commit_msg>Hopefully fixed control-data-send bug.<commit_after>#include "intnw_instruments_network_chooser.h"
#include "intnw_instruments_net_stats_wrapper.h"
#include "libcmm_net_restriction.h"
#include "debug.h"
#include <assert.h>
#include "libpowertutor.h"

#include <functional>
using std::max;

#include <instruments_private.h>
#include <resource_weights.h>

static const char *strategy_names[NUM_STRATEGIES] = {
    "wifi", "3G", "redundant"
};

struct strategy_args {
    IntNWInstrumentsNetworkChooser *chooser;
    InstrumentsWrappedNetStats **net_stats;
};

double
network_transfer_time(instruments_context_t ctx, void *strategy_arg, void *chooser_arg)
{
    struct strategy_args *args = (struct strategy_args *)strategy_arg;
    int bytelen = (int) chooser_arg;
    assert(args->net_stats);
    return args->chooser->calculateTransferTime(ctx, *args->net_stats,
                                                bytelen);
}

double
network_transfer_energy_cost(instruments_context_t ctx, void *strategy_arg, void *chooser_arg)
{
    struct strategy_args *args = (struct strategy_args *)strategy_arg;
    int bytelen = (int) chooser_arg;
    assert(args->net_stats);

    return args->chooser->calculateTransferEnergy(ctx, *args->net_stats,
                                                  bytelen);
}

double
network_transfer_data_cost(instruments_context_t ctx, void *strategy_arg, void *chooser_arg)
{
    struct strategy_args *args = (struct strategy_args *)strategy_arg;
    int bytelen = (int) chooser_arg;
    assert(args->net_stats);

    return args->chooser->calculateTransferMobileData(*args->net_stats, bytelen);
}

double
IntNWInstrumentsNetworkChooser::calculateTransferTime(instruments_context_t ctx,
                                                      InstrumentsWrappedNetStats *net_stats,
                                                      int bytelen)
{
    assert(net_stats);
    double bw = net_stats->get_bandwidth_up(ctx);
    double rtt_seconds = net_stats->get_rtt(ctx);

    bw = max(1.0, bw); // TODO: revisit.  This is a hack to avoid bogus calculations.
    rtt_seconds = max(0.0, rtt_seconds);
    return (bytelen / bw) + rtt_seconds;
}

double
IntNWInstrumentsNetworkChooser::calculateTransferEnergy(instruments_context_t ctx,
                                                        InstrumentsWrappedNetStats *net_stats,
                                                        int bytelen)
{
    assert(net_stats);

    NetworkType type;
    if (net_stats == wifi_stats) {
        type = TYPE_WIFI;
    } else if (net_stats == cellular_stats) {
        type = TYPE_MOBILE;
    } else assert(0);

    double bw = net_stats->get_bandwidth_up(ctx);
    double rtt_seconds = net_stats->get_rtt(ctx);

    return estimate_energy_cost(type, bytelen, bw, rtt_seconds * 1000.0);
}

double
IntNWInstrumentsNetworkChooser::calculateTransferMobileData(InstrumentsWrappedNetStats *net_stats,
                                                            int bytelen)
{
    if (net_stats == wifi_stats) {
        return 0;
    } else if (net_stats == cellular_stats) {
        return bytelen;
    } else assert(0);
}

IntNWInstrumentsNetworkChooser::IntNWInstrumentsNetworkChooser()
    : wifi_present(false), needs_reevaluation(true), chosen_strategy_type(-1)
{
    dbgprintf("creating InstrumentsNetworkChooser %p\n", this);

    wifi_stats = new InstrumentsWrappedNetStats;
    cellular_stats = new InstrumentsWrappedNetStats;

    for (int i = 0; i < NUM_STRATEGIES - 1; ++i) {
        strategy_args[i] = new struct strategy_args;
        strategy_args[i]->chooser = this;
    }
    strategy_args[NETWORK_CHOICE_WIFI]->net_stats = &wifi_stats;
    strategy_args[NETWORK_CHOICE_CELLULAR]->net_stats = &cellular_stats;

    for (int i = NETWORK_CHOICE_WIFI; i <= NETWORK_CHOICE_CELLULAR; ++i) {
        strategies[i] =
            make_strategy(network_transfer_time,
                          network_transfer_energy_cost,
                          network_transfer_data_cost,
                          (void *)strategy_args[i], (void *) 0);
    }

    strategies[NETWORK_CHOICE_BOTH] = make_redundant_strategy(strategies, 2);

    EvalMethod method = EMPIRICAL_ERROR_ALL_SAMPLES_INTNW;
    //EvalMethod method = EMPIRICAL_ERROR_BINNED_INTNW;
    //EvalMethod method = EMPIRICAL_ERROR_BINNED;

    evaluator = register_strategy_set_with_method(strategies, NUM_STRATEGIES, method);
}

IntNWInstrumentsNetworkChooser::~IntNWInstrumentsNetworkChooser()
{
    dbgprintf("destroying InstrumentsNetworkChooser %p\n", this);

    delete wifi_stats;
    delete cellular_stats;

    free_strategy_evaluator(evaluator);

    for (int i = 0; i < NUM_STRATEGIES; ++i) {
        free_strategy(strategies[i]);
    }
    for (int i = NETWORK_CHOICE_WIFI; i <= NETWORK_CHOICE_CELLULAR; ++i) {
        delete strategy_args[i];
    }
}

bool
IntNWInstrumentsNetworkChooser::
choose_networks(u_long send_label, size_t num_bytes,
                struct net_interface& local_iface,
                struct net_interface& remote_iface)
{
    // XXX:  don't really want to require this, but it's
    // XXX:   true for the redundancy experiments.
    // TODO: make sure that CSockMapping calls the
    // TODO:  right version of choose_networks.
    if (num_bytes == 0) {
        // TODO: can we apply the brute force method
        // TODO:  without knowing the size of the data?
        return label_matcher.choose_networks(send_label, num_bytes,
                                             local_iface, remote_iface);
    }

    assert(has_match);

    if (!wifi_present) {
        local_iface = cellular_local;
        remote_iface = cellular_remote;
        return true;
    }

    if (needs_reevaluation) {
        chosen_strategy_type = chooseNetwork(num_bytes);
        needs_reevaluation = false;
    }

    dbgprintf("chooseNetwork: %s\n", strategy_names[chosen_strategy_type]);

    if (chosen_strategy_type == NETWORK_CHOICE_WIFI ||
        chosen_strategy_type == NETWORK_CHOICE_BOTH) {
        local_iface = wifi_local;
        remote_iface = wifi_remote;
    } else {
        assert(chosen_strategy_type == NETWORK_CHOICE_CELLULAR);
        local_iface = cellular_local;
        remote_iface = cellular_remote;
    }
    return true;
}

void
IntNWInstrumentsNetworkChooser::consider(struct net_interface local_iface,
                                         struct net_interface remote_iface)
{
    // pass it to a delegate matcher in case choose_networks
    //  gets called without knowing how many bytes will be sent
    label_matcher.consider(local_iface, remote_iface);

    has_match = true;
    if (matches_type(NET_TYPE_WIFI, local_iface, remote_iface)) {
        wifi_present = true;
        wifi_local = local_iface;
        wifi_remote = remote_iface;
    } else if (matches_type(NET_TYPE_THREEG, local_iface, remote_iface)) {
        cellular_local = local_iface;
        cellular_remote = remote_iface;
    } else assert(false);
}

void
IntNWInstrumentsNetworkChooser::reset()
{
    NetworkChooserImpl::reset();
    wifi_present = false;
    needs_reevaluation = true;
    chosen_strategy_type = -1;

    label_matcher.reset();
}

int
IntNWInstrumentsNetworkChooser::chooseNetwork(int bytelen)
{
    instruments_strategy_t chosen = choose_strategy(evaluator, (void *)bytelen);
    return getStrategyIndex(chosen);
}

int IntNWInstrumentsNetworkChooser::getStrategyIndex(instruments_strategy_t strategy)
{
    for (int i = 0; i < NUM_STRATEGIES; ++i) {
        if (strategy == strategies[i]) {
            return i;
        }
    }
    assert(0);
}

void
IntNWInstrumentsNetworkChooser::setFixedResourceWeights(double energyWeight,
                                                        double dataWeight)
{
    set_fixed_resource_weights(energyWeight, dataWeight);
}

static int energy_spent_mJ = 0;
static int data_spent_bytes = 0;

void
IntNWInstrumentsNetworkChooser::setAdaptiveResourceBudgets(double goalTime,
                                                           int energyBudgetMilliJoules,
                                                           int dataBudgetBytes)
{
    struct timeval goaltime_tv;
    goaltime_tv.tv_sec = static_cast<time_t>(goalTime);
    goaltime_tv.tv_usec = (goalTime - goaltime_tv.tv_sec) * 1000000;

    energy_spent_mJ = 0;
    data_spent_bytes = 0;

    set_resource_budgets(goaltime_tv, energyBudgetMilliJoules, dataBudgetBytes);
}

void IntNWInstrumentsNetworkChooser::updateResourceWeights()
{
    int new_energy_spent_mJ = energy_consumed_since_reset();
    int new_data_spent_bytes = mobile_bytes_consumed_since_reset();
    report_spent_energy(new_energy_spent_mJ - energy_spent_mJ);
    report_spent_data(new_data_spent_bytes - data_spent_bytes);
    update_weights_now();

    energy_spent_mJ = new_energy_spent_mJ;
    data_spent_bytes = new_data_spent_bytes;
}

double IntNWInstrumentsNetworkChooser::getEnergyWeight()
{
    return get_energy_cost_weight();
}

double IntNWInstrumentsNetworkChooser::getDataWeight()
{
    return get_data_cost_weight();
}

void
IntNWInstrumentsNetworkChooser::reportNetStats(int network_type,
                                               double new_bw,
                                               double new_bw_estimate,
                                               double new_latency_seconds,
                                               double new_latency_estimate)
{
    InstrumentsWrappedNetStats *stats = NULL;
    switch (network_type) {
    case NET_TYPE_WIFI:
        stats = wifi_stats;
        break;
    case NET_TYPE_THREEG:
        stats = cellular_stats;
        break;
    default:
        assert(false);
        break;
    }

    dbgprintf("Adding new stats to %s network estimator:"
              "   bandwidth: obs %f est %f  latency: obs %f est %f\n",
              net_type_name(network_type),
              new_bw, new_bw_estimate, new_latency_seconds, new_latency_estimate);
    stats->update(new_bw, new_bw_estimate,
                  new_latency_seconds, new_latency_estimate);
    needs_reevaluation = true;
}

void
IntNWInstrumentsNetworkChooser::setRedundancyStrategy()
{
    dbgprintf("setting IntNWInstrumentsNetworkChooser::RedundancyStrategy\n");
    assert(redundancyStrategy == NULL);
    redundancyStrategy =
        new IntNWInstrumentsNetworkChooser::RedundancyStrategy(this);
}

IntNWInstrumentsNetworkChooser::RedundancyStrategy::
RedundancyStrategy(IntNWInstrumentsNetworkChooser *chooser_)
    : chooser(chooser_)
{
}

bool
IntNWInstrumentsNetworkChooser::RedundancyStrategy::
shouldTransmitRedundantly(PendingSenderIROB *psirob)
{
    assert(chooser->has_match);
    assert(chooser->chosen_strategy_type != -1);
    dbgprintf("shouldTransmitRedundantly: Chosen network strategy: %s\n",
              strategy_names[chooser->chosen_strategy_type]);
    return (chooser->chosen_strategy_type == NETWORK_CHOICE_BOTH);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"

#include "SkCanvas.h"
#include "SkComposeShader.h"
#include "SkGradientShader.h"
#include "SkGraphics.h"
#include "SkShader.h"
#include "SkString.h"
#include "SkXfermode.h"

static SkShader* make_shader(SkXfermode::Mode mode) {
    SkPoint pts[2];
    SkColor colors[2];

    pts[0].set(0, 0);
    pts[1].set(SkIntToScalar(100), 0);
    colors[0] = SK_ColorRED;
    colors[1] = SK_ColorBLUE;
    SkAutoTUnref<SkShader> shaderA(SkGradientShader::CreateLinear(pts, colors, nullptr, 2,
                                                                  SkShader::kClamp_TileMode));

    pts[0].set(0, 0);
    pts[1].set(0, SkIntToScalar(100));
    colors[0] = SK_ColorBLACK;
    colors[1] = SkColorSetARGB(0x80, 0, 0, 0);
    SkAutoTUnref<SkShader> shaderB(SkGradientShader::CreateLinear(pts, colors, nullptr, 2,
                                                                  SkShader::kClamp_TileMode));

    SkAutoTUnref<SkXfermode> xfer(SkXfermode::Create(mode));

    return new SkComposeShader(shaderA, shaderB, xfer);
}

class ComposeShaderGM : public skiagm::GM {
public:
    ComposeShaderGM() {
        fShader = make_shader(SkXfermode::kDstIn_Mode);
    }

    virtual ~ComposeShaderGM() {
        SkSafeUnref(fShader);
    }

protected:
    SkString onShortName() override {
        return SkString("composeshader");
    }

    SkISize onISize() override {
        return SkISize::Make(120, 120);
    }

    void onDraw(SkCanvas* canvas) override {

        SkPaint paint;

        paint.setColor(SK_ColorGREEN);
        canvas->drawRectCoords(0, 0, SkIntToScalar(100), SkIntToScalar(100), paint);
        paint.setShader(fShader);
        canvas->drawRectCoords(0, 0, SkIntToScalar(100), SkIntToScalar(100), paint);
    }

protected:
    SkShader*   fShader;

private:
    typedef GM INHERITED ;
};

class ComposeShaderAlphaGM : public skiagm::GM {
public:
    ComposeShaderAlphaGM() {}

protected:
    SkString onShortName() override {
        return SkString("composeshader_alpha");
    }

    SkISize onISize() override {
        return SkISize::Make(220, 750);
    }

    void onDraw(SkCanvas* canvas) override {
        SkAutoTUnref<SkShader> shader0(make_shader(SkXfermode::kDstIn_Mode));
        SkAutoTUnref<SkShader> shader1(make_shader(SkXfermode::kSrcOver_Mode));
        SkShader* shaders[] = { shader0.get(), shader1.get() };

        SkPaint paint;
        paint.setColor(SK_ColorGREEN);

        const SkRect r = SkRect::MakeXYWH(5, 5, 100, 100);

        for (size_t y = 0; y < SK_ARRAY_COUNT(shaders); ++y) {
            SkShader* shader = shaders[y];
            canvas->save();
            for (int alpha = 0xFF; alpha > 0; alpha -= 0x28) {
                paint.setAlpha(0xFF);
                paint.setShader(nullptr);
                canvas->drawRect(r, paint);

                paint.setAlpha(alpha);
                paint.setShader(shader);
                canvas->drawRect(r, paint);

                canvas->translate(r.width() + 5, 0);
            }
            canvas->restore();
            canvas->translate(0, r.height() + 5);
        }
    }
};

//////////////////////////////////////////////////////////////////////////////

DEF_GM( return new ComposeShaderGM; )
DEF_GM( return new ComposeShaderAlphaGM; )
<commit_msg>Will try composing a linear gradient with a color bitmap as well as an alpha8 bitmap to make sure the paint's color is being used/ignored in the right places.<commit_after>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"

#include "SkBitmapProcShader.h"
#include "SkCanvas.h"
#include "SkComposeShader.h"
#include "SkGradientShader.h"
#include "SkGraphics.h"
#include "SkShader.h"
#include "SkString.h"
#include "SkXfermode.h"

static SkShader* make_shader(SkXfermode::Mode mode) {
    SkPoint pts[2];
    SkColor colors[2];

    pts[0].set(0, 0);
    pts[1].set(SkIntToScalar(100), 0);
    colors[0] = SK_ColorRED;
    colors[1] = SK_ColorBLUE;
    SkAutoTUnref<SkShader> shaderA(SkGradientShader::CreateLinear(pts, colors, nullptr, 2,
                                                                  SkShader::kClamp_TileMode));

    pts[0].set(0, 0);
    pts[1].set(0, SkIntToScalar(100));
    colors[0] = SK_ColorBLACK;
    colors[1] = SkColorSetARGB(0x80, 0, 0, 0);
    SkAutoTUnref<SkShader> shaderB(SkGradientShader::CreateLinear(pts, colors, nullptr, 2,
                                                                  SkShader::kClamp_TileMode));

    SkAutoTUnref<SkXfermode> xfer(SkXfermode::Create(mode));

    return new SkComposeShader(shaderA, shaderB, xfer);
}

class ComposeShaderGM : public skiagm::GM {
public:
    ComposeShaderGM() {
        fShader = make_shader(SkXfermode::kDstIn_Mode);
    }

    virtual ~ComposeShaderGM() {
        SkSafeUnref(fShader);
    }

protected:
    SkString onShortName() override {
        return SkString("composeshader");
    }

    SkISize onISize() override {
        return SkISize::Make(120, 120);
    }

    void onDraw(SkCanvas* canvas) override {

        SkPaint paint;

        paint.setColor(SK_ColorGREEN);
        canvas->drawRectCoords(0, 0, SkIntToScalar(100), SkIntToScalar(100), paint);
        paint.setShader(fShader);
        canvas->drawRectCoords(0, 0, SkIntToScalar(100), SkIntToScalar(100), paint);
    }

protected:
    SkShader*   fShader;

private:
    typedef GM INHERITED ;
};

class ComposeShaderAlphaGM : public skiagm::GM {
public:
    ComposeShaderAlphaGM() {}

protected:
    SkString onShortName() override {
        return SkString("composeshader_alpha");
    }

    SkISize onISize() override {
        return SkISize::Make(750, 220);
    }

    void onDraw(SkCanvas* canvas) override {
        SkAutoTUnref<SkShader> shader0(make_shader(SkXfermode::kDstIn_Mode));
        SkAutoTUnref<SkShader> shader1(make_shader(SkXfermode::kSrcOver_Mode));
        SkShader* shaders[] = { shader0.get(), shader1.get() };

        SkPaint paint;
        paint.setColor(SK_ColorGREEN);

        const SkRect r = SkRect::MakeXYWH(5, 5, 100, 100);

        for (size_t y = 0; y < SK_ARRAY_COUNT(shaders); ++y) {
            SkShader* shader = shaders[y];
            canvas->save();
            for (int alpha = 0xFF; alpha > 0; alpha -= 0x28) {
                paint.setAlpha(0xFF);
                paint.setShader(nullptr);
                canvas->drawRect(r, paint);

                paint.setAlpha(alpha);
                paint.setShader(shader);
                canvas->drawRect(r, paint);

                canvas->translate(r.width() + 5, 0);
            }
            canvas->restore();
            canvas->translate(0, r.height() + 5);
        }
    }

private:
    typedef GM INHERITED ;
};

// creates a square bitmap with red background and a green circle in the center
static void draw_color_bm(SkBitmap* bm, int length) {
    SkPaint paint;
    paint.setColor(SK_ColorGREEN);

    bm->allocN32Pixels(length, length);
    bm->eraseColor(SK_ColorRED);

    SkCanvas canvas(*bm);
    canvas.drawCircle(SkIntToScalar(length/2), SkIntToScalar(length/2), SkIntToScalar(length/2),
                      paint);
}

// creates a square alpha8 bitmap with transparent background and an opaque circle in the center
static void draw_alpha8_bm(SkBitmap* bm, int length) {
    SkPaint circlePaint;
    circlePaint.setColor(SK_ColorBLACK);

    bm->allocPixels(SkImageInfo::MakeA8(length, length));
    bm->eraseColor(SK_ColorTRANSPARENT);

    SkCanvas canvas(*bm);
    canvas.drawCircle(SkIntToScalar(length/2), SkIntToScalar(length/2), SkIntToScalar(length/4),
                      circlePaint);
}

// creates a linear gradient shader
static SkShader* make_linear_gradient_shader(int length) {
    SkPoint pts[2];
    SkColor colors[2];
    pts[0].set(0, 0);
    pts[1].set(SkIntToScalar(length), 0);
    colors[0] = SK_ColorBLUE;
    colors[1] = SkColorSetARGB(0, 0, 0, 0xFF);
    return SkGradientShader::CreateLinear(pts, colors, nullptr, 2, SkShader::kClamp_TileMode);
}

class ComposeShaderBitmapGM : public skiagm::GM {
public:
    ComposeShaderBitmapGM() {
        draw_color_bm(&fColorBitmap, squareLength);
        draw_alpha8_bm(&fAlpha8Bitmap, squareLength);
        SkMatrix s;
        s.reset();
        fColorBitmapShader = new SkBitmapProcShader(fColorBitmap, SkShader::kRepeat_TileMode,
                                                    SkShader::kRepeat_TileMode, &s);
        fAlpha8BitmapShader = new SkBitmapProcShader(fAlpha8Bitmap, SkShader::kRepeat_TileMode,
                                                     SkShader::kRepeat_TileMode, &s);
        fLinearGradientShader = make_linear_gradient_shader(squareLength);
    }
    ~ComposeShaderBitmapGM() {
        SkSafeUnref(fColorBitmapShader);
        SkSafeUnref(fAlpha8BitmapShader);
        SkSafeUnref(fLinearGradientShader);
    }

protected:
    SkString onShortName() override {
        return SkString("composeshader_bitmap");
    }

    SkISize onISize() override {
        return SkISize::Make(7 * (squareLength + 5), 2 * (squareLength + 5));
    }

    void onDraw(SkCanvas* canvas) override {
        SkAutoTUnref<SkXfermode> xfer(SkXfermode::Create(SkXfermode::kDstOver_Mode));

        // gradient should appear over color bitmap
        SkAutoTUnref<SkShader> shader0(new SkComposeShader(fLinearGradientShader,
                                                           fColorBitmapShader,
                                                           xfer));
        // gradient should appear over alpha8 bitmap colorized by the paint color
        SkAutoTUnref<SkShader> shader1(new SkComposeShader(fLinearGradientShader,
                                                           fAlpha8BitmapShader,
                                                           xfer));

        SkShader* shaders[] = { shader0.get(), shader1.get() };

        SkPaint paint;
        paint.setColor(SK_ColorYELLOW);

        const SkRect r = SkRect::MakeXYWH(0, 0, SkIntToScalar(squareLength),
                                          SkIntToScalar(squareLength));

        for (size_t y = 0; y < SK_ARRAY_COUNT(shaders); ++y) {
            SkShader* shader = shaders[y];
            canvas->save();
            for (int alpha = 0xFF; alpha > 0; alpha -= 0x28) {
                paint.setAlpha(alpha);
                paint.setShader(shader);
                canvas->drawRect(r, paint);

                canvas->translate(r.width() + 5, 0);
            }
            canvas->restore();
            canvas->translate(0, r.height() + 5);
        }
    }
private:
    /** This determines the length and width of the bitmaps used in the SkComposeShaders.  Values
     *  above 20 may cause an SkASSERT to fail in SkSmallAllocator. However, larger values will
     *  work in a release build.  You can change this parameter and then compile a release build
     *  to have this GM draw larger bitmaps for easier visual inspection.
     */
    static const int squareLength = 20;

    SkBitmap fColorBitmap;
    SkBitmap fAlpha8Bitmap;
    SkShader* fColorBitmapShader;
    SkShader* fAlpha8BitmapShader;
    SkShader* fLinearGradientShader;

    typedef GM INHERITED;
};

//////////////////////////////////////////////////////////////////////////////

DEF_GM( return new ComposeShaderGM; )
DEF_GM( return new ComposeShaderAlphaGM; )
DEF_GM( return new ComposeShaderBitmapGM; )
<|endoftext|>


<commit_before>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "gm.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkDevice.h"
#include "SkString.h"

namespace skiagm {

static void create_bitmap(SkBitmap* bitmap) {
    const int W = 100;
    const int H = 100;
    bitmap->setConfig(SkBitmap::kARGB_8888_Config, W, H);
    bitmap->allocPixels();

    SkCanvas canvas(*bitmap);
    canvas.drawColor(SK_ColorRED);
    SkPaint paint;
    paint.setColor(SK_ColorBLUE);
    canvas.drawCircle(SkIntToScalar(W)/2, SkIntToScalar(H)/2, SkIntToScalar(W)/2, paint);
}

class ExtractBitmapGM : public GM {
public:
    ExtractBitmapGM() {}

protected:
    // overrides from SkEventSink
    virtual SkString onShortName() SK_OVERRIDE {
        return SkString("extractbitmap");
    }

    virtual SkISize onISize() SK_OVERRIDE {
        return make_isize(600, 600);
    }

    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
        SkBitmap bitmap;
        create_bitmap(&bitmap);
        int x = bitmap.width() / 2;
        int y = bitmap.height() / 2;
        SkBitmap subset;
        bitmap.extractSubset(&subset, SkIRect::MakeXYWH(x, y, x, y));

        canvas->translate(SkIntToScalar(20), SkIntToScalar(20));

        canvas->drawBitmap(bitmap, 0, 0);
        canvas->drawBitmap(subset, 0, 0);

        // Now do the same but with a device bitmap as source image
        SkRefPtr<SkDevice> primaryDevice(canvas->getDevice());
        SkRefPtr<SkDevice> secondDevice(canvas->createCompatibleDevice(
            SkBitmap::kARGB_8888_Config, bitmap.width(),
            bitmap.height(), true));
        secondDevice->unref();
        SkCanvas secondCanvas(secondDevice.get());
        secondCanvas.writePixels(bitmap, 0, 0);

        SkBitmap deviceBitmap = secondDevice->accessBitmap(false);
        SkBitmap deviceSubset;
        deviceBitmap.extractSubset(&deviceSubset,
             SkIRect::MakeXYWH(x, y, x, y));

        canvas->translate(SkIntToScalar(120), SkIntToScalar(0));

        canvas->drawBitmap(deviceBitmap, 0, 0);
        canvas->drawBitmap(deviceSubset, 0, 0);

    }

private:
    typedef GM INHERITED;
};

//////////////////////////////////////////////////////////////////////////////

static GM* MyFactory(void*) { return new ExtractBitmapGM; }
static GMRegistry reg(MyFactory);

}
<commit_msg>Fix buildbot.<commit_after>
/*
 * Copyright 2011 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "gm.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkDevice.h"
#include "SkString.h"

namespace skiagm {

static void create_bitmap(SkBitmap* bitmap) {
    const int W = 100;
    const int H = 100;
    bitmap->setConfig(SkBitmap::kARGB_8888_Config, W, H);
    bitmap->allocPixels();

    SkCanvas canvas(*bitmap);
    canvas.drawColor(SK_ColorRED);
    SkPaint paint;
    paint.setColor(SK_ColorBLUE);
    canvas.drawCircle(SkIntToScalar(W)/2, SkIntToScalar(H)/2, SkIntToScalar(W)/2, paint);
}

class ExtractBitmapGM : public GM {
public:
    ExtractBitmapGM() {}

protected:
    // overrides from SkEventSink
    virtual SkString onShortName() SK_OVERRIDE {
        return SkString("extractbitmap");
    }

    virtual SkISize onISize() SK_OVERRIDE {
        return make_isize(600, 600);
    }

    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
        SkBitmap bitmap;
        create_bitmap(&bitmap);
        int x = bitmap.width() / 2;
        int y = bitmap.height() / 2;
        SkBitmap subset;
        bitmap.extractSubset(&subset, SkIRect::MakeXYWH(x, y, x, y));

        canvas->translate(SkIntToScalar(20), SkIntToScalar(20));

        canvas->drawBitmap(bitmap, 0, 0);
        canvas->drawBitmap(subset, 0, 0);
/*
        // Now do the same but with a device bitmap as source image
        SkRefPtr<SkDevice> primaryDevice(canvas->getDevice());
        SkRefPtr<SkDevice> secondDevice(canvas->createCompatibleDevice(
            SkBitmap::kARGB_8888_Config, bitmap.width(),
            bitmap.height(), true));
        secondDevice->unref();
        SkCanvas secondCanvas(secondDevice.get());
        secondCanvas.writePixels(bitmap, 0, 0);

        SkBitmap deviceBitmap = secondDevice->accessBitmap(false);
        SkBitmap deviceSubset;
        deviceBitmap.extractSubset(&deviceSubset,
             SkIRect::MakeXYWH(x, y, x, y));

        canvas->translate(SkIntToScalar(120), SkIntToScalar(0));

        canvas->drawBitmap(deviceBitmap, 0, 0);
        canvas->drawBitmap(deviceSubset, 0, 0);
*/
    }

private:
    typedef GM INHERITED;
};

//////////////////////////////////////////////////////////////////////////////

static GM* MyFactory(void*) { return new ExtractBitmapGM; }
static GMRegistry reg(MyFactory);

}
<|endoftext|>


<commit_before>/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"

#include "Resources.h"
#include "SkBitmapScaler.h"
#include "SkGradientShader.h"
#include "SkTypeface.h"
#include "SkImageDecoder.h"
#include "SkStream.h"
#include "SkPaint.h"
#include "SkMipMap.h"
#include "Resources.h"
#include "sk_tool_utils.h"

static SkBitmap make_bitmap(int size) {
    SkBitmap bm;
    bm.allocN32Pixels(size, size);
    SkCanvas canvas(bm);
    canvas.clear(0xFFFFFFFF);
    SkPaint paint;
    paint.setStyle(SkPaint::kStroke_Style);
    paint.setStrokeWidth(size / 16.0f);
    canvas.drawCircle(size/2.0f, size/2.0f, size/3.0f, paint);
    return bm;
}

static SkBitmap make_bitmap2(int size) {
    SkBitmap bm;
    bm.allocN32Pixels(size, size);
    SkCanvas canvas(bm);
    canvas.clear(0xFFFFFFFF);
    SkPaint paint;
    paint.setStyle(SkPaint::kStroke_Style);

    SkScalar inset = 2;
    SkRect r = SkRect::MakeIWH(size, size).makeInset(0.5f, 0.5f);
    while (r.width() > 4) {
        canvas.drawRect(r, paint);
        r.inset(inset, inset);
        inset += 1;
    }
    return bm;
}

#include "SkNx.h"
static SkBitmap make_bitmap3(int size) {
    SkBitmap bm;
    bm.allocN32Pixels(size, size);
    SkCanvas canvas(bm);
    canvas.clear(0xFFFFFFFF);
    SkPaint paint;
    paint.setStyle(SkPaint::kStroke_Style);
    paint.setStrokeWidth(2.1f);

    SkScalar s = SkIntToScalar(size);
    Sk4f p(s, -s, -s, s);
    Sk4f d(5);
    while (p.kth<1>() < s) {
        canvas.drawLine(p.kth<0>(),p.kth<1>(), p.kth<2>(), p.kth<3>(), paint);
        p = p + d;
    }
    return bm;
}

class ShowMipLevels : public skiagm::GM {
    const int fN;
    SkBitmap  fBM[4];

public:
    static unsigned gamma(unsigned n) {
        float x = n / 255.0f;
#if 0
        x = sqrtf(x);
#else
        if (x > 0.0031308f) {
            x = 1.055f * (powf(x, (1.0f / 2.4f))) - 0.055f;
        } else {
            x = 12.92f * x;
        }
#endif
        return (int)(x * 255);
    }

    static void apply_gamma(const SkBitmap& bm) {
        return; // below is our experiment for sRGB correction
        bm.lockPixels();
        for (int y = 0; y < bm.height(); ++y) {
            for (int x = 0; x < bm.width(); ++x) {
                SkPMColor c = *bm.getAddr32(x, y);
                unsigned r = gamma(SkGetPackedR32(c));
                unsigned g = gamma(SkGetPackedG32(c));
                unsigned b = gamma(SkGetPackedB32(c));
                *bm.getAddr32(x, y) = SkPackARGB32(0xFF, r, g, b);
            }
        }
    }

    ShowMipLevels(int N) : fN(N) {
        fBM[0] = sk_tool_utils::create_checkerboard_bitmap(N, N, SK_ColorBLACK, SK_ColorWHITE, 2);
        fBM[1] = make_bitmap(N);
        fBM[2] = make_bitmap2(N);
        fBM[3] = make_bitmap3(N);
    }

protected:

    SkString onShortName() override {
        SkString str;
        str.printf("showmiplevels_%d", fN);
        return str;
    }

    SkISize onISize() override {
        return { 824, 862 };
    }

    static void DrawAndFrame(SkCanvas* canvas, const SkBitmap& orig, SkScalar x, SkScalar y) {
        SkBitmap bm;
        orig.copyTo(&bm);
        apply_gamma(bm);

        canvas->drawBitmap(bm, x, y, nullptr);
        SkPaint paint;
        paint.setStyle(SkPaint::kStroke_Style);
        paint.setColor(0xFFFFCCCC);
        canvas->drawRect(SkRect::MakeIWH(bm.width(), bm.height()).makeOffset(x, y).makeOutset(0.5f, 0.5f), paint);
    }

    template <typename F> void drawLevels(SkCanvas* canvas, const SkBitmap& baseBM, F func) {
        SkScalar x = 4;
        SkScalar y = 4;

        SkPixmap prevPM;
        baseBM.lockPixels();
        baseBM.peekPixels(&prevPM);

        SkAutoTUnref<SkMipMap> mm(SkMipMap::Build(baseBM, nullptr));

        int index = 0;
        SkMipMap::Level level;
        SkScalar scale = 0.5f;
        while (mm->extractLevel(scale, &level)) {
            SkImageInfo info = SkImageInfo::MakeN32Premul(level.fWidth, level.fHeight);
            SkPixmap levelPM{ info, level.fPixels, level.fRowBytes };

            SkBitmap bm = func(prevPM, levelPM);
            DrawAndFrame(canvas, bm, x, y);

            if (info.width() <= 2 || info.height() <= 2) {
                break;
            }
            if (index & 1) {
                x += info.width() + 4;
            } else {
                y += info.height() + 4;
            }
            scale /= 2;
            prevPM = levelPM;
            index += 1;
        }
    }

    void drawSet(SkCanvas* canvas, const SkBitmap& orig) {
        SkAutoCanvasRestore acr(canvas, true);

        drawLevels(canvas, orig, [](const SkPixmap& prev, const SkPixmap& curr) {
            SkBitmap bm;
            bm.installPixels(curr);
            return bm;
        });

        const SkBitmapScaler::ResizeMethod methods[] = {
            SkBitmapScaler::RESIZE_BOX,
            SkBitmapScaler::RESIZE_TRIANGLE,
            SkBitmapScaler::RESIZE_LANCZOS3,
            SkBitmapScaler::RESIZE_HAMMING,
            SkBitmapScaler::RESIZE_MITCHELL,
        };

        SkPixmap basePM;
        orig.lockPixels();
        orig.peekPixels(&basePM);
        for (auto method : methods) {
            canvas->translate(orig.width()/2 + 8.0f, 0);
            drawLevels(canvas, orig, [basePM, method](const SkPixmap& prev, const SkPixmap& curr) {
                SkBitmap bm;
                SkBitmapScaler::Resize(&bm, prev, method, curr.width(), curr.height());
                return bm;
            });
        }
    }

    void onDraw(SkCanvas* canvas) override {
        canvas->translate(4, 4);
        for (const auto& bm : fBM) {
            this->drawSet(canvas, bm);
            canvas->translate(0, bm.height() * 0.85f);
        }
    }

private:
    typedef skiagm::GM INHERITED;
};
DEF_GM( return new ShowMipLevels(255); )
DEF_GM( return new ShowMipLevels(256); )

<commit_msg>add GM to show miplevels for all colortypes<commit_after>/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "gm.h"

#include "Resources.h"
#include "SkBitmapScaler.h"
#include "SkGradientShader.h"
#include "SkTypeface.h"
#include "SkImageDecoder.h"
#include "SkStream.h"
#include "SkPaint.h"
#include "SkMipMap.h"
#include "Resources.h"
#include "sk_tool_utils.h"

static SkBitmap make_bitmap(int w, int h) {
    SkBitmap bm;
    bm.allocN32Pixels(w, h);
    SkCanvas canvas(bm);
    canvas.clear(0xFFFFFFFF);
    SkPaint paint;
    paint.setStyle(SkPaint::kStroke_Style);
    paint.setStrokeWidth(w / 16.0f);
    canvas.drawCircle(w/2.0f, h/2.0f, w/3.0f, paint);
    return bm;
}

static SkBitmap make_bitmap2(int w, int h) {
    SkBitmap bm;
    bm.allocN32Pixels(w, h);
    SkCanvas canvas(bm);
    canvas.clear(0xFFFFFFFF);
    SkPaint paint;
    paint.setStyle(SkPaint::kStroke_Style);

    SkScalar inset = 2;
    SkRect r = SkRect::MakeIWH(w, h).makeInset(0.5f, 0.5f);
    while (r.width() > 4) {
        canvas.drawRect(r, paint);
        r.inset(inset, inset);
        inset += 1;
    }
    return bm;
}

#include "SkNx.h"
static SkBitmap make_bitmap3(int w, int h) {
    SkBitmap bm;
    bm.allocN32Pixels(w, h);
    SkCanvas canvas(bm);
    canvas.clear(0xFFFFFFFF);
    SkPaint paint;
    paint.setStyle(SkPaint::kStroke_Style);
    paint.setStrokeWidth(2.1f);

    SkScalar s = SkIntToScalar(w);
    Sk4f p(s, -s, -s, s);
    Sk4f d(5);
    while (p.kth<1>() < s) {
        canvas.drawLine(p.kth<0>(),p.kth<1>(), p.kth<2>(), p.kth<3>(), paint);
        p = p + d;
    }
    return bm;
}

class ShowMipLevels : public skiagm::GM {
    const int fN;
    SkBitmap  fBM[4];

public:
    static unsigned gamma(unsigned n) {
        float x = n / 255.0f;
#if 0
        x = sqrtf(x);
#else
        if (x > 0.0031308f) {
            x = 1.055f * (powf(x, (1.0f / 2.4f))) - 0.055f;
        } else {
            x = 12.92f * x;
        }
#endif
        return (int)(x * 255);
    }

    static void apply_gamma(const SkBitmap& bm) {
        return; // below is our experiment for sRGB correction
        bm.lockPixels();
        for (int y = 0; y < bm.height(); ++y) {
            for (int x = 0; x < bm.width(); ++x) {
                SkPMColor c = *bm.getAddr32(x, y);
                unsigned r = gamma(SkGetPackedR32(c));
                unsigned g = gamma(SkGetPackedG32(c));
                unsigned b = gamma(SkGetPackedB32(c));
                *bm.getAddr32(x, y) = SkPackARGB32(0xFF, r, g, b);
            }
        }
    }

    ShowMipLevels(int N) : fN(N) {
        fBM[0] = sk_tool_utils::create_checkerboard_bitmap(N, N, SK_ColorBLACK, SK_ColorWHITE, 2);
        fBM[1] = make_bitmap(N, N);
        fBM[2] = make_bitmap2(N, N);
        fBM[3] = make_bitmap3(N, N);
    }

protected:

    SkString onShortName() override {
        SkString str;
        str.printf("showmiplevels_%d", fN);
        return str;
    }

    SkISize onISize() override {
        return { 824, 862 };
    }

    static void DrawAndFrame(SkCanvas* canvas, const SkBitmap& orig, SkScalar x, SkScalar y) {
        SkBitmap bm;
        orig.copyTo(&bm);
        apply_gamma(bm);

        canvas->drawBitmap(bm, x, y, nullptr);
        SkPaint paint;
        paint.setStyle(SkPaint::kStroke_Style);
        paint.setColor(0xFFFFCCCC);
        canvas->drawRect(SkRect::MakeIWH(bm.width(), bm.height()).makeOffset(x, y).makeOutset(0.5f, 0.5f), paint);
    }

    template <typename F> void drawLevels(SkCanvas* canvas, const SkBitmap& baseBM, F func) {
        SkScalar x = 4;
        SkScalar y = 4;

        SkPixmap prevPM;
        baseBM.lockPixels();
        baseBM.peekPixels(&prevPM);

        SkAutoTUnref<SkMipMap> mm(SkMipMap::Build(baseBM, nullptr));

        int index = 0;
        SkMipMap::Level level;
        SkScalar scale = 0.5f;
        while (mm->extractLevel(scale, &level)) {
            SkImageInfo info = SkImageInfo::Make(level.fWidth, level.fHeight,
                                                 baseBM.colorType(), baseBM.alphaType());
            SkPixmap levelPM{ info, level.fPixels, level.fRowBytes };

            SkBitmap bm = func(prevPM, levelPM);
            DrawAndFrame(canvas, bm, x, y);

            if (info.width() <= 2 || info.height() <= 2) {
                break;
            }
            if (index & 1) {
                x += info.width() + 4;
            } else {
                y += info.height() + 4;
            }
            scale /= 2;
            prevPM = levelPM;
            index += 1;
        }
    }

    void drawSet(SkCanvas* canvas, const SkBitmap& orig) {
        SkAutoCanvasRestore acr(canvas, true);

        drawLevels(canvas, orig, [](const SkPixmap& prev, const SkPixmap& curr) {
            SkBitmap bm;
            bm.installPixels(curr);
            return bm;
        });

        const SkBitmapScaler::ResizeMethod methods[] = {
            SkBitmapScaler::RESIZE_BOX,
            SkBitmapScaler::RESIZE_TRIANGLE,
            SkBitmapScaler::RESIZE_LANCZOS3,
            SkBitmapScaler::RESIZE_HAMMING,
            SkBitmapScaler::RESIZE_MITCHELL,
        };

        SkPixmap basePM;
        orig.lockPixels();
        orig.peekPixels(&basePM);
        for (auto method : methods) {
            canvas->translate(orig.width()/2 + 8.0f, 0);
            drawLevels(canvas, orig, [basePM, method](const SkPixmap& prev, const SkPixmap& curr) {
                SkBitmap bm;
                SkBitmapScaler::Resize(&bm, prev, method, curr.width(), curr.height());
                return bm;
            });
        }
    }

    void onDraw(SkCanvas* canvas) override {
        canvas->translate(4, 4);
        for (const auto& bm : fBM) {
            this->drawSet(canvas, bm);
            canvas->translate(0, bm.height() * 0.85f);
        }
    }

private:
    typedef skiagm::GM INHERITED;
};
DEF_GM( return new ShowMipLevels(255); )
DEF_GM( return new ShowMipLevels(256); )

///////////////////////////////////////////////////////////////////////////////////////////////////

/**
 *  Show mip levels that were built, for all supported colortypes
 */
class ShowMipLevels2 : public skiagm::GM {
    const int fW, fH;
    SkBitmap  fBM[4];

public:
    ShowMipLevels2(int w, int h) : fW(w), fH(h) {
        fBM[0] = sk_tool_utils::create_checkerboard_bitmap(w, h, SK_ColorBLACK, SK_ColorWHITE, 2);
        fBM[1] = make_bitmap(w, h);
        fBM[2] = make_bitmap2(w, h);
        fBM[3] = make_bitmap3(w, h);
    }

protected:

    SkString onShortName() override {
        SkString str;
        str.printf("showmiplevels2_%dx%d", fW, fH);
        return str;
    }

    SkISize onISize() override {
        return { 824, 862 };
    }

    static void DrawAndFrame(SkCanvas* canvas, const SkBitmap& bm, SkScalar x, SkScalar y) {
        canvas->drawBitmap(bm, x, y, nullptr);
        SkPaint paint;
        paint.setStyle(SkPaint::kStroke_Style);
        paint.setColor(0xFFFFCCCC);
        canvas->drawRect(SkRect::MakeIWH(bm.width(), bm.height()).makeOffset(x, y).makeOutset(0.5f, 0.5f), paint);
    }

    void drawLevels(SkCanvas* canvas, const SkBitmap& baseBM) {
        SkScalar x = 4;
        SkScalar y = 4;

        SkAutoTUnref<SkMipMap> mm(SkMipMap::Build(baseBM, nullptr));

        int index = 0;
        SkMipMap::Level level;
        SkScalar scale = 0.5f;
        while (mm->extractLevel(scale, &level)) {
            SkImageInfo info = SkImageInfo::Make(level.fWidth, level.fHeight,
                                                 baseBM.colorType(), baseBM.alphaType());

            SkBitmap bm;
            bm.installPixels(info, level.fPixels, level.fRowBytes);
            DrawAndFrame(canvas, bm, x, y);

            if (info.width() <= 2 || info.height() <= 2) {
                break;
            }
            if (index & 1) {
                x += info.width() + 4;
            } else {
                y += info.height() + 4;
            }
            scale /= 2;
            index += 1;
        }
    }

    void drawSet(SkCanvas* canvas, const SkBitmap& orig) {
        const SkColorType ctypes[] = {
            kN32_SkColorType, kRGB_565_SkColorType, kARGB_4444_SkColorType, kGray_8_SkColorType
        };

        SkAutoCanvasRestore acr(canvas, true);

        for (auto ctype : ctypes) {
            SkBitmap bm;
            orig.copyTo(&bm, ctype);
            drawLevels(canvas, bm);
            canvas->translate(orig.width()/2 + 8.0f, 0);
        }
    }

    void onDraw(SkCanvas* canvas) override {
        canvas->translate(4, 4);
        for (const auto& bm : fBM) {
            this->drawSet(canvas, bm);
            // round so we always produce an integral translate, so the GOLD tool won't show
            // unimportant diffs if this is drawn on a GPU with different rounding rules
            // since we draw the bitmaps using nearest-neighbor
            canvas->translate(0, SkScalarRoundToScalar(bm.height() * 0.85f));
        }
    }

private:
    typedef skiagm::GM INHERITED;
};
DEF_GM( return new ShowMipLevels2(255, 255); )
DEF_GM( return new ShowMipLevels2(256, 255); )
DEF_GM( return new ShowMipLevels2(255, 256); )
DEF_GM( return new ShowMipLevels2(256, 256); )
<|endoftext|>


<commit_before>
#include <togo/core/error/assert.hpp>
#include <togo/core/utility/utility.hpp>
#include <togo/core/log/log.hpp>
#include <togo/core/collection/fixed_array.hpp>
#include <togo/core/collection/array.hpp>
#include <togo/core/string/string.hpp>
#include <togo/core/system/system.hpp>
#include <togo/core/random/random.hpp>
#include <togo/core/io/io.hpp>
#include <togo/core/io/memory_stream.hpp>
#include <togo/core/serialization/serializer.hpp>
#include <togo/core/serialization/support.hpp>
#include <togo/core/serialization/binary_serializer.hpp>
#include <togo/core/serialization/fixed_array.hpp>
#include <togo/core/serialization/array.hpp>
#include <togo/core/serialization/string.hpp>

#include <togo/support/test.hpp>

using namespace togo;

signed main() {
	memory_init();

	u64 const seed = system::secs_since_epoch();
	XS128A rng{seed};
	TOGO_LOGF("RNG seed: %ld\n", seed);

	MemoryStream stream{memory::default_allocator(), 2048};
	BinaryOutputSerializer oser{stream};
	BinaryInputSerializer iser{stream};

	// Arithmetic
	{
		u64 const basis = random::next(rng);
		oser % basis;
		io::seek_to(stream, 0);

		u64 value = 0;
		iser % value;
		TOGO_ASSERTE(value == basis);
	}
	stream.clear();

	// SerBuffer
	{
		u64 const basis = random::next(rng);
		oser % make_ser_buffer(&basis, sizeof(u64));
		io::seek_to(stream, 0);

		u64 value = 0;
		iser % make_ser_buffer(&value, sizeof(u64));
		TOGO_ASSERTE(value == basis);
	}
	stream.clear();

	// Proxy
	{
		IntUDist<u32> udist{0, static_cast<u32>(~0)};
		u64 const basis = random::next_udist(rng, udist);
		oser % make_ser_proxy<u32>(basis);
		io::seek_to(stream, 0);

		u64 value = 0;
		iser % make_ser_proxy<u32>(value);
		TOGO_ASSERTE(value == basis);
	}
	stream.clear();

	// Enum (implicit proxy)
	{
		enum class E : u32 {
			I = 0,
			V = 0xCF9ABE2E,
		};
		E const basis = E::V;
		oser % basis;
		io::seek_to(stream, 0);

		E value = E::I;
		iser % value;
		TOGO_ASSERTE(value == basis);
	}
	stream.clear();

	// FixedArray
	{
		enum : unsigned { SIZE = 128 };
		FixedArray<u64, SIZE> basis{};
		fixed_array::resize(basis, SIZE);
		for (auto& value : basis) {
			value = random::next(rng);
		}
		oser % make_ser_collection<u8>(basis);
		io::seek_to(stream, 0);

		FixedArray<u64, SIZE> value{};
		iser % make_ser_collection<u8>(value);
		TOGO_ASSERTE(fixed_array::size(value) == SIZE);

		for (unsigned i = 0; i < SIZE; ++i) {
			TOGO_ASSERTE(value[i] == basis[i]);
		}
	}
	stream.clear();

	// Array
	{
		enum : unsigned { SIZE = 128 };
		Array<u64> basis{memory::default_allocator()};
		array::resize(basis, SIZE);
		for (auto& value : basis) {
			value = random::next(rng);
		}
		oser % make_ser_collection<u32>(basis);
		io::seek_to(stream, 0);

		Array<u64> value{memory::default_allocator()};
		iser % make_ser_collection<u32>(value);
		TOGO_ASSERTE(array::size(value) == SIZE);
		for (unsigned i = 0; i < SIZE; ++i) {
			TOGO_ASSERTE(value[i] == basis[i]);
		}
	}
	stream.clear();

	// String (FixedArray<char, N>)
	{
		static constexpr char const BASIS[]{"value"};
		FixedArray<char, array_extent(BASIS)> basis{};
		string::copy(basis, BASIS);
		oser % make_ser_string<u32>(basis);
		io::seek_to(stream, 0);

		decltype(basis) value{};
		iser % make_ser_string<u32>(value);
		TOGO_ASSERTE(string::compare_equal(value, basis));
	}
	stream.clear();

	// String (char[N])
	{
		char basis[]{"value"};
		oser % make_ser_string<u32>(basis);
		io::seek_to(stream, 0);

		decltype(basis) value{};
		iser % make_ser_string<u32>(value);

		// NB: non-C-string StringRefs here OK due to
		// capacity == size of the strings
		TOGO_ASSERTE(string::compare_equal(value, basis));
	}
	stream.clear();

	return 0;
}
<commit_msg>lib/core/test/serialization/general: use foreign endian.<commit_after>
#include <togo/core/error/assert.hpp>
#include <togo/core/utility/utility.hpp>
#include <togo/core/log/log.hpp>
#include <togo/core/collection/fixed_array.hpp>
#include <togo/core/collection/array.hpp>
#include <togo/core/string/string.hpp>
#include <togo/core/system/system.hpp>
#include <togo/core/random/random.hpp>
#include <togo/core/io/io.hpp>
#include <togo/core/io/memory_stream.hpp>
#include <togo/core/serialization/serializer.hpp>
#include <togo/core/serialization/support.hpp>
#include <togo/core/serialization/binary_serializer.hpp>
#include <togo/core/serialization/fixed_array.hpp>
#include <togo/core/serialization/array.hpp>
#include <togo/core/serialization/string.hpp>

#include <togo/support/test.hpp>

using namespace togo;

signed main() {
	memory_init();

	u64 const seed = system::secs_since_epoch();
	XS128A rng{seed};
	TOGO_LOGF("RNG seed: %ld\n", seed);

	MemoryStream stream{memory::default_allocator(), 2048};

	auto const endian_foreign = Endian::system == Endian::little
		? Endian::big
		: Endian::little
	;
	BinaryOutputSerializer oser{stream, endian_foreign};
	BinaryInputSerializer iser{stream, endian_foreign};

	// Arithmetic
	{
		u64 const basis = random::next(rng);
		oser % basis;
		io::seek_to(stream, 0);

		u64 value = 0;
		iser % value;
		TOGO_ASSERTE(value == basis);
	}
	stream.clear();

	// SerBuffer
	{
		u64 const basis = random::next(rng);
		oser % make_ser_buffer(&basis, sizeof(u64));
		io::seek_to(stream, 0);

		u64 value = 0;
		iser % make_ser_buffer(&value, sizeof(u64));
		TOGO_ASSERTE(value == basis);
	}
	stream.clear();

	// Proxy
	{
		IntUDist<u32> udist{0, static_cast<u32>(~0)};
		u64 const basis = random::next_udist(rng, udist);
		oser % make_ser_proxy<u32>(basis);
		io::seek_to(stream, 0);

		u64 value = 0;
		iser % make_ser_proxy<u32>(value);
		TOGO_ASSERTE(value == basis);
	}
	stream.clear();

	// Enum (implicit proxy)
	{
		enum class E : u32 {
			I = 0,
			V = 0xCF9ABE2E,
		};
		E const basis = E::V;
		oser % basis;
		io::seek_to(stream, 0);

		E value = E::I;
		iser % value;
		TOGO_ASSERTE(value == basis);
	}
	stream.clear();

	// FixedArray
	{
		enum : unsigned { SIZE = 128 };
		FixedArray<u64, SIZE> basis{};
		fixed_array::resize(basis, SIZE);
		for (auto& value : basis) {
			value = random::next(rng);
		}
		oser % make_ser_collection<u8>(basis);
		io::seek_to(stream, 0);

		FixedArray<u64, SIZE> value{};
		iser % make_ser_collection<u8>(value);
		TOGO_ASSERTE(fixed_array::size(value) == SIZE);

		for (unsigned i = 0; i < SIZE; ++i) {
			TOGO_ASSERTE(value[i] == basis[i]);
		}
	}
	stream.clear();

	// Array
	{
		enum : unsigned { SIZE = 128 };
		Array<u64> basis{memory::default_allocator()};
		array::resize(basis, SIZE);
		for (auto& value : basis) {
			value = random::next(rng);
		}
		oser % make_ser_collection<u32>(basis);
		io::seek_to(stream, 0);

		Array<u64> value{memory::default_allocator()};
		iser % make_ser_collection<u32>(value);
		TOGO_ASSERTE(array::size(value) == SIZE);
		for (unsigned i = 0; i < SIZE; ++i) {
			TOGO_ASSERTE(value[i] == basis[i]);
		}
	}
	stream.clear();

	// String (FixedArray<char, N>)
	{
		static constexpr char const BASIS[]{"value"};
		FixedArray<char, array_extent(BASIS)> basis{};
		string::copy(basis, BASIS);
		oser % make_ser_string<u32>(basis);
		io::seek_to(stream, 0);

		decltype(basis) value{};
		iser % make_ser_string<u32>(value);
		TOGO_ASSERTE(string::compare_equal(value, basis));
	}
	stream.clear();

	// String (char[N])
	{
		char basis[]{"value"};
		oser % make_ser_string<u32>(basis);
		io::seek_to(stream, 0);

		decltype(basis) value{};
		iser % make_ser_string<u32>(value);

		// NB: non-C-string StringRefs here OK due to
		// capacity == size of the strings
		TOGO_ASSERTE(string::compare_equal(value, basis));
	}
	stream.clear();

	return 0;
}
<|endoftext|>


<commit_before>// Chapter 20, Exercise 18: define a range-checked iterator for vector (a
// random-access iterator)

// Adapting vector implementation "vectr" from Chapter 19, exercise 8 and 9

#include "../lib_files/std_lib_facilities.h"

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

template<class T> class allocatr {
public:
    // allocate space for n objects of type T
    T* allocate(int n);

    // deallocate n objects of type T starting at p
    void deallocate(T* p) { free(p); }

    // construct a T with the value v in p
    void construct(T* p, const T& v) { new(p) T(v); }

    // destroy the T in p
    void destroy(T* p) { p->~T(); }
};

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

// allocate space for n objects of type T
template<class T> T* allocatr<T>::allocate(int n)
{
    T* p = static_cast<T*>(malloc(n*sizeof(T)));
    if (p==0) error("allocate: could not allocate memory");
    return p;
}

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

template<class T, class A = allocatr<T> > class vectr {
    A alloc;    // used to handle memory for elements
    int sz;     // the size
    T* elem;    // a pointer to the elements
    int space;  // space + free space
public:
    typedef unsigned long size_type;
    typedef T value_type;
    typedef T* iterator;
    typedef const T* const_iterator;
    class iterator_rc;

    vectr() : sz(0), elem(0), space(0) { }
    explicit vectr(size_type s);

    vectr(const vectr&);                        // copy constructor
    vectr& operator=(const vectr&);             // copy assignment

    ~vectr();                                   // destructor

    T& operator[](size_type n) { return elem[n]; }    // access; return reference
    const T& operator[](size_type n) const { return elem[n]; }

    T& at(size_type n);
    const T& at(size_type n) const;                   // checked access

    iterator begin() { return elem; }
    iterator end() { return elem+sz; }

    size_type size() const { return sz; }             // the current size
    size_type capacity() const { return space; }

    void resize(size_type newsize, T val = T());      // growth
    void push_back(const T& d);
    void reserve(size_type newalloc);

};

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

template<class T, class A>
class vectr<T,A>::iterator_rc {
    iterator curr;
    iterator first;
    iterator last;
public:
    iterator_rc(iterator c , iterator f, iterator l)
        : curr(c), first(f), last(l) { }

    T& operator*() { return *curr; }
    const T& operator*() const { return *curr; }

    iterator_rc& operator++();
    iterator_rc& operator--();
    iterator_rc& operator+=(size_type n);
    friend iterator_rc operator+(iterator_rc it, size_type n)
        { it += n; return it; }
    iterator_rc& operator-=(size_type n);
    friend iterator_rc operator-(iterator_rc it, size_type n)
        { it -= n; return it; }
    friend size_type operator-(const iterator_rc& it1, const iterator_rc& it2)
        { return (it1.curr - it2.curr); }

    bool operator ==(iterator_rc const& other) const { return curr==other.curr; }
    bool operator !=(iterator_rc const& other) const { return !(*this==other); }
};

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

template<class T, class A>
typename vectr<T,A>::iterator_rc& vectr<T,A>::iterator_rc::operator++()
{
    if (curr==last-1) throw Range_error(last-first);
    ++curr;
    return *this;
}

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

template<class T, class A>
typename vectr<T,A>::iterator_rc& vectr<T,A>::iterator_rc::operator--()
{
    if (curr==first) throw Range_error(-1);
    --curr;
    return *this;
}

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

template<class T, class A>
typename vectr<T,A>::iterator_rc& vectr<T,A>::iterator_rc::operator+=(size_type n)
{
    if (n >= (last-curr)) throw Range_error(curr+n-first);
    curr += n;
    return *this;
}

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

template<class T, class A>
typename vectr<T,A>::iterator_rc& vectr<T,A>::iterator_rc::operator-=(size_type n)
{
    if (n > curr-first) throw Range_error(curr-n-first);
    curr -= n;
}

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

template<class T, class A> vectr<T,A>::vectr(size_type s)
    : sz(s), elem(alloc.allocate(s)), space(s)
{
    for (int i = 0; i<sz; ++i)
        alloc.construct(&elem[i],T());
}

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

template<class T, class A> vectr<T,A>::vectr(const vectr& a)
    : sz(a.sz), elem(alloc.allocate(a.sz)), space(a.sz)
{
    for (int i = 0; i<sz; ++i)
        alloc.construct(&elem[i],a.elem[i]);
}

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

template<class T, class A>
vectr<T,A>& vectr<T,A>::operator=(const vectr<T,A>& a)
{
    if (this==&a) return *this; // self-assignment, no work needed

    if (a.sz<=space) {          // enough space, no need for new allocation
        for (int i = 0; i<a.sz; ++i)
            alloc.construct(&elem[i],a.elem[i]);
        sz = a.sz;
        return *this;
    }

    T* p = alloc.allocate(a.sz);            // allocate new space
    for (int i = 0; i<a.sz; ++i)            // copy elements
        alloc.construct(&p[i],a.elem[i]);
    for (int i = 0; i<sz; ++i)              // destroy old objects
        alloc.destroy(&elem[i]);
    alloc.deallocate(elem);                 // deallocate old space
    space = sz = a.sz;                      // set new size
    elem = p;                               // set new elements
    return *this;
}

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

template<class T, class A> vectr<T,A>::~vectr()
{
    for (int i = 0; i<sz; ++i)
        alloc.destroy(&elem[i]);
    alloc.deallocate(elem);
}

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

template<class T, class A> T& vectr<T,A>::at(size_type n)
{
    if (n<0 || sz<=n) throw Range_error(n);
    return elem[n];
}

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

template<class T, class A> void vectr<T,A>::resize(size_type newsize, T val)
{
    reserve(newsize);
    for (int i = sz; i<newsize; ++i)    // construct
        alloc.construct(&elem[i],val);
    for (int i = newsize; i<sz; ++i)    // destroy
        alloc.destroy(&elem[i]);
    sz = newsize;
}

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

template<class T, class A> void vectr<T,A>::push_back(const T& val)
{
    if (space==0) reserve(8);               // start with space for 8 elements
    else if (sz==space) reserve(2*space);   // get more space
    alloc.construct(&elem[sz],val);         // add val at end
    ++sz;                                   // increase the size
}

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

template<class T, class A> void vectr<T,A>::reserve(size_type newalloc)
{
    if (newalloc<=space) return;        // never decrease allocation
    T* p = alloc.allocate(newalloc);    // allocate new space
    for (int i = 0; i<sz; ++i)          // copy
        alloc.construct(&p[i],elem[i]);
    for (int i = 0; i<sz; ++i)          // destroy
        alloc.destroy(&elem[i]);
    alloc.deallocate(elem);             // deallocate old space
    elem = p;
    space = newalloc;
}

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

int main()
try {
    vectr<int> vi;
    for (int i = 0; i<5; ++i)
        vi.push_back(i);

    cout << "Size of vector: " << vi.size() << "\n";

    for (int i = 0; i<vi.size(); ++i)
        cout << vi[i] << ' ';
    cout << "\n";

    vectr<int>::iterator_rc it(vi.begin(),vi.begin(),vi.end());
    cout << *it << "\n";
    ++it;
    cout << *it << "\n";
    --it;
    cout << *it << "\n";
//    --it;   // throws error
    it += 4;
    cout << *it << "\n";
//    ++it;   // throws error
//    it += 1;    // throws error
//    it = it + 1;    // throws error
//    it -= 5;    // throws error
//    it = it - 5;    // throws error
    vectr<int>::iterator_rc it2(vi.begin(),vi.begin(),vi.end());
    int dist = it - it2;
    cout << "Distance to begin(): " << dist << "\n";
    cout << "it==it2 is " << (it==it2 ? "true" : "false") << "\n";
    cout << "it!=it2 is " << (it!=it2 ? "true" : "false") << "\n";
    it -= 4;
    cout << "it==it2 is " << (it==it2 ? "true" : "false") << "\n";
    cout << "it!=it2 is " << (it!=it2 ? "true" : "false") << "\n";

}
catch (Range_error& re) {
    cerr << "bad index: " << re.index << "\n";
}
catch (exception& e) {
    cerr << "exception: " << e.what() << endl;
}
catch (...) {
    cerr << "exception\n";
}

//------------------------------------------------------------------------------
<commit_msg>Add missing return statement [#9]<commit_after>// Chapter 20, Exercise 18: define a range-checked iterator for vector (a
// random-access iterator)

// Adapting vector implementation "vectr" from Chapter 19, exercise 8 and 9

#include "../lib_files/std_lib_facilities.h"

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

template<class T> class allocatr {
public:
    // allocate space for n objects of type T
    T* allocate(int n);

    // deallocate n objects of type T starting at p
    void deallocate(T* p) { free(p); }

    // construct a T with the value v in p
    void construct(T* p, const T& v) { new(p) T(v); }

    // destroy the T in p
    void destroy(T* p) { p->~T(); }
};

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

// allocate space for n objects of type T
template<class T> T* allocatr<T>::allocate(int n)
{
    T* p = static_cast<T*>(malloc(n*sizeof(T)));
    if (p==0) error("allocate: could not allocate memory");
    return p;
}

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

template<class T, class A = allocatr<T> > class vectr {
    A alloc;    // used to handle memory for elements
    int sz;     // the size
    T* elem;    // a pointer to the elements
    int space;  // space + free space
public:
    typedef unsigned long size_type;
    typedef T value_type;
    typedef T* iterator;
    typedef const T* const_iterator;
    class iterator_rc;

    vectr() : sz(0), elem(0), space(0) { }
    explicit vectr(size_type s);

    vectr(const vectr&);                        // copy constructor
    vectr& operator=(const vectr&);             // copy assignment

    ~vectr();                                   // destructor

    T& operator[](size_type n) { return elem[n]; }    // access; return reference
    const T& operator[](size_type n) const { return elem[n]; }

    T& at(size_type n);
    const T& at(size_type n) const;                   // checked access

    iterator begin() { return elem; }
    iterator end() { return elem+sz; }

    size_type size() const { return sz; }             // the current size
    size_type capacity() const { return space; }

    void resize(size_type newsize, T val = T());      // growth
    void push_back(const T& d);
    void reserve(size_type newalloc);

};

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

template<class T, class A>
class vectr<T,A>::iterator_rc {
    iterator curr;
    iterator first;
    iterator last;
public:
    iterator_rc(iterator c , iterator f, iterator l)
        : curr(c), first(f), last(l) { }

    T& operator*() { return *curr; }
    const T& operator*() const { return *curr; }

    iterator_rc& operator++();
    iterator_rc& operator--();
    iterator_rc& operator+=(size_type n);
    friend iterator_rc operator+(iterator_rc it, size_type n)
        { it += n; return it; }
    iterator_rc& operator-=(size_type n);
    friend iterator_rc operator-(iterator_rc it, size_type n)
        { it -= n; return it; }
    friend size_type operator-(const iterator_rc& it1, const iterator_rc& it2)
        { return (it1.curr - it2.curr); }

    bool operator ==(iterator_rc const& other) const { return curr==other.curr; }
    bool operator !=(iterator_rc const& other) const { return !(*this==other); }
};

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

template<class T, class A>
typename vectr<T,A>::iterator_rc& vectr<T,A>::iterator_rc::operator++()
{
    if (curr==last-1) throw Range_error(last-first);
    ++curr;
    return *this;
}

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

template<class T, class A>
typename vectr<T,A>::iterator_rc& vectr<T,A>::iterator_rc::operator--()
{
    if (curr==first) throw Range_error(-1);
    --curr;
    return *this;
}

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

template<class T, class A>
typename vectr<T,A>::iterator_rc& vectr<T,A>::iterator_rc::operator+=(size_type n)
{
    if (n >= (last-curr)) throw Range_error(curr+n-first);
    curr += n;
    return *this;
}

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

template<class T, class A>
typename vectr<T,A>::iterator_rc& vectr<T,A>::iterator_rc::operator-=(size_type n)
{
    if (n > curr-first) throw Range_error(curr-n-first);
    curr -= n;
    return *this;
}

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

template<class T, class A> vectr<T,A>::vectr(size_type s)
    : sz(s), elem(alloc.allocate(s)), space(s)
{
    for (int i = 0; i<sz; ++i)
        alloc.construct(&elem[i],T());
}

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

template<class T, class A> vectr<T,A>::vectr(const vectr& a)
    : sz(a.sz), elem(alloc.allocate(a.sz)), space(a.sz)
{
    for (int i = 0; i<sz; ++i)
        alloc.construct(&elem[i],a.elem[i]);
}

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

template<class T, class A>
vectr<T,A>& vectr<T,A>::operator=(const vectr<T,A>& a)
{
    if (this==&a) return *this; // self-assignment, no work needed

    if (a.sz<=space) {          // enough space, no need for new allocation
        for (int i = 0; i<a.sz; ++i)
            alloc.construct(&elem[i],a.elem[i]);
        sz = a.sz;
        return *this;
    }

    T* p = alloc.allocate(a.sz);            // allocate new space
    for (int i = 0; i<a.sz; ++i)            // copy elements
        alloc.construct(&p[i],a.elem[i]);
    for (int i = 0; i<sz; ++i)              // destroy old objects
        alloc.destroy(&elem[i]);
    alloc.deallocate(elem);                 // deallocate old space
    space = sz = a.sz;                      // set new size
    elem = p;                               // set new elements
    return *this;
}

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

template<class T, class A> vectr<T,A>::~vectr()
{
    for (int i = 0; i<sz; ++i)
        alloc.destroy(&elem[i]);
    alloc.deallocate(elem);
}

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

template<class T, class A> T& vectr<T,A>::at(size_type n)
{
    if (n<0 || sz<=n) throw Range_error(n);
    return elem[n];
}

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

template<class T, class A> void vectr<T,A>::resize(size_type newsize, T val)
{
    reserve(newsize);
    for (int i = sz; i<newsize; ++i)    // construct
        alloc.construct(&elem[i],val);
    for (int i = newsize; i<sz; ++i)    // destroy
        alloc.destroy(&elem[i]);
    sz = newsize;
}

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

template<class T, class A> void vectr<T,A>::push_back(const T& val)
{
    if (space==0) reserve(8);               // start with space for 8 elements
    else if (sz==space) reserve(2*space);   // get more space
    alloc.construct(&elem[sz],val);         // add val at end
    ++sz;                                   // increase the size
}

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

template<class T, class A> void vectr<T,A>::reserve(size_type newalloc)
{
    if (newalloc<=space) return;        // never decrease allocation
    T* p = alloc.allocate(newalloc);    // allocate new space
    for (int i = 0; i<sz; ++i)          // copy
        alloc.construct(&p[i],elem[i]);
    for (int i = 0; i<sz; ++i)          // destroy
        alloc.destroy(&elem[i]);
    alloc.deallocate(elem);             // deallocate old space
    elem = p;
    space = newalloc;
}

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

int main()
try {
    vectr<int> vi;
    for (int i = 0; i<5; ++i)
        vi.push_back(i);

    cout << "Size of vector: " << vi.size() << "\n";

    for (int i = 0; i<vi.size(); ++i)
        cout << vi[i] << ' ';
    cout << "\n";

    vectr<int>::iterator_rc it(vi.begin(),vi.begin(),vi.end());
    cout << *it << "\n";
    ++it;
    cout << *it << "\n";
    --it;
    cout << *it << "\n";
//    --it;   // throws error
    it += 4;
    cout << *it << "\n";
//    ++it;   // throws error
//    it += 1;    // throws error
//    it = it + 1;    // throws error
//    it -= 5;    // throws error
//    it = it - 5;    // throws error
    vectr<int>::iterator_rc it2(vi.begin(),vi.begin(),vi.end());
    int dist = it - it2;
    cout << "Distance to begin(): " << dist << "\n";
    cout << "it==it2 is " << (it==it2 ? "true" : "false") << "\n";
    cout << "it!=it2 is " << (it!=it2 ? "true" : "false") << "\n";
    it -= 4;
    cout << "it==it2 is " << (it==it2 ? "true" : "false") << "\n";
    cout << "it!=it2 is " << (it!=it2 ? "true" : "false") << "\n";

}
catch (Range_error& re) {
    cerr << "bad index: " << re.index << "\n";
}
catch (exception& e) {
    cerr << "exception: " << e.what() << endl;
}
catch (...) {
    cerr << "exception\n";
}

//------------------------------------------------------------------------------
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: macros.hxx,v $
 *
 *  $Revision: 1.1.1.1 $
 *
 *  last change: $Author: bm $ $Date: 2003-10-06 09:58:29 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  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., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2002 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/
#ifndef CHART_MACROS_HXX
#define CHART_MACROS_HXX

/// creates a unicode-string from an ASCII string
#define C2U(constAsciiStr) (::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( constAsciiStr ) ))

/// shows an error-box for an exception ex
#define ASSERT_EXCEPTION(ex) \
  OSL_ENSURE( false, ::rtl::OUStringToOString( \
    ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Exception caught: " )) + \
    ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr());

#define U2C(ouString) (::rtl::OUStringToOString(ouString,RTL_TEXTENCODING_ASCII_US).getStr())

// CHART_MACROS_HXX
#endif
<commit_msg>INTEGRATION: CWS ooo19126 (1.1.1.1.110); FILE MERGED 2005/09/05 18:42:55 rt 1.1.1.1.110.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: macros.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 00:47:36 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef CHART_MACROS_HXX
#define CHART_MACROS_HXX

/// creates a unicode-string from an ASCII string
#define C2U(constAsciiStr) (::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( constAsciiStr ) ))

/// shows an error-box for an exception ex
#define ASSERT_EXCEPTION(ex) \
  OSL_ENSURE( false, ::rtl::OUStringToOString( \
    ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Exception caught: " )) + \
    ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr());

#define U2C(ouString) (::rtl::OUStringToOString(ouString,RTL_TEXTENCODING_ASCII_US).getStr())

// CHART_MACROS_HXX
#endif
<|endoftext|>