<commit_before>/*
 *  Copyright 2019-2021 Diligent Graphics LLC
 *  Copyright 2015-2019 Egor Yusov
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  In no event and under no legal theory, whether in tort (including negligence),
 *  contract, or otherwise, unless required by applicable law (such as deliberate
 *  and grossly negligent acts) or agreed to in writing, shall any Contributor be
 *  liable for any damages, including any direct, indirect, special, incidental,
 *  or consequential damages of any character arising as a result of this License or
 *  out of the use or inability to use the software (including but not limited to damages
 *  for loss of goodwill, work stoppage, computer failure or malfunction, or any and
 *  all other commercial damages or losses), even if such Contributor has been advised
 *  of the possibility of such damages.
 */

#pragma once

#include <mutex>
#include <vector>
#include <unordered_map>
#include <atomic>

#include "../../../DiligentCore/Graphics/GraphicsEngine/interface/RenderDevice.h"
#include "../../../DiligentCore/Graphics/GraphicsEngine/interface/DeviceContext.h"
#include "../../../DiligentCore/Common/interface/RefCntAutoPtr.hpp"
#include "../../../DiligentCore/Common/interface/ObjectBase.hpp"
#include "../../../DiligentCore/Graphics/GraphicsTools/interface/BufferSuballocator.h"
#include "../../../DiligentCore/Graphics/GraphicsTools/interface/DynamicTextureAtlas.h"

namespace Diligent
{

namespace GLTF
{

/// GLTF resource manager
class ResourceManager final : public ObjectBase<IObject>
{
public:
    using TBase = ObjectBase<IObject>;

    struct CreateInfo
    {
        const BufferSuballocatorCreateInfo*  BuffSuballocators = nullptr; // [NumBuffSuballocators]
        const DynamicTextureAtlasCreateInfo* TexAtlases        = nullptr; // [NumTexAtlases]

        Uint32 NumBuffSuballocators = 0;
        Uint32 NumTexAtlases        = 0;

        DynamicTextureAtlasCreateInfo DefaultAtlasDesc;
    };

    static RefCntAutoPtr<ResourceManager> Create(IRenderDevice*    pDevice,
                                                 const CreateInfo& CI);

    RefCntAutoPtr<IBufferSuballocation> AllocateBufferSpace(Uint32 BufferIndex,
                                                            Uint32 Size,
                                                            Uint32 Alignment)
    {
        RefCntAutoPtr<IBufferSuballocation> pSuballoc;
        m_BufferSuballocators[BufferIndex]->Allocate(Size, Alignment, &pSuballoc);
        return pSuballoc;
    }

    RefCntAutoPtr<ITextureAtlasSuballocation> AllocateTextureSpace(TEXTURE_FORMAT Fmt,
                                                                   Uint32         Width,
                                                                   Uint32         Height,
                                                                   const char*    CacheId   = nullptr,
                                                                   IObject*       pUserData = nullptr);

    RefCntAutoPtr<ITextureAtlasSuballocation> FindAllocation(const char* CacheId);

    Uint32 GetTextureVersion()
    {
        Uint32 Version = 0;

        std::lock_guard<std::mutex> Lock{m_AtlasesMtx};
        for (auto atlas_it : m_Atlases)
            Version += atlas_it.second->GetVersion();

        return Version;
    }

    Uint32 GetBufferVersion(Uint32 Index) const
    {
        return m_BufferSuballocators[Index]->GetVersion();
    }

    IBuffer* GetBuffer(Uint32 Index, IRenderDevice* pDevice, IDeviceContext* pContext)
    {
        return m_BufferSuballocators[Index]->GetBuffer(pDevice, pContext);
    }

    ITexture* GetTexture(TEXTURE_FORMAT Fmt, IRenderDevice* pDevice, IDeviceContext* pContext)
    {
        decltype(m_Atlases)::iterator cache_it; // NB: can't initialize it without locking the mutex
        {
            std::lock_guard<std::mutex> Lock{m_AtlasesMtx};
            cache_it = m_Atlases.find(Fmt);
            if (cache_it == m_Atlases.end())
                return nullptr;
        }

        return cache_it->second->GetTexture(pDevice, pContext);
    }

    // NB: can't return reference here!
    TextureDesc GetAtlasDesc(TEXTURE_FORMAT Fmt)
    {
        {
            std::lock_guard<std::mutex> Lock{m_AtlasesMtx};

            auto cache_it = m_Atlases.find(Fmt);
            if (cache_it != m_Atlases.end())
                return cache_it->second->GetAtlasDesc();
        }

        // Atlas is not present in the map - use default description
        TextureDesc Desc = m_DefaultAtlasDesc.Desc;
        Desc.Format      = Fmt;
        return Desc;
    }

private:
    template <typename AllocatorType, typename ObjectType>
    friend class Diligent::MakeNewRCObj;

    ResourceManager(IReferenceCounters* pRefCounters,
                    IRenderDevice*      pDevice,
                    const CreateInfo&   CI);

    std::vector<RefCntAutoPtr<IBufferSuballocator>> m_BufferSuballocators;

    DynamicTextureAtlasCreateInfo m_DefaultAtlasDesc;
    const std::string             m_DefaultAtlasName;

    using AtlasesHashMapType = std::unordered_map<TEXTURE_FORMAT, RefCntAutoPtr<IDynamicTextureAtlas>, std::hash<Uint32>>;
    std::mutex         m_AtlasesMtx;
    AtlasesHashMapType m_Atlases;

    using TexAllocationsHashMapType = std::unordered_map<std::string, RefCntWeakPtr<ITextureAtlasSuballocation>>;
    std::mutex                m_TexAllocationsMtx;
    TexAllocationsHashMapType m_TexAllocations;
};

} // namespace GLTF

} // namespace Diligent
<commit_msg>GLTF ResourceManager: added stats methods<commit_after>/*
 *  Copyright 2019-2021 Diligent Graphics LLC
 *  Copyright 2015-2019 Egor Yusov
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  In no event and under no legal theory, whether in tort (including negligence),
 *  contract, or otherwise, unless required by applicable law (such as deliberate
 *  and grossly negligent acts) or agreed to in writing, shall any Contributor be
 *  liable for any damages, including any direct, indirect, special, incidental,
 *  or consequential damages of any character arising as a result of this License or
 *  out of the use or inability to use the software (including but not limited to damages
 *  for loss of goodwill, work stoppage, computer failure or malfunction, or any and
 *  all other commercial damages or losses), even if such Contributor has been advised
 *  of the possibility of such damages.
 */

#pragma once

#include <mutex>
#include <vector>
#include <unordered_map>
#include <atomic>

#include "../../../DiligentCore/Graphics/GraphicsEngine/interface/RenderDevice.h"
#include "../../../DiligentCore/Graphics/GraphicsEngine/interface/DeviceContext.h"
#include "../../../DiligentCore/Common/interface/RefCntAutoPtr.hpp"
#include "../../../DiligentCore/Common/interface/ObjectBase.hpp"
#include "../../../DiligentCore/Graphics/GraphicsTools/interface/BufferSuballocator.h"
#include "../../../DiligentCore/Graphics/GraphicsTools/interface/DynamicTextureAtlas.h"

namespace Diligent
{

namespace GLTF
{

/// GLTF resource manager
class ResourceManager final : public ObjectBase<IObject>
{
public:
    using TBase = ObjectBase<IObject>;

    struct CreateInfo
    {
        const BufferSuballocatorCreateInfo*  BuffSuballocators = nullptr; // [NumBuffSuballocators]
        const DynamicTextureAtlasCreateInfo* TexAtlases        = nullptr; // [NumTexAtlases]

        Uint32 NumBuffSuballocators = 0;
        Uint32 NumTexAtlases        = 0;

        DynamicTextureAtlasCreateInfo DefaultAtlasDesc;
    };

    static RefCntAutoPtr<ResourceManager> Create(IRenderDevice*    pDevice,
                                                 const CreateInfo& CI);

    RefCntAutoPtr<IBufferSuballocation> AllocateBufferSpace(Uint32 BufferIndex,
                                                            Uint32 Size,
                                                            Uint32 Alignment)
    {
        RefCntAutoPtr<IBufferSuballocation> pSuballoc;
        m_BufferSuballocators[BufferIndex]->Allocate(Size, Alignment, &pSuballoc);
        return pSuballoc;
    }

    RefCntAutoPtr<ITextureAtlasSuballocation> AllocateTextureSpace(TEXTURE_FORMAT Fmt,
                                                                   Uint32         Width,
                                                                   Uint32         Height,
                                                                   const char*    CacheId   = nullptr,
                                                                   IObject*       pUserData = nullptr);

    RefCntAutoPtr<ITextureAtlasSuballocation> FindAllocation(const char* CacheId);

    Uint32 GetTextureVersion()
    {
        Uint32 Version = 0;

        std::lock_guard<std::mutex> Lock{m_AtlasesMtx};
        for (auto atlas_it : m_Atlases)
            Version += atlas_it.second->GetVersion();

        return Version;
    }

    Uint32 GetBufferVersion(Uint32 Index) const
    {
        return m_BufferSuballocators[Index]->GetVersion();
    }

    IBuffer* GetBuffer(Uint32 Index, IRenderDevice* pDevice, IDeviceContext* pContext)
    {
        return m_BufferSuballocators[Index]->GetBuffer(pDevice, pContext);
    }

    ITexture* GetTexture(TEXTURE_FORMAT Fmt, IRenderDevice* pDevice, IDeviceContext* pContext)
    {
        decltype(m_Atlases)::iterator cache_it; // NB: can't initialize it without locking the mutex
        {
            std::lock_guard<std::mutex> Lock{m_AtlasesMtx};
            cache_it = m_Atlases.find(Fmt);
            if (cache_it == m_Atlases.end())
                return nullptr;
        }

        return cache_it->second->GetTexture(pDevice, pContext);
    }

    BufferSuballocatorUsageStats GetBufferUsageStats(Uint32 Index)
    {
        BufferSuballocatorUsageStats Stats;
        m_BufferSuballocators[Index]->GetUsageStats(Stats);
        return Stats;
    }

    // NB: can't return reference here!
    TextureDesc GetAtlasDesc(TEXTURE_FORMAT Fmt)
    {
        {
            std::lock_guard<std::mutex> Lock{m_AtlasesMtx};

            auto cache_it = m_Atlases.find(Fmt);
            if (cache_it != m_Atlases.end())
                return cache_it->second->GetAtlasDesc();
        }

        // Atlas is not present in the map - use default description
        TextureDesc Desc = m_DefaultAtlasDesc.Desc;
        Desc.Format      = Fmt;
        return Desc;
    }

    DynamicTextureAtlasUsageStats GetAtlasUsageStats(TEXTURE_FORMAT Fmt = TEX_FORMAT_UNKNOWN)
    {
        DynamicTextureAtlasUsageStats Stats;
        {
            std::lock_guard<std::mutex> Lock{m_AtlasesMtx};
            if (Fmt != TEX_FORMAT_UNKNOWN)
            {
                auto cache_it = m_Atlases.find(Fmt);
                if (cache_it != m_Atlases.end())
                    cache_it->second->GetUsageStats(Stats);
            }
            else
            {
                for (auto it : m_Atlases)
                {
                    DynamicTextureAtlasUsageStats AtlasStats;
                    it.second->GetUsageStats(AtlasStats);
                    Stats.Size += AtlasStats.Size;
                    Stats.TotalArea += AtlasStats.TotalArea;
                    Stats.AllocatedArea += AtlasStats.AllocatedArea;
                    Stats.UsedArea += AtlasStats.UsedArea;
                    Stats.AllocationCount += AtlasStats.AllocationCount;
                }
            }
        }

        return Stats;
    }

private:
    template <typename AllocatorType, typename ObjectType>
    friend class Diligent::MakeNewRCObj;

    ResourceManager(IReferenceCounters* pRefCounters,
                    IRenderDevice*      pDevice,
                    const CreateInfo&   CI);

    std::vector<RefCntAutoPtr<IBufferSuballocator>> m_BufferSuballocators;

    DynamicTextureAtlasCreateInfo m_DefaultAtlasDesc;
    const std::string             m_DefaultAtlasName;

    using AtlasesHashMapType = std::unordered_map<TEXTURE_FORMAT, RefCntAutoPtr<IDynamicTextureAtlas>, std::hash<Uint32>>;
    std::mutex         m_AtlasesMtx;
    AtlasesHashMapType m_Atlases;

    using TexAllocationsHashMapType = std::unordered_map<std::string, RefCntWeakPtr<ITextureAtlasSuballocation>>;
    std::mutex                m_TexAllocationsMtx;
    TexAllocationsHashMapType m_TexAllocations;
};

} // namespace GLTF

} // namespace Diligent
<|endoftext|>


<commit_before>#include <array>
#include <vector>
#include <utility> // move

#include "gtest/gtest.h"

#include "cods/Vector.h"
using namespace cods;

TEST(Vector, instantiate) {
  Vector<int> vec;
  Vector<int, 3> vec2;
  Vector<int, 3, 10> vec3;
}

TEST(Vector, copyCtor) {
  Vector<int> vec;
  vec << 1 << 2 << 3;

  decltype(vec) vec2(vec);
  EXPECT_TRUE(vec == vec2);
}

TEST(Vector, moveCtor) {
  Vector<int> vec;
  vec << 1 << 2 << 3;

  decltype(vec) temp(vec);

  decltype(vec) vec2(std::move(vec));
  EXPECT_TRUE(vec.isEmpty());
  EXPECT_TRUE(vec2 == temp);
}

TEST(Vector, ctor1) {
  Vector<int> vec;
  EXPECT_EQ(vec.size(), 0);
  EXPECT_EQ(vec.capacity(), 0);
}

TEST(Vector, ctor2) {
  int amount = 3, value = 9;
  Vector<int> vec(amount, value);
  EXPECT_EQ(vec.size(), amount);

  // Initial capacity becomes the size.
  EXPECT_EQ(vec.capacity(), amount);

  for (int i = 0; i < amount; i++) {
    EXPECT_EQ(vec[i], value);
  }
}

TEST(Vector, ctor3) {
  constexpr int amount = 3;
  std::array<int, amount> arr{{1, 3, 5}};

  Vector<int> vec(amount, arr.data());
  EXPECT_EQ(vec.size(), amount);
  EXPECT_EQ(vec.capacity(), amount);

  for (int i = 0; i < amount; i++) {
    EXPECT_EQ(vec[i], arr[i]);
  }
}

TEST(Vector, ctor4) {
  std::vector<int> svec{1, 3, 5};

  Vector<int, 3, 3> vec(svec.begin(), svec.end());
  EXPECT_EQ(vec.size(), svec.size());
  EXPECT_EQ(vec.capacity(), svec.size());

  for (int i = 0; i < svec.size(); i++) {
    EXPECT_EQ(vec[i], svec[i]);
  }
}

TEST(Vector, append) {
  Vector<int, 2, 2> vec;
  vec.append(1);
  EXPECT_EQ(vec[0], 1);
  EXPECT_EQ(vec.size(), 1);
  EXPECT_EQ(vec.capacity(), 2);

  vec.append(2);
  EXPECT_EQ(vec[1], 2);
  EXPECT_EQ(vec.size(), 2);
  EXPECT_EQ(vec.capacity(), 2);

  vec.append(3);
  EXPECT_EQ(vec[2], 3);
  EXPECT_EQ(vec.size(), 3);

  // Went from size 2->3 so capacity is changed from 2->4 because the multiplier is 2.
  EXPECT_EQ(vec.capacity(), 4);
}

TEST(Vector, appendVector) {
  Vector<int> vec, vec2;
  vec2 << 1 << 2 << 3;

  vec.append(vec2);
  EXPECT_EQ(vec, vec2);

  vec.clear();
  vec << vec2;
  EXPECT_EQ(vec, vec2);
}

TEST(Vector, prepend) {
  Vector<int, 2, 2> vec;
  vec.prepend(1);
  EXPECT_EQ(vec[0], 1);
  EXPECT_EQ(vec.size(), 1);
  EXPECT_EQ(vec.capacity(), 2);

  vec.prepend(2);
  EXPECT_EQ(vec[0], 2);
  EXPECT_EQ(vec[1], 1);
  EXPECT_EQ(vec.size(), 2);
  EXPECT_EQ(vec.capacity(), 2);

  vec.prepend(3);
  EXPECT_EQ(vec[0], 3);
  EXPECT_EQ(vec[1], 2);
  EXPECT_EQ(vec[2], 1);
  EXPECT_EQ(vec.size(), 3);
  EXPECT_EQ(vec.capacity(), 4);
}

TEST(Vector, insert) {
  Vector<int, 2, 2> vec;
  vec.insert(0, 1);
  EXPECT_EQ(vec[0], 1);
  EXPECT_EQ(vec.size(), 1);
  EXPECT_EQ(vec.capacity(), 2);

  vec.insert(1, 2);
  EXPECT_EQ(vec[0], 1);
  EXPECT_EQ(vec[1], 2);
  EXPECT_EQ(vec.size(), 2);
  EXPECT_EQ(vec.capacity(), 2);

  vec.insert(1, 3);
  EXPECT_EQ(vec[0], 1);
  EXPECT_EQ(vec[1], 3);
  EXPECT_EQ(vec[2], 2);
  EXPECT_EQ(vec.size(), 3);
  EXPECT_EQ(vec.capacity(), 4);
}

TEST(Vector, clear) {
  Vector<int> vec;
  vec.append(1);
  vec.append(2);
  vec.append(3);
  EXPECT_EQ(vec.size(), 3);

  vec.clear();
  EXPECT_EQ(vec.size(), 0);
  EXPECT_EQ(vec.capacity(), 0);
}

TEST(Vector, reserve) {
  Vector<int, 1, 2> vec;
  vec.append(1);
  vec.append(2);
  vec.append(3);
  EXPECT_EQ(vec.size(), 3);
  EXPECT_EQ(vec.capacity(), 4);

  vec.reserve(10);
  EXPECT_EQ(vec.capacity(), 10);

  vec.reserve(3);
  EXPECT_EQ(vec.capacity(), 10);
}

TEST(Vector, shrinkToFit) {
  Vector<int, 1, 2> vec;
  vec.append(1);
  vec.append(2);
  vec.append(3);
  EXPECT_EQ(vec.size(), 3);
  EXPECT_EQ(vec.capacity(), 4);

  vec.shrinkToFit();
  EXPECT_EQ(vec.capacity(), vec.size());
}

TEST(Vector, remove) {
  Vector<int> vec;
  vec.append(1);
  vec.append(2);
  vec.append(3);

  vec.remove(2);
  EXPECT_EQ(vec[0], 1);
  EXPECT_EQ(vec[1], 3);
  EXPECT_EQ(vec.size(), 2);

  vec.remove(1);
  EXPECT_EQ(vec[0], 3);
  EXPECT_EQ(vec.size(), 1);
}

TEST(Vector, removeAt) {
  Vector<int> vec;
  vec.append(1);
  vec.append(2);
  vec.append(3);

  vec.removeAt(1);
  EXPECT_EQ(vec[0], 1);
  EXPECT_EQ(vec[1], 3);
  EXPECT_EQ(vec.size(), 2);

  vec.removeAt(0);
  EXPECT_EQ(vec[0], 3);
  EXPECT_EQ(vec.size(), 1);
}

TEST(Vector, isEmpty) {
  Vector<int> vec;
  EXPECT_TRUE(vec.isEmpty());

  vec.append(1);
  EXPECT_FALSE(vec.isEmpty());

  vec.clear();
  EXPECT_TRUE(vec.isEmpty());
}

TEST(Vector, contains) {
  Vector<int> vec;
  EXPECT_FALSE(vec.contains(1));

  vec << 1 << 2 << 3;
  EXPECT_TRUE(vec.contains(1));
  EXPECT_FALSE(vec.contains(4));
}

TEST(Vector, streamOperator) {
  Vector<int> vec;
  vec << 1 << 2 << 3;
  EXPECT_EQ(vec.size(), 3);
  EXPECT_EQ(vec[0], 1);
  EXPECT_EQ(vec[1], 2);
  EXPECT_EQ(vec[2], 3);
}

TEST(Vector, equalsOperator) {
  Vector<int> vec;
  vec << 1 << 2 << 3;

  decltype(vec) vec2;
  vec2 << 1 << 2 << 3;
  EXPECT_TRUE(vec == vec2);

  decltype(vec) vec3;
  EXPECT_FALSE(vec == vec3);

  decltype(vec) vec4;
  vec4 << 3 << 2 << 1;
  EXPECT_FALSE(vec == vec4);
}

TEST(Vector, notEqualsOperator) {
  Vector<int> vec;
  vec << 1 << 2 << 3;

  decltype(vec) vec2;
  vec2 << 1 << 2 << 3;
  EXPECT_FALSE(vec != vec2);

  decltype(vec) vec3;
  EXPECT_TRUE(vec != vec3);

  decltype(vec) vec4;
  vec4 << 3 << 2 << 1;
  EXPECT_TRUE(vec != vec4);
}

TEST(Vector, hash) {
  Vector<int> vec;
  vec << 1 << 2 << 3;
  auto h = std::hash<decltype(vec)>()(vec);

  decltype(vec) vec2;
  vec2 << 3 << 2 << 1;
  auto h2 = std::hash<decltype(vec2)>()(vec2);

  EXPECT_NE(h, h2);
}

TEST(Vector, iterator) {
  Vector<int> vec;
  vec << 1 << 2 << 3;

  int i = 0;
  for (const auto &elm : vec) {
    EXPECT_EQ(vec[i], elm);
    i++;
  }
}

int main(int argc, char **argv) {
  testing::InitGoogleTest(&argc, argv);
  return (RUN_ALL_TESTS());
}
<commit_msg>Vector: Testing reference assignment using operator[]<commit_after>#include <array>
#include <vector>
#include <utility> // move

#include "gtest/gtest.h"

#include "cods/Vector.h"
using namespace cods;

TEST(Vector, instantiate) {
  Vector<int> vec;
  Vector<int, 3> vec2;
  Vector<int, 3, 10> vec3;
}

TEST(Vector, copyCtor) {
  Vector<int> vec;
  vec << 1 << 2 << 3;

  decltype(vec) vec2(vec);
  EXPECT_TRUE(vec == vec2);
}

TEST(Vector, moveCtor) {
  Vector<int> vec;
  vec << 1 << 2 << 3;

  decltype(vec) temp(vec);

  decltype(vec) vec2(std::move(vec));
  EXPECT_TRUE(vec.isEmpty());
  EXPECT_TRUE(vec2 == temp);
}

TEST(Vector, ctor1) {
  Vector<int> vec;
  EXPECT_EQ(vec.size(), 0);
  EXPECT_EQ(vec.capacity(), 0);
}

TEST(Vector, ctor2) {
  int amount = 3, value = 9;
  Vector<int> vec(amount, value);
  EXPECT_EQ(vec.size(), amount);

  // Initial capacity becomes the size.
  EXPECT_EQ(vec.capacity(), amount);

  for (int i = 0; i < amount; i++) {
    EXPECT_EQ(vec[i], value);
  }
}

TEST(Vector, ctor3) {
  constexpr int amount = 3;
  std::array<int, amount> arr{{1, 3, 5}};

  Vector<int> vec(amount, arr.data());
  EXPECT_EQ(vec.size(), amount);
  EXPECT_EQ(vec.capacity(), amount);

  for (int i = 0; i < amount; i++) {
    EXPECT_EQ(vec[i], arr[i]);
  }
}

TEST(Vector, ctor4) {
  std::vector<int> svec{1, 3, 5};

  Vector<int, 3, 3> vec(svec.begin(), svec.end());
  EXPECT_EQ(vec.size(), svec.size());
  EXPECT_EQ(vec.capacity(), svec.size());

  for (int i = 0; i < svec.size(); i++) {
    EXPECT_EQ(vec[i], svec[i]);
  }
}

TEST(Vector, append) {
  Vector<int, 2, 2> vec;
  vec.append(1);
  EXPECT_EQ(vec[0], 1);
  EXPECT_EQ(vec.size(), 1);
  EXPECT_EQ(vec.capacity(), 2);

  vec.append(2);
  EXPECT_EQ(vec[1], 2);
  EXPECT_EQ(vec.size(), 2);
  EXPECT_EQ(vec.capacity(), 2);

  vec.append(3);
  EXPECT_EQ(vec[2], 3);
  EXPECT_EQ(vec.size(), 3);

  // Went from size 2->3 so capacity is changed from 2->4 because the multiplier is 2.
  EXPECT_EQ(vec.capacity(), 4);
}

TEST(Vector, appendVector) {
  Vector<int> vec, vec2;
  vec2 << 1 << 2 << 3;

  vec.append(vec2);
  EXPECT_EQ(vec, vec2);

  vec.clear();
  vec << vec2;
  EXPECT_EQ(vec, vec2);
}

TEST(Vector, prepend) {
  Vector<int, 2, 2> vec;
  vec.prepend(1);
  EXPECT_EQ(vec[0], 1);
  EXPECT_EQ(vec.size(), 1);
  EXPECT_EQ(vec.capacity(), 2);

  vec.prepend(2);
  EXPECT_EQ(vec[0], 2);
  EXPECT_EQ(vec[1], 1);
  EXPECT_EQ(vec.size(), 2);
  EXPECT_EQ(vec.capacity(), 2);

  vec.prepend(3);
  EXPECT_EQ(vec[0], 3);
  EXPECT_EQ(vec[1], 2);
  EXPECT_EQ(vec[2], 1);
  EXPECT_EQ(vec.size(), 3);
  EXPECT_EQ(vec.capacity(), 4);
}

TEST(Vector, insert) {
  Vector<int, 2, 2> vec;
  vec.insert(0, 1);
  EXPECT_EQ(vec[0], 1);
  EXPECT_EQ(vec.size(), 1);
  EXPECT_EQ(vec.capacity(), 2);

  vec.insert(1, 2);
  EXPECT_EQ(vec[0], 1);
  EXPECT_EQ(vec[1], 2);
  EXPECT_EQ(vec.size(), 2);
  EXPECT_EQ(vec.capacity(), 2);

  vec.insert(1, 3);
  EXPECT_EQ(vec[0], 1);
  EXPECT_EQ(vec[1], 3);
  EXPECT_EQ(vec[2], 2);
  EXPECT_EQ(vec.size(), 3);
  EXPECT_EQ(vec.capacity(), 4);
}

TEST(Vector, clear) {
  Vector<int> vec;
  vec.append(1);
  vec.append(2);
  vec.append(3);
  EXPECT_EQ(vec.size(), 3);

  vec.clear();
  EXPECT_EQ(vec.size(), 0);
  EXPECT_EQ(vec.capacity(), 0);
}

TEST(Vector, reserve) {
  Vector<int, 1, 2> vec;
  vec.append(1);
  vec.append(2);
  vec.append(3);
  EXPECT_EQ(vec.size(), 3);
  EXPECT_EQ(vec.capacity(), 4);

  vec.reserve(10);
  EXPECT_EQ(vec.capacity(), 10);

  vec.reserve(3);
  EXPECT_EQ(vec.capacity(), 10);
}

TEST(Vector, shrinkToFit) {
  Vector<int, 1, 2> vec;
  vec.append(1);
  vec.append(2);
  vec.append(3);
  EXPECT_EQ(vec.size(), 3);
  EXPECT_EQ(vec.capacity(), 4);

  vec.shrinkToFit();
  EXPECT_EQ(vec.capacity(), vec.size());
}

TEST(Vector, remove) {
  Vector<int> vec;
  vec.append(1);
  vec.append(2);
  vec.append(3);

  vec.remove(2);
  EXPECT_EQ(vec[0], 1);
  EXPECT_EQ(vec[1], 3);
  EXPECT_EQ(vec.size(), 2);

  vec.remove(1);
  EXPECT_EQ(vec[0], 3);
  EXPECT_EQ(vec.size(), 1);
}

TEST(Vector, removeAt) {
  Vector<int> vec;
  vec.append(1);
  vec.append(2);
  vec.append(3);

  vec.removeAt(1);
  EXPECT_EQ(vec[0], 1);
  EXPECT_EQ(vec[1], 3);
  EXPECT_EQ(vec.size(), 2);

  vec.removeAt(0);
  EXPECT_EQ(vec[0], 3);
  EXPECT_EQ(vec.size(), 1);
}

TEST(Vector, isEmpty) {
  Vector<int> vec;
  EXPECT_TRUE(vec.isEmpty());

  vec.append(1);
  EXPECT_FALSE(vec.isEmpty());

  vec.clear();
  EXPECT_TRUE(vec.isEmpty());
}

TEST(Vector, contains) {
  Vector<int> vec;
  EXPECT_FALSE(vec.contains(1));

  vec << 1 << 2 << 3;
  EXPECT_TRUE(vec.contains(1));
  EXPECT_FALSE(vec.contains(4));
}

TEST(Vector, streamOperator) {
  Vector<int> vec;
  vec << 1 << 2 << 3;
  EXPECT_EQ(vec.size(), 3);
  EXPECT_EQ(vec[0], 1);
  EXPECT_EQ(vec[1], 2);
  EXPECT_EQ(vec[2], 3);
}

TEST(Vector, equalsOperator) {
  Vector<int> vec;
  vec << 1 << 2 << 3;

  decltype(vec) vec2;
  vec2 << 1 << 2 << 3;
  EXPECT_TRUE(vec == vec2);

  decltype(vec) vec3;
  EXPECT_FALSE(vec == vec3);

  decltype(vec) vec4;
  vec4 << 3 << 2 << 1;
  EXPECT_FALSE(vec == vec4);
}

TEST(Vector, notEqualsOperator) {
  Vector<int> vec;
  vec << 1 << 2 << 3;

  decltype(vec) vec2;
  vec2 << 1 << 2 << 3;
  EXPECT_FALSE(vec != vec2);

  decltype(vec) vec3;
  EXPECT_TRUE(vec != vec3);

  decltype(vec) vec4;
  vec4 << 3 << 2 << 1;
  EXPECT_TRUE(vec != vec4);
}

TEST(Vector, hash) {
  Vector<int> vec;
  vec << 1 << 2 << 3;
  auto h = std::hash<decltype(vec)>()(vec);

  decltype(vec) vec2;
  vec2 << 3 << 2 << 1;
  auto h2 = std::hash<decltype(vec2)>()(vec2);

  EXPECT_NE(h, h2);
}

TEST(Vector, iterator) {
  Vector<int> vec;
  vec << 1 << 2 << 3;

  int i = 0;
  for (const auto &elm : vec) {
    EXPECT_EQ(vec[i], elm);
    i++;
  }
}

TEST(Vector, refAssign) {
  Vector<int> vec;
  vec << 1 << 2 << 3;

  EXPECT_EQ(vec[0], 1);

  vec[0] = 42;
  EXPECT_EQ(vec[0], 42);
}

int main(int argc, char **argv) {
  testing::InitGoogleTest(&argc, argv);
  return (RUN_ALL_TESTS());
}
<|endoftext|>


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

TEST(VectorTest, DefaultConstructor)
{
    const freeaml::Vector<int> v;

    EXPECT_EQ(v.size(), 0u);
}

TEST(VectorTest, ConstructorWithInitializerList)
{
    const freeaml::Vector<int> v = {0, 1, 2, 3, 4};

    EXPECT_EQ(v.size(), 5u);

    EXPECT_EQ(v[0], 0);
    EXPECT_EQ(v[1], 1);
    EXPECT_EQ(v[2], 2);
    EXPECT_EQ(v[3], 3);
    EXPECT_EQ(v[4], 4);
}

TEST(VectorTest, ConstructorWithLength)
{
    const freeaml::Vector<int> v(10);

    EXPECT_EQ(v.size(), 10u);

    for (const int x : v)
    {
        EXPECT_EQ(x, 0);
    }
}

TEST(VectorTest, ConstructorWithLengthAndDefaultValue)
{
    const freeaml::Vector<int> v(10, 5);

    EXPECT_EQ(v.size(), 10u);

    for (const int x : v)
    {
        EXPECT_EQ(x, 5);
    }
}

TEST(VectorTest, ConstructorWithIteratorRange)
{
    const freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    const freeaml::Vector<int> v2(v1.begin(), v1.end());

    EXPECT_EQ(v1, v2);
}

TEST(VectorTest, CopyConstructor)
{
    const freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    const freeaml::Vector<int> v2 = v1;

    EXPECT_EQ(v1, v2);
}

TEST(VectorTest, MoveConstructor)
{
    freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    const freeaml::Vector<int> v2 = std::move(v1);

    EXPECT_EQ(v2, freeaml::Vector<int>({0, 1, 2, 3, 4}));
}

TEST(VectorTest, CopyAssignment)
{
    const freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    freeaml::Vector<int> v2;

    v2 = v1;

    EXPECT_EQ(v1, v2);
}

TEST(VectorTest, MoveAssignment)
{
    freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    freeaml::Vector<int> v2;

    v2 = std::move(v1);

    EXPECT_EQ(v2, freeaml::Vector<int>({0, 1, 2, 3, 4}));
}

TEST(VectorTest, MultiplicationByScalar)
{
    const freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    const freeaml::Vector<int> v2 = {0, 2, 4, 6, 8}; /* 2 * v1 */

    EXPECT_EQ(2 * v1, v2);
    EXPECT_EQ(v1 * 2, v2);
}

TEST(VectorTest, DivisionByScalar)
{
    const freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    const freeaml::Vector<int> v2 = {0, 0, 1, 1, 2}; /* v1 / 2 */

    EXPECT_EQ(v1 / 2, v2);
}

TEST(VectorTest, VectorAddition)
{
    const freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    const freeaml::Vector<int> v2 = {1, 2, 3, 4, 5};
    const freeaml::Vector<int> v3 = {1, 3, 5, 7, 9}; /* v1 + v2 */

    /* vector addition is commutative */
    EXPECT_EQ(v1 + v2, v3);
    EXPECT_EQ(v2 + v1, v3);
}

TEST(VectorTest, VectorSubtraction)
{
    const freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    const freeaml::Vector<int> v2 = {4, 3, 2, 1, 0};
    const freeaml::Vector<int> v3 = {-4, -2, 0, 2, 4}; /* v1 - v2 */

    EXPECT_EQ(v1 - v2, v3);
}

TEST(VectorTest, VectorNegation)
{
    const freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    const freeaml::Vector<int> v2 = {0, -1, -2, -3, -4}; /* -v1 */

    EXPECT_EQ(v1, -v2);
    EXPECT_EQ(v2, -v1);

    EXPECT_EQ(v1, -(-v1));
}

TEST(VectorTest, DotProduct)
{
    const freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    const freeaml::Vector<int> v2 = {4, 3, 2, 1, 0};

    /* dot product is commutative */
    EXPECT_EQ(v1 * v2, 10);
    EXPECT_EQ(v2 * v1, 10);
}

TEST(VectorTest, Norms)
{
    const freeaml::Vector<double> v1 = {0.0, 1.0, -2.0, 3.0, -4.0};
    const freeaml::Vector<double> v2 = -v1;

    EXPECT_LT(std::abs(v1.l1_norm() - 10.0000), 0.0001);
    EXPECT_LT(std::abs(v2.l1_norm() - 10.0000), 0.0001);

    EXPECT_LT(std::abs(v1.l2_norm() - 5.4772), 0.0001);
    EXPECT_LT(std::abs(v2.l2_norm() - 5.4772), 0.0001);

    EXPECT_LT(std::abs(v1.lp_norm(1.0) - 10.0000), 0.0001);
    EXPECT_LT(std::abs(v2.lp_norm(1.0) - 10.0000), 0.0001);

    EXPECT_LT(std::abs(v1.lp_norm(2.0) - 5.4772), 0.0001);
    EXPECT_LT(std::abs(v2.lp_norm(2.0) - 5.4772), 0.0001);

    EXPECT_LT(std::abs(v1.lp_norm(2.5) - 4.9402), 0.0001);
    EXPECT_LT(std::abs(v2.lp_norm(2.5) - 4.9402), 0.0001);

    EXPECT_LT(std::abs(v1.lp_norm(3.14) - 4.5816), 0.0001);
    EXPECT_LT(std::abs(v2.lp_norm(3.14) - 4.5816), 0.0001);

    EXPECT_EQ(v1.linf_norm(), 4.0);
    EXPECT_EQ(v2.linf_norm(), 4.0);
}

TEST(VectorTest, ElementSum)
{
    const freeaml::Vector<int> v = {0, 1, 2, 3, 4};

    EXPECT_EQ(v.sum(), 10);
}

TEST(VectorTest, MeanValue)
{
    const freeaml::Vector<double> v = {1.0, 2.0, 3.0, 4.0};

    ASSERT_LT(std::abs(v.mean() - 2.5), 1.e-10);
}

TEST(VectorTest, RandomIntegerVectorWithinDefaultRange)
{
    const freeaml::Vector<int> v = freeaml::random_vector<int>(10);

    EXPECT_EQ(v.size(), 10u);

    for (const int x : v)
    {
        EXPECT_GE(x, 0);
        EXPECT_LE(x, 1);
    }
}

TEST(VectorTest, RandomIntegerVectorWithinSpecifiedRange)
{
    const freeaml::Vector<int> v = freeaml::random_vector<int>(10, -5, 5);

    EXPECT_EQ(v.size(), 10u);

    for (const int x : v)
    {
        EXPECT_GE(x, -5);
        EXPECT_LE(x, 5);
    }
}

TEST(VectorTest, RandomFloatingPointVectorWithinDefaultRange)
{
    const freeaml::Vector<double> v = freeaml::random_vector<double>(10);

    EXPECT_EQ(v.size(), 10u);

    for (const double x : v)
    {
        EXPECT_GE(x, 0.0);
        EXPECT_LE(x, 1.0);
    }
}

TEST(VectorTest, RandomFloatingPointVectorWithinSpecifiedRange)
{
    const freeaml::Vector<double> v =
        freeaml::random_vector<double>(10, -5.0, 5.0);

    EXPECT_EQ(v.size(), 10u);

    for (const double x : v)
    {
        EXPECT_GE(x, -5.0);
        EXPECT_LE(x, 5.0);
    }
}
<commit_msg>removes spurious line<commit_after>#include <gtest/gtest.h>
#include <Vector.h>

TEST(VectorTest, DefaultConstructor)
{
    const freeaml::Vector<int> v;

    EXPECT_EQ(v.size(), 0u);
}

TEST(VectorTest, ConstructorWithInitializerList)
{
    const freeaml::Vector<int> v = {0, 1, 2, 3, 4};

    EXPECT_EQ(v.size(), 5u);

    EXPECT_EQ(v[0], 0);
    EXPECT_EQ(v[1], 1);
    EXPECT_EQ(v[2], 2);
    EXPECT_EQ(v[3], 3);
    EXPECT_EQ(v[4], 4);
}

TEST(VectorTest, ConstructorWithLength)
{
    const freeaml::Vector<int> v(10);

    EXPECT_EQ(v.size(), 10u);

    for (const int x : v)
    {
        EXPECT_EQ(x, 0);
    }
}

TEST(VectorTest, ConstructorWithLengthAndDefaultValue)
{
    const freeaml::Vector<int> v(10, 5);

    EXPECT_EQ(v.size(), 10u);

    for (const int x : v)
    {
        EXPECT_EQ(x, 5);
    }
}

TEST(VectorTest, ConstructorWithIteratorRange)
{
    const freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    const freeaml::Vector<int> v2(v1.begin(), v1.end());

    EXPECT_EQ(v1, v2);
}

TEST(VectorTest, CopyConstructor)
{
    const freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    const freeaml::Vector<int> v2 = v1;

    EXPECT_EQ(v1, v2);
}

TEST(VectorTest, MoveConstructor)
{
    freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    const freeaml::Vector<int> v2 = std::move(v1);

    EXPECT_EQ(v2, freeaml::Vector<int>({0, 1, 2, 3, 4}));
}

TEST(VectorTest, CopyAssignment)
{
    const freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    freeaml::Vector<int> v2;

    v2 = v1;

    EXPECT_EQ(v1, v2);
}

TEST(VectorTest, MoveAssignment)
{
    freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    freeaml::Vector<int> v2;

    v2 = std::move(v1);

    EXPECT_EQ(v2, freeaml::Vector<int>({0, 1, 2, 3, 4}));
}

TEST(VectorTest, MultiplicationByScalar)
{
    const freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    const freeaml::Vector<int> v2 = {0, 2, 4, 6, 8}; /* 2 * v1 */

    EXPECT_EQ(2 * v1, v2);
    EXPECT_EQ(v1 * 2, v2);
}

TEST(VectorTest, DivisionByScalar)
{
    const freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    const freeaml::Vector<int> v2 = {0, 0, 1, 1, 2}; /* v1 / 2 */

    EXPECT_EQ(v1 / 2, v2);
}

TEST(VectorTest, VectorAddition)
{
    const freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    const freeaml::Vector<int> v2 = {1, 2, 3, 4, 5};
    const freeaml::Vector<int> v3 = {1, 3, 5, 7, 9}; /* v1 + v2 */

    /* vector addition is commutative */
    EXPECT_EQ(v1 + v2, v3);
    EXPECT_EQ(v2 + v1, v3);
}

TEST(VectorTest, VectorSubtraction)
{
    const freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    const freeaml::Vector<int> v2 = {4, 3, 2, 1, 0};
    const freeaml::Vector<int> v3 = {-4, -2, 0, 2, 4}; /* v1 - v2 */

    EXPECT_EQ(v1 - v2, v3);
}

TEST(VectorTest, VectorNegation)
{
    const freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    const freeaml::Vector<int> v2 = {0, -1, -2, -3, -4}; /* -v1 */

    EXPECT_EQ(v1, -v2);
    EXPECT_EQ(v2, -v1);
    EXPECT_EQ(v1, -(-v1));
}

TEST(VectorTest, DotProduct)
{
    const freeaml::Vector<int> v1 = {0, 1, 2, 3, 4};
    const freeaml::Vector<int> v2 = {4, 3, 2, 1, 0};

    /* dot product is commutative */
    EXPECT_EQ(v1 * v2, 10);
    EXPECT_EQ(v2 * v1, 10);
}

TEST(VectorTest, Norms)
{
    const freeaml::Vector<double> v1 = {0.0, 1.0, -2.0, 3.0, -4.0};
    const freeaml::Vector<double> v2 = -v1;

    EXPECT_LT(std::abs(v1.l1_norm() - 10.0000), 0.0001);
    EXPECT_LT(std::abs(v2.l1_norm() - 10.0000), 0.0001);

    EXPECT_LT(std::abs(v1.l2_norm() - 5.4772), 0.0001);
    EXPECT_LT(std::abs(v2.l2_norm() - 5.4772), 0.0001);

    EXPECT_LT(std::abs(v1.lp_norm(1.0) - 10.0000), 0.0001);
    EXPECT_LT(std::abs(v2.lp_norm(1.0) - 10.0000), 0.0001);

    EXPECT_LT(std::abs(v1.lp_norm(2.0) - 5.4772), 0.0001);
    EXPECT_LT(std::abs(v2.lp_norm(2.0) - 5.4772), 0.0001);

    EXPECT_LT(std::abs(v1.lp_norm(2.5) - 4.9402), 0.0001);
    EXPECT_LT(std::abs(v2.lp_norm(2.5) - 4.9402), 0.0001);

    EXPECT_LT(std::abs(v1.lp_norm(3.14) - 4.5816), 0.0001);
    EXPECT_LT(std::abs(v2.lp_norm(3.14) - 4.5816), 0.0001);

    EXPECT_EQ(v1.linf_norm(), 4.0);
    EXPECT_EQ(v2.linf_norm(), 4.0);
}

TEST(VectorTest, ElementSum)
{
    const freeaml::Vector<int> v = {0, 1, 2, 3, 4};

    EXPECT_EQ(v.sum(), 10);
}

TEST(VectorTest, MeanValue)
{
    const freeaml::Vector<double> v = {1.0, 2.0, 3.0, 4.0};

    ASSERT_LT(std::abs(v.mean() - 2.5), 1.e-10);
}

TEST(VectorTest, RandomIntegerVectorWithinDefaultRange)
{
    const freeaml::Vector<int> v = freeaml::random_vector<int>(10);

    EXPECT_EQ(v.size(), 10u);

    for (const int x : v)
    {
        EXPECT_GE(x, 0);
        EXPECT_LE(x, 1);
    }
}

TEST(VectorTest, RandomIntegerVectorWithinSpecifiedRange)
{
    const freeaml::Vector<int> v = freeaml::random_vector<int>(10, -5, 5);

    EXPECT_EQ(v.size(), 10u);

    for (const int x : v)
    {
        EXPECT_GE(x, -5);
        EXPECT_LE(x, 5);
    }
}

TEST(VectorTest, RandomFloatingPointVectorWithinDefaultRange)
{
    const freeaml::Vector<double> v = freeaml::random_vector<double>(10);

    EXPECT_EQ(v.size(), 10u);

    for (const double x : v)
    {
        EXPECT_GE(x, 0.0);
        EXPECT_LE(x, 1.0);
    }
}

TEST(VectorTest, RandomFloatingPointVectorWithinSpecifiedRange)
{
    const freeaml::Vector<double> v =
        freeaml::random_vector<double>(10, -5.0, 5.0);

    EXPECT_EQ(v.size(), 10u);

    for (const double x : v)
    {
        EXPECT_GE(x, -5.0);
        EXPECT_LE(x, 5.0);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <nix/hdf5/FeatureHDF5.hpp>

#include <nix/util/util.hpp>
#include <nix/DataArray.hpp>
#include <nix/hdf5/DataArrayHDF5.hpp>

using namespace std;
using namespace nix::base;

namespace nix {
namespace hdf5 {

string linkTypeToString(LinkType link_type) {
    static vector<string> type_names = {"tagged", "untagged", "indexed"};
    return type_names[static_cast<int>(link_type)];
}

LinkType linkTypeFromString(const string &str) {
    if (str == "tagged")
        return LinkType::Tagged;
    else if (str == "untagged")
        return LinkType::Untagged;
    else if (str == "indexed")
        return LinkType::Indexed;
    else
        throw runtime_error("Unable to create a LinkType from the string: " + str);
}

FeatureHDF5::FeatureHDF5(const shared_ptr<IFile> &file, const shared_ptr<IBlock> &block, const Group &group)
    : EntityHDF5(file, group), block(block)
{
}

FeatureHDF5::FeatureHDF5(const shared_ptr<IFile> &file, const shared_ptr<IBlock> &block, const Group &group,
                         const string &id, DataArray data, LinkType link_type)
    : FeatureHDF5(file, block, group, id, data, link_type, util::getTime())
{
}

FeatureHDF5::FeatureHDF5(const shared_ptr<IFile> &file, const shared_ptr<IBlock> &block, const Group &group,
                         const string &id, DataArray data, LinkType link_type, time_t time)
    : EntityHDF5(file, group, id, time), block(block)
{
    linkType(link_type);
    // TODO: the line below currently throws an exception if the DataArray
    // is not in block - to consider if we prefer copying it to the block
    this->data(data.id());
}

void FeatureHDF5::linkType(LinkType link_type) {
    // linkTypeToString will generate an error if link_type is invalid
    group().setAttr("link_type", linkTypeToString(link_type));
    forceUpdatedAt();
}

void FeatureHDF5::data(const std::string &name_or_id) {
    if (name_or_id.empty())
        throw EmptyString("data(id)");
    if (!block->hasDataArray(name_or_id))
        throw std::runtime_error("FeatureHDF5::data: DataArray not found in block!");
    if (group().hasGroup("data"))
        group().removeGroup("data");

    auto target = dynamic_pointer_cast<DataArrayHDF5>(block->getDataArray(name_or_id));

    group().createLink(target->group(), "data");
    forceUpdatedAt();
}

shared_ptr<IDataArray> FeatureHDF5::data() const {
    shared_ptr<IDataArray> da;
    bool error = false;

    if (group().hasGroup("data")) {
        Group other_group = group().openGroup("data", false);
        da = make_shared<DataArrayHDF5>(file(), block, other_group);
        if (!block->hasDataArray(da->id())) error = true;
    }
    else error = true;

    // NOTE: we check that link exists in both places, here & in entity
    // if error = true it was missing in one of the two
    if (error)
        throw std::runtime_error("FeatureHDF5::data: DataArray not found!");

    return da;
}

LinkType FeatureHDF5::linkType() const {
    if (group().hasAttr("link_type")) {
        string link_type;
        group().getAttr("link_type", link_type);
        return linkTypeFromString(link_type);
    } else {
        throw MissingAttr("data");
    }
}

FeatureHDF5::~FeatureHDF5() {}

} // ns nix::hdf5
} // ns nix<commit_msg>[FeatureHDF5] removed runtime exception if there is no data associated with feature<commit_after>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <nix/hdf5/FeatureHDF5.hpp>

#include <nix/util/util.hpp>
#include <nix/DataArray.hpp>
#include <nix/hdf5/DataArrayHDF5.hpp>

using namespace std;
using namespace nix::base;

namespace nix {
namespace hdf5 {

string linkTypeToString(LinkType link_type) {
    static vector<string> type_names = {"tagged", "untagged", "indexed"};
    return type_names[static_cast<int>(link_type)];
}

LinkType linkTypeFromString(const string &str) {
    if (str == "tagged")
        return LinkType::Tagged;
    else if (str == "untagged")
        return LinkType::Untagged;
    else if (str == "indexed")
        return LinkType::Indexed;
    else
        throw runtime_error("Unable to create a LinkType from the string: " + str);
}

FeatureHDF5::FeatureHDF5(const shared_ptr<IFile> &file, const shared_ptr<IBlock> &block, const Group &group)
    : EntityHDF5(file, group), block(block)
{
}

FeatureHDF5::FeatureHDF5(const shared_ptr<IFile> &file, const shared_ptr<IBlock> &block, const Group &group,
                         const string &id, DataArray data, LinkType link_type)
    : FeatureHDF5(file, block, group, id, data, link_type, util::getTime())
{
}

FeatureHDF5::FeatureHDF5(const shared_ptr<IFile> &file, const shared_ptr<IBlock> &block, const Group &group,
                         const string &id, DataArray data, LinkType link_type, time_t time)
    : EntityHDF5(file, group, id, time), block(block)
{
    linkType(link_type);
    // TODO: the line below currently throws an exception if the DataArray
    // is not in block - to consider if we prefer copying it to the block
    this->data(data.id());
}

void FeatureHDF5::linkType(LinkType link_type) {
    // linkTypeToString will generate an error if link_type is invalid
    group().setAttr("link_type", linkTypeToString(link_type));
    forceUpdatedAt();
}

void FeatureHDF5::data(const std::string &name_or_id) {
    if (name_or_id.empty())
        throw EmptyString("data(id)");
    if (!block->hasDataArray(name_or_id))
        throw std::runtime_error("FeatureHDF5::data: DataArray not found in block!");
    if (group().hasGroup("data"))
        group().removeGroup("data");

    auto target = dynamic_pointer_cast<DataArrayHDF5>(block->getDataArray(name_or_id));

    group().createLink(target->group(), "data");
    forceUpdatedAt();
}

shared_ptr<IDataArray> FeatureHDF5::data() const {
    shared_ptr<IDataArray> da;

    if (group().hasGroup("data")) {
        Group other_group = group().openGroup("data", false);
        da = make_shared<DataArrayHDF5>(file(), block, other_group);
        if (!block->hasDataArray(da->id()))
            throw std::runtime_error("FeatureHDF5::data: DataArray not found!");
    }
    return da;
}

LinkType FeatureHDF5::linkType() const {
    if (group().hasAttr("link_type")) {
        string link_type;
        group().getAttr("link_type", link_type);
        return linkTypeFromString(link_type);
    } else {
        throw MissingAttr("data");
    }
}

FeatureHDF5::~FeatureHDF5() {}

} // ns nix::hdf5
} // ns nix<|endoftext|>


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

extern "C" {
#include "../src/client.h"
}

#include "macros.h"

TEST(ConnectTest, Encode1) {
  unsigned char pkt[62] = {
      LWMQTT_CONNECT_PACKET << 4,
      60,
      0,  // Protocol String MSB
      4,  // Protocol String LSB
      'M',
      'Q',
      'T',
      'T',
      4,    // Protocol level 4
      204,  // Connect Flags
      0,    // Keep Alive MSB
      10,   // Keep Alive LSB
      0,    // Client ID MSB
      7,    // Client ID LSB
      's',
      'u',
      'r',
      'g',
      'e',
      'm',
      'q',
      0,  // Will Topic MSB
      4,  // Will Topic LSB
      'w',
      'i',
      'l',
      'l',
      0,   // Will Message MSB
      12,  // Will Message LSB
      's',
      'e',
      'n',
      'd',
      ' ',
      'm',
      'e',
      ' ',
      'h',
      'o',
      'm',
      'e',
      0,  // Username ID MSB
      7,  // Username ID LSB
      's',
      'u',
      'r',
      'g',
      'e',
      'm',
      'q',
      0,   // Password ID MSB
      10,  // Password ID LSB
      'v',
      'e',
      'r',
      'y',
      's',
      'e',
      'c',
      'r',
      'e',
      't',
  };

  unsigned char buf[62];

  lwmqtt_will_t will = lwmqtt_default_will;
  will.topic.c_string = (char*)"will";
  will.payload = (void*)"send me home";
  will.payload_len = (int)strlen((const char*)will.payload);
  will.qos = LWMQTT_QOS1;

  lwmqtt_options_t opts = lwmqtt_default_options;
  opts.clean_session = false;
  opts.keep_alive = 10;
  opts.client_id.c_string = (char*)"surgemq";
  opts.username.c_string = (char*)"surgemq";
  opts.password.c_string = (char*)"verysecret";

  int len;
  lwmqtt_err_t r = lwmqtt_encode_connect(buf, 62, &len, &opts, &will);

  EXPECT_EQ(r, LWMQTT_SUCCESS);
  EXPECT_ARRAY_EQ(unsigned char, pkt, buf, len);
}

TEST(ConnectTest, Encode2) {
  unsigned char pkt[14] = {
      LWMQTT_CONNECT_PACKET << 4,
      12,
      0,  // Protocol String MSB
      4,  // Protocol String LSB
      'M',
      'Q',
      'T',
      'T',
      4,   // Protocol level 4
      2,   // Connect Flags
      0,   // Keep Alive MSB
      60,  // Keep Alive LSB
      0,   // Client ID MSB
      0,   // Client ID LSB
  };

  unsigned char buf[14];

  lwmqtt_options_t opts = lwmqtt_default_options;

  int len;
  lwmqtt_err_t r = lwmqtt_encode_connect(buf, 14, &len, &opts, NULL);

  EXPECT_EQ(r, LWMQTT_SUCCESS);
  EXPECT_ARRAY_EQ(unsigned char, pkt, buf, len);
}

TEST(ConnectTest, EncodeError1) {
  unsigned char buf[4];  // <- too small buffer

  lwmqtt_options_t opts = lwmqtt_default_options;

  int len;
  lwmqtt_err_t r = lwmqtt_encode_connect(buf, 4, &len, &opts, NULL);

  EXPECT_EQ(r, LWMQTT_BUFFER_TOO_SHORT_ERROR);
}

TEST(ConnackTest, decode1) {
  unsigned char pkt[4] = {
      LWMQTT_CONNACK_PACKET << 4, 2,
      0,  // session not present
      0,  // connection accepted
  };

  bool session_present;
  lwmqtt_connack_t connack;
  lwmqtt_err_t r = lwmqtt_decode_connack(&session_present, &connack, pkt, 4);

  EXPECT_EQ(r, LWMQTT_SUCCESS);
  EXPECT_EQ(session_present, 0);
  EXPECT_EQ(connack, 0);
}

TEST(ConnackTest, decodeError1) {
  unsigned char pkt[4] = {
      LWMQTT_CONNACK_PACKET << 4,
      3,  // <-- wrong size
      0,  // session not present
      0,  // connection accepted
  };

  bool session_present;
  lwmqtt_connack_t connack;
  lwmqtt_err_t r = lwmqtt_decode_connack(&session_present, &connack, pkt, 4);

  EXPECT_EQ(r, LWMQTT_LENGTH_MISMATCH);
}

TEST(ConnackTest, decodeError2) {
  unsigned char pkt[3] = {
      LWMQTT_CONNACK_PACKET << 4, 3,
      0,  // session not present
          // <- missing packet size
  };

  bool session_present;
  lwmqtt_connack_t connack;
  lwmqtt_err_t r = lwmqtt_decode_connack(&session_present, &connack, pkt, 3);

  EXPECT_EQ(r, LWMQTT_LENGTH_MISMATCH);
}

TEST(ZeroTest, Encode1) {
  unsigned char pkt[2] = {LWMQTT_PINGREQ_PACKET << 4, 0};

  unsigned char buf[2];

  int len;
  lwmqtt_err_t r = lwmqtt_encode_zero(buf, 2, &len, LWMQTT_PINGREQ_PACKET);

  EXPECT_EQ(r, LWMQTT_SUCCESS);
  EXPECT_ARRAY_EQ(unsigned char, pkt, buf, len);
}
<commit_msg>added ack tests<commit_after>#include <gtest/gtest.h>

extern "C" {
#include "../src/client.h"
}

#include "macros.h"

TEST(ConnectTest, Encode1) {
  unsigned char pkt[62] = {
      LWMQTT_CONNECT_PACKET << 4,
      60,
      0,  // Protocol String MSB
      4,  // Protocol String LSB
      'M',
      'Q',
      'T',
      'T',
      4,    // Protocol level 4
      204,  // Connect Flags
      0,    // Keep Alive MSB
      10,   // Keep Alive LSB
      0,    // Client ID MSB
      7,    // Client ID LSB
      's',
      'u',
      'r',
      'g',
      'e',
      'm',
      'q',
      0,  // Will Topic MSB
      4,  // Will Topic LSB
      'w',
      'i',
      'l',
      'l',
      0,   // Will Message MSB
      12,  // Will Message LSB
      's',
      'e',
      'n',
      'd',
      ' ',
      'm',
      'e',
      ' ',
      'h',
      'o',
      'm',
      'e',
      0,  // Username ID MSB
      7,  // Username ID LSB
      's',
      'u',
      'r',
      'g',
      'e',
      'm',
      'q',
      0,   // Password ID MSB
      10,  // Password ID LSB
      'v',
      'e',
      'r',
      'y',
      's',
      'e',
      'c',
      'r',
      'e',
      't',
  };

  unsigned char buf[62];

  lwmqtt_will_t will = lwmqtt_default_will;
  will.topic.c_string = (char*)"will";
  will.payload = (void*)"send me home";
  will.payload_len = (int)strlen((const char*)will.payload);
  will.qos = LWMQTT_QOS1;

  lwmqtt_options_t opts = lwmqtt_default_options;
  opts.clean_session = false;
  opts.keep_alive = 10;
  opts.client_id.c_string = (char*)"surgemq";
  opts.username.c_string = (char*)"surgemq";
  opts.password.c_string = (char*)"verysecret";

  int len;
  lwmqtt_err_t r = lwmqtt_encode_connect(buf, 62, &len, &opts, &will);

  EXPECT_EQ(r, LWMQTT_SUCCESS);
  EXPECT_ARRAY_EQ(unsigned char, pkt, buf, len);
}

TEST(ConnectTest, Encode2) {
  unsigned char pkt[14] = {
      LWMQTT_CONNECT_PACKET << 4,
      12,
      0,  // Protocol String MSB
      4,  // Protocol String LSB
      'M',
      'Q',
      'T',
      'T',
      4,   // Protocol level 4
      2,   // Connect Flags
      0,   // Keep Alive MSB
      60,  // Keep Alive LSB
      0,   // Client ID MSB
      0,   // Client ID LSB
  };

  unsigned char buf[14];

  lwmqtt_options_t opts = lwmqtt_default_options;

  int len;
  lwmqtt_err_t r = lwmqtt_encode_connect(buf, 14, &len, &opts, NULL);

  EXPECT_EQ(r, LWMQTT_SUCCESS);
  EXPECT_ARRAY_EQ(unsigned char, pkt, buf, len);
}

TEST(ConnectTest, EncodeError1) {
  unsigned char buf[4];  // <- too small buffer

  lwmqtt_options_t opts = lwmqtt_default_options;

  int len;
  lwmqtt_err_t r = lwmqtt_encode_connect(buf, 4, &len, &opts, NULL);

  EXPECT_EQ(r, LWMQTT_BUFFER_TOO_SHORT_ERROR);
}

TEST(ConnackTest, Decode1) {
  unsigned char pkt[4] = {
      LWMQTT_CONNACK_PACKET << 4, 2,
      0,  // session not present
      0,  // connection accepted
  };

  bool session_present;
  lwmqtt_connack_t connack;
  lwmqtt_err_t r = lwmqtt_decode_connack(&session_present, &connack, pkt, 4);

  EXPECT_EQ(r, LWMQTT_SUCCESS);
  EXPECT_EQ(session_present, 0);
  EXPECT_EQ(connack, 0);
}

TEST(ConnackTest, DecodeError1) {
  unsigned char pkt[4] = {
      LWMQTT_CONNACK_PACKET << 4,
      3,  // <-- wrong size
      0,  // session not present
      0,  // connection accepted
  };

  bool session_present;
  lwmqtt_connack_t connack;
  lwmqtt_err_t r = lwmqtt_decode_connack(&session_present, &connack, pkt, 4);

  EXPECT_EQ(r, LWMQTT_LENGTH_MISMATCH);
}

TEST(ConnackTest, DecodeError2) {
  unsigned char pkt[3] = {
      LWMQTT_CONNACK_PACKET << 4, 3,
      0,  // session not present
          // <- missing packet size
  };

  bool session_present;
  lwmqtt_connack_t connack;
  lwmqtt_err_t r = lwmqtt_decode_connack(&session_present, &connack, pkt, 3);

  EXPECT_EQ(r, LWMQTT_LENGTH_MISMATCH);
}

TEST(ZeroTest, Encode1) {
  unsigned char pkt[2] = {LWMQTT_PINGREQ_PACKET << 4, 0};

  unsigned char buf[2];

  int len;
  lwmqtt_err_t r = lwmqtt_encode_zero(buf, 2, &len, LWMQTT_PINGREQ_PACKET);

  EXPECT_EQ(r, LWMQTT_SUCCESS);
  EXPECT_ARRAY_EQ(unsigned char, pkt, buf, len);
}

TEST(AckTest, Decode1) {
  unsigned char pkt[4] = {
      LWMQTT_PUBACK_PACKET << 4, 2,
      0,  // packet ID MSB
      7,  // packet ID LSB
  };

  lwmqtt_packet_t type;
  bool dup;
  unsigned short packet_id;
  lwmqtt_err_t r = lwmqtt_decode_ack(&type, &dup, &packet_id, pkt, 4);

  EXPECT_EQ(r, LWMQTT_SUCCESS);
  EXPECT_EQ(type, LWMQTT_PUBACK_PACKET);
  EXPECT_EQ(dup, false);
  EXPECT_EQ(packet_id, 7);
}

TEST(AckTest, DecodeError1) {
  unsigned char pkt[4] = {
      LWMQTT_PUBACK_PACKET << 4,
      1,  // <-- wrong remaining length
      0,  // packet ID MSB
      7,  // packet ID LSB
  };

  lwmqtt_packet_t type;
  bool dup;
  unsigned short packet_id;
  lwmqtt_err_t r = lwmqtt_decode_ack(&type, &dup, &packet_id, pkt, 4);

  EXPECT_EQ(r, LWMQTT_LENGTH_MISMATCH);
}

TEST(AckTest, DecodeError2) {
  unsigned char pkt[3] = {
      LWMQTT_PUBACK_PACKET << 4,
      1,  // <-- wrong remaining length
      0,  // packet ID MSB
          //  <- insufficient bytes
  };

  lwmqtt_packet_t type;
  bool dup;
  unsigned short packet_id;
  lwmqtt_err_t r = lwmqtt_decode_ack(&type, &dup, &packet_id, pkt, 4);

  EXPECT_EQ(r, LWMQTT_LENGTH_MISMATCH);
}

TEST(AckTest, Encode1) {
  unsigned char pkt[4] = {
      LWMQTT_PUBACK_PACKET << 4, 2,
      0,  // packet ID MSB
      7,  // packet ID LSB
  };

  unsigned char buf[4];

  int len;
  lwmqtt_err_t r = lwmqtt_encode_ack(buf, 4, &len, LWMQTT_PUBACK_PACKET, 0, 7);

  EXPECT_EQ(r, LWMQTT_SUCCESS);
  EXPECT_ARRAY_EQ(unsigned char, pkt, buf, len);
}

TEST(AckTest, EncodeError1) {
  unsigned char buf[2];  // <- too small buffer

  int len;
  lwmqtt_err_t r = lwmqtt_encode_ack(buf, 2, &len, LWMQTT_PUBACK_PACKET, 0, 7);

  EXPECT_EQ(r, LWMQTT_BUFFER_TOO_SHORT_ERROR);
}
<|endoftext|>


<commit_before>/* Copyright 2015 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/examples/android/jni/tensorflow_jni.h"

#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <android/bitmap.h>

#include <jni.h>
#include <pthread.h>
#include <sys/stat.h>
#include <unistd.h>
#include <queue>
#include <sstream>
#include <string>

#include "tensorflow/core/framework/step_stats.pb.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/framework/types.pb.h"
#include "tensorflow/core/lib/strings/stringprintf.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/mutex.h"
#include "tensorflow/core/platform/types.h"
#include "tensorflow/core/public/session.h"
#include "tensorflow/examples/android/jni/jni_utils.h"

using namespace tensorflow;

// Global variables that holds the Tensorflow classifier.
static std::unique_ptr<tensorflow::Session> session;

static std::vector<std::string> g_label_strings;
static bool g_compute_graph_initialized = false;
//static mutex g_compute_graph_mutex(base::LINKER_INITIALIZED);

static int g_tensorflow_input_size;  // The image size for the mognet input.
static int g_image_mean;  // The image mean.

// For basic benchmarking.
static int g_num_runs = 0;
static int64 g_timing_total_us = 0;

#ifdef SAVE_STEP_STATS
static const bool kSaveStepStats = true;
#else
static const bool kSaveStepStats = false;
#endif

inline static int64 CurrentThreadTimeUs() {
  struct timeval tv;
  gettimeofday(&tv, NULL);
  return tv.tv_sec * 1000000 + tv.tv_usec;
}

JNIEXPORT jint JNICALL
TENSORFLOW_METHOD(initializeTensorflow)(
    JNIEnv* env, jobject thiz, jobject java_asset_manager,
    jstring model, jstring labels,
    jint num_classes, jint mognet_input_size, jint image_mean) {
  g_num_runs = 0;
  g_timing_total_us = 0;

  //MutexLock input_lock(&g_compute_graph_mutex);
  if (g_compute_graph_initialized) {
    LOG(INFO) << "Compute graph already loaded. skipping.";
    return 0;
  }

  const char* const model_cstr = env->GetStringUTFChars(model, NULL);
  const char* const labels_cstr = env->GetStringUTFChars(labels, NULL);

  g_tensorflow_input_size = mognet_input_size;
  g_image_mean = image_mean;

  LOG(INFO) << "Loading Tensorflow.";

  LOG(INFO) << "Making new SessionOptions.";
  tensorflow::SessionOptions options;
  tensorflow::ConfigProto& config = options.config;
  LOG(INFO) << "Got config, " << config.device_count_size() << " devices";

  session.reset(tensorflow::NewSession(options));
  LOG(INFO) << "Session created.";

  tensorflow::GraphDef tensorflow_graph;
  LOG(INFO) << "Graph created.";

  AAssetManager* const asset_manager =
      AAssetManager_fromJava(env, java_asset_manager);
  LOG(INFO) << "Acquired AssetManager.";

  LOG(INFO) << "Reading file to proto: " << model_cstr;
  ReadFileToProto(asset_manager, model_cstr, &tensorflow_graph);

  LOG(INFO) << "Creating session.";
  tensorflow::Status s = session->Create(tensorflow_graph);
  if (!s.ok()) {
    LOG(ERROR) << "Could not create Tensorflow Graph: " << s;
    return -1;
  }

  // Clear the proto to save memory space.
  tensorflow_graph.Clear();
  LOG(INFO) << "Tensorflow graph loaded from: " << model_cstr;

  // Read the label list
  ReadFileToVector(asset_manager, labels_cstr, &g_label_strings);
  LOG(INFO) << g_label_strings.size() << " label strings loaded from: "
            << labels_cstr;
  g_compute_graph_initialized = true;

  return 0;
}

namespace {
typedef struct {
  uint8 red;
  uint8 green;
  uint8 blue;
  uint8 alpha;
} RGBA;
}  // namespace

// Returns the top N confidence values over threshold in the provided vector,
// sorted by confidence in descending order.
static void GetTopN(
    const Eigen::TensorMap<Eigen::Tensor<float, 1, Eigen::RowMajor>,
                           Eigen::Aligned>& prediction,
    const int num_results, const float threshold,
    std::vector<std::pair<float, int> >* top_results) {
  // Will contain top N results in ascending order.
  std::priority_queue<std::pair<float, int>,
      std::vector<std::pair<float, int> >,
      std::greater<std::pair<float, int> > > top_result_pq;

  const int count = prediction.size();
  for (int i = 0; i < count; ++i) {
    const float value = prediction(i);

    // Only add it if it beats the threshold and has a chance at being in
    // the top N.
    if (value < threshold) {
      continue;
    }

    top_result_pq.push(std::pair<float, int>(value, i));

    // If at capacity, kick the smallest value out.
    if (top_result_pq.size() > num_results) {
      top_result_pq.pop();
    }
  }

  // Copy to output vector and reverse into descending order.
  while (!top_result_pq.empty()) {
    top_results->push_back(top_result_pq.top());
    top_result_pq.pop();
  }
  std::reverse(top_results->begin(), top_results->end());
}

static std::string ClassifyImage(const RGBA* const bitmap_src,
                                 const int in_stride,
                                 const int width, const int height) {
  ++g_num_runs;

  // Create input tensor
  tensorflow::Tensor input_tensor(
      tensorflow::DT_FLOAT,
      tensorflow::TensorShape({
          1, g_tensorflow_input_size, g_tensorflow_input_size, 3}));

  auto input_tensor_mapped = input_tensor.tensor<float, 4>();

  LOG(INFO) << "Tensorflow: Copying Data.";
  for (int i = 0; i < g_tensorflow_input_size; ++i) {
    const RGBA* src = bitmap_src + i * g_tensorflow_input_size;
    for (int j = 0; j < g_tensorflow_input_size; ++j) {
       // Copy 3 values
      input_tensor_mapped(0, i, j, 0) =
          static_cast<float>(src->red) - g_image_mean;
      input_tensor_mapped(0, i, j, 1) =
          static_cast<float>(src->green) - g_image_mean;
      input_tensor_mapped(0, i, j, 2) =
          static_cast<float>(src->blue) - g_image_mean;
      ++src;
    }
  }

  std::vector<std::pair<std::string, tensorflow::Tensor> > input_tensors(
      {{"input:0", input_tensor}});

  VLOG(0) << "Start computing.";
  std::vector<tensorflow::Tensor> output_tensors;
  std::vector<std::string> output_names({"output:0"});

  tensorflow::Status s;
  int64 start_time, end_time;

  if (kSaveStepStats) {
    RunOptions run_options;
    run_options.set_trace_level(RunOptions::FULL_TRACE);
    RunMetadata run_metadata;
    start_time = CurrentThreadTimeUs();
    s = session->Run(run_options, input_tensors, output_names, {},
                     &output_tensors, &run_metadata);
    end_time = CurrentThreadTimeUs();
    assert(run_metadata.has_step_stats());

    const StepStats& stats = run_metadata.step_stats();

    mkdir("/sdcard/tf/", 0755);
    const string filename =
        strings::Printf("/sdcard/tf/stepstats%05d.pb", g_num_runs);
    WriteProtoToFile(filename.c_str(), stats);
  } else {
    start_time = CurrentThreadTimeUs();
    s = session->Run(input_tensors, output_names, {}, &output_tensors);
    end_time = CurrentThreadTimeUs();
  }
  const int64 elapsed_time_inf = end_time - start_time;
  g_timing_total_us += elapsed_time_inf;
  VLOG(0) << "End computing. Ran in " << elapsed_time_inf / 1000 << "ms ("
          << (g_timing_total_us / g_num_runs / 1000) << "ms avg over "
          << g_num_runs << " runs)";

  if (!s.ok()) {
    LOG(ERROR) << "Error during inference: " << s;
    return "";
  }

  VLOG(0) << "Reading from layer " << output_names[0];
  tensorflow::Tensor* output = &output_tensors[0];
  const int kNumResults = 5;
  const float kThreshold = 0.1f;
  std::vector<std::pair<float, int> > top_results;
  GetTopN(output->flat<float>(), kNumResults, kThreshold, &top_results);

  std::stringstream ss;
  ss.precision(3);
  for (const auto& result : top_results) {
    const float confidence = result.first;
    const int index = result.second;

    ss << index << " " << confidence << " ";

    // Write out the result as a string
    if (index < g_label_strings.size()) {
      // just for safety: theoretically, the output is under 1000 unless there
      // is some numerical issues leading to a wrong prediction.
      ss << g_label_strings[index];
    } else {
      ss << "Prediction: " << index;
    }

    ss << "\n";
  }

  LOG(INFO) << "Predictions: " << ss.str();
  return ss.str();
}

JNIEXPORT jstring JNICALL
TENSORFLOW_METHOD(classifyImageRgb)(
    JNIEnv* env, jobject thiz, jintArray image, jint width, jint height) {
  // Copy image into currFrame.
  jboolean iCopied = JNI_FALSE;
  jint* pixels = env->GetIntArrayElements(image, &iCopied);

  std::string result = ClassifyImage(
      reinterpret_cast<const RGBA*>(pixels), width * 4, width, height);

  env->ReleaseIntArrayElements(image, pixels, JNI_ABORT);

  return env->NewStringUTF(result.c_str());
}

JNIEXPORT jstring JNICALL
TENSORFLOW_METHOD(classifyImageBmp)(
    JNIEnv* env, jobject thiz, jobject bitmap) {
  // Obtains the bitmap information.
  AndroidBitmapInfo info;
  CHECK_EQ(AndroidBitmap_getInfo(env, bitmap, &info),
           ANDROID_BITMAP_RESULT_SUCCESS);
  void* pixels;
  CHECK_EQ(AndroidBitmap_lockPixels(env, bitmap, &pixels),
           ANDROID_BITMAP_RESULT_SUCCESS);
  LOG(INFO) << "Height: " << info.height;
  LOG(INFO) << "Width: " << info.width;
  LOG(INFO) << "Stride: " << info.stride;
  // TODO(jiayq): deal with other formats if necessary.
  if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
    return env->NewStringUTF(
        "Error: Android system is not using RGBA_8888 in default.");
  }

  std::string result = ClassifyImage(
      static_cast<const RGBA*>(pixels), info.stride, info.width, info.height);

  // Finally, unlock the pixels
  CHECK_EQ(AndroidBitmap_unlockPixels(env, bitmap),
           ANDROID_BITMAP_RESULT_SUCCESS);

  return env->NewStringUTF(result.c_str());
}
<commit_msg>Add optional Android demo termination after running fixed number of inferences passes, to make benchmarks more reproducible. Change: 117867195<commit_after>/* Copyright 2015 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/examples/android/jni/tensorflow_jni.h"

#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
#include <android/bitmap.h>

#include <jni.h>
#include <pthread.h>
#include <sys/stat.h>
#include <unistd.h>
#include <queue>
#include <sstream>
#include <string>

#include "tensorflow/core/framework/step_stats.pb.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/framework/types.pb.h"
#include "tensorflow/core/lib/strings/stringprintf.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/mutex.h"
#include "tensorflow/core/platform/types.h"
#include "tensorflow/core/public/session.h"
#include "tensorflow/examples/android/jni/jni_utils.h"

using namespace tensorflow;

// Global variables that holds the Tensorflow classifier.
static std::unique_ptr<tensorflow::Session> session;

static std::vector<std::string> g_label_strings;
static bool g_compute_graph_initialized = false;
//static mutex g_compute_graph_mutex(base::LINKER_INITIALIZED);

static int g_tensorflow_input_size;  // The image size for the mognet input.
static int g_image_mean;  // The image mean.

// For basic benchmarking.
static int g_num_runs = 0;
static int64 g_timing_total_us = 0;

// Improve benchmarking by limiting runs to predefined amount.
// 0 (default) denotes infinite runs.
#ifndef MAX_NUM_RUNS
#define MAX_NUM_RUNS 0
#endif

#ifdef SAVE_STEP_STATS
static const bool kSaveStepStats = true;
#else
static const bool kSaveStepStats = false;
#endif

inline static int64 CurrentThreadTimeUs() {
  struct timeval tv;
  gettimeofday(&tv, NULL);
  return tv.tv_sec * 1000000 + tv.tv_usec;
}

JNIEXPORT jint JNICALL
TENSORFLOW_METHOD(initializeTensorflow)(
    JNIEnv* env, jobject thiz, jobject java_asset_manager,
    jstring model, jstring labels,
    jint num_classes, jint mognet_input_size, jint image_mean) {
  g_num_runs = 0;
  g_timing_total_us = 0;

  //MutexLock input_lock(&g_compute_graph_mutex);
  if (g_compute_graph_initialized) {
    LOG(INFO) << "Compute graph already loaded. skipping.";
    return 0;
  }

  const char* const model_cstr = env->GetStringUTFChars(model, NULL);
  const char* const labels_cstr = env->GetStringUTFChars(labels, NULL);

  g_tensorflow_input_size = mognet_input_size;
  g_image_mean = image_mean;

  LOG(INFO) << "Loading Tensorflow.";

  LOG(INFO) << "Making new SessionOptions.";
  tensorflow::SessionOptions options;
  tensorflow::ConfigProto& config = options.config;
  LOG(INFO) << "Got config, " << config.device_count_size() << " devices";

  session.reset(tensorflow::NewSession(options));
  LOG(INFO) << "Session created.";

  tensorflow::GraphDef tensorflow_graph;
  LOG(INFO) << "Graph created.";

  AAssetManager* const asset_manager =
      AAssetManager_fromJava(env, java_asset_manager);
  LOG(INFO) << "Acquired AssetManager.";

  LOG(INFO) << "Reading file to proto: " << model_cstr;
  ReadFileToProto(asset_manager, model_cstr, &tensorflow_graph);

  LOG(INFO) << "Creating session.";
  tensorflow::Status s = session->Create(tensorflow_graph);
  if (!s.ok()) {
    LOG(ERROR) << "Could not create Tensorflow Graph: " << s;
    return -1;
  }

  // Clear the proto to save memory space.
  tensorflow_graph.Clear();
  LOG(INFO) << "Tensorflow graph loaded from: " << model_cstr;

  // Read the label list
  ReadFileToVector(asset_manager, labels_cstr, &g_label_strings);
  LOG(INFO) << g_label_strings.size() << " label strings loaded from: "
            << labels_cstr;
  g_compute_graph_initialized = true;

  return 0;
}

namespace {
typedef struct {
  uint8 red;
  uint8 green;
  uint8 blue;
  uint8 alpha;
} RGBA;
}  // namespace

// Returns the top N confidence values over threshold in the provided vector,
// sorted by confidence in descending order.
static void GetTopN(
    const Eigen::TensorMap<Eigen::Tensor<float, 1, Eigen::RowMajor>,
                           Eigen::Aligned>& prediction,
    const int num_results, const float threshold,
    std::vector<std::pair<float, int> >* top_results) {
  // Will contain top N results in ascending order.
  std::priority_queue<std::pair<float, int>,
      std::vector<std::pair<float, int> >,
      std::greater<std::pair<float, int> > > top_result_pq;

  const int count = prediction.size();
  for (int i = 0; i < count; ++i) {
    const float value = prediction(i);

    // Only add it if it beats the threshold and has a chance at being in
    // the top N.
    if (value < threshold) {
      continue;
    }

    top_result_pq.push(std::pair<float, int>(value, i));

    // If at capacity, kick the smallest value out.
    if (top_result_pq.size() > num_results) {
      top_result_pq.pop();
    }
  }

  // Copy to output vector and reverse into descending order.
  while (!top_result_pq.empty()) {
    top_results->push_back(top_result_pq.top());
    top_result_pq.pop();
  }
  std::reverse(top_results->begin(), top_results->end());
}

static std::string ClassifyImage(const RGBA* const bitmap_src,
                                 const int in_stride,
                                 const int width, const int height) {
  // Force the app to quit if we've reached our run quota, to make
  // benchmarks more reproducible.
  if (MAX_NUM_RUNS > 0 && g_num_runs >= MAX_NUM_RUNS) {
    LOG(INFO) << "Benchmark complete. "
              << (g_timing_total_us / g_num_runs / 1000) << "ms/run avg over "
              << g_num_runs << " runs.";
    LOG(INFO) << "";
    exit(0);
  }

  ++g_num_runs;

  // Create input tensor
  tensorflow::Tensor input_tensor(
      tensorflow::DT_FLOAT,
      tensorflow::TensorShape({
          1, g_tensorflow_input_size, g_tensorflow_input_size, 3}));

  auto input_tensor_mapped = input_tensor.tensor<float, 4>();

  LOG(INFO) << "Tensorflow: Copying Data.";
  for (int i = 0; i < g_tensorflow_input_size; ++i) {
    const RGBA* src = bitmap_src + i * g_tensorflow_input_size;
    for (int j = 0; j < g_tensorflow_input_size; ++j) {
       // Copy 3 values
      input_tensor_mapped(0, i, j, 0) =
          static_cast<float>(src->red) - g_image_mean;
      input_tensor_mapped(0, i, j, 1) =
          static_cast<float>(src->green) - g_image_mean;
      input_tensor_mapped(0, i, j, 2) =
          static_cast<float>(src->blue) - g_image_mean;
      ++src;
    }
  }

  std::vector<std::pair<std::string, tensorflow::Tensor> > input_tensors(
      {{"input:0", input_tensor}});

  VLOG(0) << "Start computing.";
  std::vector<tensorflow::Tensor> output_tensors;
  std::vector<std::string> output_names({"output:0"});

  tensorflow::Status s;
  int64 start_time, end_time;

  if (kSaveStepStats) {
    RunOptions run_options;
    run_options.set_trace_level(RunOptions::FULL_TRACE);
    RunMetadata run_metadata;
    start_time = CurrentThreadTimeUs();
    s = session->Run(run_options, input_tensors, output_names, {},
                     &output_tensors, &run_metadata);
    end_time = CurrentThreadTimeUs();
    assert(run_metadata.has_step_stats());

    const StepStats& stats = run_metadata.step_stats();

    mkdir("/sdcard/tf/", 0755);
    const string filename =
        strings::Printf("/sdcard/tf/stepstats%05d.pb", g_num_runs);
    WriteProtoToFile(filename.c_str(), stats);
  } else {
    start_time = CurrentThreadTimeUs();
    s = session->Run(input_tensors, output_names, {}, &output_tensors);
    end_time = CurrentThreadTimeUs();
  }
  const int64 elapsed_time_inf = end_time - start_time;
  g_timing_total_us += elapsed_time_inf;
  VLOG(0) << "End computing. Ran in " << elapsed_time_inf / 1000 << "ms ("
          << (g_timing_total_us / g_num_runs / 1000) << "ms avg over "
          << g_num_runs << " runs)";

  if (!s.ok()) {
    LOG(ERROR) << "Error during inference: " << s;
    return "";
  }

  VLOG(0) << "Reading from layer " << output_names[0];
  tensorflow::Tensor* output = &output_tensors[0];
  const int kNumResults = 5;
  const float kThreshold = 0.1f;
  std::vector<std::pair<float, int> > top_results;
  GetTopN(output->flat<float>(), kNumResults, kThreshold, &top_results);

  std::stringstream ss;
  ss.precision(3);
  for (const auto& result : top_results) {
    const float confidence = result.first;
    const int index = result.second;

    ss << index << " " << confidence << " ";

    // Write out the result as a string
    if (index < g_label_strings.size()) {
      // just for safety: theoretically, the output is under 1000 unless there
      // is some numerical issues leading to a wrong prediction.
      ss << g_label_strings[index];
    } else {
      ss << "Prediction: " << index;
    }

    ss << "\n";
  }

  LOG(INFO) << "Predictions: " << ss.str();
  return ss.str();
}

JNIEXPORT jstring JNICALL
TENSORFLOW_METHOD(classifyImageRgb)(
    JNIEnv* env, jobject thiz, jintArray image, jint width, jint height) {
  // Copy image into currFrame.
  jboolean iCopied = JNI_FALSE;
  jint* pixels = env->GetIntArrayElements(image, &iCopied);

  std::string result = ClassifyImage(
      reinterpret_cast<const RGBA*>(pixels), width * 4, width, height);

  env->ReleaseIntArrayElements(image, pixels, JNI_ABORT);

  return env->NewStringUTF(result.c_str());
}

JNIEXPORT jstring JNICALL
TENSORFLOW_METHOD(classifyImageBmp)(
    JNIEnv* env, jobject thiz, jobject bitmap) {
  // Obtains the bitmap information.
  AndroidBitmapInfo info;
  CHECK_EQ(AndroidBitmap_getInfo(env, bitmap, &info),
           ANDROID_BITMAP_RESULT_SUCCESS);
  void* pixels;
  CHECK_EQ(AndroidBitmap_lockPixels(env, bitmap, &pixels),
           ANDROID_BITMAP_RESULT_SUCCESS);
  LOG(INFO) << "Image dimensions: " << info.width << "x" << info.height
            << " stride: " << info.stride;
  // TODO(jiayq): deal with other formats if necessary.
  if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
    return env->NewStringUTF(
        "Error: Android system is not using RGBA_8888 in default.");
  }

  std::string result = ClassifyImage(
      static_cast<const RGBA*>(pixels), info.stride, info.width, info.height);

  // Finally, unlock the pixels
  CHECK_EQ(AndroidBitmap_unlockPixels(env, bitmap),
           ANDROID_BITMAP_RESULT_SUCCESS);

  return env->NewStringUTF(result.c_str());
}
<|endoftext|>


<commit_before>/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/lite/micro/kernels/all_ops_resolver.h"

#include "tensorflow/lite/micro/kernels/micro_ops.h"

namespace tflite {
namespace ops {
namespace micro {

// Register each supported op with:
// AddBuiltin(<operator ID>, <registration>, [min version], [max version])
AllOpsResolver::AllOpsResolver() {
  AddBuiltin(BuiltinOperator_FULLY_CONNECTED, Register_FULLY_CONNECTED(), 1, 4);
  AddBuiltin(BuiltinOperator_MAX_POOL_2D, Register_MAX_POOL_2D());
  AddBuiltin(BuiltinOperator_SOFTMAX, Register_SOFTMAX());
  AddBuiltin(BuiltinOperator_LOGISTIC, Register_LOGISTIC());
  AddBuiltin(BuiltinOperator_SVDF, Register_SVDF());
  AddBuiltin(BuiltinOperator_CONV_2D, Register_CONV_2D(), 1, 3);
  AddBuiltin(BuiltinOperator_CONCATENATION, Register_CONCATENATION(), 1, 3);
  AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Register_DEPTHWISE_CONV_2D(), 1,
             3);
  AddBuiltin(BuiltinOperator_AVERAGE_POOL_2D, Register_AVERAGE_POOL_2D(), 1, 2);
  AddBuiltin(BuiltinOperator_ABS, Register_ABS());
  AddBuiltin(BuiltinOperator_SIN, Register_SIN());
  AddBuiltin(BuiltinOperator_COS, Register_COS());
  AddBuiltin(BuiltinOperator_LOG, Register_LOG());
  AddBuiltin(BuiltinOperator_SQRT, Register_SQRT());
  AddBuiltin(BuiltinOperator_RSQRT, Register_RSQRT());
  AddBuiltin(BuiltinOperator_SQUARE, Register_SQUARE());
  AddBuiltin(BuiltinOperator_PRELU, Register_PRELU());
  AddBuiltin(BuiltinOperator_FLOOR, Register_FLOOR());
  AddBuiltin(BuiltinOperator_MAXIMUM, Register_MAXIMUM());
  AddBuiltin(BuiltinOperator_MINIMUM, Register_MINIMUM());
  AddBuiltin(BuiltinOperator_ARG_MAX, Register_ARG_MAX());
  AddBuiltin(BuiltinOperator_ARG_MIN, Register_ARG_MIN());
  AddBuiltin(BuiltinOperator_LOGICAL_OR, Register_LOGICAL_OR());
  AddBuiltin(BuiltinOperator_LOGICAL_AND, Register_LOGICAL_AND());
  AddBuiltin(BuiltinOperator_LOGICAL_NOT, Register_LOGICAL_NOT());
  AddBuiltin(BuiltinOperator_RESHAPE, Register_RESHAPE());
  AddBuiltin(BuiltinOperator_EQUAL, Register_EQUAL());
  AddBuiltin(BuiltinOperator_NOT_EQUAL, Register_NOT_EQUAL());
  AddBuiltin(BuiltinOperator_GREATER, Register_GREATER());
  AddBuiltin(BuiltinOperator_GREATER_EQUAL, Register_GREATER_EQUAL());
  AddBuiltin(BuiltinOperator_LESS, Register_LESS());
  AddBuiltin(BuiltinOperator_LESS_EQUAL, Register_LESS_EQUAL());
  AddBuiltin(BuiltinOperator_CEIL, Register_CEIL());
  AddBuiltin(BuiltinOperator_ROUND, Register_ROUND());
  AddBuiltin(BuiltinOperator_STRIDED_SLICE, Register_STRIDED_SLICE());
  AddBuiltin(BuiltinOperator_PACK, Register_PACK());
  AddBuiltin(BuiltinOperator_PAD, Register_PAD());
  AddBuiltin(BuiltinOperator_PADV2, Register_PADV2());
  AddBuiltin(BuiltinOperator_SPLIT, Register_SPLIT(), 1, 3);
  AddBuiltin(BuiltinOperator_UNPACK, Register_UNPACK());
  AddBuiltin(BuiltinOperator_NEG, Register_NEG());
  AddBuiltin(BuiltinOperator_ADD, Register_ADD());
  AddBuiltin(BuiltinOperator_MUL, Register_MUL());
  AddBuiltin(BuiltinOperator_QUANTIZE, Register_QUANTIZE());
  AddBuiltin(BuiltinOperator_DEQUANTIZE, Register_DEQUANTIZE(), 1, 2);
  AddBuiltin(BuiltinOperator_RELU, Register_RELU());
  AddBuiltin(BuiltinOperator_RELU6, Register_RELU6());
}

}  // namespace micro
}  // namespace ops
}  // namespace tflite
<commit_msg>Fix operator versions in all_ops_resolver.  Based on op versions listed in https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/tools/versioning/op_version.cc.<commit_after>/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/lite/micro/kernels/all_ops_resolver.h"

#include "tensorflow/lite/micro/kernels/micro_ops.h"

namespace tflite {
namespace ops {
namespace micro {

// Register each supported op with:
// AddBuiltin(<operator ID>, <registration>, [min version], [max version])
AllOpsResolver::AllOpsResolver() {
  AddBuiltin(BuiltinOperator_FULLY_CONNECTED, Register_FULLY_CONNECTED(), 1, 4);
  AddBuiltin(BuiltinOperator_MAX_POOL_2D, Register_MAX_POOL_2D());
  AddBuiltin(BuiltinOperator_SOFTMAX, Register_SOFTMAX(), 1, 2);
  AddBuiltin(BuiltinOperator_LOGISTIC, Register_LOGISTIC());
  AddBuiltin(BuiltinOperator_SVDF, Register_SVDF(), 1, 3);
  AddBuiltin(BuiltinOperator_CONV_2D, Register_CONV_2D(), 1, 3);
  AddBuiltin(BuiltinOperator_CONCATENATION, Register_CONCATENATION(), 1, 3);
  AddBuiltin(BuiltinOperator_DEPTHWISE_CONV_2D, Register_DEPTHWISE_CONV_2D(), 1,
             3);
  AddBuiltin(BuiltinOperator_AVERAGE_POOL_2D, Register_AVERAGE_POOL_2D(), 1, 2);
  AddBuiltin(BuiltinOperator_ABS, Register_ABS());
  AddBuiltin(BuiltinOperator_SIN, Register_SIN());
  AddBuiltin(BuiltinOperator_COS, Register_COS());
  AddBuiltin(BuiltinOperator_LOG, Register_LOG());
  AddBuiltin(BuiltinOperator_SQRT, Register_SQRT());
  AddBuiltin(BuiltinOperator_RSQRT, Register_RSQRT());
  AddBuiltin(BuiltinOperator_SQUARE, Register_SQUARE());
  AddBuiltin(BuiltinOperator_PRELU, Register_PRELU());
  AddBuiltin(BuiltinOperator_FLOOR, Register_FLOOR());
  AddBuiltin(BuiltinOperator_MAXIMUM, Register_MAXIMUM());
  AddBuiltin(BuiltinOperator_MINIMUM, Register_MINIMUM());
  AddBuiltin(BuiltinOperator_ARG_MAX, Register_ARG_MAX());
  AddBuiltin(BuiltinOperator_ARG_MIN, Register_ARG_MIN());
  AddBuiltin(BuiltinOperator_LOGICAL_OR, Register_LOGICAL_OR());
  AddBuiltin(BuiltinOperator_LOGICAL_AND, Register_LOGICAL_AND());
  AddBuiltin(BuiltinOperator_LOGICAL_NOT, Register_LOGICAL_NOT());
  AddBuiltin(BuiltinOperator_RESHAPE, Register_RESHAPE());
  AddBuiltin(BuiltinOperator_EQUAL, Register_EQUAL(), 1, 2);
  AddBuiltin(BuiltinOperator_NOT_EQUAL, Register_NOT_EQUAL(), 1, 2);
  AddBuiltin(BuiltinOperator_GREATER, Register_GREATER(), 1, 2);
  AddBuiltin(BuiltinOperator_GREATER_EQUAL, Register_GREATER_EQUAL(), 1, 2);
  AddBuiltin(BuiltinOperator_LESS, Register_LESS(), 1, 2);
  AddBuiltin(BuiltinOperator_LESS_EQUAL, Register_LESS_EQUAL(), 1, 2);
  AddBuiltin(BuiltinOperator_CEIL, Register_CEIL());
  AddBuiltin(BuiltinOperator_ROUND, Register_ROUND());
  AddBuiltin(BuiltinOperator_STRIDED_SLICE, Register_STRIDED_SLICE());
  AddBuiltin(BuiltinOperator_PACK, Register_PACK(), 1, 2);
  AddBuiltin(BuiltinOperator_PAD, Register_PAD(), 1, 2);
  AddBuiltin(BuiltinOperator_PADV2, Register_PADV2(), 1, 2);
  AddBuiltin(BuiltinOperator_SPLIT, Register_SPLIT(), 1, 3);
  AddBuiltin(BuiltinOperator_UNPACK, Register_UNPACK(), 1, 2);
  AddBuiltin(BuiltinOperator_NEG, Register_NEG());
  AddBuiltin(BuiltinOperator_ADD, Register_ADD(), 1, 2);
  AddBuiltin(BuiltinOperator_MUL, Register_MUL(), 1, 3);
  AddBuiltin(BuiltinOperator_QUANTIZE, Register_QUANTIZE());
  AddBuiltin(BuiltinOperator_DEQUANTIZE, Register_DEQUANTIZE(), 1, 2);
  AddBuiltin(BuiltinOperator_RELU, Register_RELU());
  AddBuiltin(BuiltinOperator_RELU6, Register_RELU6());
}

}  // namespace micro
}  // namespace ops
}  // namespace tflite
<|endoftext|>


<commit_before>#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Analysis/AliasAnalysis.h"
using namespace llvm;

#include "rcs/IDAssigner.h"
using namespace rcs;

namespace rcs {
struct FakeAA: public ImmutablePass, public AliasAnalysis {
  static char ID;

  FakeAA(): ImmutablePass(ID) {}
  virtual void initializePass();
  virtual void getAnalysisUsage(AnalysisUsage &AU) const;
  virtual void *getAdjustedAnalysisPointer(AnalysisID PI);

  // interfaces of AliasAnalysis
  virtual AliasResult alias(const Location &L1, const Location &L2) {
    IDAssigner &IDA = getAnalysis<IDAssigner>();
    errs() << "FakeAA::alias " << IDA.getNumValues() << "\n";
    return NoAlias;
  }
  virtual ModRefBehavior getModRefBehavior(const Function *F) { return DoesNotAccessMemory; }
  virtual ModRefBehavior getModRefBehavior(ImmutableCallSite CS) { return DoesNotAccessMemory; }
  virtual bool pointsToConstantMemory(const Location &Loc, bool OrLocal = false) { return true; }
  virtual void deleteValue(Value *V) {}
  virtual void copyValue(Value *From, Value *To) {}
  virtual void addEscapingUse(Use &U) {}
};
}

static RegisterPass<FakeAA> X("fake-aa", "Fake AA", false, true);
static RegisterAnalysisGroup<AliasAnalysis> Y(X);

char FakeAA::ID = 0;

void FakeAA::initializePass() {
  DEBUG(dbgs() << "FakeAA::initializePass\n";);
  InitializeAliasAnalysis(this);
}

void FakeAA::getAnalysisUsage(AnalysisUsage &AU) const {
  AliasAnalysis::getAnalysisUsage(AU);
  AU.addRequired<IDAssigner>();
}

void *FakeAA::getAdjustedAnalysisPointer(AnalysisID PI) {
  if (PI == &AliasAnalysis::ID)
    return (AliasAnalysis *)this;
  return this;
}
<commit_msg>Include "Debug.h" to support gcc 4.5<commit_after>#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Analysis/AliasAnalysis.h"
using namespace llvm;

#include "rcs/IDAssigner.h"
using namespace rcs;

namespace rcs {
struct FakeAA: public ImmutablePass, public AliasAnalysis {
  static char ID;

  FakeAA(): ImmutablePass(ID) {}
  virtual void initializePass();
  virtual void getAnalysisUsage(AnalysisUsage &AU) const;
  virtual void *getAdjustedAnalysisPointer(AnalysisID PI);

  // interfaces of AliasAnalysis
  virtual AliasResult alias(const Location &L1, const Location &L2) {
    IDAssigner &IDA = getAnalysis<IDAssigner>();
    errs() << "FakeAA::alias " << IDA.getNumValues() << "\n";
    return NoAlias;
  }
  virtual ModRefBehavior getModRefBehavior(const Function *F) { return DoesNotAccessMemory; }
  virtual ModRefBehavior getModRefBehavior(ImmutableCallSite CS) { return DoesNotAccessMemory; }
  virtual bool pointsToConstantMemory(const Location &Loc, bool OrLocal = false) { return true; }
  virtual void deleteValue(Value *V) {}
  virtual void copyValue(Value *From, Value *To) {}
  virtual void addEscapingUse(Use &U) {}
};
}

static RegisterPass<FakeAA> X("fake-aa", "Fake AA", false, true);
static RegisterAnalysisGroup<AliasAnalysis> Y(X);

char FakeAA::ID = 0;

void FakeAA::initializePass() {
  DEBUG(dbgs() << "FakeAA::initializePass\n";);
  InitializeAliasAnalysis(this);
}

void FakeAA::getAnalysisUsage(AnalysisUsage &AU) const {
  AliasAnalysis::getAnalysisUsage(AU);
  AU.addRequired<IDAssigner>();
}

void *FakeAA::getAdjustedAnalysisPointer(AnalysisID PI) {
  if (PI == &AliasAnalysis::ID)
    return (AliasAnalysis *)this;
  return this;
}
<|endoftext|>