<commit_before>/*
 * Copyright (C) 2010 Google Inc. 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 Google Inc. 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.
 */

#include "config.h"
#include "platform/blob/BlobRegistry.h"

#include "platform/blob/BlobData.h"
#include "platform/blob/BlobURL.h"
#include "platform/weborigin/SecurityOrigin.h"
#include "platform/weborigin/SecurityOriginCache.h"
#include "public/platform/Platform.h"
#include "public/platform/WebBlobData.h"
#include "public/platform/WebBlobRegistry.h"
#include "public/platform/WebString.h"
#include "public/platform/WebTraceLocation.h"
#include "wtf/Assertions.h"
#include "wtf/HashMap.h"
#include "wtf/MainThread.h"
#include "wtf/RefPtr.h"
#include "wtf/ThreadSpecific.h"
#include "wtf/Threading.h"
#include "wtf/text/StringHash.h"
#include "wtf/text/WTFString.h"

namespace blink {

class BlobOriginCache : public SecurityOriginCache {
public:
    BlobOriginCache();
    virtual SecurityOrigin* cachedOrigin(const KURL&) override;
};

struct BlobRegistryContext {
    WTF_MAKE_FAST_ALLOCATED(BlobRegistryContext);
public:
    BlobRegistryContext(const KURL& url, PassOwnPtr<BlobData> blobData)
        : url(url.copy())
        , blobData(blobData)
    {
        this->blobData->detachFromCurrentThread();
    }

    BlobRegistryContext(const KURL& url, const String& type)
        : url(url.copy())
        , type(type.isolatedCopy())
    {
    }

    BlobRegistryContext(const KURL& url, const KURL& srcURL)
        : url(url.copy())
        , srcURL(srcURL.copy())
    {
    }

    BlobRegistryContext(const KURL& url, PassRefPtr<RawData> streamData)
        : url(url.copy())
        , streamData(streamData)
    {
    }

    BlobRegistryContext(const KURL& url)
        : url(url.copy())
    {
    }

    KURL url;
    KURL srcURL;
    OwnPtr<BlobData> blobData;
    PassRefPtr<RawData> streamData;
    String type;
};

static WebBlobRegistry* blobRegistry()
{
    return Platform::current()->blobRegistry();
}

typedef HashMap<String, RefPtr<SecurityOrigin>> BlobURLOriginMap;
static ThreadSpecific<BlobURLOriginMap>& originMap()
{
    // We want to create the BlobOriginCache exactly once because it is shared by all the threads.
    AtomicallyInitializedStaticReference(BlobOriginCache, cache, new BlobOriginCache);
    (void)cache; // BlobOriginCache's constructor does the interesting work.

    AtomicallyInitializedStaticReference(ThreadSpecific<BlobURLOriginMap>, map, new ThreadSpecific<BlobURLOriginMap>);
    return map;
}

static void saveToOriginMap(SecurityOrigin* origin, const KURL& url)
{
    // If the blob URL contains null origin, as in the context with unique
    // security origin or file URL, save the mapping between url and origin so
    // that the origin can be retrived when doing security origin check.
    if (origin && BlobURL::getOrigin(url) == "null")
        originMap()->add(url.string(), origin);
}

static void removeFromOriginMap(const KURL& url)
{
    if (BlobURL::getOrigin(url) == "null")
        originMap()->remove(url.string());
}

void BlobRegistry::registerBlobData(const String& uuid, PassOwnPtr<BlobData> data)
{
    blobRegistry()->registerBlobData(uuid, WebBlobData(data));
}

void BlobRegistry::addBlobDataRef(const String& uuid)
{
    blobRegistry()->addBlobDataRef(uuid);
}

void BlobRegistry::removeBlobDataRef(const String& uuid)
{
    blobRegistry()->removeBlobDataRef(uuid);
}

void BlobRegistry::registerPublicBlobURL(SecurityOrigin* origin, const KURL& url, PassRefPtr<BlobDataHandle> handle)
{
    saveToOriginMap(origin, url);
    blobRegistry()->registerPublicBlobURL(url, handle->uuid());
}

void BlobRegistry::revokePublicBlobURL(const KURL& url)
{
    removeFromOriginMap(url);
    blobRegistry()->revokePublicBlobURL(url);
}

static void registerStreamURLTask(PassOwnPtr<BlobRegistryContext> blobRegistryContext)
{
    if (WebBlobRegistry* registry = blobRegistry())
        registry->registerStreamURL(blobRegistryContext->url, blobRegistryContext->type);
}

void BlobRegistry::registerStreamURL(const KURL& url, const String& type)
{
    if (isMainThread()) {
        if (WebBlobRegistry* registry = blobRegistry())
            registry->registerStreamURL(url, type);
    } else {
        OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url, type));
        Platform::current()->mainThread()->postTask(FROM_HERE, bind(&registerStreamURLTask, context.release()));
    }
}

static void registerStreamURLFromTask(PassOwnPtr<BlobRegistryContext> blobRegistryContext)
{
    if (WebBlobRegistry* registry = blobRegistry())
        registry->registerStreamURL(blobRegistryContext->url, blobRegistryContext->srcURL);
}

void BlobRegistry::registerStreamURL(SecurityOrigin* origin, const KURL& url, const KURL& srcURL)
{
    saveToOriginMap(origin, url);

    if (isMainThread()) {
        if (WebBlobRegistry* registry = blobRegistry())
            registry->registerStreamURL(url, srcURL);
    } else {
        OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url, srcURL));
        Platform::current()->mainThread()->postTask(FROM_HERE, bind(&registerStreamURLFromTask, context.release()));
    }
}

static void addDataToStreamTask(PassOwnPtr<BlobRegistryContext> blobRegistryContext)
{
    if (WebBlobRegistry* registry = blobRegistry()) {
        RefPtr<RawData> data(blobRegistryContext->streamData);
        registry->addDataToStream(blobRegistryContext->url, data->data(), data->length());
    }
}

void BlobRegistry::addDataToStream(const KURL& url, PassRefPtr<RawData> streamData)
{
    if (isMainThread()) {
        if (WebBlobRegistry* registry = blobRegistry())
            registry->addDataToStream(url, streamData->data(), streamData->length());
    } else {
        OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url, streamData));
        Platform::current()->mainThread()->postTask(FROM_HERE, bind(&addDataToStreamTask, context.release()));
    }
}

static void flushStreamTask(PassOwnPtr<BlobRegistryContext> blobRegistryContext)
{
    if (WebBlobRegistry* registry = blobRegistry())
        registry->flushStream(blobRegistryContext->url);
}

void BlobRegistry::flushStream(const KURL& url)
{
    if (isMainThread()) {
        if (WebBlobRegistry* registry = blobRegistry())
            registry->flushStream(url);
    } else {
        OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url));
        Platform::current()->mainThread()->postTask(FROM_HERE, bind(&flushStreamTask, context.release()));
    }
}

static void finalizeStreamTask(PassOwnPtr<BlobRegistryContext> blobRegistryContext)
{
    if (WebBlobRegistry* registry = blobRegistry())
        registry->finalizeStream(blobRegistryContext->url);
}

void BlobRegistry::finalizeStream(const KURL& url)
{
    if (isMainThread()) {
        if (WebBlobRegistry* registry = blobRegistry())
            registry->finalizeStream(url);
    } else {
        OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url));
        Platform::current()->mainThread()->postTask(FROM_HERE, bind(&finalizeStreamTask, context.release()));
    }
}

static void abortStreamTask(PassOwnPtr<BlobRegistryContext> blobRegistryContext)
{
    if (WebBlobRegistry* registry = blobRegistry())
        registry->abortStream(blobRegistryContext->url);
}

void BlobRegistry::abortStream(const KURL& url)
{
    if (isMainThread()) {
        if (WebBlobRegistry* registry = blobRegistry())
            registry->abortStream(url);
    } else {
        OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url));
        Platform::current()->mainThread()->postTask(FROM_HERE, bind(&abortStreamTask, context.release()));
    }
}

static void unregisterStreamURLTask(PassOwnPtr<BlobRegistryContext> blobRegistryContext)
{
    if (WebBlobRegistry* registry = blobRegistry())
        registry->unregisterStreamURL(blobRegistryContext->url);
}

void BlobRegistry::unregisterStreamURL(const KURL& url)
{
    removeFromOriginMap(url);

    if (isMainThread()) {
        if (WebBlobRegistry* registry = blobRegistry())
            registry->unregisterStreamURL(url);
    } else {
        OwnPtr<BlobRegistryContext> context = adoptPtr(new BlobRegistryContext(url));
        Platform::current()->mainThread()->postTask(FROM_HERE, bind(&unregisterStreamURLTask, context.release()));
    }
}

BlobOriginCache::BlobOriginCache()
{
    SecurityOrigin::setCache(this);
}

SecurityOrigin* BlobOriginCache::cachedOrigin(const KURL& url)
{
    if (url.protocolIs("blob"))
        return originMap()->get(url.string());
    return 0;
}

} // namespace blink
<commit_msg>Use threadSafeBind() in BlobRegistry and remove BlobRegistryContext<commit_after>/*
 * Copyright (C) 2010 Google Inc. 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 Google Inc. 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.
 */

#include "config.h"
#include "platform/blob/BlobRegistry.h"

#include "platform/ThreadSafeFunctional.h"
#include "platform/blob/BlobData.h"
#include "platform/blob/BlobURL.h"
#include "platform/weborigin/SecurityOrigin.h"
#include "platform/weborigin/SecurityOriginCache.h"
#include "public/platform/Platform.h"
#include "public/platform/WebBlobData.h"
#include "public/platform/WebBlobRegistry.h"
#include "public/platform/WebString.h"
#include "public/platform/WebTraceLocation.h"
#include "wtf/Assertions.h"
#include "wtf/HashMap.h"
#include "wtf/MainThread.h"
#include "wtf/RefPtr.h"
#include "wtf/ThreadSpecific.h"
#include "wtf/Threading.h"
#include "wtf/text/StringHash.h"
#include "wtf/text/WTFString.h"

namespace blink {

class BlobOriginCache : public SecurityOriginCache {
public:
    BlobOriginCache();
    virtual SecurityOrigin* cachedOrigin(const KURL&) override;
};

static WebBlobRegistry* blobRegistry()
{
    return Platform::current()->blobRegistry();
}

typedef HashMap<String, RefPtr<SecurityOrigin>> BlobURLOriginMap;
static ThreadSpecific<BlobURLOriginMap>& originMap()
{
    // We want to create the BlobOriginCache exactly once because it is shared by all the threads.
    AtomicallyInitializedStaticReference(BlobOriginCache, cache, new BlobOriginCache);
    (void)cache; // BlobOriginCache's constructor does the interesting work.

    AtomicallyInitializedStaticReference(ThreadSpecific<BlobURLOriginMap>, map, new ThreadSpecific<BlobURLOriginMap>);
    return map;
}

static void saveToOriginMap(SecurityOrigin* origin, const KURL& url)
{
    // If the blob URL contains null origin, as in the context with unique
    // security origin or file URL, save the mapping between url and origin so
    // that the origin can be retrived when doing security origin check.
    if (origin && BlobURL::getOrigin(url) == "null")
        originMap()->add(url.string(), origin);
}

static void removeFromOriginMap(const KURL& url)
{
    if (BlobURL::getOrigin(url) == "null")
        originMap()->remove(url.string());
}

void BlobRegistry::registerBlobData(const String& uuid, PassOwnPtr<BlobData> data)
{
    blobRegistry()->registerBlobData(uuid, WebBlobData(data));
}

void BlobRegistry::addBlobDataRef(const String& uuid)
{
    blobRegistry()->addBlobDataRef(uuid);
}

void BlobRegistry::removeBlobDataRef(const String& uuid)
{
    blobRegistry()->removeBlobDataRef(uuid);
}

void BlobRegistry::registerPublicBlobURL(SecurityOrigin* origin, const KURL& url, PassRefPtr<BlobDataHandle> handle)
{
    saveToOriginMap(origin, url);
    blobRegistry()->registerPublicBlobURL(url, handle->uuid());
}

void BlobRegistry::revokePublicBlobURL(const KURL& url)
{
    removeFromOriginMap(url);
    blobRegistry()->revokePublicBlobURL(url);
}

static void registerStreamURLTask(const KURL& url, const String& type)
{
    if (WebBlobRegistry* registry = blobRegistry())
        registry->registerStreamURL(url, type);
}

void BlobRegistry::registerStreamURL(const KURL& url, const String& type)
{
    if (isMainThread())
        registerStreamURLTask(url, type);
    else
        Platform::current()->mainThread()->postTask(FROM_HERE, threadSafeBind(&registerStreamURLTask, url, type));
}

static void registerStreamURLFromTask(const KURL& url, const KURL& srcURL)
{
    if (WebBlobRegistry* registry = blobRegistry())
        registry->registerStreamURL(url, srcURL);
}

void BlobRegistry::registerStreamURL(SecurityOrigin* origin, const KURL& url, const KURL& srcURL)
{
    saveToOriginMap(origin, url);

    if (isMainThread())
        registerStreamURLFromTask(url, srcURL);
    else
        Platform::current()->mainThread()->postTask(FROM_HERE, threadSafeBind(&registerStreamURLFromTask, url, srcURL));
}

static void addDataToStreamTask(const KURL& url, PassRefPtr<RawData> streamData)
{
    if (WebBlobRegistry* registry = blobRegistry())
        registry->addDataToStream(url, streamData->data(), streamData->length());
}

void BlobRegistry::addDataToStream(const KURL& url, PassRefPtr<RawData> streamData)
{
    if (isMainThread())
        addDataToStreamTask(url, streamData);
    else
        Platform::current()->mainThread()->postTask(FROM_HERE, threadSafeBind(&addDataToStreamTask, url, streamData));
}

static void flushStreamTask(const KURL& url)
{
    if (WebBlobRegistry* registry = blobRegistry())
        registry->flushStream(url);
}

void BlobRegistry::flushStream(const KURL& url)
{
    if (isMainThread())
        flushStreamTask(url);
    else
        Platform::current()->mainThread()->postTask(FROM_HERE, threadSafeBind(&flushStreamTask, url));
}

static void finalizeStreamTask(const KURL& url)
{
    if (WebBlobRegistry* registry = blobRegistry())
        registry->finalizeStream(url);
}

void BlobRegistry::finalizeStream(const KURL& url)
{
    if (isMainThread())
        finalizeStreamTask(url);
    else
        Platform::current()->mainThread()->postTask(FROM_HERE, threadSafeBind(&finalizeStreamTask, url));
}

static void abortStreamTask(const KURL& url)
{
    if (WebBlobRegistry* registry = blobRegistry())
        registry->abortStream(url);
}

void BlobRegistry::abortStream(const KURL& url)
{
    if (isMainThread())
        abortStreamTask(url);
    else
        Platform::current()->mainThread()->postTask(FROM_HERE, threadSafeBind(&abortStreamTask, url));
}

static void unregisterStreamURLTask(const KURL& url)
{
    if (WebBlobRegistry* registry = blobRegistry())
        registry->unregisterStreamURL(url);
}

void BlobRegistry::unregisterStreamURL(const KURL& url)
{
    removeFromOriginMap(url);

    if (isMainThread())
        unregisterStreamURLTask(url);
    else
        Platform::current()->mainThread()->postTask(FROM_HERE, threadSafeBind(&unregisterStreamURLTask, url));
}

BlobOriginCache::BlobOriginCache()
{
    SecurityOrigin::setCache(this);
}

SecurityOrigin* BlobOriginCache::cachedOrigin(const KURL& url)
{
    if (url.protocolIs("blob"))
        return originMap()->get(url.string());
    return 0;
}

} // namespace blink
<|endoftext|>


<commit_before>/*************************************************************************
> File Name: PlayCard.cpp
> Project Name: Hearthstonepp
> Author: Young-Joong Kim
> Purpose: Implement PlayCardTask, Select Card and Passing it to Sub Logics
> Created Time: 2018/07/21
> Copyright (c) 2018, Young-Joong Kim
*************************************************************************/
#include <Tasks/BasicTasks/PlayCard.h>
#include <Tasks/BasicTasks/PlayMinion.h>
#include <Tasks/BasicTasks/PlaySpell.h>
#include <Tasks/BasicTasks/PlayWeapon.h>

namespace Hearthstonepp::BasicTasks
{
PlayCardTask::PlayCardTask(TaskAgent& agent)
    : m_agent(agent), m_requirement(TaskID::SELECT_CARD, agent)
{
    // Do Nothing
}

TaskID PlayCardTask::GetTaskID() const
{
    return TaskID::PLAY_CARD;
}

MetaData PlayCardTask::Impl(Player& player1, Player& player2) const
{
    TaskMeta serialized;
    // Get Response from GameInterface
    m_requirement.Interact(player1.id, serialized);

    using RequireTaskMeta = FlatData::ResponsePlayCard;
    const auto& buffer = serialized.GetConstBuffer();
    auto req = flatbuffers::GetRoot<RequireTaskMeta>(buffer.get());

    if (req == nullptr)
    {
        return MetaData::PLAY_CARD_FLATBUFFER_NULLPTR;
    }

    BYTE cardIndex = req->cardIndex();

    // Card Hand Index Verification
    if (cardIndex >= player1.hand.size())
    {
        return MetaData::PLAY_CARD_IDX_OUT_OF_RANGE;
    }
    // Sufficient Mana Verification
    if (player1.hand[cardIndex]->card->cost > player1.existMana)
    {
        return MetaData::PLAY_CARD_NOT_ENOUGH_MANA;
    }

    Entity* entity = player1.hand[cardIndex];

    // erase from user's hand
    player1.hand.erase(player1.hand.begin() + cardIndex);

    // Pass to Sub Logics
    switch (entity->card->cardType)
    {
        case CardType::MINION:
            return PlayMinionTask(m_agent, entity).Run(player1, player2);
        case CardType::WEAPON:
            return PlayWeaponTask(entity).Run(player1, player2);
        case CardType::SPELL:
            return PlaySpellTask(entity).Run(player1, player2);
        default:
            return MetaData::PLAY_CARD_INVALID_CARD_TYPE;
    }
}
}  // namespace Hearthstonepp::BasicTasks<commit_msg>[ci skip] Apply PlaySpellTask's change<commit_after>/*************************************************************************
> File Name: PlayCard.cpp
> Project Name: Hearthstonepp
> Author: Young-Joong Kim
> Purpose: Implement PlayCardTask, Select Card and Passing it to Sub Logics
> Created Time: 2018/07/21
> Copyright (c) 2018, Young-Joong Kim
*************************************************************************/
#include <Tasks/BasicTasks/PlayCard.h>
#include <Tasks/BasicTasks/PlayMinion.h>
#include <Tasks/BasicTasks/PlaySpell.h>
#include <Tasks/BasicTasks/PlayWeapon.h>

namespace Hearthstonepp::BasicTasks
{
PlayCardTask::PlayCardTask(TaskAgent& agent)
    : m_agent(agent), m_requirement(TaskID::SELECT_CARD, agent)
{
    // Do Nothing
}

TaskID PlayCardTask::GetTaskID() const
{
    return TaskID::PLAY_CARD;
}

MetaData PlayCardTask::Impl(Player& player1, Player& player2) const
{
    TaskMeta serialized;
    // Get Response from GameInterface
    m_requirement.Interact(player1.id, serialized);

    using RequireTaskMeta = FlatData::ResponsePlayCard;
    const auto& buffer = serialized.GetConstBuffer();
    auto req = flatbuffers::GetRoot<RequireTaskMeta>(buffer.get());

    if (req == nullptr)
    {
        return MetaData::PLAY_CARD_FLATBUFFER_NULLPTR;
    }

    BYTE cardIndex = req->cardIndex();

    // Card Hand Index Verification
    if (cardIndex >= player1.hand.size())
    {
        return MetaData::PLAY_CARD_IDX_OUT_OF_RANGE;
    }
    // Sufficient Mana Verification
    if (player1.hand[cardIndex]->card->cost > player1.existMana)
    {
        return MetaData::PLAY_CARD_NOT_ENOUGH_MANA;
    }

    Entity* entity = player1.hand[cardIndex];

    // erase from user's hand
    player1.hand.erase(player1.hand.begin() + cardIndex);

    // Pass to Sub Logics
    switch (entity->card->cardType)
    {
        case CardType::MINION:
            return PlayMinionTask(m_agent, entity).Run(player1, player2);
        case CardType::WEAPON:
            return PlayWeaponTask(entity).Run(player1, player2);
        case CardType::SPELL:
            return PlaySpellTask(m_agent, entity).Run(player1, player2);
        default:
            return MetaData::PLAY_CARD_INVALID_CARD_TYPE;
    }
}
}  // namespace Hearthstonepp::BasicTasks<|endoftext|>


<commit_before>#ifndef diff_hh_INCLUDED
#define diff_hh_INCLUDED

// Implementation of the linear space variant of the algorithm described in
// "An O(ND) Difference Algorithm and Its Variations"
// (http://xmailserver.org/diff2.pdf)

#include "array_view.hh"
#include "vector.hh"

#include <functional>
#include <iterator>

namespace Kakoune
{

template<typename T>
struct MirroredArray : public ArrayView<T>
{
    MirroredArray(ArrayView<T> data, int size)
        : ArrayView<T>(data), size(size)
    {
        kak_assert(2 * size + 1 <= data.size());
        (*this)[1] = 0;
    }

    [[gnu::always_inline]]
    T& operator[](int n) { return ArrayView<T>::operator[](n + size); }
    [[gnu::always_inline]]
    const T& operator[](int n) const { return ArrayView<T>::operator[](n + size); }
private:
    int size;
};

struct Snake{ int x, y, u, v; bool add; };

template<typename Iterator, typename Equal>
Snake find_end_snake_of_further_reaching_dpath(Iterator a, int N, Iterator b, int M,
                                               const MirroredArray<int>& V,
                                               const int D, const int k, Equal eq)
{
    int x; // our position along a

    const bool add = k == -D or (k != D and V[k-1] < V[k+1]);

    // if diagonal on the right goes further along x than diagonal on the left,
    // then we take a vertical edge from it to this diagonal, hence x = V[k+1]
    if (add)
        x = V[k+1];
    // else, we take an horizontal edge from our left diagonal,x = V[k-1]+1
    else
        x = V[k-1]+1;

    int y = x - k; // we are by construction on diagonal k, so our position along
                   // b (y) is x - k.

    int u = x, v = y;
    // follow end snake along diagonal k
    while (u < N and v < M and eq(a[u], b[v]))
        ++u, ++v;

    return { x, y, u, v, add };
}

struct SnakeLen : Snake
{
    SnakeLen(Snake s, int d) : Snake(s), d(d) {}
    int d;
};

template<typename Iterator, typename Equal>
SnakeLen find_middle_snake(Iterator a, int N, Iterator b, int M,
                           ArrayView<int> data1, ArrayView<int> data2,
                           Equal eq)
{
    const int delta = N - M;
    MirroredArray<int> V1{data1, N + M};
    MirroredArray<int> V2{data2, N + M};

    std::reverse_iterator<Iterator> ra{a + N}, rb{b + M};

    for (int D = 0; D <= (M + N + 1) / 2; ++D)
    {
        for (int k1 = -D; k1 <= D; k1 += 2)
        {
            auto p = find_end_snake_of_further_reaching_dpath(a, N, b, M, V1, D, k1, eq);
            V1[k1] = p.u;

            const int k2 = -(k1 - delta);
            if ((delta % 2 != 0) and -(D-1) <= k2 and k2 <= (D-1))
            {
                if (V1[k1] + V2[k2] >= N)
                    return { p, 2 * D - 1 };// return last snake on forward path
            }
        }

        for (int k2 = -D; k2 <= D; k2 += 2)
        {
            auto p = find_end_snake_of_further_reaching_dpath(ra, N, rb, M, V2, D, k2, eq);
            V2[k2] = p.u;

            const int k1 = -(k2 - delta);
            if ((delta % 2 == 0) and -D <= k1 and k1 <= D)
            {
                if (V1[k1] + V2[k2] >= N)
                    return { { N - p.u, M - p.v, N - p.x , M - p.y, p.add } , 2 * D };// return last snake on reverse path
            }
        }
    }

    kak_assert(false);
    return { {}, 0 };
}

struct Diff
{
    enum { Keep, Add, Remove } mode;
    int len;
    int posB;
    int posA;
};

inline void append_diff(Vector<Diff>& diffs, Diff diff)
{
    if (not diffs.empty() and diffs.back().mode == diff.mode
        and (diff.mode != Diff::Add or
             diffs.back().posB + diffs.back().len == diff.posB))
        diffs.back().len += diff.len;
    else
        diffs.push_back(diff);
}

template<typename Iterator, typename Equal>
void find_diff_rec(Iterator a, int offA, int lenA,
                   Iterator b, int offB, int lenB,
                   ArrayView<int> data1, ArrayView<int> data2,
                   Equal eq, Vector<Diff>& diffs)
{
    if (lenA > 0 and lenB > 0)
    {
        auto middle_snake = find_middle_snake(a + offA, lenA, b + offB, lenB, data1, data2, eq);
        kak_assert(middle_snake.u <= lenA and middle_snake.v <= lenB);
        if (middle_snake.d > 1)
        {
            find_diff_rec(a, offA, middle_snake.x,
                          b, offB, middle_snake.y,
                          data1, data2, eq, diffs);

            if (int len = middle_snake.u - middle_snake.x)
                append_diff(diffs, {Diff::Keep, len, 0});

            find_diff_rec(a, offA + middle_snake.u, lenA - middle_snake.u,
                          b, offB + middle_snake.v, lenB - middle_snake.v,
                          data1, data2, eq, diffs);
        }
        else
        {
            if (middle_snake.d == 1)
            {
                const int diag = middle_snake.x - (middle_snake.add ? 0 : 1);
                if (diag != 0)
                    append_diff(diffs, {Diff::Keep, diag, 0});

                if (middle_snake.add)
                    append_diff(diffs, {Diff::Add, 1, offB + diag});
                else
                    append_diff(diffs, {Diff::Remove, 1, 0});
            }
            if (int len = middle_snake.u - middle_snake.x)
                append_diff(diffs, {Diff::Keep, len, 0});
        }
    }
    else if (lenB > 0)
        append_diff(diffs, {Diff::Add, lenB, offB});
    else if (lenA > 0)
        append_diff(diffs, {Diff::Remove, lenA, 0});
}

template<typename Iterator, typename Equal = std::equal_to<typename std::iterator_traits<Iterator>::value_type>>
Vector<Diff> find_diff(Iterator a, int N, Iterator b, int M,
                                 Equal eq = Equal{})
{
    const int max = 2 * (N + M) + 1;
    Vector<int> data(2*max);
    Vector<Diff> diffs;
    find_diff_rec(a, 0, N, b, 0, M,
                  {data.data(), (size_t)max}, {data.data() + max, (size_t)max},
                  eq, diffs);

    return diffs;
}

}

#endif // diff_hh_INCLUDED
<commit_msg>Formatting tweak<commit_after>#ifndef diff_hh_INCLUDED
#define diff_hh_INCLUDED

// Implementation of the linear space variant of the algorithm described in
// "An O(ND) Difference Algorithm and Its Variations"
// (http://xmailserver.org/diff2.pdf)

#include "array_view.hh"
#include "vector.hh"

#include <functional>
#include <iterator>

namespace Kakoune
{

template<typename T>
struct MirroredArray : public ArrayView<T>
{
    MirroredArray(ArrayView<T> data, int size)
        : ArrayView<T>(data), size(size)
    {
        kak_assert(2 * size + 1 <= data.size());
        (*this)[1] = 0;
    }

    [[gnu::always_inline]]
    T& operator[](int n) { return ArrayView<T>::operator[](n + size); }
    [[gnu::always_inline]]
    const T& operator[](int n) const { return ArrayView<T>::operator[](n + size); }
private:
    int size;
};

struct Snake{ int x, y, u, v; bool add; };

template<typename Iterator, typename Equal>
Snake find_end_snake_of_further_reaching_dpath(Iterator a, int N, Iterator b, int M,
                                               const MirroredArray<int>& V,
                                               const int D, const int k, Equal eq)
{
    int x; // our position along a

    const bool add = k == -D or (k != D and V[k-1] < V[k+1]);

    // if diagonal on the right goes further along x than diagonal on the left,
    // then we take a vertical edge from it to this diagonal, hence x = V[k+1]
    if (add)
        x = V[k+1];
    // else, we take an horizontal edge from our left diagonal,x = V[k-1]+1
    else
        x = V[k-1]+1;

    int y = x - k; // we are by construction on diagonal k, so our position along
                   // b (y) is x - k.

    int u = x, v = y;
    // follow end snake along diagonal k
    while (u < N and v < M and eq(a[u], b[v]))
        ++u, ++v;

    return { x, y, u, v, add };
}

struct SnakeLen : Snake
{
    SnakeLen(Snake s, int d) : Snake(s), d(d) {}
    int d;
};

template<typename Iterator, typename Equal>
SnakeLen find_middle_snake(Iterator a, int N, Iterator b, int M,
                           ArrayView<int> data1, ArrayView<int> data2,
                           Equal eq)
{
    const int delta = N - M;
    MirroredArray<int> V1{data1, N + M};
    MirroredArray<int> V2{data2, N + M};

    std::reverse_iterator<Iterator> ra{a + N}, rb{b + M};

    for (int D = 0; D <= (M + N + 1) / 2; ++D)
    {
        for (int k1 = -D; k1 <= D; k1 += 2)
        {
            auto p = find_end_snake_of_further_reaching_dpath(a, N, b, M, V1, D, k1, eq);
            V1[k1] = p.u;

            const int k2 = -(k1 - delta);
            if ((delta % 2 != 0) and -(D-1) <= k2 and k2 <= (D-1))
            {
                if (V1[k1] + V2[k2] >= N)
                    return { p, 2 * D - 1 };// return last snake on forward path
            }
        }

        for (int k2 = -D; k2 <= D; k2 += 2)
        {
            auto p = find_end_snake_of_further_reaching_dpath(ra, N, rb, M, V2, D, k2, eq);
            V2[k2] = p.u;

            const int k1 = -(k2 - delta);
            if ((delta % 2 == 0) and -D <= k1 and k1 <= D)
            {
                if (V1[k1] + V2[k2] >= N)
                    return { { N - p.u, M - p.v, N - p.x , M - p.y, p.add } , 2 * D };// return last snake on reverse path
            }
        }
    }

    kak_assert(false);
    return { {}, 0 };
}

struct Diff
{
    enum { Keep, Add, Remove } mode;
    int len;
    int posB;
    int posA;
};

inline void append_diff(Vector<Diff>& diffs, Diff diff)
{
    if (not diffs.empty() and diffs.back().mode == diff.mode
        and (diff.mode != Diff::Add or
             diffs.back().posB + diffs.back().len == diff.posB))
        diffs.back().len += diff.len;
    else
        diffs.push_back(diff);
}

template<typename Iterator, typename Equal>
void find_diff_rec(Iterator a, int offA, int lenA,
                   Iterator b, int offB, int lenB,
                   ArrayView<int> data1, ArrayView<int> data2,
                   Equal eq, Vector<Diff>& diffs)
{
    if (lenA > 0 and lenB > 0)
    {
        auto middle_snake = find_middle_snake(a + offA, lenA, b + offB, lenB, data1, data2, eq);
        kak_assert(middle_snake.u <= lenA and middle_snake.v <= lenB);
        if (middle_snake.d > 1)
        {
            find_diff_rec(a, offA, middle_snake.x,
                          b, offB, middle_snake.y,
                          data1, data2, eq, diffs);

            if (int len = middle_snake.u - middle_snake.x)
                append_diff(diffs, {Diff::Keep, len, 0});

            find_diff_rec(a, offA + middle_snake.u, lenA - middle_snake.u,
                          b, offB + middle_snake.v, lenB - middle_snake.v,
                          data1, data2, eq, diffs);
        }
        else
        {
            if (middle_snake.d == 1)
            {
                const int diag = middle_snake.x - (middle_snake.add ? 0 : 1);
                if (diag != 0)
                    append_diff(diffs, {Diff::Keep, diag, 0});

                if (middle_snake.add)
                    append_diff(diffs, {Diff::Add, 1, offB + diag});
                else
                    append_diff(diffs, {Diff::Remove, 1, 0});
            }
            if (int len = middle_snake.u - middle_snake.x)
                append_diff(diffs, {Diff::Keep, len, 0});
        }
    }
    else if (lenB > 0)
        append_diff(diffs, {Diff::Add, lenB, offB});
    else if (lenA > 0)
        append_diff(diffs, {Diff::Remove, lenA, 0});
}

template<typename Iterator, typename Equal = std::equal_to<typename std::iterator_traits<Iterator>::value_type>>
Vector<Diff> find_diff(Iterator a, int N, Iterator b, int M, Equal eq = Equal{})
{
    const int max = 2 * (N + M) + 1;
    Vector<int> data(2*max);
    Vector<Diff> diffs;
    find_diff_rec(a, 0, N, b, 0, M,
                  {data.data(), (size_t)max}, {data.data() + max, (size_t)max},
                  eq, diffs);

    return diffs;
}

}

#endif // diff_hh_INCLUDED
<|endoftext|>


<commit_before>#include "Halide.h"
#include <stdio.h>

using namespace Halide;

template<typename A>
const char *string_of_type();

#define DECL_SOT(name)                                          \
    template<>                                                  \
    const char *string_of_type<name>() {return #name;}

DECL_SOT(uint8_t);
DECL_SOT(int8_t);
DECL_SOT(uint16_t);
DECL_SOT(int16_t);
DECL_SOT(uint32_t);
DECL_SOT(int32_t);
DECL_SOT(float);
DECL_SOT(double);

template<typename A, typename B>
bool test(int vec_width) {

    int W = vec_width*4;
    int H = 1;

    Image<A> input(W, H);
    for (int y = 0; y < H; y++) {
        for (int x = 0; x < W; x++) {
            input(x, y) = (A)((rand()&0xffff)*0.1);
        }
    }

    Var x, y;
    Func f;

    f(x, y) = cast<B>(input(x, y));

    f.vectorize(x, vec_width);

    Image<B> output(W, H);
    f.realize(output);

    /*
    for (int y = 0; y < H; y++) {
        for (int x = 0; x < W; x++) {
	    printf("%d %d -> %d %d\n", x, y, (int)(input(x, y)), (int)(output(x, y)));
        }
    }
    */

    for (int y = 0; y < H; y++) {
        for (int x = 0; x < W; x++) {

            bool ok = ((B)(input(x, y)) == output(x, y));
            if (!ok) {
                printf("%s x %d -> %s x %d failed\n",
                       string_of_type<A>(), vec_width,
                       string_of_type<B>(), vec_width);
                printf("At %d %d, %f -> %f instead of %f\n",
                       x, y,
                       (double)(input(x, y)),
                       (double)(output(x, y)),
                       (double)((B)(input(x, y))));
                return false;
            }
        }
    }

    return true;
}

template<typename A>
bool test_all(int vec_width) {
    bool ok = true;
    ok = ok && test<A, float>(vec_width);
    ok = ok && test<A, double>(vec_width);
    ok = ok && test<A, uint8_t>(vec_width);
    ok = ok && test<A, int8_t>(vec_width);
    ok = ok && test<A, uint16_t>(vec_width);
    ok = ok && test<A, int16_t>(vec_width);
    ok = ok && test<A, uint32_t>(vec_width);
    ok = ok && test<A, int32_t>(vec_width);
    return ok;
}

int main(int argc, char **argv) {

    // We don't test this on windows, because float-to-int conversions
    // on windows use _ftol2, which has its own unique calling
    // convention, and older LLVMs (e.g. pnacl) don't do it right so
    // you get clobbered registers.
    #ifdef WIN32
    printf("Not testing on windows\n");
    return 0;
    #endif

    bool ok = true;

    // We only support power-of-two vector widths for now
    for (int vec_width = 2; vec_width < 32; vec_width*=2) {
        ok = ok && test_all<float>(vec_width);
        ok = ok && test_all<double>(vec_width);
        ok = ok && test_all<uint8_t>(vec_width);
        ok = ok && test_all<int8_t>(vec_width);
        ok = ok && test_all<uint16_t>(vec_width);
        ok = ok && test_all<int16_t>(vec_width);
        ok = ok && test_all<uint32_t>(vec_width);
        ok = ok && test_all<int32_t>(vec_width);
    }

    if (!ok) return -1;
    printf("Success!\n");
    return 0;
}
<commit_msg>Enable hexagon testing.<commit_after>#include "Halide.h"
#include <stdio.h>

using namespace Halide;

template<typename A>
const char *string_of_type();

#define DECL_SOT(name)                                          \
    template<>                                                  \
    const char *string_of_type<name>() {return #name;}

DECL_SOT(uint8_t);
DECL_SOT(int8_t);
DECL_SOT(uint16_t);
DECL_SOT(int16_t);
DECL_SOT(uint32_t);
DECL_SOT(int32_t);
DECL_SOT(float);
DECL_SOT(double);

template <typename T>
bool is_type_supported(int vec_width, const Target &target) {
    return true;
}

template <>
bool is_type_supported<float>(int vec_width, const Target &target) {
    return vec_width == 1 || !target.features_any_of({Target::HVX_64, Target::HVX_128});
}

template <>
bool is_type_supported<double>(int vec_width, const Target &target) {
    return vec_width == 1 || !target.features_any_of({Target::HVX_64, Target::HVX_128});
}

template<typename A, typename B>
bool test(int vec_width, const Target &target) {
    if (!is_type_supported<A>(vec_width, target) || !is_type_supported<B>(vec_width, target)) {
        // Type not supported, return pass.
        return true;
    }

    int W = 1024;
    int H = 1;

    Image<A> input(W, H);
    for (int y = 0; y < H; y++) {
        for (int x = 0; x < W; x++) {
            input(x, y) = (A)((rand()&0xffff)*0.1);
        }
    }

    Var x, y;
    Func f;

    f(x, y) = cast<B>(input(x, y));

    if (target.has_gpu_feature()) {
        f.gpu_tile(x, 64);
    } else {
        if (target.features_any_of({Target::HVX_64, Target::HVX_128})) {
            f.hexagon();
        }
        if (vec_width > 1) {
            f.vectorize(x, vec_width);
        }
    }

    Image<B> output(W, H);
    f.realize(output);

    /*
    for (int y = 0; y < H; y++) {
        for (int x = 0; x < W; x++) {
	    printf("%d %d -> %d %d\n", x, y, (int)(input(x, y)), (int)(output(x, y)));
        }
    }
    */

    for (int y = 0; y < H; y++) {
        for (int x = 0; x < W; x++) {

            bool ok = ((B)(input(x, y)) == output(x, y));
            if (!ok) {
                printf("%s x %d -> %s x %d failed\n",
                       string_of_type<A>(), vec_width,
                       string_of_type<B>(), vec_width);
                printf("At %d %d, %f -> %f instead of %f\n",
                       x, y,
                       (double)(input(x, y)),
                       (double)(output(x, y)),
                       (double)((B)(input(x, y))));
                return false;
            }
        }
    }

    return true;
}

template<typename A>
bool test_all(int vec_width, const Target &target) {
    bool ok = true;
    ok = ok && test<A, float>(vec_width, target);
    ok = ok && test<A, double>(vec_width, target);
    ok = ok && test<A, uint8_t>(vec_width, target);
    ok = ok && test<A, int8_t>(vec_width, target);
    ok = ok && test<A, uint16_t>(vec_width, target);
    ok = ok && test<A, int16_t>(vec_width, target);
    ok = ok && test<A, uint32_t>(vec_width, target);
    ok = ok && test<A, int32_t>(vec_width, target);
    return ok;
}

int main(int argc, char **argv) {

    // We don't test this on windows, because float-to-int conversions
    // on windows use _ftol2, which has its own unique calling
    // convention, and older LLVMs (e.g. pnacl) don't do it right so
    // you get clobbered registers.
    #ifdef WIN32
    printf("Not testing on windows\n");
    return 0;
    #endif

    Target target = get_jit_target_from_environment();

    bool ok = true;

    // We only support power-of-two vector widths for now
    for (int vec_width = 1; vec_width <= 64; vec_width*=2) {
        printf("Testing vector width %d\n", vec_width);
        ok = ok && test_all<float>(vec_width, target);
        ok = ok && test_all<double>(vec_width, target);
        ok = ok && test_all<uint8_t>(vec_width, target);
        ok = ok && test_all<int8_t>(vec_width, target);
        ok = ok && test_all<uint16_t>(vec_width, target);
        ok = ok && test_all<int16_t>(vec_width, target);
        ok = ok && test_all<uint32_t>(vec_width, target);
        ok = ok && test_all<int32_t>(vec_width, target);
    }

    if (!ok) return -1;
    printf("Success!\n");
    return 0;
}
<|endoftext|>


<commit_before>/**
 * @file Cosa/Wireless/Driver/CC1101.cpp
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2013-2014, Mikael Patel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#include "Cosa/Wireless/Driver/CC1101.hh"

#if !defined(BOARD_ATTINYX5)
#include "Cosa/Power.hh"
#include "Cosa/RTC.hh"

#if defined(BOARD_ATTINY)
#define PIN PINA
#else
#define PIN PINB
#endif

/**
 * Default configuration (generated with TI SmartRF Studio tool):
 * Radio: 433 MHz, 38 kbps, GFSK. Whitening, 0 dBm.
 * Packet: Variable packet length with CRC, address check and broadcast(0x00)
 * FIFO: Append link status.
 * Frame: sync(2), length(1), dest(1), payload(max 59), crc(2)
 * - Send(62): length(1), dest(1), src(1), payload(max 59)
 * - Received(64): length(1), dest(1), src(1), payload(max 59), status(2)
 * Digital Output Pins:
 * - GDO2: valid frame received, active low
 * - GDO1: high impedance when CSN is high otherwise serial data output
 * - GDO0: high impedance, not used
 */
const uint8_t CC1101::config[CC1101::CONFIG_MAX] __PROGMEM = {
  0x47,		// GDO2 Output Pin Configuration
  0x2E,		// GDO1 Output Pin Configuration
  0x2E,		// GDO0 Output Pin Configuration
  0x07,		// RX FIFO and TX FIFO Thresholds
  0xC0,		// Synchronization word, high byte
  0x5A,		// Synchronization word, low byte
  0x3D,		// Packet Length, 61 bytes
  0x06,		// Packet Automation Control
  0x45,		// Packet Automation Control
  0xFF,		// Device Address
  0x00,		// Channel Number
  0x08,		// Frequency Synthesizer Control
  0x00,		// Frequency Synthesizer Control
  0x10,		// Frequency Control Word, High Byte
  0xA7,		// Frequency Control Word, Middle Byte
  0x62,		// Frequency Control Word, Low Byte
  0xCA,		// Modem Configuration
  0x83,		// Modem Configuration
  0x93,		// Modem Configuration
  0x22,		// Modem Configuration
  0xF8,		// Modem Configuration
  0x35,		// Modem Deviation Setting
  0x07,		// Main Radio Control State Machine Configuration
  0x30,		// Main Radio Control State Machine Configuration
  0x18,		// Main Radio Control State Machine Configuration
  0x16,		// Frequency Offset Compensation Configuration
  0x6C,		// Bit Synchronization Configuration
  0x43,		// AGC Control
  0x40,		// AGC Control
  0x91,		// AGC Control
  0x87,		// High Byte Event0 Timeout
  0x6B,		// Low Byte Event0 Timeout
  0xFB,		// Wake On Radio Control
  0x56,		// Front End RX Configuration
  0x10,		// Front End TX Configuration
  0xE9,		// Frequency Synthesizer Calibration
  0x2A,		// Frequency Synthesizer Calibration
  0x00,		// Frequency Synthesizer Calibration
  0x1F,		// Frequency Synthesizer Calibration
  0x41,		// RC Oscillator Configuration
  0x00		// RC Oscillator Configuration
};

void
CC1101::IRQPin::on_interrupt(uint16_t arg)
{
  UNUSED(arg);
  if (m_rf == 0) return;
  m_rf->m_avail = true;
}

CC1101::CC1101(uint16_t net, uint8_t dev,
	       Board::DigitalPin csn,
	       Board::ExternalInterruptPin irq) :
  SPI::Driver(csn, SPI::ACTIVE_LOW, SPI::DIV4_CLOCK, 0, SPI::MSB_ORDER, &m_irq),
  Wireless::Driver(net, dev),
  m_irq(irq, ExternalInterrupt::ON_FALLING_MODE, this),
  m_status(0)
{
}

void
CC1101::strobe(Command cmd)
{
  spi.begin(this);
  loop_until_bit_is_clear(PIN, Board::MISO);
  m_status = spi.transfer(header_t(cmd, 0, 0));
  spi.end();
}

void
CC1101::await(Mode mode)
{
  while (read_status().mode != mode) DELAY(100);
}

bool
CC1101::begin(const void* config)
{
  // Reset the device
  m_cs.pulse(30);
  DELAY(30);
  strobe(SRES);
  DELAY(300);

  // Upload the configuration. Check for default configuration
  spi.begin(this);
  loop_until_bit_is_clear(PIN, Board::MISO);
  write_P(IOCFG2,
	  config ? (const uint8_t*) config : CC1101::config,
	  CONFIG_MAX);
  spi.end();

  // Adjust configuration with instance specific state
  uint16_t sync = hton(m_addr.network);
  spi.begin(this);
  loop_until_bit_is_clear(PIN, Board::MISO);
  write(PATABLE, 0x60);
  write(CHANNR, m_channel);
  write(ADDR, m_addr.device);
  write(SYNC1, &sync, sizeof(sync));
  spi.end();

  // Initiate device driver state and enable interrupt handler
  strobe(SCAL);
  m_avail = false;
  spi.attach(this);
  m_irq.enable();
  return (true);
}

bool
CC1101::end()
{
  m_irq.disable();
  powerdown();
  return (true);
}

int
CC1101::send(uint8_t dest, uint8_t port, const iovec_t* vec)
{
  // Sanity check the payload size
  if (vec == NULL) return (-1);
  size_t len = iovec_size(vec);
  if (len > PAYLOAD_MAX) return (-1);

  // Write frame length and header(dest, src, port)
  spi.begin(this);
  loop_until_bit_is_clear(PIN, Board::MISO);
  write(TXFIFO, len + 3);
  write(TXFIFO, dest);
  write(TXFIFO, m_addr.device);
  write(TXFIFO, port);
  spi.end();

  // Write payload buffers
  for (const iovec_t* vp = vec; vp->buf != NULL; vp++) {
    spi.begin(this);
    loop_until_bit_is_clear(PIN, Board::MISO);
    write(TXFIFO, vp->buf, vp->size);
    spi.end();
  }

  // Trigger transmission and wait for completion
  strobe(STX);
  await(IDLE_MODE);

  return (len);
}

int
CC1101::send(uint8_t dest, uint8_t port, const void* buf, size_t len)
{
  iovec_t vec[2];
  iovec_t* vp = vec;
  iovec_arg(vp, buf, len);
  iovec_end(vp);
  return (send(dest, port, vec));
}

int
CC1101::recv(uint8_t& src, uint8_t& port, void* buf, size_t len, uint32_t ms)
{
  uint32_t start = RTC::millis();
  uint8_t size;

  // Put in receive mode and wait for incoming message
  strobe(SRX);
  m_avail = false;
  do {
    while (!m_avail && ((ms == 0) || (RTC::since(start) < ms))) yield();
    if (!m_avail) {
      strobe(SIDLE);
      return (-2);
    }
    // Check the received frame size
    spi.begin(this);
    loop_until_bit_is_clear(PIN, Board::MISO);
    size = read(RXBYTES);
    spi.end();
  } while ((size & BYTES_MASK) == 0);

  // Put in idle mode and read the payload
  strobe(SIDLE);

  // Read the payload size and check against buffer length
  spi.begin(this);
  loop_until_bit_is_clear(PIN, Board::MISO);
  size = read(RXFIFO) - 3;
  if (size > len) {
    spi.end();
    strobe(SFRX);
    return (-1);
  }

  // Read the frame header(dest, src, port), payload and the link quality status
  m_dest = read(RXFIFO);
  src = read(RXFIFO);
  port = read(RXFIFO);
  read(RXFIFO, buf, size);
  spi.end();

  // Read link quality status
  spi.begin(this);
  loop_until_bit_is_clear(PIN, Board::MISO);
  read(RXFIFO, &m_recv_status, sizeof(m_recv_status));
  spi.end();

  // Fix: Add address checking for robustness
  return (size);
}

void
CC1101::powerdown()
{
  await(IDLE_MODE);
  strobe(SPWD);
}

void
CC1101::wakeup_on_radio()
{
  await(IDLE_MODE);
  strobe(SWOR);
}

void
CC1101::set_output_power_level(int8_t dBm)
{
  uint8_t pa = 0xC0;
  if      (dBm < -20) pa = 0x12;
  else if (dBm < -15) pa = 0x0E;
  else if (dBm < -10) pa = 0x1D;
  else if (dBm < 0)   pa = 0x34;
  else if (dBm < 5)   pa = 0x60;
  else if (dBm < 7)   pa = 0x84;
  else if (dBm < 10)  pa = 0xC4;
  spi.begin(this);
  loop_until_bit_is_clear(PIN, Board::MISO);
  write(PATABLE, pa);
  spi.end();
}

int
CC1101::get_input_power_level()
{
  int rssi = m_recv_status.rssi;
  return (((rssi < 128) ? rssi : rssi - 256) / 2 - 74);
}
#endif
<commit_msg>Optimizing CC1101 send()/recv() SPI FIFO burst read.<commit_after>/**
 * @file Cosa/Wireless/Driver/CC1101.cpp
 * @version 1.0
 *
 * @section License
 * Copyright (C) 2013-2014, Mikael Patel
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * This file is part of the Arduino Che Cosa project.
 */

#include "Cosa/Wireless/Driver/CC1101.hh"

#if !defined(BOARD_ATTINYX5)
#include "Cosa/Power.hh"
#include "Cosa/RTC.hh"

#if defined(BOARD_ATTINY)
#define PIN PINA
#else
#define PIN PINB
#endif

/**
 * Default configuration (generated with TI SmartRF Studio tool):
 * Radio: 433 MHz, 38 kbps, GFSK. Whitening, 0 dBm.
 * Packet: Variable packet length with CRC, address check and broadcast(0x00)
 * FIFO: Append link status.
 * Frame: sync(2), length(1), dest(1), payload(max 59), crc(2)
 * - Send(62): length(1), dest(1), src(1), payload(max 59)
 * - Received(64): length(1), dest(1), src(1), payload(max 59), status(2)
 * Digital Output Pins:
 * - GDO2: valid frame received, active low
 * - GDO1: high impedance when CSN is high otherwise serial data output
 * - GDO0: high impedance, not used
 */
const uint8_t CC1101::config[CC1101::CONFIG_MAX] __PROGMEM = {
  0x47,		// GDO2 Output Pin Configuration
  0x2E,		// GDO1 Output Pin Configuration
  0x2E,		// GDO0 Output Pin Configuration
  0x07,		// RX FIFO and TX FIFO Thresholds
  0xC0,		// Synchronization word, high byte
  0x5A,		// Synchronization word, low byte
  0x3D,		// Packet Length, 61 bytes
  0x06,		// Packet Automation Control
  0x45,		// Packet Automation Control
  0xFF,		// Device Address
  0x00,		// Channel Number
  0x08,		// Frequency Synthesizer Control
  0x00,		// Frequency Synthesizer Control
  0x10,		// Frequency Control Word, High Byte
  0xA7,		// Frequency Control Word, Middle Byte
  0x62,		// Frequency Control Word, Low Byte
  0xCA,		// Modem Configuration
  0x83,		// Modem Configuration
  0x93,		// Modem Configuration
  0x22,		// Modem Configuration
  0xF8,		// Modem Configuration
  0x35,		// Modem Deviation Setting
  0x07,		// Main Radio Control State Machine Configuration
  0x30,		// Main Radio Control State Machine Configuration
  0x18,		// Main Radio Control State Machine Configuration
  0x16,		// Frequency Offset Compensation Configuration
  0x6C,		// Bit Synchronization Configuration
  0x43,		// AGC Control
  0x40,		// AGC Control
  0x91,		// AGC Control
  0x87,		// High Byte Event0 Timeout
  0x6B,		// Low Byte Event0 Timeout
  0xFB,		// Wake On Radio Control
  0x56,		// Front End RX Configuration
  0x10,		// Front End TX Configuration
  0xE9,		// Frequency Synthesizer Calibration
  0x2A,		// Frequency Synthesizer Calibration
  0x00,		// Frequency Synthesizer Calibration
  0x1F,		// Frequency Synthesizer Calibration
  0x41,		// RC Oscillator Configuration
  0x00		// RC Oscillator Configuration
};

void
CC1101::IRQPin::on_interrupt(uint16_t arg)
{
  UNUSED(arg);
  if (m_rf == 0) return;
  m_rf->m_avail = true;
}

CC1101::CC1101(uint16_t net, uint8_t dev,
	       Board::DigitalPin csn,
	       Board::ExternalInterruptPin irq) :
  SPI::Driver(csn, SPI::ACTIVE_LOW, SPI::DIV4_CLOCK, 0, SPI::MSB_ORDER, &m_irq),
  Wireless::Driver(net, dev),
  m_irq(irq, ExternalInterrupt::ON_FALLING_MODE, this),
  m_status(0)
{
}

void
CC1101::strobe(Command cmd)
{
  spi.begin(this);
  loop_until_bit_is_clear(PIN, Board::MISO);
  m_status = spi.transfer(header_t(cmd, 0, 0));
  spi.end();
}

void
CC1101::await(Mode mode)
{
  while (read_status().mode != mode) DELAY(100);
}

bool
CC1101::begin(const void* config)
{
  // Reset the device
  m_cs.pulse(30);
  DELAY(30);
  strobe(SRES);
  DELAY(300);

  // Upload the configuration. Check for default configuration
  spi.begin(this);
  loop_until_bit_is_clear(PIN, Board::MISO);
  write_P(IOCFG2,
	  config ? (const uint8_t*) config : CC1101::config,
	  CONFIG_MAX);
  spi.end();

  // Adjust configuration with instance specific state
  uint16_t sync = hton(m_addr.network);
  spi.begin(this);
  loop_until_bit_is_clear(PIN, Board::MISO);
  write(PATABLE, 0x60);
  write(CHANNR, m_channel);
  write(ADDR, m_addr.device);
  write(SYNC1, &sync, sizeof(sync));
  spi.end();

  // Initiate device driver state and enable interrupt handler
  strobe(SCAL);
  m_avail = false;
  spi.attach(this);
  m_irq.enable();
  return (true);
}

bool
CC1101::end()
{
  // Fix: Should be state-based disable/enable
  m_irq.disable();
  powerdown();
  return (true);
}

int
CC1101::send(uint8_t dest, uint8_t port, const iovec_t* vec)
{
  // Sanity check the payload size
  if (vec == NULL) return (-1);
  size_t len = iovec_size(vec);
  if (len > PAYLOAD_MAX) return (-1);

  // Write frame length and header(dest, src, port) and payload buffers
  spi.begin(this);
  loop_until_bit_is_clear(PIN, Board::MISO);
  m_status = spi.transfer(header_t(TXFIFO, 1, 0));
  spi.transfer(len + 3);
  spi.transfer(dest);
  spi.transfer(m_addr.device);
  spi.transfer(port);
  for (const iovec_t* vp = vec; vp->buf != NULL; vp++)
    spi.write(vp->buf, vp->size);
  spi.end();

  // Trigger transmission and wait for completion
  strobe(STX);
  await(IDLE_MODE);

  return (len);
}

int
CC1101::send(uint8_t dest, uint8_t port, const void* buf, size_t len)
{
  iovec_t vec[2];
  iovec_t* vp = vec;
  iovec_arg(vp, buf, len);
  iovec_end(vp);
  return (send(dest, port, vec));
}

int
CC1101::recv(uint8_t& src, uint8_t& port, void* buf, size_t len, uint32_t ms)
{
  uint32_t start = RTC::millis();
  uint8_t size;

  // Put in receive mode and wait for incoming message
  strobe(SRX);
  m_avail = false;
  do {
    while (!m_avail && ((ms == 0) || (RTC::since(start) < ms))) yield();
    if (!m_avail) {
      strobe(SIDLE);
      return (-2);
    }
    // Check the received frame size
    spi.begin(this);
    loop_until_bit_is_clear(PIN, Board::MISO);
    size = read(RXBYTES);
    spi.end();
  } while ((size & BYTES_MASK) == 0);

  // Put in idle mode and read the payload
  strobe(SIDLE);

  // Read the payload size and check against buffer length
  spi.begin(this);
  loop_until_bit_is_clear(PIN, Board::MISO);
  m_status = spi.transfer(header_t(RXFIFO, 1, 1));
  size = spi.transfer(0) - 3;
  if (size > len) {
    spi.end();
    strobe(SFRX);
    return (-1);
  }

  // Read the frame header(dest, src, port), payload and link quality status
  m_dest = spi.transfer(0);
  src = spi.transfer(0);
  port = spi.transfer(0);
  spi.read(buf, size);
  spi.read(&m_recv_status, sizeof(m_recv_status));
  spi.end();

  // Fix: Add address checking for robustness
  return (size);
}

void
CC1101::powerdown()
{
  await(IDLE_MODE);
  strobe(SPWD);
}

void
CC1101::wakeup_on_radio()
{
  await(IDLE_MODE);
  strobe(SWOR);
}

void
CC1101::set_output_power_level(int8_t dBm)
{
  uint8_t pa = 0xC0;
  if      (dBm < -20) pa = 0x12;
  else if (dBm < -15) pa = 0x0E;
  else if (dBm < -10) pa = 0x1D;
  else if (dBm < 0)   pa = 0x34;
  else if (dBm < 5)   pa = 0x60;
  else if (dBm < 7)   pa = 0x84;
  else if (dBm < 10)  pa = 0xC4;
  spi.begin(this);
  loop_until_bit_is_clear(PIN, Board::MISO);
  write(PATABLE, pa);
  spi.end();
}

int
CC1101::get_input_power_level()
{
  int rssi = m_recv_status.rssi;
  return (((rssi < 128) ? rssi : rssi - 256) / 2 - 74);
}
#endif
<|endoftext|>


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

#include <unordered_map>

// Constructor.
AdjacencyList::AdjacencyList()
{
	adjacencyList = std::unordered_map<uint64_t, std::vector<uint64_t>>();
	sorted = false;
}

// Add an edge from a to b and from b to a.
void AdjacencyList::addEdge(uint64_t a, uint64_t b)
{
	sorted = false;
	addDirectedEdge(a, b);
	addDirectedEdge(b, a);
}

// Get a vertex's neighbors.
std::vector<uint64_t> AdjacencyList::getNeighbors(uint64_t vertexId)
{
	auto search = adjacencyList.find(vertexId);

	if (search == adjacencyList.end()) {
		return std::vector<uint64_t>();
	}

	return search->second;
}

// Get the sorted vertices.
std::set<Vertex> AdjacencyList::getSorted(bool byDegree)
{
	if (!sorted || this->byDegree != byDegree)
		sort(byDegree);
	return orderedVertices;
}

// Add a directed adge from a to b.
void AdjacencyList::addDirectedEdge(uint64_t a, uint64_t b)
{
	auto search = adjacencyList.find(a);
	std::vector<uint64_t> neighbors;

	if (search == adjacencyList.end())
	{
		neighbors = std::vector<uint64_t>();
		neighbors.push_back(b);
		adjacencyList.insert(std::make_pair(a, neighbors));
	}

	else
	{
		neighbors = search->second;
		neighbors.push_back(b);
		adjacencyList[a] = neighbors;
	}

}

// Sort the vertices
std::set<Vertex> AdjacencyList::sort(bool byDegree) {
	orderedVertices = std::set<Vertex>();

	for (auto it = adjacencyList.begin(); it != adjacencyList.end(); ++it)
	{
		Vertex vertex = {
			it->first,
			it->second.size(),
			byDegree
		};

		orderedVertices.insert(vertex);
	}

	this->byDegree = byDegree;
	this->sorted = true;

	return orderedVertices;
}<commit_msg>Fix addDirectedVertex to avoid duplicates<commit_after>#include "../include/AdjacencyList.h"

#include <unordered_map>

// Constructor.
AdjacencyList::AdjacencyList()
{
	adjacencyList = std::unordered_map<uint64_t, std::vector<uint64_t>>();
	sorted = false;
}

// Add an edge from a to b and from b to a.
void AdjacencyList::addEdge(uint64_t a, uint64_t b)
{
	sorted = false;
	addDirectedEdge(a, b);
	addDirectedEdge(b, a);
}

// Get a vertex's neighbors.
std::vector<uint64_t> AdjacencyList::getNeighbors(uint64_t vertexId)
{
	auto search = adjacencyList.find(vertexId);

	if (search == adjacencyList.end()) {
		return std::vector<uint64_t>();
	}

	return search->second;
}

// Get the sorted vertices.
std::set<Vertex> AdjacencyList::getSorted(bool byDegree)
{
	if (!sorted || this->byDegree != byDegree)
		sort(byDegree);
	return orderedVertices;
}

// Add a directed adge from a to b.
void AdjacencyList::addDirectedEdge(uint64_t a, uint64_t b)
{
	auto search = adjacencyList.find(a);
	std::vector<uint64_t> neighbors;

	if (search == adjacencyList.end())
	{
		neighbors = std::vector<uint64_t>();
		neighbors.push_back(b);
		adjacencyList.insert(std::make_pair(a, neighbors));
	}

	else
	{
		neighbors = search->second;
		if (std::find(neighbors.begin(), neighbors.end(), b) == neighbors.end())
		{
			neighbors.push_back(b);
			adjacencyList[a] = neighbors;
		}
	}

}

// Sort the vertices
std::set<Vertex> AdjacencyList::sort(bool byDegree) {
	orderedVertices = std::set<Vertex>();

	for (auto it = adjacencyList.begin(); it != adjacencyList.end(); ++it)
	{
		Vertex vertex = {
			it->first,
			it->second.size(),
			byDegree
		};

		orderedVertices.insert(vertex);
	}

	this->byDegree = byDegree;
	this->sorted = true;

	return orderedVertices;
}<|endoftext|>


<commit_before>//===-- asan_fake_stack.cc ------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// FakeStack is used to detect use-after-return bugs.
//===----------------------------------------------------------------------===//
#include "asan_allocator.h"
#include "asan_poisoning.h"
#include "asan_thread.h"

namespace __asan {

static const u64 kMagic1 = kAsanStackAfterReturnMagic;
static const u64 kMagic2 = (kMagic1 << 8) | kMagic1;
static const u64 kMagic4 = (kMagic2 << 16) | kMagic2;
static const u64 kMagic8 = (kMagic4 << 32) | kMagic4;

// For small size classes inline PoisonShadow for better performance.
ALWAYS_INLINE void SetShadow(uptr ptr, uptr size, uptr class_id, u64 magic) {
  CHECK_EQ(SHADOW_SCALE, 3);  // This code expects SHADOW_SCALE=3.
  u64 *shadow = reinterpret_cast<u64*>(MemToShadow(ptr));
  if (class_id <= 6) {
    for (uptr i = 0; i < (1U << class_id); i++)
      shadow[i] = magic;
  } else {
    // The size class is too big, it's cheaper to poison only size bytes.
    PoisonShadow(ptr, size, static_cast<u8>(magic));
  }
}

void FakeStack::PoisonAll(u8 magic) {
  PoisonShadow(reinterpret_cast<uptr>(this), RequiredSize(stack_size_log()),
               magic);
}

ALWAYS_INLINE USED
FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id,
                               uptr real_stack) {
  CHECK_LT(class_id, kNumberOfSizeClasses);
  if (needs_gc_)
    GC(real_stack);
  uptr &hint_position = hint_position_[class_id];
  const int num_iter = NumberOfFrames(stack_size_log, class_id);
  u8 *flags = GetFlags(stack_size_log, class_id);
  for (int i = 0; i < num_iter; i++) {
    uptr pos = ModuloNumberOfFrames(stack_size_log, class_id, hint_position++);
    // This part is tricky. On one hand, checking and setting flags[pos]
    // should be atomic to ensure async-signal safety. But on the other hand,
    // if the signal arrives between checking and setting flags[pos], the
    // signal handler's fake stack will start from a different hint_position
    // and so will not touch this particular byte. So, it is safe to do this
    // with regular non-atimic load and store (at least I was not able to make
    // this code crash).
    if (flags[pos]) continue;
    flags[pos] = 1;
    FakeFrame *res = reinterpret_cast<FakeFrame *>(
        GetFrame(stack_size_log, class_id, pos));
    res->real_stack = real_stack;
    return res;
  }
  CHECK(0 && "Failed to allocate a fake stack frame");
  return 0;
}

ALWAYS_INLINE USED
void FakeStack::Deallocate(FakeFrame *ff, uptr stack_size_log, uptr class_id,
                           uptr real_stack) {
  u8 *base = GetFrame(stack_size_log, class_id, 0);
  u8 *cur = reinterpret_cast<u8 *>(ff);
  CHECK_LE(base, cur);
  CHECK_LT(cur, base + (1UL << stack_size_log));
  uptr pos = (cur - base) >> (kMinStackFrameSizeLog + class_id);
  u8 *flags = GetFlags(stack_size_log, class_id);
  CHECK_EQ(flags[pos], 1);
  flags[pos] = 0;
}

uptr FakeStack::AddrIsInFakeStack(uptr ptr) {
  uptr stack_size_log = this->stack_size_log();
  uptr beg = reinterpret_cast<uptr>(GetFrame(stack_size_log, 0, 0));
  uptr end = reinterpret_cast<uptr>(this) + RequiredSize(stack_size_log);
  if (ptr < beg || ptr >= end) return 0;
  uptr class_id = (ptr - beg) >> stack_size_log;
  uptr base = beg + (class_id << stack_size_log);
  CHECK_LE(base, ptr);
  CHECK_LT(ptr, base + (1UL << stack_size_log));
  uptr pos = (ptr - base) >> (kMinStackFrameSizeLog + class_id);
  return base + pos * BytesInSizeClass(class_id);
}

void FakeStack::HandleNoReturn() {
  needs_gc_ = true;
}

// When throw, longjmp or some such happens we don't call OnFree() and
// as the result may leak one or more fake frames, but the good news is that
// we are notified about all such events by HandleNoReturn().
// If we recently had such no-return event we need to collect garbage frames.
// We do it based on their 'real_stack' values -- everything that is lower
// than the current real_stack is garbage.
NOINLINE void FakeStack::GC(uptr real_stack) {
  uptr collected = 0;
  for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) {
    u8 *flags = GetFlags(stack_size_log(), class_id);
    for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n;
         i++) {
      if (flags[i] == 0) continue;  // not allocated.
      FakeFrame *ff = reinterpret_cast<FakeFrame *>(
          GetFrame(stack_size_log(), class_id, i));
      if (ff->real_stack < real_stack) {
        flags[i] = 0;
        collected++;
      }
    }
  }
  needs_gc_ = false;
}

#if SANITIZER_LINUX
static THREADLOCAL FakeStack *fake_stack_tls;

FakeStack *GetTLSFakeStack() {
  return fake_stack_tls;
}
void SetTLSFakeStack(FakeStack *fs) {
  fake_stack_tls = fs;
}
#else
FakeStack *GetTLSFakeStack() { return 0; }
void SetTLSFakeStack(FakeStack *fs) { }
#endif  // SANITIZER_LINUX

static FakeStack *GetFakeStack() {
  AsanThread *t = GetCurrentThread();
  if (!t) return 0;
  return t->fake_stack();
}

static FakeStack *GetFakeStackFast() {
  if (FakeStack *fs = GetTLSFakeStack())
    return fs;
  return GetFakeStack();
}

ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size, uptr real_stack) {
  FakeStack *fs = GetFakeStackFast();
  if (!fs) return real_stack;
  FakeFrame *ff = fs->Allocate(fs->stack_size_log(), class_id, real_stack);
  uptr ptr = reinterpret_cast<uptr>(ff);
  SetShadow(ptr, size, class_id, 0);
  return ptr;
}

ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size, uptr real_stack) {
  if (ptr == real_stack)
    return;
  FakeStack *fs = GetFakeStackFast();  // Must not be 0.
  FakeFrame *ff = reinterpret_cast<FakeFrame *>(ptr);
  fs->Deallocate(ff, fs->stack_size_log(), class_id, real_stack);
  SetShadow(ptr, size, class_id, kMagic8);
}

}  // namespace __asan

// ---------------------- Interface ---------------- {{{1
#define DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(class_id)                       \
  extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr                                \
  __asan_stack_malloc_##class_id(uptr size, uptr real_stack) {                 \
    return __asan::OnMalloc(class_id, size, real_stack);                       \
  }                                                                            \
  extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_stack_free_##class_id(  \
      uptr ptr, uptr size, uptr real_stack) {                                  \
    __asan::OnFree(ptr, class_id, size, real_stack);                           \
  }

DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(0)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(1)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(2)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(3)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(4)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(5)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(6)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(7)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(8)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(9)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(10)
<commit_msg>[asan] Android does not have TLS<commit_after>//===-- asan_fake_stack.cc ------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// FakeStack is used to detect use-after-return bugs.
//===----------------------------------------------------------------------===//
#include "asan_allocator.h"
#include "asan_poisoning.h"
#include "asan_thread.h"

namespace __asan {

static const u64 kMagic1 = kAsanStackAfterReturnMagic;
static const u64 kMagic2 = (kMagic1 << 8) | kMagic1;
static const u64 kMagic4 = (kMagic2 << 16) | kMagic2;
static const u64 kMagic8 = (kMagic4 << 32) | kMagic4;

// For small size classes inline PoisonShadow for better performance.
ALWAYS_INLINE void SetShadow(uptr ptr, uptr size, uptr class_id, u64 magic) {
  CHECK_EQ(SHADOW_SCALE, 3);  // This code expects SHADOW_SCALE=3.
  u64 *shadow = reinterpret_cast<u64*>(MemToShadow(ptr));
  if (class_id <= 6) {
    for (uptr i = 0; i < (1U << class_id); i++)
      shadow[i] = magic;
  } else {
    // The size class is too big, it's cheaper to poison only size bytes.
    PoisonShadow(ptr, size, static_cast<u8>(magic));
  }
}

void FakeStack::PoisonAll(u8 magic) {
  PoisonShadow(reinterpret_cast<uptr>(this), RequiredSize(stack_size_log()),
               magic);
}

ALWAYS_INLINE USED
FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id,
                               uptr real_stack) {
  CHECK_LT(class_id, kNumberOfSizeClasses);
  if (needs_gc_)
    GC(real_stack);
  uptr &hint_position = hint_position_[class_id];
  const int num_iter = NumberOfFrames(stack_size_log, class_id);
  u8 *flags = GetFlags(stack_size_log, class_id);
  for (int i = 0; i < num_iter; i++) {
    uptr pos = ModuloNumberOfFrames(stack_size_log, class_id, hint_position++);
    // This part is tricky. On one hand, checking and setting flags[pos]
    // should be atomic to ensure async-signal safety. But on the other hand,
    // if the signal arrives between checking and setting flags[pos], the
    // signal handler's fake stack will start from a different hint_position
    // and so will not touch this particular byte. So, it is safe to do this
    // with regular non-atimic load and store (at least I was not able to make
    // this code crash).
    if (flags[pos]) continue;
    flags[pos] = 1;
    FakeFrame *res = reinterpret_cast<FakeFrame *>(
        GetFrame(stack_size_log, class_id, pos));
    res->real_stack = real_stack;
    return res;
  }
  CHECK(0 && "Failed to allocate a fake stack frame");
  return 0;
}

ALWAYS_INLINE USED
void FakeStack::Deallocate(FakeFrame *ff, uptr stack_size_log, uptr class_id,
                           uptr real_stack) {
  u8 *base = GetFrame(stack_size_log, class_id, 0);
  u8 *cur = reinterpret_cast<u8 *>(ff);
  CHECK_LE(base, cur);
  CHECK_LT(cur, base + (1UL << stack_size_log));
  uptr pos = (cur - base) >> (kMinStackFrameSizeLog + class_id);
  u8 *flags = GetFlags(stack_size_log, class_id);
  CHECK_EQ(flags[pos], 1);
  flags[pos] = 0;
}

uptr FakeStack::AddrIsInFakeStack(uptr ptr) {
  uptr stack_size_log = this->stack_size_log();
  uptr beg = reinterpret_cast<uptr>(GetFrame(stack_size_log, 0, 0));
  uptr end = reinterpret_cast<uptr>(this) + RequiredSize(stack_size_log);
  if (ptr < beg || ptr >= end) return 0;
  uptr class_id = (ptr - beg) >> stack_size_log;
  uptr base = beg + (class_id << stack_size_log);
  CHECK_LE(base, ptr);
  CHECK_LT(ptr, base + (1UL << stack_size_log));
  uptr pos = (ptr - base) >> (kMinStackFrameSizeLog + class_id);
  return base + pos * BytesInSizeClass(class_id);
}

void FakeStack::HandleNoReturn() {
  needs_gc_ = true;
}

// When throw, longjmp or some such happens we don't call OnFree() and
// as the result may leak one or more fake frames, but the good news is that
// we are notified about all such events by HandleNoReturn().
// If we recently had such no-return event we need to collect garbage frames.
// We do it based on their 'real_stack' values -- everything that is lower
// than the current real_stack is garbage.
NOINLINE void FakeStack::GC(uptr real_stack) {
  uptr collected = 0;
  for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) {
    u8 *flags = GetFlags(stack_size_log(), class_id);
    for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n;
         i++) {
      if (flags[i] == 0) continue;  // not allocated.
      FakeFrame *ff = reinterpret_cast<FakeFrame *>(
          GetFrame(stack_size_log(), class_id, i));
      if (ff->real_stack < real_stack) {
        flags[i] = 0;
        collected++;
      }
    }
  }
  needs_gc_ = false;
}

#if SANITIZER_LINUX && !SANITIZER_ANDROID
static THREADLOCAL FakeStack *fake_stack_tls;

FakeStack *GetTLSFakeStack() {
  return fake_stack_tls;
}
void SetTLSFakeStack(FakeStack *fs) {
  fake_stack_tls = fs;
}
#else
FakeStack *GetTLSFakeStack() { return 0; }
void SetTLSFakeStack(FakeStack *fs) { }
#endif  // SANITIZER_LINUX && !SANITIZER_ANDROID

static FakeStack *GetFakeStack() {
  AsanThread *t = GetCurrentThread();
  if (!t) return 0;
  return t->fake_stack();
}

static FakeStack *GetFakeStackFast() {
  if (FakeStack *fs = GetTLSFakeStack())
    return fs;
  return GetFakeStack();
}

ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size, uptr real_stack) {
  FakeStack *fs = GetFakeStackFast();
  if (!fs) return real_stack;
  FakeFrame *ff = fs->Allocate(fs->stack_size_log(), class_id, real_stack);
  uptr ptr = reinterpret_cast<uptr>(ff);
  SetShadow(ptr, size, class_id, 0);
  return ptr;
}

ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size, uptr real_stack) {
  if (ptr == real_stack)
    return;
  FakeStack *fs = GetFakeStackFast();  // Must not be 0.
  FakeFrame *ff = reinterpret_cast<FakeFrame *>(ptr);
  fs->Deallocate(ff, fs->stack_size_log(), class_id, real_stack);
  SetShadow(ptr, size, class_id, kMagic8);
}

}  // namespace __asan

// ---------------------- Interface ---------------- {{{1
#define DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(class_id)                       \
  extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr                                \
  __asan_stack_malloc_##class_id(uptr size, uptr real_stack) {                 \
    return __asan::OnMalloc(class_id, size, real_stack);                       \
  }                                                                            \
  extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_stack_free_##class_id(  \
      uptr ptr, uptr size, uptr real_stack) {                                  \
    __asan::OnFree(ptr, class_id, size, real_stack);                           \
  }

DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(0)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(1)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(2)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(3)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(4)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(5)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(6)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(7)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(8)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(9)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(10)
<|endoftext|>


<commit_before>#include "util/file_piece.hh"

#include "util/file.hh"
#include "util/scoped.hh"
#include "util/string_piece.hh"
#include "util/tokenize_piece.hh"
#include "util/murmur_hash.hh"
#include "util/probing_hash_table.hh"
#include "util/usage.hh"

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <fstream>
#include <iostream>
#include <set> //For counting

//Struct for holding processed line
struct line_text {
	StringPiece source_phrase;
	StringPiece target_phrase;
	StringPiece prob;
	StringPiece word_all1;
	StringPiece word_all2;
};

//Ask if it's better to have it receive a pointer to a line_text struct
line_text splitLine(StringPiece textin);

uint64_t getHash(StringPiece text);

uint64_t getHash(StringPiece text) {
	std::size_t len = text.size();
	uint64_t key = util::MurmurHashNative(text.data(), len);
	return key;
}

line_text splitLine(StringPiece textin) {
	const char delim[] = " ||| ";
	std::string temp; //Temp string for conversion
	int num;
	line_text output;

	//Tokenize
	util::TokenIter<util::MultiCharacter> it(textin, util::MultiCharacter(delim));
	//Get source phrase
	output.source_phrase = *it;
	it++;
	//Get target_phrase
	output.target_phrase = *it;
	it++;
	//Get probabilities
	output.prob = *it;
	it++;
	//Get WordAllignment 1
	output.word_all1 = *it;
	it++;
	//Get WordAllignment 2
	output.word_all2 = *it;

	return output;
}

int main(int argc, char* argv[]){
	if (argc != 2) {
		// Tell the user how to run the program
		std::cerr << "Provided " << argc - 1 << " arguments, needed 1." << std::endl;
		std::cerr << "Usage: " << argv[0] << " path_to_phrasetable" << std::endl;
		return 1;
	}
	util::FilePiece filein(argv[1]);
	std::set<uint64_t> hashes;
	unsigned long setsize = hashes.size();
	unsigned int clashes = 0;
	unsigned long lines = 0;

	while(true){
		try{
			line_text newline = splitLine(filein.ReadLine());
			uint64_t hash = getHash(newline.source_phrase); //Get hash
			hashes.insert(hash); //Insert it in the set
			unsigned long newsize = hashes.size();
			if (newsize == setsize){
				clashes++; //We have a clash
			}else{
				setsize = newsize;
			}
			lines++;
			if (lines%10000 == 0){
				std::cout << "On line: " << lines << std::endl;
			}
		} catch (util::EndOfFileException e){
			std::cout << "End of file" << std::endl;
			break;
		}
	}

	std::cout << "Entries: " << lines << " Collisions: " << clashes << std::endl
}<commit_msg>Add missing ;<commit_after>#include "util/file_piece.hh"

#include "util/file.hh"
#include "util/scoped.hh"
#include "util/string_piece.hh"
#include "util/tokenize_piece.hh"
#include "util/murmur_hash.hh"
#include "util/probing_hash_table.hh"
#include "util/usage.hh"

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <fstream>
#include <iostream>
#include <set> //For counting

//Struct for holding processed line
struct line_text {
	StringPiece source_phrase;
	StringPiece target_phrase;
	StringPiece prob;
	StringPiece word_all1;
	StringPiece word_all2;
};

//Ask if it's better to have it receive a pointer to a line_text struct
line_text splitLine(StringPiece textin);

uint64_t getHash(StringPiece text);

uint64_t getHash(StringPiece text) {
	std::size_t len = text.size();
	uint64_t key = util::MurmurHashNative(text.data(), len);
	return key;
}

line_text splitLine(StringPiece textin) {
	const char delim[] = " ||| ";
	std::string temp; //Temp string for conversion
	int num;
	line_text output;

	//Tokenize
	util::TokenIter<util::MultiCharacter> it(textin, util::MultiCharacter(delim));
	//Get source phrase
	output.source_phrase = *it;
	it++;
	//Get target_phrase
	output.target_phrase = *it;
	it++;
	//Get probabilities
	output.prob = *it;
	it++;
	//Get WordAllignment 1
	output.word_all1 = *it;
	it++;
	//Get WordAllignment 2
	output.word_all2 = *it;

	return output;
}

int main(int argc, char* argv[]){
	if (argc != 2) {
		// Tell the user how to run the program
		std::cerr << "Provided " << argc - 1 << " arguments, needed 1." << std::endl;
		std::cerr << "Usage: " << argv[0] << " path_to_phrasetable" << std::endl;
		return 1;
	}
	util::FilePiece filein(argv[1]);
	std::set<uint64_t> hashes;
	unsigned long setsize = hashes.size();
	unsigned int clashes = 0;
	unsigned long lines = 0;

	while(true){
		try{
			line_text newline = splitLine(filein.ReadLine());
			uint64_t hash = getHash(newline.source_phrase); //Get hash
			hashes.insert(hash); //Insert it in the set
			unsigned long newsize = hashes.size();
			if (newsize == setsize){
				clashes++; //We have a clash
			}else{
				setsize = newsize;
			}
			lines++;
			if (lines%10000 == 0){
				std::cout << "On line: " << lines << std::endl;
			}
		} catch (util::EndOfFileException e){
			std::cout << "End of file" << std::endl;
			break;
		}
	}

	std::cout << "Entries: " << lines << " Collisions: " << clashes << std::endl;
}<|endoftext|>


<commit_before>#include <StdAfx.h>
#include <UI/Controls/PaneHeader/PaneHeader.h>
#include <UI/UIFunctions.h>
#include <core/utility/strings.h>
#include <UI/DoubleBuffer.h>
#include <core/utility/output.h>

namespace controls
{
	static std::wstring CLASS = L"PaneHeader";

	PaneHeader::~PaneHeader()
	{
		TRACE_DESTRUCTOR(CLASS);
		CWnd::DestroyWindow();
	}

	void PaneHeader::Initialize(HWND hWnd, _In_opt_ HDC hdc, _In_ UINT nid)
	{
		m_hWndParent = hWnd;

		// Assign a nID to the collapse button that is IDD_COLLAPSE more than the control's nID
		m_nID = nid;
		m_nIDCollapse = nid + IDD_COLLAPSE;

		WNDCLASSEX wc = {};
		const auto hInst = AfxGetInstanceHandle();
		if (!::GetClassInfoEx(hInst, _T("PaneHeader"), &wc)) // STRING_OK
		{
			wc.cbSize = sizeof wc;
			wc.style = 0; // not passing CS_VREDRAW | CS_HREDRAW fixes flicker
			wc.lpszClassName = _T("PaneHeader"); // STRING_OK
			wc.lpfnWndProc = ::DefWindowProc;
			wc.hbrBackground = GetSysBrush(ui::uiColor::Background); // helps spot flashing

			RegisterClassEx(&wc);
		}

		// WS_CLIPCHILDREN is used to reduce flicker
		EC_B_S(CreateEx(
			0,
			_T("PaneHeader"), // STRING_OK
			_T("PaneHeader"), // STRING_OK
			WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE,
			0,
			0,
			0,
			0,
			m_hWndParent,
			reinterpret_cast<HMENU>(static_cast<INT_PTR>(IDC_PANE_HEADER)),
			nullptr));

		// We hang if we do this:
		// Necessary for TAB to work. Without this, all TABS get stuck on the control
		// instead of passing to the children.
		//EC_B_S(ModifyStyleEx(0, WS_EX_CONTROLPARENT));

		const auto sizeText = ui::GetTextExtentPoint32(hdc, m_szLabel);
		m_iLabelWidth = sizeText.cx;
		output::DebugPrint(
			output::dbgLevel::Draw,
			L"PaneHeader::Initialize m_iLabelWidth:%d \"%ws\"\n",
			m_iLabelWidth,
			m_szLabel.c_str());
	}

	BEGIN_MESSAGE_MAP(PaneHeader, CWnd)
	ON_WM_CREATE()
	ON_WM_WINDOWPOSCHANGED()
	END_MESSAGE_MAP()

	int PaneHeader::OnCreate(LPCREATESTRUCT /*lpCreateStruct*/)
	{
		EC_B_S(m_leftLabel.Create(
			WS_CHILD | WS_CLIPSIBLINGS | ES_READONLY | WS_VISIBLE | WS_TABSTOP, CRect(0, 0, 0, 0), this, m_nID));
		::SetWindowTextW(m_leftLabel.m_hWnd, m_szLabel.c_str());
		ui::SubclassLabel(m_leftLabel.m_hWnd);
		if (m_bCollapsible)
		{
			StyleLabel(m_leftLabel.m_hWnd, ui::uiLabelStyle::PaneHeaderLabel);
		}

		EC_B_S(m_rightLabel.Create(
			WS_CHILD | WS_CLIPSIBLINGS | ES_READONLY | WS_VISIBLE | WS_TABSTOP,
			CRect(0, 0, 0, 0),
			this,
			IDD_COUNTLABEL));
		ui::SubclassLabel(m_rightLabel.m_hWnd);
		StyleLabel(m_rightLabel.m_hWnd, ui::uiLabelStyle::PaneHeaderText);

		if (m_bCollapsible)
		{
			EC_B_S(m_CollapseButton.Create(
				nullptr, WS_TABSTOP | WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, CRect(0, 0, 0, 0), this, m_nIDCollapse));
			StyleButton(
				m_CollapseButton.m_hWnd, m_bCollapsed ? ui::uiButtonStyle::UpArrow : ui::uiButtonStyle::DownArrow);
		}

		// If we need an action button, go ahead and create it
		if (m_nIDAction)
		{
			EC_B_S(m_actionButton.Create(
				strings::wstringTotstring(m_szActionButton).c_str(),
				WS_TABSTOP | WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
				CRect(0, 0, 0, 0),
				this,
				m_nIDAction));
			StyleButton(m_actionButton.m_hWnd, ui::uiButtonStyle::Unstyled);
		}

		m_bInitialized = true;
		return 0;
	}

	LRESULT PaneHeader::WindowProc(const UINT message, const WPARAM wParam, const LPARAM lParam)
	{
		LRESULT lRes = 0;
		if (ui::HandleControlUI(message, wParam, lParam, &lRes)) return lRes;

		switch (message)
		{
		case WM_CLOSE:
			::SendMessage(m_hWndParent, message, wParam, lParam);
			return true;
		case WM_HELP:
			return true;
		case WM_COMMAND:
		{
			const auto nCode = HIWORD(wParam);
			if (EN_CHANGE == nCode || CBN_SELCHANGE == nCode || CBN_EDITCHANGE == nCode || BN_CLICKED == nCode)
			{
				::SendMessage(m_hWndParent, message, wParam, lParam);
			}

			break;
		}
		}

		return CWnd::WindowProc(message, wParam, lParam);
	}

	// Draw our collapse button and label, if needed.
	// Draws everything to GetFixedHeight()
	void PaneHeader::OnWindowPosChanged(WINDOWPOS* lpwndpos)
	{
		if (!m_bInitialized || !lpwndpos) return; // TODO: wrap
		auto hWinPosInfo = WC_D(HDWP, BeginDeferWindowPos(2));
		if (hWinPosInfo)
		{
			const auto width = lpwndpos->cx;
			const auto height = lpwndpos->cy;
			output::DebugPrint(
				output::dbgLevel::Draw,
				L"PaneHeader::DeferWindowPos width:%d height:%d v:%d\n",
				width,
				height,
				IsWindowVisible());
			auto curX = 0;
			const auto actionButtonWidth = m_actionButtonWidth ? m_actionButtonWidth + 2 * m_iMargin : 0;
			const auto actionButtonAndGutterWidth = actionButtonWidth ? actionButtonWidth + m_iSideMargin : 0;
			if (m_bCollapsible)
			{
				hWinPosInfo = ui::DeferWindowPos(
					hWinPosInfo,
					m_CollapseButton.GetSafeHwnd(),
					curX,
					0,
					width - actionButtonAndGutterWidth,
					height,
					L"PaneHeader::DeferWindowPos::collapseButton");
				curX += m_iButtonHeight;
			}

			hWinPosInfo = ui::DeferWindowPos(
				hWinPosInfo,
				m_leftLabel.GetSafeHwnd(),
				curX,
				0,
				m_iLabelWidth,
				height,
				L"PaneHeader::DeferWindowPos::leftLabel");

			if (!m_bCollapsed)
			{
				// Drop the count on top of the label we drew above
				if (m_rightLabel.GetSafeHwnd())
				{
					hWinPosInfo = ui::DeferWindowPos(
						hWinPosInfo,
						m_rightLabel.GetSafeHwnd(),
						width - m_rightLabelWidth - actionButtonAndGutterWidth,
						0,
						m_rightLabelWidth,
						height,
						L"PaneHeader::DeferWindowPos::rightLabel");
				}
			}

			if (m_nIDAction)
			{
				// Drop the action button next to the label we drew above
				hWinPosInfo = ui::DeferWindowPos(
					hWinPosInfo,
					m_actionButton.GetSafeHwnd(),
					width - actionButtonWidth,
					0,
					actionButtonWidth,
					height,
					L"PaneHeader::DeferWindowPos::actionButton");
			}

			output::DebugPrint(output::dbgLevel::Draw, L"PaneHeader::DeferWindowPos end\n");
			EC_B_S(EndDeferWindowPos(hWinPosInfo));
		}

		return CWnd::OnWindowPosChanged(lpwndpos);
	}

	void PaneHeader::Redraw()
	{
		// Trigger a redraw
		RECT rcControl = {0};
		::GetWindowRect(GetSafeHwnd(), &rcControl);
		::MoveWindow(
			GetSafeHwnd(),
			rcControl.left,
			rcControl.top,
			rcControl.right - rcControl.left,
			rcControl.bottom - rcControl.top,
			false);
	}

	int PaneHeader::GetMinWidth()
	{
		auto cx = m_iLabelWidth;
		if (m_bCollapsible) cx += m_iButtonHeight;
		if (m_rightLabelWidth)
		{
			cx += m_iSideMargin;
			cx += m_rightLabelWidth;
		}

		if (m_actionButtonWidth)
		{
			cx += m_iSideMargin;
			cx += m_actionButtonWidth + 2 * m_iMargin;
		}

		return cx;
	}

	void PaneHeader::SetRightLabel(const std::wstring szLabel)
	{
		if (!m_bInitialized) return;
		EC_B_S(::SetWindowTextW(m_rightLabel.m_hWnd, szLabel.c_str()));

		const auto hdc = ::GetDC(m_rightLabel.GetSafeHwnd());
		const auto hfontOld = SelectObject(hdc, ui::GetSegoeFont());
		const auto sizeText = ui::GetTextExtentPoint32(hdc, szLabel);
		static_cast<void>(SelectObject(hdc, hfontOld));
		::ReleaseDC(m_rightLabel.GetSafeHwnd(), hdc);
		m_rightLabelWidth = sizeText.cx;

		Redraw();
	}

	void PaneHeader::SetActionButton(const std::wstring szActionButton)
	{
		// Don't bother if we never enabled the button
		if (m_nIDAction == 0) return;

		EC_B_S(::SetWindowTextW(m_actionButton.GetSafeHwnd(), szActionButton.c_str()));

		m_szActionButton = szActionButton;
		const auto hdc = ::GetDC(m_actionButton.GetSafeHwnd());
		const auto hfontOld = SelectObject(hdc, ui::GetSegoeFont());
		const auto sizeText = ui::GetTextExtentPoint32(hdc, szActionButton);
		static_cast<void>(SelectObject(hdc, hfontOld));
		::ReleaseDC(m_actionButton.GetSafeHwnd(), hdc);
		m_actionButtonWidth = sizeText.cx;

		Redraw();
	}

	bool PaneHeader::HandleChange(UINT nID)
	{
		// Collapse buttons have a nID IDD_COLLAPSE higher than nID of the pane they toggle.
		// So if we get asked about one that matches, we can assume it's time to toggle our collapse.
		if (m_nIDCollapse == nID)
		{
			OnToggleCollapse();
			return true;
		}

		return false;
	}

	void PaneHeader::OnToggleCollapse()
	{
		m_bCollapsed = !m_bCollapsed;

		StyleButton(m_CollapseButton.m_hWnd, m_bCollapsed ? ui::uiButtonStyle::UpArrow : ui::uiButtonStyle::DownArrow);
		WC_B_S(m_rightLabel.ShowWindow(m_bCollapsed ? SW_HIDE : SW_SHOW));

		// Trigger a redraw
		::PostMessage(m_hWndParent, WM_COMMAND, IDD_RECALCLAYOUT, NULL);
	}

	void PaneHeader::SetMargins(
		int iMargin,
		int iSideMargin,
		int iLabelHeight, // Height of the label
		int iButtonHeight) // Height of button
	{
		m_iMargin = iMargin;
		m_iSideMargin = iSideMargin;
		m_iLabelHeight = iLabelHeight;
		m_iButtonHeight = iButtonHeight;
	}
} // namespace controls<commit_msg>clear background<commit_after>#include <StdAfx.h>
#include <UI/Controls/PaneHeader/PaneHeader.h>
#include <UI/UIFunctions.h>
#include <core/utility/strings.h>
#include <UI/DoubleBuffer.h>
#include <core/utility/output.h>
#include <core/utility/registry.h>

namespace controls
{
	static std::wstring CLASS = L"PaneHeader";

	PaneHeader::~PaneHeader()
	{
		TRACE_DESTRUCTOR(CLASS);
		CWnd::DestroyWindow();
	}

	void PaneHeader::Initialize(HWND hWnd, _In_opt_ HDC hdc, _In_ UINT nid)
	{
		m_hWndParent = hWnd;

		// Assign a nID to the collapse button that is IDD_COLLAPSE more than the control's nID
		m_nID = nid;
		m_nIDCollapse = nid + IDD_COLLAPSE;

		WNDCLASSEX wc = {};
		const auto hInst = AfxGetInstanceHandle();
		if (!::GetClassInfoEx(hInst, _T("PaneHeader"), &wc)) // STRING_OK
		{
			wc.cbSize = sizeof wc;
			wc.style = 0; // not passing CS_VREDRAW | CS_HREDRAW fixes flicker
			wc.lpszClassName = _T("PaneHeader"); // STRING_OK
			wc.lpfnWndProc = ::DefWindowProc;
			wc.hbrBackground = GetSysBrush(ui::uiColor::Background); // helps spot flashing

			RegisterClassEx(&wc);
		}

		// WS_CLIPCHILDREN is used to reduce flicker
		EC_B_S(CreateEx(
			0,
			_T("PaneHeader"), // STRING_OK
			_T("PaneHeader"), // STRING_OK
			WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE,
			0,
			0,
			0,
			0,
			m_hWndParent,
			reinterpret_cast<HMENU>(static_cast<INT_PTR>(IDC_PANE_HEADER)),
			nullptr));

		// We hang if we do this:
		// Necessary for TAB to work. Without this, all TABS get stuck on the control
		// instead of passing to the children.
		//EC_B_S(ModifyStyleEx(0, WS_EX_CONTROLPARENT));

		const auto sizeText = ui::GetTextExtentPoint32(hdc, m_szLabel);
		m_iLabelWidth = sizeText.cx;
		output::DebugPrint(
			output::dbgLevel::Draw,
			L"PaneHeader::Initialize m_iLabelWidth:%d \"%ws\"\n",
			m_iLabelWidth,
			m_szLabel.c_str());
	}

	BEGIN_MESSAGE_MAP(PaneHeader, CWnd)
	ON_WM_CREATE()
	ON_WM_WINDOWPOSCHANGED()
	END_MESSAGE_MAP()

	int PaneHeader::OnCreate(LPCREATESTRUCT /*lpCreateStruct*/)
	{
		EC_B_S(m_leftLabel.Create(
			WS_CHILD | WS_CLIPSIBLINGS | ES_READONLY | WS_VISIBLE | WS_TABSTOP, CRect(0, 0, 0, 0), this, m_nID));
		::SetWindowTextW(m_leftLabel.m_hWnd, m_szLabel.c_str());
		ui::SubclassLabel(m_leftLabel.m_hWnd);
		if (m_bCollapsible)
		{
			StyleLabel(m_leftLabel.m_hWnd, ui::uiLabelStyle::PaneHeaderLabel);
		}

		EC_B_S(m_rightLabel.Create(
			WS_CHILD | WS_CLIPSIBLINGS | ES_READONLY | WS_VISIBLE | WS_TABSTOP,
			CRect(0, 0, 0, 0),
			this,
			IDD_COUNTLABEL));
		ui::SubclassLabel(m_rightLabel.m_hWnd);
		StyleLabel(m_rightLabel.m_hWnd, ui::uiLabelStyle::PaneHeaderText);

		if (m_bCollapsible)
		{
			EC_B_S(m_CollapseButton.Create(
				nullptr, WS_TABSTOP | WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, CRect(0, 0, 0, 0), this, m_nIDCollapse));
			StyleButton(
				m_CollapseButton.m_hWnd, m_bCollapsed ? ui::uiButtonStyle::UpArrow : ui::uiButtonStyle::DownArrow);
		}

		// If we need an action button, go ahead and create it
		if (m_nIDAction)
		{
			EC_B_S(m_actionButton.Create(
				strings::wstringTotstring(m_szActionButton).c_str(),
				WS_TABSTOP | WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
				CRect(0, 0, 0, 0),
				this,
				m_nIDAction));
			StyleButton(m_actionButton.m_hWnd, ui::uiButtonStyle::Unstyled);
		}

		m_bInitialized = true;
		return 0;
	}

	LRESULT PaneHeader::WindowProc(const UINT message, const WPARAM wParam, const LPARAM lParam)
	{
		LRESULT lRes = 0;
		if (ui::HandleControlUI(message, wParam, lParam, &lRes)) return lRes;

		switch (message)
		{
		case WM_PAINT:
			auto ps = PAINTSTRUCT{};
			::BeginPaint(m_hWnd, &ps);
			if (ps.hdc)
			{
				auto rcWin = RECT{};
				::GetClientRect(m_hWnd, &rcWin);
				const auto background = registry::uiDiag ? ui::GetSysBrush(ui::uiColor::TestGreen)
														 : ui::GetSysBrush(ui::uiColor::Background);
				FillRect(ps.hdc, &rcWin, background);
			}

			::EndPaint(m_hWnd, &ps);
			return 0;
			break;
		case WM_CLOSE:
			::SendMessage(m_hWndParent, message, wParam, lParam);
			return true;
		case WM_HELP:
			return true;
		case WM_COMMAND:
		{
			const auto nCode = HIWORD(wParam);
			if (EN_CHANGE == nCode || CBN_SELCHANGE == nCode || CBN_EDITCHANGE == nCode || BN_CLICKED == nCode)
			{
				::SendMessage(m_hWndParent, message, wParam, lParam);
			}

			break;
		}
		}

		return CWnd::WindowProc(message, wParam, lParam);
	}

	// Draw our collapse button and label, if needed.
	// Draws everything to GetFixedHeight()
	void PaneHeader::OnWindowPosChanged(WINDOWPOS* lpwndpos)
	{
		if (!m_bInitialized || !lpwndpos) return; // TODO: wrap
		auto hWinPosInfo = WC_D(HDWP, BeginDeferWindowPos(2));
		if (hWinPosInfo)
		{
			const auto width = lpwndpos->cx;
			const auto height = lpwndpos->cy;
			output::DebugPrint(
				output::dbgLevel::Draw,
				L"PaneHeader::DeferWindowPos width:%d height:%d v:%d\n",
				width,
				height,
				IsWindowVisible());
			auto curX = 0;
			const auto actionButtonWidth = m_actionButtonWidth ? m_actionButtonWidth + 2 * m_iMargin : 0;
			const auto actionButtonAndGutterWidth = actionButtonWidth ? actionButtonWidth + m_iSideMargin : 0;
			if (m_bCollapsible)
			{
				hWinPosInfo = ui::DeferWindowPos(
					hWinPosInfo,
					m_CollapseButton.GetSafeHwnd(),
					curX,
					0,
					width - actionButtonAndGutterWidth,
					height,
					L"PaneHeader::DeferWindowPos::collapseButton");
				curX += m_iButtonHeight;
			}

			hWinPosInfo = ui::DeferWindowPos(
				hWinPosInfo,
				m_leftLabel.GetSafeHwnd(),
				curX,
				0,
				m_iLabelWidth,
				height,
				L"PaneHeader::DeferWindowPos::leftLabel");

			if (!m_bCollapsed)
			{
				// Drop the count on top of the label we drew above
				if (m_rightLabel.GetSafeHwnd())
				{
					hWinPosInfo = ui::DeferWindowPos(
						hWinPosInfo,
						m_rightLabel.GetSafeHwnd(),
						width - m_rightLabelWidth - actionButtonAndGutterWidth,
						0,
						m_rightLabelWidth,
						height,
						L"PaneHeader::DeferWindowPos::rightLabel");
				}
			}

			if (m_nIDAction)
			{
				// Drop the action button next to the label we drew above
				hWinPosInfo = ui::DeferWindowPos(
					hWinPosInfo,
					m_actionButton.GetSafeHwnd(),
					width - actionButtonWidth,
					0,
					actionButtonWidth,
					height,
					L"PaneHeader::DeferWindowPos::actionButton");
			}

			output::DebugPrint(output::dbgLevel::Draw, L"PaneHeader::DeferWindowPos end\n");
			EC_B_S(EndDeferWindowPos(hWinPosInfo));
		}

		return CWnd::OnWindowPosChanged(lpwndpos);
	}

	void PaneHeader::Redraw()
	{
		// Trigger a redraw
		RECT rcControl = {0};
		::GetWindowRect(GetSafeHwnd(), &rcControl);
		::MoveWindow(
			GetSafeHwnd(),
			rcControl.left,
			rcControl.top,
			rcControl.right - rcControl.left,
			rcControl.bottom - rcControl.top,
			false);
	}

	int PaneHeader::GetMinWidth()
	{
		auto cx = m_iLabelWidth;
		if (m_bCollapsible) cx += m_iButtonHeight;
		if (m_rightLabelWidth)
		{
			cx += m_iSideMargin;
			cx += m_rightLabelWidth;
		}

		if (m_actionButtonWidth)
		{
			cx += m_iSideMargin;
			cx += m_actionButtonWidth + 2 * m_iMargin;
		}

		return cx;
	}

	void PaneHeader::SetRightLabel(const std::wstring szLabel)
	{
		if (!m_bInitialized) return;
		EC_B_S(::SetWindowTextW(m_rightLabel.m_hWnd, szLabel.c_str()));

		const auto hdc = ::GetDC(m_rightLabel.GetSafeHwnd());
		const auto hfontOld = SelectObject(hdc, ui::GetSegoeFont());
		const auto sizeText = ui::GetTextExtentPoint32(hdc, szLabel);
		static_cast<void>(SelectObject(hdc, hfontOld));
		::ReleaseDC(m_rightLabel.GetSafeHwnd(), hdc);
		m_rightLabelWidth = sizeText.cx;

		Redraw();
	}

	void PaneHeader::SetActionButton(const std::wstring szActionButton)
	{
		// Don't bother if we never enabled the button
		if (m_nIDAction == 0) return;

		EC_B_S(::SetWindowTextW(m_actionButton.GetSafeHwnd(), szActionButton.c_str()));

		m_szActionButton = szActionButton;
		const auto hdc = ::GetDC(m_actionButton.GetSafeHwnd());
		const auto hfontOld = SelectObject(hdc, ui::GetSegoeFont());
		const auto sizeText = ui::GetTextExtentPoint32(hdc, szActionButton);
		static_cast<void>(SelectObject(hdc, hfontOld));
		::ReleaseDC(m_actionButton.GetSafeHwnd(), hdc);
		m_actionButtonWidth = sizeText.cx;

		Redraw();
	}

	bool PaneHeader::HandleChange(UINT nID)
	{
		// Collapse buttons have a nID IDD_COLLAPSE higher than nID of the pane they toggle.
		// So if we get asked about one that matches, we can assume it's time to toggle our collapse.
		if (m_nIDCollapse == nID)
		{
			OnToggleCollapse();
			return true;
		}

		return false;
	}

	void PaneHeader::OnToggleCollapse()
	{
		m_bCollapsed = !m_bCollapsed;

		StyleButton(m_CollapseButton.m_hWnd, m_bCollapsed ? ui::uiButtonStyle::UpArrow : ui::uiButtonStyle::DownArrow);
		WC_B_S(m_rightLabel.ShowWindow(m_bCollapsed ? SW_HIDE : SW_SHOW));

		// Trigger a redraw
		::PostMessage(m_hWndParent, WM_COMMAND, IDD_RECALCLAYOUT, NULL);
	}

	void PaneHeader::SetMargins(
		int iMargin,
		int iSideMargin,
		int iLabelHeight, // Height of the label
		int iButtonHeight) // Height of button
	{
		m_iMargin = iMargin;
		m_iSideMargin = iSideMargin;
		m_iLabelHeight = iLabelHeight;
		m_iButtonHeight = iButtonHeight;
	}
} // namespace controls<|endoftext|>


<commit_before>#include <fgt/fgt.hpp>

#include <fgt/exceptions.hpp>

#include <armadillo>
#include <gtest/gtest.h>

namespace fgt
{

class MockGaussianTransform : public GaussianTransform {
public:
    using GaussianTransform::GaussianTransform;

private:
    virtual arma::vec compute_impl(const arma::mat& target,
            const arma::vec& weights) const override {
        return arma::zeros<arma::vec>(target.n_rows);
    }

};

TEST(GaussianTransform, IncorrectDimensions) {
    arma::mat source(1, 2);
    arma::mat target(1, 3);
    double bandwidth = 1;
    MockGaussianTransform transform(source, bandwidth);
    EXPECT_THROW(transform.compute(target), dimension_mismatch);
}
}
<commit_msg>Test invalid weight count<commit_after>#include <fgt/fgt.hpp>

#include <fgt/exceptions.hpp>

#include <armadillo>
#include <gtest/gtest.h>

namespace fgt {

class MockGaussianTransform : public GaussianTransform {
public:
    using GaussianTransform::GaussianTransform;

private:
    virtual arma::vec compute_impl(const arma::mat& target,
                                   const arma::vec& weights) const override {
        return arma::zeros<arma::vec>(target.n_rows);
    }
};

TEST(GaussianTransform, IncorrectDimensions) {
    arma::mat source(1, 2);
    arma::mat target(1, 3);
    double bandwidth = 1;
    MockGaussianTransform transform(source, bandwidth);
    EXPECT_THROW(transform.compute(target), dimension_mismatch);
}

TEST(GaussianTransform, IncorrectWeightCount) {
    arma::mat source(1, 2);
    arma::mat target(1, 2);
    arma::vec weights(2);
    double bandwidth = 1;
    MockGaussianTransform transform(source, bandwidth);
    EXPECT_THROW(transform.compute(target, weights), dimension_mismatch);
}
}
<|endoftext|>