<commit_before>//===-- tsan_go.cpp -------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// ThreadSanitizer runtime for Go language.
//
//===----------------------------------------------------------------------===//

#include "tsan_rtl.h"
#include "tsan_symbolize.h"
#include "sanitizer_common/sanitizer_common.h"
#include <stdlib.h>

namespace __tsan {

void InitializeInterceptors() {
}

void InitializeDynamicAnnotations() {
}

bool IsExpectedReport(uptr addr, uptr size) {
  return false;
}

void *internal_alloc(MBlockType typ, uptr sz) {
  return InternalAlloc(sz);
}

void internal_free(void *p) {
  InternalFree(p);
}

// Callback into Go.
static void (*go_runtime_cb)(uptr cmd, void *ctx);

enum {
  CallbackGetProc = 0,
  CallbackSymbolizeCode = 1,
  CallbackSymbolizeData = 2,
};

struct SymbolizeCodeContext {
  uptr pc;
  char *func;
  char *file;
  uptr line;
  uptr off;
  uptr res;
};

SymbolizedStack *SymbolizeCode(uptr addr) {
  SymbolizedStack *s = SymbolizedStack::New(addr);
  SymbolizeCodeContext cbctx;
  internal_memset(&cbctx, 0, sizeof(cbctx));
  cbctx.pc = addr;
  go_runtime_cb(CallbackSymbolizeCode, &cbctx);
  if (cbctx.res) {
    AddressInfo &info = s->info;
    info.module_offset = cbctx.off;
    info.function = internal_strdup(cbctx.func ? cbctx.func : "??");
    info.file = internal_strdup(cbctx.file ? cbctx.file : "-");
    info.line = cbctx.line;
    info.column = 0;
  }
  return s;
}

struct SymbolizeDataContext {
  uptr addr;
  uptr heap;
  uptr start;
  uptr size;
  char *name;
  char *file;
  uptr line;
  uptr res;
};

ReportLocation *SymbolizeData(uptr addr) {
  SymbolizeDataContext cbctx;
  internal_memset(&cbctx, 0, sizeof(cbctx));
  cbctx.addr = addr;
  go_runtime_cb(CallbackSymbolizeData, &cbctx);
  if (!cbctx.res)
    return 0;
  if (cbctx.heap) {
    MBlock *b = ctx->metamap.GetBlock(cbctx.start);
    if (!b)
      return 0;
    ReportLocation *loc = ReportLocation::New(ReportLocationHeap);
    loc->heap_chunk_start = cbctx.start;
    loc->heap_chunk_size = b->siz;
    loc->tid = b->tid;
    loc->stack = SymbolizeStackId(b->stk);
    return loc;
  } else {
    ReportLocation *loc = ReportLocation::New(ReportLocationGlobal);
    loc->global.name = internal_strdup(cbctx.name ? cbctx.name : "??");
    loc->global.file = internal_strdup(cbctx.file ? cbctx.file : "??");
    loc->global.line = cbctx.line;
    loc->global.start = cbctx.start;
    loc->global.size = cbctx.size;
    return loc;
  }
}

static ThreadState *main_thr;
static bool inited;

static Processor* get_cur_proc() {
  if (UNLIKELY(!inited)) {
    // Running Initialize().
    // We have not yet returned the Processor to Go, so we cannot ask it back.
    // Currently, Initialize() does not use the Processor, so return nullptr.
    return nullptr;
  }
  Processor *proc;
  go_runtime_cb(CallbackGetProc, &proc);
  return proc;
}

Processor *ThreadState::proc() {
  return get_cur_proc();
}

extern "C" {

static ThreadState *AllocGoroutine() {
  ThreadState *thr = (ThreadState*)internal_alloc(MBlockThreadContex,
      sizeof(ThreadState));
  internal_memset(thr, 0, sizeof(*thr));
  return thr;
}

void __tsan_init(ThreadState **thrp, Processor **procp,
                 void (*cb)(uptr cmd, void *cb)) {
  go_runtime_cb = cb;
  ThreadState *thr = AllocGoroutine();
  main_thr = *thrp = thr;
  Initialize(thr);
  *procp = thr->proc1;
  inited = true;
}

void __tsan_fini() {
  // FIXME: Not necessary thread 0.
  ThreadState *thr = main_thr;
  int res = Finalize(thr);
  exit(res);
}

void __tsan_map_shadow(uptr addr, uptr size) {
  MapShadow(addr, size);
}

void __tsan_read(ThreadState *thr, void *addr, void *pc) {
  MemoryRead(thr, (uptr)pc, (uptr)addr, kSizeLog1);
}

void __tsan_read_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) {
  if (callpc != 0)
    FuncEntry(thr, callpc);
  MemoryRead(thr, (uptr)pc, (uptr)addr, kSizeLog1);
  if (callpc != 0)
    FuncExit(thr);
}

void __tsan_write(ThreadState *thr, void *addr, void *pc) {
  MemoryWrite(thr, (uptr)pc, (uptr)addr, kSizeLog1);
}

void __tsan_write_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) {
  if (callpc != 0)
    FuncEntry(thr, callpc);
  MemoryWrite(thr, (uptr)pc, (uptr)addr, kSizeLog1);
  if (callpc != 0)
    FuncExit(thr);
}

void __tsan_read_range(ThreadState *thr, void *addr, uptr size, uptr pc) {
  MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, false);
}

void __tsan_write_range(ThreadState *thr, void *addr, uptr size, uptr pc) {
  MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, true);
}

void __tsan_func_enter(ThreadState *thr, void *pc) {
  FuncEntry(thr, (uptr)pc);
}

void __tsan_func_exit(ThreadState *thr) {
  FuncExit(thr);
}

void __tsan_malloc(ThreadState *thr, uptr pc, uptr p, uptr sz) {
  CHECK(inited);
  if (thr && pc)
    ctx->metamap.AllocBlock(thr, pc, p, sz);
  MemoryResetRange(0, 0, (uptr)p, sz);
}

void __tsan_free(uptr p, uptr sz) {
  ctx->metamap.FreeRange(get_cur_proc(), p, sz);
}

void __tsan_go_start(ThreadState *parent, ThreadState **pthr, void *pc) {
  ThreadState *thr = AllocGoroutine();
  *pthr = thr;
  int goid = ThreadCreate(parent, (uptr)pc, 0, true);
  ThreadStart(thr, goid, 0, ThreadType::Regular);
}

void __tsan_go_end(ThreadState *thr) {
  ThreadFinish(thr);
  internal_free(thr);
}

void __tsan_proc_create(Processor **pproc) {
  *pproc = ProcCreate();
}

void __tsan_proc_destroy(Processor *proc) {
  ProcDestroy(proc);
}

void __tsan_acquire(ThreadState *thr, void *addr) {
  Acquire(thr, 0, (uptr)addr);
}

void __tsan_release(ThreadState *thr, void *addr) {
  ReleaseStore(thr, 0, (uptr)addr);
}

void __tsan_release_merge(ThreadState *thr, void *addr) {
  Release(thr, 0, (uptr)addr);
}

void __tsan_finalizer_goroutine(ThreadState *thr) {
  AcquireGlobal(thr, 0);
}

void __tsan_mutex_before_lock(ThreadState *thr, uptr addr, uptr write) {
  if (write)
    MutexPreLock(thr, 0, addr);
  else
    MutexPreReadLock(thr, 0, addr);
}

void __tsan_mutex_after_lock(ThreadState *thr, uptr addr, uptr write) {
  if (write)
    MutexPostLock(thr, 0, addr);
  else
    MutexPostReadLock(thr, 0, addr);
}

void __tsan_mutex_before_unlock(ThreadState *thr, uptr addr, uptr write) {
  if (write)
    MutexUnlock(thr, 0, addr);
  else
    MutexReadUnlock(thr, 0, addr);
}

void __tsan_go_ignore_sync_begin(ThreadState *thr) {
  ThreadIgnoreSyncBegin(thr, 0);
}

void __tsan_go_ignore_sync_end(ThreadState *thr) {
  ThreadIgnoreSyncEnd(thr, 0);
}

void __tsan_report_count(u64 *pn) {
  Lock lock(&ctx->report_mtx);
  *pn = ctx->nreported;
}

}  // extern "C"
}  // namespace __tsan
<commit_msg>tsan: allow the Go runtime to return multiple stack frames for a single PC<commit_after>//===-- tsan_go.cpp -------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// ThreadSanitizer runtime for Go language.
//
//===----------------------------------------------------------------------===//

#include "tsan_rtl.h"
#include "tsan_symbolize.h"
#include "sanitizer_common/sanitizer_common.h"
#include <stdlib.h>

namespace __tsan {

void InitializeInterceptors() {
}

void InitializeDynamicAnnotations() {
}

bool IsExpectedReport(uptr addr, uptr size) {
  return false;
}

void *internal_alloc(MBlockType typ, uptr sz) {
  return InternalAlloc(sz);
}

void internal_free(void *p) {
  InternalFree(p);
}

// Callback into Go.
static void (*go_runtime_cb)(uptr cmd, void *ctx);

enum {
  CallbackGetProc = 0,
  CallbackSymbolizeCode = 1,
  CallbackSymbolizeData = 2,
};

struct SymbolizeCodeContext {
  uptr pc;
  char *func;
  char *file;
  uptr line;
  uptr off;
  uptr res;
};

SymbolizedStack *SymbolizeCode(uptr addr) {
  SymbolizedStack *first = SymbolizedStack::New(addr);
  SymbolizedStack *s = first;
  for (;;) {
    SymbolizeCodeContext cbctx;
    internal_memset(&cbctx, 0, sizeof(cbctx));
    cbctx.pc = addr;
    go_runtime_cb(CallbackSymbolizeCode, &cbctx);
    if (cbctx.res == 0)
      break;
    AddressInfo &info = s->info;
    info.module_offset = cbctx.off;
    info.function = internal_strdup(cbctx.func ? cbctx.func : "??");
    info.file = internal_strdup(cbctx.file ? cbctx.file : "-");
    info.line = cbctx.line;
    info.column = 0;

    if (cbctx.pc == addr) // outermost (non-inlined) function
      break;
    addr = cbctx.pc;
    // Allocate a stack entry for the parent of the inlined function.
    SymbolizedStack *s2 = SymbolizedStack::New(addr);
    s->next = s2;
    s = s2;
  }
  return first;
}

struct SymbolizeDataContext {
  uptr addr;
  uptr heap;
  uptr start;
  uptr size;
  char *name;
  char *file;
  uptr line;
  uptr res;
};

ReportLocation *SymbolizeData(uptr addr) {
  SymbolizeDataContext cbctx;
  internal_memset(&cbctx, 0, sizeof(cbctx));
  cbctx.addr = addr;
  go_runtime_cb(CallbackSymbolizeData, &cbctx);
  if (!cbctx.res)
    return 0;
  if (cbctx.heap) {
    MBlock *b = ctx->metamap.GetBlock(cbctx.start);
    if (!b)
      return 0;
    ReportLocation *loc = ReportLocation::New(ReportLocationHeap);
    loc->heap_chunk_start = cbctx.start;
    loc->heap_chunk_size = b->siz;
    loc->tid = b->tid;
    loc->stack = SymbolizeStackId(b->stk);
    return loc;
  } else {
    ReportLocation *loc = ReportLocation::New(ReportLocationGlobal);
    loc->global.name = internal_strdup(cbctx.name ? cbctx.name : "??");
    loc->global.file = internal_strdup(cbctx.file ? cbctx.file : "??");
    loc->global.line = cbctx.line;
    loc->global.start = cbctx.start;
    loc->global.size = cbctx.size;
    return loc;
  }
}

static ThreadState *main_thr;
static bool inited;

static Processor* get_cur_proc() {
  if (UNLIKELY(!inited)) {
    // Running Initialize().
    // We have not yet returned the Processor to Go, so we cannot ask it back.
    // Currently, Initialize() does not use the Processor, so return nullptr.
    return nullptr;
  }
  Processor *proc;
  go_runtime_cb(CallbackGetProc, &proc);
  return proc;
}

Processor *ThreadState::proc() {
  return get_cur_proc();
}

extern "C" {

static ThreadState *AllocGoroutine() {
  ThreadState *thr = (ThreadState*)internal_alloc(MBlockThreadContex,
      sizeof(ThreadState));
  internal_memset(thr, 0, sizeof(*thr));
  return thr;
}

void __tsan_init(ThreadState **thrp, Processor **procp,
                 void (*cb)(uptr cmd, void *cb)) {
  go_runtime_cb = cb;
  ThreadState *thr = AllocGoroutine();
  main_thr = *thrp = thr;
  Initialize(thr);
  *procp = thr->proc1;
  inited = true;
}

void __tsan_fini() {
  // FIXME: Not necessary thread 0.
  ThreadState *thr = main_thr;
  int res = Finalize(thr);
  exit(res);
}

void __tsan_map_shadow(uptr addr, uptr size) {
  MapShadow(addr, size);
}

void __tsan_read(ThreadState *thr, void *addr, void *pc) {
  MemoryRead(thr, (uptr)pc, (uptr)addr, kSizeLog1);
}

void __tsan_read_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) {
  if (callpc != 0)
    FuncEntry(thr, callpc);
  MemoryRead(thr, (uptr)pc, (uptr)addr, kSizeLog1);
  if (callpc != 0)
    FuncExit(thr);
}

void __tsan_write(ThreadState *thr, void *addr, void *pc) {
  MemoryWrite(thr, (uptr)pc, (uptr)addr, kSizeLog1);
}

void __tsan_write_pc(ThreadState *thr, void *addr, uptr callpc, uptr pc) {
  if (callpc != 0)
    FuncEntry(thr, callpc);
  MemoryWrite(thr, (uptr)pc, (uptr)addr, kSizeLog1);
  if (callpc != 0)
    FuncExit(thr);
}

void __tsan_read_range(ThreadState *thr, void *addr, uptr size, uptr pc) {
  MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, false);
}

void __tsan_write_range(ThreadState *thr, void *addr, uptr size, uptr pc) {
  MemoryAccessRange(thr, (uptr)pc, (uptr)addr, size, true);
}

void __tsan_func_enter(ThreadState *thr, void *pc) {
  FuncEntry(thr, (uptr)pc);
}

void __tsan_func_exit(ThreadState *thr) {
  FuncExit(thr);
}

void __tsan_malloc(ThreadState *thr, uptr pc, uptr p, uptr sz) {
  CHECK(inited);
  if (thr && pc)
    ctx->metamap.AllocBlock(thr, pc, p, sz);
  MemoryResetRange(0, 0, (uptr)p, sz);
}

void __tsan_free(uptr p, uptr sz) {
  ctx->metamap.FreeRange(get_cur_proc(), p, sz);
}

void __tsan_go_start(ThreadState *parent, ThreadState **pthr, void *pc) {
  ThreadState *thr = AllocGoroutine();
  *pthr = thr;
  int goid = ThreadCreate(parent, (uptr)pc, 0, true);
  ThreadStart(thr, goid, 0, ThreadType::Regular);
}

void __tsan_go_end(ThreadState *thr) {
  ThreadFinish(thr);
  internal_free(thr);
}

void __tsan_proc_create(Processor **pproc) {
  *pproc = ProcCreate();
}

void __tsan_proc_destroy(Processor *proc) {
  ProcDestroy(proc);
}

void __tsan_acquire(ThreadState *thr, void *addr) {
  Acquire(thr, 0, (uptr)addr);
}

void __tsan_release(ThreadState *thr, void *addr) {
  ReleaseStore(thr, 0, (uptr)addr);
}

void __tsan_release_merge(ThreadState *thr, void *addr) {
  Release(thr, 0, (uptr)addr);
}

void __tsan_finalizer_goroutine(ThreadState *thr) {
  AcquireGlobal(thr, 0);
}

void __tsan_mutex_before_lock(ThreadState *thr, uptr addr, uptr write) {
  if (write)
    MutexPreLock(thr, 0, addr);
  else
    MutexPreReadLock(thr, 0, addr);
}

void __tsan_mutex_after_lock(ThreadState *thr, uptr addr, uptr write) {
  if (write)
    MutexPostLock(thr, 0, addr);
  else
    MutexPostReadLock(thr, 0, addr);
}

void __tsan_mutex_before_unlock(ThreadState *thr, uptr addr, uptr write) {
  if (write)
    MutexUnlock(thr, 0, addr);
  else
    MutexReadUnlock(thr, 0, addr);
}

void __tsan_go_ignore_sync_begin(ThreadState *thr) {
  ThreadIgnoreSyncBegin(thr, 0);
}

void __tsan_go_ignore_sync_end(ThreadState *thr) {
  ThreadIgnoreSyncEnd(thr, 0);
}

void __tsan_report_count(u64 *pn) {
  Lock lock(&ctx->report_mtx);
  *pn = ctx->nreported;
}

}  // extern "C"
}  // namespace __tsan
<|endoftext|>


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

#include "iceoryx_utils/cxx/variant_queue.hpp"
#include "test.hpp"

using namespace ::testing;
using namespace iox;
using namespace iox::cxx;

class VariantQueue_test : public Test
{
  public:
    void SetUp()
    {
    }
    void TearDown()
    {
    }

    void PerformTestForQueueTypes(const std::function<void(uint64_t typeID)>& testCase) noexcept
    {
        for (uint64_t i = 0; i < numberOfQueueTypes; ++i)
            testCase(i);
    }

    // if a new fifo type is added this variable has to be adjusted
    uint64_t numberOfQueueTypes = 6;
};

TEST_F(VariantQueue_test, isEmptyWhenCreated)
{
    PerformTestForQueueTypes([](uint64_t typeID) {
        VariantQueue<int, 5> sut(static_cast<VariantQueueTypes>(typeID));
        EXPECT_THAT(sut.empty(), Eq(true));
    });
}

TEST_F(VariantQueue_test, isNotEmptyWhenOneElementIsInside)
{
    PerformTestForQueueTypes([](uint64_t typeID) {
        VariantQueue<int, 5> sut(static_cast<VariantQueueTypes>(typeID));
        sut.push(123);
        EXPECT_THAT(sut.empty(), Eq(false));
    });
}

TEST_F(VariantQueue_test, popsSingleElementWhichWasPushed)
{
    PerformTestForQueueTypes([](uint64_t typeID) {
        VariantQueue<int, 5> sut(static_cast<VariantQueueTypes>(typeID));
        sut.push(4123);
        auto element = sut.pop();
        ASSERT_THAT(element.has_value(), Eq(true));
        EXPECT_THAT(element.value(), Eq(4123));
    });
}

TEST_F(VariantQueue_test, popsMultiElementsWhichWerePushed)
{
    PerformTestForQueueTypes([](uint64_t typeID) {
        VariantQueue<int, 5> sut(static_cast<VariantQueueTypes>(typeID));
        sut.push(14123);
        sut.push(24123);
        sut.push(34123);

        auto element = sut.pop();
        ASSERT_THAT(element.has_value(), Eq(true));
        EXPECT_THAT(element.value(), Eq(14123));

        element = sut.pop();
        ASSERT_THAT(element.has_value(), Eq(true));
        EXPECT_THAT(element.value(), Eq(24123));

        element = sut.pop();
        ASSERT_THAT(element.has_value(), Eq(true));
        EXPECT_THAT(element.value(), Eq(34123));
    });
}

TEST_F(VariantQueue_test, pushTwoElementsAfterSecondPopIsInvalid)
{
    PerformTestForQueueTypes([](uint64_t typeID) {
        VariantQueue<int, 5> sut(static_cast<VariantQueueTypes>(typeID));
        sut.push(14123);
        sut.push(24123);

        sut.pop();
        sut.pop();

        EXPECT_THAT(sut.pop().has_value(), Eq(false));
    });
}

TEST_F(VariantQueue_test, handlesOverflow)
{
    return;
    PerformTestForQueueTypes([](uint64_t typeID) {
        VariantQueue<int, 2> sut(static_cast<VariantQueueTypes>(typeID));
        // current SOFI can hold capacity +1 values, so push some more to ensure overflow
        sut.push(14123);
        sut.push(24123);
        sut.push(22222);
        sut.push(33333);
        auto maybeOverflowValue = sut.push(667);
        EXPECT_THAT(maybeOverflowValue.has_value(), Eq(true));
    });
}

TEST_F(VariantQueue_test, noPopWhenEmpty)
{
    PerformTestForQueueTypes([](uint64_t typeID) {
        VariantQueue<int, 5> sut(static_cast<VariantQueueTypes>(typeID));
        EXPECT_THAT(sut.pop().has_value(), Eq(false));
    });
}

TEST_F(VariantQueue_test, underlyingTypeIsEmptyWhenCreated)
{
    VariantQueue<int, 5> sut(static_cast<VariantQueueTypes>(0));
    EXPECT_THAT(sut.getUnderlyingFiFo().template get_at_index<0>()->empty(), Eq(true));
}
<commit_msg>iox-#615 added blocking test and adjusted overflow test<commit_after>// Copyright (c) 2020 by Robert Bosch GmbH. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0

#include "iceoryx_utils/cxx/variant_queue.hpp"
#include "test.hpp"
#include "testutils/watch_dog.hpp"

using namespace ::testing;
using namespace iox;
using namespace iox::cxx;

class VariantQueue_test : public Test
{
  public:
    void SetUp()
    {
        m_watchdog.watchAndActOnFailure([] { std::terminate(); });
    }
    void TearDown()
    {
    }

    void PerformTestForQueueTypes(const std::function<void(uint64_t typeID)>& testCase) noexcept
    {
        for (uint64_t i = 0; i < numberOfQueueTypes; ++i)
            testCase(i);
    }

    // if a new fifo type is added this variable has to be adjusted
    uint64_t numberOfQueueTypes = 6U;
    Watchdog m_watchdog{units::Duration::fromSeconds(2U)};
};

TEST_F(VariantQueue_test, isEmptyWhenCreated)
{
    PerformTestForQueueTypes([](uint64_t typeID) {
        VariantQueue<int, 5> sut(static_cast<VariantQueueTypes>(typeID));
        EXPECT_THAT(sut.empty(), Eq(true));
    });
}

TEST_F(VariantQueue_test, isNotEmptyWhenOneElementIsInside)
{
    PerformTestForQueueTypes([](uint64_t typeID) {
        VariantQueue<int, 5> sut(static_cast<VariantQueueTypes>(typeID));
        sut.push(123);
        EXPECT_THAT(sut.empty(), Eq(false));
    });
}

TEST_F(VariantQueue_test, popsSingleElementWhichWasPushed)
{
    PerformTestForQueueTypes([](uint64_t typeID) {
        VariantQueue<int, 5> sut(static_cast<VariantQueueTypes>(typeID));
        sut.push(4123);
        auto element = sut.pop();
        ASSERT_THAT(element.has_value(), Eq(true));
        EXPECT_THAT(element.value(), Eq(4123));
    });
}

TEST_F(VariantQueue_test, popsMultiElementsWhichWerePushed)
{
    PerformTestForQueueTypes([](uint64_t typeID) {
        VariantQueue<int, 5> sut(static_cast<VariantQueueTypes>(typeID));
        sut.push(14123);
        sut.push(24123);
        sut.push(34123);

        auto element = sut.pop();
        ASSERT_THAT(element.has_value(), Eq(true));
        EXPECT_THAT(element.value(), Eq(14123));

        element = sut.pop();
        ASSERT_THAT(element.has_value(), Eq(true));
        EXPECT_THAT(element.value(), Eq(24123));

        element = sut.pop();
        ASSERT_THAT(element.has_value(), Eq(true));
        EXPECT_THAT(element.value(), Eq(34123));
    });
}

TEST_F(VariantQueue_test, pushTwoElementsAfterSecondPopIsInvalid)
{
    PerformTestForQueueTypes([](uint64_t typeID) {
        VariantQueue<int, 5> sut(static_cast<VariantQueueTypes>(typeID));
        sut.push(14123);
        sut.push(24123);

        sut.pop();
        sut.pop();

        EXPECT_THAT(sut.pop().has_value(), Eq(false));
    });
}

TEST_F(VariantQueue_test, handlesOverflow)
{
    PerformTestForQueueTypes([](uint64_t typeID) {
        VariantQueueTypes type = static_cast<VariantQueueTypes>(typeID);
        if (type == VariantQueueTypes::BlockingFiFo_MultiProducerSingleConsumer
            || type == VariantQueueTypes::BlockingFiFo_SingleProducerSingleConsumer)
        {
            return;
        }

        VariantQueue<int, 2> sut(type);
        // current SOFI can hold capacity +1 values, so push some more to ensure overflow
        sut.push(14123);
        sut.push(24123);
        sut.push(22222);
        sut.push(33333);
        auto maybeOverflowValue = sut.push(667);
        EXPECT_THAT(maybeOverflowValue.has_value(), Eq(true));
    });
}

TEST_F(VariantQueue_test, blocksOnOverflow)
{
    PerformTestForQueueTypes([](uint64_t typeID) {
        VariantQueueTypes type = static_cast<VariantQueueTypes>(typeID);
        if (!(type == VariantQueueTypes::BlockingFiFo_MultiProducerSingleConsumer
              || type == VariantQueueTypes::BlockingFiFo_SingleProducerSingleConsumer))
        {
            return;
        }

        VariantQueue<int, 2> sut(type);

        for (uint64_t i = 0U; i < sut.capacity(); ++i)
        {
            sut.push(24123 + i);
        }

        std::atomic_uint64_t counter{0U};
        std::thread t([&] {
            sut.push(1231);
            ++counter;
        });

        constexpr int64_t TIMEOUT_IN_MS = 100;
        std::this_thread::sleep_for(std::chrono::milliseconds(TIMEOUT_IN_MS));
        EXPECT_THAT(counter.load(), Eq(0U));
        auto result = sut.pop();
        ASSERT_THAT(result.has_value(), Eq(true));
        EXPECT_THAT(*result, Eq(24123));
        std::this_thread::sleep_for(std::chrono::milliseconds(TIMEOUT_IN_MS));
        EXPECT_THAT(counter.load(), Eq(1U));
        t.join();
    });
}

TEST_F(VariantQueue_test, noPopWhenEmpty)
{
    PerformTestForQueueTypes([](uint64_t typeID) {
        VariantQueue<int, 5> sut(static_cast<VariantQueueTypes>(typeID));
        EXPECT_THAT(sut.pop().has_value(), Eq(false));
    });
}

TEST_F(VariantQueue_test, underlyingTypeIsEmptyWhenCreated)
{
    VariantQueue<int, 5> sut(static_cast<VariantQueueTypes>(0));
    EXPECT_THAT(sut.getUnderlyingFiFo().template get_at_index<0>()->empty(), Eq(true));
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: interceptedinteraction.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 16:28:57 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _UCBHELPER_INTERCEPTEDINTERACTION_HXX_
#define _UCBHELPER_INTERCEPTEDINTERACTION_HXX_

//_______________________________________________
// includes

#include <vector>

#ifndef __COM_SUN_STAR_TASK_XINTERACTIONHANDLER_HPP__
#include <com/sun/star/task/XInteractionHandler.hpp>
#endif

#ifndef __COM_SUN_STAR_TASK_XINTERACTIONREQUEST_HPP__
#include <com/sun/star/task/XInteractionRequest.hpp>
#endif

#ifndef _CPPUHELPER_IMPLBASE1_HXX_
#include <cppuhelper/implbase1.hxx>
#endif
#ifndef INCLUDED_UCBHELPERDLLAPI_H
#include "ucbhelper/ucbhelperdllapi.h"
#endif

//_______________________________________________
// namespace

namespace ucbhelper{

//_______________________________________________
// definitions

/** @short  it wraps any other interaction handler and intercept
            its handle() requests.

    @descr  This class can be used as:
            - instance if special interactions must be supressed
              only
            - or as base class if interactions must be modified.
 */
class UCBHELPER_DLLPUBLIC InterceptedInteraction : public ::cppu::WeakImplHelper1< ::com::sun::star::task::XInteractionHandler >
{
    //-------------------------------------------
    // types
    public:

        struct InterceptedRequest
        {
            //-----------------------------------
            /** @short  marks an Handle as invalid.
             */
            static const sal_Int32 INVALID_HANDLE = -1;

            //-----------------------------------
            /** @short  contains the interaction request, which should be intercepted. */
            ::com::sun::star::uno::Any Request;

            //-----------------------------------
            /** @short  specify the fix continuation, which must be selected, if the
                        interaction could be intercepted successfully.
              */
            ::com::sun::star::uno::Type Continuation;

            //-----------------------------------
            /** @short  specify, if both interactions must have the same type
                        or can be derived from.

                @descr  Interaction base on exceptions - and exceptions are real types.
                        So they can be checked in its type. These parameter "MatchExact"
                        influence the type-check in the following way:
                            TRUE  => the exception will be intercepted only
                                     if it supports exactly the same type ...
                                     or
                            FALSE => derived exceptions will be intercepted too.

                @attention  This parameter does not influence the check of the continuation
                            type! The continuation must be matched exactly everytimes ...
             */
            sal_Bool MatchExact;

            //-----------------------------------
            /** @short  its an unique identifier, which must be managed by the outside code.

                @descr  If there is a derived class, which overwrites the InterceptedInteraction::intercepted()
                        method, it will be called with a reference to an InterceptedRequest struct.
                        Then it can use the handle to react without checking the request type again.
             */
            sal_Int32 Handle;

            //-----------------------------------
            /** @short  default ctor.

                @descr  Such constructed object cant be used realy.
                        Might it will crash if its used!
                        Dont forget to initialize all(!) members ...
             */
            InterceptedRequest()
            {
                MatchExact = sal_False;
                Handle     = INVALID_HANDLE;
            }

            //-----------------------------------
            /** @short  initialize this instance.

                @param  nHandle
                        used to identify every intercepted request

                @param  aRequest
                        must contain an exception object, which can be checked
                        in its uno-type against the later handled interaction.

                @param  aContinuation
                        must contain a continuation object, which is used
                        in its uno-type to locate the same continuation
                        inside the list of possible ones.

                @param  bMatchExact
                        influence the type check of the interception request.
                        Its not used to check the continuation!
             */
            InterceptedRequest(      sal_Int32                    nHandle      ,
                               const ::com::sun::star::uno::Any&  aRequest     ,
                               const ::com::sun::star::uno::Type& aContinuation,
                                     sal_Bool                     bMatchExact  )
            {
                Handle       = nHandle;
                Request      = aRequest;
                Continuation = aContinuation;
                MatchExact   = bMatchExact;
            }
        };

        //---------------------------------------
        /** @short  represent the different states, which can occure
                    as result of an interception.

            @see    impl_interceptRequest()
         */
        enum EInterceptionState
        {
            /** none of the specified interceptions match the incoming request */
            E_NOT_INTERCEPTED,
            /** the request could be intercepted - but the specified continuation could not be located.
                Thats normaly an error of the programmer. May be the interaction request does not use
                the right set of continuations ... or the interception list contains the wrong continuation. */
            E_NO_CONTINUATION_FOUND,
            /** the request could be intercepted and the specified continuation could be selected successfully. */
            E_INTERCEPTED
        };

    //-------------------------------------------
    // member
    protected:

        //---------------------------------------
        /** @short  reference to the intercepted interaction handler.

            @descr  NULL is allowed for this member!
                    All interaction will be aborted then ...
                    expecting th handle() was overwritten by
                    a derived class.
         */
        ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler > m_xInterceptedHandler;

        //---------------------------------------
        /** @short  these list contains the requests, which should be intercepted.
         */
        ::std::vector< InterceptedRequest > m_lInterceptions;

    //-------------------------------------------
    // native interface
    public:

        //---------------------------------------
        /** @short  initialize a new instance with default values.
         */
        InterceptedInteraction();

        //---------------------------------------
        /** @short  initialize a new instance with real values.

            @param  xInterceptedHandler
                    the outside interaction handler, which should
                    be intercepted here.

            @param  lInterceptions
                    the list of intercepted requests.
         */
        InterceptedInteraction(const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& xInterceptedHandler,
                               const ::std::vector< InterceptedRequest >&                                             lInterceptions     );

        //---------------------------------------
        /** @short  initialize a new instance with the interaction handler,
                    which should be intercepted.

            @attention  If such interaction handler isnt set here,
                        all incoming requests will be aborted ...
                        if the right continuation is available!

            @param  xInterceptedHandler
                    the outside interaction handler, which should
                    be intercepted here.
         */
        void setInterceptedHandler(const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& xInterceptedHandler);

        //---------------------------------------
        /** @short  set a new list of intercepted interactions.

            @attention  If the interface method handle() will be overwritten by
                        a derived class, the functionality behind these static list
                        cant be used.

            @param  lInterceptions
                    the list of intercepted requests.
         */
        void setInterceptions(const ::std::vector< InterceptedRequest >& lInterceptions);

        //---------------------------------------
        /** @short  extract a requested continuation from te list of available ones.

            @param  lContinuations
                    the list of available continuations.

            @param  aType
                    is used to locate the right continuation,
                    by checking its interface type.

            @return A valid reference to the continuation, if it could be located ...
                    or an empty reference otherwhise.
         */
        static ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionContinuation > extractContinuation(
                    const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionContinuation > >& lContinuations,
                    const ::com::sun::star::uno::Type&                                                                                aType         );

    //-------------------------------------------
    // useable for derived classes
    protected:

        //---------------------------------------
        /** @short  can be overwritten by a derived class to handle interceptions
                    outside.

            @descr  This base implementation checks, if the request could be intercepted
                    successfully. Then this method intercepted() is called.
                    The default implementation returns "NOT_INTERCEPTED" everytimes.
                    So the method impl_interceptRequest() uses the right continuation automaticly.

                    If this method was overwritten and something different "NO_INTERCEPTED"
                    is returned, the method impl_interceptRequest() will return immediatly with
                    the result, which is returned by this intercepted() method.
                    Then the continuations must be selected inside the intercepted() call!

            @param  rRequest
                    it points to the intercepted request (means the item of the
                    set interception list). e.g. its "Handle" member can be used
                    to identify it and react very easy, without the need to check the
                    type of the exception ...

            @param  xOrgRequest
                    points to the original interaction, which was intercepted.
                    It provides access to the exception and the list of possible
                    continuations.

            @return The result of this operation.
                    Note: If E_NOT_INTERCEPTED is returned the default handling of the base class
                    will be used automaticly for this request!
         */
        virtual EInterceptionState intercepted(const InterceptedRequest&                                                             rRequest   ,
                                               const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionRequest >& xOrgRequest);

    //-------------------------------------------
    // uno interface
    public:

        //---------------------------------------
        /** @short  implements the default handling of this class ....
                    or can be overwritten by any derived class.

            @descr  If no further class is derived from this one
                    -> the default implementation is used. Then the
                    internal list of requests is used to handle different
                    interactions automaticly.
                    (see impl_interceptRequest())

                    If this method was overwritten by a derived implementation
                    -> the new implementation has to do everything by itself.
                    Of course it can access all members/helpers and work with it.
                    But the default implementation isnt used automaticly then.

            @param  xRequest
                    the interaction request, which should be intercepted.
         */
        virtual void SAL_CALL handle(const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionRequest >& xRequest)
            throw(::com::sun::star::uno::RuntimeException);

    //-------------------------------------------
    // helper
    private:

        //---------------------------------------
        /** @short  implements the default handling:
                    - intercept or forward to internal handler.
         */
        UCBHELPER_DLLPRIVATE void impl_handleDefault(const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionRequest >& xRequest);

        //---------------------------------------
        /** @short  implements the interception of requests.

            @descr  The incoming request will be analyzed, if it match
                    any request of the m_lIntercepions list.
                    If an interception could be found, its continuation will be
                    searched and selected.

                    The method return the state of that operation.
                    But it doesnt call the intercepted and here set
                    interaction handler. That has to be done in the outside method.

            @param  xRequest
                    the interaction request, which should be intercepted.

            @return A identifier, which inidicates if the request was intercepted,
                    the continuation was found and selected ... or not.
         */
        UCBHELPER_DLLPRIVATE EInterceptionState impl_interceptRequest(const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionRequest >& xRequest);
};

} // namespace ucbhelper

#endif // _UCBHELPER_INTERCEPTEDINTERACTION_HXX_
<commit_msg>INTEGRATION: CWS changefileheader (1.4.104); FILE MERGED 2008/04/01 16:02:45 thb 1.4.104.3: #i85898# Stripping all external header guards 2008/04/01 12:58:44 thb 1.4.104.2: #i85898# Stripping all external header guards 2008/03/31 15:31:29 rt 1.4.104.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: interceptedinteraction.hxx,v $
 * $Revision: 1.5 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _UCBHELPER_INTERCEPTEDINTERACTION_HXX_
#define _UCBHELPER_INTERCEPTEDINTERACTION_HXX_

//_______________________________________________
// includes

#include <vector>

#ifndef __COM_SUN_STAR_TASK_XINTERACTIONHANDLER_HPP__
#include <com/sun/star/task/XInteractionHandler.hpp>
#endif

#ifndef __COM_SUN_STAR_TASK_XINTERACTIONREQUEST_HPP__
#include <com/sun/star/task/XInteractionRequest.hpp>
#endif
#include <cppuhelper/implbase1.hxx>
#include "ucbhelper/ucbhelperdllapi.h"

//_______________________________________________
// namespace

namespace ucbhelper{

//_______________________________________________
// definitions

/** @short  it wraps any other interaction handler and intercept
            its handle() requests.

    @descr  This class can be used as:
            - instance if special interactions must be supressed
              only
            - or as base class if interactions must be modified.
 */
class UCBHELPER_DLLPUBLIC InterceptedInteraction : public ::cppu::WeakImplHelper1< ::com::sun::star::task::XInteractionHandler >
{
    //-------------------------------------------
    // types
    public:

        struct InterceptedRequest
        {
            //-----------------------------------
            /** @short  marks an Handle as invalid.
             */
            static const sal_Int32 INVALID_HANDLE = -1;

            //-----------------------------------
            /** @short  contains the interaction request, which should be intercepted. */
            ::com::sun::star::uno::Any Request;

            //-----------------------------------
            /** @short  specify the fix continuation, which must be selected, if the
                        interaction could be intercepted successfully.
              */
            ::com::sun::star::uno::Type Continuation;

            //-----------------------------------
            /** @short  specify, if both interactions must have the same type
                        or can be derived from.

                @descr  Interaction base on exceptions - and exceptions are real types.
                        So they can be checked in its type. These parameter "MatchExact"
                        influence the type-check in the following way:
                            TRUE  => the exception will be intercepted only
                                     if it supports exactly the same type ...
                                     or
                            FALSE => derived exceptions will be intercepted too.

                @attention  This parameter does not influence the check of the continuation
                            type! The continuation must be matched exactly everytimes ...
             */
            sal_Bool MatchExact;

            //-----------------------------------
            /** @short  its an unique identifier, which must be managed by the outside code.

                @descr  If there is a derived class, which overwrites the InterceptedInteraction::intercepted()
                        method, it will be called with a reference to an InterceptedRequest struct.
                        Then it can use the handle to react without checking the request type again.
             */
            sal_Int32 Handle;

            //-----------------------------------
            /** @short  default ctor.

                @descr  Such constructed object cant be used realy.
                        Might it will crash if its used!
                        Dont forget to initialize all(!) members ...
             */
            InterceptedRequest()
            {
                MatchExact = sal_False;
                Handle     = INVALID_HANDLE;
            }

            //-----------------------------------
            /** @short  initialize this instance.

                @param  nHandle
                        used to identify every intercepted request

                @param  aRequest
                        must contain an exception object, which can be checked
                        in its uno-type against the later handled interaction.

                @param  aContinuation
                        must contain a continuation object, which is used
                        in its uno-type to locate the same continuation
                        inside the list of possible ones.

                @param  bMatchExact
                        influence the type check of the interception request.
                        Its not used to check the continuation!
             */
            InterceptedRequest(      sal_Int32                    nHandle      ,
                               const ::com::sun::star::uno::Any&  aRequest     ,
                               const ::com::sun::star::uno::Type& aContinuation,
                                     sal_Bool                     bMatchExact  )
            {
                Handle       = nHandle;
                Request      = aRequest;
                Continuation = aContinuation;
                MatchExact   = bMatchExact;
            }
        };

        //---------------------------------------
        /** @short  represent the different states, which can occure
                    as result of an interception.

            @see    impl_interceptRequest()
         */
        enum EInterceptionState
        {
            /** none of the specified interceptions match the incoming request */
            E_NOT_INTERCEPTED,
            /** the request could be intercepted - but the specified continuation could not be located.
                Thats normaly an error of the programmer. May be the interaction request does not use
                the right set of continuations ... or the interception list contains the wrong continuation. */
            E_NO_CONTINUATION_FOUND,
            /** the request could be intercepted and the specified continuation could be selected successfully. */
            E_INTERCEPTED
        };

    //-------------------------------------------
    // member
    protected:

        //---------------------------------------
        /** @short  reference to the intercepted interaction handler.

            @descr  NULL is allowed for this member!
                    All interaction will be aborted then ...
                    expecting th handle() was overwritten by
                    a derived class.
         */
        ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler > m_xInterceptedHandler;

        //---------------------------------------
        /** @short  these list contains the requests, which should be intercepted.
         */
        ::std::vector< InterceptedRequest > m_lInterceptions;

    //-------------------------------------------
    // native interface
    public:

        //---------------------------------------
        /** @short  initialize a new instance with default values.
         */
        InterceptedInteraction();

        //---------------------------------------
        /** @short  initialize a new instance with real values.

            @param  xInterceptedHandler
                    the outside interaction handler, which should
                    be intercepted here.

            @param  lInterceptions
                    the list of intercepted requests.
         */
        InterceptedInteraction(const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& xInterceptedHandler,
                               const ::std::vector< InterceptedRequest >&                                             lInterceptions     );

        //---------------------------------------
        /** @short  initialize a new instance with the interaction handler,
                    which should be intercepted.

            @attention  If such interaction handler isnt set here,
                        all incoming requests will be aborted ...
                        if the right continuation is available!

            @param  xInterceptedHandler
                    the outside interaction handler, which should
                    be intercepted here.
         */
        void setInterceptedHandler(const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& xInterceptedHandler);

        //---------------------------------------
        /** @short  set a new list of intercepted interactions.

            @attention  If the interface method handle() will be overwritten by
                        a derived class, the functionality behind these static list
                        cant be used.

            @param  lInterceptions
                    the list of intercepted requests.
         */
        void setInterceptions(const ::std::vector< InterceptedRequest >& lInterceptions);

        //---------------------------------------
        /** @short  extract a requested continuation from te list of available ones.

            @param  lContinuations
                    the list of available continuations.

            @param  aType
                    is used to locate the right continuation,
                    by checking its interface type.

            @return A valid reference to the continuation, if it could be located ...
                    or an empty reference otherwhise.
         */
        static ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionContinuation > extractContinuation(
                    const ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionContinuation > >& lContinuations,
                    const ::com::sun::star::uno::Type&                                                                                aType         );

    //-------------------------------------------
    // useable for derived classes
    protected:

        //---------------------------------------
        /** @short  can be overwritten by a derived class to handle interceptions
                    outside.

            @descr  This base implementation checks, if the request could be intercepted
                    successfully. Then this method intercepted() is called.
                    The default implementation returns "NOT_INTERCEPTED" everytimes.
                    So the method impl_interceptRequest() uses the right continuation automaticly.

                    If this method was overwritten and something different "NO_INTERCEPTED"
                    is returned, the method impl_interceptRequest() will return immediatly with
                    the result, which is returned by this intercepted() method.
                    Then the continuations must be selected inside the intercepted() call!

            @param  rRequest
                    it points to the intercepted request (means the item of the
                    set interception list). e.g. its "Handle" member can be used
                    to identify it and react very easy, without the need to check the
                    type of the exception ...

            @param  xOrgRequest
                    points to the original interaction, which was intercepted.
                    It provides access to the exception and the list of possible
                    continuations.

            @return The result of this operation.
                    Note: If E_NOT_INTERCEPTED is returned the default handling of the base class
                    will be used automaticly for this request!
         */
        virtual EInterceptionState intercepted(const InterceptedRequest&                                                             rRequest   ,
                                               const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionRequest >& xOrgRequest);

    //-------------------------------------------
    // uno interface
    public:

        //---------------------------------------
        /** @short  implements the default handling of this class ....
                    or can be overwritten by any derived class.

            @descr  If no further class is derived from this one
                    -> the default implementation is used. Then the
                    internal list of requests is used to handle different
                    interactions automaticly.
                    (see impl_interceptRequest())

                    If this method was overwritten by a derived implementation
                    -> the new implementation has to do everything by itself.
                    Of course it can access all members/helpers and work with it.
                    But the default implementation isnt used automaticly then.

            @param  xRequest
                    the interaction request, which should be intercepted.
         */
        virtual void SAL_CALL handle(const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionRequest >& xRequest)
            throw(::com::sun::star::uno::RuntimeException);

    //-------------------------------------------
    // helper
    private:

        //---------------------------------------
        /** @short  implements the default handling:
                    - intercept or forward to internal handler.
         */
        UCBHELPER_DLLPRIVATE void impl_handleDefault(const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionRequest >& xRequest);

        //---------------------------------------
        /** @short  implements the interception of requests.

            @descr  The incoming request will be analyzed, if it match
                    any request of the m_lIntercepions list.
                    If an interception could be found, its continuation will be
                    searched and selected.

                    The method return the state of that operation.
                    But it doesnt call the intercepted and here set
                    interaction handler. That has to be done in the outside method.

            @param  xRequest
                    the interaction request, which should be intercepted.

            @return A identifier, which inidicates if the request was intercepted,
                    the continuation was found and selected ... or not.
         */
        UCBHELPER_DLLPRIVATE EInterceptionState impl_interceptRequest(const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionRequest >& xRequest);
};

} // namespace ucbhelper

#endif // _UCBHELPER_INTERCEPTEDINTERACTION_HXX_
<|endoftext|>


<commit_before>#include "Optimizer.h"

#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/BasicBlock.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/Transforms/Scalar.h>
#include <llvm/Transforms/IPO.h>
#include "preprocessor/llvm_includes_end.h"

#include "Arith256.h"
#include "Type.h"

namespace dev
{
namespace eth
{
namespace jit
{

bool optimize(llvm::Module& _module)
{
	auto pm = llvm::legacy::PassManager{};
	//pm.add(llvm::createFunctionInliningPass(2, 2)); // Problem with APInt value bigger than 64bit
	pm.add(llvm::createCFGSimplificationPass());
	pm.add(llvm::createInstructionCombiningPass());
	pm.add(llvm::createAggressiveDCEPass());
	pm.add(llvm::createLowerSwitchPass());
	return pm.run(_module);
}

namespace
{

class LowerEVMPass : public llvm::BasicBlockPass
{
	static char ID;

	bool m_mulFuncNeeded = false;

public:
	LowerEVMPass():
		llvm::BasicBlockPass(ID)
	{}

	virtual bool runOnBasicBlock(llvm::BasicBlock& _bb) override;

	virtual bool doFinalization(llvm::Module& _module) override;
};

char LowerEVMPass::ID = 0;

bool LowerEVMPass::runOnBasicBlock(llvm::BasicBlock& _bb)
{
	auto modified = false;
	auto module = _bb.getParent()->getParent();
	auto i512Ty = llvm::IntegerType::get(_bb.getContext(), 512);
	for (auto it = _bb.begin(); it != _bb.end(); )
	{
		auto& inst = *it++;
		llvm::Function* func = nullptr;
		if (inst.getType() == Type::Word)
		{
			switch (inst.getOpcode())
			{
			case llvm::Instruction::Mul:
				func = Arith256::getMulFunc(*module);
				break;

			case llvm::Instruction::UDiv:
				func = Arith256::getUDiv256Func(*module);
				break;

			case llvm::Instruction::URem:
				func = Arith256::getURem256Func(*module);
				break;

			case llvm::Instruction::SDiv:
				func = Arith256::getSDiv256Func(*module);
				break;

			case llvm::Instruction::SRem:
				func = Arith256::getSRem256Func(*module);
				break;
			}
		}
		else if (inst.getType() == i512Ty)
		{
			switch (inst.getOpcode())
			{
			case llvm::Instruction::URem:
				func = Arith256::getURem512Func(*module);
				break;
			}
		}

		if (func)
		{
			auto call = llvm::CallInst::Create(func, {inst.getOperand(0), inst.getOperand(1)}, "", &inst);
			inst.replaceAllUsesWith(call);
			inst.eraseFromParent();
			modified = true;
		}
	}
	return modified;
}

bool LowerEVMPass::doFinalization(llvm::Module&)
{
	return false;
}

}

bool prepare(llvm::Module& _module)
{
	auto pm = llvm::legacy::PassManager{};
	pm.add(llvm::createDeadCodeEliminationPass());
	pm.add(new LowerEVMPass{});
	return pm.run(_module);
}

}
}
}
<commit_msg>Enable function inlining optimization.<commit_after>#include "Optimizer.h"

#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/BasicBlock.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/Transforms/Scalar.h>
#include <llvm/Transforms/IPO.h>
#include "preprocessor/llvm_includes_end.h"

#include "Arith256.h"
#include "Type.h"

namespace dev
{
namespace eth
{
namespace jit
{

bool optimize(llvm::Module& _module)
{
	auto pm = llvm::legacy::PassManager{};
	pm.add(llvm::createFunctionInliningPass(2, 2));
	pm.add(llvm::createCFGSimplificationPass());
	pm.add(llvm::createInstructionCombiningPass());
	pm.add(llvm::createAggressiveDCEPass());
	pm.add(llvm::createLowerSwitchPass());
	return pm.run(_module);
}

namespace
{

class LowerEVMPass : public llvm::BasicBlockPass
{
	static char ID;

	bool m_mulFuncNeeded = false;

public:
	LowerEVMPass():
		llvm::BasicBlockPass(ID)
	{}

	virtual bool runOnBasicBlock(llvm::BasicBlock& _bb) override;

	virtual bool doFinalization(llvm::Module& _module) override;
};

char LowerEVMPass::ID = 0;

bool LowerEVMPass::runOnBasicBlock(llvm::BasicBlock& _bb)
{
	auto modified = false;
	auto module = _bb.getParent()->getParent();
	auto i512Ty = llvm::IntegerType::get(_bb.getContext(), 512);
	for (auto it = _bb.begin(); it != _bb.end(); )
	{
		auto& inst = *it++;
		llvm::Function* func = nullptr;
		if (inst.getType() == Type::Word)
		{
			switch (inst.getOpcode())
			{
			case llvm::Instruction::Mul:
				func = Arith256::getMulFunc(*module);
				break;

			case llvm::Instruction::UDiv:
				func = Arith256::getUDiv256Func(*module);
				break;

			case llvm::Instruction::URem:
				func = Arith256::getURem256Func(*module);
				break;

			case llvm::Instruction::SDiv:
				func = Arith256::getSDiv256Func(*module);
				break;

			case llvm::Instruction::SRem:
				func = Arith256::getSRem256Func(*module);
				break;
			}
		}
		else if (inst.getType() == i512Ty)
		{
			switch (inst.getOpcode())
			{
			case llvm::Instruction::URem:
				func = Arith256::getURem512Func(*module);
				break;
			}
		}

		if (func)
		{
			auto call = llvm::CallInst::Create(func, {inst.getOperand(0), inst.getOperand(1)}, "", &inst);
			inst.replaceAllUsesWith(call);
			inst.eraseFromParent();
			modified = true;
		}
	}
	return modified;
}

bool LowerEVMPass::doFinalization(llvm::Module&)
{
	return false;
}

}

bool prepare(llvm::Module& _module)
{
	auto pm = llvm::legacy::PassManager{};
	pm.add(llvm::createDeadCodeEliminationPass());
	pm.add(new LowerEVMPass{});
	return pm.run(_module);
}

}
}
}
<|endoftext|>


<commit_before><commit_msg>remove stray semicolon<commit_after><|endoftext|>


<commit_before>#include "EditorSceneViewFrame.h"
#include "EditorMainWindow.h"
#include "EditorApplication.h"

#include <Core/GameInput.h>

EditorSceneViewFrame::EditorSceneViewFrame(QWidget* parent /*= Q_NULLPTR*/) : QFrame(parent)
{
	setFocusPolicy(Qt::FocusPolicy::ClickFocus);
}

EditorSceneViewFrame::~EditorSceneViewFrame()
{
}

void EditorSceneViewFrame::mousePressEvent(QMouseEvent* event)
{
	MAD::UGameInput::Get().OnKeyDown(event->button(), false);
}

void EditorSceneViewFrame::keyPressEvent(QKeyEvent* event)
{
	switch (event->key())
	{
	case Qt::Key_Escape:
	{
		MAD::UGameInput::Get().OnFocusChanged(false);
		setCursor(Qt::ArrowCursor);
		clearFocus();
		qEditorApp->GetMainWindow()->setFocus();
		break;
	}
	default:
		MAD::UGameInput::Get().OnKeyDown(event->key(), false);
	}
}

void EditorSceneViewFrame::keyReleaseEvent(QKeyEvent* event)
{
	MAD::UGameInput::Get().OnKeyUp(event->key());
}

void EditorSceneViewFrame::focusInEvent(QFocusEvent* event)
{
	if (event->reason() == Qt::FocusReason::MouseFocusReason)
	{
		if (event->gotFocus())
		{
			setCursor(Qt::BlankCursor);
			MAD::UGameInput::Get().OnFocusChanged(true);
		}
		else
		{
			MAD::UGameInput::Get().OnFocusChanged(false);
		}
	}
	//QWidget::focusInEvent(event);
}
<commit_msg>Forgot to re-add the call to the base QWidget::focusInEvent event handler<commit_after>#include "EditorSceneViewFrame.h"
#include "EditorMainWindow.h"
#include "EditorApplication.h"

#include <Core/GameInput.h>

EditorSceneViewFrame::EditorSceneViewFrame(QWidget* parent /*= Q_NULLPTR*/) : QFrame(parent)
{
	setFocusPolicy(Qt::FocusPolicy::ClickFocus);
}

EditorSceneViewFrame::~EditorSceneViewFrame()
{
}

void EditorSceneViewFrame::mousePressEvent(QMouseEvent* event)
{
	MAD::UGameInput::Get().OnKeyDown(event->button(), false);
}

void EditorSceneViewFrame::keyPressEvent(QKeyEvent* event)
{
	switch (event->key())
	{
	case Qt::Key_Escape:
	{
		MAD::UGameInput::Get().OnFocusChanged(false);
		setCursor(Qt::ArrowCursor);
		clearFocus();
		qEditorApp->GetMainWindow()->setFocus();
		break;
	}
	default:
		MAD::UGameInput::Get().OnKeyDown(event->key(), false);
	}
}

void EditorSceneViewFrame::keyReleaseEvent(QKeyEvent* event)
{
	MAD::UGameInput::Get().OnKeyUp(event->key());
}

void EditorSceneViewFrame::focusInEvent(QFocusEvent* event)
{
	if (event->reason() == Qt::FocusReason::MouseFocusReason)
	{
		if (event->gotFocus())
		{
			setCursor(Qt::BlankCursor);
			MAD::UGameInput::Get().OnFocusChanged(true);
		}
		else
		{
			MAD::UGameInput::Get().OnFocusChanged(false);
		}
	}

	QWidget::focusInEvent(event);
}
<|endoftext|>


<commit_before>// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include <rs-vino/age-gender-detection.h>
#include <rs-vino/openvino-helpers.h>
#include <easylogging++.h>

using namespace InferenceEngine;

namespace openvino_helpers
{
    age_gender_detection::age_gender_detection(
        const std::string &pathToModel,
        bool isAsync,
        int maxBatch, bool isBatchDynamic,
        bool doRawOutputMessages
    )
        : base_detection( "age/gender", pathToModel, maxBatch, isBatchDynamic, isAsync, doRawOutputMessages)
        , _n_enqued_frames(0)
    {
    }

    void age_gender_detection::submit_request()
    {
        if( !_n_enqued_frames )
            return;
        _n_enqued_frames = 0;
        base_detection::submit_request();
    }

    void age_gender_detection::enqueue( const cv::Mat &face )
    {
        if( !enabled() )
            return;
        if( !_request )
            _request = net.CreateInferRequestPtr();

        Blob::Ptr inputBlob = _request->GetBlob( input );
        matU8ToBlob<uint8_t>( face, inputBlob, _n_enqued_frames );

        ++_n_enqued_frames;
    }

    age_gender_detection::Result age_gender_detection::operator[] (int idx) const
    {
        Blob::Ptr  genderBlob = _request->GetBlob( outputGender );
        Blob::Ptr  ageBlob = _request->GetBlob( outputAge );

        age_gender_detection::Result r = {
            ageBlob->buffer().as<float*>()[idx] * 100,
            genderBlob->buffer().as<float*>()[idx * 2 + 1]
        };
        if (doRawOutputMessages)
            LOG(DEBUG) << "element" << idx << ", male prob = " << r.maleProb << ", age = " << r.age;

        return r;
    }

    CNNNetwork age_gender_detection::read_network()
    {
        LOG(INFO) << "Loading " << topoName << " model from: " << pathToModel;

        CNNNetwork network;

#ifdef OPENVINO2019
        CNNNetReader netReader;

        /** Read network model **/
        netReader.ReadNetwork( pathToModel );
        network = netReader.getNetwork();

        /** Extract model name and load its weights **/
        std::string binFileName = remove_ext( pathToModel ) + ".bin";
        netReader.ReadWeights( binFileName );
#else
        InferenceEngine::Core ie;
        /** Read network model **/
        network = ie.ReadNetwork(pathToModel);
#endif

        /** Set batch size **/
        //LOG(DEBUG) << "Batch size is set to " << maxBatch;
        network.setBatchSize(maxBatch);

        // Age/Gender Recognition network should have one input and two outputs

        LOG(DEBUG) << "Checking Age/Gender Recognition network inputs";
        InputsDataMap inputInfo(network.getInputsInfo());
        if (inputInfo.size() != 1)
            throw std::logic_error("Age/Gender Recognition network should have only one input");
        InputInfo::Ptr& inputInfoFirst = inputInfo.begin()->second;
        inputInfoFirst->setPrecision(Precision::U8);
        input = inputInfo.begin()->first;

        LOG(DEBUG) << "Checking Age/Gender Recognition network outputs";
        OutputsDataMap outputInfo(network.getOutputsInfo());
        if (outputInfo.size() != 2)
            throw std::logic_error("Age/Gender Recognition network should have two output layers");
        auto it = outputInfo.begin();

        DataPtr ptrAgeOutput = (it++)->second;
        DataPtr ptrGenderOutput = (it++)->second;

        if (!ptrAgeOutput)
            throw std::logic_error("Age output data pointer is not valid");
        if (!ptrGenderOutput)
            throw std::logic_error("Gender output data pointer is not valid");

#ifdef OPENVINO2019
        auto genderCreatorLayer = ptrGenderOutput->getCreatorLayer().lock();
        auto ageCreatorLayer = ptrAgeOutput->getCreatorLayer().lock();

        if (!ageCreatorLayer)
            throw std::logic_error("Age creator layer pointer is not valid");
        if (!genderCreatorLayer)
            throw std::logic_error("Gender creator layer pointer is not valid");

        // if gender output is convolution, it can be swapped with age
        if (genderCreatorLayer->type == "Convolution")
            std::swap(ptrAgeOutput, ptrGenderOutput);

        if (ptrAgeOutput->getCreatorLayer().lock()->type != "Convolution")
            throw std::logic_error("In Age/Gender Recognition network, age layer (" + ageCreatorLayer->name +
                                    ") should be a Convolution, but was: " + ageCreatorLayer->type);

        if (ptrGenderOutput->getCreatorLayer().lock()->type != "SoftMax")
            throw std::logic_error("In Age/Gender Recognition network, gender layer (" + genderCreatorLayer->name +
                                    ") should be a SoftMax, but was: " + genderCreatorLayer->type);

        if( doRawOutputMessages )
        {
            LOG(DEBUG) << "Age layer: " << ageCreatorLayer->name;
            LOG(DEBUG) << "Gender layer: " << genderCreatorLayer->name;
        }
#endif

        outputAge = ptrAgeOutput->getName();
        outputGender = ptrGenderOutput->getName();

        _enabled = true;
        return network;
    }
}
<commit_msg>checking age/gender layer setup with ngraph<commit_after>// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include <rs-vino/age-gender-detection.h>
#include <rs-vino/openvino-helpers.h>
#include <easylogging++.h>
#include "types.h"

using namespace InferenceEngine;

namespace openvino_helpers
{
    age_gender_detection::age_gender_detection(
        const std::string &pathToModel,
        bool isAsync,
        int maxBatch, bool isBatchDynamic,
        bool doRawOutputMessages
    )
        : base_detection( "age/gender", pathToModel, maxBatch, isBatchDynamic, isAsync, doRawOutputMessages)
        , _n_enqued_frames(0)
    {
    }

    void age_gender_detection::submit_request()
    {
        if( !_n_enqued_frames )
            return;
        _n_enqued_frames = 0;
        base_detection::submit_request();
    }

    void age_gender_detection::enqueue( const cv::Mat &face )
    {
        if( !enabled() )
            return;
        if( !_request )
            _request = net.CreateInferRequestPtr();

        Blob::Ptr inputBlob = _request->GetBlob( input );
        matU8ToBlob<uint8_t>( face, inputBlob, _n_enqued_frames );

        ++_n_enqued_frames;
    }

    age_gender_detection::Result age_gender_detection::operator[] (int idx) const
    {
        Blob::Ptr  genderBlob = _request->GetBlob( outputGender );
        Blob::Ptr  ageBlob = _request->GetBlob( outputAge );

        age_gender_detection::Result r = {
            ageBlob->buffer().as<float*>()[idx] * 100,
            genderBlob->buffer().as<float*>()[idx * 2 + 1]
        };
        if (doRawOutputMessages)
            LOG(DEBUG) << "element" << idx << ", male prob = " << r.maleProb << ", age = " << r.age;

        return r;
    }

    CNNNetwork age_gender_detection::read_network()
    {
        LOG(INFO) << "Loading " << topoName << " model from: " << pathToModel;

        CNNNetwork network;

#ifdef OPENVINO2019
        CNNNetReader netReader;

        /** Read network model **/
        netReader.ReadNetwork( pathToModel );
        network = netReader.getNetwork();

        /** Extract model name and load its weights **/
        std::string binFileName = remove_ext( pathToModel ) + ".bin";
        netReader.ReadWeights( binFileName );
#else
        InferenceEngine::Core ie;
        /** Read network model **/
        network = ie.ReadNetwork(pathToModel);
#endif

        /** Set batch size **/
        //LOG(DEBUG) << "Batch size is set to " << maxBatch;
        network.setBatchSize(maxBatch);

        // Age/Gender Recognition network should have one input and two outputs

        LOG(DEBUG) << "Checking Age/Gender Recognition network inputs";
        InputsDataMap inputInfo(network.getInputsInfo());
        if (inputInfo.size() != 1)
            throw std::logic_error("Age/Gender Recognition network should have only one input");
        InputInfo::Ptr& inputInfoFirst = inputInfo.begin()->second;
        inputInfoFirst->setPrecision(Precision::U8);
        input = inputInfo.begin()->first;

        LOG(DEBUG) << "Checking Age/Gender Recognition network outputs";
        OutputsDataMap outputInfo(network.getOutputsInfo());
        if (outputInfo.size() != 2)
            throw std::logic_error("Age/Gender Recognition network should have two output layers");
        auto it = outputInfo.begin();

        DataPtr ptrAgeOutput = (it++)->second;
        DataPtr ptrGenderOutput = (it++)->second;

        if (!ptrAgeOutput)
            throw std::logic_error("Age output data pointer is not valid");
        if (!ptrGenderOutput)
            throw std::logic_error("Gender output data pointer is not valid");

#ifdef OPENVINO2019
        auto genderCreatorLayer = ptrGenderOutput->getCreatorLayer().lock();
        auto ageCreatorLayer = ptrAgeOutput->getCreatorLayer().lock();

        if (!ageCreatorLayer)
            throw std::logic_error("Age creator layer pointer is not valid");
        if (!genderCreatorLayer)
            throw std::logic_error("Gender creator layer pointer is not valid");

        // if gender output is convolution, it can be swapped with age
        if (genderCreatorLayer->type == "Convolution")
            std::swap(ptrAgeOutput, ptrGenderOutput);

        if (ptrAgeOutput->getCreatorLayer().lock()->type != "Convolution")
            throw std::logic_error("In Age/Gender Recognition network, age layer (" + ageCreatorLayer->name +
                ") should be a Convolution, but was: " + ageCreatorLayer->type);

        if (ptrGenderOutput->getCreatorLayer().lock()->type != "SoftMax")
            throw std::logic_error("In Age/Gender Recognition network, gender layer (" + genderCreatorLayer->name +
                ") should be a SoftMax, but was: " + genderCreatorLayer->type);

        if (doRawOutputMessages)
        {
            LOG(DEBUG) << "Age layer: " << ageCreatorLayer->name;
            LOG(DEBUG) << "Gender layer: " << genderCreatorLayer->name;
        }
#else
#ifdef OPENVINO_NGRAPH
        if (auto ngraphFunction = network.getFunction()) {

                for (const auto& op : ngraphFunction->get_ops()) {
                    std::string friendly_name = op->get_friendly_name();
                    std::string output_type = op->get_type_name();

                    if ((friendly_name.find(ptrGenderOutput->getName()) != std::string::npos) && (output_type == "Convolution")) {
                         std::swap(ptrAgeOutput, ptrGenderOutput);
                        break;
                    }
                }

                bool outputAgeOk = false;

                for (const auto& op : ngraphFunction->get_ops()) {
                    std::string friendly_name = op->get_friendly_name();
                    std::string output_type = op->get_type_name();

                    if ((friendly_name.find(ptrAgeOutput->getName()) != std::string::npos) && (output_type == "Convolution")) {
                        outputAgeOk = true;
                        break;
                    }
                }

                if (!outputAgeOk)
                {
                    throw std::logic_error("In Age/Gender Recognition network, Age layer (" + ptrAgeOutput->getName() + ") should be a Convolution");
                }

                bool outputGenderOk = false;

                for (const auto& op : ngraphFunction->get_ops()) {
                    std::string friendly_name = op->get_friendly_name();
                    std::string output_type = op->get_type_name();

                    if ((friendly_name.find(ptrGenderOutput->getName()) != std::string::npos) && (output_type == "Softmax")) {
                        outputGenderOk = true;
                        break;
                    }
                }

                if (!outputGenderOk)
                {
                    throw std::logic_error("In Age/Gender Recognition network, Gender layer (" + ptrGenderOutput->getName() + ") should be a Softmax");
                }
        }

        if (doRawOutputMessages)
        {
            LOG(DEBUG) << "Age layer: " << ptrAgeOutput->getName();
            LOG(DEBUG) << "Gender layer: " << ptrGenderOutput->getName();
        }
#endif
#endif

        outputAge = ptrAgeOutput->getName();
        outputGender = ptrGenderOutput->getName();

        _enabled = true;
        return network;
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include <rs-vino/age-gender-detection.h>
#include <rs-vino/openvino-helpers.h>
#include <easylogging++.h>

using namespace InferenceEngine;

namespace openvino_helpers
{
    age_gender_detection::age_gender_detection(
        const std::string &pathToModel,
        bool isAsync,
        int maxBatch, bool isBatchDynamic,
        bool doRawOutputMessages
    )
        : base_detection( "age/gender", pathToModel, maxBatch, isBatchDynamic, isAsync, doRawOutputMessages)
        , _n_enqued_frames(0)
    {
    }

    void age_gender_detection::submit_request()
    {
        if( !_n_enqued_frames )
            return;
        _n_enqued_frames = 0;
        base_detection::submit_request();
    }

    void age_gender_detection::enqueue( const cv::Mat &face )
    {
        if( !enabled() )
            return;
        if( !_request )
            _request = net.CreateInferRequestPtr();

        Blob::Ptr inputBlob = _request->GetBlob( input );
        matU8ToBlob<uint8_t>( face, inputBlob, _n_enqued_frames );

        ++_n_enqued_frames;
    }

    age_gender_detection::Result age_gender_detection::operator[] (int idx) const
    {
        Blob::Ptr  genderBlob = _request->GetBlob( outputGender );
        Blob::Ptr  ageBlob = _request->GetBlob( outputAge );

        age_gender_detection::Result r = {
            ageBlob->buffer().as<float*>()[idx] * 100,
            genderBlob->buffer().as<float*>()[idx * 2 + 1]
        };
        if (doRawOutputMessages)
            LOG(DEBUG) << "element" << idx << ", male prob = " << r.maleProb << ", age = " << r.age;

        return r;
    }

    CNNNetwork age_gender_detection::read_network()
    {
        LOG(INFO) << "Loading " << topoName << " model from: " << pathToModel;

        CNNNetwork network;

#ifdef OPENVINO2019
        CNNNetReader netReader;

        /** Read network model **/
        netReader.ReadNetwork( pathToModel );
        network = netReader.getNetwork();

        /** Extract model name and load its weights **/
        std::string binFileName = remove_ext( pathToModel ) + ".bin";
        netReader.ReadWeights( binFileName );
#else
        InferenceEngine::Core ie;
        /** Read network model **/
        network = ie.ReadNetwork(pathToModel);
#endif

        /** Set batch size **/
        //LOG(DEBUG) << "Batch size is set to " << maxBatch;
        network.setBatchSize(maxBatch);

        // Age/Gender Recognition network should have one input and two outputs

        LOG(DEBUG) << "Checking Age/Gender Recognition network inputs";
        InputsDataMap inputInfo(network.getInputsInfo());
        if (inputInfo.size() != 1)
            throw std::logic_error("Age/Gender Recognition network should have only one input");
        InputInfo::Ptr& inputInfoFirst = inputInfo.begin()->second;
        inputInfoFirst->setPrecision(Precision::U8);
        input = inputInfo.begin()->first;

        LOG(DEBUG) << "Checking Age/Gender Recognition network outputs";
        OutputsDataMap outputInfo(network.getOutputsInfo());
        if (outputInfo.size() != 2)
            throw std::logic_error("Age/Gender Recognition network should have two output layers");
        auto it = outputInfo.begin();

        DataPtr ptrAgeOutput = (it++)->second;
        DataPtr ptrGenderOutput = (it++)->second;

        if (!ptrAgeOutput)
            throw std::logic_error("Age output data pointer is not valid");
        if (!ptrGenderOutput)
            throw std::logic_error("Gender output data pointer is not valid");

#ifdef OPENVINO2019
        auto genderCreatorLayer = ptrGenderOutput->getCreatorLayer().lock();
        auto ageCreatorLayer = ptrAgeOutput->getCreatorLayer().lock();

        if (!ageCreatorLayer)
            throw std::logic_error("Age creator layer pointer is not valid");
        if (!genderCreatorLayer)
            throw std::logic_error("Gender creator layer pointer is not valid");

        // if gender output is convolution, it can be swapped with age
        if (genderCreatorLayer->type == "Convolution")
            std::swap(ptrAgeOutput, ptrGenderOutput);

        if (ptrAgeOutput->getCreatorLayer().lock()->type != "Convolution")
            throw std::logic_error("In Age/Gender Recognition network, age layer (" + ageCreatorLayer->name +
                ") should be a Convolution, but was: " + ageCreatorLayer->type);

        if (ptrGenderOutput->getCreatorLayer().lock()->type != "SoftMax")
            throw std::logic_error("In Age/Gender Recognition network, gender layer (" + genderCreatorLayer->name +
                ") should be a SoftMax, but was: " + genderCreatorLayer->type);

        if (doRawOutputMessages)
        {
            LOG(DEBUG) << "Age layer: " << ageCreatorLayer->name;
            LOG(DEBUG) << "Gender layer: " << genderCreatorLayer->name;
        }
#else
#ifdef OPENVINO_NGRAPH
        if (auto ngraphFunction = network.getFunction()) {

                for (const auto& op : ngraphFunction->get_ops()) {
                    std::string friendly_name = op->get_friendly_name();
                    std::string output_type = op->get_type_name();

                    if ((friendly_name.find(ptrGenderOutput->getName()) != std::string::npos) && (output_type == "Convolution")) {
                         std::swap(ptrAgeOutput, ptrGenderOutput);
                        break;
                    }
                }

                bool outputAgeOk = false;

                for (const auto& op : ngraphFunction->get_ops()) {
                    std::string friendly_name = op->get_friendly_name();
                    std::string output_type = op->get_type_name();

                    if ((friendly_name.find(ptrAgeOutput->getName()) != std::string::npos) && (output_type == "Convolution")) {
                        outputAgeOk = true;
                        break;
                    }
                }

                if (!outputAgeOk)
                {
                    throw std::logic_error("In Age/Gender Recognition network, Age layer (" + ptrAgeOutput->getName() + ") should be a Convolution");
                }

                bool outputGenderOk = false;

                for (const auto& op : ngraphFunction->get_ops()) {
                    std::string friendly_name = op->get_friendly_name();
                    std::string output_type = op->get_type_name();

                    if ((friendly_name.find(ptrGenderOutput->getName()) != std::string::npos) && (output_type == "Softmax")) {
                        outputGenderOk = true;
                        break;
                    }
                }

                if (!outputGenderOk)
                {
                    throw std::logic_error("In Age/Gender Recognition network, Gender layer (" + ptrGenderOutput->getName() + ") should be a Softmax");
                }
        }

        if (doRawOutputMessages)
        {
            LOG(DEBUG) << "Age layer: " << ptrAgeOutput->getName();
            LOG(DEBUG) << "Gender layer: " << ptrGenderOutput->getName();
        }
#endif
#endif

        outputAge = ptrAgeOutput->getName();
        outputGender = ptrGenderOutput->getName();

        _enabled = true;
        return network;
    }
}
<commit_msg>Update age-gender-detection.cpp<commit_after>// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//

#include <rs-vino/age-gender-detection.h>
#include <rs-vino/openvino-helpers.h>
#include <easylogging++.h>

using namespace InferenceEngine;

namespace openvino_helpers
{
    age_gender_detection::age_gender_detection(
        const std::string &pathToModel,
        bool isAsync,
        int maxBatch, bool isBatchDynamic,
        bool doRawOutputMessages
    )
        : base_detection( "age/gender", pathToModel, maxBatch, isBatchDynamic, isAsync, doRawOutputMessages)
        , _n_enqued_frames(0)
    {
    }

    void age_gender_detection::submit_request()
    {
        if( !_n_enqued_frames )
            return;
        _n_enqued_frames = 0;
        base_detection::submit_request();
    }

    void age_gender_detection::enqueue( const cv::Mat &face )
    {
        if( !enabled() )
            return;
        if( !_request )
            _request = net.CreateInferRequestPtr();

        Blob::Ptr inputBlob = _request->GetBlob( input );
        matU8ToBlob<uint8_t>( face, inputBlob, _n_enqued_frames );

        ++_n_enqued_frames;
    }

    age_gender_detection::Result age_gender_detection::operator[] (int idx) const
    {
        Blob::Ptr  genderBlob = _request->GetBlob( outputGender );
        Blob::Ptr  ageBlob = _request->GetBlob( outputAge );

        age_gender_detection::Result r = {
            ageBlob->buffer().as<float*>()[idx] * 100,
            genderBlob->buffer().as<float*>()[idx * 2 + 1]
        };
        if (doRawOutputMessages)
            LOG(DEBUG) << "element" << idx << ", male prob = " << r.maleProb << ", age = " << r.age;

        return r;
    }

    CNNNetwork age_gender_detection::read_network()
    {
        LOG(INFO) << "Loading " << topoName << " model from: " << pathToModel;

        CNNNetwork network;

#ifdef OPENVINO2019
        CNNNetReader netReader;

        /** Read network model **/
        netReader.ReadNetwork( pathToModel );
        network = netReader.getNetwork();

        /** Extract model name and load its weights **/
        std::string binFileName = remove_ext( pathToModel ) + ".bin";
        netReader.ReadWeights( binFileName );
#else
        InferenceEngine::Core ie;
        /** Read network model **/
        network = ie.ReadNetwork(pathToModel);
#endif

        /** Set batch size **/
        //LOG(DEBUG) << "Batch size is set to " << maxBatch;
        network.setBatchSize(maxBatch);

        // Age/Gender Recognition network should have one input and two outputs

        LOG(DEBUG) << "Checking Age/Gender Recognition network inputs";
        InputsDataMap inputInfo(network.getInputsInfo());
        if (inputInfo.size() != 1)
            throw std::logic_error("Age/Gender Recognition network should have only one input");
        InputInfo::Ptr& inputInfoFirst = inputInfo.begin()->second;
        inputInfoFirst->setPrecision(Precision::U8);
        input = inputInfo.begin()->first;

        LOG(DEBUG) << "Checking Age/Gender Recognition network outputs";
        OutputsDataMap outputInfo(network.getOutputsInfo());
        if (outputInfo.size() != 2)
            throw std::logic_error("Age/Gender Recognition network should have two output layers");
        auto it = outputInfo.begin();

        DataPtr ptrAgeOutput = (it++)->second;
        DataPtr ptrGenderOutput = (it++)->second;

        if (!ptrAgeOutput)
            throw std::logic_error("Age output data pointer is not valid");
        if (!ptrGenderOutput)
            throw std::logic_error("Gender output data pointer is not valid");

#ifdef OPENVINO2019
        auto genderCreatorLayer = ptrGenderOutput->getCreatorLayer().lock();
        auto ageCreatorLayer = ptrAgeOutput->getCreatorLayer().lock();

        if (!ageCreatorLayer)
            throw std::logic_error("Age creator layer pointer is not valid");
        if (!genderCreatorLayer)
            throw std::logic_error("Gender creator layer pointer is not valid");

        // if gender output is convolution, it can be swapped with age
        if (genderCreatorLayer->type == "Convolution")
            std::swap(ptrAgeOutput, ptrGenderOutput);

        if (ptrAgeOutput->getCreatorLayer().lock()->type != "Convolution")
            throw std::logic_error("In Age/Gender Recognition network, age layer (" + ageCreatorLayer->name +
                ") should be a Convolution, but was: " + ageCreatorLayer->type);

        if (ptrGenderOutput->getCreatorLayer().lock()->type != "SoftMax")
            throw std::logic_error("In Age/Gender Recognition network, gender layer (" + genderCreatorLayer->name +
                ") should be a SoftMax, but was: " + genderCreatorLayer->type);

        if (doRawOutputMessages)
        {
            LOG(DEBUG) << "Age layer: " << ageCreatorLayer->name;
            LOG(DEBUG) << "Gender layer: " << genderCreatorLayer->name;
        }
#else
#ifdef OPENVINO_NGRAPH
        if (auto ngraphFunction = network.getFunction())
        {
            // Looking for the age and gender nodes in the ngraph: the age layer node should be Convolution type.
            // If we find ptrGenderOutput is with Convolution type, swap them.
            for (const auto& op : ngraphFunction->get_ops())
            {
                std::string friendly_name = op->get_friendly_name();
                std::string output_type = op->get_type_name();

                if ((friendly_name.find(ptrGenderOutput->getName()) != std::string::npos) && (output_type == "Convolution"))
                {
                    std::swap(ptrAgeOutput, ptrGenderOutput);
                    break;
                }
            }

            bool outputAgeOk = false;

            for (const auto& op : ngraphFunction->get_ops())
            {
                std::string friendly_name = op->get_friendly_name();
                std::string output_type = op->get_type_name();

                if ((friendly_name.find(ptrAgeOutput->getName()) != std::string::npos) && (output_type == "Convolution")) {
                    outputAgeOk = true;
                    break;
                }
            }

            if (!outputAgeOk)
            {
                throw std::logic_error("In Age/Gender Recognition network, Age layer (" + ptrAgeOutput->getName() + ") should be a Convolution");
            }

            bool outputGenderOk = false;

            for (const auto& op : ngraphFunction->get_ops()) {
                std::string friendly_name = op->get_friendly_name();
                std::string output_type = op->get_type_name();

                if ((friendly_name.find(ptrGenderOutput->getName()) != std::string::npos) && (output_type == "Softmax")) {
                    outputGenderOk = true;
                    break;
                }
            }

            if (!outputGenderOk)
            {
                throw std::logic_error("In Age/Gender Recognition network, Gender layer (" + ptrGenderOutput->getName() + ") should be a Softmax");
            }
        }

        if (doRawOutputMessages)
        {
            LOG(DEBUG) << "Age layer: " << ptrAgeOutput->getName();
            LOG(DEBUG) << "Gender layer: " << ptrGenderOutput->getName();
        }
#endif
#endif

        outputAge = ptrAgeOutput->getName();
        outputGender = ptrGenderOutput->getName();

        _enabled = true;
        return network;
    }
}
<|endoftext|>