<commit_before>//
// Created by Peter Eichinger on 30.10.18.
//

#include "BaseChunkAllocator.h"

#include "saiga/imgui/imgui.h"
#include "saiga/util/easylogging++.h"
#include "saiga/util/tostring.h"

#include "BufferChunkAllocator.h"
#include "ChunkCreator.h"
namespace Saiga::Vulkan::Memory
{
MemoryLocation* BaseChunkAllocator::allocate(vk::DeviceSize size)
{
    std::scoped_lock alloc_lock(allocationMutex);
    ChunkIterator chunkAlloc;
    FreeIterator freeSpace;
    std::tie(chunkAlloc, freeSpace) = strategy->findRange(chunks.begin(), chunks.end(), size);

    MemoryLocation* val = allocate_in_free_space(size, chunkAlloc, freeSpace);

    return val;
}

MemoryLocation* BaseChunkAllocator::allocate_in_free_space(vk::DeviceSize size, ChunkIterator& chunkAlloc,
                                                           FreeIterator& freeSpace)
{
    MemoryLocation* val;
    if (chunkAlloc == chunks.end())
    {
        chunkAlloc = createNewChunk();
        freeSpace  = chunkAlloc->freeList.begin();
    }

    auto memoryStart = freeSpace->offset;

    freeSpace->offset += size;
    freeSpace->size -= size;

    if (freeSpace->size == 0)
    {
        chunkAlloc->freeList.erase(freeSpace);
    }

    findNewMax(chunkAlloc);

    // MemoryLocation{iter->buffer, iter->chunk->memory, offset, size, iter->mappedPointer};

    auto targetLocation = std::__1::make_unique<MemoryLocation>(chunkAlloc->buffer, chunkAlloc->chunk->memory,
                                                                memoryStart, size, chunkAlloc->mappedPointer);
    auto memoryEnd      = memoryStart + size;

    auto insertionPoint =
        lower_bound(chunkAlloc->allocations.begin(), chunkAlloc->allocations.end(), memoryEnd,
                    [](const auto& element, vk::DeviceSize value) { return element->offset < value; });

    val = chunkAlloc->allocations.insert(insertionPoint, move(targetLocation))->get();
    chunkAlloc->allocated += size;
    return val;
}

void BaseChunkAllocator::findNewMax(ChunkIterator& chunkAlloc) const
{
    auto& freeList = chunkAlloc->freeList;

    if (chunkAlloc->freeList.empty())
    {
        chunkAlloc->maxFreeRange = std::nullopt;
        return;
    }

    chunkAlloc->maxFreeRange = *max_element(freeList.begin(), freeList.end(),
                                            [](auto& first, auto& second) { return first.size < second.size; });
}

void BaseChunkAllocator::deallocate(MemoryLocation* location)
{
    std::scoped_lock alloc_lock(allocationMutex);

    ChunkIterator fChunk;
    AllocationIterator fLoc;

    std::tie(fChunk, fLoc) = find_allocation(location);

    auto& chunkAllocs = fChunk->allocations;

    SAIGA_ASSERT(fLoc != chunkAllocs.end(), "Allocation is not part of the chunk");
    auto& chunkFree = fChunk->freeList;
    LOG(INFO) << "Deallocating " << location->size << " bytes in chunk/offset [" << distance(chunks.begin(), fChunk)
              << "/" << (*fLoc)->offset << "]";

    FreeIterator freePrev, freeNext, freeInsert;
    bool foundInsert = false;
    freePrev = freeNext = chunkFree.end();
    freeInsert          = chunkFree.end();
    for (auto freeIt = chunkFree.begin(); freeIt != chunkFree.end(); ++freeIt)
    {
        if (freeIt->offset + freeIt->size == location->offset)
        {
            freePrev = freeIt;
        }
        if (freeIt->offset == location->offset + location->size)
        {
            freeNext = freeIt;
            break;
        }
        if ((freeIt->offset + freeIt->size) < location->offset)
        {
            freeInsert  = freeIt;
            foundInsert = true;
        }
    }

    if (freePrev != chunkFree.end() && freeNext != chunkFree.end())
    {
        // Free space before and after newly freed space -> merge
        freePrev->size += location->size + freeNext->size;
        chunkFree.erase(freeNext);
    }
    else if (freePrev != chunkFree.end())
    {
        // Free only before -> increase size
        freePrev->size += location->size;
    }
    else if (freeNext != chunkFree.end())
    {
        // Free only after newly freed -> move and increase size
        freeNext->offset = location->offset;
        freeNext->size += location->size;
    }
    else
    {
        FreeIterator insertionPoint;
        if (foundInsert)
        {
            insertionPoint = std::next(freeInsert);
        }
        else
        {
            insertionPoint = chunkFree.begin();
        }

        chunkFree.insert(insertionPoint, FreeListEntry{location->offset, location->size});
    }

    findNewMax(fChunk);

    chunkAllocs.erase(fLoc);

    fChunk->allocated -= location->size;
    if (chunks.size() >= 2)
    {
        // Free memory if second to last and last chunk are empty
        auto last           = chunks.end() - 1;
        auto second_to_last = last - 1;
        if (last->allocations.empty() && second_to_last->allocations.empty())
        {
            m_device.destroy(last->buffer);
            m_chunkAllocator->deallocate(last->chunk);
            chunks.erase(last);
        }
    }
}
void BaseChunkAllocator::destroy()
{
    for (auto& alloc : chunks)
    {
        m_device.destroy(alloc.buffer);
    }
}

bool BaseChunkAllocator::memory_is_free(vk::DeviceMemory memory, FreeListEntry free_mem)
{
    auto chunk = std::find_if(chunks.begin(), chunks.end(),
                              [&](const auto& chunk_entry) { return chunk_entry.chunk->memory = memory; });

    SAIGA_ASSERT(chunk != chunks.end(), "Wrong allocator");

    if (chunk->freeList.empty())
    {
        return false;
    }
    auto found =
        std::lower_bound(chunk->freeList.begin(), chunk->freeList.end(), free_mem,
                         [](const auto& free_entry, const auto& value) { return free_entry.offset < value.offset; });

    // if (found->offset > free_mem.offset)
    //{
    //    return false;
    //}
    //
    // if (found->offset + found->size < free_mem.offset + free_mem.size)
    //{
    //    return false;
    //}

    return found->offset == free_mem.offset && found->size == free_mem.size;
}

MemoryLocation* BaseChunkAllocator::reserve_space(vk::DeviceMemory memory, FreeListEntry freeListEntry,
                                                  vk::DeviceSize size)
{
    auto chunk = std::find_if(chunks.begin(), chunks.end(),
                              [&](const auto& chunk_entry) { return chunk_entry.chunk->memory = memory; });

    SAIGA_ASSERT(chunk != chunks.end(), "Wrong allocator");

    auto free = std::find(chunk->freeList.begin(), chunk->freeList.end(), freeListEntry);

    SAIGA_ASSERT(free != chunk->freeList.end(), "Free space not found");

    return allocate_in_free_space(size, chunk, free);
}

void BaseChunkAllocator::move_allocation(MemoryLocation* target, MemoryLocation* source)
{
    const auto size = source->size;

    MemoryLocation source_copy = *source;

    ChunkIterator target_chunk, source_chunk;
    AllocationIterator target_alloc, source_alloc;

    std::tie(target_chunk, target_alloc) = find_allocation(target);
    std::tie(source_chunk, source_alloc) = find_allocation(source);

    *source = *target;  // copy values from target to source;

    // target_chunk->allocated -= size;
    source_chunk->allocated -= size;

    std::move(source_alloc, std::next(source_alloc), target_alloc);

    //**target_alloc = source_copy;
    source_chunk->allocations.erase(source_alloc);

    auto found =
        std::lower_bound(source_chunk->freeList.begin(), source_chunk->freeList.end(), source_copy,
                         [](const auto& free_entry, const auto& value) { return free_entry.offset < value.offset; });

    source_chunk->freeList.insert(found, FreeListEntry{source_copy.offset, source_copy.size});

    findNewMax(source_chunk);
}

std::pair<ChunkIterator, AllocationIterator> BaseChunkAllocator::find_allocation(MemoryLocation* location)
{
    auto fChunk = std::find_if(chunks.begin(), chunks.end(),
                               [&](ChunkAllocation const& alloc) { return alloc.chunk->memory == location->memory; });

    auto& chunkAllocs = fChunk->allocations;

    SAIGA_ASSERT(fChunk != chunks.end(), "Allocation was not done with this allocator!");
    auto fLoc =
        std::lower_bound(chunkAllocs.begin(), chunkAllocs.end(), location,
                         [](const auto& element, const auto& value) { return element->offset < value->offset; });

    return std::make_pair(fChunk, fLoc);
}

}  // namespace Saiga::Vulkan::Memory
<commit_msg>Fix wrong allocation bug that destroys memory allocation<commit_after>//
// Created by Peter Eichinger on 30.10.18.
//

#include "BaseChunkAllocator.h"

#include "saiga/imgui/imgui.h"
#include "saiga/util/easylogging++.h"
#include "saiga/util/tostring.h"

#include "BufferChunkAllocator.h"
#include "ChunkCreator.h"
namespace Saiga::Vulkan::Memory
{
MemoryLocation* BaseChunkAllocator::allocate(vk::DeviceSize size)
{
    std::scoped_lock alloc_lock(allocationMutex);
    ChunkIterator chunkAlloc;
    FreeIterator freeSpace;
    std::tie(chunkAlloc, freeSpace) = strategy->findRange(chunks.begin(), chunks.end(), size);

    MemoryLocation* val = allocate_in_free_space(size, chunkAlloc, freeSpace);

    return val;
}

MemoryLocation* BaseChunkAllocator::allocate_in_free_space(vk::DeviceSize size, ChunkIterator& chunkAlloc,
                                                           FreeIterator& freeSpace)
{
    MemoryLocation* val;
    if (chunkAlloc == chunks.end())
    {
        chunkAlloc = createNewChunk();
        freeSpace  = chunkAlloc->freeList.begin();
    }

    auto memoryStart = freeSpace->offset;

    freeSpace->offset += size;
    freeSpace->size -= size;

    if (freeSpace->size == 0)
    {
        chunkAlloc->freeList.erase(freeSpace);
    }

    findNewMax(chunkAlloc);

    // MemoryLocation{iter->buffer, iter->chunk->memory, offset, size, iter->mappedPointer};

    auto targetLocation = std::__1::make_unique<MemoryLocation>(chunkAlloc->buffer, chunkAlloc->chunk->memory,
                                                                memoryStart, size, chunkAlloc->mappedPointer);
    auto memoryEnd      = memoryStart + size;

    auto insertionPoint =
        lower_bound(chunkAlloc->allocations.begin(), chunkAlloc->allocations.end(), memoryEnd,
                    [](const auto& element, vk::DeviceSize value) { return element->offset < value; });

    val = chunkAlloc->allocations.insert(insertionPoint, move(targetLocation))->get();
    chunkAlloc->allocated += size;
    return val;
}

void BaseChunkAllocator::findNewMax(ChunkIterator& chunkAlloc) const
{
    auto& freeList = chunkAlloc->freeList;

    if (chunkAlloc->freeList.empty())
    {
        chunkAlloc->maxFreeRange = std::nullopt;
        return;
    }

    chunkAlloc->maxFreeRange = *max_element(freeList.begin(), freeList.end(),
                                            [](auto& first, auto& second) { return first.size < second.size; });
}

void BaseChunkAllocator::deallocate(MemoryLocation* location)
{
    std::scoped_lock alloc_lock(allocationMutex);

    ChunkIterator fChunk;
    AllocationIterator fLoc;

    std::tie(fChunk, fLoc) = find_allocation(location);

    auto& chunkAllocs = fChunk->allocations;

    SAIGA_ASSERT(fLoc != chunkAllocs.end(), "Allocation is not part of the chunk");
    auto& chunkFree = fChunk->freeList;
    LOG(INFO) << "Deallocating " << location->size << " bytes in chunk/offset [" << distance(chunks.begin(), fChunk)
              << "/" << (*fLoc)->offset << "]";

    FreeIterator freePrev, freeNext, freeInsert;
    bool foundInsert = false;
    freePrev = freeNext = chunkFree.end();
    freeInsert          = chunkFree.end();
    for (auto freeIt = chunkFree.begin(); freeIt != chunkFree.end(); ++freeIt)
    {
        if (freeIt->offset + freeIt->size == location->offset)
        {
            freePrev = freeIt;
        }
        if (freeIt->offset == location->offset + location->size)
        {
            freeNext = freeIt;
            break;
        }
        if ((freeIt->offset + freeIt->size) < location->offset)
        {
            freeInsert  = freeIt;
            foundInsert = true;
        }
    }

    if (freePrev != chunkFree.end() && freeNext != chunkFree.end())
    {
        // Free space before and after newly freed space -> merge
        freePrev->size += location->size + freeNext->size;
        chunkFree.erase(freeNext);
    }
    else if (freePrev != chunkFree.end())
    {
        // Free only before -> increase size
        freePrev->size += location->size;
    }
    else if (freeNext != chunkFree.end())
    {
        // Free only after newly freed -> move and increase size
        freeNext->offset = location->offset;
        freeNext->size += location->size;
    }
    else
    {
        FreeIterator insertionPoint;
        if (foundInsert)
        {
            insertionPoint = std::next(freeInsert);
        }
        else
        {
            insertionPoint = chunkFree.begin();
        }

        chunkFree.insert(insertionPoint, FreeListEntry{location->offset, location->size});
    }

    findNewMax(fChunk);

    chunkAllocs.erase(fLoc);

    fChunk->allocated -= location->size;
    if (chunks.size() >= 2)
    {
        // Free memory if second to last and last chunk are empty
        auto last           = chunks.end() - 1;
        auto second_to_last = last - 1;
        if (last->allocations.empty() && second_to_last->allocations.empty())
        {
            m_device.destroy(last->buffer);
            m_chunkAllocator->deallocate(last->chunk);
            chunks.erase(last);
        }
    }
}
void BaseChunkAllocator::destroy()
{
    for (auto& alloc : chunks)
    {
        m_device.destroy(alloc.buffer);
    }
}

bool BaseChunkAllocator::memory_is_free(vk::DeviceMemory memory, FreeListEntry free_mem)
{
    auto chunk = std::find_if(chunks.begin(), chunks.end(),
                              [&](const auto& chunk_entry) { return chunk_entry.chunk->memory == memory; });

    SAIGA_ASSERT(chunk != chunks.end(), "Wrong allocator");

    if (chunk->freeList.empty())
    {
        return false;
    }
    auto found =
        std::lower_bound(chunk->freeList.begin(), chunk->freeList.end(), free_mem,
                         [](const auto& free_entry, const auto& value) { return free_entry.offset < value.offset; });

    // if (found->offset > free_mem.offset)
    //{
    //    return false;
    //}
    //
    // if (found->offset + found->size < free_mem.offset + free_mem.size)
    //{
    //    return false;
    //}

    return found->offset == free_mem.offset && found->size == free_mem.size;
}

MemoryLocation* BaseChunkAllocator::reserve_space(vk::DeviceMemory memory, FreeListEntry freeListEntry,
                                                  vk::DeviceSize size)
{
    auto chunk = std::find_if(chunks.begin(), chunks.end(),
                              [&](const auto& chunk_entry) { return chunk_entry.chunk->memory == memory; });

    SAIGA_ASSERT(chunk != chunks.end(), "Wrong allocator");

    auto free = std::find(chunk->freeList.begin(), chunk->freeList.end(), freeListEntry);

    SAIGA_ASSERT(free != chunk->freeList.end(), "Free space not found");

    return allocate_in_free_space(size, chunk, free);
}

void BaseChunkAllocator::move_allocation(MemoryLocation* target, MemoryLocation* source)
{
    const auto size = source->size;

    MemoryLocation source_copy = *source;

    ChunkIterator target_chunk, source_chunk;
    AllocationIterator target_alloc, source_alloc;

    std::tie(target_chunk, target_alloc) = find_allocation(target);
    std::tie(source_chunk, source_alloc) = find_allocation(source);

    *source = *target;  // copy values from target to source;

    // target_chunk->allocated -= size;
    source_chunk->allocated -= size;

    std::move(source_alloc, std::next(source_alloc), target_alloc);

    //**target_alloc = source_copy;
    source_chunk->allocations.erase(source_alloc);

    auto found =
        std::lower_bound(source_chunk->freeList.begin(), source_chunk->freeList.end(), source_copy,
                         [](const auto& free_entry, const auto& value) { return free_entry.offset < value.offset; });

    source_chunk->freeList.insert(found, FreeListEntry{source_copy.offset, source_copy.size});

    findNewMax(source_chunk);
}

std::pair<ChunkIterator, AllocationIterator> BaseChunkAllocator::find_allocation(MemoryLocation* location)
{
    auto fChunk = std::find_if(chunks.begin(), chunks.end(),
                               [&](ChunkAllocation const& alloc) { return alloc.chunk->memory == location->memory; });

    SAIGA_ASSERT(fChunk != chunks.end(), "Allocation was not done with this allocator!");

    auto& chunkAllocs = fChunk->allocations;
    auto fLoc =
        std::lower_bound(chunkAllocs.begin(), chunkAllocs.end(), location,
                         [](const auto& element, const auto& value) { return element->offset < value->offset; });

    return std::make_pair(fChunk, fLoc);
}

}  // namespace Saiga::Vulkan::Memory
<|endoftext|>


<commit_before><commit_msg>Fix life step lookup.<commit_after><|endoftext|>


<commit_before><commit_msg>Add room sub depth, inscreasing complexity by a lot<commit_after><|endoftext|>


<commit_before><commit_msg>Update net.cpp<commit_after><|endoftext|>


<commit_before>/*
 * File:   Test
 * Author: Joshua Johannson
 *
 */

#include <gtest/gtest.h>
#include "TestHelper.hpp"
#include <api/ApiJsonObject.h>

class  MyObject : public ApiJsonObject
{
  public:
    int i = 10;
    string s = "";
    bool b = false;

    void params() override {JsonObject::params();
      param("i", i);
      param("s", s);
      param("b", b);
    }
};

TEST(JsonObjectTest, fromToJson)
{
  Json valIn{
      {"i", 20},
      {"s", "string"},
      {"b", true},
      {"dontHave", "error"}
  };

  Json valOut{
      {"i", 20},
      {"s", "string"},
      {"b", true},
  };

  MyObject myObject;
  myObject.fromJson(valIn);

  EXPECT_EQ(20, myObject.i);
  EXPECT_EQ("string", myObject.s);
  EXPECT_EQ(true, myObject.b);
  EXPECT_EQ(valOut, myObject.toJson());
}

TEST(JsonObjectTest, saveLoad)
{
  Json val{
      {"i", 20},
      {"s", "string"},
      {"b", true}
  };

  MyObject myObject;
  myObject.fromJson(val);
  myObject.save("../test/", "testJsonObject.json");
  cout << "save finish" << endl;

  MyObject myObjectNew;

  cout << "now load" << endl;
  myObjectNew.load("../test/", "testJsonObject.json");

  EXPECT_EQ(20, myObjectNew.i);
  EXPECT_EQ("string", myObjectNew.s);
  EXPECT_EQ(true, myObjectNew.b);
  EXPECT_TRUE(testCompareJson(val, myObjectNew.toJson()));
}

TEST(JsonObjectTest, exceptions)
{
  Json val{
      {"i", false},
      {"s", 100},
      {"b", true}
  };

  MyObject myObject;

  try
  {
    myObject = val;
    cout << myObject.toJson().dump(2) << endl;
    //FAIL();
  } catch (exception &e) {
    SUCCEED();
  }
}

class SimpleObj: public ApiJsonObject{
  public:
    float from;
    float to;
    int id;
    string name = "--";
    vector<int> vec;
    vector<SimpleObj> objVec;

    SimpleObj(){
      cout << endl << "[SimpleObj] '"<< name <<"' create" << endl;

      cout << "pointer from: " << static_cast<void*>(&from) << endl;
      cout << "pointer name: " << static_cast<void*>(&name) << endl;
    }

    void params() override
    {
      JsonObject::params();
      cout << "[SimpleObj] defineParams() " << endl;

      param("from", from);
      param("to", to);
      param("id", id);
      param("name", name);
      param("vec", vec);
      param("objVec", objVec);
    }
};

class As {
  public:
    string name = "--";
    As(string name) {
      this->name = name;
      cout << "Constructor " << name << endl;
    }
    As(const As& old) {
      cout << "Copy "<< name << "  other: " << old.name << endl;
      //*this = old;
    }

    As& operator=(As const &r) {
      cout << "Copy assign "<< name << "  other: " << r.name << endl;
      //*this = r;
      return *this;
    }

    ~As() {
      cout << "delete "<< name << endl;
    }
};

TEST(JsonObjectTest, simpleJsonObject)
{
  {
    As a("a");
    As b("b");
    b = a;
    cout << "Name: " << b.name << endl;
    As c = a;
  }

  Json json{
      {"from", 1.0},
      {"to", 4.0},
      {"id",2},
      {"name", "outer"},
      {"vec", {1,2,3,4}},
      {"objVec", {{
          {"from", 99.0},
          {"to", 999.0},
          {"id",222},
          {"name", "inner"},
          {"vec", {122,222,322,422}},
          {"objVec", Json::array()}
      }}
      }
  };

  SimpleObj obj;
  obj.params();
  obj.name = "OLD";

  cout << endl << "======= fromJson ==" << endl;
  obj = json;

  //vector<string> a;
  //a = json.get<vector<string>>();

  cout << endl << "======= toJson ==" << endl;
  cout << "from: " << obj.from << " name:" << obj.name << endl;

  Json out = obj;
  EXPECT_TRUE(testCompareJson(json, out));
  cout << "Json: " << out.dump(2) << endl;
}

TEST(JsonObjectTest, notifyParamsChanged)
{
    // check send package queue
    EXPECT_EQ(0, Frontend::requestsToSend.size());

    MyObject obj;
    obj.setStorePath("../test/jsonObjectTest");
    obj.processApi(ApiRequest("", "subscribe"));

    obj.s = "test";
    obj.i = 12345;
    obj.notifyParamsChanged({"i", "s", "not-a-param"});

    // check send package queue
    EXPECT_TRUE(1 <= Frontend::requestsToSend.size());
    EXPECT_TRUE(testCompareJson(
            ApiRequest("", "update", Json{
                    {"s", "test"},
                    {"i", 12345}
            }).toJson(),
            Frontend::requestsToSend.back().second.toJson()));
}
<commit_msg>trainServer: api: add tests for paramWithFunction<commit_after>/*
 * File:   Test
 * Author: Joshua Johannson
 *
 */

#include <gtest/gtest.h>
#include "TestHelper.hpp"
#include <api/ApiJsonObject.h>

class  MyObject : public ApiJsonObject
{
  public:
    int i = 10;
    string s = "";
    bool b = false;

    void params() override {JsonObject::params();
      param("i", i);
      param("s", s);
      param("b", b);
    }
};

TEST(JsonObjectTest, fromToJson)
{
  Json valIn{
      {"i", 20},
      {"s", "string"},
      {"b", true},
      {"dontHave", "error"}
  };

  Json valOut{
      {"i", 20},
      {"s", "string"},
      {"b", true},
  };

  MyObject myObject;
  myObject.fromJson(valIn);

  EXPECT_EQ(20, myObject.i);
  EXPECT_EQ("string", myObject.s);
  EXPECT_EQ(true, myObject.b);
  EXPECT_EQ(valOut, myObject.toJson());
}

TEST(JsonObjectTest, saveLoad)
{
  Json val{
      {"i", 20},
      {"s", "string"},
      {"b", true}
  };

  MyObject myObject;
  myObject.fromJson(val);
  myObject.save("../test/", "testJsonObject.json");
  cout << "save finish" << endl;

  MyObject myObjectNew;

  cout << "now load" << endl;
  myObjectNew.load("../test/", "testJsonObject.json");

  EXPECT_EQ(20, myObjectNew.i);
  EXPECT_EQ("string", myObjectNew.s);
  EXPECT_EQ(true, myObjectNew.b);
  EXPECT_TRUE(testCompareJson(val, myObjectNew.toJson()));
}

TEST(JsonObjectTest, exceptions)
{
  Json val{
      {"i", false},
      {"s", 100},
      {"b", true}
  };

  MyObject myObject;

  try
  {
    myObject = val;
    cout << myObject.toJson().dump(2) << endl;
    //FAIL();
  } catch (exception &e) {
    SUCCEED();
  }
}

class SimpleObj: public ApiJsonObject{
  public:
    float from;
    float to;
    int id;
    string name = "--";
    vector<int> vec;
    vector<SimpleObj> objVec;

    SimpleObj(){
      cout << endl << "[SimpleObj] '"<< name <<"' create" << endl;

      cout << "pointer from: " << static_cast<void*>(&from) << endl;
      cout << "pointer name: " << static_cast<void*>(&name) << endl;
    }

    void params() override
    {
      JsonObject::params();
      cout << "[SimpleObj] defineParams() " << endl;

      param("from", from);
      param("to", to);
      param("id", id);
      param("name", name);
      param("vec", vec);
      param("objVec", objVec);
    }
};

class As {
  public:
    string name = "--";
    As(string name) {
      this->name = name;
      cout << "Constructor " << name << endl;
    }
    As(const As& old) {
      cout << "Copy "<< name << "  other: " << old.name << endl;
      //*this = old;
    }

    As& operator=(As const &r) {
      cout << "Copy assign "<< name << "  other: " << r.name << endl;
      //*this = r;
      return *this;
    }

    ~As() {
      cout << "delete "<< name << endl;
    }
};

TEST(JsonObjectTest, simpleJsonObject)
{
  {
    As a("a");
    As b("b");
    b = a;
    cout << "Name: " << b.name << endl;
    As c = a;
  }

  Json json{
      {"from", 1.0},
      {"to", 4.0},
      {"id",2},
      {"name", "outer"},
      {"vec", {1,2,3,4}},
      {"objVec", {{
          {"from", 99.0},
          {"to", 999.0},
          {"id",222},
          {"name", "inner"},
          {"vec", {122,222,322,422}},
          {"objVec", Json::array()}
      }}
      }
  };

  SimpleObj obj;
  obj.params();
  obj.name = "OLD";

  cout << endl << "======= fromJson ==" << endl;
  obj = json;

  //vector<string> a;
  //a = json.get<vector<string>>();

  cout << endl << "======= toJson ==" << endl;
  cout << "from: " << obj.from << " name:" << obj.name << endl;

  Json out = obj;
  EXPECT_TRUE(testCompareJson(json, out));
  cout << "Json: " << out.dump(2) << endl;
}

TEST(JsonObjectTest, notifyParamsChanged)
{
    // check send package queue
    EXPECT_EQ(0, Frontend::requestsToSend.size());

    MyObject obj;
    obj.setStorePath("../test/jsonObjectTest");
    obj.processApi(ApiRequest("", "subscribe"));

    obj.s = "test";
    obj.i = 12345;
    obj.notifyParamsChanged({"i", "s", "not-a-param"});

    // check send package queue
    EXPECT_TRUE(1 <= Frontend::requestsToSend.size());
    EXPECT_TRUE(testCompareJson(
            ApiRequest("", "update", Json{
                    {"s", "test"},
                    {"i", 12345}
            }).toJson(),
            Frontend::requestsToSend.back().second.toJson()));
}

class ObjWithFunction: public JsonObject {
  public:
    string text;
    map<int, string> idMap; //@TODO somehow map<K, V> can only be set if K = string

    void params() override
    { JsonObject::params();
      paramWithFunction("text", [this](Json j) {text = j;}, [](){ return "set from lambda!";});
      paramWithFunction("idMap",
                        [this](Json j) {
                          idMap.clear();
                          for (auto it=j.begin(); it!=j.end(); it++)
                            idMap.insert(make_pair(it.value().begin().value(),
                                                   next(it.value().begin()).value().get<string>()));
                        },
                        [this] () { return idMap;} );
    }
};

TEST(JsonObjectTest, paramWithFunction)
{
  ObjWithFunction objWithFunction;
  Json setJ{
      {"text", "hello"},
      {"idMap", {
          {1, "first"},
          {2, "second"},
      }}
  };
  /*
   * setJ =
   * {
   *   "text": "hello",
   *   "idMap": [
   *     [
   *       1,
   *       "first"
   *     ],
   *     [
   *       2,
   *       "second"
   *     ]
   *   ],
   * }
   */
  objWithFunction = setJ;

  map<int, string> idMap = {
      {1, "first"},
      {2, "second"}
  };
  EXPECT_EQ("hello", objWithFunction.text);
  EXPECT_EQ(idMap, objWithFunction.idMap);
  EXPECT_TRUE(testCompareJson(
      Json{
          {"text", "set from lambda!"},
          {"idMap", {
              {1, "first"},
              {2, "second"},
          }}
      }, objWithFunction.toJson()));
}<|endoftext|>


<commit_before><commit_msg>AutoFill: For now only import data from the uploaded form.<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/autofill/autofill_metrics.h"

#include "base/metrics/histogram.h"

AutofillMetrics::AutofillMetrics() {
}

AutofillMetrics::~AutofillMetrics() {
}

void AutofillMetrics::Log(CreditCardInfoBarMetric metric) const {
  DCHECK(metric < NUM_CREDIT_CARD_INFO_BAR_METRICS);

  UMA_HISTOGRAM_ENUMERATION("Autofill.CreditCardInfoBar", metric,
                            NUM_CREDIT_CARD_INFO_BAR_METRICS);
}

void AutofillMetrics::Log(ServerQueryMetric metric) const {
  DCHECK(metric < NUM_SERVER_QUERY_METRICS);

  UMA_HISTOGRAM_ENUMERATION("Autofill.ServerQueryResponse", metric,
                            NUM_SERVER_QUERY_METRICS);
}

void AutofillMetrics::Log(QualityMetric metric,
                          const std::string& experiment_id) const {
  DCHECK(metric < NUM_QUALITY_METRICS);

  std::string histogram_name = "Autofill.Quality";
  if (!experiment_id.empty())
    histogram_name += "_" + experiment_id;

  UMA_HISTOGRAM_ENUMERATION(histogram_name, metric, NUM_QUALITY_METRICS);
}

void AutofillMetrics::LogStoredProfileCount(size_t num_profiles) const {
  UMA_HISTOGRAM_COUNTS("Autofill.StoredProfileCount", num_profiles);
}

void AutofillMetrics::LogAddressSuggestionsCount(size_t num_suggestions) const {
  printf("LogAddressSuggestionsCount(%d)\n", (int)num_suggestions);
  UMA_HISTOGRAM_COUNTS("Autofill.AddressSuggestionsCount", num_suggestions);
}

<commit_msg>Remove a stray debugging printf<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/autofill/autofill_metrics.h"

#include "base/metrics/histogram.h"

AutofillMetrics::AutofillMetrics() {
}

AutofillMetrics::~AutofillMetrics() {
}

void AutofillMetrics::Log(CreditCardInfoBarMetric metric) const {
  DCHECK(metric < NUM_CREDIT_CARD_INFO_BAR_METRICS);

  UMA_HISTOGRAM_ENUMERATION("Autofill.CreditCardInfoBar", metric,
                            NUM_CREDIT_CARD_INFO_BAR_METRICS);
}

void AutofillMetrics::Log(ServerQueryMetric metric) const {
  DCHECK(metric < NUM_SERVER_QUERY_METRICS);

  UMA_HISTOGRAM_ENUMERATION("Autofill.ServerQueryResponse", metric,
                            NUM_SERVER_QUERY_METRICS);
}

void AutofillMetrics::Log(QualityMetric metric,
                          const std::string& experiment_id) const {
  DCHECK(metric < NUM_QUALITY_METRICS);

  std::string histogram_name = "Autofill.Quality";
  if (!experiment_id.empty())
    histogram_name += "_" + experiment_id;

  UMA_HISTOGRAM_ENUMERATION(histogram_name, metric, NUM_QUALITY_METRICS);
}

void AutofillMetrics::LogStoredProfileCount(size_t num_profiles) const {
  UMA_HISTOGRAM_COUNTS("Autofill.StoredProfileCount", num_profiles);
}

void AutofillMetrics::LogAddressSuggestionsCount(size_t num_suggestions) const {
  UMA_HISTOGRAM_COUNTS("Autofill.AddressSuggestionsCount", num_suggestions);
}

<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/external_protocol_handler.h"

#if defined(OS_WIN)
#include <windows.h>
#include <shellapi.h>
#endif

#include <set>

#include "base/logging.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_process_impl.h"
#include "chrome/common/pref_service.h"
#include "chrome/common/pref_names.h"
#include "googleurl/src/gurl.h"
#include "net/base/escape.h"

#if defined(OS_WIN)
#include "base/registry.h"
#include "chrome/browser/views/external_protocol_dialog.h"
#endif

// static
void ExternalProtocolHandler::PrepopulateDictionary(DictionaryValue* win_pref) {
  static bool is_warm = false;
  if (is_warm)
    return;
  is_warm = true;

  static const wchar_t* const denied_schemes[] = {
    L"afp",
    L"data",
    L"disk",
    L"disks",
    // ShellExecuting file:///C:/WINDOWS/system32/notepad.exe will simply
    // execute the file specified!  Hopefully we won't see any "file" schemes
    // because we think of file:// URLs as handled URLs, but better to be safe
    // than to let an attacker format the user's hard drive.
    L"file",
    L"hcp",
    L"javascript",
    L"ms-help",
    L"nntp",
    L"shell",
    L"vbscript",
    // view-source is a special case in chrome. When it comes through an
    // iframe or a redirect, it looks like an external protocol, but we don't
    // want to shellexecute it.
    L"view-source",
    L"vnd.ms.radio",
  };

  static const wchar_t* const allowed_schemes[] = {
    L"mailto",
    L"news",
    L"snews",
  };

  bool should_block;
  for (size_t i = 0; i < arraysize(denied_schemes); ++i) {
    if (!win_pref->GetBoolean(denied_schemes[i], &should_block)) {
      win_pref->SetBoolean(denied_schemes[i], true);
    }
  }

  for (size_t i = 0; i < arraysize(allowed_schemes); ++i) {
    if (!win_pref->GetBoolean(allowed_schemes[i], &should_block)) {
      win_pref->SetBoolean(allowed_schemes[i], false);
    }
  }
}

// static
ExternalProtocolHandler::BlockState ExternalProtocolHandler::GetBlockState(
    const std::wstring& scheme) {
  if (scheme.length() == 1) {
    // We have a URL that looks something like:
    //   C:/WINDOWS/system32/notepad.exe
    // ShellExecuting this URL will cause the specified program to be executed.
    return BLOCK;
  }

  // Check the stored prefs.
  // TODO(pkasting): http://b/119651 This kind of thing should go in the
  // preferences on the profile, not in the local state.
  PrefService* pref = g_browser_process->local_state();
  if (pref) {  // May be NULL during testing.
    DictionaryValue* win_pref =
        pref->GetMutableDictionary(prefs::kExcludedSchemes);
    CHECK(win_pref);

    // Warm up the dictionary if needed.
    PrepopulateDictionary(win_pref);

    bool should_block;
    if (win_pref->GetBoolean(scheme, &should_block))
      return should_block ? BLOCK : DONT_BLOCK;
  }

  return UNKNOWN;
}

// static
void ExternalProtocolHandler::LaunchUrl(const GURL& url,
                                        int render_process_host_id,
                                        int tab_contents_id) {
#if defined(OS_WIN)
  // Escape the input scheme to be sure that the command does not
  // have parameters unexpected by the external program.
  std::string escaped_url_string = EscapeExternalHandlerValue(url.spec());
  GURL escaped_url(escaped_url_string);
  BlockState block_state = GetBlockState(ASCIIToWide(escaped_url.scheme()));
  if (block_state == BLOCK)
    return;

  if (block_state == UNKNOWN) {
    std::wstring command = ExternalProtocolDialog::GetApplicationForProtocol(
                               escaped_url);
    if (command.empty()) {
      // ShellExecute won't do anything. Don't bother warning the user.
      return;
    }

    // Ask the user if they want to allow the protocol. This will call
    // LaunchUrlWithoutSecurityCheck if the user decides to accept the protocol.
    ExternalProtocolDialog::RunExternalProtocolDialog(escaped_url,
                                                      command,
                                                      render_process_host_id,
                                                      tab_contents_id);
    return;
  }

  // Put this work on the file thread since ShellExecute may block for a
  // significant amount of time.
  MessageLoop* loop = g_browser_process->file_thread()->message_loop();
  if (loop == NULL) {
    return;
  }

  // Otherwise the protocol is white-listed, so go ahead and launch.
  loop->PostTask(FROM_HERE,
      NewRunnableFunction(
          &ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck,
          escaped_url));
#elif defined(OS_POSIX)
  // TODO(port): Implement launching external handler.
  NOTIMPLEMENTED();
#endif
}

// static
void ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(const GURL& url) {
#if defined(OS_WIN)
  // Quote the input scheme to be sure that the command does not have
  // parameters unexpected by the external program. This url should already
  // have been escaped.
  std::string escaped_url = url.spec();
  escaped_url.insert(0, "\"");
  escaped_url += "\"";

  // According to Mozilla in uriloader/exthandler/win/nsOSHelperAppService.cpp:
  // "Some versions of windows (Win2k before SP3, Win XP before SP1) crash in
  // ShellExecute on long URLs (bug 161357 on bugzilla.mozilla.org). IE 5 and 6
  // support URLS of 2083 chars in length, 2K is safe."
  const size_t kMaxUrlLength = 2048;
  if (escaped_url.length() > kMaxUrlLength) {
    NOTREACHED();
    return;
  }

  RegKey key;
  std::wstring registry_path = ASCIIToWide(url.scheme()) +
                               L"\\shell\\open\\command";
  key.Open(HKEY_CLASSES_ROOT, registry_path.c_str());
  if (key.Valid()) {
    DWORD size = 0;
    key.ReadValue(NULL, NULL, &size);
    if (size <= 2) {
      // ShellExecute crashes the process when the command is empty.
      // We check for "2" because it always returns the trailing NULL.
      // TODO(nsylvain): we should also add a dialog to warn on errors. See
      // bug 1136923.
      return;
    }
  }

  if (reinterpret_cast<ULONG_PTR>(ShellExecuteA(NULL, "open",
                                                escaped_url.c_str(), NULL, NULL,
                                                SW_SHOWNORMAL)) <= 32) {
    // We fail to execute the call. We could display a message to the user.
    // TODO(nsylvain): we should also add a dialog to warn on errors. See
    // bug 1136923.
    return;
  }
#elif defined(OS_POSIX)
  // TODO(port): Implement launching external handler.
  NOTIMPLEMENTED();
#endif
}

// static
void ExternalProtocolHandler::RegisterPrefs(PrefService* prefs) {
  prefs->RegisterDictionaryPref(prefs::kExcludedSchemes);
}
<commit_msg>Allow external whitelisted protocols on the Mac.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/external_protocol_handler.h"

#if defined(OS_WIN)
#include <windows.h>
#include <shellapi.h>
#endif

#include <set>

#include "base/logging.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_process_impl.h"
#include "chrome/common/pref_service.h"
#include "chrome/common/pref_names.h"
#include "googleurl/src/gurl.h"
#include "net/base/escape.h"

#if defined(OS_WIN)
#include "base/registry.h"
#include "chrome/browser/views/external_protocol_dialog.h"
#elif defined(OS_MACOSX)
#include <ApplicationServices/ApplicationServices.h>
#include "base/scoped_cftyperef.h"
#include "base/sys_string_conversions.h"
#endif

// static
void ExternalProtocolHandler::PrepopulateDictionary(DictionaryValue* win_pref) {
  static bool is_warm = false;
  if (is_warm)
    return;
  is_warm = true;

  static const wchar_t* const denied_schemes[] = {
    L"afp",
    L"data",
    L"disk",
    L"disks",
    // ShellExecuting file:///C:/WINDOWS/system32/notepad.exe will simply
    // execute the file specified!  Hopefully we won't see any "file" schemes
    // because we think of file:// URLs as handled URLs, but better to be safe
    // than to let an attacker format the user's hard drive.
    L"file",
    L"hcp",
    L"javascript",
    L"ms-help",
    L"nntp",
    L"shell",
    L"vbscript",
    // view-source is a special case in chrome. When it comes through an
    // iframe or a redirect, it looks like an external protocol, but we don't
    // want to shellexecute it.
    L"view-source",
    L"vnd.ms.radio",
  };

  static const wchar_t* const allowed_schemes[] = {
    L"mailto",
    L"news",
    L"snews",
  };

  bool should_block;
  for (size_t i = 0; i < arraysize(denied_schemes); ++i) {
    if (!win_pref->GetBoolean(denied_schemes[i], &should_block)) {
      win_pref->SetBoolean(denied_schemes[i], true);
    }
  }

  for (size_t i = 0; i < arraysize(allowed_schemes); ++i) {
    if (!win_pref->GetBoolean(allowed_schemes[i], &should_block)) {
      win_pref->SetBoolean(allowed_schemes[i], false);
    }
  }
}

// static
ExternalProtocolHandler::BlockState ExternalProtocolHandler::GetBlockState(
    const std::wstring& scheme) {
  if (scheme.length() == 1) {
    // We have a URL that looks something like:
    //   C:/WINDOWS/system32/notepad.exe
    // ShellExecuting this URL will cause the specified program to be executed.
    return BLOCK;
  }

  // Check the stored prefs.
  // TODO(pkasting): http://b/119651 This kind of thing should go in the
  // preferences on the profile, not in the local state.
  PrefService* pref = g_browser_process->local_state();
  if (pref) {  // May be NULL during testing.
    DictionaryValue* win_pref =
        pref->GetMutableDictionary(prefs::kExcludedSchemes);
    CHECK(win_pref);

    // Warm up the dictionary if needed.
    PrepopulateDictionary(win_pref);

    bool should_block;
    if (win_pref->GetBoolean(scheme, &should_block))
      return should_block ? BLOCK : DONT_BLOCK;
  }

  return UNKNOWN;
}

// static
void ExternalProtocolHandler::LaunchUrl(const GURL& url,
                                        int render_process_host_id,
                                        int tab_contents_id) {
#if !defined(OS_LINUX)
  // Escape the input scheme to be sure that the command does not
  // have parameters unexpected by the external program.
  std::string escaped_url_string = EscapeExternalHandlerValue(url.spec());
  GURL escaped_url(escaped_url_string);
  BlockState block_state = GetBlockState(ASCIIToWide(escaped_url.scheme()));
  if (block_state == BLOCK)
    return;

#if defined(OS_WIN)
  if (block_state == UNKNOWN) {
    std::wstring command = ExternalProtocolDialog::GetApplicationForProtocol(
                               escaped_url);
    if (command.empty()) {
      // ShellExecute won't do anything. Don't bother warning the user.
      return;
    }

    // Ask the user if they want to allow the protocol. This will call
    // LaunchUrlWithoutSecurityCheck if the user decides to accept the protocol.
    ExternalProtocolDialog::RunExternalProtocolDialog(escaped_url,
                                                      command,
                                                      render_process_host_id,
                                                      tab_contents_id);
    return;
  }
#else
  // For now, allow only whitelisted protocols to fire.
  // TODO(port): implement dialog for Mac
  if (block_state == UNKNOWN)
    return;
#endif

  // Put this work on the file thread since ShellExecute may block for a
  // significant amount of time.
  MessageLoop* loop = g_browser_process->file_thread()->message_loop();
  if (loop == NULL) {
    return;
  }

  // Otherwise the protocol is white-listed, so go ahead and launch.
  loop->PostTask(FROM_HERE,
      NewRunnableFunction(
          &ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck,
          escaped_url));
#else
  // TODO(port): Implement launching external handler.
  NOTIMPLEMENTED();
#endif
}

// static
void ExternalProtocolHandler::LaunchUrlWithoutSecurityCheck(const GURL& url) {
#if defined(OS_WIN)
  // Quote the input scheme to be sure that the command does not have
  // parameters unexpected by the external program. This url should already
  // have been escaped.
  std::string escaped_url = url.spec();
  escaped_url.insert(0, "\"");
  escaped_url += "\"";

  // According to Mozilla in uriloader/exthandler/win/nsOSHelperAppService.cpp:
  // "Some versions of windows (Win2k before SP3, Win XP before SP1) crash in
  // ShellExecute on long URLs (bug 161357 on bugzilla.mozilla.org). IE 5 and 6
  // support URLS of 2083 chars in length, 2K is safe."
  const size_t kMaxUrlLength = 2048;
  if (escaped_url.length() > kMaxUrlLength) {
    NOTREACHED();
    return;
  }

  RegKey key;
  std::wstring registry_path = ASCIIToWide(url.scheme()) +
                               L"\\shell\\open\\command";
  key.Open(HKEY_CLASSES_ROOT, registry_path.c_str());
  if (key.Valid()) {
    DWORD size = 0;
    key.ReadValue(NULL, NULL, &size);
    if (size <= 2) {
      // ShellExecute crashes the process when the command is empty.
      // We check for "2" because it always returns the trailing NULL.
      // TODO(nsylvain): we should also add a dialog to warn on errors. See
      // bug 1136923.
      return;
    }
  }

  if (reinterpret_cast<ULONG_PTR>(ShellExecuteA(NULL, "open",
                                                escaped_url.c_str(), NULL, NULL,
                                                SW_SHOWNORMAL)) <= 32) {
    // We fail to execute the call. We could display a message to the user.
    // TODO(nsylvain): we should also add a dialog to warn on errors. See
    // bug 1136923.
    return;
  }
#elif defined(OS_MACOSX)
  scoped_cftyperef<CFStringRef> string_ref(
      base::SysUTF8ToCFStringRef(url.spec()));
  if (!string_ref)
    return;

  scoped_cftyperef<CFURLRef> url_ref(CFURLCreateWithString(kCFAllocatorDefault,
                                                           string_ref,
                                                           NULL));
  if (!url_ref)
    return;

  LSOpenCFURLRef(url_ref, NULL);
#elif defined(OS_LINUX)
  // TODO(port): Implement launching external handler.
  NOTIMPLEMENTED();
#endif
}

// static
void ExternalProtocolHandler::RegisterPrefs(PrefService* prefs) {
  prefs->RegisterDictionaryPref(prefs::kExcludedSchemes);
}
<|endoftext|>


<commit_before>/* ************************************************************************* */
/* This file is part of Shard.                                               */
/*                                                                           */
/* Shard is free software: you can redistribute it and/or modify             */
/* it under the terms of the GNU Affero General Public License as            */
/* published by the Free Software Foundation.                                */
/*                                                                           */
/* This program 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 Affero General Public License for more details.                       */
/*                                                                           */
/* You should have received a copy of the GNU Affero General Public License  */
/* along with this program. If not, see <http://www.gnu.org/licenses/>.      */
/* ************************************************************************* */

#pragma once

/* ************************************************************************* */

#include <fstream>

// Shard
#include "shard/Path.hpp"
#include "shard/String.hpp"
#include "shard/UniquePtr.hpp"

/* ************************************************************************* */

namespace shard {
inline namespace v1 {
namespace tokenizer {

/* ************************************************************************* */

using ReadMode = char;

class Source
{

protected:

    UniquePtr<std::basic_streambuf<ReadMode>> m_sb;

public:

    /**
     * @brief constructs Source with input from file.
     */
    explicit Source (const Path& path):
            m_sb([](const auto& l_path)
            {
                auto ptr = makeUnique<std::basic_filebuf<ReadMode>>();
                ptr->open(l_path, std::ios_base::in | std::ios_base::binary);
                return ptr;
            }(path)) {}

    /**
     * @brief constructs Source with input from string.
     */
    explicit Source (const String& source):
            m_sb(makeUnique<std::basic_stringbuf<ReadMode>>(source)) {}

/* ************************************************************************* */

public:

    /**
     * @brief returns if input is empty.
     */
    inline bool empty()
    {
        return get() == std::char_traits<ReadMode>::eof();
        //return m_sb->in_avail() <= 0;
    }

    /**
     * @brief read current character.
     */
    inline ReadMode get()
    {
        return static_cast<ReadMode>(m_sb->sgetc());
    }

    /**
     * @brief read current character and move to next.
     */
    inline ReadMode extract()
    {
        return static_cast<ReadMode>(m_sb->sbumpc());
    }

    /**
     * @brief move to next character and read it.
     */
    inline ReadMode getNext()
    {
        return static_cast<ReadMode>(m_sb->snextc());
    }
};

/* ************************************************************************* */

}
}
}

/* ************************************************************************* */
<commit_msg>added function unget to source<commit_after>/* ************************************************************************* */
/* This file is part of Shard.                                               */
/*                                                                           */
/* Shard is free software: you can redistribute it and/or modify             */
/* it under the terms of the GNU Affero General Public License as            */
/* published by the Free Software Foundation.                                */
/*                                                                           */
/* This program 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 Affero General Public License for more details.                       */
/*                                                                           */
/* You should have received a copy of the GNU Affero General Public License  */
/* along with this program. If not, see <http://www.gnu.org/licenses/>.      */
/* ************************************************************************* */

#pragma once

/* ************************************************************************* */

#include <fstream>

// Shard
#include "shard/Path.hpp"
#include "shard/String.hpp"
#include "shard/UniquePtr.hpp"

/* ************************************************************************* */

namespace shard {
inline namespace v1 {
namespace tokenizer {

/* ************************************************************************* */

using ReadMode = char;

class Source
{

protected:

    UniquePtr<std::basic_streambuf<ReadMode>> m_sb;

public:

    /**
     * @brief constructs Source with input from file.
     */
    explicit Source (const Path& path):
            m_sb([](const auto& l_path)
            {
                auto ptr = makeUnique<std::basic_filebuf<ReadMode>>();
                ptr->open(l_path, std::ios_base::in | std::ios_base::binary);
                return ptr;
            }(path)) {}

    /**
     * @brief constructs Source with input from string.
     */
    explicit Source (const String& source):
            m_sb(makeUnique<std::basic_stringbuf<ReadMode>>(source)) {}

/* ************************************************************************* */

public:

    /**
     * @brief returns if input is empty.
     */
    inline bool empty()
    {
        return get() == std::char_traits<ReadMode>::eof();
        //return m_sb->in_avail() <= 0;
    }

    /**
     * @brief read current character.
     */
    inline ReadMode get()
    {
        return static_cast<ReadMode>(m_sb->sgetc());
    }

    /**
     * @brief read current character and move to next.
     */
    inline ReadMode extract()
    {
        return static_cast<ReadMode>(m_sb->sbumpc());
    }

    /**
     * @brief move to next character and read it.
     */
    inline ReadMode getNext()
    {
        return static_cast<ReadMode>(m_sb->snextc());
    }

    /**
     * @brief return to previous character and read it.
     */
    inline ReadMode unget()
    {
        return static_cast<ReadMode>(m_sb->sungetc());
    }
};

/* ************************************************************************* */

}
}
}

/* ************************************************************************* */
<|endoftext|>


<commit_before><commit_msg>Make sure that the sync backend host doesn't exist in a post-shutdown state, and make sure the preference is cleared before shutting down the backend.<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2018 The Khronos Group Inc.
// Copyright (c) 2018 Valve Corporation
// Copyright (c) 2018 LunarG Inc.
//
// 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.

#ifndef INCLUDE_SPIRV_TOOLS_INSTRUMENT_HPP_
#define INCLUDE_SPIRV_TOOLS_INSTRUMENT_HPP_

// Shader Instrumentation Interface
//
// This file provides an external interface for applications that wish to
// communicate with shaders instrumented by passes created by:
//
//   CreateInstBindlessCheckPass
//   CreateInstBuffAddrCheckPass
//   CreateInstDebugPrintfPass
//
// More detailed documentation of these routines can be found in optimizer.hpp

namespace spvtools {

// Stream Output Buffer Offsets
//
// The following values provide offsets into the output buffer struct
// generated by InstrumentPass::GenDebugStreamWrite. This method is utilized
// by InstBindlessCheckPass, InstBuffAddrCheckPass, and InstDebugPrintfPass.
//
// The first member of the debug output buffer contains the next available word
// in the data stream to be written. Shaders will atomically read and update
// this value so as not to overwrite each others records. This value must be
// initialized to zero
static const int kDebugOutputSizeOffset = 0;

// The second member of the output buffer is the start of the stream of records
// written by the instrumented shaders. Each record represents a validation
// error. The format of the records is documented below.
static const int kDebugOutputDataOffset = 1;

// Common Stream Record Offsets
//
// The following are offsets to fields which are common to all records written
// to the output stream.
//
// Each record first contains the size of the record in 32-bit words, including
// the size word.
static const int kInstCommonOutSize = 0;

// This is the shader id passed by the layer when the instrumentation pass is
// created.
static const int kInstCommonOutShaderId = 1;

// This is the ordinal position of the instruction within the SPIR-V shader
// which generated the validation error.
static const int kInstCommonOutInstructionIdx = 2;

// This is the stage which generated the validation error. This word is used
// to determine the contents of the next two words in the record.
// 0:Vert, 1:TessCtrl, 2:TessEval, 3:Geom, 4:Frag, 5:Compute
static const int kInstCommonOutStageIdx = 3;
static const int kInstCommonOutCnt = 4;

// Stage-specific Stream Record Offsets
//
// Each stage will contain different values in the next set of words of the
// record used to identify which instantiation of the shader generated the
// validation error.
//
// Vertex Shader Output Record Offsets
static const int kInstVertOutVertexIndex = kInstCommonOutCnt;
static const int kInstVertOutInstanceIndex = kInstCommonOutCnt + 1;
static const int kInstVertOutUnused = kInstCommonOutCnt + 2;

// Frag Shader Output Record Offsets
static const int kInstFragOutFragCoordX = kInstCommonOutCnt;
static const int kInstFragOutFragCoordY = kInstCommonOutCnt + 1;
static const int kInstFragOutUnused = kInstCommonOutCnt + 2;

// Compute Shader Output Record Offsets
static const int kInstCompOutGlobalInvocationIdX = kInstCommonOutCnt;
static const int kInstCompOutGlobalInvocationIdY = kInstCommonOutCnt + 1;
static const int kInstCompOutGlobalInvocationIdZ = kInstCommonOutCnt + 2;

// Tessellation Control Shader Output Record Offsets
static const int kInstTessCtlOutInvocationId = kInstCommonOutCnt;
static const int kInstTessCtlOutPrimitiveId = kInstCommonOutCnt + 1;
static const int kInstTessCtlOutUnused = kInstCommonOutCnt + 2;

// Tessellation Eval Shader Output Record Offsets
static const int kInstTessEvalOutPrimitiveId = kInstCommonOutCnt;
static const int kInstTessEvalOutTessCoordU = kInstCommonOutCnt + 1;
static const int kInstTessEvalOutTessCoordV = kInstCommonOutCnt + 2;

// Geometry Shader Output Record Offsets
static const int kInstGeomOutPrimitiveId = kInstCommonOutCnt;
static const int kInstGeomOutInvocationId = kInstCommonOutCnt + 1;
static const int kInstGeomOutUnused = kInstCommonOutCnt + 2;

// Ray Tracing Shader Output Record Offsets
static const int kInstRayTracingOutLaunchIdX = kInstCommonOutCnt;
static const int kInstRayTracingOutLaunchIdY = kInstCommonOutCnt + 1;
static const int kInstRayTracingOutLaunchIdZ = kInstCommonOutCnt + 2;

// Mesh Shader Output Record Offsets
static const int kInstMeshOutGlobalInvocationIdX = kInstCommonOutCnt;
static const int kInstMeshOutGlobalInvocationIdY = kInstCommonOutCnt + 1;
static const int kInstMeshOutGlobalInvocationIdZ = kInstCommonOutCnt + 2;

// Task Shader Output Record Offsets
static const int kInstTaskOutGlobalInvocationIdX = kInstCommonOutCnt;
static const int kInstTaskOutGlobalInvocationIdY = kInstCommonOutCnt + 1;
static const int kInstTaskOutGlobalInvocationIdZ = kInstCommonOutCnt + 2;

// Size of Common and Stage-specific Members
static const int kInstStageOutCnt = kInstCommonOutCnt + 3;

// Validation Error Code Offset
//
// This identifies the validation error. It also helps to identify
// how many words follow in the record and their meaning.
static const int kInstValidationOutError = kInstStageOutCnt;

// Validation-specific Output Record Offsets
//
// Each different validation will generate a potentially different
// number of words at the end of the record giving more specifics
// about the validation error.
//
// A bindless bounds error will output the index and the bound.
static const int kInstBindlessBoundsOutDescIndex = kInstStageOutCnt + 1;
static const int kInstBindlessBoundsOutDescBound = kInstStageOutCnt + 2;
static const int kInstBindlessBoundsOutUnused = kInstStageOutCnt + 3;
static const int kInstBindlessBoundsOutCnt = kInstStageOutCnt + 4;

// A descriptor uninitialized error will output the index.
static const int kInstBindlessUninitOutDescIndex = kInstStageOutCnt + 1;
static const int kInstBindlessUninitOutUnused = kInstStageOutCnt + 2;
static const int kInstBindlessUninitOutUnused2 = kInstStageOutCnt + 3;
static const int kInstBindlessUninitOutCnt = kInstStageOutCnt + 4;

// A buffer out-of-bounds error will output the descriptor
// index, the buffer offset and the buffer size
static const int kInstBindlessBuffOOBOutDescIndex = kInstStageOutCnt + 1;
static const int kInstBindlessBuffOOBOutBuffOff = kInstStageOutCnt + 2;
static const int kInstBindlessBuffOOBOutBuffSize = kInstStageOutCnt + 3;
static const int kInstBindlessBuffOOBOutCnt = kInstStageOutCnt + 4;

// A buffer address unalloc error will output the 64-bit pointer in
// two 32-bit pieces, lower bits first.
static const int kInstBuffAddrUnallocOutDescPtrLo = kInstStageOutCnt + 1;
static const int kInstBuffAddrUnallocOutDescPtrHi = kInstStageOutCnt + 2;
static const int kInstBuffAddrUnallocOutCnt = kInstStageOutCnt + 3;

// Maximum Output Record Member Count
static const int kInstMaxOutCnt = kInstStageOutCnt + 4;

// Validation Error Codes
//
// These are the possible validation error codes.
static const int kInstErrorBindlessBounds = 0;
static const int kInstErrorBindlessUninit = 1;
static const int kInstErrorBuffAddrUnallocRef = 2;
// Deleted: static const int kInstErrorBindlessBuffOOB = 3;
// This comment will will remain for 2 releases to allow
// for the transition of all builds. Buffer OOB is
// generating the following four differentiated codes instead:
static const int kInstErrorBuffOOBUniform = 4;
static const int kInstErrorBuffOOBStorage = 5;
static const int kInstErrorBuffOOBUniformTexel = 6;
static const int kInstErrorBuffOOBStorageTexel = 7;

// Direct Input Buffer Offsets
//
// The following values provide member offsets into the input buffers
// consumed by InstrumentPass::GenDebugDirectRead(). This method is utilized
// by InstBindlessCheckPass.
//
// The only object in an input buffer is a runtime array of unsigned
// integers. Each validation will have its own formatting of this array.
static const int kDebugInputDataOffset = 0;

// Debug Buffer Bindings
//
// These are the bindings for the different buffers which are
// read or written by the instrumentation passes.
//
// This is the output buffer written by InstBindlessCheckPass,
// InstBuffAddrCheckPass, and possibly other future validations.
static const int kDebugOutputBindingStream = 0;

// The binding for the input buffer read by InstBindlessCheckPass.
static const int kDebugInputBindingBindless = 1;

// The binding for the input buffer read by InstBuffAddrCheckPass.
static const int kDebugInputBindingBuffAddr = 2;

// This is the output buffer written by InstDebugPrintfPass.
static const int kDebugOutputPrintfStream = 3;

// Bindless Validation Input Buffer Format
//
// An input buffer for bindless validation consists of a single array of
// unsigned integers we will call Data[]. This array is formatted as follows.
//
// At offset kDebugInputBindlessInitOffset in Data[] is a single uint which
// gives an offset to the start of the bindless initialization data. More
// specifically, if the following value is zero, we know that the descriptor at
// (set = s, binding = b, index = i) is not initialized; if the value is
// non-zero, and the descriptor points to a buffer, the value is the length of
// the buffer in bytes and can be used to check for out-of-bounds buffer
// references:
// Data[ i + Data[ b + Data[ s + Data[ kDebugInputBindlessInitOffset ] ] ] ]
static const int kDebugInputBindlessInitOffset = 0;

// At offset kDebugInputBindlessOffsetLengths is some number of uints which
// provide the bindless length data. More specifically, the number of
// descriptors at (set=s, binding=b) is:
// Data[ Data[ s + kDebugInputBindlessOffsetLengths ] + b ]
static const int kDebugInputBindlessOffsetLengths = 1;

// Buffer Device Address Input Buffer Format
//
// An input buffer for buffer device address validation consists of a single
// array of unsigned 64-bit integers we will call Data[]. This array is
// formatted as follows:
//
// At offset kDebugInputBuffAddrPtrOffset is a list of sorted valid buffer
// addresses. The list is terminated with the address 0xffffffffffffffff.
// If 0x0 is not a valid buffer address, this address is inserted at the
// start of the list.
//
static const int kDebugInputBuffAddrPtrOffset = 1;
//
// At offset kDebugInputBuffAddrLengthOffset in Data[] is a single uint64 which
// gives an offset to the start of the buffer length data. More
// specifically, for a buffer whose pointer is located at input buffer offset
// i, the length is located at:
//
// Data[ i - kDebugInputBuffAddrPtrOffset
//         + Data[ kDebugInputBuffAddrLengthOffset ] ]
//
// The length associated with the 0xffffffffffffffff address is zero. If
// not a valid buffer, the length associated with the 0x0 address is zero.
static const int kDebugInputBuffAddrLengthOffset = 0;

}  // namespace spvtools

#endif  // INCLUDE_SPIRV_TOOLS_INSTRUMENT_HPP_
<commit_msg>Add kInstErrorMax to instrument.hpp (#4315)<commit_after>// Copyright (c) 2018 The Khronos Group Inc.
// Copyright (c) 2018 Valve Corporation
// Copyright (c) 2018 LunarG Inc.
//
// 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.

#ifndef INCLUDE_SPIRV_TOOLS_INSTRUMENT_HPP_
#define INCLUDE_SPIRV_TOOLS_INSTRUMENT_HPP_

// Shader Instrumentation Interface
//
// This file provides an external interface for applications that wish to
// communicate with shaders instrumented by passes created by:
//
//   CreateInstBindlessCheckPass
//   CreateInstBuffAddrCheckPass
//   CreateInstDebugPrintfPass
//
// More detailed documentation of these routines can be found in optimizer.hpp

namespace spvtools {

// Stream Output Buffer Offsets
//
// The following values provide offsets into the output buffer struct
// generated by InstrumentPass::GenDebugStreamWrite. This method is utilized
// by InstBindlessCheckPass, InstBuffAddrCheckPass, and InstDebugPrintfPass.
//
// The first member of the debug output buffer contains the next available word
// in the data stream to be written. Shaders will atomically read and update
// this value so as not to overwrite each others records. This value must be
// initialized to zero
static const int kDebugOutputSizeOffset = 0;

// The second member of the output buffer is the start of the stream of records
// written by the instrumented shaders. Each record represents a validation
// error. The format of the records is documented below.
static const int kDebugOutputDataOffset = 1;

// Common Stream Record Offsets
//
// The following are offsets to fields which are common to all records written
// to the output stream.
//
// Each record first contains the size of the record in 32-bit words, including
// the size word.
static const int kInstCommonOutSize = 0;

// This is the shader id passed by the layer when the instrumentation pass is
// created.
static const int kInstCommonOutShaderId = 1;

// This is the ordinal position of the instruction within the SPIR-V shader
// which generated the validation error.
static const int kInstCommonOutInstructionIdx = 2;

// This is the stage which generated the validation error. This word is used
// to determine the contents of the next two words in the record.
// 0:Vert, 1:TessCtrl, 2:TessEval, 3:Geom, 4:Frag, 5:Compute
static const int kInstCommonOutStageIdx = 3;
static const int kInstCommonOutCnt = 4;

// Stage-specific Stream Record Offsets
//
// Each stage will contain different values in the next set of words of the
// record used to identify which instantiation of the shader generated the
// validation error.
//
// Vertex Shader Output Record Offsets
static const int kInstVertOutVertexIndex = kInstCommonOutCnt;
static const int kInstVertOutInstanceIndex = kInstCommonOutCnt + 1;
static const int kInstVertOutUnused = kInstCommonOutCnt + 2;

// Frag Shader Output Record Offsets
static const int kInstFragOutFragCoordX = kInstCommonOutCnt;
static const int kInstFragOutFragCoordY = kInstCommonOutCnt + 1;
static const int kInstFragOutUnused = kInstCommonOutCnt + 2;

// Compute Shader Output Record Offsets
static const int kInstCompOutGlobalInvocationIdX = kInstCommonOutCnt;
static const int kInstCompOutGlobalInvocationIdY = kInstCommonOutCnt + 1;
static const int kInstCompOutGlobalInvocationIdZ = kInstCommonOutCnt + 2;

// Tessellation Control Shader Output Record Offsets
static const int kInstTessCtlOutInvocationId = kInstCommonOutCnt;
static const int kInstTessCtlOutPrimitiveId = kInstCommonOutCnt + 1;
static const int kInstTessCtlOutUnused = kInstCommonOutCnt + 2;

// Tessellation Eval Shader Output Record Offsets
static const int kInstTessEvalOutPrimitiveId = kInstCommonOutCnt;
static const int kInstTessEvalOutTessCoordU = kInstCommonOutCnt + 1;
static const int kInstTessEvalOutTessCoordV = kInstCommonOutCnt + 2;

// Geometry Shader Output Record Offsets
static const int kInstGeomOutPrimitiveId = kInstCommonOutCnt;
static const int kInstGeomOutInvocationId = kInstCommonOutCnt + 1;
static const int kInstGeomOutUnused = kInstCommonOutCnt + 2;

// Ray Tracing Shader Output Record Offsets
static const int kInstRayTracingOutLaunchIdX = kInstCommonOutCnt;
static const int kInstRayTracingOutLaunchIdY = kInstCommonOutCnt + 1;
static const int kInstRayTracingOutLaunchIdZ = kInstCommonOutCnt + 2;

// Mesh Shader Output Record Offsets
static const int kInstMeshOutGlobalInvocationIdX = kInstCommonOutCnt;
static const int kInstMeshOutGlobalInvocationIdY = kInstCommonOutCnt + 1;
static const int kInstMeshOutGlobalInvocationIdZ = kInstCommonOutCnt + 2;

// Task Shader Output Record Offsets
static const int kInstTaskOutGlobalInvocationIdX = kInstCommonOutCnt;
static const int kInstTaskOutGlobalInvocationIdY = kInstCommonOutCnt + 1;
static const int kInstTaskOutGlobalInvocationIdZ = kInstCommonOutCnt + 2;

// Size of Common and Stage-specific Members
static const int kInstStageOutCnt = kInstCommonOutCnt + 3;

// Validation Error Code Offset
//
// This identifies the validation error. It also helps to identify
// how many words follow in the record and their meaning.
static const int kInstValidationOutError = kInstStageOutCnt;

// Validation-specific Output Record Offsets
//
// Each different validation will generate a potentially different
// number of words at the end of the record giving more specifics
// about the validation error.
//
// A bindless bounds error will output the index and the bound.
static const int kInstBindlessBoundsOutDescIndex = kInstStageOutCnt + 1;
static const int kInstBindlessBoundsOutDescBound = kInstStageOutCnt + 2;
static const int kInstBindlessBoundsOutUnused = kInstStageOutCnt + 3;
static const int kInstBindlessBoundsOutCnt = kInstStageOutCnt + 4;

// A descriptor uninitialized error will output the index.
static const int kInstBindlessUninitOutDescIndex = kInstStageOutCnt + 1;
static const int kInstBindlessUninitOutUnused = kInstStageOutCnt + 2;
static const int kInstBindlessUninitOutUnused2 = kInstStageOutCnt + 3;
static const int kInstBindlessUninitOutCnt = kInstStageOutCnt + 4;

// A buffer out-of-bounds error will output the descriptor
// index, the buffer offset and the buffer size
static const int kInstBindlessBuffOOBOutDescIndex = kInstStageOutCnt + 1;
static const int kInstBindlessBuffOOBOutBuffOff = kInstStageOutCnt + 2;
static const int kInstBindlessBuffOOBOutBuffSize = kInstStageOutCnt + 3;
static const int kInstBindlessBuffOOBOutCnt = kInstStageOutCnt + 4;

// A buffer address unalloc error will output the 64-bit pointer in
// two 32-bit pieces, lower bits first.
static const int kInstBuffAddrUnallocOutDescPtrLo = kInstStageOutCnt + 1;
static const int kInstBuffAddrUnallocOutDescPtrHi = kInstStageOutCnt + 2;
static const int kInstBuffAddrUnallocOutCnt = kInstStageOutCnt + 3;

// Maximum Output Record Member Count
static const int kInstMaxOutCnt = kInstStageOutCnt + 4;

// Validation Error Codes
//
// These are the possible validation error codes.
static const int kInstErrorBindlessBounds = 0;
static const int kInstErrorBindlessUninit = 1;
static const int kInstErrorBuffAddrUnallocRef = 2;
// Deleted: static const int kInstErrorBindlessBuffOOB = 3;
// This comment will will remain for 2 releases to allow
// for the transition of all builds. Buffer OOB is
// generating the following four differentiated codes instead:
static const int kInstErrorBuffOOBUniform = 4;
static const int kInstErrorBuffOOBStorage = 5;
static const int kInstErrorBuffOOBUniformTexel = 6;
static const int kInstErrorBuffOOBStorageTexel = 7;
static const int kInstErrorMax = kInstErrorBuffOOBStorageTexel;

// Direct Input Buffer Offsets
//
// The following values provide member offsets into the input buffers
// consumed by InstrumentPass::GenDebugDirectRead(). This method is utilized
// by InstBindlessCheckPass.
//
// The only object in an input buffer is a runtime array of unsigned
// integers. Each validation will have its own formatting of this array.
static const int kDebugInputDataOffset = 0;

// Debug Buffer Bindings
//
// These are the bindings for the different buffers which are
// read or written by the instrumentation passes.
//
// This is the output buffer written by InstBindlessCheckPass,
// InstBuffAddrCheckPass, and possibly other future validations.
static const int kDebugOutputBindingStream = 0;

// The binding for the input buffer read by InstBindlessCheckPass.
static const int kDebugInputBindingBindless = 1;

// The binding for the input buffer read by InstBuffAddrCheckPass.
static const int kDebugInputBindingBuffAddr = 2;

// This is the output buffer written by InstDebugPrintfPass.
static const int kDebugOutputPrintfStream = 3;

// Bindless Validation Input Buffer Format
//
// An input buffer for bindless validation consists of a single array of
// unsigned integers we will call Data[]. This array is formatted as follows.
//
// At offset kDebugInputBindlessInitOffset in Data[] is a single uint which
// gives an offset to the start of the bindless initialization data. More
// specifically, if the following value is zero, we know that the descriptor at
// (set = s, binding = b, index = i) is not initialized; if the value is
// non-zero, and the descriptor points to a buffer, the value is the length of
// the buffer in bytes and can be used to check for out-of-bounds buffer
// references:
// Data[ i + Data[ b + Data[ s + Data[ kDebugInputBindlessInitOffset ] ] ] ]
static const int kDebugInputBindlessInitOffset = 0;

// At offset kDebugInputBindlessOffsetLengths is some number of uints which
// provide the bindless length data. More specifically, the number of
// descriptors at (set=s, binding=b) is:
// Data[ Data[ s + kDebugInputBindlessOffsetLengths ] + b ]
static const int kDebugInputBindlessOffsetLengths = 1;

// Buffer Device Address Input Buffer Format
//
// An input buffer for buffer device address validation consists of a single
// array of unsigned 64-bit integers we will call Data[]. This array is
// formatted as follows:
//
// At offset kDebugInputBuffAddrPtrOffset is a list of sorted valid buffer
// addresses. The list is terminated with the address 0xffffffffffffffff.
// If 0x0 is not a valid buffer address, this address is inserted at the
// start of the list.
//
static const int kDebugInputBuffAddrPtrOffset = 1;
//
// At offset kDebugInputBuffAddrLengthOffset in Data[] is a single uint64 which
// gives an offset to the start of the buffer length data. More
// specifically, for a buffer whose pointer is located at input buffer offset
// i, the length is located at:
//
// Data[ i - kDebugInputBuffAddrPtrOffset
//         + Data[ kDebugInputBuffAddrLengthOffset ] ]
//
// The length associated with the 0xffffffffffffffff address is zero. If
// not a valid buffer, the length associated with the 0x0 address is zero.
static const int kDebugInputBuffAddrLengthOffset = 0;

}  // namespace spvtools

#endif  // INCLUDE_SPIRV_TOOLS_INSTRUMENT_HPP_
<|endoftext|>


<commit_before>#include <aabb.h>
#include <HgMath.h>
#include <float.h>
#include <stdlib.h>

#include "str_utils.h"

//#define max(a,b) (a > b ? a : b)
//#define min(a,b) (a < b ? a : b)

inline float max(float a, float b) { return (a > b) ? a : b; }
inline float min(float a, float b) { return (a < b) ? a : b; }

AABB* BoundingBoxes::allocate(uint32_t count) {
	AABB* r = (AABB*)malloc(sizeof(*r) * count);
	return r;
}

BoundingBoxes::BoundingBoxes() : bounding_boxes(nullptr)
{
	cube_count = 0;
}

void BoundingBoxes::setBoxes(const AABB* bc, uint32_t count) {
	if (bounding_boxes) SAFE_FREE(bounding_boxes);
	bounding_boxes = (AABB*)malloc(sizeof(*bounding_boxes) * count);
	cube_count = count;

	boundingVolume = bc[0];

	for (uint32_t i = 0; i < count; i++) {
		bounding_boxes[i] = bc[i];

		if (bounding_boxes[i].lb < boundingVolume.lb) boundingVolume.lb = bounding_boxes[i].lb;
		if (!(boundingVolume.rt < bounding_boxes[i].rt)) boundingVolume.rt = bounding_boxes[i].rt;
	}
}

static bool cast_ray(const vector3* dirfrac, const vector3* pos, AABB bb) {
	vector3 a = vector3_sub(&bb.lb, pos);
	a = vector3_mul(&a, dirfrac);

	vector3 b = vector3_sub(&bb.rt, pos);
	b = vector3_mul(&b, dirfrac);

	float dmin = max(max(min(a.components.x, b.components.x), min(a.components.y, b.components.y)), min(a.components.z, b.components.z));
	float dmax = min(min(max(a.components.x, b.components.x), max(a.components.y, b.components.y)), max(a.components.z, b.components.z));

	//intersection, but behind ray position
	if (dmax < 0) return false;

	//ray doesn't intersect AABB
	if (dmin > dmax) return false;
}

void BoundingBoxes::cast_ray(const vector3* ray, const vector3* pos, void(*intersectClbk)(aabb_result* result, void* userData), void* userData) const {
	//see https://gamedev.stackexchange.com/questions/18436/most-efficient-aabb-vs-ray-collision-algorithms

	vector3 one = { 1.0,1.0,1.0 };
	vector3 dirfrac = vector3_div(&one, ray);
	aabb_result r;
	AABB* cubes = bounding_boxes;

	vector3 a, b;
	float dmin, dmax;

	if (!::cast_ray(&dirfrac, pos, boundingVolume)) return; //quickly eliminate entire volume

	for (uint32_t i = 0; i < cube_count; i++) {
		a = vector3_sub(&cubes[i].lb, pos);
		a = vector3_mul(&a, &dirfrac);

		b = vector3_sub(&cubes[i].rt, pos);
		b = vector3_mul(&b, &dirfrac);

		dmin = max(max(min(a.components.x, b.components.x), min(a.components.y, b.components.y)), min(a.components.z, b.components.z));
		dmax = min(min(max(a.components.x, b.components.x), max(a.components.y, b.components.y)), max(a.components.z, b.components.z));

		//intersection, but behind ray position
		if (dmax < 0) continue;

		//ray doesn't intersect AABB
		if (dmin > dmax) continue;

		r.dist = dmin;
		r.index = i;

		intersectClbk(&r, userData);
	}
}<commit_msg>the quick check is broken<commit_after>#include <aabb.h>
#include <HgMath.h>
#include <float.h>
#include <stdlib.h>

#include "str_utils.h"

//#define max(a,b) (a > b ? a : b)
//#define min(a,b) (a < b ? a : b)

inline float max(float a, float b) { return (a > b) ? a : b; }
inline float min(float a, float b) { return (a < b) ? a : b; }

AABB* BoundingBoxes::allocate(uint32_t count) {
	AABB* r = (AABB*)malloc(sizeof(*r) * count);
	return r;
}

BoundingBoxes::BoundingBoxes() : bounding_boxes(nullptr)
{
	cube_count = 0;
}

void BoundingBoxes::setBoxes(const AABB* bc, uint32_t count) {
	if (bounding_boxes) SAFE_FREE(bounding_boxes);
	bounding_boxes = (AABB*)malloc(sizeof(*bounding_boxes) * count);
	cube_count = count;

	boundingVolume = bc[0];

	for (uint32_t i = 0; i < count; i++) {
		bounding_boxes[i] = bc[i];

		if (bounding_boxes[i].lb < boundingVolume.lb) boundingVolume.lb = bounding_boxes[i].lb;
		if (!(boundingVolume.rt < bounding_boxes[i].rt)) boundingVolume.rt = bounding_boxes[i].rt;
	}
}

static bool cast_ray(const vector3* dirfrac, const vector3* pos, AABB bb) {
	vector3 a = vector3_sub(&bb.lb, pos);
	a = vector3_mul(&a, dirfrac);

	vector3 b = vector3_sub(&bb.rt, pos);
	b = vector3_mul(&b, dirfrac);

	float dmin = max(max(min(a.components.x, b.components.x), min(a.components.y, b.components.y)), min(a.components.z, b.components.z));
	float dmax = min(min(max(a.components.x, b.components.x), max(a.components.y, b.components.y)), max(a.components.z, b.components.z));

	//intersection, but behind ray position
	if (dmax < 0) return false;

	//ray doesn't intersect AABB
	if (dmin > dmax) return false;
}

void BoundingBoxes::cast_ray(const vector3* ray, const vector3* pos, void(*intersectClbk)(aabb_result* result, void* userData), void* userData) const {
	//see https://gamedev.stackexchange.com/questions/18436/most-efficient-aabb-vs-ray-collision-algorithms

	vector3 one = { 1.0,1.0,1.0 };
	vector3 dirfrac = vector3_div(&one, ray);
	aabb_result r;
	AABB* cubes = bounding_boxes;

	vector3 a, b;
	float dmin, dmax;

//	if (!::cast_ray(&dirfrac, pos, boundingVolume)) return; //broken.....

	for (uint32_t i = 0; i < cube_count; i++) {
		a = vector3_sub(&cubes[i].lb, pos);
		a = vector3_mul(&a, &dirfrac);

		b = vector3_sub(&cubes[i].rt, pos);
		b = vector3_mul(&b, &dirfrac);

		dmin = max(max(min(a.components.x, b.components.x), min(a.components.y, b.components.y)), min(a.components.z, b.components.z));
		dmax = min(min(max(a.components.x, b.components.x), max(a.components.y, b.components.y)), max(a.components.z, b.components.z));

		//intersection, but behind ray position
		if (dmax < 0) continue;

		//ray doesn't intersect AABB
		if (dmin > dmax) continue;

		r.dist = dmin;
		r.index = i;

		intersectClbk(&r, userData);
	}
}<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//------------------------------------------------------------------------------

#include "cling/Interpreter/ValuePrinter.h"

#include "cling/Interpreter/CValuePrinter.h"
#include "cling/Interpreter/ValuePrinterInfo.h"
#include "cling/Interpreter/Value.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"

#include "llvm/Support/raw_ostream.h"

#include <string>

// Implements the CValuePrinter interface.
extern "C" void cling_PrintValue(void* /*clang::Expr**/ E,
                      void* /*clang::ASTContext**/ C,
                      const void* value) {
  clang::Expr* Exp = (clang::Expr*)E;
  clang::ASTContext* Context = (clang::ASTContext*)C;
  cling::ValuePrinterInfo VPI(Exp, Context);
  cling::printValue(llvm::outs(), value, value, VPI);

  cling::flushOStream(llvm::outs());
}

static void StreamChar(llvm::raw_ostream& o, const char v) {
  o << '"' << v << "\"\n";
}

static void StreamCharPtr(llvm::raw_ostream& o, const char* const v) {
  o << '"';
  const char* p = v;
  for (;*p && p - v < 128; ++p) {
    o << *p;
  }
  if (*p) o << "\"...\n";
  else o << "\"\n";
}

static void StreamRef(llvm::raw_ostream& o, const void* v) {
  o <<"&" << v << "\n";
}

static void StreamPtr(llvm::raw_ostream& o, const void* v) {
  if (v)
    o << *(intptr_t*)v;
  else
    o << "0x0";

  o << "\n";
}

static void StreamObj(llvm::raw_ostream& o, const void* v,
                      const cling::ValuePrinterInfo& VPI) {
  const clang::Type* Ty = VPI.getExpr()->getType().getTypePtr();
  if (clang::CXXRecordDecl* CXXRD = Ty->getAsCXXRecordDecl())
    if (CXXRD->getQualifiedNameAsString().compare("cling::Value") == 0) {
      cling::Value* V = (cling::Value*)v;
      if (V->isValid()) {
        o << "boxes [";
        const clang::ASTContext& C = *VPI.getASTContext();
        o <<
          "(" <<
          V->type.getAsString(C.getPrintingPolicy()) <<
          ") ";
        clang::QualType valType = V->type.getDesugaredType(C);
        if (valType->isPointerType())
          o << V->value.PointerVal;
        else if (valType->isFloatingType())
          o << V->value.DoubleVal;
        else if (valType->isIntegerType())
          o << V->value.IntVal.getSExtValue();
        else if (valType->isBooleanType())
          o << V->value.IntVal.getBoolValue();
        o << "]\n";

        return;
      } else
        o << "<<<invalid>>> ";
    }

  // TODO: Print the object members.
  o << "@" << v << "\n";
}

static void StreamValue(llvm::raw_ostream& o, const void* const p,
                        const cling::ValuePrinterInfo& VPI) {
  clang::QualType Ty = VPI.getExpr()->getType();
  const clang::ASTContext& C = *VPI.getASTContext();
  Ty = Ty.getDesugaredType(C);
  if (const clang::BuiltinType *BT
           = llvm::dyn_cast<clang::BuiltinType>(Ty.getCanonicalType())) {
    switch (BT->getKind()) {
    case clang::BuiltinType::Bool:
      if (*(bool*)p) o << "true\n";
      else o << "false\n"; break;
    case clang::BuiltinType::Char_U:
    case clang::BuiltinType::UChar:
    case clang::BuiltinType::Char_S:
    case clang::BuiltinType::SChar:  StreamChar(o, *(char*)p); break;
    case clang::BuiltinType::Short:  o << *(short*)p << "\n"; break;
    case clang::BuiltinType::UShort: o << *(unsigned short*)p << "\n"; break;
    case clang::BuiltinType::Int:    o << *(int*)p << "\n"; break;
    case clang::BuiltinType::UInt:   o << *(unsigned int*)p << "\n"; break;
    case clang::BuiltinType::Long:   o << *(long*)p << "\n"; break;
    case clang::BuiltinType::ULong:  o << *(unsigned long*)p << "\n"; break;
    case clang::BuiltinType::LongLong:  o << *(long long*)p << "\n"; break;
    case clang::BuiltinType::ULongLong: o << *(unsigned long long*)p << "\n";
      break;
    case clang::BuiltinType::Float:  o << *(float*)p << "\n"; break;
    case clang::BuiltinType::Double: o << *(double*)p << "\n"; break;
    default:
      StreamObj(o, p, VPI);
    }
  }
  else if (Ty.getAsString().compare("class std::basic_string<char>") == 0) {
    StreamObj(o, p, VPI);
    o <<"c_str: ";
    StreamCharPtr(o, ((const char*) (*(const std::string*)p).c_str()));
  }
  else if (Ty->isEnumeralType()) {
    StreamObj(o, p, VPI);
    int value = *(int*)p;
    clang::EnumDecl* ED = Ty->getAs<clang::EnumType>()->getDecl();
    bool IsFirst = true;
    llvm::APSInt ValAsAPSInt = C.MakeIntValue(value, C.IntTy);
    for (clang::EnumDecl::enumerator_iterator I = ED->enumerator_begin(),
           E = ED->enumerator_end(); I != E; ++I) {
      if (I->getInitVal() == ValAsAPSInt) {
        if (!IsFirst) {
          o << " ? ";
        }
        o << "(" << I->getQualifiedNameAsString() << ")";
        IsFirst = false;
      }
    }
    o << " : (int) " << value << "\n";
  }
  else if (Ty->isReferenceType())
    StreamRef(o, p);
  else if (Ty->isPointerType()) {
    clang::QualType PointeeTy = Ty->getPointeeType();
    if (PointeeTy->isCharType())
      StreamCharPtr(o, (const char*)p);
    else
      StreamPtr(o, p);
  }
  else
    StreamObj(o, p, VPI);
}

namespace cling {
  void printValueDefault(llvm::raw_ostream& o, const void* const p,
                         const ValuePrinterInfo& VPI) {
    const clang::Expr* E = VPI.getExpr();
    o << "(";
    o << E->getType().getAsString();
    if (E->isRValue()) // show the user that the var cannot be changed
      o << " const";
    o << ") ";
    StreamValue(o, p, VPI);
  }

  void flushOStream(llvm::raw_ostream& o) {
    o.flush();
  }

} // end namespace cling
<commit_msg>Set the sign of the APSInt.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//------------------------------------------------------------------------------

#include "cling/Interpreter/ValuePrinter.h"

#include "cling/Interpreter/CValuePrinter.h"
#include "cling/Interpreter/ValuePrinterInfo.h"
#include "cling/Interpreter/Value.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"

#include "llvm/Support/raw_ostream.h"

#include <string>

// Implements the CValuePrinter interface.
extern "C" void cling_PrintValue(void* /*clang::Expr**/ E,
                      void* /*clang::ASTContext**/ C,
                      const void* value) {
  clang::Expr* Exp = (clang::Expr*)E;
  clang::ASTContext* Context = (clang::ASTContext*)C;
  cling::ValuePrinterInfo VPI(Exp, Context);
  cling::printValue(llvm::outs(), value, value, VPI);

  cling::flushOStream(llvm::outs());
}

static void StreamChar(llvm::raw_ostream& o, const char v) {
  o << '"' << v << "\"\n";
}

static void StreamCharPtr(llvm::raw_ostream& o, const char* const v) {
  o << '"';
  const char* p = v;
  for (;*p && p - v < 128; ++p) {
    o << *p;
  }
  if (*p) o << "\"...\n";
  else o << "\"\n";
}

static void StreamRef(llvm::raw_ostream& o, const void* v) {
  o <<"&" << v << "\n";
}

static void StreamPtr(llvm::raw_ostream& o, const void* v) {
  if (v)
    o << *(intptr_t*)v;
  else
    o << "0x0";

  o << "\n";
}

static void StreamObj(llvm::raw_ostream& o, const void* v,
                      const cling::ValuePrinterInfo& VPI) {
  const clang::Type* Ty = VPI.getExpr()->getType().getTypePtr();
  if (clang::CXXRecordDecl* CXXRD = Ty->getAsCXXRecordDecl())
    if (CXXRD->getQualifiedNameAsString().compare("cling::Value") == 0) {
      cling::Value* V = (cling::Value*)v;
      if (V->isValid()) {
        o << "boxes [";
        const clang::ASTContext& C = *VPI.getASTContext();
        o <<
          "(" <<
          V->type.getAsString(C.getPrintingPolicy()) <<
          ") ";
        clang::QualType valType = V->type.getDesugaredType(C);
        if (valType->isPointerType())
          o << V->value.PointerVal;
        else if (valType->isFloatingType())
          o << V->value.DoubleVal;
        else if (valType->isIntegerType())
          o << V->value.IntVal.getSExtValue();
        else if (valType->isBooleanType())
          o << V->value.IntVal.getBoolValue();
        o << "]\n";

        return;
      } else
        o << "<<<invalid>>> ";
    }

  // TODO: Print the object members.
  o << "@" << v << "\n";
}

static void StreamValue(llvm::raw_ostream& o, const void* const p,
                        const cling::ValuePrinterInfo& VPI) {
  clang::QualType Ty = VPI.getExpr()->getType();
  const clang::ASTContext& C = *VPI.getASTContext();
  Ty = Ty.getDesugaredType(C);
  if (const clang::BuiltinType *BT
           = llvm::dyn_cast<clang::BuiltinType>(Ty.getCanonicalType())) {
    switch (BT->getKind()) {
    case clang::BuiltinType::Bool:
      if (*(bool*)p) o << "true\n";
      else o << "false\n"; break;
    case clang::BuiltinType::Char_U:
    case clang::BuiltinType::UChar:
    case clang::BuiltinType::Char_S:
    case clang::BuiltinType::SChar:  StreamChar(o, *(char*)p); break;
    case clang::BuiltinType::Short:  o << *(short*)p << "\n"; break;
    case clang::BuiltinType::UShort: o << *(unsigned short*)p << "\n"; break;
    case clang::BuiltinType::Int:    o << *(int*)p << "\n"; break;
    case clang::BuiltinType::UInt:   o << *(unsigned int*)p << "\n"; break;
    case clang::BuiltinType::Long:   o << *(long*)p << "\n"; break;
    case clang::BuiltinType::ULong:  o << *(unsigned long*)p << "\n"; break;
    case clang::BuiltinType::LongLong:  o << *(long long*)p << "\n"; break;
    case clang::BuiltinType::ULongLong: o << *(unsigned long long*)p << "\n";
      break;
    case clang::BuiltinType::Float:  o << *(float*)p << "\n"; break;
    case clang::BuiltinType::Double: o << *(double*)p << "\n"; break;
    default:
      StreamObj(o, p, VPI);
    }
  }
  else if (Ty.getAsString().compare("class std::basic_string<char>") == 0) {
    StreamObj(o, p, VPI);
    o <<"c_str: ";
    StreamCharPtr(o, ((const char*) (*(const std::string*)p).c_str()));
  }
  else if (Ty->isEnumeralType()) {
    StreamObj(o, p, VPI);
    clang::EnumDecl* ED = Ty->getAs<clang::EnumType>()->getDecl();
    uint64_t value = *(uint64_t*)p;
    bool IsFirst = true;
    llvm::APSInt ValAsAPSInt = C.MakeIntValue(value, ED->getPromotionType());
    for (clang::EnumDecl::enumerator_iterator I = ED->enumerator_begin(),
           E = ED->enumerator_end(); I != E; ++I) {
      ValAsAPSInt.setIsSigned(I->getInitVal().isSigned());
      if (I->getInitVal() == ValAsAPSInt) {
        if (!IsFirst) {
          o << " ? ";
        }
        o << "(" << I->getQualifiedNameAsString() << ")";
        IsFirst = false;
      }
    }
    o << " : (int) " << (int)value << "\n";
  }
  else if (Ty->isReferenceType())
    StreamRef(o, p);
  else if (Ty->isPointerType()) {
    clang::QualType PointeeTy = Ty->getPointeeType();
    if (PointeeTy->isCharType())
      StreamCharPtr(o, (const char*)p);
    else
      StreamPtr(o, p);
  }
  else
    StreamObj(o, p, VPI);
}

namespace cling {
  void printValueDefault(llvm::raw_ostream& o, const void* const p,
                         const ValuePrinterInfo& VPI) {
    const clang::Expr* E = VPI.getExpr();
    o << "(";
    o << E->getType().getAsString();
    if (E->isRValue()) // show the user that the var cannot be changed
      o << " const";
    o << ") ";
    StreamValue(o, p, VPI);
  }

  void flushOStream(llvm::raw_ostream& o) {
    o.flush();
  }

} // end namespace cling
<|endoftext|>