<commit_before>#include "sprites.h"

Sprites::Sprites(Arduboy &a)
{
  arduboy = &a;
  sBuffer = arduboy->getBuffer();
}

SimpleSprite::SimpleSprite(int x, int y, const uint8_t *bitmap) :
x(x), y(y), bitmap(bitmap)
{
}

Sprite::Sprite(int x, int y, const uint8_t *bitmap) :
  SimpleSprite(x,y, bitmap) {
}

Sprite::Sprite(int x, int y, const uint8_t *bitmap, const uint8_t *mask) :
  SimpleSprite(x,y, bitmap), mask(mask) {
}

void Sprites::draw(Sprite sprite)
{
  draw(sprite.x, sprite.y,
    sprite.bitmap, sprite.frame,
    sprite.mask, sprite.maskFrame);
}

void Sprites::draw(int16_t x, int16_t y, const uint8_t *bitmap)
{
  draw(x, y, bitmap, 0, NULL, 0);
}

void Sprites::draw(int16_t x, int16_t y, const uint8_t *bitmap, const uint8_t *mask)
{
  draw(x, y, bitmap, 0, mask, 0);
}

void Sprites::draw(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame)
{
  draw(x, y, bitmap, frame, NULL, 0);
}

void Sprites::draw(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame, const uint8_t *mask, uint8_t sprite_frame)
{
  uint8_t width = pgm_read_byte(bitmap);
  uint8_t height = pgm_read_byte(++bitmap);
  unsigned int frame_offset;
  bitmap++;
  if (frame > 0 || sprite_frame > 0) {
    frame_offset = (width * ( height/8 + ( height%8 == 0 ? 0 : 1)));
    bitmap += frame * frame_offset;
    if (mask!=0)
      mask += sprite_frame * frame_offset;
  }

  drawBitmap(x, y, bitmap, mask, width, height, mask==0 ? SPRITE_UNMASKED : SPRITE_MASKED);
}

// should we still even support these modes?
// void Sprites::drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint8_t color) {
  // drawComplexBitmap(x, y, bitmap, NULL, w, h, color ? SPRITE_IS_MASK : SPRITE_IS_MASK_ERASE);
// }

void Sprites::drawBitmap(int16_t x, int16_t y,
  const uint8_t *bitmap, const uint8_t *mask,
  int16_t w, int16_t h, uint8_t draw_mode) {
  // no need to draw at all of we're offscreen
  if (x+w < 0 || x > WIDTH-1 || y+h < 0 || y > HEIGHT-1)
    return;

  // xOffset technically doesn't need to be 16 bit but the math operations
  // are measurably faster if it is
  int xOffset, ofs, ofs2;
  int8_t yOffset = abs(y) % 8;
  int8_t sRow = y / 8;
  uint8_t loop_w, loop_h, start_h;

  if (y < 0 && yOffset > 0) {
    sRow--;
    yOffset = 8 - yOffset;
  }

  // if the right side of the render is offscreen skip those loops
  if (x+w > WIDTH-1) {
    loop_w = WIDTH-x;
  } else {
    loop_w = w;
  }
  // if the left side of the render is offscreen skip those loops
  if (x<0) {
    xOffset = abs(x);
  } else {
    xOffset = 0;
  }

  // if the top side of the render is offscreen skip those loops
  if (sRow < -1) {
    start_h = abs(sRow)-1;
  } else {
    start_h = 0;
  }

  loop_h = h/8 + (h%8 > 0 ? 1 : 0); // divide, then round up

  // if (sRow + loop_h - 1 > (HEIGHT/8)-1)
  if (sRow + loop_h > (HEIGHT/8)) {
    loop_h = (HEIGHT/8) - sRow;
  }

  sRow += start_h;
  ofs = (sRow*WIDTH) + x + xOffset;
  uint8_t rendered_width = (loop_w - xOffset);
  uint8_t *bofs = (uint8_t *)bitmap+(start_h*w) + xOffset;
  uint8_t *mask_ofs;
  if (mask!=0)
    mask_ofs = (uint8_t *)mask+(start_h*w) + xOffset;
  uint8_t data;

  uint8_t top_mask;
  uint8_t bottom_mask;
  switch (draw_mode) {
    case SPRITE_UNMASKED:
    top_mask = ((1<<yOffset)-1);
    bottom_mask= ~(0xFF >> (8-yOffset));
    // really if yOffset = 0 you have a faster case here that could be
    // optimized
      for (uint8_t a = start_h; a < loop_h; a++) {
        for (uint8_t iCol = xOffset; iCol < loop_w; iCol++) {
            if (sRow >= 0) {
                data = sBuffer[ofs];
                data &= top_mask;
                data |= pgm_read_byte(bofs) << yOffset;
                sBuffer[ofs] = data;
            }
            if (yOffset > 0) {
                data = sBuffer[ofs+WIDTH];
                data &= bottom_mask;
                data |= pgm_read_byte(bofs) >> (8-yOffset);
                sBuffer[ofs+WIDTH] = data;
            }
          ofs++;
          bofs++;
        }
        sRow++;
        bofs += w - rendered_width;
        ofs += WIDTH - rendered_width;
      }
    break;
    case SPRITE_IS_MASK:
      for (uint8_t a = start_h; a < loop_h; a++) {
        for (uint8_t iCol = xOffset; iCol < loop_w; iCol++) {
            if (sRow >= 0) {
                sBuffer[ofs] |= pgm_read_byte(bofs) << yOffset;
            }
            if (yOffset > 0) {
                sBuffer[ofs+WIDTH] |= pgm_read_byte(bofs) >> (8-yOffset);
            }
          ofs++;
          bofs++;
        }
        sRow++;
        bofs += w - rendered_width;
        ofs += WIDTH - rendered_width;
      }
    break;
    case SPRITE_IS_MASK_ERASE:
      for (uint8_t a = start_h; a < loop_h; a++) {
        for (uint8_t iCol = xOffset; iCol < loop_w; iCol++) {
            if (sRow >= 0) {
              sBuffer[ofs]  &= ~(pgm_read_byte(bofs) << yOffset);
            }
            if (yOffset > 0) {
              sBuffer[ofs+WIDTH] &= ~(pgm_read_byte(bofs) >> (8-yOffset));
            }
          ofs++;
          bofs++;
        }
        sRow++;
        bofs += w - rendered_width;
        ofs += WIDTH - rendered_width;
      }
    break;
    case SPRITE_MASKED:
    for (uint8_t a = start_h; a < loop_h; a++) {
      for (uint8_t iCol = xOffset; iCol < loop_w; iCol++) {
          if (sRow >= 0) {
            data = sBuffer[ofs];
            data &= (pgm_read_byte(mask_ofs) << yOffset);
            data |= (pgm_read_byte(bofs) << yOffset);
            sBuffer[ofs] = data;
          }
          if (yOffset > 0) {
            data = sBuffer[ofs+WIDTH];
            data &= (pgm_read_byte(mask_ofs) >> (8-yOffset));
            data |= (pgm_read_byte(bofs) >> (8-yOffset));
            sBuffer[ofs+WIDTH] = data;
          }
        ofs++;
        mask_ofs++;
        bofs++;
      }
      sRow++;
      bofs += w - rendered_width;
      mask_ofs += w - rendered_width;
      ofs += WIDTH - rendered_width;
    }
    break;

  }
}
<commit_msg>fix: do not write past the end of the buffer<commit_after>#include "sprites.h"

Sprites::Sprites(Arduboy &a)
{
  arduboy = &a;
  sBuffer = arduboy->getBuffer();
}

SimpleSprite::SimpleSprite(int x, int y, const uint8_t *bitmap) :
x(x), y(y), bitmap(bitmap)
{
}

Sprite::Sprite(int x, int y, const uint8_t *bitmap) :
  SimpleSprite(x,y, bitmap) {
}

Sprite::Sprite(int x, int y, const uint8_t *bitmap, const uint8_t *mask) :
  SimpleSprite(x,y, bitmap), mask(mask) {
}

void Sprites::draw(Sprite sprite)
{
  draw(sprite.x, sprite.y,
    sprite.bitmap, sprite.frame,
    sprite.mask, sprite.maskFrame);
}

void Sprites::draw(int16_t x, int16_t y, const uint8_t *bitmap)
{
  draw(x, y, bitmap, 0, NULL, 0);
}

void Sprites::draw(int16_t x, int16_t y, const uint8_t *bitmap, const uint8_t *mask)
{
  draw(x, y, bitmap, 0, mask, 0);
}

void Sprites::draw(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame)
{
  draw(x, y, bitmap, frame, NULL, 0);
}

void Sprites::draw(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame, const uint8_t *mask, uint8_t sprite_frame)
{
  uint8_t width = pgm_read_byte(bitmap);
  uint8_t height = pgm_read_byte(++bitmap);
  unsigned int frame_offset;
  bitmap++;
  if (frame > 0 || sprite_frame > 0) {
    frame_offset = (width * ( height/8 + ( height%8 == 0 ? 0 : 1)));
    bitmap += frame * frame_offset;
    if (mask!=0)
      mask += sprite_frame * frame_offset;
  }

  drawBitmap(x, y, bitmap, mask, width, height, mask==0 ? SPRITE_UNMASKED : SPRITE_MASKED);
}

// should we still even support these modes?
// void Sprites::drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint8_t color) {
  // drawComplexBitmap(x, y, bitmap, NULL, w, h, color ? SPRITE_IS_MASK : SPRITE_IS_MASK_ERASE);
// }

void Sprites::drawBitmap(int16_t x, int16_t y,
  const uint8_t *bitmap, const uint8_t *mask,
  int16_t w, int16_t h, uint8_t draw_mode) {
  // no need to draw at all of we're offscreen
  if (x+w < 0 || x > WIDTH-1 || y+h < 0 || y > HEIGHT-1)
    return;

  // xOffset technically doesn't need to be 16 bit but the math operations
  // are measurably faster if it is
  int xOffset, ofs, ofs2;
  int8_t yOffset = abs(y) % 8;
  int8_t sRow = y / 8;
  uint8_t loop_w, loop_h, start_h;

  if (y < 0 && yOffset > 0) {
    sRow--;
    yOffset = 8 - yOffset;
  }

  // if the right side of the render is offscreen skip those loops
  if (x+w > WIDTH-1) {
    loop_w = WIDTH-x;
  } else {
    loop_w = w;
  }
  // if the left side of the render is offscreen skip those loops
  if (x<0) {
    xOffset = abs(x);
  } else {
    xOffset = 0;
  }

  // if the top side of the render is offscreen skip those loops
  if (sRow < -1) {
    start_h = abs(sRow)-1;
  } else {
    start_h = 0;
  }

  loop_h = h/8 + (h%8 > 0 ? 1 : 0); // divide, then round up

  // if (sRow + loop_h - 1 > (HEIGHT/8)-1)
  if (sRow + loop_h > (HEIGHT/8)) {
    loop_h = (HEIGHT/8) - sRow;
  }

  sRow += start_h;
  ofs = (sRow*WIDTH) + x + xOffset;
  uint8_t rendered_width = (loop_w - xOffset);
  uint8_t *bofs = (uint8_t *)bitmap+(start_h*w) + xOffset;
  uint8_t *mask_ofs;
  if (mask!=0)
    mask_ofs = (uint8_t *)mask+(start_h*w) + xOffset;
  uint8_t data;

  uint8_t top_mask;
  uint8_t bottom_mask;
  switch (draw_mode) {
    case SPRITE_UNMASKED:
    top_mask = ((1<<yOffset)-1);
    bottom_mask= ~(0xFF >> (8-yOffset));
    // really if yOffset = 0 you have a faster case here that could be
    // optimized
      for (uint8_t a = start_h; a < loop_h; a++) {
        for (uint8_t iCol = xOffset; iCol < loop_w; iCol++) {
            if (sRow >= 0) {
                data = sBuffer[ofs];
                data &= top_mask;
                data |= pgm_read_byte(bofs) << yOffset;
                sBuffer[ofs] = data;
            }
            if (yOffset > 0 && sRow<7) {
                data = sBuffer[ofs+WIDTH];
                data &= bottom_mask;
                data |= pgm_read_byte(bofs) >> (8-yOffset);
                sBuffer[ofs+WIDTH] = data;
            }
          ofs++;
          bofs++;
        }
        sRow++;
        bofs += w - rendered_width;
        ofs += WIDTH - rendered_width;
      }
    break;
    case SPRITE_IS_MASK:
      for (uint8_t a = start_h; a < loop_h; a++) {
        for (uint8_t iCol = xOffset; iCol < loop_w; iCol++) {
            if (sRow >= 0) {
                sBuffer[ofs] |= pgm_read_byte(bofs) << yOffset;
            }
            if (yOffset > 0 && sRow<7) {
                sBuffer[ofs+WIDTH] |= pgm_read_byte(bofs) >> (8-yOffset);
            }
          ofs++;
          bofs++;
        }
        sRow++;
        bofs += w - rendered_width;
        ofs += WIDTH - rendered_width;
      }
    break;
    case SPRITE_IS_MASK_ERASE:
      for (uint8_t a = start_h; a < loop_h; a++) {
        for (uint8_t iCol = xOffset; iCol < loop_w; iCol++) {
            if (sRow >= 0) {
              sBuffer[ofs]  &= ~(pgm_read_byte(bofs) << yOffset);
            }
            if (yOffset > 0 && sRow<7) {
              sBuffer[ofs+WIDTH] &= ~(pgm_read_byte(bofs) >> (8-yOffset));
            }
          ofs++;
          bofs++;
        }
        sRow++;
        bofs += w - rendered_width;
        ofs += WIDTH - rendered_width;
      }
    break;
    case SPRITE_MASKED:
    for (uint8_t a = start_h; a < loop_h; a++) {
      for (uint8_t iCol = xOffset; iCol < loop_w; iCol++) {
          if (sRow >= 0) {
            data = sBuffer[ofs];
            data &= (pgm_read_byte(mask_ofs) << yOffset);
            data |= (pgm_read_byte(bofs) << yOffset);
            sBuffer[ofs] = data;
          }
          if (yOffset > 0 && sRow<7) {
            data = sBuffer[ofs+WIDTH];
            data &= (pgm_read_byte(mask_ofs) >> (8-yOffset));
            data |= (pgm_read_byte(bofs) >> (8-yOffset));
            sBuffer[ofs+WIDTH] = data;
          }
        ofs++;
        mask_ofs++;
        bofs++;
      }
      sRow++;
      bofs += w - rendered_width;
      mask_ofs += w - rendered_width;
      ofs += WIDTH - rendered_width;
    }
    break;

  }
}
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.8  2000/05/09 00:22:40  andyh
 * Memory Cleanup.  XMLPlatformUtils::Terminate() deletes all lazily
 * allocated memory; memory leak checking tools will no longer report
 * that leaks exist.  (DOM GetElementsByTagID temporarily removed
 * as part of this.)
 *
 * Revision 1.7  2000/03/24 19:50:29  roddey
 * Clear the 'initialized' flag when the termination call is made. Probably
 * not required technically, but...
 *
 * Revision 1.6  2000/03/02 19:54:44  roddey
 * This checkin includes many changes done while waiting for the
 * 1.1.0 code to be finished. I can't list them all here, but a list is
 * available elsewhere.
 *
 * Revision 1.5  2000/02/06 07:48:03  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.4  2000/01/19 00:56:59  roddey
 * Changes to get rid of dependence on old utils standard streams and to
 * get rid of the fgLibLocation stuff.
 *
 * Revision 1.3  1999/12/18 00:18:10  roddey
 * More changes to support the new, completely orthagonal support for
 * intrinsic encodings.
 *
 * Revision 1.2  1999/12/15 19:41:28  roddey
 * Support for the new transcoder system, where even intrinsic encodings are
 * done via the same transcoder abstraction as external ones.
 *
 * Revision 1.1.1.1  1999/11/09 01:04:53  twl
 * Initial checkin
 *
 * Revision 1.2  1999/11/08 20:45:11  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <util/XMLMsgLoader.hpp>
#include <util/Mutexes.hpp>
#include <util/PlatformUtils.hpp>
#include <util/RefVectorOf.hpp>
#include <util/TransService.hpp>
#include <util/XMLString.hpp>
#include <util/XMLNetAccessor.hpp>
#include <util/XMLUni.hpp>

// ---------------------------------------------------------------------------
//  Local data members
//
//  gSyncMutex
//      This is a mutex that will be used to synchronize access to some of
//      the static data of the platform utilities class and here locally.
// ---------------------------------------------------------------------------
static XMLMutex*                gSyncMutex = 0;
static RefVectorOf<XMLDeleter>* gLazyData;
static bool                     gInitFlag = false;

// ---------------------------------------------------------------------------
//  XMLPlatformUtils: Static Data Members
// ---------------------------------------------------------------------------
XMLNetAccessor*     XMLPlatformUtils::fgNetAccessor = 0;
XMLTransService*    XMLPlatformUtils::fgTransService = 0;

// ---------------------------------------------------------------------------
//  XMLPlatformUtils: Init/term methods
// ---------------------------------------------------------------------------
void XMLPlatformUtils::Initialize()
{
    //
    //  Make sure we haven't already been initialized. Note that this is not
    //  thread safe and is not intended for that. Its more for those COM
    //  like processes that cannot keep up with whether they have initialized
    //  us yet or not.
    //
    if (gInitFlag)
        return;
    gInitFlag = true;

    // Create the local sync mutex
    gSyncMutex = new XMLMutex;

    // Create the array for saving lazily allocated objects to be deleted at termination
    gLazyData= new RefVectorOf<XMLDeleter>(512);

    //
    //  Call the platform init method, which is implemented in each of the
    //  per-platform implementation cpp files. This one does the very low
    //  level per-platform setup. It cannot use any XML util services at all,
    //  i.e. only native services.
    //
    platformInit();

    //
    //  Ask the per-platform code to make the desired transcoding service for
    //  us to use. This call cannot throw any exceptions or do anything that
    //  cause any transcoding to happen. It should create the service and
    //  return it or zero if it cannot.
    //
    //  This one also cannot use any utility services. It can only create a
    //  transcoding service object and return it.
    //
    //  If we cannot make one, then we call panic to end the process.
    //
    fgTransService = makeTransService();
    if (!fgTransService)
        panic(Panic_NoTransService);

    // Initialize the transcoder service
    fgTransService->initTransService();

    //
    //  Try to create a default local code page transcoder. This is the one
    //  that will be used internally by the XMLString class. If we cannot
    //  create one, then call the panic method.
    //
    XMLLCPTranscoder* defXCode = XMLPlatformUtils::fgTransService->makeNewLCPTranscoder();
    if (!defXCode)
        panic(Panic_NoDefTranscoder);
    XMLString::initString(defXCode);

    //
    //  Now lets ask the per-platform code to give us an instance of the type
    //  of network access implementation he wants to use. This can return
    //  a zero pointer if this platform doesn't want to support this.
    //
    fgNetAccessor = makeNetAccessor();
}

void XMLPlatformUtils::Terminate()
{
    // Delete any net accessor that got installed
    delete fgNetAccessor;
    fgNetAccessor = 0;

    //
    //  Call the method that cleans up the registered lazy eval objects.
    //  This is all higher level code which might try to report errors if
    //  they have problems, so we want to do this before we hose our
    //  fundamental bits and pieces.
    //
    cleanupLazyData();

    //
    //  Call some other internal modules to give them a chance to clean up.
    //  Do the string class last in case something tries to use it during
    //  cleanup.
    //
    XMLString::termString();

    // Clean up the the transcoding service
    delete fgTransService;
    fgTransService = 0;

    // Clean up the sync mutex
    delete gSyncMutex;
    gSyncMutex = 0;

    //
    //  And do platform termination. This cannot do use any XML services
    //  at all, it can only clean up local stuff. It it reports an error,
    //  it cannot use any XML exception or error reporting services.
    //
    platformTerm();

    // And say we are no longer initialized
    gInitFlag = false;
}

// ---------------------------------------------------------------------------
//  XMLPlatformUtils: Msg support methods
// ---------------------------------------------------------------------------
XMLMsgLoader* XMLPlatformUtils::loadMsgSet(const XMLCh* const msgDomain)
{
    //
    //  Ask the platform support to load up the correct type of message
    //  loader for the indicated message set. We don't check here whether it
    //  works or not. That's their decision.
    //
    return loadAMsgSet(msgDomain);
}

// ---------------------------------------------------------------------------
//  XMLPlatformUtils: Lazy eval methods
// ---------------------------------------------------------------------------
void XMLPlatformUtils::registerLazyData(XMLDeleter* const deleter)
{
    // Just add a copy of this object to the vector. MUST be synchronized
    XMLMutexLock lock(gSyncMutex);
    gLazyData->addElement(deleter);
}

void XMLPlatformUtils::cleanupLazyData()
{
    //
    //  Loop through the vector and try to delete each object. Use a try
    //  block so that we don't fall out prematurely if one of them hoses.
    //  Note that we effectively do them in reverse order of their having
    //  been registered.
    //
    //  Also, note that we don't synchronize here because this is happening
    //  during shutdown.
    //
    while (gLazyData->size())
    {
        try
        {
            gLazyData->removeLastElement();
        }

        catch(...)
        {
            // We don't try to report errors here, just fall through
        }
    }
    delete gLazyData;
    gLazyData = 0;
}
<commit_msg>check if initialized in Terminate() to stop access violations submitted by John_Roper@iOra.com<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Log$
 * Revision 1.9  2000/06/26 20:30:04  jpolast
 * check if initialized in Terminate() to stop access violations
 * submitted by John_Roper@iOra.com
 *
 * Revision 1.8  2000/05/09 00:22:40  andyh
 * Memory Cleanup.  XMLPlatformUtils::Terminate() deletes all lazily
 * allocated memory; memory leak checking tools will no longer report
 * that leaks exist.  (DOM GetElementsByTagID temporarily removed
 * as part of this.)
 *
 * Revision 1.7  2000/03/24 19:50:29  roddey
 * Clear the 'initialized' flag when the termination call is made. Probably
 * not required technically, but...
 *
 * Revision 1.6  2000/03/02 19:54:44  roddey
 * This checkin includes many changes done while waiting for the
 * 1.1.0 code to be finished. I can't list them all here, but a list is
 * available elsewhere.
 *
 * Revision 1.5  2000/02/06 07:48:03  rahulj
 * Year 2K copyright swat.
 *
 * Revision 1.4  2000/01/19 00:56:59  roddey
 * Changes to get rid of dependence on old utils standard streams and to
 * get rid of the fgLibLocation stuff.
 *
 * Revision 1.3  1999/12/18 00:18:10  roddey
 * More changes to support the new, completely orthagonal support for
 * intrinsic encodings.
 *
 * Revision 1.2  1999/12/15 19:41:28  roddey
 * Support for the new transcoder system, where even intrinsic encodings are
 * done via the same transcoder abstraction as external ones.
 *
 * Revision 1.1.1.1  1999/11/09 01:04:53  twl
 * Initial checkin
 *
 * Revision 1.2  1999/11/08 20:45:11  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <util/XMLMsgLoader.hpp>
#include <util/Mutexes.hpp>
#include <util/PlatformUtils.hpp>
#include <util/RefVectorOf.hpp>
#include <util/TransService.hpp>
#include <util/XMLString.hpp>
#include <util/XMLNetAccessor.hpp>
#include <util/XMLUni.hpp>

// ---------------------------------------------------------------------------
//  Local data members
//
//  gSyncMutex
//      This is a mutex that will be used to synchronize access to some of
//      the static data of the platform utilities class and here locally.
// ---------------------------------------------------------------------------
static XMLMutex*                gSyncMutex = 0;
static RefVectorOf<XMLDeleter>* gLazyData;
static bool                     gInitFlag = false;

// ---------------------------------------------------------------------------
//  XMLPlatformUtils: Static Data Members
// ---------------------------------------------------------------------------
XMLNetAccessor*     XMLPlatformUtils::fgNetAccessor = 0;
XMLTransService*    XMLPlatformUtils::fgTransService = 0;

// ---------------------------------------------------------------------------
//  XMLPlatformUtils: Init/term methods
// ---------------------------------------------------------------------------
void XMLPlatformUtils::Initialize()
{
    //
    //  Make sure we haven't already been initialized. Note that this is not
    //  thread safe and is not intended for that. Its more for those COM
    //  like processes that cannot keep up with whether they have initialized
    //  us yet or not.
    //
    if (gInitFlag)
        return;
    gInitFlag = true;

    // Create the local sync mutex
    gSyncMutex = new XMLMutex;

    // Create the array for saving lazily allocated objects to be deleted at termination
    gLazyData= new RefVectorOf<XMLDeleter>(512);

    //
    //  Call the platform init method, which is implemented in each of the
    //  per-platform implementation cpp files. This one does the very low
    //  level per-platform setup. It cannot use any XML util services at all,
    //  i.e. only native services.
    //
    platformInit();

    //
    //  Ask the per-platform code to make the desired transcoding service for
    //  us to use. This call cannot throw any exceptions or do anything that
    //  cause any transcoding to happen. It should create the service and
    //  return it or zero if it cannot.
    //
    //  This one also cannot use any utility services. It can only create a
    //  transcoding service object and return it.
    //
    //  If we cannot make one, then we call panic to end the process.
    //
    fgTransService = makeTransService();
    if (!fgTransService)
        panic(Panic_NoTransService);

    // Initialize the transcoder service
    fgTransService->initTransService();

    //
    //  Try to create a default local code page transcoder. This is the one
    //  that will be used internally by the XMLString class. If we cannot
    //  create one, then call the panic method.
    //
    XMLLCPTranscoder* defXCode = XMLPlatformUtils::fgTransService->makeNewLCPTranscoder();
    if (!defXCode)
        panic(Panic_NoDefTranscoder);
    XMLString::initString(defXCode);

    //
    //  Now lets ask the per-platform code to give us an instance of the type
    //  of network access implementation he wants to use. This can return
    //  a zero pointer if this platform doesn't want to support this.
    //
    fgNetAccessor = makeNetAccessor();
}

void XMLPlatformUtils::Terminate()
{

	if (!gInitFlag)
		return;

    // Delete any net accessor that got installed
    delete fgNetAccessor;
    fgNetAccessor = 0;

    //
    //  Call the method that cleans up the registered lazy eval objects.
    //  This is all higher level code which might try to report errors if
    //  they have problems, so we want to do this before we hose our
    //  fundamental bits and pieces.
    //
    cleanupLazyData();

    //
    //  Call some other internal modules to give them a chance to clean up.
    //  Do the string class last in case something tries to use it during
    //  cleanup.
    //
    XMLString::termString();

    // Clean up the the transcoding service
    delete fgTransService;
    fgTransService = 0;

    // Clean up the sync mutex
    delete gSyncMutex;
    gSyncMutex = 0;

    //
    //  And do platform termination. This cannot do use any XML services
    //  at all, it can only clean up local stuff. It it reports an error,
    //  it cannot use any XML exception or error reporting services.
    //
    platformTerm();

    // And say we are no longer initialized
    gInitFlag = false;
}

// ---------------------------------------------------------------------------
//  XMLPlatformUtils: Msg support methods
// ---------------------------------------------------------------------------
XMLMsgLoader* XMLPlatformUtils::loadMsgSet(const XMLCh* const msgDomain)
{
    //
    //  Ask the platform support to load up the correct type of message
    //  loader for the indicated message set. We don't check here whether it
    //  works or not. That's their decision.
    //
    return loadAMsgSet(msgDomain);
}

// ---------------------------------------------------------------------------
//  XMLPlatformUtils: Lazy eval methods
// ---------------------------------------------------------------------------
void XMLPlatformUtils::registerLazyData(XMLDeleter* const deleter)
{
    // Just add a copy of this object to the vector. MUST be synchronized
    XMLMutexLock lock(gSyncMutex);
    gLazyData->addElement(deleter);
}

void XMLPlatformUtils::cleanupLazyData()
{
    //
    //  Loop through the vector and try to delete each object. Use a try
    //  block so that we don't fall out prematurely if one of them hoses.
    //  Note that we effectively do them in reverse order of their having
    //  been registered.
    //
    //  Also, note that we don't synchronize here because this is happening
    //  during shutdown.
    //
    while (gLazyData->size())
    {
        try
        {
            gLazyData->removeLastElement();
        }

        catch(...)
        {
            // We don't try to report errors here, just fall through
        }
    }
    delete gLazyData;
    gLazyData = 0;
}
<|endoftext|>


<commit_before><commit_msg>PWGGA: Correct TrainCfg Number<commit_after><|endoftext|>


<commit_before>#include <fstream>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <sstream>
#include "bh.h"
#include "bh_ve_cpu.h"

#include "utils.auto.cpp"

void bh_string_option(char *&option, const char *env_name, const char *conf_name)
{
    option = getenv(env_name);           // For the compiler
    if (NULL==option) {
        option = bh_component_config_lookup(&myself, conf_name);
    }
    char err_msg[100];

    if (!option) {
        sprintf(err_msg, "cpu-ve: String is not set; option (%s).\n", conf_name);
        throw runtime_error(err_msg);
    }
}

void bh_path_option(char *&option, const char *env_name, const char *conf_name)
{
    option = getenv(env_name);           // For the compiler
    if (NULL==option) {
        option = bh_component_config_lookup(&myself, conf_name);
    }
    char err_msg[100];

    if (!option) {
        sprintf(err_msg, "cpu-ve: Path is not set; option (%s).\n", conf_name);
        throw runtime_error(err_msg);
    }
    if (0 != access(option, F_OK)) {
        if (ENOENT == errno) {
            sprintf(err_msg, "cpu-ve: Path does not exist; path (%s).\n", option);
        } else if (ENOTDIR == errno) {
            sprintf(err_msg, "cpu-ve: Path is not a directory; path (%s).\n", option);
        } else {
            sprintf(err_msg, "cpu-ve: Path is broken somehow; path (%s).\n", option);
        }
        throw runtime_error(err_msg);
    }
}

/**
 * Read the entire file provided via filename into memory.
 *
 * It is the resposibility of the caller to de-allocate the buffer.
 *
 * @return size_t bytes read.
 */
size_t read_file(const char* filename, char** contents)
{
    int size = 0;

    std::ifstream file(filename, std::ios::in|std::ios::binary|std::ios::ate);

    if (file.is_open()) {
        size = file.tellg();
        *contents = (char*)malloc(size);
        file.seekg(0, std::ios::beg);
        file.read(*contents, size);
        file.close();
    }

    return size;
}

void assign_string(char*& output, const char* input)
{
    size_t length = strlen(input);

    output = (char*)malloc(sizeof(char) * length+1);
    if (!output) {
        std::cout << "Something went terribly wrong!" << std::endl;
    }
    strncpy(output, input, length);
    output[length] = '\0';
}

inline
bool is_contiguous(bh_view *operand)
{
    if ((operand->ndim == 3) && \
        (operand->stride[2] == 1) && \
        (operand->stride[1] == operand->shape[2]) && \
        (operand->stride[0] == operand->shape[2]*operand->shape[1])
    ) {
        return true;
    } else if ((operand->ndim == 2) && \
               (operand->stride[1] == 1) && \
               (operand->stride[0] == operand->shape[1])) {
        return true;
    } else if ((operand->ndim == 1) && (operand->stride[0] == 1)) {
        return true;
    }

    return false;
}

/**
 * Compute the layoutmask of the instruction.
 *
 */
int bh_layoutmask(bh_instruction *instr)
{
    int mask = 0;
    const int nops = bh_operands(instr->opcode);

    switch(nops) {
        case 3:
            mask |= (is_contiguous(&instr->operand[0])) ? A0_CONTIGUOUS : A0_STRIDED;
            if (bh_is_constant(&instr->operand[2])) {
                mask |= (is_contiguous(&instr->operand[1])) ? A1_CONTIGUOUS : A1_STRIDED;
                mask |= A2_CONSTANT;
            } else if (bh_is_constant(&instr->operand[1])) {
                mask |= A1_CONSTANT;
                mask |= (is_contiguous(&instr->operand[2])) ? A2_CONTIGUOUS : A2_STRIDED;
            } else {
                mask |= (is_contiguous(&instr->operand[1])) ? A1_CONTIGUOUS : A1_STRIDED;
                mask |= (is_contiguous(&instr->operand[2])) ? A2_CONTIGUOUS : A2_STRIDED;
            }
            break;

        case 2:
            mask |= (is_contiguous(&instr->operand[0])) ? A0_CONTIGUOUS : A0_STRIDED;
            if (bh_is_constant(&instr->operand[1])) {
                mask |= A1_CONSTANT;
            } else {
                mask |= (is_contiguous(&instr->operand[1])) ? A1_CONTIGUOUS : A1_STRIDED;
            }
            break;

        case 1:
            mask |= (is_contiguous(&instr->operand[0])) ? A0_CONTIGUOUS : A0_STRIDED;
            if (bh_is_constant(&instr->operand[1])) {
                mask |= A1_CONSTANT;
            } else {
                mask |= (is_contiguous(&instr->operand[1])) ? A1_CONTIGUOUS : A1_STRIDED;
            }
            break;

        case 0:
        default:
            break;
    }
    return mask;
}

int bh_typesig(bh_instruction *instr)
{
    int typesig;
    const int nops = bh_operands(instr->opcode);
    switch(nops) {
        case 3:
            typesig = instr->operand[0].base->type+1;

            if (bh_is_constant(&instr->operand[1])) {
                typesig += ((1+instr->constant.type) << 4) \
                          +((1+instr->operand[2].base->type) << 8);

            } else if (bh_is_constant(&instr->operand[2])) {
                typesig += ((1+instr->operand[1].base->type) << 4) \
                          +((1+instr->constant.type) << 8);

            } else {
                typesig += ((1+instr->operand[1].base->type) << 4) \
                          +((1+instr->operand[2].base->type) << 8);
            }
            break;
        case 2:
            typesig = instr->operand[0].base->type+1;

            if (bh_is_constant(&instr->operand[1])) {
                typesig += ((1+instr->constant.type) << 4);
            } else {
                typesig += ((1+instr->operand[1].base->type) << 4);
            }
            break;
        case 1:
            typesig = (1+instr->operand[0].base->type);
            break;
        case 0:
        default:
            typesig = 0;
            break;
    }

    return typesig;
}

const char* bhopcode_to_cexpr(bh_opcode opcode, const bh_type type)
{
    switch(opcode) {

        case BH_ADD_REDUCE:
            return "rvar += *tmp_current";
        case BH_MULTIPLY_REDUCE:
            return "rvar *= *tmp_current";
        case BH_MINIMUM_REDUCE:
            return "rvar = rvar < *tmp_current ? rvar : *tmp_current";
        case BH_MAXIMUM_REDUCE:
            return "rvar = rvar < *tmp_current ? *tmp_current : rvar";
        case BH_LOGICAL_AND_REDUCE:
            return "rvar = rvar && *tmp_current";
        case BH_BITWISE_AND_REDUCE:
            return "rvar &= *tmp_current";
        case BH_LOGICAL_OR_REDUCE:
            return "rvar = rvar || *tmp_current";
        case BH_BITWISE_OR_REDUCE:
            return "rvar |= *tmp_current";

        case BH_LOGICAL_XOR_REDUCE:
            return "rvar = !rvar != !*tmp_current";
        case BH_BITWISE_XOR_REDUCE:
            return "rvar = rvar ^ *tmp_current";

        // Binary elementwise: ADD, MULTIPLY...
        case BH_ADD:
            return "*a0_current = *a1_current + *a2_current";
        case BH_SUBTRACT:
            return "*a0_current = *a1_current - *a2_current";
        case BH_MULTIPLY:
            return "*a0_current = *a1_current * *a2_current";
        case BH_DIVIDE:
            return "*a0_current = *a1_current / *a2_current";
        case BH_POWER:
            return "*a0_current = pow( *a1_current, *a2_current )";
        case BH_GREATER:
            return "*a0_current = *a1_current > *a2_current";
        case BH_GREATER_EQUAL:
            return "*a0_current = *a1_current >= *a2_current";
        case BH_LESS:
            return "*a0_current = *a1_current < *a2_current";
        case BH_LESS_EQUAL:
            return "*a0_current = *a1_current <= *a2_current";
        case BH_EQUAL:
            return "*a0_current = *a1_current == *a2_current";
        case BH_NOT_EQUAL:
            return "*a0_current = *a1_current != *a2_current";
        case BH_LOGICAL_AND:
            return "*a0_current = *a1_current && *a2_current";
        case BH_LOGICAL_OR:
            return "*a0_current = *a1_current || *a2_current";
        case BH_LOGICAL_XOR:
            return "*a0_current = (!*a1_current != !*a2_current)";
        case BH_MAXIMUM:
            return "*a0_current = *a1_current < *a2_current ? *a2_current : *a1_current";
        case BH_MINIMUM:
            return "*a0_current = *a1_current < *a2_current ? *a1_current : *a2_current";
        case BH_BITWISE_AND:
            return "*a0_current = *a1_current & *a2_current";
        case BH_BITWISE_OR:
            return "*a0_current = *a1_current | *a2_current";
        case BH_BITWISE_XOR:
            return "*a0_current = *a1_current ^ *a2_current";
        case BH_LEFT_SHIFT:
            return "*a0_current = (*a1_current) << (*a2_current)";
        case BH_RIGHT_SHIFT:
            return "*a0_current = (*a1_current) >> (*a2_current)";
        case BH_ARCTAN2:
            return "*a0_current = atan2( *a1_current, *a2_current )";
        case BH_MOD:
            return "*a0_current = *a1_current - floor(*a1_current / *a2_current) * *a2_current";

        // Unary elementwise: SQRT, SIN...
        case BH_ABSOLUTE:
            return "*a0_current = *a1_current < 0.0 ? -*a1_current: *a1_current";
        case BH_LOGICAL_NOT:
            return "*a0_current = !*a1_current";
        case BH_INVERT:
            return "*a0_current = ~*a1_current";
        case BH_COS:
            return "*a0_current = cos( *a1_current )";
        case BH_SIN:
            return "*a0_current = sin( *a1_current )";
        case BH_TAN:
            return "*a0_current = tan( *a1_current )";
        case BH_COSH:
            return "*a0_current = cosh( *a1_current )";
        case BH_SINH:
            return "*a0_current = sinh( *a1_current )";
        case BH_TANH:
            return "*a0_current = tanh( *a1_current )";
        case BH_ARCSIN:
            return "*a0_current = asin( *a1_current )";
        case BH_ARCCOS:
            return "*a0_current = acos( *a1_current )";
        case BH_ARCTAN:
            return "*a0_current = atan( *a1_current )";
        case BH_ARCSINH:
            return "*a0_current = asinh( *a1_current )";
        case BH_ARCCOSH:
            return "*a0_current = acosh( *a1_current )";
        case BH_ARCTANH:
            return "*a0_current = atanh( *a1_current )";
        case BH_EXP:
            return "*a0_current = exp( *a1_current )";
        case BH_EXP2:
            return "*a0_current = pow( 2, *a1_current )";
        case BH_EXPM1:
            return "*a0_current = expm1( *a1_current )";
        case BH_LOG:
            return "*a0_current = log( *a1_current )";
        case BH_LOG2:
            return "*a0_current = log2( *a1_current )";
        case BH_LOG10:
            return "*a0_current = log10( *a1_current )";
        case BH_LOG1P:
            return "*a0_current = log1p( *a1_current )";
        case BH_SQRT:
            return "*a0_current = sqrt( *a1_current )";
        case BH_CEIL:
            return "*a0_current = ceil( *a1_current )";
        case BH_TRUNC:
            return "*a0_current = trunc( *a1_current )";
        case BH_FLOOR:
            return "*a0_current = floor( *a1_current )";
        case BH_RINT:
            return "*a0_current = (*a1_current > 0.0) ? floor(*a1_current + 0.5) : ceil(*a1_current - 0.5)";
        case BH_ISNAN:
            return "*a0_current = isnan(*a1_current)";
        case BH_ISINF:
            return "*a0_current = isinf(*a1_current)";
        case BH_IDENTITY:
            return "*a0_current = *a1_current";
        case BH_REAL:
            return (type==BH_FLOAT32) ? "*a0_current = crealf(*a1_current)": "*a0_current = creal(*a1_current)";
        case BH_IMAG:
            return (type==BH_FLOAT32) ? "*a0_current = cimagf(*a1_current)": "*a0_current = cimagf(*a1_current)";

        default:
            return "__UNKNOWN__";
    }
}

<commit_msg>fixed mask BUG for instruction that takes one operand<commit_after>#include <fstream>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <sstream>
#include "bh.h"
#include "bh_ve_cpu.h"

#include "utils.auto.cpp"

void bh_string_option(char *&option, const char *env_name, const char *conf_name)
{
    option = getenv(env_name);           // For the compiler
    if (NULL==option) {
        option = bh_component_config_lookup(&myself, conf_name);
    }
    char err_msg[100];

    if (!option) {
        sprintf(err_msg, "cpu-ve: String is not set; option (%s).\n", conf_name);
        throw runtime_error(err_msg);
    }
}

void bh_path_option(char *&option, const char *env_name, const char *conf_name)
{
    option = getenv(env_name);           // For the compiler
    if (NULL==option) {
        option = bh_component_config_lookup(&myself, conf_name);
    }
    char err_msg[100];

    if (!option) {
        sprintf(err_msg, "cpu-ve: Path is not set; option (%s).\n", conf_name);
        throw runtime_error(err_msg);
    }
    if (0 != access(option, F_OK)) {
        if (ENOENT == errno) {
            sprintf(err_msg, "cpu-ve: Path does not exist; path (%s).\n", option);
        } else if (ENOTDIR == errno) {
            sprintf(err_msg, "cpu-ve: Path is not a directory; path (%s).\n", option);
        } else {
            sprintf(err_msg, "cpu-ve: Path is broken somehow; path (%s).\n", option);
        }
        throw runtime_error(err_msg);
    }
}

/**
 * Read the entire file provided via filename into memory.
 *
 * It is the resposibility of the caller to de-allocate the buffer.
 *
 * @return size_t bytes read.
 */
size_t read_file(const char* filename, char** contents)
{
    int size = 0;

    std::ifstream file(filename, std::ios::in|std::ios::binary|std::ios::ate);

    if (file.is_open()) {
        size = file.tellg();
        *contents = (char*)malloc(size);
        file.seekg(0, std::ios::beg);
        file.read(*contents, size);
        file.close();
    }

    return size;
}

void assign_string(char*& output, const char* input)
{
    size_t length = strlen(input);

    output = (char*)malloc(sizeof(char) * length+1);
    if (!output) {
        std::cout << "Something went terribly wrong!" << std::endl;
    }
    strncpy(output, input, length);
    output[length] = '\0';
}

inline
bool is_contiguous(bh_view *operand)
{
    if ((operand->ndim == 3) && \
        (operand->stride[2] == 1) && \
        (operand->stride[1] == operand->shape[2]) && \
        (operand->stride[0] == operand->shape[2]*operand->shape[1])
    ) {
        return true;
    } else if ((operand->ndim == 2) && \
               (operand->stride[1] == 1) && \
               (operand->stride[0] == operand->shape[1])) {
        return true;
    } else if ((operand->ndim == 1) && (operand->stride[0] == 1)) {
        return true;
    }

    return false;
}

/**
 * Compute the layoutmask of the instruction.
 *
 */
int bh_layoutmask(bh_instruction *instr)
{
    int mask = 0;
    const int nops = bh_operands(instr->opcode);

    switch(nops) {
        case 3:
            mask |= (is_contiguous(&instr->operand[0])) ? A0_CONTIGUOUS : A0_STRIDED;
            if (bh_is_constant(&instr->operand[2])) {
                mask |= (is_contiguous(&instr->operand[1])) ? A1_CONTIGUOUS : A1_STRIDED;
                mask |= A2_CONSTANT;
            } else if (bh_is_constant(&instr->operand[1])) {
                mask |= A1_CONSTANT;
                mask |= (is_contiguous(&instr->operand[2])) ? A2_CONTIGUOUS : A2_STRIDED;
            } else {
                mask |= (is_contiguous(&instr->operand[1])) ? A1_CONTIGUOUS : A1_STRIDED;
                mask |= (is_contiguous(&instr->operand[2])) ? A2_CONTIGUOUS : A2_STRIDED;
            }
            break;

        case 2:
            mask |= (is_contiguous(&instr->operand[0])) ? A0_CONTIGUOUS : A0_STRIDED;
            if (bh_is_constant(&instr->operand[1])) {
                mask |= A1_CONSTANT;
            } else {
                mask |= (is_contiguous(&instr->operand[1])) ? A1_CONTIGUOUS : A1_STRIDED;
            }
            break;

        case 1:
            mask |= (is_contiguous(&instr->operand[0])) ? A0_CONTIGUOUS : A0_STRIDED;
            break;

        case 0:
        default:
            break;
    }
    return mask;
}

int bh_typesig(bh_instruction *instr)
{
    int typesig;
    const int nops = bh_operands(instr->opcode);
    switch(nops) {
        case 3:
            typesig = instr->operand[0].base->type+1;

            if (bh_is_constant(&instr->operand[1])) {
                typesig += ((1+instr->constant.type) << 4) \
                          +((1+instr->operand[2].base->type) << 8);

            } else if (bh_is_constant(&instr->operand[2])) {
                typesig += ((1+instr->operand[1].base->type) << 4) \
                          +((1+instr->constant.type) << 8);

            } else {
                typesig += ((1+instr->operand[1].base->type) << 4) \
                          +((1+instr->operand[2].base->type) << 8);
            }
            break;
        case 2:
            typesig = instr->operand[0].base->type+1;

            if (bh_is_constant(&instr->operand[1])) {
                typesig += ((1+instr->constant.type) << 4);
            } else {
                typesig += ((1+instr->operand[1].base->type) << 4);
            }
            break;
        case 1:
            typesig = (1+instr->operand[0].base->type);
            break;
        case 0:
        default:
            typesig = 0;
            break;
    }

    return typesig;
}

const char* bhopcode_to_cexpr(bh_opcode opcode, const bh_type type)
{
    switch(opcode) {

        case BH_ADD_REDUCE:
            return "rvar += *tmp_current";
        case BH_MULTIPLY_REDUCE:
            return "rvar *= *tmp_current";
        case BH_MINIMUM_REDUCE:
            return "rvar = rvar < *tmp_current ? rvar : *tmp_current";
        case BH_MAXIMUM_REDUCE:
            return "rvar = rvar < *tmp_current ? *tmp_current : rvar";
        case BH_LOGICAL_AND_REDUCE:
            return "rvar = rvar && *tmp_current";
        case BH_BITWISE_AND_REDUCE:
            return "rvar &= *tmp_current";
        case BH_LOGICAL_OR_REDUCE:
            return "rvar = rvar || *tmp_current";
        case BH_BITWISE_OR_REDUCE:
            return "rvar |= *tmp_current";

        case BH_LOGICAL_XOR_REDUCE:
            return "rvar = !rvar != !*tmp_current";
        case BH_BITWISE_XOR_REDUCE:
            return "rvar = rvar ^ *tmp_current";

        // Binary elementwise: ADD, MULTIPLY...
        case BH_ADD:
            return "*a0_current = *a1_current + *a2_current";
        case BH_SUBTRACT:
            return "*a0_current = *a1_current - *a2_current";
        case BH_MULTIPLY:
            return "*a0_current = *a1_current * *a2_current";
        case BH_DIVIDE:
            return "*a0_current = *a1_current / *a2_current";
        case BH_POWER:
            return "*a0_current = pow( *a1_current, *a2_current )";
        case BH_GREATER:
            return "*a0_current = *a1_current > *a2_current";
        case BH_GREATER_EQUAL:
            return "*a0_current = *a1_current >= *a2_current";
        case BH_LESS:
            return "*a0_current = *a1_current < *a2_current";
        case BH_LESS_EQUAL:
            return "*a0_current = *a1_current <= *a2_current";
        case BH_EQUAL:
            return "*a0_current = *a1_current == *a2_current";
        case BH_NOT_EQUAL:
            return "*a0_current = *a1_current != *a2_current";
        case BH_LOGICAL_AND:
            return "*a0_current = *a1_current && *a2_current";
        case BH_LOGICAL_OR:
            return "*a0_current = *a1_current || *a2_current";
        case BH_LOGICAL_XOR:
            return "*a0_current = (!*a1_current != !*a2_current)";
        case BH_MAXIMUM:
            return "*a0_current = *a1_current < *a2_current ? *a2_current : *a1_current";
        case BH_MINIMUM:
            return "*a0_current = *a1_current < *a2_current ? *a1_current : *a2_current";
        case BH_BITWISE_AND:
            return "*a0_current = *a1_current & *a2_current";
        case BH_BITWISE_OR:
            return "*a0_current = *a1_current | *a2_current";
        case BH_BITWISE_XOR:
            return "*a0_current = *a1_current ^ *a2_current";
        case BH_LEFT_SHIFT:
            return "*a0_current = (*a1_current) << (*a2_current)";
        case BH_RIGHT_SHIFT:
            return "*a0_current = (*a1_current) >> (*a2_current)";
        case BH_ARCTAN2:
            return "*a0_current = atan2( *a1_current, *a2_current )";
        case BH_MOD:
            return "*a0_current = *a1_current - floor(*a1_current / *a2_current) * *a2_current";

        // Unary elementwise: SQRT, SIN...
        case BH_ABSOLUTE:
            return "*a0_current = *a1_current < 0.0 ? -*a1_current: *a1_current";
        case BH_LOGICAL_NOT:
            return "*a0_current = !*a1_current";
        case BH_INVERT:
            return "*a0_current = ~*a1_current";
        case BH_COS:
            return "*a0_current = cos( *a1_current )";
        case BH_SIN:
            return "*a0_current = sin( *a1_current )";
        case BH_TAN:
            return "*a0_current = tan( *a1_current )";
        case BH_COSH:
            return "*a0_current = cosh( *a1_current )";
        case BH_SINH:
            return "*a0_current = sinh( *a1_current )";
        case BH_TANH:
            return "*a0_current = tanh( *a1_current )";
        case BH_ARCSIN:
            return "*a0_current = asin( *a1_current )";
        case BH_ARCCOS:
            return "*a0_current = acos( *a1_current )";
        case BH_ARCTAN:
            return "*a0_current = atan( *a1_current )";
        case BH_ARCSINH:
            return "*a0_current = asinh( *a1_current )";
        case BH_ARCCOSH:
            return "*a0_current = acosh( *a1_current )";
        case BH_ARCTANH:
            return "*a0_current = atanh( *a1_current )";
        case BH_EXP:
            return "*a0_current = exp( *a1_current )";
        case BH_EXP2:
            return "*a0_current = pow( 2, *a1_current )";
        case BH_EXPM1:
            return "*a0_current = expm1( *a1_current )";
        case BH_LOG:
            return "*a0_current = log( *a1_current )";
        case BH_LOG2:
            return "*a0_current = log2( *a1_current )";
        case BH_LOG10:
            return "*a0_current = log10( *a1_current )";
        case BH_LOG1P:
            return "*a0_current = log1p( *a1_current )";
        case BH_SQRT:
            return "*a0_current = sqrt( *a1_current )";
        case BH_CEIL:
            return "*a0_current = ceil( *a1_current )";
        case BH_TRUNC:
            return "*a0_current = trunc( *a1_current )";
        case BH_FLOOR:
            return "*a0_current = floor( *a1_current )";
        case BH_RINT:
            return "*a0_current = (*a1_current > 0.0) ? floor(*a1_current + 0.5) : ceil(*a1_current - 0.5)";
        case BH_ISNAN:
            return "*a0_current = isnan(*a1_current)";
        case BH_ISINF:
            return "*a0_current = isinf(*a1_current)";
        case BH_IDENTITY:
            return "*a0_current = *a1_current";
        case BH_REAL:
            return (type==BH_FLOAT32) ? "*a0_current = crealf(*a1_current)": "*a0_current = creal(*a1_current)";
        case BH_IMAG:
            return (type==BH_FLOAT32) ? "*a0_current = cimagf(*a1_current)": "*a0_current = cimagf(*a1_current)";

        default:
            return "__UNKNOWN__";
    }
}

<|endoftext|>


<commit_before>/*
 * Copyright 2010, The Android Open Source Project
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "android/app/l10n_util.h"

#include "base/logging.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"

namespace l10n_util {

class JNIHelper {
    public:
        JNIHelper();
        ~JNIHelper();
        string16 getLocalisedString(int message_id);

    private:
        JNIEnv* mEnv;
        jclass mClassRef;
        string16 mMessageCache[ANDROID_L10N_IDS_MESSAGE_COUNT];
};

JNIHelper jniHelper;

JNIHelper::JNIHelper()
    : mEnv(0)
{
}

JNIHelper::~JNIHelper()
{
    if (mEnv)
        mEnv->DeleteGlobalRef(mClassRef);
}

string16 JNIHelper::getLocalisedString(int message_id)
{
    if (!mEnv) {
        mEnv = android::GetJNIEnv();
        jclass localClass = mEnv->FindClass("android/webkit/L10nUtils");
        mClassRef = static_cast<jclass>(mEnv->NewGlobalRef(localClass));
        mEnv->DeleteLocalRef(localClass);
    }

    if (!mMessageCache[message_id].empty())
        return mMessageCache[message_id];

    DCHECK(mEnv);
    static jmethodID getLocalisedString = mEnv->GetStaticMethodID(mClassRef, "getLocalisedString", "(I)Ljava/lang/String;");
    jstring result = static_cast<jstring>(mEnv->CallStaticObjectMethod(mClassRef, getLocalisedString, message_id));
    string16 str = android::JstringToString16(mEnv, result);
    mEnv->DeleteLocalRef(result);
    mMessageCache[message_id] = str;
    return str;
}

// Implementation of the necessary libchromium l10n utility functions...

string16 GetStringUTF16(int message_id)
{
    return jniHelper.getLocalisedString(message_id);
}

string16 GetStringFUTF16(int message_id, const string16& a, const string16& b, const string16& c)
{
    const string16 str = GetStringUTF16(message_id);
    std::vector<string16> replacements;
    replacements.push_back(a);
    replacements.push_back(b);
    replacements.push_back(c);
    return ReplaceStringPlaceholders(str, replacements, NULL);
}

}
<commit_msg>Use current thread's JNIEnv.<commit_after>/*
 * Copyright 2010, The Android Open Source Project
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "android/app/l10n_util.h"

#include "base/logging.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"

namespace l10n_util {

class JNIHelper {
    public:
        JNIHelper();
        ~JNIHelper();
        string16 getLocalisedString(int message_id);

    private:
        JNIEnv* mEnv;
        jclass mClassRef;
        string16 mMessageCache[ANDROID_L10N_IDS_MESSAGE_COUNT];
};

JNIHelper jniHelper;

JNIHelper::JNIHelper()
    : mEnv(0)
{
}

JNIHelper::~JNIHelper()
{
    if (mEnv) {
        // Because the stored mEnv could be bad during c++ destruction phase
        // since it's thread local.
        JNIEnv* currentEnv = android::GetJNIEnv();
        if (currentEnv)
            currentEnv->DeleteGlobalRef(mClassRef);
    }
}

string16 JNIHelper::getLocalisedString(int message_id)
{
    if (!mEnv) {
        mEnv = android::GetJNIEnv();
        jclass localClass = mEnv->FindClass("android/webkit/L10nUtils");
        mClassRef = static_cast<jclass>(mEnv->NewGlobalRef(localClass));
        mEnv->DeleteLocalRef(localClass);
    }

    if (!mMessageCache[message_id].empty())
        return mMessageCache[message_id];

    DCHECK(mEnv);
    static jmethodID getLocalisedString = mEnv->GetStaticMethodID(mClassRef, "getLocalisedString", "(I)Ljava/lang/String;");
    jstring result = static_cast<jstring>(mEnv->CallStaticObjectMethod(mClassRef, getLocalisedString, message_id));
    string16 str = android::JstringToString16(mEnv, result);
    mEnv->DeleteLocalRef(result);
    mMessageCache[message_id] = str;
    return str;
}

// Implementation of the necessary libchromium l10n utility functions...

string16 GetStringUTF16(int message_id)
{
    return jniHelper.getLocalisedString(message_id);
}

string16 GetStringFUTF16(int message_id, const string16& a, const string16& b, const string16& c)
{
    const string16 str = GetStringUTF16(message_id);
    std::vector<string16> replacements;
    replacements.push_back(a);
    replacements.push_back(b);
    replacements.push_back(c);
    return ReplaceStringPlaceholders(str, replacements, NULL);
}

}
<|endoftext|>


<commit_before>#include <iostream>

using namespace std;

/*
	Project Euler #1 - Multiples of 3 and 5

	If we list all the natural numbers below 10 that are multiples of 3 or 5,
	we get 3, 5, 6 and 9. The sum of these multiples is 23.

	Find the sum of all the multiples of 3 or 5 below 1000.
*/

int main()
{
	const unsigned int limit = 1000;
	unsigned int i = 0;
	unsigned int sum = 0;

	while(i < limit)
	{
		if(i % 3  == 0 || i % 5 == 0)
			sum += i;

		i++;
	}

	cout << sum << endl;

	return 0;
}
<commit_msg>Correct problem title.<commit_after>#include <iostream>

using namespace std;

/*
	Project Euler #1 - Multiples of 3 or 5

	If we list all the natural numbers below 10 that are multiples of 3 or 5,
	we get 3, 5, 6 and 9. The sum of these multiples is 23.

	Find the sum of all the multiples of 3 or 5 below 1000.
*/

int main()
{
	const unsigned int limit = 1000;
	unsigned int i = 0;
	unsigned int sum = 0;

	while(i < limit)
	{
		if(i % 3  == 0 || i % 5 == 0)
			sum += i;

		i++;
	}

	cout << sum << endl;

	return 0;
}
<|endoftext|>


<commit_before>#include "API.hpp"
#include "APICamera.hpp"
#include "ros/ros.h"
#include <ros/console.h>
#include <map>

//messages
#include "api_application/System.h"
#include "api_application/SetFormation.h"
#include "api_application/Formation.h"
#include "api_application/MoveFormation.h"

using namespace kitrokopter;

/**
 * Initializes the API which means starting the announcement service.
 *
 * @param argc remapping arguments from the command line for ros
 * @param argv remapping arguments from the command line for ros
 * @param sync whether to do blocking ROS spinning
 */
API::API(int argc, char **argv, bool sync)
{
    this->idCounter = 0;
    //this->formation = NULL;
    this->controllerIds = std::vector<int>(1);
    this->positionIds = std::vector<int>(5);
    this->cameraSystem = APICameraSystem();

    ros::init(argc, argv, "api_server");
    ros::NodeHandle nodeHandle;
    announceService = nodeHandle.advertiseService("announce", &API::announce, this);
    ROS_INFO("Ready to deliver IDs.");

    formationPublisher = nodeHandle.advertise<api_application::Formation>("Formation", 1);
    ROS_INFO("Ready to send a formation.");

    formationMovementPublisher = nodeHandle.advertise<api_application::MoveFormation>("MoveFormation", 1);
    ROS_INFO("Ready to move a formation.");

    systemPublisher = nodeHandle.advertise<api_application::System>("System", 1);
    ROS_INFO("Ready to send system signals.");

    if (sync) {
       ros::spin();
    } else {
       spinner = new ros::AsyncSpinner(1);
       spinner->start();
    }
}

/**
 * Destructs the API, stopping the ROS spinner.
 */
API::~API()
{
   delete spinner;
}

/**
 * Start the system
 */
void API::startSystem() {
    this->sendSystemSignal(STARTUP);
}

/**
 * Shutdown the system
 */
void API::shutdownSystem() {
    this->sendSystemSignal(SHUTDOWN);
}

/**
 * Send a system signal.
 *
 * @param signal the signal to send
 */
void API::sendSystemSignal(uint8_t signal) {
    api_application::System message;
    message.header.stamp = ros::Time::now();
    message.command = signal;
    this->systemPublisher.publish(message);
}

/**
 * Get a pointer to the APIQuadcopter with the corresponding id
 * or a null pointer if there is no such APIQuadcopter.
 *
 * @param id the APIQuadcopter's id
 * @return the APIQuadcopter with this id or a null pointer if there is no such APIQuadcopter
 */
APIQuadcopter* API::getQuadcopter(int id) {
    if (this->quadcopters.find(id) != this->quadcopters.end()) {
	return &this->quadcopters[id];
    } else {
	return NULL;
    }
}

/**
 * Removes the APIQuadcopter with the corresponding id.
 *
 * @param id the APIQuadcopter's id
 * @return whether there was a APIQuadcopter with this id to remove
 */
bool API::removeQuadcopter(int id) {
    if (this->quadcopters.find(id) != this->quadcopters.end()) {
	quadcopters.erase(id);
	return true;
    } else {
	return false;
    }
}

/**
 * Get all channels where a quadcopter is online.
 *
 * @return array of channels
 */
std::vector<uint8_t> API::scanChannels() {
   if (this->quadcopters.size() == 0) {
       throw new std::runtime_error("no quadcopter module to scan with");
   }
   return this->quadcopters.begin()->second.scanChannels();
}

/**
 * Scan for all available quadcopters and distribute them to the quadcopter modules.
 *
 * @return whether the function was able to distribute all quadcopter channels or or give all quadcopter modules a channel.
 */
bool API::initializeQuadcopters() {
    if (this->quadcopters.size() == 0) {
        return false;
    }
    std::vector<uint8_t> channels = this->scanChannels();
    if (channels.size() == 0){
        return false;
    }
    int max;
    if (this->quadcopters.size() > channels.size()) {
    	max = channels.size();
    } else {
    	max = this->quadcopters.size();
    }
    std::map<uint32_t, APIQuadcopter>::iterator quadIt = this->quadcopters.begin();
    for (int i = 0; i < max; i++)
    {
    	if (quadIt->second.connectOnChannel(channels[i]) == false)
    	{
    		return false;
    	}
    	quadIt++;
    }
    sendQuadcoptersToController();
    return true;
}

/**
 * Initialize the controller
 */
void API::sendQuadcoptersToController() {
    /**
     * since the service does not provide a good way
     * to deal with quadcopters not selected for flight
     * send only "selected for flight" quadcopters
     */
    ros::NodeHandle nodeHandle;
    ros::ServiceClient client = nodeHandle.serviceClient<control_application::SetQuadcopters>("SetQuadcopters");
    control_application::SetQuadcopters srv;
    srv.request.header.stamp = ros::Time::now();
    std::vector<APIQuadcopter*> result;
    for (std::map<uint32_t, APIQuadcopter>::iterator it =
        this->quadcopters.begin(); it != this->quadcopters.end(); ++it)
    {
        srv.request.quadcoptersId.push_back(&it->first);
    }
    srv.request.amount = srv.request.quadcoptersId.size();
}

/**
 * Initializes the cameras
 */
void API::initializeCameras() {
    this->cameraSystem.initializeCameras(this->quadcopters);
}

/**
 * Function to be called when the announce service is invoked.
 */
bool API::announce(api_application::Announce::Request &req, api_application::Announce::Response &res)
{
    res.id = idCounter++;
    switch (req.type) {
	case 0:
	    this->cameraSystem.addCamera(APICamera(res.id));
	    break;
	case 1:
	    this->quadcopters[res.id] = APIQuadcopter(res.id);
	    this->quadcopters[res.id].listen();
	    break;
	case 2:
	    this->controllerIds.push_back(res.id);
	    break;
	case 3:
	    this->positionIds.push_back(res.id);
	    break;
	default:
	    ROS_ERROR("Malformed register attempt!");
	    res.id = -1;
	    return false;
    }
    ROS_INFO("Registered new module with type %d and id %d", req.type, res.id);
    return true;
}

/**
 * Initializes the controller
 */
void API::initializeController() {

}

/**
 * Sets a new formation.
 *
 * @param newFormation th enew formation
 */
void API::setFormation(APIFormation newFormation) {
    this->formation = newFormation;
    sendFormation();
}

/**
 * Send the formation to the controller
 */
void API::sendFormation() {
    api_application::Formation msg;
    msg.header.stamp = ros::Time::now();
    msg.distance = this->formation.getMinimumDistance();
    msg.amount = this->formation.getQuadcopterAmount();
    Vector positions = this->formation.getQuadcopterPositions();
    for (std::vector<Vector>::iterator it = positions.begin(); it != positions.end(); ++it)
    {
        msg.xPositions.push_back(it.getX());
        msg.yPositions.push_back(it.getY());
        msg.zPositions.push_back(it.getZ());
    }
}

/**
 * Get a pointer to the formation.
 *
 * @return the formation
 */
APIFormation* API::getFormation() {
    return &this->formation;
}

/**
 * Get a pointer to the camera system
 *
 * @return the pointer
 */
APICameraSystem* API::getCameraSystem()
{
   return &cameraSystem;
}

/**
 * Get a vector of all quadcopters.
 *
 * @return vector of all quadcopters
 */
std::vector<APIQuadcopter*> API::getQuadcopters() {
    std::vector<APIQuadcopter*> result;
    for (std::map<uint32_t, APIQuadcopter>::iterator it =
    			this->quadcopters.begin(); it != this->quadcopters.end(); ++it)
    {
    		result.push_back(&it->second);
    }
    return result;
}

/**
 * Get all quadcopters which are selected to fly in formation.
 *
 * @return a vector of pointers to the quadcopters
 */
std::vector<APIQuadcopter*> API::getQuadcoptersSelectedForFlight() {
    std::vector<APIQuadcopter*> result;
    for (std::map<uint32_t, APIQuadcopter>::iterator it =
        this->quadcopters.begin(); it != this->quadcopters.end(); ++it)
    {
        if (it->second.isSelectedForFlight())
        {
            result.push_back(&it->second);
        }
    }
    return result;
}

/**
 * Get all quadcopters which are selected to fly in formation.
 *
 * @return a vector of pointers to the quadcopters
 */
std::vector<APIQuadcopter*> API::getQuadcoptersNotSelectedForFlight() {
    std::vector<APIQuadcopter*> result;
    for (std::map<uint32_t, APIQuadcopter>::iterator it =
        this->quadcopters.begin(); it != this->quadcopters.end(); ++it)
    {
        if (!it->second.isSelectedForFlight())
        {
            result.push_back(&it->second);
        }
    }
    return result;
}

/**
 * Get all quadcopters which are selected to fly in formation.
 *
 * @return a vector of pointers to the quadcopters
 */
std::vector<APICamera*> API::getCameras() {
    return this->cameraSystem.getCamerasAsVector();
}

/**
 * Move the formation by a vector
 *
 * @param vector the vector for moving the formation
 */
void API::moveFormation(Vector vector) {
    api_application::MoveFormation message;
    message.header.stamp = ros::Time::now();
    message.xMovement = vector.getX();
    message.yMovement = vector.getY();
    message.ZMovement = vector.getZ();
    this->systemPublisher.publish(message);
}
<commit_msg>Changed to setformation<commit_after>#include "API.hpp"
#include "APICamera.hpp"
#include "ros/ros.h"
#include <ros/console.h>
#include <map>

//messages
#include "api_application/System.h"
#include "api_application/SetFormation.h"
#include "api_application/MoveFormation.h"

using namespace kitrokopter;

/**
 * Initializes the API which means starting the announcement service.
 *
 * @param argc remapping arguments from the command line for ros
 * @param argv remapping arguments from the command line for ros
 * @param sync whether to do blocking ROS spinning
 */
API::API(int argc, char **argv, bool sync)
{
    this->idCounter = 0;
    //this->formation = NULL;
    this->controllerIds = std::vector<int>(1);
    this->positionIds = std::vector<int>(5);
    this->cameraSystem = APICameraSystem();

    ros::init(argc, argv, "api_server");
    ros::NodeHandle nodeHandle;
    announceService = nodeHandle.advertiseService("announce", &API::announce, this);
    ROS_INFO("Ready to deliver IDs.");

    formationPublisher = nodeHandle.advertise<api_application::SetFormation>("SetFormation", 1);
    ROS_INFO("Ready to send a formation.");

    formationMovementPublisher = nodeHandle.advertise<api_application::MoveFormation>("MoveFormation", 1);
    ROS_INFO("Ready to move a formation.");

    systemPublisher = nodeHandle.advertise<api_application::System>("System", 1);
    ROS_INFO("Ready to send system signals.");

    if (sync) {
       ros::spin();
    } else {
       spinner = new ros::AsyncSpinner(1);
       spinner->start();
    }
}

/**
 * Destructs the API, stopping the ROS spinner.
 */
API::~API()
{
   delete spinner;
}

/**
 * Start the system
 */
void API::startSystem() {
    this->sendSystemSignal(STARTUP);
}

/**
 * Shutdown the system
 */
void API::shutdownSystem() {
    this->sendSystemSignal(SHUTDOWN);
}

/**
 * Send a system signal.
 *
 * @param signal the signal to send
 */
void API::sendSystemSignal(uint8_t signal) {
    api_application::System message;
    message.header.stamp = ros::Time::now();
    message.command = signal;
    this->systemPublisher.publish(message);
}

/**
 * Get a pointer to the APIQuadcopter with the corresponding id
 * or a null pointer if there is no such APIQuadcopter.
 *
 * @param id the APIQuadcopter's id
 * @return the APIQuadcopter with this id or a null pointer if there is no such APIQuadcopter
 */
APIQuadcopter* API::getQuadcopter(int id) {
    if (this->quadcopters.find(id) != this->quadcopters.end()) {
	return &this->quadcopters[id];
    } else {
	return NULL;
    }
}

/**
 * Removes the APIQuadcopter with the corresponding id.
 *
 * @param id the APIQuadcopter's id
 * @return whether there was a APIQuadcopter with this id to remove
 */
bool API::removeQuadcopter(int id) {
    if (this->quadcopters.find(id) != this->quadcopters.end()) {
	quadcopters.erase(id);
	return true;
    } else {
	return false;
    }
}

/**
 * Get all channels where a quadcopter is online.
 *
 * @return array of channels
 */
std::vector<uint8_t> API::scanChannels() {
   if (this->quadcopters.size() == 0) {
       throw new std::runtime_error("no quadcopter module to scan with");
   }
   return this->quadcopters.begin()->second.scanChannels();
}

/**
 * Scan for all available quadcopters and distribute them to the quadcopter modules.
 *
 * @return whether the function was able to distribute all quadcopter channels or or give all quadcopter modules a channel.
 */
bool API::initializeQuadcopters() {
    if (this->quadcopters.size() == 0) {
        return false;
    }
    std::vector<uint8_t> channels = this->scanChannels();
    if (channels.size() == 0){
        return false;
    }
    int max;
    if (this->quadcopters.size() > channels.size()) {
    	max = channels.size();
    } else {
    	max = this->quadcopters.size();
    }
    std::map<uint32_t, APIQuadcopter>::iterator quadIt = this->quadcopters.begin();
    for (int i = 0; i < max; i++)
    {
    	if (quadIt->second.connectOnChannel(channels[i]) == false)
    	{
    		return false;
    	}
    	quadIt++;
    }
    sendQuadcoptersToController();
    return true;
}

/**
 * Initialize the controller
 */
void API::sendQuadcoptersToController() {
    /**
     * since the service does not provide a good way
     * to deal with quadcopters not selected for flight
     * send only "selected for flight" quadcopters
     */
    ros::NodeHandle nodeHandle;
    ros::ServiceClient client = nodeHandle.serviceClient<control_application::SetQuadcopters>("SetQuadcopters");
    control_application::SetQuadcopters srv;
    srv.request.header.stamp = ros::Time::now();
    std::vector<APIQuadcopter*> result;
    for (std::map<uint32_t, APIQuadcopter>::iterator it =
        this->quadcopters.begin(); it != this->quadcopters.end(); ++it)
    {
        srv.request.quadcoptersId.push_back(&it->first);
    }
    srv.request.amount = srv.request.quadcoptersId.size();
}

/**
 * Initializes the cameras
 */
void API::initializeCameras() {
    this->cameraSystem.initializeCameras(this->quadcopters);
}

/**
 * Function to be called when the announce service is invoked.
 */
bool API::announce(api_application::Announce::Request &req, api_application::Announce::Response &res)
{
    res.id = idCounter++;
    switch (req.type) {
	case 0:
	    this->cameraSystem.addCamera(APICamera(res.id));
	    break;
	case 1:
	    this->quadcopters[res.id] = APIQuadcopter(res.id);
	    this->quadcopters[res.id].listen();
	    break;
	case 2:
	    this->controllerIds.push_back(res.id);
	    break;
	case 3:
	    this->positionIds.push_back(res.id);
	    break;
	default:
	    ROS_ERROR("Malformed register attempt!");
	    res.id = -1;
	    return false;
    }
    ROS_INFO("Registered new module with type %d and id %d", req.type, res.id);
    return true;
}

/**
 * Initializes the controller
 */
void API::initializeController() {

}

/**
 * Sets a new formation.
 *
 * @param newFormation th enew formation
 */
void API::setFormation(APIFormation newFormation) {
    this->formation = newFormation;
    sendFormation();
}

/**
 * Send the formation to the controller
 */
void API::sendFormation() {
    api_application::SetFormation msg;
    msg.header.stamp = ros::Time::now();
    msg.distance = this->formation.getMinimumDistance();
    msg.amount = this->formation.getQuadcopterAmount();
    Vector positions = this->formation.getQuadcopterPositions();
    for (std::vector<Vector>::iterator it = positions.begin(); it != positions.end(); ++it)
    {
        msg.xPositions.push_back(it.getX());
        msg.yPositions.push_back(it.getY());
        msg.zPositions.push_back(it.getZ());
    }
}

/**
 * Get a pointer to the formation.
 *
 * @return the formation
 */
APIFormation* API::getFormation() {
    return &this->formation;
}

/**
 * Get a pointer to the camera system
 *
 * @return the pointer
 */
APICameraSystem* API::getCameraSystem()
{
   return &cameraSystem;
}

/**
 * Get a vector of all quadcopters.
 *
 * @return vector of all quadcopters
 */
std::vector<APIQuadcopter*> API::getQuadcopters() {
    std::vector<APIQuadcopter*> result;
    for (std::map<uint32_t, APIQuadcopter>::iterator it =
    			this->quadcopters.begin(); it != this->quadcopters.end(); ++it)
    {
    		result.push_back(&it->second);
    }
    return result;
}

/**
 * Get all quadcopters which are selected to fly in formation.
 *
 * @return a vector of pointers to the quadcopters
 */
std::vector<APIQuadcopter*> API::getQuadcoptersSelectedForFlight() {
    std::vector<APIQuadcopter*> result;
    for (std::map<uint32_t, APIQuadcopter>::iterator it =
        this->quadcopters.begin(); it != this->quadcopters.end(); ++it)
    {
        if (it->second.isSelectedForFlight())
        {
            result.push_back(&it->second);
        }
    }
    return result;
}

/**
 * Get all quadcopters which are selected to fly in formation.
 *
 * @return a vector of pointers to the quadcopters
 */
std::vector<APIQuadcopter*> API::getQuadcoptersNotSelectedForFlight() {
    std::vector<APIQuadcopter*> result;
    for (std::map<uint32_t, APIQuadcopter>::iterator it =
        this->quadcopters.begin(); it != this->quadcopters.end(); ++it)
    {
        if (!it->second.isSelectedForFlight())
        {
            result.push_back(&it->second);
        }
    }
    return result;
}

/**
 * Get all quadcopters which are selected to fly in formation.
 *
 * @return a vector of pointers to the quadcopters
 */
std::vector<APICamera*> API::getCameras() {
    return this->cameraSystem.getCamerasAsVector();
}

/**
 * Move the formation by a vector
 *
 * @param vector the vector for moving the formation
 */
void API::moveFormation(Vector vector) {
    api_application::MoveFormation message;
    message.header.stamp = ros::Time::now();
    message.xMovement = vector.getX();
    message.yMovement = vector.getY();
    message.ZMovement = vector.getZ();
    this->systemPublisher.publish(message);
}
<|endoftext|>


<commit_before>#include "Myasquo.h"
#include <string>
#include <mysql/mysql.h>
#include <mysql/errmsg.h>
#include <boost/asio/placeholders.hpp>

namespace {
std::string path_to_filename(const std::string& path) {
    std::string result = path;
    result.erase(0,path.rfind("/")+1);
    return result;
}

std::string itoa(int i) {
    char buf[20];
    sprintf(buf,"%d",i);
    return std::string(buf);
}
}

#define LOGPREFIX ::path_to_filename(__FILE__)+":"+itoa(__LINE__)+" "

Myasquo::Myasquo(const std::string& hostname,
                 int port,
                 const std::string& username,
                 const std::string& password,
                 const std::string& database,
                 const std::string queuePath):
    m_hostname(hostname),
    m_port(port),
    m_username(username),
    m_password(password),
    m_database(database),
    m_dbQueuePath(queuePath),
    m_connected(false),
    m_conn(NULL),
    m_ownIoService(true),
    m_ioService(new boost::asio::io_service()),
    m_work(*m_ioService),
    m_reconnectTimer(*m_ioService),
    m_reopenTimer(*m_ioService)
{
    if (!m_dbQueue.open(queuePath)) {
        throw std::runtime_error(m_dbQueue.lastError());
    }

    m_ioService->post(boost::bind(&Myasquo::doConnect,this,boost::system::error_code()));
    if (m_ownIoService)
        m_thread = boost::thread(boost::bind(&boost::asio::io_service::run, m_ioService));
}

Myasquo::Myasquo(const std::string &hostname,
                 int port,
                 const std::string &username,
                 const std::string &password,
                 const std::string &database,
                 const std::string queuePath,
                 boost::asio::io_service &io_service):
    m_hostname(hostname),
    m_port(port),
    m_username(username),
    m_password(password),
    m_database(database),
    m_dbQueuePath(queuePath),
    m_connected(false),
    m_ownIoService(false),
    m_ioService(&io_service),
    m_work(*m_ioService),
    m_reconnectTimer(*m_ioService),
    m_reopenTimer(*m_ioService)
{
    if (!m_dbQueue.open(queuePath)) {
        throw std::runtime_error(m_dbQueue.lastError());
    }

    m_ioService->post(boost::bind(&Myasquo::doConnect,this,boost::system::error_code()));
    if (m_ownIoService)
        m_thread = boost::thread(boost::bind(&boost::asio::io_service::run, m_ioService));
}

Myasquo::~Myasquo()
{
    m_reopenTimer.cancel();
    m_reconnectTimer.cancel();
    m_dbQueue.close();
    if (m_ownIoService)
        delete m_ioService;
    m_thread.join();
    if (m_conn) {
        onLogMessage(LOGPREFIX+"Closing MySQL connection",LOG_LEVEL_INFO);
        mysql_close(m_conn);
    }
}

void Myasquo::handleError()
{
    onError();
    if (!m_dbQueue.is_open()) {
        boost::posix_time::time_duration dur = m_reopenTimer.expires_from_now();
        if (dur.total_nanoseconds() <= 0) {
            m_reopenTimer.expires_from_now(boost::posix_time::seconds(1));
            m_reopenTimer.async_wait(
                        boost::bind(&Myasquo::doOpenQueue, this, boost::asio::placeholders::error)
                        );
        }
    }

    if (!m_connected) {
        boost::posix_time::time_duration dur = m_reconnectTimer.expires_from_now();
        if (dur.total_nanoseconds() <= 0) {
            m_reconnectTimer.expires_from_now(boost::posix_time::seconds(1));
            m_reconnectTimer.async_wait(
                        boost::bind(&Myasquo::doConnect, this, boost::asio::placeholders::error)
                        );
        }
    }
}

void Myasquo::query(const std::string &query)
{
    m_ioService->post(boost::bind(&Myasquo::doQuery, this, query));
}

void Myasquo::ping()
{
    m_ioService->post(boost::bind(&Myasquo::doPing, this));
}

void Myasquo::doConnect(const boost::system::error_code& e)
{
    if (e == boost::asio::error::operation_aborted)
        return;

    m_conn = mysql_init(NULL);
    if (!m_conn) throw std::runtime_error("Not enough memory to allocate MySQL");
    m_conn->free_me = 1;
    m_conn->reconnect = 0;

    if (!mysql_real_connect(m_conn,
                            m_hostname.c_str(),
                            m_username.c_str(),
                            m_password.c_str(),
                            m_database.c_str(),
                            m_port,
                            NULL,
                            CLIENT_INTERACTIVE))
    {
        onLogMessage(LOGPREFIX+"Connection to MySQL failed: "+
                     std::string(mysql_error(m_conn)),LOG_LEVEL_WARNING);
        m_connected = false;
        handleError();
        return;
    }

    onLogMessage(LOGPREFIX+"Successfully connected to MySQL",LOG_LEVEL_INFO);
    m_connected = true;

    if (!m_dbQueue.empty())
        doProcessDBQueue();

    onConnect();
}

void Myasquo::doOpenQueue(const boost::system::error_code& e) {
    if (e == boost::asio::error::operation_aborted)
        return;

    if (!m_dbQueue.open(m_dbQueuePath)) {
        onLogMessage(LOGPREFIX+m_dbQueue.lastError(),LOG_LEVEL_WARNING);
        handleError();
    } else {
        onLogMessage(LOGPREFIX+"DBQueue opened: path: "+
                     m_dbQueuePath+" empty:"+ (m_dbQueue.empty()?"yes":"no"),LOG_LEVEL_INFO);
        if (m_connected && !m_dbQueue.empty())
            doProcessDBQueue();
    }
}

void Myasquo::doQuery(const std::string& msg)
{
    if (m_connected) {
        int err = executeQuery(msg);
        if (err) {
            onLogMessage(LOGPREFIX+"Query execution failed: "+ mysql_error(m_conn) +" Query: "+msg,LOG_LEVEL_WARNING);
            if (err>=CR_MIN_ERROR) {
                onLogMessage(LOGPREFIX+"Critical error, reconnecting",LOG_LEVEL_ALERT);
                if (!doPushToDBQueue(msg))
                    m_dbQueue.close();

                mysql_close(m_conn);
                m_connected = false;
                handleError();
            }
        } else
            onLogMessage(LOGPREFIX+"Query execution succeeded. Query: "+msg,LOG_LEVEL_DEBUG);

    }
    else if (!doPushToDBQueue(msg)) {
        m_dbQueue.close();
        handleError();
    }
}

bool Myasquo::doPushToDBQueue(const std::string& msg)
{
    if (m_dbQueue.is_open()) {
        if (!m_dbQueue.push(msg)) {
            onLogMessage(LOGPREFIX+m_dbQueue.lastError(),LOG_LEVEL_WARNING);
            return false;
        } else
            onLogMessage(LOGPREFIX+"Value pushed to DBQueue: "+msg,LOG_LEVEL_DEBUG);
    } else
        onLogMessage(LOGPREFIX+"DBQueue is not opened. Discarding query: "+msg,LOG_LEVEL_WARNING);
    return true;
}

void Myasquo::doProcessDBQueue()
{
    if (!m_connected || m_dbQueue.empty()) return;

    while (!m_dbQueue.empty()) {

        std::string msg = m_dbQueue.front();
        if (msg.empty()) {
            onLogMessage(LOGPREFIX+m_dbQueue.lastError(),LOG_LEVEL_WARNING);
            m_dbQueue.close();
            handleError();
            return;
        } else {
            onLogMessage(LOGPREFIX+"Value taken from DBQueue: "+msg,LOG_LEVEL_DEBUG);
        }

        int err = executeQuery(msg);
        if (err && err>=CR_MIN_ERROR) {
            mysql_close(m_conn);
            m_connected = false;
            handleError();
            return;
        }

        if (!m_dbQueue.pop()) {
            onLogMessage(LOGPREFIX+m_dbQueue.lastError(),LOG_LEVEL_WARNING);
            m_dbQueue.close();
            handleError();
            return;
        } else
            onLogMessage(LOGPREFIX+"Value poped from DBQueue (empty: "+
                         (m_dbQueue.empty()?"yes)":"no)"),LOG_LEVEL_DEBUG);
    }
}

void Myasquo::doPing()
{
    onLogMessage(LOGPREFIX+"Pinging mysql",LOG_LEVEL_DEBUG);
    if (mysql_ping(m_conn) != 0) {
        onLogMessage(LOGPREFIX+"Connection to MySQL failed: "+
                     std::string(mysql_error(m_conn)),LOG_LEVEL_WARNING);
        m_connected = false;
        handleError();
    }
}

int Myasquo::executeQuery(const std::string& msg)
{
    onLogMessage(LOGPREFIX+"Executing query: "+msg,LOG_LEVEL_DEBUG);

    if (mysql_query(m_conn,msg.c_str()) != 0) {
        onLogMessage(LOGPREFIX+"MySQL Query failed: "+
                     std::string(mysql_error(m_conn)),LOG_LEVEL_WARNING);
        return  mysql_errno(m_conn);
    }

    MYSQL_RES *result = mysql_use_result(m_conn);
    if (!result) return mysql_errno(m_conn);
    int numFields = mysql_num_fields(result);
    MYSQL_ROW row;
    while (row = mysql_fetch_row(result)) {
         if (!onQueryResultRow(row,numFields,mysql_fetch_lengths(result))) {
           while (mysql_fetch_row(result)) {} //read the rest and return
           break;
         }
    }
    onQueryResultRow(NULL,0,NULL);
    mysql_free_result(result);

    return 0;
}
<commit_msg>Something...<commit_after>#include "Myasquo.h"
#include <string>
#include <mysql/mysql.h>
#include <mysql/errmsg.h>
#include <boost/asio/placeholders.hpp>

namespace {
std::string path_to_filename(const std::string& path) {
    std::string result = path;
    result.erase(0,path.rfind("/")+1);
    return result;
}

std::string itoa(int i) {
    char buf[20];
    sprintf(buf,"%d",i);
    return std::string(buf);
}
}

#define LOGPREFIX ::path_to_filename(__FILE__)+":"+itoa(__LINE__)+" "

Myasquo::Myasquo(const std::string& hostname,
                 int port,
                 const std::string& username,
                 const std::string& password,
                 const std::string& database,
                 const std::string queuePath):
    m_hostname(hostname),
    m_port(port),
    m_username(username),
    m_password(password),
    m_database(database),
    m_dbQueuePath(queuePath),
    m_connected(false),
    m_conn(NULL),
    m_ownIoService(true),
    m_ioService(new boost::asio::io_service()),
    m_work(*m_ioService),
    m_reconnectTimer(*m_ioService),
    m_reopenTimer(*m_ioService)
{
    if (!m_dbQueue.open(queuePath)) {
        throw std::runtime_error(m_dbQueue.lastError());
    }

    m_ioService->post(boost::bind(&Myasquo::doConnect,this,boost::system::error_code()));
    if (m_ownIoService)
        m_thread = boost::thread(boost::bind(&boost::asio::io_service::run, m_ioService));
}

Myasquo::Myasquo(const std::string &hostname,
                 int port,
                 const std::string &username,
                 const std::string &password,
                 const std::string &database,
                 const std::string queuePath,
                 boost::asio::io_service &io_service):
    m_hostname(hostname),
    m_port(port),
    m_username(username),
    m_password(password),
    m_database(database),
    m_dbQueuePath(queuePath),
    m_connected(false),
    m_ownIoService(false),
    m_ioService(&io_service),
    m_work(*m_ioService),
    m_reconnectTimer(*m_ioService),
    m_reopenTimer(*m_ioService)
{
    if (!m_dbQueue.open(queuePath)) {
        throw std::runtime_error(m_dbQueue.lastError());
    }

    m_ioService->post(boost::bind(&Myasquo::doConnect,this,boost::system::error_code()));
    if (m_ownIoService)
        m_thread = boost::thread(boost::bind(&boost::asio::io_service::run, m_ioService));
}

Myasquo::~Myasquo()
{
    m_reopenTimer.cancel();
    m_reconnectTimer.cancel();
    m_dbQueue.close();
    if (m_ownIoService) {
        delete m_ioService;
        m_thread.join();
    }
    if (m_conn) {
        mysql_close(m_conn);
    }
    onLogMessage(LOGPREFIX+"Closing MySQL connection",LOG_LEVEL_INFO);
}

void Myasquo::handleError()
{
    onError();
    if (!m_dbQueue.is_open()) {
        boost::posix_time::time_duration dur = m_reopenTimer.expires_from_now();
        if (dur.total_nanoseconds() <= 0) {
            m_reopenTimer.expires_from_now(boost::posix_time::seconds(1));
            m_reopenTimer.async_wait(
                        boost::bind(&Myasquo::doOpenQueue, this, boost::asio::placeholders::error)
                        );
        }
    }

    if (!m_connected) {
        boost::posix_time::time_duration dur = m_reconnectTimer.expires_from_now();
        if (dur.total_nanoseconds() <= 0) {
            m_reconnectTimer.expires_from_now(boost::posix_time::seconds(1));
            m_reconnectTimer.async_wait(
                        boost::bind(&Myasquo::doConnect, this, boost::asio::placeholders::error)
                        );
        }
    }
}

void Myasquo::query(const std::string &query)
{
    m_ioService->post(boost::bind(&Myasquo::doQuery, this, query));
}

void Myasquo::ping()
{
    m_ioService->post(boost::bind(&Myasquo::doPing, this));
}

void Myasquo::doConnect(const boost::system::error_code& e)
{
    if (e == boost::asio::error::operation_aborted)
        return;

    m_conn = mysql_init(NULL);
    if (!m_conn) throw std::runtime_error("Not enough memory to allocate MySQL");
    m_conn->free_me = 1;
    m_conn->reconnect = 0;

    if (!mysql_real_connect(m_conn,
                            m_hostname.c_str(),
                            m_username.c_str(),
                            m_password.c_str(),
                            m_database.c_str(),
                            m_port,
                            NULL,
                            CLIENT_INTERACTIVE))
    {
        onLogMessage(LOGPREFIX+"Connection to MySQL failed: "+
                     std::string(mysql_error(m_conn)),LOG_LEVEL_WARNING);
        m_connected = false;
        handleError();
        return;
    }

    onLogMessage(LOGPREFIX+"Successfully connected to MySQL",LOG_LEVEL_INFO);
    m_connected = true;

    if (!m_dbQueue.empty())
        doProcessDBQueue();

    onConnect();
}

void Myasquo::doOpenQueue(const boost::system::error_code& e) {
    if (e == boost::asio::error::operation_aborted)
        return;

    if (!m_dbQueue.open(m_dbQueuePath)) {
        onLogMessage(LOGPREFIX+m_dbQueue.lastError(),LOG_LEVEL_WARNING);
        handleError();
    } else {
        onLogMessage(LOGPREFIX+"DBQueue opened: path: "+
                     m_dbQueuePath+" empty:"+ (m_dbQueue.empty()?"yes":"no"),LOG_LEVEL_INFO);
        if (m_connected && !m_dbQueue.empty())
            doProcessDBQueue();
    }
}

void Myasquo::doQuery(const std::string& msg)
{
    if (m_connected) {
        int err = executeQuery(msg);
        if (err) {
            onLogMessage(LOGPREFIX+"Query execution failed: "+ mysql_error(m_conn) +" Query: "+msg,LOG_LEVEL_WARNING);
            if (err>=CR_MIN_ERROR) {
                onLogMessage(LOGPREFIX+"Critical error, reconnecting",LOG_LEVEL_ALERT);
                if (!doPushToDBQueue(msg))
                    m_dbQueue.close();

                mysql_close(m_conn);
                m_connected = false;
                handleError();
            }
        } else
            onLogMessage(LOGPREFIX+"Query execution succeeded. Query: "+msg,LOG_LEVEL_DEBUG);

    }
    else if (!doPushToDBQueue(msg)) {
        m_dbQueue.close();
        handleError();
    }
}

bool Myasquo::doPushToDBQueue(const std::string& msg)
{
    if (m_dbQueue.is_open()) {
        if (!m_dbQueue.push(msg)) {
            onLogMessage(LOGPREFIX+m_dbQueue.lastError(),LOG_LEVEL_WARNING);
            return false;
        } else
            onLogMessage(LOGPREFIX+"Value pushed to DBQueue: "+msg,LOG_LEVEL_DEBUG);
    } else
        onLogMessage(LOGPREFIX+"DBQueue is not opened. Discarding query: "+msg,LOG_LEVEL_WARNING);
    return true;
}

void Myasquo::doProcessDBQueue()
{
    if (!m_connected || m_dbQueue.empty()) return;

    while (!m_dbQueue.empty()) {

        std::string msg = m_dbQueue.front();
        if (msg.empty()) {
            onLogMessage(LOGPREFIX+m_dbQueue.lastError(),LOG_LEVEL_WARNING);
            m_dbQueue.close();
            handleError();
            return;
        } else {
            onLogMessage(LOGPREFIX+"Value taken from DBQueue: "+msg,LOG_LEVEL_DEBUG);
        }

        int err = executeQuery(msg);
        if (err && err>=CR_MIN_ERROR) {
            mysql_close(m_conn);
            m_connected = false;
            handleError();
            return;
        }

        if (!m_dbQueue.pop()) {
            onLogMessage(LOGPREFIX+m_dbQueue.lastError(),LOG_LEVEL_WARNING);
            m_dbQueue.close();
            handleError();
            return;
        } else
            onLogMessage(LOGPREFIX+"Value poped from DBQueue (empty: "+
                         (m_dbQueue.empty()?"yes)":"no)"),LOG_LEVEL_DEBUG);
    }
}

void Myasquo::doPing()
{
    onLogMessage(LOGPREFIX+"Pinging mysql",LOG_LEVEL_DEBUG);
    if (mysql_ping(m_conn) != 0) {
        onLogMessage(LOGPREFIX+"Connection to MySQL failed: "+
                     std::string(mysql_error(m_conn)),LOG_LEVEL_WARNING);
        m_connected = false;
        handleError();
    }
}

int Myasquo::executeQuery(const std::string& msg)
{
    onLogMessage(LOGPREFIX+"Executing query: "+msg,LOG_LEVEL_DEBUG);

    if (mysql_query(m_conn,msg.c_str()) != 0) {
        onLogMessage(LOGPREFIX+"MySQL Query failed: "+
                     std::string(mysql_error(m_conn)),LOG_LEVEL_WARNING);
        return  mysql_errno(m_conn);
    }

    MYSQL_RES *result = mysql_use_result(m_conn);
    if (!result) return mysql_errno(m_conn);
    int numFields = mysql_num_fields(result);
    MYSQL_ROW row;
    while (row = mysql_fetch_row(result)) {
         if (!onQueryResultRow(row,numFields,mysql_fetch_lengths(result))) {
           while (mysql_fetch_row(result)) {} //read the rest and return
           break;
         }
    }
    onQueryResultRow(NULL,0,NULL);
    mysql_free_result(result);

    return 0;
}
<|endoftext|>