<commit_before>/*
 * THE NEW CHRONOTEXT TOOLKIT: https://github.com/arielm/new-chronotext-toolkit
 * COPYRIGHT (C) 2012-2015, ARIEL MALKA ALL RIGHTS RESERVED.
 *
 * THE FOLLOWING SOURCE-CODE IS DISTRIBUTED UNDER THE SIMPLIFIED BSD LICENSE:
 * https://github.com/arielm/new-chronotext-toolkit/blob/master/LICENSE.md
 */

#include "emscripten/CrossDelegate.h"
#include "cross/Context.h"

using namespace std;

namespace chr
{
    namespace intern
    {
        CrossDelegate *instance = nullptr;
    }

    CrossDelegate& delegate()
    {
        return checkedReference(intern::instance);
    }

    // ---

    bool CrossDelegate::performInit()
    {
        if (!initialized_)
        {
            emscripten_set_mousedown_callback(0, 0, 1, mouseCallback);
            emscripten_set_mouseup_callback(0, 0, 1, mouseCallback);
            emscripten_set_mousemove_callback(0, 0, 1, mouseCallback);

            // ---

            if (initInfo.windowInfo.size.x * initInfo.windowInfo.size.y == 0)
            {
                int innerWidth = EM_ASM_INT_V("return window.innerWidth");
                int innerHeight = EM_ASM_INT_V("return window.innerHeight");
                emscripten_set_canvas_size(innerWidth, innerHeight);

                setupInfo.windowInfo = WindowInfo(innerWidth, innerHeight, initInfo.windowInfo.aaSamples);
            }
            else
            {
                setupInfo.windowInfo = WindowInfo(initInfo.windowInfo.size.x, initInfo.windowInfo.size.y, initInfo.windowInfo.aaSamples);
                emscripten_set_canvas_size(initInfo.windowInfo.size.x, initInfo.windowInfo.size.y);
            }

            EmscriptenWebGLContextAttributes attr;
            emscripten_webgl_init_context_attributes(&attr);

            attr.alpha = attr.depth = attr.stencil = attr.preserveDrawingBuffer = attr.preferLowPowerToHighPerformance = attr.failIfMajorPerformanceCaveat = 0;
            attr.enableExtensionsByDefault = 1;
            attr.antialias = (initInfo.windowInfo.aaSamples > 0) ? 1 : 0;
            attr.premultipliedAlpha = 0;
            attr.majorVersion = 1;
            attr.minorVersion = 0;

            EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(0, &attr);
            emscripten_webgl_make_context_current(ctx);

            // ---

            intern::instance = this;
            initialized_ = _init();
        }

        return initialized_;
    }

    void CrossDelegate::performUninit()
    {
        if (initialized_ && !setup_)
        {
            _uninit();

            initialized_ = false;
            intern::instance = nullptr;
        }
    }

    void CrossDelegate::performSetup()
    {
        if (!setup_ && initialized_)
        {
            _setup();

            // ---

            setup_ = true;
        }
    }

    void CrossDelegate::performShutdown()
    {
        if (setup_)
        {
            _shutdown();

            // ---

            setup_ = false;
        }
    }

    void CrossDelegate::performResize(const glm::vec2 &size)
    {
        setupInfo.windowInfo.size = size;
        sketch->performResize(size);
    }

    void CrossDelegate::performUpdate()
    {
        /*
         * SUBSEQUENT CALLS TO FrameClock::getTime() DURING THE FRAME WILL RETURN THE SAME TIME-SAMPLE
         */
        sketch->clock()->update(true);

        sketch->performUpdate();
        updateCount++;
    }

    void CrossDelegate::performDraw()
    {
        sketch->draw();
    }

    void CrossDelegate::run(int width, int height, int aaSamples)
    {
        initInfo.windowInfo = WindowInfo(width, height, aaSamples);

        performInit();
        performSetup();
        performResize(setupInfo.windowInfo.size);

        sketch->performStart(CrossSketch::START_REASON_VIEW_SHOWN);

        emscripten_set_main_loop(mainLoopCallback, 0, 1);

        sketch->performStop(CrossSketch::STOP_REASON_VIEW_HIDDEN);

        performShutdown();
        performUninit();
    }

    void CrossDelegate::processMouseEvents()
    {
        for (auto &event : mouseEvents)
        {
            switch (event.kind)
            {
                case MouseEvent::KIND_PRESSED:
                    sketch->addTouch(event.button, event.x, event.y);
                    break;

                case MouseEvent::KIND_DRAGGED:
                    sketch->updateTouch(event.button, event.x, event.y);
                    break;

                case MouseEvent::KIND_RELEASED:
                    sketch->removeTouch(event.button, event.x, event.y);
                    break;

                default:
                    break;
            }
        }
    }

    void CrossDelegate::clearMouseEvents()
    {
        mouseEvents.clear();
    }

    void CrossDelegate::mainLoopCallback()
    {
        intern::instance->processMouseEvents();

        intern::instance->performUpdate();
        intern::instance->performDraw();

        intern::instance->clearMouseEvents();
    }

    EM_BOOL CrossDelegate::mouseCallback(int eventType, const EmscriptenMouseEvent *e, void *userData)
    {
        switch (eventType)
        {
            case EMSCRIPTEN_EVENT_MOUSEDOWN:
            {
                intern::instance->mouseEvents.emplace_back(intern::instance->mouseX, intern::instance->mouseY, e->button, MouseEvent::KIND_PRESSED);

                intern::instance->mouseButton = e->button;
                intern::instance->mousePressed = true;
                break;
            }

            case EMSCRIPTEN_EVENT_MOUSEUP:
            {
                intern::instance->mouseEvents.emplace_back(intern::instance->mouseX, intern::instance->mouseY, e->button, MouseEvent::KIND_RELEASED);

                intern::instance->mouseButton = e->button;
                intern::instance->mousePressed = false;
                break;
            }

            case EMSCRIPTEN_EVENT_MOUSEMOVE:
            {
                intern::instance->mouseEvents.emplace_back(e->clientX, e->clientY, intern::instance->mouseButton, intern::instance->mousePressed ? MouseEvent::KIND_DRAGGED : MouseEvent::KIND_MOVED);

                intern::instance->mouseX = e->clientX;
                intern::instance->mouseY = e->clientY;
                break;
            }
        }

        return 0;
    }
}
<commit_msg>UNIFICATION...<commit_after>/*
 * THE NEW CHRONOTEXT TOOLKIT: https://github.com/arielm/new-chronotext-toolkit
 * COPYRIGHT (C) 2012-2015, ARIEL MALKA ALL RIGHTS RESERVED.
 *
 * THE FOLLOWING SOURCE-CODE IS DISTRIBUTED UNDER THE SIMPLIFIED BSD LICENSE:
 * https://github.com/arielm/new-chronotext-toolkit/blob/master/LICENSE.md
 */

#include "emscripten/CrossDelegate.h"
#include "cross/Context.h"

using namespace std;

namespace chr
{
    namespace intern
    {
        CrossDelegate *instance = nullptr;
    }

    CrossDelegate& delegate()
    {
        return checkedReference(intern::instance);
    }

    // ---

    bool CrossDelegate::performInit()
    {
        if (!initialized_)
        {
            emscripten_set_mousedown_callback(0, 0, 1, mouseCallback);
            emscripten_set_mouseup_callback(0, 0, 1, mouseCallback);
            emscripten_set_mousemove_callback(0, 0, 1, mouseCallback);

            // ---

            int targetWidth;
            int targetHeight;

            if (initInfo.windowInfo.size.x * initInfo.windowInfo.size.y == 0)
            {
                targetWidth = EM_ASM_INT_V("return window.innerWidth");
                targetHeight = EM_ASM_INT_V("return window.innerHeight");
            }
            else
            {
                targetWidth = initInfo.windowInfo.size.x;
                targetHeight = initInfo.windowInfo.size.y;
            }

            setupInfo.windowInfo = WindowInfo(targetWidth, targetHeight, initInfo.windowInfo.aaSamples);
            emscripten_set_canvas_size(targetWidth, targetHeight);

            // ---

            EmscriptenWebGLContextAttributes attr;
            emscripten_webgl_init_context_attributes(&attr);

            attr.alpha = attr.depth = attr.stencil = attr.preserveDrawingBuffer = attr.preferLowPowerToHighPerformance = attr.failIfMajorPerformanceCaveat = 0;
            attr.enableExtensionsByDefault = 1;
            attr.antialias = (initInfo.windowInfo.aaSamples > 0) ? 1 : 0;
            attr.premultipliedAlpha = 0;
            attr.majorVersion = 1;
            attr.minorVersion = 0;

            EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(0, &attr);
            emscripten_webgl_make_context_current(ctx);

            // ---

            intern::instance = this;
            initialized_ = _init();
        }

        return initialized_;
    }

    void CrossDelegate::performUninit()
    {
        if (initialized_ && !setup_)
        {
            _uninit();

            initialized_ = false;
            intern::instance = nullptr;
        }
    }

    void CrossDelegate::performSetup()
    {
        if (!setup_ && initialized_)
        {
            _setup();

            // ---

            setup_ = true;
        }
    }

    void CrossDelegate::performShutdown()
    {
        if (setup_)
        {
            _shutdown();

            // ---

            setup_ = false;
        }
    }

    void CrossDelegate::performResize(const glm::vec2 &size)
    {
        setupInfo.windowInfo.size = size;
        sketch->performResize(size);
    }

    void CrossDelegate::performUpdate()
    {
        /*
         * SUBSEQUENT CALLS TO FrameClock::getTime() DURING THE FRAME WILL RETURN THE SAME TIME-SAMPLE
         */
        sketch->clock()->update(true);

        sketch->performUpdate();
        updateCount++;
    }

    void CrossDelegate::performDraw()
    {
        sketch->draw();
    }

    void CrossDelegate::run(int width, int height, int aaSamples)
    {
        initInfo.windowInfo = WindowInfo(width, height, aaSamples);

        performInit();
        performSetup();
        performResize(setupInfo.windowInfo.size);

        sketch->performStart(CrossSketch::START_REASON_VIEW_SHOWN);

        emscripten_set_main_loop(mainLoopCallback, 0, 1);

        sketch->performStop(CrossSketch::STOP_REASON_VIEW_HIDDEN);

        performShutdown();
        performUninit();
    }

    void CrossDelegate::processMouseEvents()
    {
        for (auto &event : mouseEvents)
        {
            switch (event.kind)
            {
                case MouseEvent::KIND_PRESSED:
                    sketch->addTouch(event.button, event.x, event.y);
                    break;

                case MouseEvent::KIND_DRAGGED:
                    sketch->updateTouch(event.button, event.x, event.y);
                    break;

                case MouseEvent::KIND_RELEASED:
                    sketch->removeTouch(event.button, event.x, event.y);
                    break;

                default:
                    break;
            }
        }
    }

    void CrossDelegate::clearMouseEvents()
    {
        mouseEvents.clear();
    }

    void CrossDelegate::mainLoopCallback()
    {
        intern::instance->processMouseEvents();

        intern::instance->performUpdate();
        intern::instance->performDraw();

        intern::instance->clearMouseEvents();
    }

    EM_BOOL CrossDelegate::mouseCallback(int eventType, const EmscriptenMouseEvent *e, void *userData)
    {
        switch (eventType)
        {
            case EMSCRIPTEN_EVENT_MOUSEDOWN:
            {
                intern::instance->mouseEvents.emplace_back(intern::instance->mouseX, intern::instance->mouseY, e->button, MouseEvent::KIND_PRESSED);

                intern::instance->mouseButton = e->button;
                intern::instance->mousePressed = true;
                break;
            }

            case EMSCRIPTEN_EVENT_MOUSEUP:
            {
                intern::instance->mouseEvents.emplace_back(intern::instance->mouseX, intern::instance->mouseY, e->button, MouseEvent::KIND_RELEASED);

                intern::instance->mouseButton = e->button;
                intern::instance->mousePressed = false;
                break;
            }

            case EMSCRIPTEN_EVENT_MOUSEMOVE:
            {
                intern::instance->mouseEvents.emplace_back(e->clientX, e->clientY, intern::instance->mouseButton, intern::instance->mousePressed ? MouseEvent::KIND_DRAGGED : MouseEvent::KIND_MOVED);

                intern::instance->mouseX = e->clientX;
                intern::instance->mouseY = e->clientY;
                break;
            }
        }

        return 0;
    }
}
<|endoftext|>


<commit_before>//===- Loads.cpp - Local load analysis ------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines simple local analyses for load instructions.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/Loads.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/DataLayout.h"
#include "llvm/GlobalAlias.h"
#include "llvm/GlobalVariable.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/LLVMContext.h"
#include "llvm/Operator.h"
using namespace llvm;

/// AreEquivalentAddressValues - Test if A and B will obviously have the same
/// value. This includes recognizing that %t0 and %t1 will have the same
/// value in code like this:
///   %t0 = getelementptr \@a, 0, 3
///   store i32 0, i32* %t0
///   %t1 = getelementptr \@a, 0, 3
///   %t2 = load i32* %t1
///
static bool AreEquivalentAddressValues(const Value *A, const Value *B) {
  // Test if the values are trivially equivalent.
  if (A == B) return true;

  // Test if the values come from identical arithmetic instructions.
  // Use isIdenticalToWhenDefined instead of isIdenticalTo because
  // this function is only used when one address use dominates the
  // other, which means that they'll always either have the same
  // value or one of them will have an undefined value.
  if (isa<BinaryOperator>(A) || isa<CastInst>(A) ||
      isa<PHINode>(A) || isa<GetElementPtrInst>(A))
    if (const Instruction *BI = dyn_cast<Instruction>(B))
      if (cast<Instruction>(A)->isIdenticalToWhenDefined(BI))
        return true;

  // Otherwise they may not be equivalent.
  return false;
}

/// getUnderlyingObjectWithOffset - Strip off up to MaxLookup GEPs and
/// bitcasts to get back to the underlying object being addressed, keeping
/// track of the offset in bytes from the GEPs relative to the result.
/// This is closely related to GetUnderlyingObject but is located
/// here to avoid making VMCore depend on DataLayout.
static Value *getUnderlyingObjectWithOffset(Value *V, const DataLayout *TD,
                                            uint64_t &ByteOffset,
                                            unsigned MaxLookup = 6) {
  if (!V->getType()->isPointerTy())
    return V;
  for (unsigned Count = 0; MaxLookup == 0 || Count < MaxLookup; ++Count) {
    if (GEPOperator *GEP = dyn_cast<GEPOperator>(V)) {
      if (!GEP->hasAllConstantIndices())
        return V;
      SmallVector<Value*, 8> Indices(GEP->op_begin() + 1, GEP->op_end());
      ByteOffset += TD->getIndexedOffset(GEP->getPointerOperandType(),
                                         Indices);
      V = GEP->getPointerOperand();
    } else if (Operator::getOpcode(V) == Instruction::BitCast) {
      V = cast<Operator>(V)->getOperand(0);
    } else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(V)) {
      if (GA->mayBeOverridden())
        return V;
      V = GA->getAliasee();
    } else {
      return V;
    }
    assert(V->getType()->isPointerTy() && "Unexpected operand type!");
  }
  return V;
}

/// isSafeToLoadUnconditionally - Return true if we know that executing a load
/// from this value cannot trap.  If it is not obviously safe to load from the
/// specified pointer, we do a quick local scan of the basic block containing
/// ScanFrom, to determine if the address is already accessed.
bool llvm::isSafeToLoadUnconditionally(Value *V, Instruction *ScanFrom,
                                       unsigned Align, const DataLayout *TD) {
  uint64_t ByteOffset = 0;
  Value *Base = V;
  if (TD)
    Base = getUnderlyingObjectWithOffset(V, TD, ByteOffset);

  Type *BaseType = 0;
  unsigned BaseAlign = 0;
  if (const AllocaInst *AI = dyn_cast<AllocaInst>(Base)) {
    // An alloca is safe to load from as load as it is suitably aligned.
    BaseType = AI->getAllocatedType();
    BaseAlign = AI->getAlignment();
  } else if (const GlobalValue *GV = dyn_cast<GlobalValue>(Base)) {
    // Global variables are safe to load from but their size cannot be
    // guaranteed if they are overridden.
    if (!isa<GlobalAlias>(GV) && !GV->mayBeOverridden()) {
      BaseType = GV->getType()->getElementType();
      BaseAlign = GV->getAlignment();
    }
  }

  if (BaseType && BaseType->isSized()) {
    if (TD && BaseAlign == 0)
      BaseAlign = TD->getPrefTypeAlignment(BaseType);

    if (Align <= BaseAlign) {
      if (!TD)
        return true; // Loading directly from an alloca or global is OK.

      // Check if the load is within the bounds of the underlying object.
      PointerType *AddrTy = cast<PointerType>(V->getType());
      uint64_t LoadSize = TD->getTypeStoreSize(AddrTy->getElementType());
      if (ByteOffset + LoadSize <= TD->getTypeAllocSize(BaseType) &&
          (Align == 0 || (ByteOffset % Align) == 0))
        return true;
    }
  }

  // Otherwise, be a little bit aggressive by scanning the local block where we
  // want to check to see if the pointer is already being loaded or stored
  // from/to.  If so, the previous load or store would have already trapped,
  // so there is no harm doing an extra load (also, CSE will later eliminate
  // the load entirely).
  BasicBlock::iterator BBI = ScanFrom, E = ScanFrom->getParent()->begin();

  while (BBI != E) {
    --BBI;

    // If we see a free or a call which may write to memory (i.e. which might do
    // a free) the pointer could be marked invalid.
    if (isa<CallInst>(BBI) && BBI->mayWriteToMemory() &&
        !isa<DbgInfoIntrinsic>(BBI))
      return false;

    if (LoadInst *LI = dyn_cast<LoadInst>(BBI)) {
      if (AreEquivalentAddressValues(LI->getOperand(0), V)) return true;
    } else if (StoreInst *SI = dyn_cast<StoreInst>(BBI)) {
      if (AreEquivalentAddressValues(SI->getOperand(1), V)) return true;
    }
  }
  return false;
}

/// FindAvailableLoadedValue - Scan the ScanBB block backwards (starting at the
/// instruction before ScanFrom) checking to see if we have the value at the
/// memory address *Ptr locally available within a small number of instructions.
/// If the value is available, return it.
///
/// If not, return the iterator for the last validated instruction that the
/// value would be live through.  If we scanned the entire block and didn't find
/// something that invalidates *Ptr or provides it, ScanFrom would be left at
/// begin() and this returns null.  ScanFrom could also be left
///
/// MaxInstsToScan specifies the maximum instructions to scan in the block.  If
/// it is set to 0, it will scan the whole block. You can also optionally
/// specify an alias analysis implementation, which makes this more precise.
///
/// If TBAATag is non-null and a load or store is found, the TBAA tag from the
/// load or store is recorded there.  If there is no TBAA tag or if no access
/// is found, it is left unmodified.
Value *llvm::FindAvailableLoadedValue(Value *Ptr, BasicBlock *ScanBB,
                                      BasicBlock::iterator &ScanFrom,
                                      unsigned MaxInstsToScan,
                                      AliasAnalysis *AA,
                                      MDNode **TBAATag) {
  if (MaxInstsToScan == 0) MaxInstsToScan = ~0U;

  // If we're using alias analysis to disambiguate get the size of *Ptr.
  uint64_t AccessSize = 0;
  if (AA) {
    Type *AccessTy = cast<PointerType>(Ptr->getType())->getElementType();
    AccessSize = AA->getTypeStoreSize(AccessTy);
  }

  while (ScanFrom != ScanBB->begin()) {
    // We must ignore debug info directives when counting (otherwise they
    // would affect codegen).
    Instruction *Inst = --ScanFrom;
    if (isa<DbgInfoIntrinsic>(Inst))
      continue;

    // Restore ScanFrom to expected value in case next test succeeds
    ScanFrom++;

    // Don't scan huge blocks.
    if (MaxInstsToScan-- == 0) return 0;

    --ScanFrom;
    // If this is a load of Ptr, the loaded value is available.
    // (This is true even if the load is volatile or atomic, although
    // those cases are unlikely.)
    if (LoadInst *LI = dyn_cast<LoadInst>(Inst))
      if (AreEquivalentAddressValues(LI->getOperand(0), Ptr)) {
        if (TBAATag) *TBAATag = LI->getMetadata(LLVMContext::MD_tbaa);
        return LI;
      }

    if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) {
      // If this is a store through Ptr, the value is available!
      // (This is true even if the store is volatile or atomic, although
      // those cases are unlikely.)
      if (AreEquivalentAddressValues(SI->getOperand(1), Ptr)) {
        if (TBAATag) *TBAATag = SI->getMetadata(LLVMContext::MD_tbaa);
        return SI->getOperand(0);
      }

      // If Ptr is an alloca and this is a store to a different alloca, ignore
      // the store.  This is a trivial form of alias analysis that is important
      // for reg2mem'd code.
      if ((isa<AllocaInst>(Ptr) || isa<GlobalVariable>(Ptr)) &&
          (isa<AllocaInst>(SI->getOperand(1)) ||
           isa<GlobalVariable>(SI->getOperand(1))))
        continue;

      // If we have alias analysis and it says the store won't modify the loaded
      // value, ignore the store.
      if (AA &&
          (AA->getModRefInfo(SI, Ptr, AccessSize) & AliasAnalysis::Mod) == 0)
        continue;

      // Otherwise the store that may or may not alias the pointer, bail out.
      ++ScanFrom;
      return 0;
    }

    // If this is some other instruction that may clobber Ptr, bail out.
    if (Inst->mayWriteToMemory()) {
      // If alias analysis claims that it really won't modify the load,
      // ignore it.
      if (AA &&
          (AA->getModRefInfo(Inst, Ptr, AccessSize) & AliasAnalysis::Mod) == 0)
        continue;

      // May modify the pointer, bail out.
      ++ScanFrom;
      return 0;
    }
  }

  // Got to the start of the block, we didn't find it, but are done for this
  // block.
  return 0;
}
<commit_msg>use ValueTracking's GetPointerBaseWithConstantOffset() function instead of a local implementation<commit_after>//===- Loads.cpp - Local load analysis ------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines simple local analyses for load instructions.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/Loads.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/DataLayout.h"
#include "llvm/GlobalAlias.h"
#include "llvm/GlobalVariable.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/LLVMContext.h"
#include "llvm/Operator.h"
using namespace llvm;

/// AreEquivalentAddressValues - Test if A and B will obviously have the same
/// value. This includes recognizing that %t0 and %t1 will have the same
/// value in code like this:
///   %t0 = getelementptr \@a, 0, 3
///   store i32 0, i32* %t0
///   %t1 = getelementptr \@a, 0, 3
///   %t2 = load i32* %t1
///
static bool AreEquivalentAddressValues(const Value *A, const Value *B) {
  // Test if the values are trivially equivalent.
  if (A == B) return true;

  // Test if the values come from identical arithmetic instructions.
  // Use isIdenticalToWhenDefined instead of isIdenticalTo because
  // this function is only used when one address use dominates the
  // other, which means that they'll always either have the same
  // value or one of them will have an undefined value.
  if (isa<BinaryOperator>(A) || isa<CastInst>(A) ||
      isa<PHINode>(A) || isa<GetElementPtrInst>(A))
    if (const Instruction *BI = dyn_cast<Instruction>(B))
      if (cast<Instruction>(A)->isIdenticalToWhenDefined(BI))
        return true;

  // Otherwise they may not be equivalent.
  return false;
}

/// isSafeToLoadUnconditionally - Return true if we know that executing a load
/// from this value cannot trap.  If it is not obviously safe to load from the
/// specified pointer, we do a quick local scan of the basic block containing
/// ScanFrom, to determine if the address is already accessed.
bool llvm::isSafeToLoadUnconditionally(Value *V, Instruction *ScanFrom,
                                       unsigned Align, const DataLayout *TD) {
  int64_t ByteOffset = 0;
  Value *Base = V;
  if (TD)
    Base = GetPointerBaseWithConstantOffset(V, ByteOffset, *TD);

  if (ByteOffset < 0) // out of bounds
    return false;

  Type *BaseType = 0;
  unsigned BaseAlign = 0;
  if (const AllocaInst *AI = dyn_cast<AllocaInst>(Base)) {
    // An alloca is safe to load from as load as it is suitably aligned.
    BaseType = AI->getAllocatedType();
    BaseAlign = AI->getAlignment();
  } else if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Base)) {
    // Global variables are safe to load from but their size cannot be
    // guaranteed if they are overridden.
    if (!GV->mayBeOverridden()) {
      BaseType = GV->getType()->getElementType();
      BaseAlign = GV->getAlignment();
    }
  }

  if (BaseType && BaseType->isSized()) {
    if (TD && BaseAlign == 0)
      BaseAlign = TD->getPrefTypeAlignment(BaseType);

    if (Align <= BaseAlign) {
      if (!TD)
        return true; // Loading directly from an alloca or global is OK.

      // Check if the load is within the bounds of the underlying object.
      PointerType *AddrTy = cast<PointerType>(V->getType());
      uint64_t LoadSize = TD->getTypeStoreSize(AddrTy->getElementType());
      if (ByteOffset + LoadSize <= TD->getTypeAllocSize(BaseType) &&
          (Align == 0 || (ByteOffset % Align) == 0))
        return true;
    }
  }

  // Otherwise, be a little bit aggressive by scanning the local block where we
  // want to check to see if the pointer is already being loaded or stored
  // from/to.  If so, the previous load or store would have already trapped,
  // so there is no harm doing an extra load (also, CSE will later eliminate
  // the load entirely).
  BasicBlock::iterator BBI = ScanFrom, E = ScanFrom->getParent()->begin();

  while (BBI != E) {
    --BBI;

    // If we see a free or a call which may write to memory (i.e. which might do
    // a free) the pointer could be marked invalid.
    if (isa<CallInst>(BBI) && BBI->mayWriteToMemory() &&
        !isa<DbgInfoIntrinsic>(BBI))
      return false;

    if (LoadInst *LI = dyn_cast<LoadInst>(BBI)) {
      if (AreEquivalentAddressValues(LI->getOperand(0), V)) return true;
    } else if (StoreInst *SI = dyn_cast<StoreInst>(BBI)) {
      if (AreEquivalentAddressValues(SI->getOperand(1), V)) return true;
    }
  }
  return false;
}

/// FindAvailableLoadedValue - Scan the ScanBB block backwards (starting at the
/// instruction before ScanFrom) checking to see if we have the value at the
/// memory address *Ptr locally available within a small number of instructions.
/// If the value is available, return it.
///
/// If not, return the iterator for the last validated instruction that the
/// value would be live through.  If we scanned the entire block and didn't find
/// something that invalidates *Ptr or provides it, ScanFrom would be left at
/// begin() and this returns null.  ScanFrom could also be left
///
/// MaxInstsToScan specifies the maximum instructions to scan in the block.  If
/// it is set to 0, it will scan the whole block. You can also optionally
/// specify an alias analysis implementation, which makes this more precise.
///
/// If TBAATag is non-null and a load or store is found, the TBAA tag from the
/// load or store is recorded there.  If there is no TBAA tag or if no access
/// is found, it is left unmodified.
Value *llvm::FindAvailableLoadedValue(Value *Ptr, BasicBlock *ScanBB,
                                      BasicBlock::iterator &ScanFrom,
                                      unsigned MaxInstsToScan,
                                      AliasAnalysis *AA,
                                      MDNode **TBAATag) {
  if (MaxInstsToScan == 0) MaxInstsToScan = ~0U;

  // If we're using alias analysis to disambiguate get the size of *Ptr.
  uint64_t AccessSize = 0;
  if (AA) {
    Type *AccessTy = cast<PointerType>(Ptr->getType())->getElementType();
    AccessSize = AA->getTypeStoreSize(AccessTy);
  }

  while (ScanFrom != ScanBB->begin()) {
    // We must ignore debug info directives when counting (otherwise they
    // would affect codegen).
    Instruction *Inst = --ScanFrom;
    if (isa<DbgInfoIntrinsic>(Inst))
      continue;

    // Restore ScanFrom to expected value in case next test succeeds
    ScanFrom++;

    // Don't scan huge blocks.
    if (MaxInstsToScan-- == 0) return 0;

    --ScanFrom;
    // If this is a load of Ptr, the loaded value is available.
    // (This is true even if the load is volatile or atomic, although
    // those cases are unlikely.)
    if (LoadInst *LI = dyn_cast<LoadInst>(Inst))
      if (AreEquivalentAddressValues(LI->getOperand(0), Ptr)) {
        if (TBAATag) *TBAATag = LI->getMetadata(LLVMContext::MD_tbaa);
        return LI;
      }

    if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) {
      // If this is a store through Ptr, the value is available!
      // (This is true even if the store is volatile or atomic, although
      // those cases are unlikely.)
      if (AreEquivalentAddressValues(SI->getOperand(1), Ptr)) {
        if (TBAATag) *TBAATag = SI->getMetadata(LLVMContext::MD_tbaa);
        return SI->getOperand(0);
      }

      // If Ptr is an alloca and this is a store to a different alloca, ignore
      // the store.  This is a trivial form of alias analysis that is important
      // for reg2mem'd code.
      if ((isa<AllocaInst>(Ptr) || isa<GlobalVariable>(Ptr)) &&
          (isa<AllocaInst>(SI->getOperand(1)) ||
           isa<GlobalVariable>(SI->getOperand(1))))
        continue;

      // If we have alias analysis and it says the store won't modify the loaded
      // value, ignore the store.
      if (AA &&
          (AA->getModRefInfo(SI, Ptr, AccessSize) & AliasAnalysis::Mod) == 0)
        continue;

      // Otherwise the store that may or may not alias the pointer, bail out.
      ++ScanFrom;
      return 0;
    }

    // If this is some other instruction that may clobber Ptr, bail out.
    if (Inst->mayWriteToMemory()) {
      // If alias analysis claims that it really won't modify the load,
      // ignore it.
      if (AA &&
          (AA->getModRefInfo(Inst, Ptr, AccessSize) & AliasAnalysis::Mod) == 0)
        continue;

      // May modify the pointer, bail out.
      ++ScanFrom;
      return 0;
    }
  }

  // Got to the start of the block, we didn't find it, but are done for this
  // block.
  return 0;
}
<|endoftext|>


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

#include "ITFReader.h"
#include <zxing/oned/OneDResultPoint.h>
#include <zxing/common/Array.h>
#include <zxing/ReaderException.h>
#include <math.h>

namespace zxing {
  namespace oned {

    static const int W = 3; // Pixel width of a wide line
    static const int N = 1; // Pixed width of a narrow line

    const int DEFAULT_ALLOWED_LENGTHS[4] = { 6, 10, 14, 44 };

    /**
     * Start/end guard pattern.
     *
     * Note: The end pattern is reversed because the row is reversed before
     * searching for the END_PATTERN
     */
    static const int START_PATTERN_LEN = 4;
    static const int START_PATTERN[START_PATTERN_LEN] = {N, N, N, N};

    static const int END_PATTERN_REVERSED_LEN = 3;
    static const int END_PATTERN_REVERSED[END_PATTERN_REVERSED_LEN] = {N, N, W};

    /**
     * Patterns of Wide / Narrow lines to indicate each digit
     */
    static const int PATTERNS_LEN = 10;
    static const int PATTERNS[PATTERNS_LEN][5] = {
      {N, N, W, W, N}, // 0
      {W, N, N, N, W}, // 1
      {N, W, N, N, W}, // 2
      {W, W, N, N, N}, // 3
      {N, N, W, N, W}, // 4
      {W, N, W, N, N}, // 5
      {N, W, W, N, N}, // 6
      {N, N, N, W, W}, // 7
      {W, N, N, W, N}, // 8
      {N, W, N, W, N}  // 9
    };

    ITFReader::ITFReader() : narrowLineWidth(-1) {
    }

    Ref<Result> ITFReader::decodeRow(int rowNumber, Ref<BitArray> row) {
      int* startRange = 0;
      int* endRange = 0;
      try {
        // Find out where the Middle section (payload) starts & ends
        startRange = decodeStart(row);
        endRange = decodeEnd(row);

        std::string tmpResult;
        decodeMiddle(row, startRange[1], endRange[0], tmpResult);

        // To avoid false positives with 2D barcodes (and other patterns), make
        // an assumption that the decoded string must be 6, 10 or 14 digits.
        int length = tmpResult.length();
        bool lengthOK = false;
        if (length == 6 || length == 10 || length == 14) {
          lengthOK = true;
        }
        if (!lengthOK) {
          throw ReaderException("not enough characters count");
        }

        Ref<String> resultString(new String(tmpResult));

        std::vector< Ref<ResultPoint> > resultPoints(2);
        Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(startRange[1], (float) rowNumber));
        Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(endRange[0], (float) rowNumber));
        resultPoints[0] = resultPoint1;
        resultPoints[1] = resultPoint2;

        delete [] startRange;
        delete [] endRange;
        ArrayRef<unsigned char> resultBytes(1);
        return Ref<Result>(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_ITF));
      } catch (ReaderException re) {
        delete [] startRange;
        delete [] endRange;
        return Ref<Result>();
      }
    }

    /**
     * @param row          row of black/white values to search
     * @param payloadStart offset of start pattern
     * @param resultString {@link StringBuffer} to append decoded chars to
     * @throws ReaderException if decoding could not complete successfully
     */
    void ITFReader::decodeMiddle(Ref<BitArray> row, int payloadStart, int payloadEnd,
        std::string& resultString) {
      // Digits are interleaved in pairs - 5 black lines for one digit, and the
      // 5
      // interleaved white lines for the second digit.
      // Therefore, need to scan 10 lines and then
      // split these into two arrays
      int counterDigitPairLen = 10;
      int counterDigitPair[counterDigitPairLen];
      for (int i=0; i<counterDigitPairLen; i++) {
        counterDigitPair[i] = 0;
      }

      int counterBlack[5];
      int counterWhite[5];
      for (int i=0; i<5; i++) {
        counterBlack[i] = 0;
        counterWhite[i] = 0;
      }

      while (payloadStart < payloadEnd) {
        // Get 10 runs of black/white.
        if (!recordPattern(row, payloadStart, counterDigitPair, counterDigitPairLen)) {
          throw ReaderException("");
        }
        // Split them into each array
        for (int k = 0; k < 5; k++) {
          int twoK = k << 1;
          counterBlack[k] = counterDigitPair[twoK];
          counterWhite[k] = counterDigitPair[twoK + 1];
        }

        int bestMatch = decodeDigit(counterBlack, 5);
        resultString.append(1, (char) ('0' + bestMatch));
        bestMatch = decodeDigit(counterWhite, 5);
        resultString.append(1, (char) ('0' + bestMatch));

        for (int i = 0; i < counterDigitPairLen; i++) {
          payloadStart += counterDigitPair[i];
        }
      }
    }

    /**
     * Identify where the start of the middle / payload section starts.
     *
     * @param row row of black/white values to search
     * @return Array, containing index of start of 'start block' and end of
     *         'start block'
     * @throws ReaderException
     */
    int* ITFReader::decodeStart(Ref<BitArray> row) {
      int endStart = skipWhiteSpace(row);
      int* startPattern = 0;
      try {
          startPattern = findGuardPattern(row, endStart, START_PATTERN, START_PATTERN_LEN);

          // Determine the width of a narrow line in pixels. We can do this by
          // getting the width of the start pattern and dividing by 4 because its
          // made up of 4 narrow lines.
          narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2;
          validateQuietZone(row, startPattern[0]);
          return startPattern;
      } catch (ReaderException re) {
          delete [] startPattern;
        throw re;
      }
    }

    /**
     * Identify where the end of the middle / payload section ends.
     *
     * @param row row of black/white values to search
     * @return Array, containing index of start of 'end block' and end of 'end
     *         block'
     * @throws ReaderException
     */

    int* ITFReader::decodeEnd(Ref<BitArray> row) {
      // For convenience, reverse the row and then
      // search from 'the start' for the end block
      row->reverse();
                        int* endPattern = 0;
      try {
        int endStart = skipWhiteSpace(row);
        endPattern = findGuardPattern(row, endStart, END_PATTERN_REVERSED, END_PATTERN_REVERSED_LEN);

        // The start & end patterns must be pre/post fixed by a quiet zone. This
        // zone must be at least 10 times the width of a narrow line.
        // ref: http://www.barcode-1.net/i25code.html
        validateQuietZone(row, endPattern[0]);

        // Now recalculate the indices of where the 'endblock' starts & stops to
        // accommodate
        // the reversed nature of the search
        int temp = endPattern[0];
        endPattern[0] = row->getSize() - endPattern[1];
        endPattern[1] = row->getSize() - temp;

        row->reverse();
        return endPattern;
      } catch (ReaderException re) {
                                delete [] endPattern;
        row->reverse();
        throw re;
      }
    }

    /**
     * The start & end patterns must be pre/post fixed by a quiet zone. This
     * zone must be at least 10 times the width of a narrow line.  Scan back until
     * we either get to the start of the barcode or match the necessary number of
     * quiet zone pixels.
     *
     * Note: Its assumed the row is reversed when using this method to find
     * quiet zone after the end pattern.
     *
     * ref: http://www.barcode-1.net/i25code.html
     *
     * @param row bit array representing the scanned barcode.
     * @param startPattern index into row of the start or end pattern.
     * @throws ReaderException if the quiet zone cannot be found, a ReaderException is thrown.
     */
    void ITFReader::validateQuietZone(Ref<BitArray> row, int startPattern) {
//#pragma mark needs some corrections
//      int quietCount = narrowLineWidth * 10;  // expect to find this many pixels of quiet zone
//
//      for (int i = startPattern - 1; quietCount > 0 && i >= 0; i--) {
//        if (row->get(i)) {
//          break;
//        }
//        quietCount--;
//      }
//      if (quietCount != 0) {
//        // Unable to find the necessary number of quiet zone pixels.
//        throw ReaderException("Unable to find the necessary number of quiet zone pixels");
//      }
    }

    /**
     * Skip all whitespace until we get to the first black line.
     *
     * @param row row of black/white values to search
     * @return index of the first black line.
     * @throws ReaderException Throws exception if no black lines are found in the row
     */
    int ITFReader::skipWhiteSpace(Ref<BitArray> row) {
      int width = row->getSize();
      int endStart = 0;
      while (endStart < width) {
        if (row->get(endStart)) {
          break;
        }
        endStart++;
      }
      if (endStart == width) {
        throw ReaderException("");
      }
      return endStart;
    }

    /**
     * @param row       row of black/white values to search
     * @param rowOffset position to start search
     * @param pattern   pattern of counts of number of black and white pixels that are
     *                  being searched for as a pattern
     * @return start/end horizontal offset of guard pattern, as an array of two
     *         ints
     * @throws ReaderException if pattern is not found
     */
    int* ITFReader::findGuardPattern(Ref<BitArray> row, int rowOffset, const int pattern[],
        int patternLen) {
      // TODO: This is very similar to implementation in UPCEANReader. Consider if they can be
      // merged to a single method.
      int patternLength = patternLen;
      int counters[patternLength];
      for (int i=0; i<patternLength; i++) {
        counters[i] = 0;
      }
      int width = row->getSize();
      bool isWhite = false;

      int counterPosition = 0;
      int patternStart = rowOffset;
      for (int x = rowOffset; x < width; x++) {
        bool pixel = row->get(x);
        if (pixel ^ isWhite) {
          counters[counterPosition]++;
        } else {
          if (counterPosition == patternLength - 1) {
            if (patternMatchVariance(counters, patternLength, pattern,
                MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {
              int* resultValue = new int[2];
              resultValue[0] = patternStart;
              resultValue[1] = x;
              return resultValue;
            }
            patternStart += counters[0] + counters[1];
            for (int y = 2; y < patternLength; y++) {
              counters[y - 2] = counters[y];
            }
            counters[patternLength - 2] = 0;
            counters[patternLength - 1] = 0;
            counterPosition--;
          } else {
            counterPosition++;
          }
          counters[counterPosition] = 1;
          isWhite = !isWhite;
        }
      }
      throw ReaderException("");
    }

    /**
     * Attempts to decode a sequence of ITF black/white lines into single
     * digit.
     *
     * @param counters the counts of runs of observed black/white/black/... values
     * @return The decoded digit
     * @throws ReaderException if digit cannot be decoded
     */
    int ITFReader::decodeDigit(int counters[], int countersLen){
      unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
      int bestMatch = -1;
      int max = PATTERNS_LEN;
      for (int i = 0; i < max; i++) {
        int pattern[countersLen];
        for(int ind = 0; ind<countersLen; ind++){
          pattern[ind] = PATTERNS[i][ind];
        }
        unsigned int variance = patternMatchVariance(counters, countersLen, pattern,
            MAX_INDIVIDUAL_VARIANCE);
        if (variance < bestVariance) {
          bestVariance = variance;
          bestMatch = i;
        }
      }
      if (bestMatch >= 0) {
        return bestMatch;
      } else {
        throw ReaderException("digit didint found");
      }
    }

    ITFReader::~ITFReader(){
    }
  }
}
<commit_msg>Issue 920 add ITF length 18, make C++ consistent with Java here<commit_after>/*
 *  ITFReader.cpp
 *  ZXing
 *
 *  Copyright 2010 ZXing authors All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ITFReader.h"
#include <zxing/oned/OneDResultPoint.h>
#include <zxing/common/Array.h>
#include <zxing/ReaderException.h>
#include <math.h>

namespace zxing {
  namespace oned {

    static const int W = 3; // Pixel width of a wide line
    static const int N = 1; // Pixed width of a narrow line

    const int DEFAULT_ALLOWED_LENGTHS_LEN = 10;
    const int DEFAULT_ALLOWED_LENGTHS[DEFAULT_ALLOWED_LENGTHS_LEN] = { 44, 24, 20, 18, 16, 14, 12, 10, 8, 6 };

    /**
     * Start/end guard pattern.
     *
     * Note: The end pattern is reversed because the row is reversed before
     * searching for the END_PATTERN
     */
    static const int START_PATTERN_LEN = 4;
    static const int START_PATTERN[START_PATTERN_LEN] = {N, N, N, N};

    static const int END_PATTERN_REVERSED_LEN = 3;
    static const int END_PATTERN_REVERSED[END_PATTERN_REVERSED_LEN] = {N, N, W};

    /**
     * Patterns of Wide / Narrow lines to indicate each digit
     */
    static const int PATTERNS_LEN = 10;
    static const int PATTERNS[PATTERNS_LEN][5] = {
      {N, N, W, W, N}, // 0
      {W, N, N, N, W}, // 1
      {N, W, N, N, W}, // 2
      {W, W, N, N, N}, // 3
      {N, N, W, N, W}, // 4
      {W, N, W, N, N}, // 5
      {N, W, W, N, N}, // 6
      {N, N, N, W, W}, // 7
      {W, N, N, W, N}, // 8
      {N, W, N, W, N}  // 9
    };

    ITFReader::ITFReader() : narrowLineWidth(-1) {
    }

    Ref<Result> ITFReader::decodeRow(int rowNumber, Ref<BitArray> row) {
      int* startRange = 0;
      int* endRange = 0;
      try {
        // Find out where the Middle section (payload) starts & ends
        startRange = decodeStart(row);
        endRange = decodeEnd(row);

        std::string tmpResult;
        decodeMiddle(row, startRange[1], endRange[0], tmpResult);

        // To avoid false positives with 2D barcodes (and other patterns), make
        // an assumption that the decoded string must be a known length
        int length = tmpResult.length();
        bool lengthOK = false;
        for (int i = 0; i < DEFAULT_ALLOWED_LENGTHS_LEN; i++) {
          if (length == DEFAULT_ALLOWED_LENGTHS[i]) {
            lengthOK = true;
            break;
          }
        }
        if (!lengthOK) {
          throw ReaderException("not enough characters count");
        }

        Ref<String> resultString(new String(tmpResult));

        std::vector< Ref<ResultPoint> > resultPoints(2);
        Ref<OneDResultPoint> resultPoint1(new OneDResultPoint(startRange[1], (float) rowNumber));
        Ref<OneDResultPoint> resultPoint2(new OneDResultPoint(endRange[0], (float) rowNumber));
        resultPoints[0] = resultPoint1;
        resultPoints[1] = resultPoint2;

        delete [] startRange;
        delete [] endRange;
        ArrayRef<unsigned char> resultBytes(1);
        return Ref<Result>(new Result(resultString, resultBytes, resultPoints, BarcodeFormat_ITF));
      } catch (ReaderException re) {
        delete [] startRange;
        delete [] endRange;
        return Ref<Result>();
      }
    }

    /**
     * @param row          row of black/white values to search
     * @param payloadStart offset of start pattern
     * @param resultString {@link StringBuffer} to append decoded chars to
     * @throws ReaderException if decoding could not complete successfully
     */
    void ITFReader::decodeMiddle(Ref<BitArray> row, int payloadStart, int payloadEnd,
        std::string& resultString) {
      // Digits are interleaved in pairs - 5 black lines for one digit, and the
      // 5
      // interleaved white lines for the second digit.
      // Therefore, need to scan 10 lines and then
      // split these into two arrays
      int counterDigitPairLen = 10;
      int counterDigitPair[counterDigitPairLen];
      for (int i=0; i<counterDigitPairLen; i++) {
        counterDigitPair[i] = 0;
      }

      int counterBlack[5];
      int counterWhite[5];
      for (int i=0; i<5; i++) {
        counterBlack[i] = 0;
        counterWhite[i] = 0;
      }

      while (payloadStart < payloadEnd) {
        // Get 10 runs of black/white.
        if (!recordPattern(row, payloadStart, counterDigitPair, counterDigitPairLen)) {
          throw ReaderException("");
        }
        // Split them into each array
        for (int k = 0; k < 5; k++) {
          int twoK = k << 1;
          counterBlack[k] = counterDigitPair[twoK];
          counterWhite[k] = counterDigitPair[twoK + 1];
        }

        int bestMatch = decodeDigit(counterBlack, 5);
        resultString.append(1, (char) ('0' + bestMatch));
        bestMatch = decodeDigit(counterWhite, 5);
        resultString.append(1, (char) ('0' + bestMatch));

        for (int i = 0; i < counterDigitPairLen; i++) {
          payloadStart += counterDigitPair[i];
        }
      }
    }

    /**
     * Identify where the start of the middle / payload section starts.
     *
     * @param row row of black/white values to search
     * @return Array, containing index of start of 'start block' and end of
     *         'start block'
     * @throws ReaderException
     */
    int* ITFReader::decodeStart(Ref<BitArray> row) {
      int endStart = skipWhiteSpace(row);
      int* startPattern = 0;
      try {
          startPattern = findGuardPattern(row, endStart, START_PATTERN, START_PATTERN_LEN);

          // Determine the width of a narrow line in pixels. We can do this by
          // getting the width of the start pattern and dividing by 4 because its
          // made up of 4 narrow lines.
          narrowLineWidth = (startPattern[1] - startPattern[0]) >> 2;
          validateQuietZone(row, startPattern[0]);
          return startPattern;
      } catch (ReaderException re) {
          delete [] startPattern;
        throw re;
      }
    }

    /**
     * Identify where the end of the middle / payload section ends.
     *
     * @param row row of black/white values to search
     * @return Array, containing index of start of 'end block' and end of 'end
     *         block'
     * @throws ReaderException
     */

    int* ITFReader::decodeEnd(Ref<BitArray> row) {
      // For convenience, reverse the row and then
      // search from 'the start' for the end block
      row->reverse();
                        int* endPattern = 0;
      try {
        int endStart = skipWhiteSpace(row);
        endPattern = findGuardPattern(row, endStart, END_PATTERN_REVERSED, END_PATTERN_REVERSED_LEN);

        // The start & end patterns must be pre/post fixed by a quiet zone. This
        // zone must be at least 10 times the width of a narrow line.
        // ref: http://www.barcode-1.net/i25code.html
        validateQuietZone(row, endPattern[0]);

        // Now recalculate the indices of where the 'endblock' starts & stops to
        // accommodate
        // the reversed nature of the search
        int temp = endPattern[0];
        endPattern[0] = row->getSize() - endPattern[1];
        endPattern[1] = row->getSize() - temp;

        row->reverse();
        return endPattern;
      } catch (ReaderException re) {
                                delete [] endPattern;
        row->reverse();
        throw re;
      }
    }

    /**
     * The start & end patterns must be pre/post fixed by a quiet zone. This
     * zone must be at least 10 times the width of a narrow line.  Scan back until
     * we either get to the start of the barcode or match the necessary number of
     * quiet zone pixels.
     *
     * Note: Its assumed the row is reversed when using this method to find
     * quiet zone after the end pattern.
     *
     * ref: http://www.barcode-1.net/i25code.html
     *
     * @param row bit array representing the scanned barcode.
     * @param startPattern index into row of the start or end pattern.
     * @throws ReaderException if the quiet zone cannot be found, a ReaderException is thrown.
     */
    void ITFReader::validateQuietZone(Ref<BitArray> row, int startPattern) {
//#pragma mark needs some corrections
//      int quietCount = narrowLineWidth * 10;  // expect to find this many pixels of quiet zone
//
//      for (int i = startPattern - 1; quietCount > 0 && i >= 0; i--) {
//        if (row->get(i)) {
//          break;
//        }
//        quietCount--;
//      }
//      if (quietCount != 0) {
//        // Unable to find the necessary number of quiet zone pixels.
//        throw ReaderException("Unable to find the necessary number of quiet zone pixels");
//      }
    }

    /**
     * Skip all whitespace until we get to the first black line.
     *
     * @param row row of black/white values to search
     * @return index of the first black line.
     * @throws ReaderException Throws exception if no black lines are found in the row
     */
    int ITFReader::skipWhiteSpace(Ref<BitArray> row) {
      int width = row->getSize();
      int endStart = 0;
      while (endStart < width) {
        if (row->get(endStart)) {
          break;
        }
        endStart++;
      }
      if (endStart == width) {
        throw ReaderException("");
      }
      return endStart;
    }

    /**
     * @param row       row of black/white values to search
     * @param rowOffset position to start search
     * @param pattern   pattern of counts of number of black and white pixels that are
     *                  being searched for as a pattern
     * @return start/end horizontal offset of guard pattern, as an array of two
     *         ints
     * @throws ReaderException if pattern is not found
     */
    int* ITFReader::findGuardPattern(Ref<BitArray> row, int rowOffset, const int pattern[],
        int patternLen) {
      // TODO: This is very similar to implementation in UPCEANReader. Consider if they can be
      // merged to a single method.
      int patternLength = patternLen;
      int counters[patternLength];
      for (int i=0; i<patternLength; i++) {
        counters[i] = 0;
      }
      int width = row->getSize();
      bool isWhite = false;

      int counterPosition = 0;
      int patternStart = rowOffset;
      for (int x = rowOffset; x < width; x++) {
        bool pixel = row->get(x);
        if (pixel ^ isWhite) {
          counters[counterPosition]++;
        } else {
          if (counterPosition == patternLength - 1) {
            if (patternMatchVariance(counters, patternLength, pattern,
                MAX_INDIVIDUAL_VARIANCE) < MAX_AVG_VARIANCE) {
              int* resultValue = new int[2];
              resultValue[0] = patternStart;
              resultValue[1] = x;
              return resultValue;
            }
            patternStart += counters[0] + counters[1];
            for (int y = 2; y < patternLength; y++) {
              counters[y - 2] = counters[y];
            }
            counters[patternLength - 2] = 0;
            counters[patternLength - 1] = 0;
            counterPosition--;
          } else {
            counterPosition++;
          }
          counters[counterPosition] = 1;
          isWhite = !isWhite;
        }
      }
      throw ReaderException("");
    }

    /**
     * Attempts to decode a sequence of ITF black/white lines into single
     * digit.
     *
     * @param counters the counts of runs of observed black/white/black/... values
     * @return The decoded digit
     * @throws ReaderException if digit cannot be decoded
     */
    int ITFReader::decodeDigit(int counters[], int countersLen){
      unsigned int bestVariance = MAX_AVG_VARIANCE; // worst variance we'll accept
      int bestMatch = -1;
      int max = PATTERNS_LEN;
      for (int i = 0; i < max; i++) {
        int pattern[countersLen];
        for(int ind = 0; ind<countersLen; ind++){
          pattern[ind] = PATTERNS[i][ind];
        }
        unsigned int variance = patternMatchVariance(counters, countersLen, pattern,
            MAX_INDIVIDUAL_VARIANCE);
        if (variance < bestVariance) {
          bestVariance = variance;
          bestMatch = i;
        }
      }
      if (bestMatch >= 0) {
        return bestMatch;
      } else {
        throw ReaderException("digit didint found");
      }
    }

    ITFReader::~ITFReader(){
    }
  }
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: impltext.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: thb $ $Date: 2004-03-18 10:41:13 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include "impltext.hxx"
#include <canvas/canvastools.hxx>

#ifndef _DRAFTS_COM_SUN_STAR_RENDERING_TEXTDIRECTION_HPP__
#include <drafts/com/sun/star/rendering/TextDirection.hpp>
#endif
#ifndef _DRAFTS_COM_SUN_STAR_RENDERING_XCANVAS_HPP__
#include <drafts/com/sun/star/rendering/XCanvas.hpp>
#endif
#ifndef _DRAFTS_COM_SUN_STAR_RENDERING_STRINGCONTEXT_HPP__
#include <drafts/com/sun/star/rendering/StringContext.hpp>
#endif

#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif

#ifndef _BGFX_MATRIX_B2DHOMMATRIX_HXX
#include <basegfx/matrix/b2dhommatrix.hxx>
#endif

using namespace ::drafts::com::sun::star;
using namespace ::com::sun::star;

namespace cppcanvas
{
    namespace internal
    {

        ImplText::ImplText( const CanvasSharedPtr&  rParentCanvas,
                            const ::rtl::OUString&  rText ) :
            CanvasGraphicHelper( rParentCanvas ),
            mpFont(),
            maText(rText)
        {
        }

        ImplText::~ImplText()
        {
        }

        bool ImplText::draw() const
        {
            CanvasSharedPtr pCanvas( getCanvas() );

            OSL_ENSURE( pCanvas.get() != NULL &&
                        pCanvas->getUNOCanvas().is(),
                        "ImplBitmap::draw: invalid canvas" );

            rendering::StringContext aText;
            aText.Text = maText;
            aText.StartPosition = 0;
            aText.Length = maText.getLength();

            // TODO: implement caching
            pCanvas->getUNOCanvas()->drawText( aText,
                                               mpFont->getUNOFont(),
                                               pCanvas->getViewState(),
                                               maRenderState,
                                               rendering::TextDirection::LEFT_TO_RIGHT );

            return true;
        }

        void ImplText::setFont( const FontSharedPtr& rFont )
        {
            mpFont = rFont;
        }

        FontSharedPtr ImplText::getFont()
        {
            return mpFont;
        }
    }
}
<commit_msg>INTEGRATION: CWS presentationengine01 (1.2.2); FILE MERGED 2004/07/20 19:09:08 thb 1.2.2.4: #110496# Unified include statements; removed external prefix from boost includes 2004/05/27 20:51:29 thb 1.2.2.3: #110496# Added classification code to all TODO/HACK/FIXME comments. There are four categories:  - code quality (C)  - performance (P)  - missing functionality (F)  - and missing/incomplete error handling (E)<commit_after>/*************************************************************************
 *
 *  $RCSfile: impltext.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2004-11-26 21:02:57 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 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
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include <impltext.hxx>
#include <canvas/canvastools.hxx>

#ifndef _DRAFTS_COM_SUN_STAR_RENDERING_TEXTDIRECTION_HPP__
#include <drafts/com/sun/star/rendering/TextDirection.hpp>
#endif
#ifndef _DRAFTS_COM_SUN_STAR_RENDERING_XCANVAS_HPP__
#include <drafts/com/sun/star/rendering/XCanvas.hpp>
#endif
#ifndef _DRAFTS_COM_SUN_STAR_RENDERING_STRINGCONTEXT_HPP__
#include <drafts/com/sun/star/rendering/StringContext.hpp>
#endif

#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif

#ifndef _BGFX_MATRIX_B2DHOMMATRIX_HXX
#include <basegfx/matrix/b2dhommatrix.hxx>
#endif

using namespace ::drafts::com::sun::star;
using namespace ::com::sun::star;

namespace cppcanvas
{
    namespace internal
    {

        ImplText::ImplText( const CanvasSharedPtr&  rParentCanvas,
                            const ::rtl::OUString&  rText ) :
            CanvasGraphicHelper( rParentCanvas ),
            mpFont(),
            maText(rText)
        {
        }

        ImplText::~ImplText()
        {
        }

        bool ImplText::draw() const
        {
            CanvasSharedPtr pCanvas( getCanvas() );

            OSL_ENSURE( pCanvas.get() != NULL &&
                        pCanvas->getUNOCanvas().is(),
                        "ImplBitmap::draw: invalid canvas" );

            rendering::StringContext aText;
            aText.Text = maText;
            aText.StartPosition = 0;
            aText.Length = maText.getLength();

            // TODO(P1): implement caching
            // TODO(F2): where to get current BiDi status?
            sal_Int8 nBidiOption = rendering::TextDirection::WEAK_LEFT_TO_RIGHT;
            pCanvas->getUNOCanvas()->drawText( aText,
                                               mpFont->getUNOFont(),
                                               pCanvas->getViewState(),
                                               maRenderState,
                                               nBidiOption );

            return true;
        }

        void ImplText::setFont( const FontSharedPtr& rFont )
        {
            mpFont = rFont;
        }

        FontSharedPtr ImplText::getFont()
        {
            return mpFont;
        }
    }
}
<|endoftext|>


<commit_before>/// HEADER
#include "apex_ros_interface.h"

/// PROJECT
#include <csapex/utility/register_apex_plugin.h>
#include <csapex_ros/ros_handler.h>
#include "import_ros.h"
#include <csapex/model/subgraph_node.h>
#include <csapex/model/node_state.h>
#include <csapex/factory/message_factory.h>
#include <csapex_ros/ros_message_conversion.h>
#include <csapex/msg/generic_value_message.hpp>
#include <csapex_ros/yaml_io.hpp>
#include <csapex/model/graph_facade.h>
#include <csapex/model/node_handle.h>
#include <csapex/model/node.h>
#include <csapex/signal/event.h>
#include <csapex/msg/no_message.h>
#include <csapex/model/token.h>
#include <csapex/msg/any_message.h>

/// SYSTEM
#include <boost/regex.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <std_msgs/Int32.h>
#include <std_msgs/Bool.h>
#include <std_msgs/String.h>
#include <std_msgs/Float64.h>
#include <QMimeData>

CSAPEX_REGISTER_CLASS(csapex::APEXRosInterface, csapex::CorePlugin)

using namespace csapex;

template <typename RosType, typename ApexType>
struct ConvertIntegral
{
    static typename connection_types::GenericValueMessage<ApexType>::Ptr ros2apex(const typename RosType::ConstPtr &ros_msg) {
        typename connection_types::GenericValueMessage<ApexType>::Ptr out(new connection_types::GenericValueMessage<ApexType>);
        out->value = ros_msg->data;
        return out;
    }
    static typename RosType::Ptr apex2ros(const typename connection_types::GenericValueMessage<ApexType>::ConstPtr& apex_msg) {
        typename RosType::Ptr out(new RosType);
        out->data = apex_msg->value;
        return out;
    }
};

APEXRosInterface::APEXRosInterface()
    : core_(nullptr), disabled_(false)
{
    last_clock_ = ros::Time(0);
}

APEXRosInterface::~APEXRosInterface()
{
}

void APEXRosInterface::prepare(Settings &settings)
{
    ROSHandler::createInstance(settings);
}

void APEXRosInterface::init(CsApexCore &core)
{
    core_ = &core;

    auto init = [this]() {
        registerCommandListener();
        registerClockWatchdog();
    };
    if(ROSHandler::instance().isConnected()) {
        init();
    } else {
        connection_ = ROSHandler::instance().connected.connect(init);
    }

    RosMessageConversion::registerConversion<std_msgs::Bool, connection_types::GenericValueMessage<bool>, ConvertIntegral<std_msgs::Bool, bool> >();
    RosMessageConversion::registerConversion<std_msgs::Int32, connection_types::GenericValueMessage<int>, ConvertIntegral<std_msgs::Int32, int> >();
    RosMessageConversion::registerConversion<std_msgs::Float64, connection_types::GenericValueMessage<double>, ConvertIntegral<std_msgs::Float64, double> >();
    RosMessageConversion::registerConversion<std_msgs::String, connection_types::GenericValueMessage<std::string>, ConvertIntegral<std_msgs::String, std::string> >();

    core_->loaded.connect([this](){
        if(ROSHandler::instance().isConnected()) {
            XmlRpc::XmlRpcValue params, result, payload;
            params[0] = ros::this_node::getName();

            std::string prefix = ros::this_node::getName();

            if (ros::master::execute("getParamNames", params, result, payload, true)) {
                if(result.getType() != XmlRpc::XmlRpcValue::TypeArray) {
                    return;
                }

                std::string name = result[1];
                if(name != "Parameter names") {
                    return;
                }

                XmlRpc::XmlRpcValue data = result[2];
                for(std::size_t i = 0, total = data.size(); i < total; ++i) {
                    std::string parameter_name = data[i];

                    if(parameter_name.substr(0, prefix.size()) != prefix) {
                        continue;
                    }

                    try {
                        XmlRpc::XmlRpcValue parameter_value;
                        ros::param::getCached(parameter_name, parameter_value);

                        loadParameterValue(prefix, parameter_name, parameter_value);
                    } catch (std::exception e) {
                        // silence
                    }
                }
            }
        }
    });
}

void APEXRosInterface::setupGraph(SubgraphNode *graph)
{
    clock_reset_event_ = graph->createInternalEvent(connection_types::makeEmpty<connection_types::AnyMessage>(), graph->makeUUID("event_ros_time_reset"), "ros time reset");
}

void APEXRosInterface::loadParameterValue(const std::string& prefix, const std::string& parameter_name, const XmlRpc::XmlRpcValue& parameter_value)
{
    std::string apex_name = parameter_name.substr(prefix.size());

    Graph* graph = core_->getRoot()->getGraph();

    std::vector<std::string> levels;

    std::cerr << "analyzing parameter " << parameter_name << std::endl;

    std::size_t delim = 0;
    while(delim != std::string::npos) {
        delim = apex_name.find('/');
        std::string subname = apex_name.substr(0, delim);
        if(!subname.empty()) {
            levels.push_back(subname);
        }
        apex_name = apex_name.substr(delim+1);
    }

    if(levels.empty()) {
        return;
    }

    NodeHandle* nh = nullptr;
    std::string param_name;
    for(std::size_t i = 0, n = levels.size(); i < n - 1; ++i) {
        const std::string subname = levels.at(i);
        std::cerr << "searching for " << subname << std::endl;
        nh = graph->findNodeHandleWithLabel(subname);
        if(!nh) {
            std::cerr << "no parameter for " << parameter_name << ", label " << subname << " non-existent" << std::endl;
            return;
        }

        if (NodePtr node = nh->getNode().lock()) {
            std::ostringstream param_name_builder;
            std::copy(std::next(levels.begin(), i + 1), levels.end(), std::ostream_iterator<std::string>(param_name_builder, "/"));
            param_name = param_name_builder.str();
            param_name = param_name.substr(0, param_name.size() - 1);

            std::cerr << "searching for param " << param_name << " in node " << node->getUUID() << std::endl;
            if (node->hasParameter(param_name))
                break;
            boost::algorithm::replace_all(param_name, " ", "_");
            std::cerr << "searching for param " << param_name << " (fallback)" << std::endl;
            if (node->hasParameter(param_name))
                break;
        }
        if(i < n - 2) {
            graph = dynamic_cast<Graph*>(nh->getNode().lock().get());
            if(!graph) {
                std::cerr << "no parameter for " << parameter_name << ", child " << subname << " is not a graph" << std::endl;
                return;
            }
        }

    }
    std::cerr << "found parameter " << param_name << std::endl;
    if(!nh) {
        std::cerr << "cannot set parameter " << param_name << ", no node handle exists" << std::endl;
        return;
    }

    NodePtr node = nh->getNode().lock();
    if(!node) {
        std::cerr << "cannot set parameter " << param_name << ", no node exists" << std::endl;
        return;
    }

    if(!node->hasParameter(param_name)) {
        std::cerr << "node " << nh->getUUID() << " doesn't have a parameter called " << param_name << std::endl;
        return;
    }

    param::ParameterPtr p = node->getMappedParameter(param_name);

    switch(parameter_value.getType()) {
    case XmlRpc::XmlRpcValue::TypeInt: {
        int val;
        ros::param::get(parameter_name, val);
        std::cerr << "setting int parameter for " << nh->getUUID() << ":" << param_name << std::endl;
        p->set(val);
    }
        break;
    case XmlRpc::XmlRpcValue::TypeDouble: {
        double val;
        ros::param::get(parameter_name, val);
        std::cerr << "setting double parameter for " << nh->getUUID() << ":" << param_name << std::endl;
        p->set(val);
    }
        break;
    case XmlRpc::XmlRpcValue::TypeBoolean: {
        bool val;
        ros::param::get(parameter_name, val);
        std::cerr << "setting bool parameter for " << nh->getUUID() << ":" << param_name << std::endl;
        p->set(val);
    }
        break;
    case XmlRpc::XmlRpcValue::TypeString: {
        std::string val;
        ros::param::get(parameter_name, val);
        std::cerr << "setting string parameter for " << nh->getUUID() << ":" << param_name << std::endl;
        p->set(val);
    }
        break;

    default:
        std::cerr << "cannot set parameter for " << nh->getUUID() << ":" << param_name  << " is of unknown type " << (int) parameter_value.getType() << std::endl;
        break;
    }
}

void APEXRosInterface::registerCommandListener()
{
    assert(ROSHandler::instance().isConnected());
    global_command_sub_ = ROSHandler::instance().nh()->subscribe
            <std_msgs::String>("/syscommand", 10, std::bind(&APEXRosInterface::command, this, std::placeholders::_1, true));
    private_command_sub_ = ROSHandler::instance().nh()->subscribe
            <std_msgs::String>("command", 10, std::bind(&APEXRosInterface::command, this, std::placeholders::_1, false));

    ros::spinOnce();
}

void APEXRosInterface::command(const std_msgs::StringConstPtr& cmd, bool global_cmd)
{
    std::string command = cmd->data;
    bool local_cmd = !global_cmd;

    /*
     * pause / unpause:
     *   - temporary disable everything to conserve computational power
     *   - globally accepted, if this node is not disabled
     *
     * stop / resume
     *   - completely disable / enable this subsystem, when it is not needed
     *   - only locally accepted
     *   - overwrites pause -> a disabled instance cannot be unpaused
     */

    if(!disabled_) {
        // disabled state is stronger than pause / unpause
        if(command == "pause") {
            core_->setPause(true);

        } else if(command == "unpause"){
            core_->setPause(false);
        }
    }

    if(local_cmd) {
        if(command == "stop") {
            disabled_ = true;
            core_->setPause(true);
        } else if(command == "resume") {
            disabled_ = false;
            core_->setPause(false);
        }
    }
}

void APEXRosInterface::registerClockWatchdog()
{
    clock_sub_ = ROSHandler::instance().nh()->subscribe
            <rosgraph_msgs::Clock>("/clock", 10, std::bind(&APEXRosInterface::clock, this, std::placeholders::_1));
}

void APEXRosInterface::clock(const rosgraph_msgs::ClockConstPtr &clock)
{
    ros::Time now = clock->clock;
    if(now < last_clock_) {
        std::cerr << "time reset" << std::endl;

        TokenDataConstPtr data(new connection_types::AnyMessage);
        TokenPtr token = std::make_shared<Token>(data);
        token->setActive(true);
        clock_reset_event_->triggerWith(token);
    }

    last_clock_ = now;
}

void APEXRosInterface::shutdown()
{
    ROSHandler::instance().stop();

    RosMessageConversion::instance().shutdown();
}
<commit_msg>moved console_bridge use to csapex_ros<commit_after>/// HEADER
#include "apex_ros_interface.h"

/// PROJECT
#include <csapex/utility/register_apex_plugin.h>
#include <csapex_ros/ros_handler.h>
#include "import_ros.h"
#include <csapex/model/subgraph_node.h>
#include <csapex/model/node_state.h>
#include <csapex/factory/message_factory.h>
#include <csapex_ros/ros_message_conversion.h>
#include <csapex/msg/generic_value_message.hpp>
#include <csapex_ros/yaml_io.hpp>
#include <csapex/model/graph_facade.h>
#include <csapex/model/node_handle.h>
#include <csapex/model/node.h>
#include <csapex/signal/event.h>
#include <csapex/msg/no_message.h>
#include <csapex/model/token.h>
#include <csapex/msg/any_message.h>

/// SYSTEM
#include <console_bridge/console.h>
#include <boost/regex.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <std_msgs/Int32.h>
#include <std_msgs/Bool.h>
#include <std_msgs/String.h>
#include <std_msgs/Float64.h>
#include <QMimeData>

CSAPEX_REGISTER_CLASS(csapex::APEXRosInterface, csapex::CorePlugin)

using namespace csapex;

template <typename RosType, typename ApexType>
struct ConvertIntegral
{
    static typename connection_types::GenericValueMessage<ApexType>::Ptr ros2apex(const typename RosType::ConstPtr &ros_msg) {
        typename connection_types::GenericValueMessage<ApexType>::Ptr out(new connection_types::GenericValueMessage<ApexType>);
        out->value = ros_msg->data;
        return out;
    }
    static typename RosType::Ptr apex2ros(const typename connection_types::GenericValueMessage<ApexType>::ConstPtr& apex_msg) {
        typename RosType::Ptr out(new RosType);
        out->data = apex_msg->value;
        return out;
    }
};

APEXRosInterface::APEXRosInterface()
    : core_(nullptr), disabled_(false)
{
    last_clock_ = ros::Time(0);
}

APEXRosInterface::~APEXRosInterface()
{
}

void APEXRosInterface::prepare(Settings &settings)
{
    ROSHandler::createInstance(settings);
}

void APEXRosInterface::init(CsApexCore &core)
{
    core_ = &core;

    if(core_->getSettings().get<bool>("debug")) {
        console_bridge::setLogLevel(console_bridge::CONSOLE_BRIDGE_LOG_DEBUG);
    }

    auto init = [this]() {
        registerCommandListener();
        registerClockWatchdog();
    };
    if(ROSHandler::instance().isConnected()) {
        init();
    } else {
        connection_ = ROSHandler::instance().connected.connect(init);
    }

    RosMessageConversion::registerConversion<std_msgs::Bool, connection_types::GenericValueMessage<bool>, ConvertIntegral<std_msgs::Bool, bool> >();
    RosMessageConversion::registerConversion<std_msgs::Int32, connection_types::GenericValueMessage<int>, ConvertIntegral<std_msgs::Int32, int> >();
    RosMessageConversion::registerConversion<std_msgs::Float64, connection_types::GenericValueMessage<double>, ConvertIntegral<std_msgs::Float64, double> >();
    RosMessageConversion::registerConversion<std_msgs::String, connection_types::GenericValueMessage<std::string>, ConvertIntegral<std_msgs::String, std::string> >();

    core_->loaded.connect([this](){
        if(ROSHandler::instance().isConnected()) {
            XmlRpc::XmlRpcValue params, result, payload;
            params[0] = ros::this_node::getName();

            std::string prefix = ros::this_node::getName();

            if (ros::master::execute("getParamNames", params, result, payload, true)) {
                if(result.getType() != XmlRpc::XmlRpcValue::TypeArray) {
                    return;
                }

                std::string name = result[1];
                if(name != "Parameter names") {
                    return;
                }

                XmlRpc::XmlRpcValue data = result[2];
                for(std::size_t i = 0, total = data.size(); i < total; ++i) {
                    std::string parameter_name = data[i];

                    if(parameter_name.substr(0, prefix.size()) != prefix) {
                        continue;
                    }

                    try {
                        XmlRpc::XmlRpcValue parameter_value;
                        ros::param::getCached(parameter_name, parameter_value);

                        loadParameterValue(prefix, parameter_name, parameter_value);
                    } catch (std::exception e) {
                        // silence
                    }
                }
            }
        }
    });
}

void APEXRosInterface::setupGraph(SubgraphNode *graph)
{
    clock_reset_event_ = graph->createInternalEvent(connection_types::makeEmpty<connection_types::AnyMessage>(), graph->makeUUID("event_ros_time_reset"), "ros time reset");
}

void APEXRosInterface::loadParameterValue(const std::string& prefix, const std::string& parameter_name, const XmlRpc::XmlRpcValue& parameter_value)
{
    std::string apex_name = parameter_name.substr(prefix.size());

    Graph* graph = core_->getRoot()->getGraph();

    std::vector<std::string> levels;

    std::cerr << "analyzing parameter " << parameter_name << std::endl;

    std::size_t delim = 0;
    while(delim != std::string::npos) {
        delim = apex_name.find('/');
        std::string subname = apex_name.substr(0, delim);
        if(!subname.empty()) {
            levels.push_back(subname);
        }
        apex_name = apex_name.substr(delim+1);
    }

    if(levels.empty()) {
        return;
    }

    NodeHandle* nh = nullptr;
    std::string param_name;
    for(std::size_t i = 0, n = levels.size(); i < n - 1; ++i) {
        const std::string subname = levels.at(i);
        std::cerr << "searching for " << subname << std::endl;
        nh = graph->findNodeHandleWithLabel(subname);
        if(!nh) {
            std::cerr << "no parameter for " << parameter_name << ", label " << subname << " non-existent" << std::endl;
            return;
        }

        if (NodePtr node = nh->getNode().lock()) {
            std::ostringstream param_name_builder;
            std::copy(std::next(levels.begin(), i + 1), levels.end(), std::ostream_iterator<std::string>(param_name_builder, "/"));
            param_name = param_name_builder.str();
            param_name = param_name.substr(0, param_name.size() - 1);

            std::cerr << "searching for param " << param_name << " in node " << node->getUUID() << std::endl;
            if (node->hasParameter(param_name))
                break;
            boost::algorithm::replace_all(param_name, " ", "_");
            std::cerr << "searching for param " << param_name << " (fallback)" << std::endl;
            if (node->hasParameter(param_name))
                break;
        }
        if(i < n - 2) {
            graph = dynamic_cast<Graph*>(nh->getNode().lock().get());
            if(!graph) {
                std::cerr << "no parameter for " << parameter_name << ", child " << subname << " is not a graph" << std::endl;
                return;
            }
        }

    }
    std::cerr << "found parameter " << param_name << std::endl;
    if(!nh) {
        std::cerr << "cannot set parameter " << param_name << ", no node handle exists" << std::endl;
        return;
    }

    NodePtr node = nh->getNode().lock();
    if(!node) {
        std::cerr << "cannot set parameter " << param_name << ", no node exists" << std::endl;
        return;
    }

    if(!node->hasParameter(param_name)) {
        std::cerr << "node " << nh->getUUID() << " doesn't have a parameter called " << param_name << std::endl;
        return;
    }

    param::ParameterPtr p = node->getMappedParameter(param_name);

    switch(parameter_value.getType()) {
    case XmlRpc::XmlRpcValue::TypeInt: {
        int val;
        ros::param::get(parameter_name, val);
        std::cerr << "setting int parameter for " << nh->getUUID() << ":" << param_name << std::endl;
        p->set(val);
    }
        break;
    case XmlRpc::XmlRpcValue::TypeDouble: {
        double val;
        ros::param::get(parameter_name, val);
        std::cerr << "setting double parameter for " << nh->getUUID() << ":" << param_name << std::endl;
        p->set(val);
    }
        break;
    case XmlRpc::XmlRpcValue::TypeBoolean: {
        bool val;
        ros::param::get(parameter_name, val);
        std::cerr << "setting bool parameter for " << nh->getUUID() << ":" << param_name << std::endl;
        p->set(val);
    }
        break;
    case XmlRpc::XmlRpcValue::TypeString: {
        std::string val;
        ros::param::get(parameter_name, val);
        std::cerr << "setting string parameter for " << nh->getUUID() << ":" << param_name << std::endl;
        p->set(val);
    }
        break;

    default:
        std::cerr << "cannot set parameter for " << nh->getUUID() << ":" << param_name  << " is of unknown type " << (int) parameter_value.getType() << std::endl;
        break;
    }
}

void APEXRosInterface::registerCommandListener()
{
    assert(ROSHandler::instance().isConnected());
    global_command_sub_ = ROSHandler::instance().nh()->subscribe
            <std_msgs::String>("/syscommand", 10, std::bind(&APEXRosInterface::command, this, std::placeholders::_1, true));
    private_command_sub_ = ROSHandler::instance().nh()->subscribe
            <std_msgs::String>("command", 10, std::bind(&APEXRosInterface::command, this, std::placeholders::_1, false));

    ros::spinOnce();
}

void APEXRosInterface::command(const std_msgs::StringConstPtr& cmd, bool global_cmd)
{
    std::string command = cmd->data;
    bool local_cmd = !global_cmd;

    /*
     * pause / unpause:
     *   - temporary disable everything to conserve computational power
     *   - globally accepted, if this node is not disabled
     *
     * stop / resume
     *   - completely disable / enable this subsystem, when it is not needed
     *   - only locally accepted
     *   - overwrites pause -> a disabled instance cannot be unpaused
     */

    if(!disabled_) {
        // disabled state is stronger than pause / unpause
        if(command == "pause") {
            core_->setPause(true);

        } else if(command == "unpause"){
            core_->setPause(false);
        }
    }

    if(local_cmd) {
        if(command == "stop") {
            disabled_ = true;
            core_->setPause(true);
        } else if(command == "resume") {
            disabled_ = false;
            core_->setPause(false);
        }
    }
}

void APEXRosInterface::registerClockWatchdog()
{
    clock_sub_ = ROSHandler::instance().nh()->subscribe
            <rosgraph_msgs::Clock>("/clock", 10, std::bind(&APEXRosInterface::clock, this, std::placeholders::_1));
}

void APEXRosInterface::clock(const rosgraph_msgs::ClockConstPtr &clock)
{
    ros::Time now = clock->clock;
    if(now < last_clock_) {
        std::cerr << "time reset" << std::endl;

        TokenDataConstPtr data(new connection_types::AnyMessage);
        TokenPtr token = std::make_shared<Token>(data);
        token->setActive(true);
        clock_reset_event_->triggerWith(token);
    }

    last_clock_ = now;
}

void APEXRosInterface::shutdown()
{
    ROSHandler::instance().stop();

    RosMessageConversion::instance().shutdown();
}
<|endoftext|>