<commit_before>#include <bureaucracy/timer.hpp>

#include <algorithm>
#include <cassert>

using bureaucracy::Timer;

Timer::Timer()
  : my_nextFuture{my_futureEvents.end()}
  , my_nextId{0}
  , my_isAccepting{true}
  , my_isRunning{true}
  , my_isFiring{false}
{
    my_timerThread = std::thread{[this]() {
        std::unique_lock<std::mutex> lock{my_mutex};

        while(my_isAccepting)
        {
            if(my_futureEvents.empty())
            {
                my_wakeup.wait(lock);
            }
            else
            {
                auto const now = std::chrono::steady_clock::now();
                auto begin = std::begin(my_futureEvents);
                auto const end = std::end(my_futureEvents);
                auto last = std::find_if(begin, end, [now](auto const & event) {
                    return now < event.due;
                });
                if(begin != last)
                {
                    my_isFiring = true;
                    my_nextFuture = last;
                    lock.unlock();
                    std::for_each(begin, last, [this](auto & futureEvent) {
                        auto it = my_events.find(futureEvent.event);
                        assert(it != my_events.end());
                        it->second();
                    });
                    lock.lock();
                    my_isFiring = false;
                    my_futureEvents.erase(begin, last);
                    my_nextFuture = my_futureEvents.begin();
                    std::for_each(
                        std::begin(my_pendingEvents),
                        std::end(my_pendingEvents), [this](auto & event) {
                            auto it = std::find_if(
                                std::begin(my_futureEvents),
                                std::end(my_futureEvents),
                                [&event](auto const & futureEvent) {
                                    return event.due < futureEvent.due;
                                });
                            my_futureEvents.emplace(
                                it, FutureEvent{event.event, event.due});
                            my_events.emplace(event.event, std::move(event.fn));
                        });
                    my_pendingEvents.erase(std::begin(my_pendingEvents),
                                           std::end(my_pendingEvents));
                }
                else
                {
                    auto alarm = (*begin).due;
                    my_wakeup.wait_until(lock, alarm);
                }
            }
        }
    }};
}

/// \cond false
Timer::~Timer() noexcept
{
    stop();
}
/// \endcond

Timer::Item Timer::add(Event event, Time due)
{
    std::lock_guard<std::mutex> lock{my_mutex};

    if(my_isAccepting)
    {
        auto id = [this]() {
            auto ret = my_nextId;
            auto it = my_events.find(ret);
            while(it != my_events.end())
            {
                ++ret;
                it = my_events.find(ret);
            }
            my_nextId = ret + 1;
            return ret;
        }();

        if(my_isFiring)
        {
            my_pendingEvents.emplace_back(
                PendingEvent{id, due, std::move(event)});
        }
        else
        {
            auto it = std::find_if(std::begin(my_futureEvents),
                                   std::end(my_futureEvents),
                                   [due](auto const & currentEvent) {
                                       return due < currentEvent.due;
                                   });
            my_futureEvents.emplace(it, FutureEvent{id, due});
            my_events.emplace(id, std::move(event));
            my_nextFuture = std::begin(my_futureEvents);
            my_wakeup.notify_one();
        }
        return Item{this, id};
    }
    else
    {
        throw std::runtime_error{"Not accepting"};
    }
}

void Timer::stop()
{
    std::unique_lock<std::mutex> lock{my_mutex};

    if(my_isAccepting)
    {
        my_isAccepting = false;
        my_wakeup.notify_one();
        lock.unlock();
        my_timerThread.join();
        lock.lock();
        my_isRunning = false;
    }
}

bool Timer::isAccepting() const noexcept
{
    std::lock_guard<std::mutex> lock{my_mutex};
    return my_isAccepting;
}

bool Timer::isRunning() const noexcept
{
    std::lock_guard<std::mutex> lock{my_mutex};
    return my_isRunning;
}

Timer::Item::CancelStatus Timer::cancel(Timer::Item item)
{
    std::lock_guard<std::mutex> lock{my_mutex};

    // If we're firing, check the pending events since they haven't been merged
    // in yet.
    if(my_isFiring)
    {
        auto const pendingEnd = std::end(my_pendingEvents);
        auto const pendingIt = std::find_if(
            std::begin(my_pendingEvents),
            pendingEnd, [id = item.my_id](auto const & pendingEvent) {
                return pendingEvent.event == id;
            });
        if(pendingIt != pendingEnd)
        {
            my_pendingEvents.erase(pendingIt);
            return Timer::Item::CancelStatus::cancelled;
        }
    }

    // We need to the check the future events whether we're firing or not.
    auto const end = std::end(my_futureEvents);
    auto futureIt = std::find_if(
        my_nextFuture, end, [id = item.my_id](auto const & futureEvent) {
            return futureEvent.event == id;
        });
    if(futureIt != end)
    {
        my_futureEvents.erase(futureIt);
        my_events.erase(item.my_id);
        return Timer::Item::CancelStatus::cancelled;
    }

    // At this point, we didn't find the item in either queue.  It's either an
    // invalid id or queued to fire.
    return Timer::Item::CancelStatus::failed;
}

Timer::Timer::Item::Item(Timer * const timer, Id id)
  : my_timer{timer}
  , my_id{id}
{
}
<commit_msg>Fix issue raised by clang-tidy<commit_after>#include <bureaucracy/timer.hpp>

#include <algorithm>
#include <cassert>

using bureaucracy::Timer;

Timer::Timer()
  : my_nextFuture{my_futureEvents.end()}
  , my_nextId{0}
  , my_isAccepting{true}
  , my_isRunning{true}
  , my_isFiring{false}
{
    my_timerThread = std::thread{[this]() {
        std::unique_lock<std::mutex> lock{my_mutex};

        while(my_isAccepting)
        {
            if(my_futureEvents.empty())
            {
                my_wakeup.wait(lock);
            }
            else
            {
                auto const now = std::chrono::steady_clock::now();
                auto begin = std::begin(my_futureEvents);
                auto const end = std::end(my_futureEvents);
                auto last = std::find_if(begin, end, [now](auto const & event) {
                    return now < event.due;
                });
                if(begin != last)
                {
                    my_isFiring = true;
                    my_nextFuture = last;
                    lock.unlock();
                    std::for_each(begin, last, [this](auto & futureEvent) {
                        auto it = my_events.find(futureEvent.event);
                        assert(it != my_events.end());
                        it->second();
                    });
                    lock.lock();
                    my_isFiring = false;
                    my_futureEvents.erase(begin, last);
                    my_nextFuture = my_futureEvents.begin();
                    std::for_each(
                        std::begin(my_pendingEvents),
                        std::end(my_pendingEvents), [this](auto & event) {
                            auto it = std::find_if(
                                std::begin(my_futureEvents),
                                std::end(my_futureEvents),
                                [&event](auto const & futureEvent) {
                                    return event.due < futureEvent.due;
                                });
                            my_futureEvents.emplace(
                                it, FutureEvent{event.event, event.due});
                            my_events.emplace(event.event, std::move(event.fn));
                        });
                    my_pendingEvents.erase(std::begin(my_pendingEvents),
                                           std::end(my_pendingEvents));
                }
                else
                {
                    auto alarm = (*begin).due;
                    my_wakeup.wait_until(lock, alarm);
                }
            }
        }
    }};
}

/// \cond false
Timer::~Timer() noexcept
{
    stop();
}
/// \endcond

Timer::Item Timer::add(Event event, Time due)
{
    std::lock_guard<std::mutex> lock{my_mutex};

    if(my_isAccepting)
    {
        auto id = [this]() {
            auto ret = my_nextId;
            auto it = my_events.find(ret);
            while(it != my_events.end())
            {
                ++ret;
                it = my_events.find(ret);
            }
            my_nextId = ret + 1;
            return ret;
        }();

        if(my_isFiring)
        {
            my_pendingEvents.emplace_back(
                PendingEvent{id, due, std::move(event)});
        }
        else
        {
            auto it = std::find_if(std::begin(my_futureEvents),
                                   std::end(my_futureEvents),
                                   [due](auto const & currentEvent) {
                                       return due < currentEvent.due;
                                   });
            my_futureEvents.emplace(it, FutureEvent{id, due});
            my_events.emplace(id, std::move(event));
            my_nextFuture = std::begin(my_futureEvents);
            my_wakeup.notify_one();
        }
        return Item{this, id};
    }
    throw std::runtime_error{"Not accepting"};
}

void Timer::stop()
{
    std::unique_lock<std::mutex> lock{my_mutex};

    if(my_isAccepting)
    {
        my_isAccepting = false;
        my_wakeup.notify_one();
        lock.unlock();
        my_timerThread.join();
        lock.lock();
        my_isRunning = false;
    }
}

bool Timer::isAccepting() const noexcept
{
    std::lock_guard<std::mutex> lock{my_mutex};
    return my_isAccepting;
}

bool Timer::isRunning() const noexcept
{
    std::lock_guard<std::mutex> lock{my_mutex};
    return my_isRunning;
}

Timer::Item::CancelStatus Timer::cancel(Timer::Item item)
{
    std::lock_guard<std::mutex> lock{my_mutex};

    // If we're firing, check the pending events since they haven't been merged
    // in yet.
    if(my_isFiring)
    {
        auto const pendingEnd = std::end(my_pendingEvents);
        auto const pendingIt = std::find_if(
            std::begin(my_pendingEvents),
            pendingEnd, [id = item.my_id](auto const & pendingEvent) {
                return pendingEvent.event == id;
            });
        if(pendingIt != pendingEnd)
        {
            my_pendingEvents.erase(pendingIt);
            return Timer::Item::CancelStatus::cancelled;
        }
    }

    // We need to the check the future events whether we're firing or not.
    auto const end = std::end(my_futureEvents);
    auto futureIt = std::find_if(
        my_nextFuture, end, [id = item.my_id](auto const & futureEvent) {
            return futureEvent.event == id;
        });
    if(futureIt != end)
    {
        my_futureEvents.erase(futureIt);
        my_events.erase(item.my_id);
        return Timer::Item::CancelStatus::cancelled;
    }

    // At this point, we didn't find the item in either queue.  It's either an
    // invalid id or queued to fire.
    return Timer::Item::CancelStatus::failed;
}

Timer::Timer::Item::Item(Timer * const timer, Id id)
  : my_timer{timer}
  , my_id{id}
{
}
<|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 "SkGradientShader.h"

namespace skiagm {

struct GradData {
    int             fCount;
    const SkColor*  fColors;
    const SkScalar* fPos;
};

static const SkColor gColors[] = {
    SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
};
static const SkScalar gPos0[] = { 0, SK_Scalar1 };
static const SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
static const SkScalar gPos2[] = {
    0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1
};

static const GradData gGradData[] = {
    { 2, gColors, NULL },
    { 2, gColors, gPos0 },
    { 2, gColors, gPos1 },
    { 5, gColors, NULL },
    { 5, gColors, gPos2 }
};

static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
                            SkShader::TileMode tm, SkUnitMapper* mapper) {
    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
                                          data.fCount, tm, mapper);
}

static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
                            SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center;
    center.set(SkScalarAve(pts[0].fX, pts[1].fX),
               SkScalarAve(pts[0].fY, pts[1].fY));
    return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
                                          data.fPos, data.fCount, tm, mapper);
}

static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
                           SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center;
    center.set(SkScalarAve(pts[0].fX, pts[1].fX),
               SkScalarAve(pts[0].fY, pts[1].fY));
    return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
                                         data.fPos, data.fCount, mapper);
}

static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
                             SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center0, center1;
    center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
    center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
                SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
    return SkGradientShader::CreateTwoPointRadial(
                                                  center1, (pts[1].fX - pts[0].fX) / 7,
                                                  center0, (pts[1].fX - pts[0].fX) / 2,
                                                  data.fColors, data.fPos, data.fCount, tm, mapper);
}

typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
                               SkShader::TileMode tm, SkUnitMapper* mapper);
static const GradMaker gGradMakers[] = {
    MakeLinear, MakeRadial, MakeSweep, Make2Radial
};

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

class GradientsGM : public GM {
public:
	GradientsGM() {
        this->setBGColor(0xFFDDDDDD);
    }

protected:
    SkString onShortName() {
        return SkString("gradients");
    }

    virtual SkISize onISize() { return make_isize(640, 510); }

    virtual void onDraw(SkCanvas* canvas) {

        SkPoint pts[2] = {
            { 0, 0 },
            { SkIntToScalar(100), SkIntToScalar(100) }
        };
        SkShader::TileMode tm = SkShader::kClamp_TileMode;
        SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
        SkPaint paint;
        paint.setAntiAlias(true);

        canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
        for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
            canvas->save();
            for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); j++) {
                SkShader* shader = gGradMakers[j](pts, gGradData[i], tm, NULL);
                paint.setShader(shader);
                canvas->drawRect(r, paint);
                shader->unref();
                canvas->translate(0, SkIntToScalar(120));
            }
            canvas->restore();
            canvas->translate(SkIntToScalar(120), 0);
        }
    }

private:
    typedef GM INHERITED;
};

/*
 Inspired by this <canvas> javascript, where we need to detect that we are not
 solving a quadratic equation, but must instead solve a linear (since our X^2
 coefficient is 0)

 ctx.fillStyle = '#f00';
 ctx.fillRect(0, 0, 100, 50);

 var g = ctx.createRadialGradient(-80, 25, 70, 0, 25, 150);
 g.addColorStop(0, '#f00');
 g.addColorStop(0.01, '#0f0');
 g.addColorStop(0.99, '#0f0');
 g.addColorStop(1, '#f00');
 ctx.fillStyle = g;
 ctx.fillRect(0, 0, 100, 50);
 */
class GradientsDegenrate2PointGM : public GM {
public:
    GradientsDegenrate2PointGM() {}

protected:
    SkString onShortName() {
        return SkString("gradients_degenerate_2pt");
    }

	virtual SkISize onISize() { return make_isize(320, 320); }

    void drawBG(SkCanvas* canvas) {
        canvas->drawColor(SK_ColorBLUE);
    }

    virtual void onDraw(SkCanvas* canvas) {
        this->drawBG(canvas);

        SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorRED };
        SkScalar pos[] = { 0, SkFloatToScalar(0.01f), SkFloatToScalar(0.99f), SK_Scalar1 };
        SkPoint c0;
        c0.iset(-80, 25);
        SkScalar r0 = SkIntToScalar(70);
        SkPoint c1;
        c1.iset(0, 25);
        SkScalar r1 = SkIntToScalar(150);
        SkShader* s = SkGradientShader::CreateTwoPointRadial(c0, r0, c1, r1, colors,
                                                             pos, SK_ARRAY_COUNT(pos),
                                                             SkShader::kClamp_TileMode);
        SkPaint paint;
        paint.setShader(s)->unref();
        canvas->drawPaint(paint);
    }

private:
    typedef GM INHERITED;
};

/// Tests correctness of *optimized* codepaths in gradients.

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

protected:
    SkString onShortName() { return SkString("clamped_gradients"); }

    virtual SkISize onISize() { return make_isize(640, 510); }

    void drawBG(SkCanvas* canvas) {
        canvas->drawColor(0xFFDDDDDD);
    }

    virtual void onDraw(SkCanvas* canvas) {
        this->drawBG(canvas);

        SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(300) };
        SkPaint paint;
        paint.setAntiAlias(true);

        SkPoint center;
        center.iset(0, 300);
        canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
        SkShader* shader = SkGradientShader::CreateRadial(
            SkPoint(center),
            SkIntToScalar(200), gColors, NULL, 5,
            SkShader::kClamp_TileMode, NULL);
        paint.setShader(shader);
        canvas->drawRect(r, paint);
        shader->unref();
    }

private:
    typedef GM INHERITED;
};

/// Checks quality of large radial gradients, which may display
/// some banding.

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

protected:
    SkString onShortName() { return SkString("radial_gradient"); }
    virtual SkISize onISize() { return make_isize(1280, 1024); }
    void drawBG(SkCanvas* canvas) {
        canvas->drawColor(0xFF000000);
    }
    virtual void onDraw(SkCanvas* canvas) {
        this->drawBG(canvas);

        SkPaint paint;
        paint.setDither(true);
        SkPoint center;
        center.set(SkIntToScalar(640), SkIntToScalar(512));
        SkScalar radius = SkIntToScalar(640);
        SkColor colors [3] = { 0x7f7f7f7f, 0x7f7f7f7f, 0xb2000000 };
        SkScalar pos [3] = { SkFloatToScalar(0.0),
                             SkFloatToScalar(0.35),
                             SkFloatToScalar(1.0) };
        SkShader* shader =
            SkGradientShader::CreateRadial(center, radius, colors,
                                           pos, 3, SkShader::kClamp_TileMode);
        paint.setShader(shader)->unref();
        SkRect r = { 0, 0, SkIntToScalar(1280), SkIntToScalar(1024) };
        canvas->drawRect(r, paint);
    }
private:
    typedef GM INHERITED;
};

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

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

static GM* MyFactory2(void*) { return new GradientsDegenrate2PointGM; }
static GMRegistry reg2(MyFactory2);

static GM* MyFactory3(void*) { return new ClampedGradientsGM; }
static GMRegistry reg3(MyFactory3);

static GM* MyFactory4(void*) { return new RadialGradientGM; }
static GMRegistry reg4(MyFactory4);
}

<commit_msg>increase height to include entire circle for large radial<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 "SkGradientShader.h"

namespace skiagm {

struct GradData {
    int             fCount;
    const SkColor*  fColors;
    const SkScalar* fPos;
};

static const SkColor gColors[] = {
    SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorWHITE, SK_ColorBLACK
};
static const SkScalar gPos0[] = { 0, SK_Scalar1 };
static const SkScalar gPos1[] = { SK_Scalar1/4, SK_Scalar1*3/4 };
static const SkScalar gPos2[] = {
    0, SK_Scalar1/8, SK_Scalar1/2, SK_Scalar1*7/8, SK_Scalar1
};

static const GradData gGradData[] = {
    { 2, gColors, NULL },
    { 2, gColors, gPos0 },
    { 2, gColors, gPos1 },
    { 5, gColors, NULL },
    { 5, gColors, gPos2 }
};

static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
                            SkShader::TileMode tm, SkUnitMapper* mapper) {
    return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
                                          data.fCount, tm, mapper);
}

static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
                            SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center;
    center.set(SkScalarAve(pts[0].fX, pts[1].fX),
               SkScalarAve(pts[0].fY, pts[1].fY));
    return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
                                          data.fPos, data.fCount, tm, mapper);
}

static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
                           SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center;
    center.set(SkScalarAve(pts[0].fX, pts[1].fX),
               SkScalarAve(pts[0].fY, pts[1].fY));
    return SkGradientShader::CreateSweep(center.fX, center.fY, data.fColors,
                                         data.fPos, data.fCount, mapper);
}

static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
                             SkShader::TileMode tm, SkUnitMapper* mapper) {
    SkPoint center0, center1;
    center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
                SkScalarAve(pts[0].fY, pts[1].fY));
    center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
                SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
    return SkGradientShader::CreateTwoPointRadial(
                                                  center1, (pts[1].fX - pts[0].fX) / 7,
                                                  center0, (pts[1].fX - pts[0].fX) / 2,
                                                  data.fColors, data.fPos, data.fCount, tm, mapper);
}

typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
                               SkShader::TileMode tm, SkUnitMapper* mapper);
static const GradMaker gGradMakers[] = {
    MakeLinear, MakeRadial, MakeSweep, Make2Radial
};

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

class GradientsGM : public GM {
public:
	GradientsGM() {
        this->setBGColor(0xFFDDDDDD);
    }

protected:
    SkString onShortName() {
        return SkString("gradients");
    }

    virtual SkISize onISize() { return make_isize(640, 510); }

    virtual void onDraw(SkCanvas* canvas) {

        SkPoint pts[2] = {
            { 0, 0 },
            { SkIntToScalar(100), SkIntToScalar(100) }
        };
        SkShader::TileMode tm = SkShader::kClamp_TileMode;
        SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(100) };
        SkPaint paint;
        paint.setAntiAlias(true);

        canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
        for (size_t i = 0; i < SK_ARRAY_COUNT(gGradData); i++) {
            canvas->save();
            for (size_t j = 0; j < SK_ARRAY_COUNT(gGradMakers); j++) {
                SkShader* shader = gGradMakers[j](pts, gGradData[i], tm, NULL);
                paint.setShader(shader);
                canvas->drawRect(r, paint);
                shader->unref();
                canvas->translate(0, SkIntToScalar(120));
            }
            canvas->restore();
            canvas->translate(SkIntToScalar(120), 0);
        }
    }

private:
    typedef GM INHERITED;
};

/*
 Inspired by this <canvas> javascript, where we need to detect that we are not
 solving a quadratic equation, but must instead solve a linear (since our X^2
 coefficient is 0)

 ctx.fillStyle = '#f00';
 ctx.fillRect(0, 0, 100, 50);

 var g = ctx.createRadialGradient(-80, 25, 70, 0, 25, 150);
 g.addColorStop(0, '#f00');
 g.addColorStop(0.01, '#0f0');
 g.addColorStop(0.99, '#0f0');
 g.addColorStop(1, '#f00');
 ctx.fillStyle = g;
 ctx.fillRect(0, 0, 100, 50);
 */
class GradientsDegenrate2PointGM : public GM {
public:
    GradientsDegenrate2PointGM() {}

protected:
    SkString onShortName() {
        return SkString("gradients_degenerate_2pt");
    }

	virtual SkISize onISize() { return make_isize(320, 320); }

    void drawBG(SkCanvas* canvas) {
        canvas->drawColor(SK_ColorBLUE);
    }

    virtual void onDraw(SkCanvas* canvas) {
        this->drawBG(canvas);

        SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorGREEN, SK_ColorRED };
        SkScalar pos[] = { 0, SkFloatToScalar(0.01f), SkFloatToScalar(0.99f), SK_Scalar1 };
        SkPoint c0;
        c0.iset(-80, 25);
        SkScalar r0 = SkIntToScalar(70);
        SkPoint c1;
        c1.iset(0, 25);
        SkScalar r1 = SkIntToScalar(150);
        SkShader* s = SkGradientShader::CreateTwoPointRadial(c0, r0, c1, r1, colors,
                                                             pos, SK_ARRAY_COUNT(pos),
                                                             SkShader::kClamp_TileMode);
        SkPaint paint;
        paint.setShader(s)->unref();
        canvas->drawPaint(paint);
    }

private:
    typedef GM INHERITED;
};

/// Tests correctness of *optimized* codepaths in gradients.

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

protected:
    SkString onShortName() { return SkString("clamped_gradients"); }

    virtual SkISize onISize() { return make_isize(640, 510); }

    void drawBG(SkCanvas* canvas) {
        canvas->drawColor(0xFFDDDDDD);
    }

    virtual void onDraw(SkCanvas* canvas) {
        this->drawBG(canvas);

        SkRect r = { 0, 0, SkIntToScalar(100), SkIntToScalar(300) };
        SkPaint paint;
        paint.setAntiAlias(true);

        SkPoint center;
        center.iset(0, 300);
        canvas->translate(SkIntToScalar(20), SkIntToScalar(20));
        SkShader* shader = SkGradientShader::CreateRadial(
            SkPoint(center),
            SkIntToScalar(200), gColors, NULL, 5,
            SkShader::kClamp_TileMode, NULL);
        paint.setShader(shader);
        canvas->drawRect(r, paint);
        shader->unref();
    }

private:
    typedef GM INHERITED;
};

/// Checks quality of large radial gradients, which may display
/// some banding.

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

protected:
    SkString onShortName() { return SkString("radial_gradient"); }
    virtual SkISize onISize() { return make_isize(1280, 1280); }
    void drawBG(SkCanvas* canvas) {
        canvas->drawColor(0xFF000000);
    }
    virtual void onDraw(SkCanvas* canvas) {
        const SkISize dim = this->getISize();

        this->drawBG(canvas);

        SkPaint paint;
        paint.setDither(true);
        SkPoint center;
        center.set(SkIntToScalar(dim.width())/2, SkIntToScalar(dim.height())/2);
        SkScalar radius = SkIntToScalar(dim.width())/2;
        const SkColor colors[] = { 0x7f7f7f7f, 0x7f7f7f7f, 0xb2000000 };
        const SkScalar pos[] = { SkFloatToScalar(0.0),
                             SkFloatToScalar(0.35),
                             SkFloatToScalar(1.0) };
        SkShader* shader =
            SkGradientShader::CreateRadial(center, radius, colors,
                                           pos, SK_ARRAY_COUNT(pos),
                                           SkShader::kClamp_TileMode);
        paint.setShader(shader)->unref();
        SkRect r = {
            0, 0, SkIntToScalar(dim.width()), SkIntToScalar(dim.height())
        };
        canvas->drawRect(r, paint);
    }
private:
    typedef GM INHERITED;
};

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

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

static GM* MyFactory2(void*) { return new GradientsDegenrate2PointGM; }
static GMRegistry reg2(MyFactory2);

static GM* MyFactory3(void*) { return new ClampedGradientsGM; }
static GMRegistry reg3(MyFactory3);

static GM* MyFactory4(void*) { return new RadialGradientGM; }
static GMRegistry reg4(MyFactory4);
}

<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// *       Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// *       Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// *       Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////

//-----------------------------------------------------------------------------
//
//	class Semaphore -- implementation for Windows
//
//-----------------------------------------------------------------------------

#include "IlmThreadSemaphore.h"
#include "Iex.h"
#include <string>
#include <assert.h>
#include <iostream>

namespace IlmThread {

using namespace Iex;

namespace {

std::string
errorString ()
{
    LPSTR messageBuffer;
    DWORD bufferLength;
    std::string message;

    //
    // Call FormatMessage() to allow for message
    // text to be acquired from the system.
    //

    if (bufferLength = FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
				       FORMAT_MESSAGE_IGNORE_INSERTS |
				       FORMAT_MESSAGE_FROM_SYSTEM,
				       0,
				       GetLastError (),
				       MAKELANGID (LANG_NEUTRAL,
						   SUBLANG_DEFAULT),
				       (LPSTR) &messageBuffer,
				       0,
				       NULL))
    {
	message = messageBuffer;
        LocalFree (messageBuffer);
    }

    return message;
}

} // namespace

Semaphore::Semaphore (unsigned int value)
{
    if ((_semaphore = ::CreateSemaphore (0, value, 0x7fffffff, 0)) == 0)
    {
	THROW (LogicExc, "Could not create semaphore "
			 "(" << errorString() << ").");
    }
}

Semaphore::~Semaphore()
{
    bool ok = ::CloseHandle (_semaphore);
    assert (ok);
}

void
Semaphore::wait()
{
    if (::WaitForSingleObject (_semaphore, INFINITE) != WAIT_OBJECT_0)
    {
	THROW (LogicExc, "Could not wait on semaphore "
			 "(" << errorString() << ").");
    }
}

void
Semaphore::tryWait()
{
    return ::WaitForSingleObject (_semaphore, 0) == WAIT_OBJECT_0;
}

void
Semaphore::post()
{
    if (!::ReleaseSemaphore (_semaphore, 1, 0))
    {
	THROW (LogicExc, "Could not post on semaphore "
			 "(" << errorString() << ").");
    }
}

int
Semaphore::value() const
{
    LONG v = -1;

    if (!::ReleaseSemaphore (_semaphore, 0, &v) || v < 0)
    {
	THROW (LogicExc, "Could not get value of semaphore "
			 "(" << errorString () << ").");
    }

    return v;
}

} // namespace IlmThread
<commit_msg>Wrong return type for method tryWait().<commit_after>///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2005, Industrial Light & Magic, a division of Lucas
// Digital Ltd. LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// *       Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// *       Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// *       Neither the name of Industrial Light & Magic nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////

//-----------------------------------------------------------------------------
//
//	class Semaphore -- implementation for Windows
//
//-----------------------------------------------------------------------------

#include "IlmThreadSemaphore.h"
#include "Iex.h"
#include <string>
#include <assert.h>
#include <iostream>

namespace IlmThread {

using namespace Iex;

namespace {

std::string
errorString ()
{
    LPSTR messageBuffer;
    DWORD bufferLength;
    std::string message;

    //
    // Call FormatMessage() to allow for message
    // text to be acquired from the system.
    //

    if (bufferLength = FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
				       FORMAT_MESSAGE_IGNORE_INSERTS |
				       FORMAT_MESSAGE_FROM_SYSTEM,
				       0,
				       GetLastError (),
				       MAKELANGID (LANG_NEUTRAL,
						   SUBLANG_DEFAULT),
				       (LPSTR) &messageBuffer,
				       0,
				       NULL))
    {
	message = messageBuffer;
        LocalFree (messageBuffer);
    }

    return message;
}

} // namespace

Semaphore::Semaphore (unsigned int value)
{
    if ((_semaphore = ::CreateSemaphore (0, value, 0x7fffffff, 0)) == 0)
    {
	THROW (LogicExc, "Could not create semaphore "
			 "(" << errorString() << ").");
    }
}

Semaphore::~Semaphore()
{
    bool ok = ::CloseHandle (_semaphore);
    assert (ok);
}

void
Semaphore::wait()
{
    if (::WaitForSingleObject (_semaphore, INFINITE) != WAIT_OBJECT_0)
    {
	THROW (LogicExc, "Could not wait on semaphore "
			 "(" << errorString() << ").");
    }
}

bool
Semaphore::tryWait()
{
    return ::WaitForSingleObject (_semaphore, 0) == WAIT_OBJECT_0;
}

void
Semaphore::post()
{
    if (!::ReleaseSemaphore (_semaphore, 1, 0))
    {
	THROW (LogicExc, "Could not post on semaphore "
			 "(" << errorString() << ").");
    }
}

int
Semaphore::value() const
{
    LONG v = -1;

    if (!::ReleaseSemaphore (_semaphore, 0, &v) || v < 0)
    {
	THROW (LogicExc, "Could not get value of semaphore "
			 "(" << errorString () << ").");
    }

    return v;
}

} // namespace IlmThread
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/audio_processing/high_pass_filter_impl.h"

#include <assert.h>

#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
#include "webrtc/modules/audio_processing/audio_buffer.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/typedefs.h"

namespace webrtc {
namespace {
const int16_t kFilterCoefficients8kHz[5] =
    {3798, -7596, 3798, 7807, -3733};

const int16_t kFilterCoefficients[5] =
    {4012, -8024, 4012, 8002, -3913};

struct FilterState {
  int16_t y[4];
  int16_t x[2];
  const int16_t* ba;
};

int InitializeFilter(FilterState* hpf, int sample_rate_hz) {
  assert(hpf != NULL);

  if (sample_rate_hz == AudioProcessing::kSampleRate8kHz) {
    hpf->ba = kFilterCoefficients8kHz;
  } else {
    hpf->ba = kFilterCoefficients;
  }

  WebRtcSpl_MemSetW16(hpf->x, 0, 2);
  WebRtcSpl_MemSetW16(hpf->y, 0, 4);

  return AudioProcessing::kNoError;
}

int Filter(FilterState* hpf, int16_t* data, int length) {
  assert(hpf != NULL);

  int32_t tmp_int32 = 0;
  int16_t* y = hpf->y;
  int16_t* x = hpf->x;
  const int16_t* ba = hpf->ba;

  for (int i = 0; i < length; i++) {
    //  y[i] = b[0] * x[i] + b[1] * x[i-1] + b[2] * x[i-2]
    //         + -a[1] * y[i-1] + -a[2] * y[i-2];

    tmp_int32 =
        WEBRTC_SPL_MUL_16_16(y[1], ba[3]); // -a[1] * y[i-1] (low part)
    tmp_int32 +=
        WEBRTC_SPL_MUL_16_16(y[3], ba[4]); // -a[2] * y[i-2] (low part)
    tmp_int32 = (tmp_int32 >> 15);
    tmp_int32 +=
        WEBRTC_SPL_MUL_16_16(y[0], ba[3]); // -a[1] * y[i-1] (high part)
    tmp_int32 +=
        WEBRTC_SPL_MUL_16_16(y[2], ba[4]); // -a[2] * y[i-2] (high part)
    tmp_int32 = (tmp_int32 << 1);

    tmp_int32 += WEBRTC_SPL_MUL_16_16(data[i], ba[0]); // b[0]*x[0]
    tmp_int32 += WEBRTC_SPL_MUL_16_16(x[0], ba[1]);    // b[1]*x[i-1]
    tmp_int32 += WEBRTC_SPL_MUL_16_16(x[1], ba[2]);    // b[2]*x[i-2]

    // Update state (input part)
    x[1] = x[0];
    x[0] = data[i];

    // Update state (filtered part)
    y[2] = y[0];
    y[3] = y[1];
    y[0] = static_cast<int16_t>(tmp_int32 >> 13);
    y[1] = static_cast<int16_t>(
        (tmp_int32 - (static_cast<int32_t>(y[0]) << 13)) << 2);

    // Rounding in Q12, i.e. add 2^11
    tmp_int32 += 2048;

    // Saturate (to 2^27) so that the HP filtered signal does not overflow
    tmp_int32 = WEBRTC_SPL_SAT(static_cast<int32_t>(134217727),
                               tmp_int32,
                               static_cast<int32_t>(-134217728));

    // Convert back to Q0 and use rounding.
    data[i] = (int16_t)(tmp_int32 >> 12);
  }

  return AudioProcessing::kNoError;
}
}  // namespace

typedef FilterState Handle;

HighPassFilterImpl::HighPassFilterImpl(const AudioProcessing* apm,
                                       CriticalSectionWrapper* crit)
  : ProcessingComponent(),
    apm_(apm),
    crit_(crit) {}

HighPassFilterImpl::~HighPassFilterImpl() {}

int HighPassFilterImpl::ProcessCaptureAudio(AudioBuffer* audio) {
  int err = apm_->kNoError;

  if (!is_component_enabled()) {
    return apm_->kNoError;
  }

  assert(audio->samples_per_split_channel() <= 160);

  for (int i = 0; i < num_handles(); i++) {
    Handle* my_handle = static_cast<Handle*>(handle(i));
    err = Filter(my_handle,
                 audio->split_bands(i)[kBand0To8kHz],
                 audio->samples_per_split_channel());

    if (err != apm_->kNoError) {
      return GetHandleError(my_handle);
    }
  }

  return apm_->kNoError;
}

int HighPassFilterImpl::Enable(bool enable) {
  CriticalSectionScoped crit_scoped(crit_);
  return EnableComponent(enable);
}

bool HighPassFilterImpl::is_enabled() const {
  return is_component_enabled();
}

void* HighPassFilterImpl::CreateHandle() const {
  return new FilterState;
}

void HighPassFilterImpl::DestroyHandle(void* handle) const {
  delete static_cast<Handle*>(handle);
}

int HighPassFilterImpl::InitializeHandle(void* handle) const {
  return InitializeFilter(static_cast<Handle*>(handle),
                          apm_->proc_sample_rate_hz());
}

int HighPassFilterImpl::ConfigureHandle(void* /*handle*/) const {
  return apm_->kNoError; // Not configurable.
}

int HighPassFilterImpl::num_handles_required() const {
  return apm_->num_output_channels();
}

int HighPassFilterImpl::GetHandleError(void* handle) const {
  // The component has no detailed errors.
  assert(handle != NULL);
  return apm_->kUnspecifiedError;
}
}  // namespace webrtc
<commit_msg>audio_processing: Replaced macro WEBRTC_SPL_MUL_16_16 with * in high_pass_filter<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/audio_processing/high_pass_filter_impl.h"

#include <assert.h>

#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
#include "webrtc/modules/audio_processing/audio_buffer.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/typedefs.h"

namespace webrtc {
namespace {
const int16_t kFilterCoefficients8kHz[5] =
    {3798, -7596, 3798, 7807, -3733};

const int16_t kFilterCoefficients[5] =
    {4012, -8024, 4012, 8002, -3913};

struct FilterState {
  int16_t y[4];
  int16_t x[2];
  const int16_t* ba;
};

int InitializeFilter(FilterState* hpf, int sample_rate_hz) {
  assert(hpf != NULL);

  if (sample_rate_hz == AudioProcessing::kSampleRate8kHz) {
    hpf->ba = kFilterCoefficients8kHz;
  } else {
    hpf->ba = kFilterCoefficients;
  }

  WebRtcSpl_MemSetW16(hpf->x, 0, 2);
  WebRtcSpl_MemSetW16(hpf->y, 0, 4);

  return AudioProcessing::kNoError;
}

int Filter(FilterState* hpf, int16_t* data, int length) {
  assert(hpf != NULL);

  int32_t tmp_int32 = 0;
  int16_t* y = hpf->y;
  int16_t* x = hpf->x;
  const int16_t* ba = hpf->ba;

  for (int i = 0; i < length; i++) {
    //  y[i] = b[0] * x[i] + b[1] * x[i-1] + b[2] * x[i-2]
    //         + -a[1] * y[i-1] + -a[2] * y[i-2];

    tmp_int32 = y[1] * ba[3];  // -a[1] * y[i-1] (low part)
    tmp_int32 += y[3] * ba[4];  // -a[2] * y[i-2] (low part)
    tmp_int32 = (tmp_int32 >> 15);
    tmp_int32 += y[0] * ba[3];  // -a[1] * y[i-1] (high part)
    tmp_int32 += y[2] * ba[4];  // -a[2] * y[i-2] (high part)
    tmp_int32 = (tmp_int32 << 1);

    tmp_int32 += data[i] * ba[0];  // b[0]*x[0]
    tmp_int32 += x[0] * ba[1];  // b[1]*x[i-1]
    tmp_int32 += x[1] * ba[2];  // b[2]*x[i-2]

    // Update state (input part)
    x[1] = x[0];
    x[0] = data[i];

    // Update state (filtered part)
    y[2] = y[0];
    y[3] = y[1];
    y[0] = static_cast<int16_t>(tmp_int32 >> 13);
    y[1] = static_cast<int16_t>(
        (tmp_int32 - (static_cast<int32_t>(y[0]) << 13)) << 2);

    // Rounding in Q12, i.e. add 2^11
    tmp_int32 += 2048;

    // Saturate (to 2^27) so that the HP filtered signal does not overflow
    tmp_int32 = WEBRTC_SPL_SAT(static_cast<int32_t>(134217727),
                               tmp_int32,
                               static_cast<int32_t>(-134217728));

    // Convert back to Q0 and use rounding.
    data[i] = (int16_t)(tmp_int32 >> 12);
  }

  return AudioProcessing::kNoError;
}
}  // namespace

typedef FilterState Handle;

HighPassFilterImpl::HighPassFilterImpl(const AudioProcessing* apm,
                                       CriticalSectionWrapper* crit)
  : ProcessingComponent(),
    apm_(apm),
    crit_(crit) {}

HighPassFilterImpl::~HighPassFilterImpl() {}

int HighPassFilterImpl::ProcessCaptureAudio(AudioBuffer* audio) {
  int err = apm_->kNoError;

  if (!is_component_enabled()) {
    return apm_->kNoError;
  }

  assert(audio->samples_per_split_channel() <= 160);

  for (int i = 0; i < num_handles(); i++) {
    Handle* my_handle = static_cast<Handle*>(handle(i));
    err = Filter(my_handle,
                 audio->split_bands(i)[kBand0To8kHz],
                 audio->samples_per_split_channel());

    if (err != apm_->kNoError) {
      return GetHandleError(my_handle);
    }
  }

  return apm_->kNoError;
}

int HighPassFilterImpl::Enable(bool enable) {
  CriticalSectionScoped crit_scoped(crit_);
  return EnableComponent(enable);
}

bool HighPassFilterImpl::is_enabled() const {
  return is_component_enabled();
}

void* HighPassFilterImpl::CreateHandle() const {
  return new FilterState;
}

void HighPassFilterImpl::DestroyHandle(void* handle) const {
  delete static_cast<Handle*>(handle);
}

int HighPassFilterImpl::InitializeHandle(void* handle) const {
  return InitializeFilter(static_cast<Handle*>(handle),
                          apm_->proc_sample_rate_hz());
}

int HighPassFilterImpl::ConfigureHandle(void* /*handle*/) const {
  return apm_->kNoError; // Not configurable.
}

int HighPassFilterImpl::num_handles_required() const {
  return apm_->num_output_channels();
}

int HighPassFilterImpl::GetHandleError(void* handle) const {
  // The component has no detailed errors.
  assert(handle != NULL);
  return apm_->kUnspecifiedError;
}
}  // namespace webrtc
<|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- *
 *                       OpenSim:  testIterators.cpp                        *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2014-2014 Stanford University and the Authors                *
 * Author(s): Ayman Habib                                                     *
 * Contributer(s) :                                                           *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0.         *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 * -------------------------------------------------------------------------- */
#include <iostream>
#include <OpenSim/Simulation/Model/Model.h>
#include <OpenSim/Common/LoadOpenSimLibrary.h>
#include <OpenSim/Auxiliary/auxiliaryTestFunctions.h>

using namespace OpenSim;
using namespace std;

// Example filter that allows for iterating only through Components that have
// state variables, used for demonstration purposes.
class ComponentWithStateVariables : public ComponentFilter {
public:
    ComponentWithStateVariables() {
        //std::cout << "ComponentWithStateVariables constructed" << std::endl;
    };
    bool isMatch(const Component& comp) const override {
        return (comp.getNumStateVariables()>0);
    };
    ~ComponentWithStateVariables() {
        //std::cout << "ComponentWithStateVariables destructed" << std::endl;
    }
    ComponentWithStateVariables* clone() const {
        return new ComponentWithStateVariables(*this);
    }
};
int main()
{
    try {
        LoadOpenSimLibrary("osimActuators");

        std::string filename = "arm26.osim";

        Model model(filename);
        model.initSystem();
        ComponentList<Component> componentsList = model.getComponentList();
        std::cout << "list begin: " << componentsList.begin()->getName() << std::endl;
        int numComponents = 0;
        for (ComponentList<Component>::const_iterator it = componentsList.begin();
            it != componentsList.end();
            ++it) {
                std::cout << "Iterator is at: " << it->getConcreteClassName() << " " << it->getName() << std::endl;
                numComponents++;
        }

        ComponentList<OpenSim::Body> bodiesList = model.getComponentList<OpenSim::Body>();
        int numBodies = 0;
        std::cout << "Bodies list begin: " << bodiesList.begin()->getName() << std::endl;
        for (ComponentList<OpenSim::Body>::const_iterator it = bodiesList.begin();
        it != bodiesList.end();
        ++it) {
            std::cout << "Iterator is at Body: " << it->getName() << std::endl;
            numBodies++;
        }

        std::cout << "Bodies list begin: " << bodiesList.begin()->getName() << std::endl;
        int numBodiesPost = 0;
        for (ComponentList<OpenSim::Body>::const_iterator itPost = bodiesList.begin();
            itPost != bodiesList.end();
            itPost++) {
            std::cout << "Iterator is at Body: " << itPost->getName() << std::endl;
            numBodiesPost++;
        }

        int numMuscles = 0;
        std::cout << "Using range-for loop over Muscles: " << std::endl;
        ComponentList<Muscle> musclesList = model.getComponentList<Muscle>();
        for (const Muscle& muscle : musclesList) {
            std::cout << "Iterator is at muscle: " << muscle.getName() << std::endl;
            numMuscles++;
        }

        int numGeomPaths = 0;
        ComponentList<GeometryPath> geomPathList = model.getComponentList<GeometryPath>();
        for (const GeometryPath& gpath : geomPathList) {
            numGeomPaths++;
        }
        const OpenSim::Joint& shoulderJnt = model.getJointSet().get(0);
        // cycle thru components under shoulderJnt should return the Joint itself and the Coordinate
        int numJntComponents = 0;
        ComponentList<Component> jComponentsList = shoulderJnt.getComponentList();
        std::cout << "Components/subComponents under Shoulder Joint:" << std::endl;
        for (ComponentList<Component>::const_iterator it = jComponentsList.begin();
            it != jComponentsList.end();
            ++it) {
            std::cout << "Iterator is at: " << it->getConcreteClassName() << " " << it->getName() << std::endl;
            numJntComponents++;
        }
        cout << "Num all components = " << numComponents << std::endl;
        cout << "Num bodies = " << numBodies << std::endl;
        cout << "Num Muscles = " << numMuscles << std::endl;
        cout << "Num GeometryPath components = " << numGeomPaths << std::endl;
        // Components = Model+3Body+3Marker+2(Joint+Coordinate)+6(Muscle+GeometryPath)
        // Should test against 1+#Bodies+#Markers+#Joints+#Constraints+#Coordinates+#Forces+#ForcesWithPath+..
        // Would that account for internal (split-bodies etc.?)
        int numComponentsWithStateVariables = 0;
        ComponentList<ModelComponent> compWithStates = model.getComponentList<ModelComponent>();
        ComponentWithStateVariables* myFilter = new ComponentWithStateVariables();
        compWithStates.setFilter(myFilter); // Filter is cloned and can be deleted safely
        delete myFilter;
        for (const ModelComponent& comp : compWithStates) {
            cout << comp.getConcreteClassName() << ":" << comp.getName() << endl;
            numComponentsWithStateVariables++;
        }
        //Now test a std::iterator method
        ComponentList<ModelComponent> comps = model.getComponentList<ModelComponent>();
        ComponentList<ModelComponent>::const_iterator skipIter = comps.begin();
        int countSkipComponent = 0;
        while (skipIter != comps.end()){
            cout << skipIter->getConcreteClassName() << ":" << skipIter->getName() << endl;
            std::advance(skipIter, 2);
            countSkipComponent++;
        }

        ASSERT(numComponents == 23);
        ASSERT(numBodies == model.getNumBodies());
        ASSERT(numBodiesPost == numBodies);
        ASSERT(numMuscles == model.getMuscles().getSize());
        ASSERT(numComponentsWithStateVariables == 11);
        ASSERT(numJntComponents == 2);
        ASSERT(countSkipComponent == 12);
    }
    catch (Exception &ex) {
        ex.print(std::cout);
        return 1;
    }
    cout << "Done" << endl;
    return 0;
}
<commit_msg>Clarifying text in test case.<commit_after>/* -------------------------------------------------------------------------- *
 *                       OpenSim:  testIterators.cpp                        *
 * -------------------------------------------------------------------------- *
 * The OpenSim API is a toolkit for musculoskeletal modeling and simulation.  *
 * See http://opensim.stanford.edu and the NOTICE file for more information.  *
 * OpenSim is developed at Stanford University and supported by the US        *
 * National Institutes of Health (U54 GM072970, R24 HD065690) and by DARPA    *
 * through the Warrior Web program.                                           *
 *                                                                            *
 * Copyright (c) 2014-2014 Stanford University and the Authors                *
 * Author(s): Ayman Habib                                                     *
 * Contributer(s) :                                                           *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0.         *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 * -------------------------------------------------------------------------- */
#include <iostream>
#include <OpenSim/Simulation/Model/Model.h>
#include <OpenSim/Common/LoadOpenSimLibrary.h>
#include <OpenSim/Auxiliary/auxiliaryTestFunctions.h>

using namespace OpenSim;
using namespace std;

// Example filter that allows for iterating only through Components that have
// state variables, used for demonstration purposes.
class ComponentWithStateVariables : public ComponentFilter {
public:
    ComponentWithStateVariables() {
        //std::cout << "ComponentWithStateVariables constructed" << std::endl;
    };
    bool isMatch(const Component& comp) const override {
        return (comp.getNumStateVariables()>0);
    };
    ~ComponentWithStateVariables() {
        //std::cout << "ComponentWithStateVariables destructed" << std::endl;
    }
    ComponentWithStateVariables* clone() const {
        return new ComponentWithStateVariables(*this);
    }
};
int main()
{
    try {
        LoadOpenSimLibrary("osimActuators");

        std::string filename = "arm26.osim";

        Model model(filename);
        model.initSystem();
        ComponentList<Component> componentsList = model.getComponentList();
        std::cout << "list begin: " << componentsList.begin()->getName() << std::endl;
        int numComponents = 0;
        for (ComponentList<Component>::const_iterator it = componentsList.begin();
            it != componentsList.end();
            ++it) {
                std::cout << "Iterator is at: " << it->getConcreteClassName() << " " << it->getName() << std::endl;
                numComponents++;
        }

        ComponentList<OpenSim::Body> bodiesList = model.getComponentList<OpenSim::Body>();
        int numBodies = 0;
        std::cout << "Bodies list begin: " << bodiesList.begin()->getName() << std::endl;
        for (ComponentList<OpenSim::Body>::const_iterator it = bodiesList.begin();
        it != bodiesList.end();
        ++it) {
            std::cout << "Iterator is at Body: " << it->getName() << std::endl;
            numBodies++;
        }
        // Now we try the post increment variant of the iterator
        std::cout << "Bodies list begin, using post increment: " << bodiesList.begin()->getName() << std::endl;
        int numBodiesPost = 0;
        for (ComponentList<OpenSim::Body>::const_iterator itPost = bodiesList.begin();
            itPost != bodiesList.end();
            itPost++) {
            std::cout << "Iterator is at Body: " << itPost->getName() << std::endl;
            numBodiesPost++;
        }

        int numMuscles = 0;
        std::cout << "Using range-for loop over Muscles: " << std::endl;
        ComponentList<Muscle> musclesList = model.getComponentList<Muscle>();
        for (const Muscle& muscle : musclesList) {
            std::cout << "Iterator is at muscle: " << muscle.getName() << std::endl;
            numMuscles++;
        }

        int numGeomPaths = 0;
        ComponentList<GeometryPath> geomPathList = model.getComponentList<GeometryPath>();
        for (const GeometryPath& gpath : geomPathList) {
            numGeomPaths++;
        }
        const OpenSim::Joint& shoulderJnt = model.getJointSet().get(0);
        // cycle thru components under shoulderJnt should return the Joint itself and the Coordinate
        int numJntComponents = 0;
        ComponentList<Component> jComponentsList = shoulderJnt.getComponentList();
        std::cout << "Components/subComponents under Shoulder Joint:" << std::endl;
        for (ComponentList<Component>::const_iterator it = jComponentsList.begin();
            it != jComponentsList.end();
            ++it) {
            std::cout << "Iterator is at: " << it->getConcreteClassName() << " " << it->getName() << std::endl;
            numJntComponents++;
        }
        cout << "Num all components = " << numComponents << std::endl;
        cout << "Num bodies = " << numBodies << std::endl;
        cout << "Num Muscles = " << numMuscles << std::endl;
        cout << "Num GeometryPath components = " << numGeomPaths << std::endl;
        // Components = Model+3Body+3Marker+2(Joint+Coordinate)+6(Muscle+GeometryPath)
        // Should test against 1+#Bodies+#Markers+#Joints+#Constraints+#Coordinates+#Forces+#ForcesWithPath+..
        // Would that account for internal (split-bodies etc.?)
        int numComponentsWithStateVariables = 0;
        ComponentList<ModelComponent> compWithStates = model.getComponentList<ModelComponent>();
        ComponentWithStateVariables* myFilter = new ComponentWithStateVariables();
        compWithStates.setFilter(myFilter); // Filter is cloned and can be deleted safely
        delete myFilter;
        for (const ModelComponent& comp : compWithStates) {
            cout << comp.getConcreteClassName() << ":" << comp.getName() << endl;
            numComponentsWithStateVariables++;
        }
        //Now test a std::iterator method
        ComponentList<ModelComponent> comps = model.getComponentList<ModelComponent>();
        ComponentList<ModelComponent>::const_iterator skipIter = comps.begin();
        int countSkipComponent = 0;
        while (skipIter != comps.end()){
            cout << skipIter->getConcreteClassName() << ":" << skipIter->getName() << endl;
            std::advance(skipIter, 2);
            countSkipComponent++;
        }

        ASSERT(numComponents == 23);
        ASSERT(numBodies == model.getNumBodies());
        ASSERT(numBodiesPost == numBodies);
        ASSERT(numMuscles == model.getMuscles().getSize());
        ASSERT(numComponentsWithStateVariables == 11);
        ASSERT(numJntComponents == 2);
        ASSERT(countSkipComponent == 12);
    }
    catch (Exception &ex) {
        ex.print(std::cout);
        return 1;
    }
    cout << "Done" << endl;
    return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright © 2010 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/**
 * \file lower_vector.cpp
 * IR lowering pass to remove some types of ir_quadop_vector
 *
 * \author Ian Romanick <ian.d.romanick@intel.com>
 */

#include "ir.h"
#include "ir_rvalue_visitor.h"

class lower_vector_visitor : public ir_rvalue_visitor {
public:
   lower_vector_visitor() : progress(false)
   {
      /* empty */
   }

   void handle_rvalue(ir_rvalue **rvalue);

   /**
    * Should SWZ-like expressions be lowered?
    */
   bool dont_lower_swz;

   bool progress;
};

/**
 * Determine if an IR expression tree looks like an extended swizzle
 *
 * Extended swizzles consist of access of a single vector source (with possible
 * per component negation) and the constants -1, 0, or 1.
 */
bool
is_extended_swizzle(ir_expression *ir)
{
   /* Track any variables that are accessed by this expression.
    */
   ir_variable *var = NULL;

   assert(ir->operation == ir_quadop_vector);

   for (unsigned i = 0; i < ir->type->vector_elements; i++) {
      ir_rvalue *op = ir->operands[i];

      while (op != NULL) {
	 switch (op->ir_type) {
	 case ir_type_constant: {
	    const ir_constant *const c = op->as_constant();

	    if (!c->is_one() && !c->is_zero() && !c->is_negative_one())
	       return false;

	    op = NULL;
	    break;
	 }

	 case ir_type_dereference_variable: {
	    ir_dereference_variable *const d = (ir_dereference_variable *) op;

	    if ((var != NULL) && (var != d->var))
	       return false;

	    var = d->var;
	    op = NULL;
	    break;
	 }

	 case ir_type_expression: {
	    ir_expression *const ex = (ir_expression *) op;

	    if (ex->operation != ir_unop_neg)
	       return false;

	    op = ex->operands[0];
	    break;
	 }

	 case ir_type_swizzle:
	    op = ((ir_swizzle *) op)->val;
	    break;

	 default:
	    return false;
	 }
      }
   }

   return true;
}

void
lower_vector_visitor::handle_rvalue(ir_rvalue **rvalue)
{
   if (!*rvalue)
      return;

   ir_expression *expr = (*rvalue)->as_expression();
   if ((expr == NULL) || (expr->operation != ir_quadop_vector))
      return;

   if (this->dont_lower_swz && is_extended_swizzle(expr))
      return;

   /* FINISHME: Is this the right thing to use for the talloc context?
    */
   void *const mem_ctx = expr;

   assert(expr->type->vector_elements == expr->get_num_operands());

   /* Generate a temporary with the same type as the ir_quadop_operation.
    */
   ir_variable *const temp =
      new(mem_ctx) ir_variable(expr->type, "vecop_tmp", ir_var_temporary);

   this->base_ir->insert_before(temp);

   /* Counter of the number of components collected so far.
    */
   unsigned assigned;

   /* Write-mask in the destination that receives counted by 'assigned'.
    */
   unsigned write_mask;

   /* Generate upto four assignments to that variable.  Try to group component
    * assignments together:
    *
    * - All constant components can be assigned at once.
    * - All assigments of components from a single variable with the same
    *   unary operator can be assigned at once.
    */
   ir_constant_data d = { { 0 } };

   assigned = 0;
   write_mask = 0;
   for (unsigned i = 0; i < expr->type->vector_elements; i++) {
      const ir_constant *const c = expr->operands[i]->as_constant();

      if (c == NULL)
	 continue;

      switch (expr->type->base_type) {
      case GLSL_TYPE_UINT:  d.u[assigned] = c->value.u[0]; break;
      case GLSL_TYPE_INT:   d.i[assigned] = c->value.i[0]; break;
      case GLSL_TYPE_FLOAT: d.f[assigned] = c->value.f[0]; break;
      case GLSL_TYPE_BOOL:  d.b[assigned] = c->value.b[0]; break;
      defatul:              assert(!"Should not get here."); break;
      }

      write_mask |= (1U << i);
      assigned++;
   }

   assert((write_mask == 0) == (assigned == 0));

   /* If there were constant values, generate an assignment.
    */
   if (assigned > 0) {
      ir_constant *const c =
	 new(mem_ctx) ir_constant(glsl_type::get_instance(expr->type->base_type,
							  assigned, 0),
				  &d);
      ir_dereference *const lhs = new(mem_ctx) ir_dereference_variable(temp);
      ir_assignment *const assign =
	 new(mem_ctx) ir_assignment(lhs, c, NULL, write_mask);

      this->base_ir->insert_before(assign);
   }

   /* FINISHME: This should try to coalesce assignments.
    */
   for (unsigned i = 0; i < expr->type->vector_elements; i++) {
      if (expr->operands[i]->ir_type == ir_type_constant)
	 continue;

      ir_dereference *const lhs = new(mem_ctx) ir_dereference_variable(temp);
      ir_assignment *const assign =
	 new(mem_ctx) ir_assignment(lhs, expr->operands[i], NULL, (1U << i));

      this->base_ir->insert_before(assign);
      assigned++;
   }

   assert(assigned == expr->type->vector_elements);

   *rvalue = new(mem_ctx) ir_dereference_variable(temp);
   this->progress = true;
}

bool
lower_quadop_vector(exec_list *instructions, bool dont_lower_swz)
{
   lower_vector_visitor v;

   v.dont_lower_swz = dont_lower_swz;
   visit_list_elements(&v, instructions);

   return v.progress;
}
<commit_msg>glsl: Fix type of label 'default' in switch statement.<commit_after>/*
 * Copyright © 2010 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/**
 * \file lower_vector.cpp
 * IR lowering pass to remove some types of ir_quadop_vector
 *
 * \author Ian Romanick <ian.d.romanick@intel.com>
 */

#include "ir.h"
#include "ir_rvalue_visitor.h"

class lower_vector_visitor : public ir_rvalue_visitor {
public:
   lower_vector_visitor() : progress(false)
   {
      /* empty */
   }

   void handle_rvalue(ir_rvalue **rvalue);

   /**
    * Should SWZ-like expressions be lowered?
    */
   bool dont_lower_swz;

   bool progress;
};

/**
 * Determine if an IR expression tree looks like an extended swizzle
 *
 * Extended swizzles consist of access of a single vector source (with possible
 * per component negation) and the constants -1, 0, or 1.
 */
bool
is_extended_swizzle(ir_expression *ir)
{
   /* Track any variables that are accessed by this expression.
    */
   ir_variable *var = NULL;

   assert(ir->operation == ir_quadop_vector);

   for (unsigned i = 0; i < ir->type->vector_elements; i++) {
      ir_rvalue *op = ir->operands[i];

      while (op != NULL) {
	 switch (op->ir_type) {
	 case ir_type_constant: {
	    const ir_constant *const c = op->as_constant();

	    if (!c->is_one() && !c->is_zero() && !c->is_negative_one())
	       return false;

	    op = NULL;
	    break;
	 }

	 case ir_type_dereference_variable: {
	    ir_dereference_variable *const d = (ir_dereference_variable *) op;

	    if ((var != NULL) && (var != d->var))
	       return false;

	    var = d->var;
	    op = NULL;
	    break;
	 }

	 case ir_type_expression: {
	    ir_expression *const ex = (ir_expression *) op;

	    if (ex->operation != ir_unop_neg)
	       return false;

	    op = ex->operands[0];
	    break;
	 }

	 case ir_type_swizzle:
	    op = ((ir_swizzle *) op)->val;
	    break;

	 default:
	    return false;
	 }
      }
   }

   return true;
}

void
lower_vector_visitor::handle_rvalue(ir_rvalue **rvalue)
{
   if (!*rvalue)
      return;

   ir_expression *expr = (*rvalue)->as_expression();
   if ((expr == NULL) || (expr->operation != ir_quadop_vector))
      return;

   if (this->dont_lower_swz && is_extended_swizzle(expr))
      return;

   /* FINISHME: Is this the right thing to use for the talloc context?
    */
   void *const mem_ctx = expr;

   assert(expr->type->vector_elements == expr->get_num_operands());

   /* Generate a temporary with the same type as the ir_quadop_operation.
    */
   ir_variable *const temp =
      new(mem_ctx) ir_variable(expr->type, "vecop_tmp", ir_var_temporary);

   this->base_ir->insert_before(temp);

   /* Counter of the number of components collected so far.
    */
   unsigned assigned;

   /* Write-mask in the destination that receives counted by 'assigned'.
    */
   unsigned write_mask;

   /* Generate upto four assignments to that variable.  Try to group component
    * assignments together:
    *
    * - All constant components can be assigned at once.
    * - All assigments of components from a single variable with the same
    *   unary operator can be assigned at once.
    */
   ir_constant_data d = { { 0 } };

   assigned = 0;
   write_mask = 0;
   for (unsigned i = 0; i < expr->type->vector_elements; i++) {
      const ir_constant *const c = expr->operands[i]->as_constant();

      if (c == NULL)
	 continue;

      switch (expr->type->base_type) {
      case GLSL_TYPE_UINT:  d.u[assigned] = c->value.u[0]; break;
      case GLSL_TYPE_INT:   d.i[assigned] = c->value.i[0]; break;
      case GLSL_TYPE_FLOAT: d.f[assigned] = c->value.f[0]; break;
      case GLSL_TYPE_BOOL:  d.b[assigned] = c->value.b[0]; break;
      default:              assert(!"Should not get here."); break;
      }

      write_mask |= (1U << i);
      assigned++;
   }

   assert((write_mask == 0) == (assigned == 0));

   /* If there were constant values, generate an assignment.
    */
   if (assigned > 0) {
      ir_constant *const c =
	 new(mem_ctx) ir_constant(glsl_type::get_instance(expr->type->base_type,
							  assigned, 0),
				  &d);
      ir_dereference *const lhs = new(mem_ctx) ir_dereference_variable(temp);
      ir_assignment *const assign =
	 new(mem_ctx) ir_assignment(lhs, c, NULL, write_mask);

      this->base_ir->insert_before(assign);
   }

   /* FINISHME: This should try to coalesce assignments.
    */
   for (unsigned i = 0; i < expr->type->vector_elements; i++) {
      if (expr->operands[i]->ir_type == ir_type_constant)
	 continue;

      ir_dereference *const lhs = new(mem_ctx) ir_dereference_variable(temp);
      ir_assignment *const assign =
	 new(mem_ctx) ir_assignment(lhs, expr->operands[i], NULL, (1U << i));

      this->base_ir->insert_before(assign);
      assigned++;
   }

   assert(assigned == expr->type->vector_elements);

   *rvalue = new(mem_ctx) ir_dereference_variable(temp);
   this->progress = true;
}

bool
lower_quadop_vector(exec_list *instructions, bool dont_lower_swz)
{
   lower_vector_visitor v;

   v.dont_lower_swz = dont_lower_swz;
   visit_list_elements(&v, instructions);

   return v.progress;
}
<|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 "SkPaint.h"
#include "SkDashPathEffect.h"

static void drawline(SkCanvas* canvas, int on, int off, const SkPaint& paint,
                     SkScalar finalX = SkIntToScalar(600)) {
    SkPaint p(paint);

    const SkScalar intervals[] = {
        SkIntToScalar(on),
        SkIntToScalar(off),
    };

    p.setPathEffect(new SkDashPathEffect(intervals, 2, 0))->unref();
    canvas->drawLine(0, 0, finalX, 0, p);
}

// earlier bug stopped us from drawing very long single-segment dashes, because
// SkPathMeasure was skipping very small delta-T values (nearlyzero). This is
// now fixes, so this giant dash should appear.
static void show_giant_dash(SkCanvas* canvas) {
    SkPaint paint;

    drawline(canvas, 1, 1, paint, SkIntToScalar(20 * 1000));
}

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

protected:
    SkString onShortName() {
        return SkString("dashing");
    }

    SkISize onISize() { return skiagm::make_isize(640, 300); }

    virtual void onDraw(SkCanvas* canvas) {
        static const struct {
            int fOnInterval;
            int fOffInterval;
        } gData[] = {
            { 1, 1 },
            { 4, 1 },
        };

        SkPaint paint;
        paint.setStyle(SkPaint::kStroke_Style);

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

        for (int width = 0; width <= 2; ++width) {
            for (size_t data = 0; data < SK_ARRAY_COUNT(gData); ++data) {
                for (int aa = 0; aa <= 1; ++aa) {
                    int w = width * width * width;
                    paint.setAntiAlias(SkToBool(aa));
                    paint.setStrokeWidth(SkIntToScalar(w));

                    int scale = w ? w : 1;

                    drawline(canvas, gData[data].fOnInterval * scale,
                             gData[data].fOffInterval * scale,
                             paint);
                    canvas->translate(0, SkIntToScalar(20));
                }
            }
        }

        show_giant_dash(canvas);
    }
};

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

static void make_unit_star(SkPath* path, int n) {
    SkScalar rad = -SK_ScalarPI / 2;
    const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n;

    path->moveTo(0, -SK_Scalar1);
    for (int i = 1; i < n; i++) {
        rad += drad;
        SkScalar cosV, sinV = SkScalarSinCos(rad, &cosV);
        path->lineTo(cosV, sinV);
    }
    path->close();
}

static void make_path_line(SkPath* path, const SkRect& bounds) {
    path->moveTo(bounds.left(), bounds.top());
    path->lineTo(bounds.right(), bounds.bottom());
}

static void make_path_rect(SkPath* path, const SkRect& bounds) {
    path->addRect(bounds);
}

static void make_path_oval(SkPath* path, const SkRect& bounds) {
    path->addOval(bounds);
}

static void make_path_star(SkPath* path, const SkRect& bounds) {
    make_unit_star(path, 5);
    SkMatrix matrix;
    matrix.setRectToRect(path->getBounds(), bounds, SkMatrix::kCenter_ScaleToFit);
    path->transform(matrix);
}

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

protected:
    SkString onShortName() {
        return SkString("dashing2");
    }

    SkISize onISize() { return skiagm::make_isize(640, 480); }

    virtual void onDraw(SkCanvas* canvas) {
        static const int gIntervals[] = {
            3,  // 3 dashes: each count [0] followed by intervals [1..count]
            2,  10, 10,
            4,  20, 5, 5, 5,
            2,  2, 2
        };

        void (*gProc[])(SkPath*, const SkRect&) = {
            make_path_line, make_path_rect, make_path_oval, make_path_star,
        };

        SkPaint paint;
        paint.setAntiAlias(true);
        paint.setStyle(SkPaint::kStroke_Style);
        paint.setStrokeWidth(SkIntToScalar(6));

        SkRect bounds = SkRect::MakeWH(SkIntToScalar(120), SkIntToScalar(120));
        bounds.offset(SkIntToScalar(20), SkIntToScalar(20));
        SkScalar dx = bounds.width() * 4 / 3;
        SkScalar dy = bounds.height() * 4 / 3;

        const int* intervals = &gIntervals[1];
        for (int y = 0; y < gIntervals[0]; ++y) {
            SkScalar vals[SK_ARRAY_COUNT(gIntervals)];  // more than enough
            int count = *intervals++;
            for (int i = 0; i < count; ++i) {
                vals[i] = SkIntToScalar(*intervals++);
            }
            SkScalar phase = vals[0] / 2;
            paint.setPathEffect(new SkDashPathEffect(vals, count, phase))->unref();

            for (size_t x = 0; x < SK_ARRAY_COUNT(gProc); ++x) {
                SkPath path;
                SkRect r = bounds;
                r.offset(x * dx, y * dy);
                gProc[x](&path, r);

                canvas->drawPath(path, paint);
            }
        }
    }
};

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

// Test out the on/off line dashing Chrome if fond of
class Dashing3GM : public skiagm::GM {
public:
    Dashing3GM() {}

protected:
    SkString onShortName() {
        return SkString("dashing3");
    }

    SkISize onISize() { return skiagm::make_isize(640, 480); }

    // Draw a 100x100 block of dashed lines. The horizontal ones are BW
    // while the vertical ones are AA.
    void drawDashedLines(SkCanvas* canvas, SkScalar length, SkScalar phase) {
        SkPaint p;
        p.setColor(SK_ColorBLACK);
        p.setStyle(SkPaint::kStroke_Style);
        p.setStrokeWidth(SK_Scalar1);

        SkScalar intervals[2] = { SK_Scalar1, SK_Scalar1 };

        p.setPathEffect(new SkDashPathEffect(intervals, 2, phase, false));

        SkPoint pts[2];

        for (int y = 0; y < 100; y += 5) {
            pts[0].set(0, SkIntToScalar(y));
            pts[1].set(length, SkIntToScalar(y));

            canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p);
        }

        p.setAntiAlias(true);

        for (int x = 0; x < 100; x += 7) {
            pts[0].set(SkIntToScalar(x), 0);
            pts[1].set(SkIntToScalar(x), length);

            canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p);
        }
    }

    virtual void onDraw(SkCanvas* canvas) {
        // fast path should work on this run
        canvas->save();
            this->drawDashedLines(canvas, 100, SK_Scalar1);
        canvas->restore();

        // non-1 phase should break the fast path
        canvas->save();
            canvas->translate(110, 0);
            this->drawDashedLines(canvas, 100, SK_ScalarHalf);
        canvas->restore();

        // non-integer length should break the fast path
        canvas->save();
            canvas->translate(220, 0);
            this->drawDashedLines(canvas, 99.5, SK_ScalarHalf);
        canvas->restore();

        // rotation should break the fast path
        canvas->save();
            canvas->translate(110+SK_ScalarRoot2Over2*100, 110+SK_ScalarRoot2Over2*100);
            canvas->rotate(45);
            canvas->translate(-50, -50);

            this->drawDashedLines(canvas, 100, SK_Scalar1);
        canvas->restore();

    }

};

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

static skiagm::GM* F0(void*) { return new DashingGM; }
static skiagm::GM* F1(void*) { return new Dashing2GM; }
static skiagm::GM* F2(void*) { return new Dashing3GM; }

static skiagm::GMRegistry gR0(F0);
static skiagm::GMRegistry gR1(F1);
static skiagm::GMRegistry gR2(F2);

<commit_msg>Expand dashing3 GM to include additional dashing cases<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 "SkCanvas.h"
#include "SkPaint.h"
#include "SkDashPathEffect.h"

static void drawline(SkCanvas* canvas, int on, int off, const SkPaint& paint,
                     SkScalar finalX = SkIntToScalar(600)) {
    SkPaint p(paint);

    const SkScalar intervals[] = {
        SkIntToScalar(on),
        SkIntToScalar(off),
    };

    p.setPathEffect(new SkDashPathEffect(intervals, 2, 0))->unref();
    canvas->drawLine(0, 0, finalX, 0, p);
}

// earlier bug stopped us from drawing very long single-segment dashes, because
// SkPathMeasure was skipping very small delta-T values (nearlyzero). This is
// now fixes, so this giant dash should appear.
static void show_giant_dash(SkCanvas* canvas) {
    SkPaint paint;

    drawline(canvas, 1, 1, paint, SkIntToScalar(20 * 1000));
}

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

protected:
    SkString onShortName() {
        return SkString("dashing");
    }

    SkISize onISize() { return skiagm::make_isize(640, 300); }

    virtual void onDraw(SkCanvas* canvas) {
        static const struct {
            int fOnInterval;
            int fOffInterval;
        } gData[] = {
            { 1, 1 },
            { 4, 1 },
        };

        SkPaint paint;
        paint.setStyle(SkPaint::kStroke_Style);

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

        for (int width = 0; width <= 2; ++width) {
            for (size_t data = 0; data < SK_ARRAY_COUNT(gData); ++data) {
                for (int aa = 0; aa <= 1; ++aa) {
                    int w = width * width * width;
                    paint.setAntiAlias(SkToBool(aa));
                    paint.setStrokeWidth(SkIntToScalar(w));

                    int scale = w ? w : 1;

                    drawline(canvas, gData[data].fOnInterval * scale,
                             gData[data].fOffInterval * scale,
                             paint);
                    canvas->translate(0, SkIntToScalar(20));
                }
            }
        }

        show_giant_dash(canvas);
    }
};

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

static void make_unit_star(SkPath* path, int n) {
    SkScalar rad = -SK_ScalarPI / 2;
    const SkScalar drad = (n >> 1) * SK_ScalarPI * 2 / n;

    path->moveTo(0, -SK_Scalar1);
    for (int i = 1; i < n; i++) {
        rad += drad;
        SkScalar cosV, sinV = SkScalarSinCos(rad, &cosV);
        path->lineTo(cosV, sinV);
    }
    path->close();
}

static void make_path_line(SkPath* path, const SkRect& bounds) {
    path->moveTo(bounds.left(), bounds.top());
    path->lineTo(bounds.right(), bounds.bottom());
}

static void make_path_rect(SkPath* path, const SkRect& bounds) {
    path->addRect(bounds);
}

static void make_path_oval(SkPath* path, const SkRect& bounds) {
    path->addOval(bounds);
}

static void make_path_star(SkPath* path, const SkRect& bounds) {
    make_unit_star(path, 5);
    SkMatrix matrix;
    matrix.setRectToRect(path->getBounds(), bounds, SkMatrix::kCenter_ScaleToFit);
    path->transform(matrix);
}

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

protected:
    SkString onShortName() {
        return SkString("dashing2");
    }

    SkISize onISize() { return skiagm::make_isize(640, 480); }

    virtual void onDraw(SkCanvas* canvas) {
        static const int gIntervals[] = {
            3,  // 3 dashes: each count [0] followed by intervals [1..count]
            2,  10, 10,
            4,  20, 5, 5, 5,
            2,  2, 2
        };

        void (*gProc[])(SkPath*, const SkRect&) = {
            make_path_line, make_path_rect, make_path_oval, make_path_star,
        };

        SkPaint paint;
        paint.setAntiAlias(true);
        paint.setStyle(SkPaint::kStroke_Style);
        paint.setStrokeWidth(SkIntToScalar(6));

        SkRect bounds = SkRect::MakeWH(SkIntToScalar(120), SkIntToScalar(120));
        bounds.offset(SkIntToScalar(20), SkIntToScalar(20));
        SkScalar dx = bounds.width() * 4 / 3;
        SkScalar dy = bounds.height() * 4 / 3;

        const int* intervals = &gIntervals[1];
        for (int y = 0; y < gIntervals[0]; ++y) {
            SkScalar vals[SK_ARRAY_COUNT(gIntervals)];  // more than enough
            int count = *intervals++;
            for (int i = 0; i < count; ++i) {
                vals[i] = SkIntToScalar(*intervals++);
            }
            SkScalar phase = vals[0] / 2;
            paint.setPathEffect(new SkDashPathEffect(vals, count, phase))->unref();

            for (size_t x = 0; x < SK_ARRAY_COUNT(gProc); ++x) {
                SkPath path;
                SkRect r = bounds;
                r.offset(x * dx, y * dy);
                gProc[x](&path, r);

                canvas->drawPath(path, paint);
            }
        }
    }
};

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

// Test out the on/off line dashing Chrome if fond of
class Dashing3GM : public skiagm::GM {
public:
    Dashing3GM() {}

protected:
    SkString onShortName() {
        return SkString("dashing3");
    }

    SkISize onISize() { return skiagm::make_isize(640, 480); }

    // Draw a 100x100 block of dashed lines. The horizontal ones are BW
    // while the vertical ones are AA.
    void drawDashedLines(SkCanvas* canvas,
                         SkScalar lineLength,
                         SkScalar phase,
                         SkScalar dashLength,
                         int strokeWidth,
                         bool circles) {
        SkPaint p;
        p.setColor(SK_ColorBLACK);
        p.setStyle(SkPaint::kStroke_Style);
        p.setStrokeWidth(SkIntToScalar(strokeWidth));

        if (circles) {
            p.setStrokeCap(SkPaint::kRound_Cap);
        }

        SkScalar intervals[2] = { dashLength, dashLength };

        p.setPathEffect(new SkDashPathEffect(intervals, 2, phase, false));

        SkPoint pts[2];

        for (int y = 0; y < 100; y += 10*strokeWidth) {
            pts[0].set(0, SkIntToScalar(y));
            pts[1].set(lineLength, SkIntToScalar(y));

            canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p);
        }

        p.setAntiAlias(true);

        for (int x = 0; x < 100; x += 14*strokeWidth) {
            pts[0].set(SkIntToScalar(x), 0);
            pts[1].set(SkIntToScalar(x), lineLength);

            canvas->drawPoints(SkCanvas::kLines_PointMode, 2, pts, p);
        }
    }

    virtual void onDraw(SkCanvas* canvas) {
        // 1on/1off 1x1 squares with phase of 0 - points fastpath
        canvas->save();
            canvas->translate(2, 0);
            this->drawDashedLines(canvas, 100, 0, SK_Scalar1, 1, false);
        canvas->restore();

        // 1on/1off 1x1 squares with phase of .5 - rects fastpath (due to partial squares)
        canvas->save();
            canvas->translate(112, 0);
            this->drawDashedLines(canvas, 100, SK_ScalarHalf, SK_Scalar1, 1, false);
        canvas->restore();

        // 1on/1off 1x1 squares with phase of 1 - points fastpath
        canvas->save();
            canvas->translate(222, 0);
            this->drawDashedLines(canvas, 100, SK_Scalar1, SK_Scalar1, 1, false);
        canvas->restore();

        // 1on/1off 1x1 squares with phase of 1 and non-integer length - rects fastpath
        canvas->save();
            canvas->translate(332, 0);
            this->drawDashedLines(canvas, 99.5, SK_ScalarHalf, SK_Scalar1, 1, false);
        canvas->restore();

        // 1on/1off 3x3 squares with phase of 0 - points fast path
        canvas->save();
            canvas->translate(2, 110);
            this->drawDashedLines(canvas, 100, 0, SkIntToScalar(3), 3, false);
        canvas->restore();

        // 1on/1off 3x3 squares with phase of 1.5 - rects fast path
        canvas->save();
            canvas->translate(112, 110);
            this->drawDashedLines(canvas, 100, SkFloatToScalar(1.5f), SkIntToScalar(3), 3, false);
        canvas->restore();

        // 1on/1off 1x1 circles with phase of 1 - no fast path yet
        canvas->save();
            canvas->translate(2, 220);
            this->drawDashedLines(canvas, 100, SK_Scalar1, SK_Scalar1, 1, true);
        canvas->restore();

        // 1on/1off 3x3 circles with phase of 1 - no fast path yet
        canvas->save();
            canvas->translate(112, 220);
            this->drawDashedLines(canvas, 100, 0, SkIntToScalar(3), 3, true);
        canvas->restore();

        // 1on/1off 1x1 squares with rotation - should break fast path
        canvas->save();
            canvas->translate(332+SK_ScalarRoot2Over2*100, 110+SK_ScalarRoot2Over2*100);
            canvas->rotate(45);
            canvas->translate(-50, -50);

            this->drawDashedLines(canvas, 100, SK_Scalar1, SK_Scalar1, 1, false);
        canvas->restore();

        // 3on/3off 3x1 rects - should use rect fast path regardless of phase
        for (int phase = 0; phase <= 3; ++phase) {
            canvas->save();
                canvas->translate(SkIntToScalar(phase*110+2),
                                  SkIntToScalar(330));
                this->drawDashedLines(canvas, 100, SkIntToScalar(phase), SkIntToScalar(3), 1, false);
            canvas->restore();
        }
    }

};

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

static skiagm::GM* F0(void*) { return new DashingGM; }
static skiagm::GM* F1(void*) { return new Dashing2GM; }
static skiagm::GM* F2(void*) { return new Dashing3GM; }

static skiagm::GMRegistry gR0(F0);
static skiagm::GMRegistry gR1(F1);
static skiagm::GMRegistry gR2(F2);

<|endoftext|>


<commit_before>#include "gtest/gtest.h"

#include "amf.hpp"
#include "types/amfvector.hpp"

template<typename T>
static void isEqual(const std::vector<u8>& expected, AmfVector<T> vector) {
	ASSERT_EQ(expected, vector.serialize());
}

TEST(VectorSerializationTest, EmptyVectorInt) {
	AmfVector<int> vec({}, false);
	v8 expected { 0x0d, 0x01, 0x00 };
	ASSERT_EQ(expected, vec.serialize());

	vec = {{}, true};
	expected = { 0x0d, 0x01, 0x01 };
	ASSERT_EQ(expected, vec.serialize());
}

TEST(VectorSerializationTest, VectorInt) {
	AmfVector<int> vec({ 1, 2, 3 }, false);
	v8 expected {
		0x0d, 0x07, 0x00,
		0x00, 0x00, 0x00, 0x01,
		0x00, 0x00, 0x00, 0x02,
		0x00, 0x00, 0x00, 0x03
	};
	ASSERT_EQ(expected, vec.serialize());

	vec = {{ 0xff, 0x100, 0xfffe, 0xffff, 0x123456, 0xfffffff }, true};
	expected = {
		0x0d, 0x0d, 0x01,
		0x00, 0x00, 0x00, 0xff,
		0x00, 0x00, 0x01, 0x00,
		0x00, 0x00, 0xff, 0xfe,
		0x00, 0x00, 0xff, 0xff,
		0x00, 0x12, 0x34, 0x56,
		0x0f, 0xff, 0xff, 0xff
	};
	ASSERT_EQ(expected, vec.serialize());
}

TEST(VectorSerializationTest, VectorInt32) {
	AmfVector<int> vec({
		0x20000000,
		0x40000000,
		0x7fffffff
	}, true);
	v8 expected {
		0x0d, 0x07, 0x01,
		0x20, 0x00, 0x00, 0x00,
		0x40, 0x00, 0x00, 0x00,
		0x7f, 0xff, 0xff, 0xff
	};
	ASSERT_EQ(expected, vec.serialize());
}

TEST(VectorSerializationTest, VectorIntNegative) {
	AmfVector<int> vec({ -1, -2, -0xffff }, false);
	v8 expected {
		0x0d, 0x07, 0x00,
		0xff, 0xff, 0xff, 0xff,
		0xff, 0xff, 0xff, 0xfe,
		0xff, 0xff, 0x00, 0x01
	};
	ASSERT_EQ(expected, vec.serialize());
}

TEST(VectorSerializationTest, VectorInt32Negative) {
	AmfVector<int> vec({
		-0x20000000,
		-0x40000000,
		-0x7fffffff,
		-0x80000000
	}, true);
	v8 expected {
		0x0d, 0x09, 0x01,
		0xe0, 0x00, 0x00, 0x00,
		0xc0, 0x00, 0x00, 0x00,
		0x80, 0x00, 0x00, 0x01,
		0x80, 0x00, 0x00, 0x00
	};
	ASSERT_EQ(expected, vec.serialize());
}

TEST(VectorSerializationTest, VectorIntFixedDefault) {
	AmfVector<int> vec({1, 3, 5});
	v8 expected {
		0x0d, 0x07, 0x00,
		0x00, 0x00, 0x00, 0x01,
		0x00, 0x00, 0x00, 0x03,
		0x00, 0x00, 0x00, 0x05
	};
	ASSERT_EQ(expected, vec.serialize());
}
<commit_msg>Fix int literal in test<commit_after>#include "gtest/gtest.h"

#include "amf.hpp"
#include "types/amfvector.hpp"

template<typename T>
static void isEqual(const std::vector<u8>& expected, AmfVector<T> vector) {
	ASSERT_EQ(expected, vector.serialize());
}

TEST(VectorSerializationTest, EmptyVectorInt) {
	AmfVector<int> vec({}, false);
	v8 expected { 0x0d, 0x01, 0x00 };
	ASSERT_EQ(expected, vec.serialize());

	vec = {{}, true};
	expected = { 0x0d, 0x01, 0x01 };
	ASSERT_EQ(expected, vec.serialize());
}

TEST(VectorSerializationTest, VectorInt) {
	AmfVector<int> vec({ 1, 2, 3 }, false);
	v8 expected {
		0x0d, 0x07, 0x00,
		0x00, 0x00, 0x00, 0x01,
		0x00, 0x00, 0x00, 0x02,
		0x00, 0x00, 0x00, 0x03
	};
	ASSERT_EQ(expected, vec.serialize());

	vec = {{ 0xff, 0x100, 0xfffe, 0xffff, 0x123456, 0xfffffff }, true};
	expected = {
		0x0d, 0x0d, 0x01,
		0x00, 0x00, 0x00, 0xff,
		0x00, 0x00, 0x01, 0x00,
		0x00, 0x00, 0xff, 0xfe,
		0x00, 0x00, 0xff, 0xff,
		0x00, 0x12, 0x34, 0x56,
		0x0f, 0xff, 0xff, 0xff
	};
	ASSERT_EQ(expected, vec.serialize());
}

TEST(VectorSerializationTest, VectorInt32) {
	AmfVector<int> vec({
		0x20000000,
		0x40000000,
		0x7fffffff
	}, true);
	v8 expected {
		0x0d, 0x07, 0x01,
		0x20, 0x00, 0x00, 0x00,
		0x40, 0x00, 0x00, 0x00,
		0x7f, 0xff, 0xff, 0xff
	};
	ASSERT_EQ(expected, vec.serialize());
}

TEST(VectorSerializationTest, VectorIntNegative) {
	AmfVector<int> vec({ -1, -2, -0xffff }, false);
	v8 expected {
		0x0d, 0x07, 0x00,
		0xff, 0xff, 0xff, 0xff,
		0xff, 0xff, 0xff, 0xfe,
		0xff, 0xff, 0x00, 0x01
	};
	ASSERT_EQ(expected, vec.serialize());
}

TEST(VectorSerializationTest, VectorInt32Negative) {
	AmfVector<int> vec({
		-0x20000000,
		-0x40000000,
		-0x7fffffff,
		-2147483648
	}, true);
	v8 expected {
		0x0d, 0x09, 0x01,
		0xe0, 0x00, 0x00, 0x00,
		0xc0, 0x00, 0x00, 0x00,
		0x80, 0x00, 0x00, 0x01,
		0x80, 0x00, 0x00, 0x00
	};
	ASSERT_EQ(expected, vec.serialize());
}

TEST(VectorSerializationTest, VectorIntFixedDefault) {
	AmfVector<int> vec({1, 3, 5});
	v8 expected {
		0x0d, 0x07, 0x00,
		0x00, 0x00, 0x00, 0x01,
		0x00, 0x00, 0x00, 0x03,
		0x00, 0x00, 0x00, 0x05
	};
	ASSERT_EQ(expected, vec.serialize());
}
<|endoftext|>