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

#include "src/core/SkStrikeCache.h"

#include <cctype>

#include "include/core/SkGraphics.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkTraceMemoryDump.h"
#include "include/core/SkTypeface.h"
#include "include/private/SkMutex.h"
#include "include/private/SkTemplates.h"
#include "src/core/SkGlyphRunPainter.h"
#include "src/core/SkScalerCache.h"

bool gSkUseThreadLocalStrikeCaches_IAcknowledgeThisIsIncrediblyExperimental = false;

SkStrikeCache* SkStrikeCache::GlobalStrikeCache() {
#if !defined(SK_BUILD_FOR_IOS)
    if (gSkUseThreadLocalStrikeCaches_IAcknowledgeThisIsIncrediblyExperimental) {
        static thread_local auto* cache = new SkStrikeCache;
        return cache;
    }
#endif
    static auto* cache = new SkStrikeCache;
    return cache;
}

SkStrikeCache::ExclusiveStrikePtr::ExclusiveStrikePtr(sk_sp<Strike> strike)
    : fStrike{std::move(strike)} {}

SkStrikeCache::ExclusiveStrikePtr::ExclusiveStrikePtr()
    : fStrike{nullptr} {}

SkStrikeCache::ExclusiveStrikePtr::ExclusiveStrikePtr(ExclusiveStrikePtr&& o)
    : fStrike{std::move(o.fStrike)} {
    o.fStrike = nullptr;
}

SkStrikeCache::ExclusiveStrikePtr&
SkStrikeCache::ExclusiveStrikePtr::operator = (ExclusiveStrikePtr&& that) {
    fStrike = std::move(that.fStrike);
    return *this;
}

SkStrike* SkStrikeCache::ExclusiveStrikePtr::get() const {
    return fStrike.get();
}

SkStrike* SkStrikeCache::ExclusiveStrikePtr::operator -> () const {
    return this->get();
}

SkStrike& SkStrikeCache::ExclusiveStrikePtr::operator *  () const {
    return *this->get();
}

SkStrikeCache::ExclusiveStrikePtr::operator bool () const {
    return fStrike != nullptr;
}

bool operator == (const SkStrikeCache::ExclusiveStrikePtr& lhs,
                  const SkStrikeCache::ExclusiveStrikePtr& rhs) {
    return lhs.fStrike == rhs.fStrike;
}

bool operator == (const SkStrikeCache::ExclusiveStrikePtr& lhs, decltype(nullptr)) {
    return lhs.fStrike == nullptr;
}

bool operator == (decltype(nullptr), const SkStrikeCache::ExclusiveStrikePtr& rhs) {
    return nullptr == rhs.fStrike;
}

SkStrikeCache::~SkStrikeCache() {
    Strike* strike = fHead;
    while (strike) {
        Strike* next = strike->fNext;
        strike->unref();
        strike = next;
    }
}

SkExclusiveStrikePtr SkStrikeCache::findOrCreateStrikeExclusive(
        const SkDescriptor& desc, const SkScalerContextEffects& effects, const SkTypeface& typeface)
{
    return SkExclusiveStrikePtr(this->findOrCreateStrike(desc, effects, typeface));
}

auto SkStrikeCache::findOrCreateStrike(const SkDescriptor& desc,
                                       const SkScalerContextEffects& effects,
                                       const SkTypeface& typeface) -> sk_sp<Strike> {
    SkAutoSpinlock ac(fLock);
    sk_sp<Strike> strike = this->internalFindStrikeOrNull(desc);
    if (strike == nullptr) {
        auto scaler = typeface.createScalerContext(effects, &desc);
        strike = this->internalCreateStrike(desc, std::move(scaler));
    }
    return strike;
}

SkScopedStrikeForGPU SkStrikeCache::findOrCreateScopedStrike(const SkDescriptor& desc,
                                                             const SkScalerContextEffects& effects,
                                                             const SkTypeface& typeface) {
    return SkScopedStrikeForGPU{this->findOrCreateStrike(desc, effects, typeface).release()};
}

void SkStrikeCache::PurgeAll() {
    GlobalStrikeCache()->purgeAll();
}

void SkStrikeCache::Dump() {
    SkDebugf("GlyphCache [     used    budget ]\n");
    SkDebugf("    bytes  [ %8zu  %8zu ]\n",
             SkGraphics::GetFontCacheUsed(), SkGraphics::GetFontCacheLimit());
    SkDebugf("    count  [ %8zu  %8zu ]\n",
             SkGraphics::GetFontCacheCountUsed(), SkGraphics::GetFontCacheCountLimit());

    int counter = 0;

    auto visitor = [&counter](const Strike& strike) {
        const SkScalerContextRec& rec = strike.fScalerCache.getScalerContext()->getRec();

        SkDebugf("index %d\n", counter);
        SkDebugf("%s", rec.dump().c_str());
        counter += 1;
    };

    GlobalStrikeCache()->forEachStrike(visitor);
}

namespace {
    const char gGlyphCacheDumpName[] = "skia/sk_glyph_cache";
}  // namespace

void SkStrikeCache::DumpMemoryStatistics(SkTraceMemoryDump* dump) {
    dump->dumpNumericValue(gGlyphCacheDumpName, "size", "bytes", SkGraphics::GetFontCacheUsed());
    dump->dumpNumericValue(gGlyphCacheDumpName, "budget_size", "bytes",
                           SkGraphics::GetFontCacheLimit());
    dump->dumpNumericValue(gGlyphCacheDumpName, "glyph_count", "objects",
                           SkGraphics::GetFontCacheCountUsed());
    dump->dumpNumericValue(gGlyphCacheDumpName, "budget_glyph_count", "objects",
                           SkGraphics::GetFontCacheCountLimit());

    if (dump->getRequestedDetails() == SkTraceMemoryDump::kLight_LevelOfDetail) {
        dump->setMemoryBacking(gGlyphCacheDumpName, "malloc", nullptr);
        return;
    }

    auto visitor = [&dump](const Strike& strike) {
        const SkTypeface* face = strike.fScalerCache.getScalerContext()->getTypeface();
        const SkScalerContextRec& rec = strike.fScalerCache.getScalerContext()->getRec();

        SkString fontName;
        face->getFamilyName(&fontName);
        // Replace all special characters with '_'.
        for (size_t index = 0; index < fontName.size(); ++index) {
            if (!std::isalnum(fontName[index])) {
                fontName[index] = '_';
            }
        }

        SkString dumpName = SkStringPrintf(
                "%s/%s_%d/%p", gGlyphCacheDumpName, fontName.c_str(), rec.fFontID, &strike);

        dump->dumpNumericValue(dumpName.c_str(),
                               "size", "bytes", strike.fMemoryUsed);
        dump->dumpNumericValue(dumpName.c_str(),
                               "glyph_count", "objects",
                               strike.fScalerCache.countCachedGlyphs());
        dump->setMemoryBacking(dumpName.c_str(), "malloc", nullptr);
    };

    GlobalStrikeCache()->forEachStrike(visitor);
}

SkExclusiveStrikePtr SkStrikeCache::findStrikeExclusive(const SkDescriptor& desc) {
    SkAutoSpinlock ac(fLock);
    return SkExclusiveStrikePtr(this->internalFindStrikeOrNull(desc));
}

auto SkStrikeCache::internalFindStrikeOrNull(const SkDescriptor& desc) -> sk_sp<Strike> {
    for (Strike* strike = fHead; strike != nullptr; strike = strike->fNext) {
        if (strike->fScalerCache.getDescriptor() == desc) {
            if (fHead != strike) {
                // Make most recently used
                strike->fPrev->fNext = strike->fNext;
                if (strike->fNext != nullptr) {
                    strike->fNext->fPrev = strike->fPrev;
                } else {
                    fTail = strike->fPrev;
                }
                fHead->fPrev = strike;
                strike->fNext = fHead;
                strike->fPrev = nullptr;
                fHead = strike;
            }

            return sk_ref_sp(strike);
        }
    }

    return nullptr;
}

SkExclusiveStrikePtr SkStrikeCache::createStrikeExclusive(
        const SkDescriptor& desc,
        std::unique_ptr<SkScalerContext> scaler,
        SkFontMetrics* maybeMetrics,
        std::unique_ptr<SkStrikePinner> pinner)
{
    SkAutoSpinlock ac(fLock);
    return SkExclusiveStrikePtr(
            this->internalCreateStrike(desc, std::move(scaler), maybeMetrics, std::move(pinner)));
}

auto SkStrikeCache::internalCreateStrike(
        const SkDescriptor& desc,
        std::unique_ptr<SkScalerContext> scaler,
        SkFontMetrics* maybeMetrics,
        std::unique_ptr<SkStrikePinner> pinner) -> sk_sp<Strike> {
    auto strike =
            sk_make_sp<Strike>(this, desc, std::move(scaler), maybeMetrics, std::move(pinner));
    this->internalAttachToHead(strike);
    return strike;
}

void SkStrikeCache::purgeAll() {
    SkAutoSpinlock ac(fLock);
    this->internalPurge(fTotalMemoryUsed);
}

size_t SkStrikeCache::getTotalMemoryUsed() const {
    SkAutoSpinlock ac(fLock);
    return fTotalMemoryUsed;
}

int SkStrikeCache::getCacheCountUsed() const {
    SkAutoSpinlock ac(fLock);
    return fCacheCount;
}

int SkStrikeCache::getCacheCountLimit() const {
    SkAutoSpinlock ac(fLock);
    return fCacheCountLimit;
}

size_t SkStrikeCache::setCacheSizeLimit(size_t newLimit) {
    static const size_t minLimit = 256 * 1024;
    if (newLimit < minLimit) {
        newLimit = minLimit;
    }

    SkAutoSpinlock ac(fLock);

    size_t prevLimit = fCacheSizeLimit;
    fCacheSizeLimit = newLimit;
    this->internalPurge();
    return prevLimit;
}

size_t  SkStrikeCache::getCacheSizeLimit() const {
    SkAutoSpinlock ac(fLock);
    return fCacheSizeLimit;
}

int SkStrikeCache::setCacheCountLimit(int newCount) {
    if (newCount < 0) {
        newCount = 0;
    }

    SkAutoSpinlock ac(fLock);

    int prevCount = fCacheCountLimit;
    fCacheCountLimit = newCount;
    this->internalPurge();
    return prevCount;
}

int SkStrikeCache::getCachePointSizeLimit() const {
    SkAutoSpinlock ac(fLock);
    return fPointSizeLimit;
}

int SkStrikeCache::setCachePointSizeLimit(int newLimit) {
    if (newLimit < 0) {
        newLimit = 0;
    }

    SkAutoSpinlock ac(fLock);

    int prevLimit = fPointSizeLimit;
    fPointSizeLimit = newLimit;
    return prevLimit;
}

void SkStrikeCache::forEachStrike(std::function<void(const Strike&)> visitor) const {
    SkAutoSpinlock ac(fLock);

    this->validate();

    for (Strike* strike = fHead; strike != nullptr; strike = strike->fNext) {
        visitor(*strike);
    }
}

size_t SkStrikeCache::internalPurge(size_t minBytesNeeded) {
    this->validate();

    size_t bytesNeeded = 0;
    if (fTotalMemoryUsed > fCacheSizeLimit) {
        bytesNeeded = fTotalMemoryUsed - fCacheSizeLimit;
    }
    bytesNeeded = std::max(bytesNeeded, minBytesNeeded);
    if (bytesNeeded) {
        // no small purges!
        bytesNeeded = std::max(bytesNeeded, fTotalMemoryUsed >> 2);
    }

    int countNeeded = 0;
    if (fCacheCount > fCacheCountLimit) {
        countNeeded = fCacheCount - fCacheCountLimit;
        // no small purges!
        countNeeded = std::max(countNeeded, fCacheCount >> 2);
    }

    // early exit
    if (!countNeeded && !bytesNeeded) {
        return 0;
    }

    size_t  bytesFreed = 0;
    int     countFreed = 0;

    // Start at the tail and proceed backwards deleting; the list is in LRU
    // order, with unimportant entries at the tail.
    Strike* strike = fTail;
    while (strike != nullptr && (bytesFreed < bytesNeeded || countFreed < countNeeded)) {
        Strike* prev = strike->fPrev;

        // Only delete if the strike is not pinned.
        if (strike->fPinner == nullptr || strike->fPinner->canDelete()) {
            bytesFreed += strike->fMemoryUsed;
            countFreed += 1;
            this->internalRemoveStrike(strike);
        }
        strike = prev;
    }

    this->validate();

#ifdef SPEW_PURGE_STATUS
    if (countFreed) {
        SkDebugf("purging %dK from font cache [%d entries]\n",
                 (int)(bytesFreed >> 10), countFreed);
    }
#endif

    return bytesFreed;
}

void SkStrikeCache::internalAttachToHead(sk_sp<Strike> strike) {
    SkASSERT(nullptr == strike->fPrev && nullptr == strike->fNext);

    fCacheCount += 1;
    fTotalMemoryUsed += strike->fMemoryUsed;

    if (fHead) {
        fHead->fPrev = strike.get();
        strike->fNext = fHead;
    }

    if (fTail == nullptr) {
        fTail = strike.get();
    }

    fHead = strike.release(); // Transfer ownership of strike to the cache list.
}

void SkStrikeCache::internalRemoveStrike(Strike* strike) {
    SkASSERT(fCacheCount > 0);
    fCacheCount -= 1;
    fTotalMemoryUsed -= strike->fMemoryUsed;

    if (strike->fPrev) {
        strike->fPrev->fNext = strike->fNext;
    } else {
        fHead = strike->fNext;
    }
    if (strike->fNext) {
        strike->fNext->fPrev = strike->fPrev;
    } else {
        fTail = strike->fPrev;
    }
    strike->fPrev = strike->fNext = nullptr;
    strike->fRemoved = true;
    strike->unref();
}

void SkStrikeCache::validate() const {
#ifdef SK_DEBUG
    size_t computedBytes = 0;
    int computedCount = 0;

    const Strike* strike = fHead;
    while (strike != nullptr) {
        computedBytes += strike->fMemoryUsed;
        computedCount += 1;
        strike = strike->fNext;
    }

    // Can't use SkASSERTF because it looses thread annotations.
    if (fCacheCount != computedCount) {
        SkDebugf("fCacheCount: %d, computedCount: %d", fCacheCount, computedCount);
        SK_ABORT("fCacheCount != computedCount");
    }
    if (fTotalMemoryUsed != computedBytes) {
        SkDebugf("fTotalMemoryUsed: %d, computedBytes: %d", fTotalMemoryUsed, computedBytes);
        SK_ABORT("fTotalMemoryUsed == computedBytes");
    }
#endif
}

void SkStrikeCache::Strike::updateDelta(size_t increase) {
    if (increase != 0) {
        SkAutoSpinlock lock{fStrikeCache->fLock};
        fMemoryUsed += increase;
        if (!fRemoved) {
            fStrikeCache->fTotalMemoryUsed += increase;
        }
    }
}
<commit_msg>Roll Skia from cf8c53436c77 to b43313646796 (1 revision)<commit_after>/*
 * Copyright 2018 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "src/core/SkStrikeCache.h"

#include <cctype>

#include "include/core/SkGraphics.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkTraceMemoryDump.h"
#include "include/core/SkTypeface.h"
#include "include/private/SkMutex.h"
#include "include/private/SkTemplates.h"
#include "src/core/SkGlyphRunPainter.h"
#include "src/core/SkScalerCache.h"

bool gSkUseThreadLocalStrikeCaches_IAcknowledgeThisIsIncrediblyExperimental = false;

SkStrikeCache* SkStrikeCache::GlobalStrikeCache() {
#if !defined(SK_BUILD_FOR_IOS)
    if (gSkUseThreadLocalStrikeCaches_IAcknowledgeThisIsIncrediblyExperimental) {
        static thread_local auto* cache = new SkStrikeCache;
        return cache;
    }
#endif
    static auto* cache = new SkStrikeCache;
    return cache;
}

SkStrikeCache::ExclusiveStrikePtr::ExclusiveStrikePtr(sk_sp<Strike> strike)
    : fStrike{std::move(strike)} {}

SkStrikeCache::ExclusiveStrikePtr::ExclusiveStrikePtr()
    : fStrike{nullptr} {}

SkStrikeCache::ExclusiveStrikePtr::ExclusiveStrikePtr(ExclusiveStrikePtr&& o)
    : fStrike{std::move(o.fStrike)} {
    o.fStrike = nullptr;
}

SkStrikeCache::ExclusiveStrikePtr&
SkStrikeCache::ExclusiveStrikePtr::operator = (ExclusiveStrikePtr&& that) {
    fStrike = std::move(that.fStrike);
    return *this;
}

SkStrike* SkStrikeCache::ExclusiveStrikePtr::get() const {
    return fStrike.get();
}

SkStrike* SkStrikeCache::ExclusiveStrikePtr::operator -> () const {
    return this->get();
}

SkStrike& SkStrikeCache::ExclusiveStrikePtr::operator *  () const {
    return *this->get();
}

SkStrikeCache::ExclusiveStrikePtr::operator bool () const {
    return fStrike != nullptr;
}

bool operator == (const SkStrikeCache::ExclusiveStrikePtr& lhs,
                  const SkStrikeCache::ExclusiveStrikePtr& rhs) {
    return lhs.fStrike == rhs.fStrike;
}

bool operator == (const SkStrikeCache::ExclusiveStrikePtr& lhs, decltype(nullptr)) {
    return lhs.fStrike == nullptr;
}

bool operator == (decltype(nullptr), const SkStrikeCache::ExclusiveStrikePtr& rhs) {
    return nullptr == rhs.fStrike;
}

SkStrikeCache::~SkStrikeCache() {
    Strike* strike = fHead;
    while (strike) {
        Strike* next = strike->fNext;
        strike->unref();
        strike = next;
    }
}

SkExclusiveStrikePtr SkStrikeCache::findOrCreateStrikeExclusive(
        const SkDescriptor& desc, const SkScalerContextEffects& effects, const SkTypeface& typeface)
{
    return SkExclusiveStrikePtr(this->findOrCreateStrike(desc, effects, typeface));
}

auto SkStrikeCache::findOrCreateStrike(const SkDescriptor& desc,
                                       const SkScalerContextEffects& effects,
                                       const SkTypeface& typeface) -> sk_sp<Strike> {
    SkAutoSpinlock ac(fLock);
    sk_sp<Strike> strike = this->internalFindStrikeOrNull(desc);
    if (strike == nullptr) {
        auto scaler = typeface.createScalerContext(effects, &desc);
        strike = this->internalCreateStrike(desc, std::move(scaler));
    }
    this->internalPurge();
    return strike;
}

SkScopedStrikeForGPU SkStrikeCache::findOrCreateScopedStrike(const SkDescriptor& desc,
                                                             const SkScalerContextEffects& effects,
                                                             const SkTypeface& typeface) {
    return SkScopedStrikeForGPU{this->findOrCreateStrike(desc, effects, typeface).release()};
}

void SkStrikeCache::PurgeAll() {
    GlobalStrikeCache()->purgeAll();
}

void SkStrikeCache::Dump() {
    SkDebugf("GlyphCache [     used    budget ]\n");
    SkDebugf("    bytes  [ %8zu  %8zu ]\n",
             SkGraphics::GetFontCacheUsed(), SkGraphics::GetFontCacheLimit());
    SkDebugf("    count  [ %8zu  %8zu ]\n",
             SkGraphics::GetFontCacheCountUsed(), SkGraphics::GetFontCacheCountLimit());

    int counter = 0;

    auto visitor = [&counter](const Strike& strike) {
        const SkScalerContextRec& rec = strike.fScalerCache.getScalerContext()->getRec();

        SkDebugf("index %d\n", counter);
        SkDebugf("%s", rec.dump().c_str());
        counter += 1;
    };

    GlobalStrikeCache()->forEachStrike(visitor);
}

namespace {
    const char gGlyphCacheDumpName[] = "skia/sk_glyph_cache";
}  // namespace

void SkStrikeCache::DumpMemoryStatistics(SkTraceMemoryDump* dump) {
    dump->dumpNumericValue(gGlyphCacheDumpName, "size", "bytes", SkGraphics::GetFontCacheUsed());
    dump->dumpNumericValue(gGlyphCacheDumpName, "budget_size", "bytes",
                           SkGraphics::GetFontCacheLimit());
    dump->dumpNumericValue(gGlyphCacheDumpName, "glyph_count", "objects",
                           SkGraphics::GetFontCacheCountUsed());
    dump->dumpNumericValue(gGlyphCacheDumpName, "budget_glyph_count", "objects",
                           SkGraphics::GetFontCacheCountLimit());

    if (dump->getRequestedDetails() == SkTraceMemoryDump::kLight_LevelOfDetail) {
        dump->setMemoryBacking(gGlyphCacheDumpName, "malloc", nullptr);
        return;
    }

    auto visitor = [&dump](const Strike& strike) {
        const SkTypeface* face = strike.fScalerCache.getScalerContext()->getTypeface();
        const SkScalerContextRec& rec = strike.fScalerCache.getScalerContext()->getRec();

        SkString fontName;
        face->getFamilyName(&fontName);
        // Replace all special characters with '_'.
        for (size_t index = 0; index < fontName.size(); ++index) {
            if (!std::isalnum(fontName[index])) {
                fontName[index] = '_';
            }
        }

        SkString dumpName = SkStringPrintf(
                "%s/%s_%d/%p", gGlyphCacheDumpName, fontName.c_str(), rec.fFontID, &strike);

        dump->dumpNumericValue(dumpName.c_str(),
                               "size", "bytes", strike.fMemoryUsed);
        dump->dumpNumericValue(dumpName.c_str(),
                               "glyph_count", "objects",
                               strike.fScalerCache.countCachedGlyphs());
        dump->setMemoryBacking(dumpName.c_str(), "malloc", nullptr);
    };

    GlobalStrikeCache()->forEachStrike(visitor);
}

SkExclusiveStrikePtr SkStrikeCache::findStrikeExclusive(const SkDescriptor& desc) {
    SkAutoSpinlock ac(fLock);
    sk_sp<SkStrike> result = this->internalFindStrikeOrNull(desc);
    this->internalPurge();
    return SkExclusiveStrikePtr(result);
}

auto SkStrikeCache::internalFindStrikeOrNull(const SkDescriptor& desc) -> sk_sp<Strike> {
    for (Strike* strike = fHead; strike != nullptr; strike = strike->fNext) {
        if (strike->fScalerCache.getDescriptor() == desc) {
            if (fHead != strike) {
                // Make most recently used
                strike->fPrev->fNext = strike->fNext;
                if (strike->fNext != nullptr) {
                    strike->fNext->fPrev = strike->fPrev;
                } else {
                    fTail = strike->fPrev;
                }
                fHead->fPrev = strike;
                strike->fNext = fHead;
                strike->fPrev = nullptr;
                fHead = strike;
            }

            return sk_ref_sp(strike);
        }
    }

    return nullptr;
}

SkExclusiveStrikePtr SkStrikeCache::createStrikeExclusive(
        const SkDescriptor& desc,
        std::unique_ptr<SkScalerContext> scaler,
        SkFontMetrics* maybeMetrics,
        std::unique_ptr<SkStrikePinner> pinner)
{
    SkAutoSpinlock ac(fLock);
    return SkExclusiveStrikePtr(
            this->internalCreateStrike(desc, std::move(scaler), maybeMetrics, std::move(pinner)));
}

auto SkStrikeCache::internalCreateStrike(
        const SkDescriptor& desc,
        std::unique_ptr<SkScalerContext> scaler,
        SkFontMetrics* maybeMetrics,
        std::unique_ptr<SkStrikePinner> pinner) -> sk_sp<Strike> {
    auto strike =
            sk_make_sp<Strike>(this, desc, std::move(scaler), maybeMetrics, std::move(pinner));
    this->internalAttachToHead(strike);
    return strike;
}

void SkStrikeCache::purgeAll() {
    SkAutoSpinlock ac(fLock);
    this->internalPurge(fTotalMemoryUsed);
}

size_t SkStrikeCache::getTotalMemoryUsed() const {
    SkAutoSpinlock ac(fLock);
    return fTotalMemoryUsed;
}

int SkStrikeCache::getCacheCountUsed() const {
    SkAutoSpinlock ac(fLock);
    return fCacheCount;
}

int SkStrikeCache::getCacheCountLimit() const {
    SkAutoSpinlock ac(fLock);
    return fCacheCountLimit;
}

size_t SkStrikeCache::setCacheSizeLimit(size_t newLimit) {
    SkAutoSpinlock ac(fLock);

    size_t prevLimit = fCacheSizeLimit;
    fCacheSizeLimit = newLimit;
    this->internalPurge();
    return prevLimit;
}

size_t  SkStrikeCache::getCacheSizeLimit() const {
    SkAutoSpinlock ac(fLock);
    return fCacheSizeLimit;
}

int SkStrikeCache::setCacheCountLimit(int newCount) {
    if (newCount < 0) {
        newCount = 0;
    }

    SkAutoSpinlock ac(fLock);

    int prevCount = fCacheCountLimit;
    fCacheCountLimit = newCount;
    this->internalPurge();
    return prevCount;
}

int SkStrikeCache::getCachePointSizeLimit() const {
    SkAutoSpinlock ac(fLock);
    return fPointSizeLimit;
}

int SkStrikeCache::setCachePointSizeLimit(int newLimit) {
    if (newLimit < 0) {
        newLimit = 0;
    }

    SkAutoSpinlock ac(fLock);

    int prevLimit = fPointSizeLimit;
    fPointSizeLimit = newLimit;
    return prevLimit;
}

void SkStrikeCache::forEachStrike(std::function<void(const Strike&)> visitor) const {
    SkAutoSpinlock ac(fLock);

    this->validate();

    for (Strike* strike = fHead; strike != nullptr; strike = strike->fNext) {
        visitor(*strike);
    }
}

size_t SkStrikeCache::internalPurge(size_t minBytesNeeded) {
    this->validate();

    size_t bytesNeeded = 0;
    if (fTotalMemoryUsed > fCacheSizeLimit) {
        bytesNeeded = fTotalMemoryUsed - fCacheSizeLimit;
    }
    bytesNeeded = std::max(bytesNeeded, minBytesNeeded);
    if (bytesNeeded) {
        // no small purges!
        bytesNeeded = std::max(bytesNeeded, fTotalMemoryUsed >> 2);
    }

    int countNeeded = 0;
    if (fCacheCount > fCacheCountLimit) {
        countNeeded = fCacheCount - fCacheCountLimit;
        // no small purges!
        countNeeded = std::max(countNeeded, fCacheCount >> 2);
    }

    // early exit
    if (!countNeeded && !bytesNeeded) {
        return 0;
    }

    size_t  bytesFreed = 0;
    int     countFreed = 0;

    // Start at the tail and proceed backwards deleting; the list is in LRU
    // order, with unimportant entries at the tail.
    Strike* strike = fTail;
    while (strike != nullptr && (bytesFreed < bytesNeeded || countFreed < countNeeded)) {
        Strike* prev = strike->fPrev;

        // Only delete if the strike is not pinned.
        if (strike->fPinner == nullptr || strike->fPinner->canDelete()) {
            bytesFreed += strike->fMemoryUsed;
            countFreed += 1;
            this->internalRemoveStrike(strike);
        }
        strike = prev;
    }

    this->validate();

#ifdef SPEW_PURGE_STATUS
    if (countFreed) {
        SkDebugf("purging %dK from font cache [%d entries]\n",
                 (int)(bytesFreed >> 10), countFreed);
    }
#endif

    return bytesFreed;
}

void SkStrikeCache::internalAttachToHead(sk_sp<Strike> strike) {
    SkASSERT(nullptr == strike->fPrev && nullptr == strike->fNext);

    fCacheCount += 1;
    fTotalMemoryUsed += strike->fMemoryUsed;

    if (fHead) {
        fHead->fPrev = strike.get();
        strike->fNext = fHead;
    }

    if (fTail == nullptr) {
        fTail = strike.get();
    }

    fHead = strike.release(); // Transfer ownership of strike to the cache list.
}

void SkStrikeCache::internalRemoveStrike(Strike* strike) {
    SkASSERT(fCacheCount > 0);
    fCacheCount -= 1;
    fTotalMemoryUsed -= strike->fMemoryUsed;

    if (strike->fPrev) {
        strike->fPrev->fNext = strike->fNext;
    } else {
        fHead = strike->fNext;
    }
    if (strike->fNext) {
        strike->fNext->fPrev = strike->fPrev;
    } else {
        fTail = strike->fPrev;
    }
    strike->fPrev = strike->fNext = nullptr;
    strike->fRemoved = true;
    strike->unref();
}

void SkStrikeCache::validate() const {
#ifdef SK_DEBUG
    size_t computedBytes = 0;
    int computedCount = 0;

    const Strike* strike = fHead;
    while (strike != nullptr) {
        computedBytes += strike->fMemoryUsed;
        computedCount += 1;
        strike = strike->fNext;
    }

    // Can't use SkASSERTF because it looses thread annotations.
    if (fCacheCount != computedCount) {
        SkDebugf("fCacheCount: %d, computedCount: %d", fCacheCount, computedCount);
        SK_ABORT("fCacheCount != computedCount");
    }
    if (fTotalMemoryUsed != computedBytes) {
        SkDebugf("fTotalMemoryUsed: %d, computedBytes: %d", fTotalMemoryUsed, computedBytes);
        SK_ABORT("fTotalMemoryUsed == computedBytes");
    }
#endif
}

void SkStrikeCache::Strike::updateDelta(size_t increase) {
    if (increase != 0) {
        SkAutoSpinlock lock{fStrikeCache->fLock};
        fMemoryUsed += increase;
        if (!fRemoved) {
            fStrikeCache->fTotalMemoryUsed += increase;
        }
    }
}
<|endoftext|>


<commit_before>#ifndef ANIMATEDTUPLE_HPP_
#define ANIMATEDTUPLE_HPP_

#include <tuple>

template <typename ...Tp>
using AnimatedTuple = std::tuple<Animated<Tp>...>;

// FIXME(#57): generalize tuple iteration process
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
iterateTick(AnimatedTuple<Tp...>&, int32_t)
{}

template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
iterateTick(AnimatedTuple<Tp...>& properties, int32_t deltaTime)
{
    std::get<I>(properties).tick(deltaTime);
    iterateTick<I + 1, Tp...>(properties, deltaTime);
}

#endif  // ANIMATEDTUPLE_HPP_
<commit_msg>Implement iterateStop for AnimatedTuple (#58)<commit_after>#ifndef ANIMATEDTUPLE_HPP_
#define ANIMATEDTUPLE_HPP_

#include <tuple>

template <typename ...Tp>
using AnimatedTuple = std::tuple<Animated<Tp>...>;

// FIXME(#57): generalize tuple iteration process
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
iterateTick(AnimatedTuple<Tp...>&, int32_t)
{}

template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
iterateTick(AnimatedTuple<Tp...>& properties, int32_t deltaTime)
{
    std::get<I>(properties).tick(deltaTime);
    iterateTick<I + 1, Tp...>(properties, deltaTime);
}

template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
iterateStop(AnimatedTuple<Tp...>&)
{}

template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
iterateStop(AnimatedTuple<Tp...>& properties)
{
    std::get<I>(properties).stop();
    iterateStop<I + 1, Tp...>(properties);
}

#endif  // ANIMATEDTUPLE_HPP_
<|endoftext|>


<commit_before>/*
 * Copyright 2016-2017 gtalent2@gmail.com
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
#ifndef NOSTALGIA_CORE_GBA_REGISTERS_HPP
#define NOSTALGIA_CORE_GBA_REGISTERS_HPP

#define REG_DISPCNT *((volatile unsigned int*) 0x04000000)

/////////////////////////////////////////////////////////////////
// background registers

// control registers
#define REG_BG0CNT *((volatile unsigned int*) 0x04000008)
#define REG_BG1CNT *((volatile unsigned int*) 0x0400000a)
#define REG_BG2CNT *((volatile unsigned int*) 0x0400000c)
#define REG_BG3CNT *((volatile unsigned int*) 0x0400000e)

// horizontal scrolling registers
#define REG_BG0HOFS *((volatile unsigned int*) 0x04000010)
#define REG_BG1HOFS *((volatile unsigned int*) 0x04000014)
#define REG_BG2HOFS *((volatile unsigned int*) 0x04000018)
#define REG_BG3HOFS *((volatile unsigned int*) 0x0400001a)

// vertical scrolling registers
#define REG_BG0VOFS *((volatile unsigned int*) 0x04000012)
#define REG_BG1VOFS *((volatile unsigned int*) 0x04000016)
#define REG_BG2VOFS *((volatile unsigned int*) 0x0400001a)
#define REG_BG3VOFS *((volatile unsigned int*) 0x0400001c)

#endif
<commit_msg>Correct 4th background position registers.<commit_after>/*
 * Copyright 2016-2017 gtalent2@gmail.com
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
#ifndef NOSTALGIA_CORE_GBA_REGISTERS_HPP
#define NOSTALGIA_CORE_GBA_REGISTERS_HPP

#define REG_DISPCNT *((volatile unsigned int*) 0x04000000)

/////////////////////////////////////////////////////////////////
// background registers

// control registers
#define REG_BG0CNT *((volatile unsigned int*) 0x04000008)
#define REG_BG1CNT *((volatile unsigned int*) 0x0400000a)
#define REG_BG2CNT *((volatile unsigned int*) 0x0400000c)
#define REG_BG3CNT *((volatile unsigned int*) 0x0400000e)

// horizontal scrolling registers
#define REG_BG0HOFS *((volatile unsigned int*) 0x04000010)
#define REG_BG1HOFS *((volatile unsigned int*) 0x04000014)
#define REG_BG2HOFS *((volatile unsigned int*) 0x04000018)
#define REG_BG3HOFS *((volatile unsigned int*) 0x0400001c)

// vertical scrolling registers
#define REG_BG0VOFS *((volatile unsigned int*) 0x04000012)
#define REG_BG1VOFS *((volatile unsigned int*) 0x04000016)
#define REG_BG2VOFS *((volatile unsigned int*) 0x0400001a)
#define REG_BG3VOFS *((volatile unsigned int*) 0x0400001e)

#endif
<|endoftext|>


<commit_before>// The "Square Detector" program.
// It loads several images sequentially and tries to find squares in
// each image

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

#include <iostream>
#include <math.h>
#include <string.h>
#include <stdio.h>

#include <ros/ros.h>
#include <osuar_vision/windowCoordinates.h>

using namespace cv;

int thresh = 50, N = 11;

// Threshold for maximum cosine between angles (x100).
int maxCosineThresh = 25;

// Threshold for ratio of shortest side / longest side (x100).
int sideRatioThresh = 85;

// Maximum square area.
int maxSquareArea = 41000;

// Find colors of any hue...
int wallHueLow  = 0;
int wallHueHigh = 179;

// ...of low saturation...
int wallSatLow  = 0;
int wallSatHigh = 40;

// ...ranging down to gray, but not completely dark. That is to say, white.
int wallValLow  = 50;
int wallValHigh = 255;

ros::Publisher visPub;
osuar_vision::windowCoordinates winCoords;

// helper function:
// finds a cosine of angle between vectors
// from pt0->pt1 and from pt0->pt2
static double angle( Point pt1, Point pt2, Point pt0 )
{
    double dx1 = pt1.x - pt0.x;
    double dy1 = pt1.y - pt0.y;
    double dx2 = pt2.x - pt0.x;
    double dy2 = pt2.y - pt0.y;
    return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}

// returns sequence of squares detected on the image.
// the sequence is stored in the specified memory storage
static void findSquares( const Mat& image, vector<vector<Point> >& squares )
{
    squares.clear();

    Mat pyr, timg, gray0(image.size(), CV_8U), gray;

    // down-scale and upscale the image to filter out the noise
    pyrDown(image, pyr, Size(image.cols/2, image.rows/2));
    pyrUp(pyr, timg, image.size());
    vector<vector<Point> > contours;

    // find squares in every color plane of the image
    //for( int c = 0; c < 3; c++ )
    //{
        //int ch[] = {c, 0};
        //mixChannels(&timg, 1, &gray0, 1, ch, 1);

        // try several threshold levels
        for( int l = 0; l < N; l++ )
        {
            // hack: use Canny instead of zero threshold level.
            // Canny helps to catch squares with gradient shading
            if( l == 0 )
            {
                // apply Canny. Take the upper threshold from slider
                // and set the lower to 0 (which forces edges merging)
                Canny(image, gray, 0, thresh, 5);
                // dilate canny output to remove potential
                // holes between edge segments
                dilate(gray, gray, Mat(), Point(-1,-1));
            }
            else
            {
                // apply threshold if l!=0:
                //     tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0
                gray = image >= (l+1)*255/N;
            }

            // find contours and store them all as a list
            findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);

            vector<Point> approx;

            // test each contour
            for( size_t i = 0; i < contours.size(); i++ )
            {
                // approximate contour with accuracy proportional
                // to the contour perimeter
                approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);

                // square contours should have 4 vertices after approximation
                // relatively large area (to filter out noisy contours)
                // and be convex.
                // Note: absolute value of an area is used because
                // area may be positive or negative - in accordance with the
                // contour orientation
                if( approx.size() == 4 &&
                    fabs(contourArea(Mat(approx))) > 1000 &&
                    fabs(contourArea(Mat(approx))) < maxSquareArea &&
                    isContourConvex(Mat(approx)) )
                {
                    double maxCosine = 0;
                    double minSideLen = 100000;
                    double maxSideLen = 0;
                    double sideRatio = 0;

                    for( int j = 2; j < 5; j++ )
                    {
                        // find the maximum cosine of the angle between joint edges
                        double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
                        maxCosine = MAX(maxCosine, cosine);

                        // Find the maximum difference in length of adjacent
                        // sides
                        double sideLen = sqrt(pow((approx[j%4].x - approx[(j+1)%4].x), 2) + pow((approx[j%4].y - approx[(j+1)%4].y), 2));
                        minSideLen = MIN(minSideLen, sideLen);
                        maxSideLen = MAX(maxSideLen, sideLen);
                    }

                    sideRatio = minSideLen / maxSideLen;

                    std::cout << minSideLen << "  " << maxSideLen << "\n";

                    // if cosines of all angles are small
                    // (all angles are ~90 degree) then write quandrange
                    // vertices to resultant sequence
                    if( maxCosine < ((double) maxCosineThresh)/100 && sideRatio >= (double) sideRatioThresh/100 )
                        squares.push_back(approx);
                }
            }
        }
    //}
}

// the function draws all the squares in the image
static void drawSquares( Mat& image, const vector<vector<Point> >& squares )
{
    for( size_t i = 0; i < squares.size(); i++ )
    {
        const Point* p = &squares[i][0];
        int n = (int)squares[i].size();
        polylines(image, &p, &n, 1, true, Scalar(0,255,0), 3, CV_AA);

        std::cout << "x: " << squares[i][0].x << "  y: " << squares[i][0].y << "\n";

        // Only publish coordinates for one of the squares. Coordinates are
        // shifted over by half the camera resolution (which itself is scaled
        // down by a factor of two!) on each axis. The y coordinate is inverted
        // so up is positive.
        if (i == 0) {
            putText(image, "0", squares[0][0], FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255,0,0));
            putText(image, "1", squares[0][1], FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255,0,0));
            putText(image, "2", squares[0][2], FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255,0,0));
            putText(image, "3", squares[0][3], FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255,0,0));
            winCoords.x =   (squares[0][0].x + squares[0][2].x)/2 - 180;
            winCoords.y = -((squares[0][0].y + squares[0][2].y)/2 - 120);
            visPub.publish(winCoords);
        }
    }
}

int main(int argc, char** argv) {
    ros::init(argc, argv, "vision");
    ros::NodeHandle nh;
    visPub = nh.advertise<osuar_vision::windowCoordinates>("window_coordinates", 1);

    // Instantiate VideoCapture object. See here for details:
    // http://opencv.willowgarage.com/documentation/cpp/reading_and_writing_images_and_video.html
    VideoCapture cap(1);

    // Configure video. Our camera NEEDS the frame width to be set to 720
    // pixels.
    cap.set(CV_CAP_PROP_FRAME_WIDTH, 720);
    cap.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
    //cap.set(CV_CAP_PROP_FPS, 20);

    // Instantiate a Mat in which to store each video frame.
    Mat origFrame;
    Mat resizedFrame;   // Scaled-down from origFrame by factor of 2.
    Mat hsvFrame;   // Converted to HSV space from resizedFrame.
    Mat bwFrame;   // Black/white image after thresholding hsvFrame.

    namedWindow("origImage", 1);
    namedWindow("hsvImage", 1);
    namedWindow("bwImage", 1);
    cvNamedWindow("control panel");
    cvCreateTrackbar("threshold",   "control panel", &thresh,      300, NULL);
    cvCreateTrackbar("maxCosineThresh (x100)", "control panel", &maxCosineThresh, 100, NULL);
    cvCreateTrackbar("sideRatioThresh (x100)", "control panel", &sideRatioThresh, 100, NULL);
    cvCreateTrackbar("maxSquareArea", "control panel", &maxSquareArea, 100000, NULL);
    cvCreateTrackbar("wallHueLow",  "control panel", &wallHueLow,  179, NULL);
    cvCreateTrackbar("wallHueHigh", "control panel", &wallHueHigh, 179, NULL);
    cvCreateTrackbar("wallSatLow",  "control panel", &wallSatLow,  255, NULL);
    cvCreateTrackbar("wallSatHigh", "control panel", &wallSatHigh, 255, NULL);
    cvCreateTrackbar("wallValLow",  "control panel", &wallValLow,  255, NULL);
    cvCreateTrackbar("wallValHigh", "control panel", &wallValHigh, 255, NULL);
    vector<vector<Point> > squares;

    while (true) {
        // Capture image.
        cap >> origFrame;

        // Resize the image to increase processing rate. See here for details:
        // http://opencv.willowgarage.com/documentation/cpp/image_filtering.html
        pyrDown(origFrame, resizedFrame, Size(origFrame.cols/2, origFrame.rows/2));

        // Convert the frame to HSV. TODO: combine this with more filtering and
        // turn into function.
        cvtColor(resizedFrame, hsvFrame, CV_BGR2HSV);

        // Threshold hsvFrame for color of maze walls.
        inRange(hsvFrame, Scalar(wallHueLow,  wallSatLow,  wallValLow),
                          Scalar(wallHueHigh, wallSatHigh, wallValHigh), bwFrame);

        // Find and draw squares.
        findSquares(bwFrame, squares);
        drawSquares(resizedFrame, squares);

        // Show the image, with the squares overlaid.
        imshow("origImage", resizedFrame);
        imshow("bwImage", bwFrame);

        // Wait 5 milliseconds for a keypress.
        int c = waitKey(5);
        // Exit if the spacebar is pressed. NOTE: killing the program with
        // Ctrl+C sometimes stops OpenCV at a bad place and effects a kernel
        // panic! If you really like Ctrl+C, do so at your own risk!
        if ((char) c == 32) {
            return 0;
        }
    }

    return 0;
}
<commit_msg>Better thresholds.<commit_after>// The "Square Detector" program.
// It loads several images sequentially and tries to find squares in
// each image

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"

#include <iostream>
#include <math.h>
#include <string.h>
#include <stdio.h>

#include <ros/ros.h>
#include <osuar_vision/windowCoordinates.h>

using namespace cv;

int thresh = 50, N = 11;

// Threshold for maximum cosine between angles (x100).
int maxCosineThresh = 20;

// Threshold for ratio of shortest side / longest side (x100).
int sideRatioThresh = 75;

// Maximum square area.
int maxSquareArea = 41000;

// Find colors of any hue...
int wallHueLow  = 50;
int wallHueHigh = 132;

// ...of low saturation...
int wallSatLow  = 0;
int wallSatHigh = 100;

// ...ranging down to gray, but not completely dark. That is to say, white.
int wallValLow  = 90;
int wallValHigh = 255;

ros::Publisher visPub;
osuar_vision::windowCoordinates winCoords;

// helper function:
// finds a cosine of angle between vectors
// from pt0->pt1 and from pt0->pt2
static double angle( Point pt1, Point pt2, Point pt0 )
{
    double dx1 = pt1.x - pt0.x;
    double dy1 = pt1.y - pt0.y;
    double dx2 = pt2.x - pt0.x;
    double dy2 = pt2.y - pt0.y;
    return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}

// returns sequence of squares detected on the image.
// the sequence is stored in the specified memory storage
static void findSquares( const Mat& image, vector<vector<Point> >& squares )
{
    squares.clear();

    Mat pyr, timg, gray0(image.size(), CV_8U), gray;

    // down-scale and upscale the image to filter out the noise
    pyrDown(image, pyr, Size(image.cols/2, image.rows/2));
    pyrUp(pyr, timg, image.size());
    vector<vector<Point> > contours;

    // find squares in every color plane of the image
    //for( int c = 0; c < 3; c++ )
    //{
        //int ch[] = {c, 0};
        //mixChannels(&timg, 1, &gray0, 1, ch, 1);

        // try several threshold levels
        for( int l = 0; l < N; l++ )
        {
            // hack: use Canny instead of zero threshold level.
            // Canny helps to catch squares with gradient shading
            if( l == 0 )
            {
                // apply Canny. Take the upper threshold from slider
                // and set the lower to 0 (which forces edges merging)
                Canny(image, gray, 0, thresh, 5);
                // dilate canny output to remove potential
                // holes between edge segments
                dilate(gray, gray, Mat(), Point(-1,-1));
            }
            else
            {
                // apply threshold if l!=0:
                //     tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0
                gray = image >= (l+1)*255/N;
            }

            // find contours and store them all as a list
            findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);

            vector<Point> approx;

            // test each contour
            for( size_t i = 0; i < contours.size(); i++ )
            {
                // approximate contour with accuracy proportional
                // to the contour perimeter
                approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true);

                // square contours should have 4 vertices after approximation
                // relatively large area (to filter out noisy contours)
                // and be convex.
                // Note: absolute value of an area is used because
                // area may be positive or negative - in accordance with the
                // contour orientation
                if( approx.size() == 4 &&
                    fabs(contourArea(Mat(approx))) > 1000 &&
                    fabs(contourArea(Mat(approx))) < maxSquareArea &&
                    isContourConvex(Mat(approx)) )
                {
                    double maxCosine = 0;
                    double minSideLen = 100000;
                    double maxSideLen = 0;
                    double sideRatio = 0;

                    for( int j = 2; j < 5; j++ )
                    {
                        // find the maximum cosine of the angle between joint edges
                        double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1]));
                        maxCosine = MAX(maxCosine, cosine);

                        // Find the maximum difference in length of adjacent
                        // sides
                        double sideLen = sqrt(pow((approx[j%4].x - approx[(j+1)%4].x), 2) + pow((approx[j%4].y - approx[(j+1)%4].y), 2));
                        minSideLen = MIN(minSideLen, sideLen);
                        maxSideLen = MAX(maxSideLen, sideLen);
                    }

                    sideRatio = minSideLen / maxSideLen;

                    std::cout << minSideLen << "  " << maxSideLen << "\n";

                    // if cosines of all angles are small
                    // (all angles are ~90 degree) then write quandrange
                    // vertices to resultant sequence
                    if( maxCosine < ((double) maxCosineThresh)/100 && sideRatio >= (double) sideRatioThresh/100 )
                        squares.push_back(approx);
                }
            }
        }
    //}
}

// the function draws all the squares in the image
static void drawSquares( Mat& image, const vector<vector<Point> >& squares )
{
    for( size_t i = 0; i < squares.size(); i++ )
    {
        const Point* p = &squares[i][0];
        int n = (int)squares[i].size();
        polylines(image, &p, &n, 1, true, Scalar(0,255,0), 3, CV_AA);

        std::cout << "x: " << squares[i][0].x << "  y: " << squares[i][0].y << "\n";

        // Only publish coordinates for one of the squares. Coordinates are
        // shifted over by half the camera resolution (which itself is scaled
        // down by a factor of two!) on each axis. The y coordinate is inverted
        // so up is positive.
        if (i == 0) {
            putText(image, "0", squares[0][0], FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255,0,0));
            putText(image, "1", squares[0][1], FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255,0,0));
            putText(image, "2", squares[0][2], FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255,0,0));
            putText(image, "3", squares[0][3], FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255,0,0));
            winCoords.x =   (squares[0][0].x + squares[0][2].x)/2 - 180;
            winCoords.y = -((squares[0][0].y + squares[0][2].y)/2 - 120);
            visPub.publish(winCoords);
        }
    }
}

int main(int argc, char** argv) {
    ros::init(argc, argv, "vision");
    ros::NodeHandle nh;
    visPub = nh.advertise<osuar_vision::windowCoordinates>("window_coordinates", 1);

    // Instantiate VideoCapture object. See here for details:
    // http://opencv.willowgarage.com/documentation/cpp/reading_and_writing_images_and_video.html
    VideoCapture cap(1);

    // Configure video. Our camera NEEDS the frame width to be set to 720
    // pixels.
    cap.set(CV_CAP_PROP_FRAME_WIDTH, 720);
    cap.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
    //cap.set(CV_CAP_PROP_FPS, 20);

    // Instantiate a Mat in which to store each video frame.
    Mat origFrame;
    Mat resizedFrame;   // Scaled-down from origFrame by factor of 2.
    Mat hsvFrame;   // Converted to HSV space from resizedFrame.
    Mat bwFrame;   // Black/white image after thresholding hsvFrame.

    namedWindow("origImage", 1);
    namedWindow("hsvImage", 1);
    namedWindow("bwImage", 1);
    cvNamedWindow("control panel");
    cvCreateTrackbar("threshold",   "control panel", &thresh,      300, NULL);
    cvCreateTrackbar("maxCosineThresh (x100)", "control panel", &maxCosineThresh, 100, NULL);
    cvCreateTrackbar("sideRatioThresh (x100)", "control panel", &sideRatioThresh, 100, NULL);
    cvCreateTrackbar("maxSquareArea", "control panel", &maxSquareArea, 100000, NULL);
    cvCreateTrackbar("wallHueLow",  "control panel", &wallHueLow,  179, NULL);
    cvCreateTrackbar("wallHueHigh", "control panel", &wallHueHigh, 179, NULL);
    cvCreateTrackbar("wallSatLow",  "control panel", &wallSatLow,  255, NULL);
    cvCreateTrackbar("wallSatHigh", "control panel", &wallSatHigh, 255, NULL);
    cvCreateTrackbar("wallValLow",  "control panel", &wallValLow,  255, NULL);
    cvCreateTrackbar("wallValHigh", "control panel", &wallValHigh, 255, NULL);
    vector<vector<Point> > squares;

    while (true) {
        // Capture image.
        cap >> origFrame;

        // Resize the image to increase processing rate. See here for details:
        // http://opencv.willowgarage.com/documentation/cpp/image_filtering.html
        pyrDown(origFrame, resizedFrame, Size(origFrame.cols/2, origFrame.rows/2));

        // Convert the frame to HSV. TODO: combine this with more filtering and
        // turn into function.
        cvtColor(resizedFrame, hsvFrame, CV_BGR2HSV);

        // Threshold hsvFrame for color of maze walls.
        inRange(hsvFrame, Scalar(wallHueLow,  wallSatLow,  wallValLow),
                          Scalar(wallHueHigh, wallSatHigh, wallValHigh), bwFrame);

        // Find and draw squares.
        findSquares(bwFrame, squares);
        drawSquares(resizedFrame, squares);

        // Show the image, with the squares overlaid.
        imshow("origImage", resizedFrame);
        imshow("bwImage", bwFrame);

        // Wait 5 milliseconds for a keypress.
        int c = waitKey(5);
        // Exit if the spacebar is pressed. NOTE: killing the program with
        // Ctrl+C sometimes stops OpenCV at a bad place and effects a kernel
        // panic! If you really like Ctrl+C, do so at your own risk!
        if ((char) c == 32) {
            return 0;
        }
    }

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2004-2006 The Regents of The University of Michigan
 * 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 the copyright holders 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.
 *
 * Authors: Kevin Lim
 */

#include "base/intmath.hh"
#include "cpu/pred/tournament.hh"

TournamentBP::TournamentBP(unsigned _localPredictorSize,
                           unsigned _localCtrBits,
                           unsigned _localHistoryTableSize,
                           unsigned _localHistoryBits,
                           unsigned _globalPredictorSize,
                           unsigned _globalCtrBits,
                           unsigned _globalHistoryBits,
                           unsigned _choicePredictorSize,
                           unsigned _choiceCtrBits,
                           unsigned _instShiftAmt)
    : localPredictorSize(_localPredictorSize),
      localCtrBits(_localCtrBits),
      localHistoryTableSize(_localHistoryTableSize),
      localHistoryBits(_localHistoryBits),
      globalPredictorSize(_globalPredictorSize),
      globalCtrBits(_globalCtrBits),
      globalHistoryBits(_globalHistoryBits),
      choicePredictorSize(_globalPredictorSize),
      choiceCtrBits(_choiceCtrBits),
      instShiftAmt(_instShiftAmt)
{
    if (!isPowerOf2(localPredictorSize)) {
        fatal("Invalid local predictor size!\n");
    }

    //Setup the array of counters for the local predictor
    localCtrs.resize(localPredictorSize);

    for (int i = 0; i < localPredictorSize; ++i)
        localCtrs[i].setBits(localCtrBits);

    localPredictorMask = floorPow2(localPredictorSize) - 1;

    if (!isPowerOf2(localHistoryTableSize)) {
        fatal("Invalid local history table size!\n");
    }

    //Setup the history table for the local table
    localHistoryTable.resize(localHistoryTableSize);

    for (int i = 0; i < localHistoryTableSize; ++i)
        localHistoryTable[i] = 0;

    // Setup the local history mask
    localHistoryMask = (1 << localHistoryBits) - 1;

    if (!isPowerOf2(globalPredictorSize)) {
        fatal("Invalid global predictor size!\n");
    }

    //Setup the array of counters for the global predictor
    globalCtrs.resize(globalPredictorSize);

    for (int i = 0; i < globalPredictorSize; ++i)
        globalCtrs[i].setBits(globalCtrBits);

    //Clear the global history
    globalHistory = 0;
    // Setup the global history mask
    globalHistoryMask = (1 << globalHistoryBits) - 1;

    if (!isPowerOf2(choicePredictorSize)) {
        fatal("Invalid choice predictor size!\n");
    }

    //Setup the array of counters for the choice predictor
    choiceCtrs.resize(choicePredictorSize);

    for (int i = 0; i < choicePredictorSize; ++i)
        choiceCtrs[i].setBits(choiceCtrBits);

    // @todo: Allow for different thresholds between the predictors.
    threshold = (1 << (localCtrBits - 1)) - 1;
    threshold = threshold / 2;
}

inline
unsigned
TournamentBP::calcLocHistIdx(Addr &branch_addr)
{
    // Get low order bits after removing instruction offset.
    return (branch_addr >> instShiftAmt) & (localHistoryTableSize - 1);
}

inline
void
TournamentBP::updateGlobalHistTaken()
{
    globalHistory = (globalHistory << 1) | 1;
    globalHistory = globalHistory & globalHistoryMask;
}

inline
void
TournamentBP::updateGlobalHistNotTaken()
{
    globalHistory = (globalHistory << 1);
    globalHistory = globalHistory & globalHistoryMask;
}

inline
void
TournamentBP::updateLocalHistTaken(unsigned local_history_idx)
{
    localHistoryTable[local_history_idx] =
        (localHistoryTable[local_history_idx] << 1) | 1;
}

inline
void
TournamentBP::updateLocalHistNotTaken(unsigned local_history_idx)
{
    localHistoryTable[local_history_idx] =
        (localHistoryTable[local_history_idx] << 1);
}

bool
TournamentBP::lookup(Addr &branch_addr, void * &bp_history)
{
    bool local_prediction;
    unsigned local_history_idx;
    unsigned local_predictor_idx;

    bool global_prediction;
    bool choice_prediction;

    //Lookup in the local predictor to get its branch prediction
    local_history_idx = calcLocHistIdx(branch_addr);
    local_predictor_idx = localHistoryTable[local_history_idx]
        & localPredictorMask;
    local_prediction = localCtrs[local_predictor_idx].read() > threshold;

    //Lookup in the global predictor to get its branch prediction
    global_prediction = globalCtrs[globalHistory].read() > threshold;

    //Lookup in the choice predictor to see which one to use
    choice_prediction = choiceCtrs[globalHistory].read() > threshold;

    // Create BPHistory and pass it back to be recorded.
    BPHistory *history = new BPHistory;
    history->globalHistory = globalHistory;
    history->localPredTaken = local_prediction;
    history->globalPredTaken = global_prediction;
    history->globalUsed = choice_prediction;
    bp_history = (void *)history;

    assert(globalHistory < globalPredictorSize &&
           local_history_idx < localHistoryTableSize &&
           local_predictor_idx < localPredictorSize);

    // Commented code is for doing speculative update of counters and
    // all histories.
    if (choice_prediction) {
        if (global_prediction) {
//            updateHistoriesTaken(local_history_idx);
//            globalCtrs[globalHistory].increment();
//            localCtrs[local_history_idx].increment();
            updateGlobalHistTaken();
            return true;
        } else {
//            updateHistoriesNotTaken(local_history_idx);
//            globalCtrs[globalHistory].decrement();
//            localCtrs[local_history_idx].decrement();
            updateGlobalHistNotTaken();
            return false;
        }
    } else {
        if (local_prediction) {
//            updateHistoriesTaken(local_history_idx);
//            globalCtrs[globalHistory].increment();
//            localCtrs[local_history_idx].increment();
            updateGlobalHistTaken();
            return true;
        } else {
//            updateHistoriesNotTaken(local_history_idx);
//            globalCtrs[globalHistory].decrement();
//            localCtrs[local_history_idx].decrement();
            updateGlobalHistNotTaken();
            return false;
        }
    }
}

void
TournamentBP::uncondBr(void * &bp_history)
{
    // Create BPHistory and pass it back to be recorded.
    BPHistory *history = new BPHistory;
    history->globalHistory = globalHistory;
    history->localPredTaken = true;
    history->globalPredTaken = true;
    bp_history = static_cast<void *>(history);

    updateGlobalHistTaken();
}

void
TournamentBP::update(Addr &branch_addr, bool taken, void *bp_history)
{
    unsigned local_history_idx;
    unsigned local_predictor_idx;
    unsigned local_predictor_hist;

    // Get the local predictor's current prediction
    local_history_idx = calcLocHistIdx(branch_addr);
    local_predictor_hist = localHistoryTable[local_history_idx];
    local_predictor_idx = local_predictor_hist & localPredictorMask;

    // Update the choice predictor to tell it which one was correct if
    // there was a prediction.
    if (bp_history) {
        BPHistory *history = static_cast<BPHistory *>(bp_history);
        if (history->localPredTaken != history->globalPredTaken) {
            // If the local prediction matches the actual outcome,
            // decerement the counter.  Otherwise increment the
            // counter.
            if (history->localPredTaken == taken) {
                choiceCtrs[globalHistory].decrement();
            } else if (history->globalPredTaken == taken){
                choiceCtrs[globalHistory].increment();
            }
        }

        // We're done with this history, now delete it.
        delete history;
    }

    assert(globalHistory < globalPredictorSize &&
           local_history_idx < localHistoryTableSize &&
           local_predictor_idx < localPredictorSize);

    // Update the counters and local history with the proper
    // resolution of the branch.  Global history is updated
    // speculatively and restored upon squash() calls, so it does not
    // need to be updated.
    if (taken) {
        localCtrs[local_predictor_idx].increment();
        globalCtrs[globalHistory].increment();

        updateLocalHistTaken(local_history_idx);
    } else {
        localCtrs[local_predictor_idx].decrement();
        globalCtrs[globalHistory].decrement();

        updateLocalHistNotTaken(local_history_idx);
    }
}

void
TournamentBP::squash(void *bp_history)
{
    BPHistory *history = static_cast<BPHistory *>(bp_history);

    // Restore global history to state prior to this branch.
    globalHistory = history->globalHistory;

    // Delete this BPHistory now that we're done with it.
    delete history;
}

#ifdef DEBUG
int
TournamentBP::BPHistory::newCount = 0;
#endif
<commit_msg>BPRED: Fixed the treshold-bug in the tournament predictor.<commit_after>/*
 * Copyright (c) 2004-2006 The Regents of The University of Michigan
 * 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 the copyright holders 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.
 *
 * Authors: Kevin Lim
 */

#include "base/intmath.hh"
#include "cpu/pred/tournament.hh"

TournamentBP::TournamentBP(unsigned _localPredictorSize,
                           unsigned _localCtrBits,
                           unsigned _localHistoryTableSize,
                           unsigned _localHistoryBits,
                           unsigned _globalPredictorSize,
                           unsigned _globalCtrBits,
                           unsigned _globalHistoryBits,
                           unsigned _choicePredictorSize,
                           unsigned _choiceCtrBits,
                           unsigned _instShiftAmt)
    : localPredictorSize(_localPredictorSize),
      localCtrBits(_localCtrBits),
      localHistoryTableSize(_localHistoryTableSize),
      localHistoryBits(_localHistoryBits),
      globalPredictorSize(_globalPredictorSize),
      globalCtrBits(_globalCtrBits),
      globalHistoryBits(_globalHistoryBits),
      choicePredictorSize(_globalPredictorSize),
      choiceCtrBits(_choiceCtrBits),
      instShiftAmt(_instShiftAmt)
{
    if (!isPowerOf2(localPredictorSize)) {
        fatal("Invalid local predictor size!\n");
    }

    //Setup the array of counters for the local predictor
    localCtrs.resize(localPredictorSize);

    for (int i = 0; i < localPredictorSize; ++i)
        localCtrs[i].setBits(localCtrBits);

    localPredictorMask = floorPow2(localPredictorSize) - 1;

    if (!isPowerOf2(localHistoryTableSize)) {
        fatal("Invalid local history table size!\n");
    }

    //Setup the history table for the local table
    localHistoryTable.resize(localHistoryTableSize);

    for (int i = 0; i < localHistoryTableSize; ++i)
        localHistoryTable[i] = 0;

    // Setup the local history mask
    localHistoryMask = (1 << localHistoryBits) - 1;

    if (!isPowerOf2(globalPredictorSize)) {
        fatal("Invalid global predictor size!\n");
    }

    //Setup the array of counters for the global predictor
    globalCtrs.resize(globalPredictorSize);

    for (int i = 0; i < globalPredictorSize; ++i)
        globalCtrs[i].setBits(globalCtrBits);

    //Clear the global history
    globalHistory = 0;
    // Setup the global history mask
    globalHistoryMask = (1 << globalHistoryBits) - 1;

    if (!isPowerOf2(choicePredictorSize)) {
        fatal("Invalid choice predictor size!\n");
    }

    //Setup the array of counters for the choice predictor
    choiceCtrs.resize(choicePredictorSize);

    for (int i = 0; i < choicePredictorSize; ++i)
        choiceCtrs[i].setBits(choiceCtrBits);

    // @todo: Allow for different thresholds between the predictors.
    threshold = (1 << (localCtrBits - 1)) - 1;
}

inline
unsigned
TournamentBP::calcLocHistIdx(Addr &branch_addr)
{
    // Get low order bits after removing instruction offset.
    return (branch_addr >> instShiftAmt) & (localHistoryTableSize - 1);
}

inline
void
TournamentBP::updateGlobalHistTaken()
{
    globalHistory = (globalHistory << 1) | 1;
    globalHistory = globalHistory & globalHistoryMask;
}

inline
void
TournamentBP::updateGlobalHistNotTaken()
{
    globalHistory = (globalHistory << 1);
    globalHistory = globalHistory & globalHistoryMask;
}

inline
void
TournamentBP::updateLocalHistTaken(unsigned local_history_idx)
{
    localHistoryTable[local_history_idx] =
        (localHistoryTable[local_history_idx] << 1) | 1;
}

inline
void
TournamentBP::updateLocalHistNotTaken(unsigned local_history_idx)
{
    localHistoryTable[local_history_idx] =
        (localHistoryTable[local_history_idx] << 1);
}

bool
TournamentBP::lookup(Addr &branch_addr, void * &bp_history)
{
    bool local_prediction;
    unsigned local_history_idx;
    unsigned local_predictor_idx;

    bool global_prediction;
    bool choice_prediction;

    //Lookup in the local predictor to get its branch prediction
    local_history_idx = calcLocHistIdx(branch_addr);
    local_predictor_idx = localHistoryTable[local_history_idx]
        & localPredictorMask;
    local_prediction = localCtrs[local_predictor_idx].read() > threshold;

    //Lookup in the global predictor to get its branch prediction
    global_prediction = globalCtrs[globalHistory].read() > threshold;

    //Lookup in the choice predictor to see which one to use
    choice_prediction = choiceCtrs[globalHistory].read() > threshold;

    // Create BPHistory and pass it back to be recorded.
    BPHistory *history = new BPHistory;
    history->globalHistory = globalHistory;
    history->localPredTaken = local_prediction;
    history->globalPredTaken = global_prediction;
    history->globalUsed = choice_prediction;
    bp_history = (void *)history;

    assert(globalHistory < globalPredictorSize &&
           local_history_idx < localHistoryTableSize &&
           local_predictor_idx < localPredictorSize);

    // Commented code is for doing speculative update of counters and
    // all histories.
    if (choice_prediction) {
        if (global_prediction) {
//            updateHistoriesTaken(local_history_idx);
//            globalCtrs[globalHistory].increment();
//            localCtrs[local_history_idx].increment();
            updateGlobalHistTaken();
            return true;
        } else {
//            updateHistoriesNotTaken(local_history_idx);
//            globalCtrs[globalHistory].decrement();
//            localCtrs[local_history_idx].decrement();
            updateGlobalHistNotTaken();
            return false;
        }
    } else {
        if (local_prediction) {
//            updateHistoriesTaken(local_history_idx);
//            globalCtrs[globalHistory].increment();
//            localCtrs[local_history_idx].increment();
            updateGlobalHistTaken();
            return true;
        } else {
//            updateHistoriesNotTaken(local_history_idx);
//            globalCtrs[globalHistory].decrement();
//            localCtrs[local_history_idx].decrement();
            updateGlobalHistNotTaken();
            return false;
        }
    }
}

void
TournamentBP::uncondBr(void * &bp_history)
{
    // Create BPHistory and pass it back to be recorded.
    BPHistory *history = new BPHistory;
    history->globalHistory = globalHistory;
    history->localPredTaken = true;
    history->globalPredTaken = true;
    bp_history = static_cast<void *>(history);

    updateGlobalHistTaken();
}

void
TournamentBP::update(Addr &branch_addr, bool taken, void *bp_history)
{
    unsigned local_history_idx;
    unsigned local_predictor_idx;
    unsigned local_predictor_hist;

    // Get the local predictor's current prediction
    local_history_idx = calcLocHistIdx(branch_addr);
    local_predictor_hist = localHistoryTable[local_history_idx];
    local_predictor_idx = local_predictor_hist & localPredictorMask;

    // Update the choice predictor to tell it which one was correct if
    // there was a prediction.
    if (bp_history) {
        BPHistory *history = static_cast<BPHistory *>(bp_history);
        if (history->localPredTaken != history->globalPredTaken) {
            // If the local prediction matches the actual outcome,
            // decerement the counter.  Otherwise increment the
            // counter.
            if (history->localPredTaken == taken) {
                choiceCtrs[globalHistory].decrement();
            } else if (history->globalPredTaken == taken){
                choiceCtrs[globalHistory].increment();
            }
        }

        // We're done with this history, now delete it.
        delete history;
    }

    assert(globalHistory < globalPredictorSize &&
           local_history_idx < localHistoryTableSize &&
           local_predictor_idx < localPredictorSize);

    // Update the counters and local history with the proper
    // resolution of the branch.  Global history is updated
    // speculatively and restored upon squash() calls, so it does not
    // need to be updated.
    if (taken) {
        localCtrs[local_predictor_idx].increment();
        globalCtrs[globalHistory].increment();

        updateLocalHistTaken(local_history_idx);
    } else {
        localCtrs[local_predictor_idx].decrement();
        globalCtrs[globalHistory].decrement();

        updateLocalHistNotTaken(local_history_idx);
    }
}

void
TournamentBP::squash(void *bp_history)
{
    BPHistory *history = static_cast<BPHistory *>(bp_history);

    // Restore global history to state prior to this branch.
    globalHistory = history->globalHistory;

    // Delete this BPHistory now that we're done with it.
    delete history;
}

#ifdef DEBUG
int
TournamentBP::BPHistory::newCount = 0;
#endif
<|endoftext|>


<commit_before>//
//  FacebookRewardVideoAd.cpp
//  ee_x
//
//  Created by Zinge on 10/11/17.
//
//

#include "ee/facebook_ads/private/FacebookRewardedAd.hpp"

#include <cassert>

#include <ee/ads/internal/AsyncHelper.hpp>
#include <ee/core/IMessageBridge.hpp>
#include <ee/core/Logger.hpp>
#include <ee/core/Utils.hpp>

#include "ee/facebook_ads/FacebookAdsBridge.hpp"

namespace ee {
namespace facebook_ads {
using Self = RewardedAd;

Self::RewardedAd(
    IMessageBridge& bridge, const Logger& logger,
    const std::shared_ptr<ads::IAsyncHelper<IRewardedAdResult>>& displayer,
    Bridge* plugin, const std::string& adId)
    : bridge_(bridge)
    , logger_(logger)
    , displayer_(displayer)
    , plugin_(plugin)
    , adId_(adId)
    , messageHelper_("FacebookAdsRewardedAd", adId) {
    logger_.debug("%s", __PRETTY_FUNCTION__);
    loader_ = std::make_unique<ads::AsyncHelper<bool>>();

    bridge_.registerHandler(
        [this](const std::string& message) {
            onLoaded();
            return "";
        },
        messageHelper_.onLoaded());
    bridge_.registerHandler(
        [this](const std::string& message) {
            onFailedToLoad(message);
            return "";
        },
        messageHelper_.onFailedToLoad());
    bridge_.registerHandler(
        [this](const std::string& message) {
            onClicked();
            return "";
        },
        messageHelper_.onClicked());
    bridge_.registerHandler(
        [this](const std::string& message) {
            onClosed(core::toBool(message));
            return "";
        },
        messageHelper_.onClosed());
}

Self::~RewardedAd() {}

void Self::destroy() {
    logger_.debug("%s", __PRETTY_FUNCTION__);

    bridge_.deregisterHandler(messageHelper_.onLoaded());
    bridge_.deregisterHandler(messageHelper_.onFailedToLoad());
    bridge_.deregisterHandler(messageHelper_.onClicked());
    bridge_.deregisterHandler(messageHelper_.onClosed());

    auto succeeded = plugin_->destroyRewardedAd(adId_);
    assert(succeeded);
}

bool Self::createInternalAd() {
    logger_.debug("%s", __PRETTY_FUNCTION__);
    auto response = bridge_.call(messageHelper_.createInternalAd());
    return core::toBool(response);
}

bool Self::destroyInternalAd() {
    logger_.debug("%s", __PRETTY_FUNCTION__);
    auto response = bridge_.call(messageHelper_.destroyInternalAd());
    return core::toBool(response);
}

bool Self::isLoaded() const {
    auto response = bridge_.call(messageHelper_.isLoaded());
    return core::toBool(response);
}

Task<bool> Self::load() {
    logger_.debug("%s: loading = %s", __PRETTY_FUNCTION__,
                  core::toString(loader_->isProcessing()).c_str());
    auto result = co_await loader_->process(
        [this] { //
            bridge_.call(messageHelper_.load());
        },
        [this](bool result) {
            if (result) {
                // OK.
            } else {
                // Reinitialize internal ad if it was failed to load.
                destroyInternalAd();
                createInternalAd();
            }
        });
    co_return result;
}

Task<IRewardedAdResult> Self::show() {
    logger_.debug("%s", __PRETTY_FUNCTION__);
    auto result = co_await displayer_->process(
        [this] { //
            bridge_.call(messageHelper_.show());
        },
        [this](IRewardedAdResult result) {
            if (result == IRewardedAdResult::Failed) {
                // Failed to show.
            } else {
                destroyInternalAd();
                createInternalAd();
            }
        });
    co_return result;
}

void Self::onLoaded() {
    logger_.debug("%s: loading = %s", __PRETTY_FUNCTION__,
                  core::toString(loader_->isProcessing()).c_str());
    if (loader_->isProcessing()) {
        loader_->resolve(true);
    } else {
        assert(false);
    }
    dispatchEvent([](auto&& observer) {
        if (observer.onLoaded) {
            observer.onLoaded();
        }
    });
}

void Self::onFailedToLoad(const std::string& message) {
    logger_.debug("%s: message = %s loading = %s", __PRETTY_FUNCTION__,
                  message.c_str(),
                  core::toString(loader_->isProcessing()).c_str());
    if (loader_->isProcessing()) {
        loader_->resolve(false);
    } else {
        assert(false);
    }
}

void Self::onClicked() {
    logger_.debug("%s", __PRETTY_FUNCTION__);
    dispatchEvent([](auto&& observer) {
        if (observer.onClicked) {
            observer.onClicked();
        }
    });
}

void Self::onClosed(bool rewarded) {
    logger_.debug("%s: rewarded = %s displaying = %s", __PRETTY_FUNCTION__,
                  core::toString(rewarded).c_str(),
                  core::toString(displayer_->isProcessing()).c_str());
    if (displayer_->isProcessing()) {
        displayer_->resolve(rewarded ? IRewardedAdResult::Completed
                                     : IRewardedAdResult::Canceled);
    } else {
        assert(false);
    }
}
} // namespace facebook_ads
} // namespace ee
<commit_msg>Fix message tag.<commit_after>//
//  FacebookRewardVideoAd.cpp
//  ee_x
//
//  Created by Zinge on 10/11/17.
//
//

#include "ee/facebook_ads/private/FacebookRewardedAd.hpp"

#include <cassert>

#include <ee/ads/internal/AsyncHelper.hpp>
#include <ee/core/IMessageBridge.hpp>
#include <ee/core/Logger.hpp>
#include <ee/core/Utils.hpp>

#include "ee/facebook_ads/FacebookAdsBridge.hpp"

namespace ee {
namespace facebook_ads {
using Self = RewardedAd;

Self::RewardedAd(
    IMessageBridge& bridge, const Logger& logger,
    const std::shared_ptr<ads::IAsyncHelper<IRewardedAdResult>>& displayer,
    Bridge* plugin, const std::string& adId)
    : bridge_(bridge)
    , logger_(logger)
    , displayer_(displayer)
    , plugin_(plugin)
    , adId_(adId)
    , messageHelper_("FacebookRewardedAd", adId) {
    logger_.debug("%s", __PRETTY_FUNCTION__);
    loader_ = std::make_unique<ads::AsyncHelper<bool>>();

    bridge_.registerHandler(
        [this](const std::string& message) {
            onLoaded();
            return "";
        },
        messageHelper_.onLoaded());
    bridge_.registerHandler(
        [this](const std::string& message) {
            onFailedToLoad(message);
            return "";
        },
        messageHelper_.onFailedToLoad());
    bridge_.registerHandler(
        [this](const std::string& message) {
            onClicked();
            return "";
        },
        messageHelper_.onClicked());
    bridge_.registerHandler(
        [this](const std::string& message) {
            onClosed(core::toBool(message));
            return "";
        },
        messageHelper_.onClosed());
}

Self::~RewardedAd() {}

void Self::destroy() {
    logger_.debug("%s", __PRETTY_FUNCTION__);

    bridge_.deregisterHandler(messageHelper_.onLoaded());
    bridge_.deregisterHandler(messageHelper_.onFailedToLoad());
    bridge_.deregisterHandler(messageHelper_.onClicked());
    bridge_.deregisterHandler(messageHelper_.onClosed());

    auto succeeded = plugin_->destroyRewardedAd(adId_);
    assert(succeeded);
}

bool Self::createInternalAd() {
    logger_.debug("%s", __PRETTY_FUNCTION__);
    auto response = bridge_.call(messageHelper_.createInternalAd());
    return core::toBool(response);
}

bool Self::destroyInternalAd() {
    logger_.debug("%s", __PRETTY_FUNCTION__);
    auto response = bridge_.call(messageHelper_.destroyInternalAd());
    return core::toBool(response);
}

bool Self::isLoaded() const {
    auto response = bridge_.call(messageHelper_.isLoaded());
    return core::toBool(response);
}

Task<bool> Self::load() {
    logger_.debug("%s: loading = %s", __PRETTY_FUNCTION__,
                  core::toString(loader_->isProcessing()).c_str());
    auto result = co_await loader_->process(
        [this] { //
            bridge_.call(messageHelper_.load());
        },
        [this](bool result) {
            if (result) {
                // OK.
            } else {
                // Reinitialize internal ad if it was failed to load.
                destroyInternalAd();
                createInternalAd();
            }
        });
    co_return result;
}

Task<IRewardedAdResult> Self::show() {
    logger_.debug("%s", __PRETTY_FUNCTION__);
    auto result = co_await displayer_->process(
        [this] { //
            bridge_.call(messageHelper_.show());
        },
        [this](IRewardedAdResult result) {
            if (result == IRewardedAdResult::Failed) {
                // Failed to show.
            } else {
                destroyInternalAd();
                createInternalAd();
            }
        });
    co_return result;
}

void Self::onLoaded() {
    logger_.debug("%s: loading = %s", __PRETTY_FUNCTION__,
                  core::toString(loader_->isProcessing()).c_str());
    if (loader_->isProcessing()) {
        loader_->resolve(true);
    } else {
        assert(false);
    }
    dispatchEvent([](auto&& observer) {
        if (observer.onLoaded) {
            observer.onLoaded();
        }
    });
}

void Self::onFailedToLoad(const std::string& message) {
    logger_.debug("%s: message = %s loading = %s", __PRETTY_FUNCTION__,
                  message.c_str(),
                  core::toString(loader_->isProcessing()).c_str());
    if (loader_->isProcessing()) {
        loader_->resolve(false);
    } else {
        assert(false);
    }
}

void Self::onClicked() {
    logger_.debug("%s", __PRETTY_FUNCTION__);
    dispatchEvent([](auto&& observer) {
        if (observer.onClicked) {
            observer.onClicked();
        }
    });
}

void Self::onClosed(bool rewarded) {
    logger_.debug("%s: rewarded = %s displaying = %s", __PRETTY_FUNCTION__,
                  core::toString(rewarded).c_str(),
                  core::toString(displayer_->isProcessing()).c_str());
    if (displayer_->isProcessing()) {
        displayer_->resolve(rewarded ? IRewardedAdResult::Completed
                                     : IRewardedAdResult::Canceled);
    } else {
        assert(false);
    }
}
} // namespace facebook_ads
} // namespace ee
<|endoftext|>


<commit_before>#ifndef MJOLNIR_IMPLICIT_MEMBRANE_POTENTIAL
#define MJOLNIR_IMPLICIT_MEMBRANE_POTENTIAL
#include <mjolnir/core/System.hpp>
#include <cmath>

namespace mjolnir
{

/* Implicit membrane potential                                                *
 *  V(z) = ma * tanh(be * (|z| - th/2))                                       *
 * dV/dr = (z/|z|) * ma * (cosh^2(be * (|z| - th/2)))                         *
 * Cutoff ratio ensure 1/1000 accuracy.                                       */
template<typename traitsT>
class ImplicitMembranePotential
{
  public:
    typedef traitsT traits_type;
    typedef typename traits_type::real_type real_type;
    typedef typename traits_type::coordinate_type coordinate_type;
    typedef real_type parameter_type;

    static constexpr real_type cutoff_ratio = 4.0;

  public:
    ImplicitMembranePotential(
        const real_type thick, const real_type magnitude, const real_type bend,
        const std::vector<parameter_type>& hydrophobicities)
        : half_thick_(thick * 0.5), interaction_magnitude_(magnitude),
          bend_(bend), hydrophobicities_(hydrophobicities)
    {}
    ImplicitMembranePotential(
        const real_type thick, const real_type magnitude, const real_type bend,
        std::vector<parameter_type>&& hydrophobicities)
        : half_thick_(thick * 0.5), interaction_magnitude_(magnitude),
          bend_(bend), hydrophobicities_(std::move(hydrophobicities))
    {}
    ~ImplicitMembranePotential() = default;

    real_type potential(const std::size_t i, const real_type z) const noexcept
    {
        return hydrophobicities_[i] * interaction_magnitude_ *
            std::tanh(bend_ * (std::abs(z) - half_thick_));
    }
    real_type derivative(const std::size_t i, const real_type z) const noexcept
    {
        return hydrophobicities_[i] * std::copysign(1.0, z) *
            interaction_magnitude_ * bend_ /
            std::pow((std::cosh(bend_ * (std::abs(z) - half_thick_))), 2);
    }
    real_type max_cutoff_length() const noexcept
    {
        return cutoff_ratio / this->bend_ + this->half_thick_;
    }

    // nothing to be done if system parameter (e.g. temperature) changes
    void update(const System<traitsT>&) const noexcept {return;}

    std::vector<std::size_t> participants() const
    {
        std::vector<std::size_t> retval;
        retval.reserve(this->hydrophobicities_.size());
        for(std::size_t i=0; i<this->hydrophobicities_.size(); ++i)
        {
            if(this->hydrophobicities_[i] != 0)
            {
                retval.push_back(i);
            }
        }
        return retval;
    }

    std::string name() const {return "ImplicitMembrane";}

    real_type  half_thick() const noexcept {return half_thick_;}
    real_type& half_thick()       noexcept {return half_thick_;}

    real_type  bend() const noexcept {return bend_;}
    real_type& bend()       noexcept {return bend_;}

    real_type  interaction_magnitude() const noexcept
    {return interaction_magnitude_;}
    real_type& interaction_magnitude()       noexcept
    {return interaction_magnitude_;}

  private:

    real_type half_thick_;            // half of thickness of the membrane.
    real_type interaction_magnitude_; // overall scaling parameter.
    real_type bend_;                  // the slope of tanh carve.
    std::vector<parameter_type> hydrophobicities_;
};

template<typename traitsT>
constexpr typename ImplicitMembranePotential<traitsT>::real_type
ImplicitMembranePotential<traitsT>::cutoff_ratio;

} // mjolnir
#endif /* MJOLNIR_IMPLICIT_MEMBRANE_POTENTIAL */
<commit_msg>change return type of potential::name<commit_after>#ifndef MJOLNIR_IMPLICIT_MEMBRANE_POTENTIAL
#define MJOLNIR_IMPLICIT_MEMBRANE_POTENTIAL
#include <mjolnir/core/System.hpp>
#include <cmath>

namespace mjolnir
{
/* Implicit membrane potential                                                *
 *  V(z) = k * tanh(bend * (|z| - thick/2))                                   *
 * dV/dr = (z/|z|) * k * (cosh^2(bend * (|z| - thick/2)))                     *
 *                 y                                                          *
 *  _________      ^      _______                                             *
 *  _________\_____|_____/______x                                             *
 *  -thick/2  \____|____/ thick/2                                             *
 *               -k|                                                          *
 * Cutoff ratio ensure 1/1000 accuracy.                                       */
template<typename traitsT>
class ImplicitMembranePotential
{
  public:
    typedef traitsT traits_type;
    typedef typename traits_type::real_type real_type;
    typedef typename traits_type::coordinate_type coordinate_type;
    typedef real_type parameter_type;

    static constexpr real_type cutoff_ratio = 4.0;

  public:
    ImplicitMembranePotential(
        const real_type thick, const real_type magnitude, const real_type bend,
        const std::vector<parameter_type>& hydrophobicities)
        : half_thick_(thick * 0.5), interaction_magnitude_(magnitude),
          bend_(bend), hydrophobicities_(hydrophobicities)
    {}
    ImplicitMembranePotential(
        const real_type thick, const real_type magnitude, const real_type bend,
        std::vector<parameter_type>&& hydrophobicities)
        : half_thick_(thick * 0.5), interaction_magnitude_(magnitude),
          bend_(bend), hydrophobicities_(std::move(hydrophobicities))
    {}
    ~ImplicitMembranePotential() = default;

    real_type potential(const std::size_t i, const real_type z) const noexcept
    {
        return hydrophobicities_[i] * interaction_magnitude_ *
            std::tanh(bend_ * (std::abs(z) - half_thick_));
    }
    real_type derivative(const std::size_t i, const real_type z) const noexcept
    {
        return hydrophobicities_[i] * std::copysign(1.0, z) *
            interaction_magnitude_ * bend_ /
            std::pow((std::cosh(bend_ * (std::abs(z) - half_thick_))), 2);
    }
    real_type max_cutoff_length() const noexcept
    {
        return cutoff_ratio / this->bend_ + this->half_thick_;
    }

    // nothing to be done if system parameter (e.g. temperature) changes
    void update(const System<traitsT>&) const noexcept {return;}

    std::vector<std::size_t> participants() const
    {
        std::vector<std::size_t> retval;
        retval.reserve(this->hydrophobicities_.size());
        for(std::size_t i=0; i<this->hydrophobicities_.size(); ++i)
        {
            if(this->hydrophobicities_[i] != 0)
            {
                retval.push_back(i);
            }
        }
        return retval;
    }

    const char* name() const noexcept {return "ImplicitMembrane";}

    real_type  half_thick() const noexcept {return half_thick_;}
    real_type& half_thick()       noexcept {return half_thick_;}

    real_type  bend() const noexcept {return bend_;}
    real_type& bend()       noexcept {return bend_;}

    real_type  interaction_magnitude() const noexcept
    {return interaction_magnitude_;}
    real_type& interaction_magnitude()       noexcept
    {return interaction_magnitude_;}

  private:

    real_type half_thick_;            // half of thickness of the membrane.
    real_type interaction_magnitude_; // overall scaling parameter.
    real_type bend_;                  // the slope of tanh carve.
    std::vector<parameter_type> hydrophobicities_;
};

template<typename traitsT>
constexpr typename ImplicitMembranePotential<traitsT>::real_type
ImplicitMembranePotential<traitsT>::cutoff_ratio;

} // mjolnir
#endif /* MJOLNIR_IMPLICIT_MEMBRANE_POTENTIAL */
<|endoftext|>