<commit_before>#include "StdAfx.h"
#include "Rw2Decoder.h"

/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009 Klaus Post

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

    http://www.klauspost.com
*/
namespace RawSpeed {

Rw2Decoder::Rw2Decoder(TiffIFD *rootIFD, FileMap* file) :
    RawDecoder(file), mRootIFD(rootIFD), input_start(0) {
      decoderVersion = 1;
}
Rw2Decoder::~Rw2Decoder(void) {
  if (input_start)
    delete input_start;
  input_start = 0;
}

RawImage Rw2Decoder::decodeRaw() {

  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(PANASONIC_STRIPOFFSET);

  bool isOldPanasonic = FALSE;

  if (data.empty()) {
    if (!mRootIFD->hasEntryRecursive(STRIPOFFSETS))
      ThrowRDE("RW2 Decoder: No image data found");
    isOldPanasonic = TRUE;
    data = mRootIFD->getIFDsWithTag(STRIPOFFSETS);
  }

  TiffIFD* raw = data[0];
  uint32 height = raw->getEntry((TiffTag)3)->getShort();
  uint32 width = raw->getEntry((TiffTag)2)->getShort();

  mRaw->dim = iPoint2D(width, height);
  mRaw->bpp = 2;
  mRaw->createData();

  if (isOldPanasonic) {
    TiffEntry *offsets = raw->getEntry(STRIPOFFSETS);
    TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS);

    if (offsets->count != 1) {
      ThrowRDE("RW2 Decoder: Multiple Strips found: %u", offsets->count);
    }
    int off = offsets->getInt();
    if (!mFile->isValid(off))
      ThrowRDE("Panasonic RAW Decoder: Invalid image data offset, cannot decode.");

    int count = counts->getInt();
    if (count != (int)(width*height*2))
      ThrowRDE("Panasonic RAW Decoder: Byte count is wrong.");

    ByteStream input_start(mFile->getData(off), mFile->getSize() - off);
    iPoint2D pos(0, 0);
    readUncompressedRaw(input_start, mRaw->dim,pos, width*2, 16, FALSE);

  } else {

    TiffEntry *offsets = raw->getEntry(PANASONIC_STRIPOFFSET);

    if (offsets->count != 1) {
      ThrowRDE("RW2 Decoder: Multiple Strips found: %u", offsets->count);
    }

    load_flags = 0x2008;
    int off = offsets->getInt();

    if (!mFile->isValid(off))
      ThrowRDE("RW2 Decoder: Invalid image data offset, cannot decode.");

    input_start = new ByteStream(mFile->getData(off), mFile->getSize() - off);
    DecodeRw2();
  }
  return mRaw;
}

void Rw2Decoder::DecodeRw2() {
  startThreads();
}

void Rw2Decoder::decodeThreaded(RawDecoderThread * t) {
  int x, i, j, sh = 0, pred[2], nonz[2];
  int w = mRaw->dim.x / 14;
  uint32 y;

  /* 9 + 1/7 bits per pixel */
  int skip = w * 14 * t->start_y * 9;
  skip += w * 2 * t->start_y;
  skip /= 8;

  PanaBitpump bits(new ByteStream(input_start));
  bits.load_flags = load_flags;
  bits.skipBytes(skip);

  for (y = t->start_y; y < t->end_y; y++) {
    ushort16* dest = (ushort16*)mRaw->getData(0, y);
    for (x = 0; x < w; x++) {
      pred[0] = pred[1] = nonz[0] = nonz[1] = 0;
      for (i = 0; i < 14; i++) {
        // Even pixels
        if (i % 3 == 2)
          sh = 4 >> (3 - bits.getBits(2));
        if (nonz[0]) {
          if ((j = bits.getBits(8))) {
            if ((pred[0] -= 0x80 << sh) < 0 || sh == 4)
              pred[0] &= ~(-1 << sh);
            pred[0] += j << sh;
          }
        } else if ((nonz[0] = bits.getBits(8)) || i > 11)
          pred[0] = nonz[0] << 4 | bits.getBits(4);
        *dest++ = pred[0];

        // Odd pixels
        i++;
        if (i % 3 == 2)
          sh = 4 >> (3 - bits.getBits(2));
        if (nonz[1]) {
          if ((j = bits.getBits(8))) {
            if ((pred[1] -= 0x80 << sh) < 0 || sh == 4)
              pred[1] &= ~(-1 << sh);
            pred[1] += j << sh;
          }
        } else if ((nonz[1] = bits.getBits(8)) || i > 11)
          pred[1] = nonz[1] << 4 | bits.getBits(4);
        *dest++ = pred[1];
      }
    }
  }
}

void Rw2Decoder::checkSupport(CameraMetaData *meta) {
  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL);
  if (data.empty())
    ThrowRDE("RW2 Support check: Model name found");

  string make = data[0]->getEntry(MAKE)->getString();
  string model = data[0]->getEntry(MODEL)->getString();
  this->checkCameraSupported(meta, make, model, getMode(model));
}

void Rw2Decoder::decodeMetaData(CameraMetaData *meta) {
  mRaw->cfa.setCFA(CFA_BLUE, CFA_GREEN, CFA_GREEN2, CFA_RED);
  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL);

  if (data.empty())
    ThrowRDE("CR2 Meta Decoder: Model name not found");

  string make = data[0]->getEntry(MAKE)->getString();
  string model = data[0]->getEntry(MODEL)->getString();
  string mode = getMode(model);

  setMetaData(meta, make, model, mode);
}

bool Rw2Decoder::almostEqualRelative(float A, float B, float maxRelativeError) {
  if (A == B)
    return true;

  float relativeError = fabs((A - B) / B);
  if (relativeError <= maxRelativeError)
    return true;
  return false;
}

std::string Rw2Decoder::getMode(const string model) {
  float ratio = 3.0f / 2.0f;  // Default
  if (mRaw->isAllocated()) {
    ratio = (float)mRaw->dim.x / (float)mRaw->dim.y;
  }

  if (almostEqualRelative(ratio, 16.0f / 9.0f, 0.02f))
    return "16:9";
  if (almostEqualRelative(ratio, 3.0f / 2.0f, 0.02f))
    return "3:2";
  if (almostEqualRelative(ratio, 4.0f / 3.0f, 0.02f))
    return "4:3";
  if (almostEqualRelative(ratio, 1.0f, 0.02f))
    return "1:1";

  return "";
}

PanaBitpump::PanaBitpump(ByteStream* _input) : input(_input), vbits(0) {
}

PanaBitpump::~PanaBitpump() {
  if (input)
    delete input;
  input = 0;
}

void PanaBitpump::skipBytes(int bytes) {
  int blocks = (bytes / 0x4000) * 0x4000;
  input->skipBytes(blocks);
  for (int i = blocks; i < bytes; i++)
    getBits(8);
}

uint32 PanaBitpump::getBits(int nbits) {
  int byte;

  if (!vbits) {
    /* On truncated files this routine will just return just for the truncated
    * part of the file. Since there is no chance of affecting output buffer
    * size we allow the decoder to decode this
    */
    if (input->getRemainSize() < 0x4000 - load_flags) {
      memcpy(buf + load_flags, input->getData(), input->getRemainSize());
      input->skipBytes(input->getRemainSize());
    } else {
      memcpy(buf + load_flags, input->getData(), 0x4000 - load_flags);
      input->skipBytes(0x4000 - load_flags);
      if (input->getRemainSize() < load_flags) {
        memcpy(buf, input->getData(), input->getRemainSize());
        input->skipBytes(input->getRemainSize());
      } else {
        memcpy(buf, input->getData(), load_flags);
        input->skipBytes(load_flags);
      }
    }
  }
  vbits = (vbits - nbits) & 0x1ffff;
  byte = vbits >> 3 ^ 0x3ff0;
  return (buf[byte] | buf[byte+1] << 8) >> (vbits & 7) & ~(-1 << nbits);
}

} // namespace RawSpeed
<commit_msg>Panasonic: Avoid using mod 3 and keep separate counter. Completely disable old Panasonic images.<commit_after>#include "StdAfx.h"
#include "Rw2Decoder.h"

/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009 Klaus Post

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

    http://www.klauspost.com
*/
namespace RawSpeed {

Rw2Decoder::Rw2Decoder(TiffIFD *rootIFD, FileMap* file) :
    RawDecoder(file), mRootIFD(rootIFD), input_start(0) {
      decoderVersion = 1;
}
Rw2Decoder::~Rw2Decoder(void) {
  if (input_start)
    delete input_start;
  input_start = 0;
}

RawImage Rw2Decoder::decodeRaw() {

  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(PANASONIC_STRIPOFFSET);

  bool isOldPanasonic = FALSE;

  if (data.empty()) {
    if (!mRootIFD->hasEntryRecursive(STRIPOFFSETS))
      ThrowRDE("RW2 Decoder: No image data found");
    isOldPanasonic = TRUE;
    data = mRootIFD->getIFDsWithTag(STRIPOFFSETS);
  }

  TiffIFD* raw = data[0];
  uint32 height = raw->getEntry((TiffTag)3)->getShort();
  uint32 width = raw->getEntry((TiffTag)2)->getShort();

  mRaw->bpp = 2;

  if (isOldPanasonic) {
    ThrowRDE("Cannot decoder old-style Panasonic RAW files");
    TiffEntry *offsets = raw->getEntry(STRIPOFFSETS);
    TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS);

    if (offsets->count != 1) {
      ThrowRDE("RW2 Decoder: Multiple Strips found: %u", offsets->count);
    }
    int off = offsets->getInt();
    if (!mFile->isValid(off))
      ThrowRDE("Panasonic RAW Decoder: Invalid image data offset, cannot decode.");

    int count = counts->getInt();
    if (count != (int)(width*height*2))
      ThrowRDE("Panasonic RAW Decoder: Byte count is wrong.");

    if (!mFile->isValid(off+count))
      ThrowRDE("Panasonic RAW Decoder: Invalid image data offset, cannot decode.");

    mRaw->dim = iPoint2D(width, height);
    mRaw->createData();
    ByteStream input_start(mFile->getData(off), mFile->getSize() - off);
    iPoint2D pos(0, 0);
    readUncompressedRaw(input_start, mRaw->dim,pos, width*2, 16, FALSE);

  } else {

    mRaw->dim = iPoint2D(width, height);
    mRaw->createData();
    TiffEntry *offsets = raw->getEntry(PANASONIC_STRIPOFFSET);

    if (offsets->count != 1) {
      ThrowRDE("RW2 Decoder: Multiple Strips found: %u", offsets->count);
    }

    load_flags = 0x2008;
    int off = offsets->getInt();

    if (!mFile->isValid(off))
      ThrowRDE("RW2 Decoder: Invalid image data offset, cannot decode.");

    input_start = new ByteStream(mFile->getData(off), mFile->getSize() - off);
    DecodeRw2();
  }
  return mRaw;
}

void Rw2Decoder::DecodeRw2() {
  startThreads();
}

void Rw2Decoder::decodeThreaded(RawDecoderThread * t) {
  int x, i, j, sh = 0, pred[2], nonz[2];
  int w = mRaw->dim.x / 14;
  uint32 y;

  /* 9 + 1/7 bits per pixel */
  int skip = w * 14 * t->start_y * 9;
  skip += w * 2 * t->start_y;
  skip /= 8;

  PanaBitpump bits(new ByteStream(input_start));
  bits.load_flags = load_flags;
  bits.skipBytes(skip);

  for (y = t->start_y; y < t->end_y; y++) {
    ushort16* dest = (ushort16*)mRaw->getData(0, y);
    for (x = 0; x < w; x++) {
      pred[0] = pred[1] = nonz[0] = nonz[1] = 0;
      int u = 0;
      for (i = 0; i < 14; i++) {
        // Even pixels
        if (u == 2)
        {
          sh = 4 >> (3 - bits.getBits(2));
          u = -1;
        }
        if (nonz[0]) {
          if ((j = bits.getBits(8))) {
            if ((pred[0] -= 0x80 << sh) < 0 || sh == 4)
              pred[0] &= ~(-1 << sh);
            pred[0] += j << sh;
          }
        } else if ((nonz[0] = bits.getBits(8)) || i > 11)
          pred[0] = nonz[0] << 4 | bits.getBits(4);
        *dest++ = pred[0];

        // Odd pixels
        i++;
        u++;
        if (u == 2)
        {
          sh = 4 >> (3 - bits.getBits(2));
          u = -1;
        }
        if (nonz[1]) {
          if ((j = bits.getBits(8))) {
            if ((pred[1] -= 0x80 << sh) < 0 || sh == 4)
              pred[1] &= ~(-1 << sh);
            pred[1] += j << sh;
          }
        } else if ((nonz[1] = bits.getBits(8)) || i > 11)
          pred[1] = nonz[1] << 4 | bits.getBits(4);
        *dest++ = pred[1];
        u++;
      }
    }
  }
}

void Rw2Decoder::checkSupport(CameraMetaData *meta) {
  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL);
  if (data.empty())
    ThrowRDE("RW2 Support check: Model name found");

  string make = data[0]->getEntry(MAKE)->getString();
  string model = data[0]->getEntry(MODEL)->getString();
  this->checkCameraSupported(meta, make, model, getMode(model));
}

void Rw2Decoder::decodeMetaData(CameraMetaData *meta) {
  mRaw->cfa.setCFA(CFA_BLUE, CFA_GREEN, CFA_GREEN2, CFA_RED);
  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL);

  if (data.empty())
    ThrowRDE("CR2 Meta Decoder: Model name not found");

  string make = data[0]->getEntry(MAKE)->getString();
  string model = data[0]->getEntry(MODEL)->getString();
  string mode = getMode(model);

  setMetaData(meta, make, model, mode);
}

bool Rw2Decoder::almostEqualRelative(float A, float B, float maxRelativeError) {
  if (A == B)
    return true;

  float relativeError = fabs((A - B) / B);
  if (relativeError <= maxRelativeError)
    return true;
  return false;
}

std::string Rw2Decoder::getMode(const string model) {
  float ratio = 3.0f / 2.0f;  // Default
  if (mRaw->isAllocated()) {
    ratio = (float)mRaw->dim.x / (float)mRaw->dim.y;
  }

  if (almostEqualRelative(ratio, 16.0f / 9.0f, 0.02f))
    return "16:9";
  if (almostEqualRelative(ratio, 3.0f / 2.0f, 0.02f))
    return "3:2";
  if (almostEqualRelative(ratio, 4.0f / 3.0f, 0.02f))
    return "4:3";
  if (almostEqualRelative(ratio, 1.0f, 0.02f))
    return "1:1";

  return "";
}

PanaBitpump::PanaBitpump(ByteStream* _input) : input(_input), vbits(0) {
}

PanaBitpump::~PanaBitpump() {
  if (input)
    delete input;
  input = 0;
}

void PanaBitpump::skipBytes(int bytes) {
  int blocks = (bytes / 0x4000) * 0x4000;
  input->skipBytes(blocks);
  for (int i = blocks; i < bytes; i++)
    getBits(8);
}

uint32 PanaBitpump::getBits(int nbits) {
  int byte;

  if (!vbits) {
    /* On truncated files this routine will just return just for the truncated
    * part of the file. Since there is no chance of affecting output buffer
    * size we allow the decoder to decode this
    */
    if (input->getRemainSize() < 0x4000 - load_flags) {
      memcpy(buf + load_flags, input->getData(), input->getRemainSize());
      input->skipBytes(input->getRemainSize());
    } else {
      memcpy(buf + load_flags, input->getData(), 0x4000 - load_flags);
      input->skipBytes(0x4000 - load_flags);
      if (input->getRemainSize() < load_flags) {
        memcpy(buf, input->getData(), input->getRemainSize());
        input->skipBytes(input->getRemainSize());
      } else {
        memcpy(buf, input->getData(), load_flags);
        input->skipBytes(load_flags);
      }
    }
  }
  vbits = (vbits - nbits) & 0x1ffff;
  byte = vbits >> 3 ^ 0x3ff0;
  return (buf[byte] | buf[byte+1] << 8) >> (vbits & 7) & ~(-1 << nbits);
}

} // namespace RawSpeed
<|endoftext|>


<commit_before>/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is [Open Source Virtual Machine.].
 *
 * The Initial Developer of the Original Code is
 * Adobe System Incorporated.
 * Portions created by the Initial Developer are Copyright (C) 2004-2006
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Adobe AS3 Team
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

#include "MMgc.h"

#define MMGC_SCALAR_GUARD 0xafafafaf
#define MMGC_NORM_VECTOR_GUARD 0xbfbf0001
#define MMGC_PRIM_VECTOR_GUARD 0xbfbf0002

namespace MMgc
{
	void *AllocCall(size_t s, FixedMallocOpts opts)
	{
		return AllocCallInline(s, opts);
	}

	void DeleteCall( void* p )
	{
		DeleteCallInline(p);
	}

#ifdef MMGC_USE_SYSTEM_MALLOC
	void *SystemNew(size_t size)
	{
		void *space = VMPI_alloc(size);
		GCHeap::GetGCHeap()->TrackSystemAlloc(space, size);
		return space;
	}

	void SystemDelete(void *p)
	{
		GCHeap::GetGCHeap()->TrackSystemFree(p);
		VMPI_free(p);
	}
#endif
};

#ifndef MMGC_OVERRIDE_GLOBAL_NEW

void* operator new(size_t size, MMgc::NewDummyOperand /*ignored*/) MMGC_NEW_THROWS_CLAUSE
{
	return MMgc::NewCall(size);
}

void* operator new(size_t size, MMgc::NewDummyOperand /*ignored*/, MMgc::FixedMallocOpts opts) MMGC_NEW_THROWS_CLAUSE
{
	return MMgc::NewCall(size, opts);
}

namespace MMgc
{
	REALLY_INLINE void *GuardedFixedAlloc(size_t size, FixedMallocOpts opts, uint32_t guard)
	{
#ifdef MMGC_DELETE_DEBUGGING
		// lets store a guard cookie so that we can see if it is released with a proper delete (scalar/vector)
		size += sizeof(size_t);
#else
		(void)guard; // get rid of warning
#endif //MMGC_DELETE_DEBUGGING

		size_t* mem = (size_t*)AllocCallInline(size, opts);

#ifdef MMGC_DELETE_DEBUGGING
		if ( mem )
		{
			// add the guard cookie
			*(mem) = guard;
			mem += 1;
		}
#endif // MMGC_DELETE_DEBUGGING

		return mem;
	}

	/*REALLY_INLINE*/
	void* NewCall(size_t size, FixedMallocOpts opts)
	{
		GCAssertMsg(GCHeap::GetGCHeap()->StackEnteredCheck(), "MMGC_ENTER macro must exist on the stack");
		return GuardedFixedAlloc(size, opts, MMGC_SCALAR_GUARD);
	}

	REALLY_INLINE size_t CallocSizeCalc(size_t el_size, size_t count, bool& overflow, bool addCookie)
	{
		uint64_t size = (uint64_t)count * (uint64_t)el_size;

		if(addCookie)
			size += sizeof(size_t);

		if(size > 0xfffffff0)
		{
			overflow = true;
			return 0;
		}
		return (size_t)size;
	}

	void* NewArrayCalloc(size_t el_size, size_t count, FixedMallocOpts opts, bool isPrimitive)
	{
		GCAssertMsg(GCHeap::GetGCHeap()->StackEnteredCheck(), "MMGC_ENTER macro must exist on the stack");

		bool overflow = false;
		size_t size = CallocSizeCalc(el_size, count, overflow, isPrimitive ? false : true);
		if(overflow)
		{
			GCAssertMsg(false, "Attempted allocation overflows size_t\n");
			return NULL;
		}

		return GuardedFixedAlloc(size, opts, isPrimitive ? MMGC_PRIM_VECTOR_GUARD : MMGC_NORM_VECTOR_GUARD);
	}

#ifdef MMGC_DELETE_DEBUGGING
	// Helper functions to check the
	bool CheckForAllocationGuard(size_t* mem, size_t guard)
	{
		mem--;
		return (*mem == guard);
	}

	bool IsScalarAllocation(void* p)
	{
		return CheckForAllocationGuard((size_t*)p, MMGC_SCALAR_GUARD);
	}

	bool IsVectorAllocation(void* p, bool primitive)
	{
		// Check if we have vector guard right before the pointer.
		size_t* w = (size_t*)p;
		size_t guard = primitive ? MMGC_PRIM_VECTOR_GUARD : MMGC_NORM_VECTOR_GUARD;
		return CheckForAllocationGuard(w, guard) || // simple vector
			CheckForAllocationGuard(w-1, guard); // vector with count
	}

	bool IsGCHeapAllocation(void* p)
	{
		return (GCHeap::GetGCHeap() && GCHeap::GetGCHeap()->IsAddressInHeap(p));
	}

	void VerifyScalarDelete(void* p)
	{
		if (!IsScalarAllocation(p))
		{
			if (IsVectorAllocation(p, true) || IsVectorAllocation(p, false))
			{
				GCAssertMsg(0, "Trying to release array pointer with scalar destructor! Check the allocation and free calls for this object!");
			}
			else if (!IsGCHeapAllocation(p))
			{
				GCAssertMsg(0, "Trying to release system memory with scalar deletefunc! Check the allocation and free calls for this object!");
			}
			else
			{
				GCAssertMsg(0, "Trying to release funky memory with scalar deletefunc! Check the allocation and free calls for this object!");
			}
		}
	}

	void VerifyVectorDelete(void* p, bool primitive)
	{
		if (!IsVectorAllocation(p, primitive))
		{
			if (IsVectorAllocation(p, !primitive))
			{
				GCAssertMsg(0, "Trying to release array pointer with different type destructor! Check the allocation and free calls for this object!");
			}
			if (IsScalarAllocation(p))
			{
				GCAssertMsg(0, "Trying to release scalar pointer with vector destructor! Check the allocation and free calls for this object!");
			}
			else if (!IsGCHeapAllocation(p))
			{
				GCAssertMsg(0, "Trying to release system pointer with vector deletefunc! Check the allocation and free calls for this object!");
			}
			else
			{
				GCAssertMsg(0, "Trying to release funky memory with vector deletefunc! Check the allocation and free calls for this object!");
			}
		}
	}

#endif //MMGC_DELETE_DEBUGGING

	// Functions to actually release the memory through FixedMalloc.
	void DeleteFunc( void* p )
	{
#ifdef MMGC_DELETE_DEBUGGING
		// we need to adjust the pointer to release also the guard.
		size_t* temp = (size_t*)p;
		temp--;
		p = temp;
#endif //MMGC_DELETE_DEBUGGING

		DeleteCallInline(p);
	}

	void DeleteArrayFunc( void* p )
	{
		if( p )
		{
#ifdef MMGC_DELETE_DEBUGGING
			p = ((size_t*)p - 2);
#else
			p = ((size_t*)p - 1);
#endif //MMGC_DELETE_DEBUGGING
			DeleteCallInline(p);
		}
	}

	void SimpleDestructorCall(void* p)
	{
		if( p )
		{
#ifdef MMGC_DELETE_DEBUGGING
			VerifyScalarDelete( p );
#endif
			DeleteFunc( p );
		}
	}

	void SimpleDestructorArrayCall(void* p, bool primitive)
	{
		if(p)
		{
#ifdef MMGC_DELETE_DEBUGGING
			VerifyVectorDelete( p, primitive );
#else
			(void)primitive; // get rid of warning
#endif
			// not using DeleteArrayFunc, that's for non-Simple case with count cookie
			DeleteFunc( p );
		}
	}

} // namespace MMgc

#endif //MMGC_OVERRIDE_GLOBAL_NEW
<commit_msg>Disable MMGC_ENTER requirement for can fail allocations<commit_after>/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is [Open Source Virtual Machine.].
 *
 * The Initial Developer of the Original Code is
 * Adobe System Incorporated.
 * Portions created by the Initial Developer are Copyright (C) 2004-2006
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Adobe AS3 Team
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

#include "MMgc.h"

#define MMGC_SCALAR_GUARD 0xafafafaf
#define MMGC_NORM_VECTOR_GUARD 0xbfbf0001
#define MMGC_PRIM_VECTOR_GUARD 0xbfbf0002

namespace MMgc
{
	void *AllocCall(size_t s, FixedMallocOpts opts)
	{
		return AllocCallInline(s, opts);
	}

	void DeleteCall( void* p )
	{
		DeleteCallInline(p);
	}

#ifdef MMGC_USE_SYSTEM_MALLOC
	void *SystemNew(size_t size)
	{
		void *space = VMPI_alloc(size);
		GCHeap::GetGCHeap()->TrackSystemAlloc(space, size);
		return space;
	}

	void SystemDelete(void *p)
	{
		GCHeap::GetGCHeap()->TrackSystemFree(p);
		VMPI_free(p);
	}
#endif
};

#ifndef MMGC_OVERRIDE_GLOBAL_NEW

void* operator new(size_t size, MMgc::NewDummyOperand /*ignored*/) MMGC_NEW_THROWS_CLAUSE
{
	return MMgc::NewCall(size);
}

void* operator new(size_t size, MMgc::NewDummyOperand /*ignored*/, MMgc::FixedMallocOpts opts) MMGC_NEW_THROWS_CLAUSE
{
	return MMgc::NewCall(size, opts);
}

namespace MMgc
{
	REALLY_INLINE void *GuardedFixedAlloc(size_t size, FixedMallocOpts opts, uint32_t guard)
	{
#ifdef MMGC_DELETE_DEBUGGING
		// lets store a guard cookie so that we can see if it is released with a proper delete (scalar/vector)
		size += sizeof(size_t);
#else
		(void)guard; // get rid of warning
#endif //MMGC_DELETE_DEBUGGING

		size_t* mem = (size_t*)AllocCallInline(size, opts);

#ifdef MMGC_DELETE_DEBUGGING
		if ( mem )
		{
			// add the guard cookie
			*(mem) = guard;
			mem += 1;
		}
#endif // MMGC_DELETE_DEBUGGING

		return mem;
	}

	/*REALLY_INLINE*/
	void* NewCall(size_t size, FixedMallocOpts opts)
	{
		GCAssertMsg(GCHeap::GetGCHeap()->StackEnteredCheck() || (opts&kCanFail) != 0, "MMGC_ENTER macro must exist on the stack");
		return GuardedFixedAlloc(size, opts, MMGC_SCALAR_GUARD);
	}

	REALLY_INLINE size_t CallocSizeCalc(size_t el_size, size_t count, bool& overflow, bool addCookie)
	{
		uint64_t size = (uint64_t)count * (uint64_t)el_size;

		if(addCookie)
			size += sizeof(size_t);

		if(size > 0xfffffff0)
		{
			overflow = true;
			return 0;
		}
		return (size_t)size;
	}

	void* NewArrayCalloc(size_t el_size, size_t count, FixedMallocOpts opts, bool isPrimitive)
	{
		GCAssertMsg(GCHeap::GetGCHeap()->StackEnteredCheck() || (opts&kCanFail) != 0, "MMGC_ENTER macro must exist on the stack");

		bool overflow = false;
		size_t size = CallocSizeCalc(el_size, count, overflow, isPrimitive ? false : true);
		if(overflow)
		{
			GCAssertMsg(false, "Attempted allocation overflows size_t\n");
			return NULL;
		}

		return GuardedFixedAlloc(size, opts, isPrimitive ? MMGC_PRIM_VECTOR_GUARD : MMGC_NORM_VECTOR_GUARD);
	}

#ifdef MMGC_DELETE_DEBUGGING
	// Helper functions to check the
	bool CheckForAllocationGuard(size_t* mem, size_t guard)
	{
		mem--;
		return (*mem == guard);
	}

	bool IsScalarAllocation(void* p)
	{
		return CheckForAllocationGuard((size_t*)p, MMGC_SCALAR_GUARD);
	}

	bool IsVectorAllocation(void* p, bool primitive)
	{
		// Check if we have vector guard right before the pointer.
		size_t* w = (size_t*)p;
		size_t guard = primitive ? MMGC_PRIM_VECTOR_GUARD : MMGC_NORM_VECTOR_GUARD;
		return CheckForAllocationGuard(w, guard) || // simple vector
			CheckForAllocationGuard(w-1, guard); // vector with count
	}

	bool IsGCHeapAllocation(void* p)
	{
		return (GCHeap::GetGCHeap() && GCHeap::GetGCHeap()->IsAddressInHeap(p));
	}

	void VerifyScalarDelete(void* p)
	{
		if (!IsScalarAllocation(p))
		{
			if (IsVectorAllocation(p, true) || IsVectorAllocation(p, false))
			{
				GCAssertMsg(0, "Trying to release array pointer with scalar destructor! Check the allocation and free calls for this object!");
			}
			else if (!IsGCHeapAllocation(p))
			{
				GCAssertMsg(0, "Trying to release system memory with scalar deletefunc! Check the allocation and free calls for this object!");
			}
			else
			{
				GCAssertMsg(0, "Trying to release funky memory with scalar deletefunc! Check the allocation and free calls for this object!");
			}
		}
	}

	void VerifyVectorDelete(void* p, bool primitive)
	{
		if (!IsVectorAllocation(p, primitive))
		{
			if (IsVectorAllocation(p, !primitive))
			{
				GCAssertMsg(0, "Trying to release array pointer with different type destructor! Check the allocation and free calls for this object!");
			}
			if (IsScalarAllocation(p))
			{
				GCAssertMsg(0, "Trying to release scalar pointer with vector destructor! Check the allocation and free calls for this object!");
			}
			else if (!IsGCHeapAllocation(p))
			{
				GCAssertMsg(0, "Trying to release system pointer with vector deletefunc! Check the allocation and free calls for this object!");
			}
			else
			{
				GCAssertMsg(0, "Trying to release funky memory with vector deletefunc! Check the allocation and free calls for this object!");
			}
		}
	}

#endif //MMGC_DELETE_DEBUGGING

	// Functions to actually release the memory through FixedMalloc.
	void DeleteFunc( void* p )
	{
#ifdef MMGC_DELETE_DEBUGGING
		// we need to adjust the pointer to release also the guard.
		size_t* temp = (size_t*)p;
		temp--;
		p = temp;
#endif //MMGC_DELETE_DEBUGGING

		DeleteCallInline(p);
	}

	void DeleteArrayFunc( void* p )
	{
		if( p )
		{
#ifdef MMGC_DELETE_DEBUGGING
			p = ((size_t*)p - 2);
#else
			p = ((size_t*)p - 1);
#endif //MMGC_DELETE_DEBUGGING
			DeleteCallInline(p);
		}
	}

	void SimpleDestructorCall(void* p)
	{
		if( p )
		{
#ifdef MMGC_DELETE_DEBUGGING
			VerifyScalarDelete( p );
#endif
			DeleteFunc( p );
		}
	}

	void SimpleDestructorArrayCall(void* p, bool primitive)
	{
		if(p)
		{
#ifdef MMGC_DELETE_DEBUGGING
			VerifyVectorDelete( p, primitive );
#else
			(void)primitive; // get rid of warning
#endif
			// not using DeleteArrayFunc, that's for non-Simple case with count cookie
			DeleteFunc( p );
		}
	}

} // namespace MMgc

#endif //MMGC_OVERRIDE_GLOBAL_NEW
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

/// \ingroup macros
/// \file runSimulation.C
/// \brief Macro for running simulation
///
/// Macro extracted from the MUON test script
///
/// \author Laurent Aphecetche

#if !defined(__CINT__) || defined(__MAKECINT__)
#include "AliCDBManager.h"
#include "AliSimulation.h"
#include "AliRun.h"
#include "AliHeader.h"
#include <TRandom.h>
#include <Riostream.h>
#endif

void runSimulation(int seed,
                   int nevents,
                   const char* config,
                   const char* embedwith,
                   int runnumber)
{
// Uncoment following lines to run simulation with local residual mis-alignment
// (generated via MUONGenerateGeometryData.C macro)
// AliCDBManager* man = AliCDBManager::Instance();
// man->SetDefaultStorage("local://$ALICE_ROOT/OCDB");
// man->SetSpecificStorage("MUON/Align/Data","local://$ALICE_ROOT/OCDB/MUON/ResMisAlignCDB");

  AliSimulation MuonSim(config);

  if ( strlen(embedwith) > 0 )
  {
    // setups specific to embedding

    gAlice->SetConfigFunction("Config(\"\", \"param\", \"AliMUONDigitStoreV2S\",kTRUE);");

    // get the run number from real data

    AliRunLoader* runLoader = AliRunLoader::Open(embedwith,"titi");
    if (runLoader == 0x0)
    {
      cerr << Form("Cannot open file %s",embedwith) << endl;
      return;
    }

    runLoader->LoadHeader();

    if ( ! runLoader->GetHeader() ) {
      cerr << "Cannot load header." << endl;
      return;
    }
    else {
      Int_t runNumber = runLoader->GetHeader()->GetRun();
      MuonSim.SetRunNumber(runNumber);
      cout << Form("***** RUN NUMBER SET TO %09d ACCORDING TO %s ",runNumber,embedwith) << endl;
    }
    runLoader->UnloadHeader();
    delete runLoader;

    cout << "***** EMBEDDING MODE : USING RAW OCDB" << endl;
    AliCDBManager::Instance()->SetDefaultStorage("raw://");
    AliCDBManager::Instance()->SetSpecificStorage("local://$ALICE_ROOT/OCDB","MUON/Align/Data");

  }
  else if ( runnumber > 0 )
  {
    // simulation with anchor run

    cout << "***** ANCHOR RUN MODE : USING RAW OCDB AS MUCH AS POSSIBLE" << endl;
    cout << "*****                   AND TAKING VERTEX FROM OCDB IF AVAILABLE" << endl;

    // Last parameter of Config.C indicates we're doing realistic simulations, so we NEED
    // the ITS in the geometry
    gAlice->SetConfigFunction("Config(\"\", \"param\", \"AliMUONDigitStoreV2S\",kFALSE,kTRUE);");

    AliCDBManager::Instance()->SetDefaultStorage("raw://");
    // use something like : "alien://folder=/alice/data/2011/OCDB?cacheFold=/Users/laurent/OCDBcache" instead of "raw://"
    // if getting slow/problematic accesses to OCDB...

    AliCDBManager::Instance()->SetSpecificStorage("MUON/Align/Data","alien://folder=/alice/cern.ch/user/j/jcastill/LHC10hMisAlignCDB");

    MuonSim.SetRunNumber(runnumber);

    MuonSim.UseVertexFromCDB();
  }
  else
  {
    gAlice->SetConfigFunction("Config(\"\", \"param\", \"AliMUONDigitStoreV2S\",kFALSE);");
  }

  MuonSim.SetSeed(seed);
  MuonSim.SetTriggerConfig("MUON");
  MuonSim.SetWriteRawData("MUON ","raw.root",kTRUE);

  MuonSim.SetMakeSDigits("MUON");
  MuonSim.SetMakeDigits("MUON ITS"); // ITS needed to propagate the simulated vertex
  MuonSim.SetMakeDigitsFromHits("ITS"); // ITS needed to propagate the simulated vertex

  MuonSim.SetRunHLT("libAliHLTMUON.so chains=dHLT-sim");

  MuonSim.SetRunQA("MUON:ALL");

  if ( strlen(embedwith) > 0 )
  {
    MuonSim.MergeWith(embedwith);
  }

  MuonSim.Run(nevents);
  //gObjectTable->Print();

}
<commit_msg>test commit<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

/// \ingroup macros
/// \file runSimulation.C
/// \brief Macro for running simulation
///
/// Macro extracted from the MUON test script
///
/// \author Laurent Git Aphecetche

#if !defined(__CINT__) || defined(__MAKECINT__)
#include "AliCDBManager.h"
#include "AliSimulation.h"
#include "AliRun.h"
#include "AliHeader.h"
#include <TRandom.h>
#include <Riostream.h>
#endif

void runSimulation(int seed,
                   int nevents,
                   const char* config,
                   const char* embedwith,
                   int runnumber)
{
// Uncoment following lines to run simulation with local residual mis-alignment
// (generated via MUONGenerateGeometryData.C macro)
// AliCDBManager* man = AliCDBManager::Instance();
// man->SetDefaultStorage("local://$ALICE_ROOT/OCDB");
// man->SetSpecificStorage("MUON/Align/Data","local://$ALICE_ROOT/OCDB/MUON/ResMisAlignCDB");

  AliSimulation MuonSim(config);

  if ( strlen(embedwith) > 0 )
  {
    // setups specific to embedding

    gAlice->SetConfigFunction("Config(\"\", \"param\", \"AliMUONDigitStoreV2S\",kTRUE);");

    // get the run number from real data

    AliRunLoader* runLoader = AliRunLoader::Open(embedwith,"titi");
    if (runLoader == 0x0)
    {
      cerr << Form("Cannot open file %s",embedwith) << endl;
      return;
    }

    runLoader->LoadHeader();

    if ( ! runLoader->GetHeader() ) {
      cerr << "Cannot load header." << endl;
      return;
    }
    else {
      Int_t runNumber = runLoader->GetHeader()->GetRun();
      MuonSim.SetRunNumber(runNumber);
      cout << Form("***** RUN NUMBER SET TO %09d ACCORDING TO %s ",runNumber,embedwith) << endl;
    }
    runLoader->UnloadHeader();
    delete runLoader;

    cout << "***** EMBEDDING MODE : USING RAW OCDB" << endl;
    AliCDBManager::Instance()->SetDefaultStorage("raw://");
    AliCDBManager::Instance()->SetSpecificStorage("local://$ALICE_ROOT/OCDB","MUON/Align/Data");

  }
  else if ( runnumber > 0 )
  {
    // simulation with anchor run

    cout << "***** ANCHOR RUN MODE : USING RAW OCDB AS MUCH AS POSSIBLE" << endl;
    cout << "*****                   AND TAKING VERTEX FROM OCDB IF AVAILABLE" << endl;

    // Last parameter of Config.C indicates we're doing realistic simulations, so we NEED
    // the ITS in the geometry
    gAlice->SetConfigFunction("Config(\"\", \"param\", \"AliMUONDigitStoreV2S\",kFALSE,kTRUE);");

    AliCDBManager::Instance()->SetDefaultStorage("raw://");
    // use something like : "alien://folder=/alice/data/2011/OCDB?cacheFold=/Users/laurent/OCDBcache" instead of "raw://"
    // if getting slow/problematic accesses to OCDB...

    AliCDBManager::Instance()->SetSpecificStorage("MUON/Align/Data","alien://folder=/alice/cern.ch/user/j/jcastill/LHC10hMisAlignCDB");

    MuonSim.SetRunNumber(runnumber);

    MuonSim.UseVertexFromCDB();
  }
  else
  {
    gAlice->SetConfigFunction("Config(\"\", \"param\", \"AliMUONDigitStoreV2S\",kFALSE);");
  }

  MuonSim.SetSeed(seed);
  MuonSim.SetTriggerConfig("MUON");
  MuonSim.SetWriteRawData("MUON ","raw.root",kTRUE);

  MuonSim.SetMakeSDigits("MUON");
  MuonSim.SetMakeDigits("MUON ITS"); // ITS needed to propagate the simulated vertex
  MuonSim.SetMakeDigitsFromHits("ITS"); // ITS needed to propagate the simulated vertex

  MuonSim.SetRunHLT("libAliHLTMUON.so chains=dHLT-sim");

  MuonSim.SetRunQA("MUON:ALL");

  if ( strlen(embedwith) > 0 )
  {
    MuonSim.MergeWith(embedwith);
  }

  MuonSim.Run(nevents);
  //gObjectTable->Print();

}
<|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
The MIT License

Copyright (c) 2008, 2009 Flusspferd contributors (see "CONTRIBUTORS" or
                                       http://flusspferd.org/contributors.txt)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifndef FLUSSPFERD_CREATE_NATIVE_FUNCTION_HPP
#define FLUSSPFERD_CREATE_NATIVE_FUNCTION_HPP

#include "../create.hpp"
#include <boost/version.hpp>
#include <boost/fusion/functional/invocation/invoke.hpp>
#include <boost/fusion/view/joint_view.hpp>
#include <boost/fusion/container/vector/vector10.hpp>
#include <boost/mpl/has_xxx.hpp>
#include <boost/mpl/eval_if.hpp>

namespace flusspferd {

#ifndef IN_DOXYGEN

#if BOOST_VERSION < 104100
#define VECTOR0 boost::fusion::vector0
#else
#define VECTOR0 boost::fusion::vector0<>
#endif

namespace detail {
  template<typename Class>
  struct create_traits<
    Class,
    typename boost::enable_if<
      boost::is_base_of<native_function_base, Class>
    >::type
  >
  {
    typedef Class &result_type;

    typedef boost::parameter::parameters<
      param::tag::arguments,
      name_spec,
      container_spec,
      attributes_spec
    > parameters;

    static result_type create()
    {
      boost::optional<unsigned> determined_arity(Class::determine_arity());

      unsigned arity = 0u;
      if (determined_arity)
        arity = determined_arity.get();

      root_function fun(
          native_function_base::create_function(arity, std::string()));
      return *new Class(fun);
    }

    template<typename ArgPack>
    static result_type
    create(ArgPack const &args) {
      boost::optional<unsigned> determined_arity(Class::determine_arity());

      unsigned arity;
      if (determined_arity)
        arity = determined_arity.get();
      else
        arity = args[param::_arity | 0u];

      flusspferd::root_string name(args[param::_name | flusspferd::string()]);
      root_function fun(
          native_function_base::create_function(
              arity,
              name.to_string()));

      typedef typename boost::parameter::value_type<
          ArgPack,
          param::tag::arguments,
          VECTOR0
        >::type input_arguments_type;

      input_arguments_type input_arguments(
          args[param::_arguments | VECTOR0()]);

      typedef
        boost::fusion::vector1<function>
        obj_seq_type;

      obj_seq_type obj_seq(fun);

      typedef boost::fusion::joint_view<
          obj_seq_type,
          input_arguments_type
        > full_arguments_type;

      full_arguments_type full_arguments(obj_seq, input_arguments);

      return boost::fusion::invoke(new_functor<Class>(), full_arguments);
    }
  };
}

#undef VECTOR0

#endif //IN_DOXYGEN

}

#endif
<commit_msg>feature #178: formally add arity to create<NativeFunction> parameters<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
The MIT License

Copyright (c) 2008, 2009 Flusspferd contributors (see "CONTRIBUTORS" or
                                       http://flusspferd.org/contributors.txt)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifndef FLUSSPFERD_CREATE_NATIVE_FUNCTION_HPP
#define FLUSSPFERD_CREATE_NATIVE_FUNCTION_HPP

#include "../create.hpp"
#include <boost/version.hpp>
#include <boost/fusion/functional/invocation/invoke.hpp>
#include <boost/fusion/view/joint_view.hpp>
#include <boost/fusion/container/vector/vector10.hpp>
#include <boost/mpl/has_xxx.hpp>
#include <boost/mpl/eval_if.hpp>

namespace flusspferd {

#ifndef IN_DOXYGEN

#if BOOST_VERSION < 104100
#define VECTOR0 boost::fusion::vector0
#else
#define VECTOR0 boost::fusion::vector0<>
#endif

namespace detail {
  template<typename Class>
  struct create_traits<
    Class,
    typename boost::enable_if<
      boost::is_base_of<native_function_base, Class>
    >::type
  >
  {
    typedef Class &result_type;

    typedef boost::parameter::parameters<
      param::tag::arguments,
      param::tag::arity,
      name_spec,
      container_spec,
      attributes_spec
    > parameters;

    static result_type create()
    {
      boost::optional<unsigned> determined_arity(Class::determine_arity());

      unsigned arity = 0u;
      if (determined_arity)
        arity = determined_arity.get();

      root_function fun(
          native_function_base::create_function(arity, std::string()));
      return *new Class(fun);
    }

    template<typename ArgPack>
    static result_type
    create(ArgPack const &args) {
      boost::optional<unsigned> determined_arity(Class::determine_arity());

      unsigned arity;
      if (determined_arity)
        arity = determined_arity.get();
      else
        arity = args[param::_arity | 0u];

      flusspferd::root_string name(args[param::_name | flusspferd::string()]);
      root_function fun(
          native_function_base::create_function(
              arity,
              name.to_string()));

      typedef typename boost::parameter::value_type<
          ArgPack,
          param::tag::arguments,
          VECTOR0
        >::type input_arguments_type;

      input_arguments_type input_arguments(
          args[param::_arguments | VECTOR0()]);

      typedef
        boost::fusion::vector1<function>
        obj_seq_type;

      obj_seq_type obj_seq(fun);

      typedef boost::fusion::joint_view<
          obj_seq_type,
          input_arguments_type
        > full_arguments_type;

      full_arguments_type full_arguments(obj_seq, input_arguments);

      return boost::fusion::invoke(new_functor<Class>(), full_arguments);
    }
  };
}

#undef VECTOR0

#endif //IN_DOXYGEN

}

#endif
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * Copyright (c) 2016 Kohei Yoshida
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 ************************************************************************/

#ifndef INCLUDED_MDDS_SIDE_ITERATOR_HPP
#define INCLUDED_MDDS_SIDE_ITERATOR_HPP

#include "mdds/multi_type_vector_types.hpp"

#include <type_traits>
#include <vector>
#include <memory>

namespace mdds { namespace mtv {

template<typename _MtvT>
class collection;

template<typename _MtvT>
class side_iterator
{
    typedef _MtvT mtv_type;
    friend collection<mtv_type>;

    typedef typename mtv_type::size_type size_type;
    typedef typename mtv_type::const_iterator const_iterator;
    typedef typename mtv_type::const_position_type const_position_type;

    /** meta-data about each mtv instance.  */
    struct mtv_item
    {
        const mtv_type* vector;
        const_iterator block_pos;
        const_iterator block_end;

        mtv_item(const mtv_type* v, const const_iterator& bp, const const_iterator& be) :
            vector(v), block_pos(bp), block_end(be) {}
    };

    /** single element value. */
    struct node
    {
        friend class side_iterator;

        /** type of current element */
        mdds::mtv::element_t type;

        /** index of current mtv instance */
        size_type index;

        /** logical position of the current element within the mtv.  */
        size_type position;

        template<typename _Blk>
        typename _Blk::value_type get() const
        {
            return _Blk::at(*__position.first->data, __position.second);
        }

    private:
        /** position object of current element within the mtv instance.  */
        const_position_type __position;
    };

    enum begin_state_type { begin_state };
    enum end_state_type { end_state };

    std::vector<mtv_item> m_vectors;
    node m_cur_node;
    size_type m_elem_pos;
    size_type m_mtv_size;
    uintptr_t m_identity;

    side_iterator(std::vector<mtv_item>&& vectors, size_type mtv_size, uintptr_t identity, begin_state_type);
    side_iterator(std::vector<mtv_item>&& vectors, size_type mtv_size, uintptr_t identity, end_state_type);

public:
    typedef node value_type;

    template<typename _T>
    side_iterator(const _T& begin, const _T& end);

    const value_type& operator*() const
    {
        return m_cur_node;
    }

    const value_type* operator->() const
    {
        return &m_cur_node;
    }

    side_iterator& operator++();

    bool operator== (const side_iterator& other) const;
};

/**
 * Special-purpose collection of multiple multi_type_vector instances to
 * allow them to be traversed "sideways". All involved multi_type_vector
 * instances must be of the same type and length.
 */
template<typename _MtvT>
class collection
{
    typedef _MtvT mtv_type;
    typedef typename mtv_type::size_type size_type;

    std::vector<const mtv_type*> m_vectors;
    size_type m_mtv_size;
    uintptr_t m_identity;

public:

    typedef side_iterator<mtv_type> const_iterator;

    template<typename _T>
    collection(const _T& begin, const _T& end);

    const_iterator begin() const;

    const_iterator end() const;

    size_type size() const;

private:

    std::vector<typename const_iterator::mtv_item> build_iterator_state() const;

    void init_insert_vector(const std::unique_ptr<mtv_type>& p);

    void init_insert_vector(const std::shared_ptr<mtv_type>& p);

    template<typename _T>
    void init_insert_vector(const _T& t,  typename std::enable_if<std::is_pointer<_T>::value>::type* = 0);

    template<typename _T>
    void init_insert_vector(const _T& t,  typename std::enable_if<!std::is_pointer<_T>::value>::type* = 0);

    void check_vector_size(const mtv_type& t);
};

}}

#include "collection_def.inl"

#endif
<commit_msg>Rename the header guard too.<commit_after>/*************************************************************************
 *
 * Copyright (c) 2016 Kohei Yoshida
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 ************************************************************************/

#ifndef INCLUDED_MDDS_COLLECTION_HPP
#define INCLUDED_MDDS_COLLECTION_HPP

#include "mdds/multi_type_vector_types.hpp"

#include <type_traits>
#include <vector>
#include <memory>

namespace mdds { namespace mtv {

template<typename _MtvT>
class collection;

template<typename _MtvT>
class side_iterator
{
    typedef _MtvT mtv_type;
    friend collection<mtv_type>;

    typedef typename mtv_type::size_type size_type;
    typedef typename mtv_type::const_iterator const_iterator;
    typedef typename mtv_type::const_position_type const_position_type;

    /** meta-data about each mtv instance.  */
    struct mtv_item
    {
        const mtv_type* vector;
        const_iterator block_pos;
        const_iterator block_end;

        mtv_item(const mtv_type* v, const const_iterator& bp, const const_iterator& be) :
            vector(v), block_pos(bp), block_end(be) {}
    };

    /** single element value. */
    struct node
    {
        friend class side_iterator;

        /** type of current element */
        mdds::mtv::element_t type;

        /** index of current mtv instance */
        size_type index;

        /** logical position of the current element within the mtv.  */
        size_type position;

        template<typename _Blk>
        typename _Blk::value_type get() const
        {
            return _Blk::at(*__position.first->data, __position.second);
        }

    private:
        /** position object of current element within the mtv instance.  */
        const_position_type __position;
    };

    enum begin_state_type { begin_state };
    enum end_state_type { end_state };

    std::vector<mtv_item> m_vectors;
    node m_cur_node;
    size_type m_elem_pos;
    size_type m_mtv_size;
    uintptr_t m_identity;

    side_iterator(std::vector<mtv_item>&& vectors, size_type mtv_size, uintptr_t identity, begin_state_type);
    side_iterator(std::vector<mtv_item>&& vectors, size_type mtv_size, uintptr_t identity, end_state_type);

public:
    typedef node value_type;

    template<typename _T>
    side_iterator(const _T& begin, const _T& end);

    const value_type& operator*() const
    {
        return m_cur_node;
    }

    const value_type* operator->() const
    {
        return &m_cur_node;
    }

    side_iterator& operator++();

    bool operator== (const side_iterator& other) const;
};

/**
 * Special-purpose collection of multiple multi_type_vector instances to
 * allow them to be traversed "sideways". All involved multi_type_vector
 * instances must be of the same type and length.
 */
template<typename _MtvT>
class collection
{
    typedef _MtvT mtv_type;
    typedef typename mtv_type::size_type size_type;

    std::vector<const mtv_type*> m_vectors;
    size_type m_mtv_size;
    uintptr_t m_identity;

public:

    typedef side_iterator<mtv_type> const_iterator;

    template<typename _T>
    collection(const _T& begin, const _T& end);

    const_iterator begin() const;

    const_iterator end() const;

    size_type size() const;

private:

    std::vector<typename const_iterator::mtv_item> build_iterator_state() const;

    void init_insert_vector(const std::unique_ptr<mtv_type>& p);

    void init_insert_vector(const std::shared_ptr<mtv_type>& p);

    template<typename _T>
    void init_insert_vector(const _T& t,  typename std::enable_if<std::is_pointer<_T>::value>::type* = 0);

    template<typename _T>
    void init_insert_vector(const _T& t,  typename std::enable_if<!std::is_pointer<_T>::value>::type* = 0);

    void check_vector_size(const mtv_type& t);
};

}}

#include "collection_def.inl"

#endif
<|endoftext|>


<commit_before>/***************************************************************************************
* file        : cached_allocator.hpp
* data        : 2016/03/05
* author      : Victor Zarubkin
* contact     : v.s.zarubkin@gmail.com
* copyright   : Copyright (C) 2016  Victor Zarubkin
*             :
* description : This header contains definition of cached_allocator class which can be used to speed-up rapid allocations
*             : and deallocations of memory buffers of the same size. It is best to use this allocator to allocate and deallocate
*             : single instances of objects (memory buffers of size 1).
*             :
* references  : Original (and actual) version of source code can be found here <http://www.github.com/cas4ey/shared_allocator>.
*             :
* license     : This file is part of SharedAllocator.
*             :
*             : SharedAllocator is free software: you can redistribute it and/or modify
*             : it under the terms of the GNU General Public License as published by
*             : the Free Software Foundation, either version 3 of the License, or
*             : (at your option) any later version.
*             :
*             : SharedAllocator is distributed in the hope that it will be useful,
*             : but WITHOUT ANY WARRANTY; without even the implied warranty of
*             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*             : GNU General Public License for more details.
*             :
*             : You should have received a copy of the GNU General Public License
*             : along with SharedAllocator. If not, see <http://www.gnu.org/licenses/>.
*             :
*             : A copy of the GNU General Public License can be found in file LICENSE.
****************************************************************************************/

#ifndef SHARED___ALLOCATOR__SINGLE_CACHED_ALLOCATOR___HPP___
#define SHARED___ALLOCATOR__SINGLE_CACHED_ALLOCATOR___HPP___

#include "shared_allocator/shared_allocator.hpp"
#include <vector>

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace salloc {

    /** \brief Allocator that caches memory for objects for further usage.

    It caches deallocated memory buffers and uses them later to provide fast allocation of memory buffers of the SAME SIZE (or lesser size).

    \note It is better to use this allocator to allocate memory buffers of the same size.

    \note BEST TO USE IF YOU WANT TO ALLOCATE AND DEALLOCATE BUFFERS OF SIZE 1 (SINGLE INSTANCES OF OBJECTS)
    (Best fit for std::list, std::set, std::map BUT NOT for std::vector).

    \ingroup salloc */
    template <class T, class TAlloc = shared_allocator<T> >
    class cached_allocator
    {
    protected:

        typedef cached_allocator<T, TAlloc> ThisType;
        typedef ::std::vector<T*, typename TAlloc::template rebind<T*>::other> MemoryCache;

        MemoryCache m_memoryCache; ///< Memory cache of objects
        TAlloc        m_allocator; ///< Allocator to allocate new instances of T

    public:

        typedef T                         value_type;

        typedef value_type*                  pointer;
        typedef const value_type*      const_pointer;
        typedef void*                   void_pointer;
        typedef const void*       const_void_pointer;

        typedef value_type&                reference;
        typedef const value_type&    const_reference;

        typedef size_t                     size_type;
        typedef ptrdiff_t            difference_type;

        /** \brief Auxiliary struct to convert this type to single_cached_allocator of other type. */
        template <class U>
        struct rebind
        {
            typedef cached_allocator<U, typename TAlloc::template rebind<U>::other> other;
        };

        /** \brief Returns an actual adress of value.

        \note Uses std::addressof */
        pointer address(reference _value) const throw()
        {
            return ::std::addressof(_value);
        }

        /** \brief Returns an actual adress of const value.

        \note Uses std::addressof */
        const_pointer address(const_reference _value) const throw()
        {
            return ::std::addressof(_value);
        }

        /** \brief Default constructor.

        Does nothing. */
        cached_allocator() throw()
        {
        }

        /** \brief Empty copy constructor.

        Does nothing. */
        template <class U>
        cached_allocator(const U&) throw()
        {
        }

        /** \brief Move constructor.

        Moves reserved memory. */
        cached_allocator(ThisType&& _rvalueAlloc) : m_memoryCache(::std::move(_rvalueAlloc.m_memoryCache))
        {
        }

        /** \brief Empty assignment operator.

        Does nothing and returns reference to this allocator. */
        template <class U>
        ThisType& operator=(const U&)
        {
            return *this;
        }

        ~cached_allocator()
        {
            private_clear();
        }

        /** \brief Clear memory cache.

        Also deallocates all cached memory. */
        void clear()
        {
            private_clear();
            m_memoryCache.clear();
        }

        /** \brief Swaps two allocators with their cache.

        \param _anotherAlloc Reference to another allocator. */
        void swap(ThisType& _anotherAlloc)
        {
            m_memoryCache.swap(_anotherAlloc.m_memoryCache);
        }

        /** \brief Reserve memory for certain number of elements.

        Reserves memory for number of buffers of specified size.

        \param _arraySize Required number of elements to reserve (size of one memory buffer).
        \param _reservationsNumber Required number of memory buffers. */
        void reserve(size_type _arraySize, size_type _reservationsNumber)
        {
            m_memoryCache.reserve(m_memoryCache.size() + _reservationsNumber);
            for (size_type i = 0; i < _reservationsNumber; ++i)
            {
                m_memoryCache.push_back(m_allocator.allocate(_arraySize));
            }
        }

        /** \brief Returns number of elements in allocated memory.

        \param _memory Pointer to allocated memory.

        \warning Please, notice that the number of ELEMENTS will be returned (not number of BYTES).

        \note This function made template to avoid compiler errors for allocators that do not have size() function. */
        template <class U>
        inline size_type size(const U* _memory) const
        {
            return m_allocator.size(_memory);
        }

        /** \brief Stores pointer to memory in cache to be used later.

        \param _memory Pointer to allocated memory. */
        void deallocate(pointer _memory, size_type = 0)
        {
            m_memoryCache.push_back(_memory);
        }

        /** \brief Truly deallocates memory.

        \param _memory Pointer to allocated memory. */
        inline void deallocate_force(pointer _memory, size_type = 0)
        {
            m_allocator.deallocate(_memory, 0);
        }

        /** \brief Allocate elements.

        \param _number Required number of elements. */
        pointer allocate(size_type _number = 1)
        {
            if (!m_memoryCache.empty())
            {
                pointer pMem = m_memoryCache.back();
                m_memoryCache.pop_back();
                return _number < 2 ? pMem : m_allocator.allocate(_number, pMem);
            }

            return m_allocator.allocate(_number);
        }

        /** \brief Allocate elements using hint.

        \param _number Required number of elements.
        \param _currentMemory Pointer to memory allocated earlier (it contains size which will be used as a hint). */
        pointer allocate(size_type _number, void* _currentMemory)
        {
            if (!m_memoryCache.empty())
            {
                pointer pMem = m_memoryCache.back();
                m_memoryCache.pop_back();
                return _number < 2 ? pMem : m_allocator.allocate(_number, pMem);
            }

            return m_allocator.allocate(_number, _currentMemory);
        }

        /** \brief Construct new object on preallocated memory using default constructor.

        \param _singleObject Pointer to preallocated memory. */
        inline void construct(T* _singleObject)
        {
            m_allocator.construct(_singleObject);
        }

        /** \brief Construct new object on preallocated memory using copy-constructor.

        \param _singleObject Pointer to preallocated memory.
        \param _value Const-reference to another object instance to be coped from.

        \note Declared as template function to make it possible to use this allocator with
        types without public copy-constructor. */
        template <class U>
        inline void construct(U* _singleObject, const U& _value)
        {
            m_allocator.construct(_singleObject, _value);
        }

        /** \brief Construct new object on preallocated memory using move-constructor.

        \param _singleObject Pointer to preallocated memory.
        \param _value Rvalue-reference to another object instance to be moved from.

        \note Declared as template function to make it possible to use this allocator with
        types without public move-constructor. */
        template <class U>
        inline void construct(U* _singleObject, U&& _value)
        {
            m_allocator.construct(_singleObject, _value);
        }

        /** \brief Construct new object on preallocated memory using arguments list.

        \param _singleObject Pointer to preallocated memory.
        \param _constructorArguments Variadic arguments list to be used by object constructor.

        \note Declared as template function to make it possible to use this allocator with
        types without specific constructor with arguments. */
        template <class U, class... TArgs>
        inline void construct(U* _singleObject, TArgs&&... _constructorArguments)
        {
            ::new (static_cast<void*>(_singleObject)) U(::std::forward<TArgs>(_constructorArguments)...);
        }

        /** \brief Destroy pointed object.

        Invokes object's destructor.

        \param _singleObject Pointer to object.

        \note Declared as template function to make it possible to use this allocator with
        types without public destructor. */
        template <class U>
        inline void destroy(U* _singleObject)
        {
            m_allocator.destroy(_singleObject);
        }

        /** \brief Estimate maximum array size. */
        size_t max_size() const throw()
        {
            return (size_t)(-1) / sizeof(T);
        }

    protected:

        /** \brief Deallocates all memory stored in memory cache. */
        inline void private_clear()
        {
            for (auto pMem : m_memoryCache)
            {
                m_allocator.deallocate(pMem, 0);
            }
        }

    }; // END class single_cached_allocator<T>.

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    // Using single_cached_allocator for itself is restricted.
    template <class T, class U>
    class cached_allocator<T, ::salloc::cached_allocator<U> >;

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    template <class T>
    using local_cached_allocator = ::salloc::cached_allocator<T, ::std::allocator<T> >;

} // END namespace salloc.

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace std {

    template <class T, class TAlloc>
    inline void swap(::salloc::cached_allocator<T, TAlloc>& _left, ::salloc::cached_allocator<T, TAlloc>& _right)
    {
        _left.swap(_right);
    }

} // END namespace std.

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#endif // SHARED___ALLOCATOR__SINGLE_CACHED_ALLOCATOR___HPP___
<commit_msg>building by gcc under linux<commit_after>/***************************************************************************************
* file        : cached_allocator.hpp
* data        : 2016/03/05
* author      : Victor Zarubkin
* contact     : v.s.zarubkin@gmail.com
* copyright   : Copyright (C) 2016  Victor Zarubkin
*             :
* description : This header contains definition of cached_allocator class which can be used to speed-up rapid allocations
*             : and deallocations of memory buffers of the same size. It is best to use this allocator to allocate and deallocate
*             : single instances of objects (memory buffers of size 1).
*             :
* references  : Original (and actual) version of source code can be found here <http://www.github.com/cas4ey/shared_allocator>.
*             :
* license     : This file is part of SharedAllocator.
*             :
*             : SharedAllocator is free software: you can redistribute it and/or modify
*             : it under the terms of the GNU General Public License as published by
*             : the Free Software Foundation, either version 3 of the License, or
*             : (at your option) any later version.
*             :
*             : SharedAllocator is distributed in the hope that it will be useful,
*             : but WITHOUT ANY WARRANTY; without even the implied warranty of
*             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*             : GNU General Public License for more details.
*             :
*             : You should have received a copy of the GNU General Public License
*             : along with SharedAllocator. If not, see <http://www.gnu.org/licenses/>.
*             :
*             : A copy of the GNU General Public License can be found in file LICENSE.
****************************************************************************************/

#ifndef SHARED___ALLOCATOR__SINGLE_CACHED_ALLOCATOR___HPP___
#define SHARED___ALLOCATOR__SINGLE_CACHED_ALLOCATOR___HPP___

#include "shared_allocator/shared_allocator.hpp"
#include <vector>

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace salloc {

    /** \brief Allocator that caches memory for objects for further usage.

    It caches deallocated memory buffers and uses them later to provide fast allocation of memory buffers of the SAME SIZE (or lesser size).

    \note It is better to use this allocator to allocate memory buffers of the same size.

    \note BEST TO USE IF YOU WANT TO ALLOCATE AND DEALLOCATE BUFFERS OF SIZE 1 (SINGLE INSTANCES OF OBJECTS)
    (Best fit for std::list, std::set, std::map BUT NOT for std::vector).

    \ingroup salloc */
    template <class T, class TAlloc = shared_allocator<T> >
    class cached_allocator
    {
    protected:

        typedef cached_allocator<T, TAlloc> ThisType;
        typedef ::std::vector<T*, typename TAlloc::template rebind<T*>::other> MemoryCache;

        MemoryCache m_memoryCache; ///< Memory cache of objects
        TAlloc        m_allocator; ///< Allocator to allocate new instances of T

    public:

        typedef T                         value_type;

        typedef value_type*                  pointer;
        typedef const value_type*      const_pointer;
        typedef void*                   void_pointer;
        typedef const void*       const_void_pointer;

        typedef value_type&                reference;
        typedef const value_type&    const_reference;

        typedef size_t                     size_type;
        typedef ptrdiff_t            difference_type;

        /** \brief Auxiliary struct to convert this type to single_cached_allocator of other type. */
        template <class U>
        struct rebind
        {
            typedef cached_allocator<U, typename TAlloc::template rebind<U>::other> other;
        };

        /** \brief Returns an actual adress of value.

        \note Uses std::addressof */
        pointer address(reference _value) const throw()
        {
            return ::std::addressof(_value);
        }

        /** \brief Returns an actual adress of const value.

        \note Uses std::addressof */
        const_pointer address(const_reference _value) const throw()
        {
            return ::std::addressof(_value);
        }

        /** \brief Default constructor.

        Does nothing. */
        cached_allocator() throw()
        {
        }

        /** \brief Empty copy constructor.

        Does nothing. */
        cached_allocator(const ThisType&) throw()
        {
        }

        /** \brief Empty copy constructor.

        Does nothing. */
        template <class U>
        cached_allocator(const U&) throw()
        {
        }

        /** \brief Move constructor.

        Moves reserved memory. */
        cached_allocator(ThisType&& _rvalueAlloc) : m_memoryCache(::std::move(_rvalueAlloc.m_memoryCache))
        {
        }

        /** \brief Empty assignment operator.

        Does nothing and returns reference to this allocator. */
        template <class U>
        ThisType& operator=(const U&)
        {
            return *this;
        }

        ~cached_allocator()
        {
            private_clear();
        }

        /** \brief Clear memory cache.

        Also deallocates all cached memory. */
        void clear()
        {
            private_clear();
            m_memoryCache.clear();
        }

        /** \brief Swaps two allocators with their cache.

        \param _anotherAlloc Reference to another allocator. */
        void swap(ThisType& _anotherAlloc)
        {
            m_memoryCache.swap(_anotherAlloc.m_memoryCache);
        }

        /** \brief Reserve memory for certain number of elements.

        Reserves memory for number of buffers of specified size.

        \param _arraySize Required number of elements to reserve (size of one memory buffer).
        \param _reservationsNumber Required number of memory buffers. */
        void reserve(size_type _arraySize, size_type _reservationsNumber)
        {
            m_memoryCache.reserve(m_memoryCache.size() + _reservationsNumber);
            for (size_type i = 0; i < _reservationsNumber; ++i)
            {
                m_memoryCache.push_back(m_allocator.allocate(_arraySize));
            }
        }

        /** \brief Returns number of elements in allocated memory.

        \param _memory Pointer to allocated memory.

        \warning Please, notice that the number of ELEMENTS will be returned (not number of BYTES).

        \note This function made template to avoid compiler errors for allocators that do not have size() function. */
        template <class U>
        inline size_type size(const U* _memory) const
        {
            return m_allocator.size(_memory);
        }

        /** \brief Stores pointer to memory in cache to be used later.

        \param _memory Pointer to allocated memory. */
        void deallocate(pointer _memory, size_type = 0)
        {
            m_memoryCache.push_back(_memory);
        }

        /** \brief Truly deallocates memory.

        \param _memory Pointer to allocated memory. */
        inline void deallocate_force(pointer _memory, size_type = 0)
        {
            m_allocator.deallocate(_memory, 0);
        }

        /** \brief Allocate elements.

        \param _number Required number of elements. */
        pointer allocate(size_type _number = 1)
        {
            if (!m_memoryCache.empty())
            {
                pointer pMem = m_memoryCache.back();
                m_memoryCache.pop_back();
                return _number < 2 ? pMem : m_allocator.allocate(_number, pMem);
            }

            return m_allocator.allocate(_number);
        }

        /** \brief Allocate elements using hint.

        \param _number Required number of elements.
        \param _currentMemory Pointer to memory allocated earlier (it contains size which will be used as a hint). */
        pointer allocate(size_type _number, void* _currentMemory)
        {
            if (!m_memoryCache.empty())
            {
                pointer pMem = m_memoryCache.back();
                m_memoryCache.pop_back();
                return _number < 2 ? pMem : m_allocator.allocate(_number, pMem);
            }

            return m_allocator.allocate(_number, _currentMemory);
        }

        /** \brief Construct new object on preallocated memory using default constructor.

        \param _singleObject Pointer to preallocated memory. */
        inline void construct(T* _singleObject)
        {
            m_allocator.construct(_singleObject);
        }

        /** \brief Construct new object on preallocated memory using copy-constructor.

        \param _singleObject Pointer to preallocated memory.
        \param _value Const-reference to another object instance to be coped from.

        \note Declared as template function to make it possible to use this allocator with
        types without public copy-constructor. */
        template <class U>
        inline void construct(U* _singleObject, const U& _value)
        {
            m_allocator.construct(_singleObject, _value);
        }

        /** \brief Construct new object on preallocated memory using move-constructor.

        \param _singleObject Pointer to preallocated memory.
        \param _value Rvalue-reference to another object instance to be moved from.

        \note Declared as template function to make it possible to use this allocator with
        types without public move-constructor. */
        template <class U>
        inline void construct(U* _singleObject, U&& _value)
        {
            m_allocator.construct(_singleObject, _value);
        }

        /** \brief Construct new object on preallocated memory using arguments list.

        \param _singleObject Pointer to preallocated memory.
        \param _constructorArguments Variadic arguments list to be used by object constructor.

        \note Declared as template function to make it possible to use this allocator with
        types without specific constructor with arguments. */
        template <class U, class... TArgs>
        inline void construct(U* _singleObject, TArgs&&... _constructorArguments)
        {
            ::new (static_cast<void*>(_singleObject)) U(::std::forward<TArgs>(_constructorArguments)...);
        }

        /** \brief Destroy pointed object.

        Invokes object's destructor.

        \param _singleObject Pointer to object.

        \note Declared as template function to make it possible to use this allocator with
        types without public destructor. */
        template <class U>
        inline void destroy(U* _singleObject)
        {
            m_allocator.destroy(_singleObject);
        }

        /** \brief Estimate maximum array size. */
        size_t max_size() const throw()
        {
            return (size_t)(-1) / sizeof(T);
        }

    protected:

        /** \brief Deallocates all memory stored in memory cache. */
        inline void private_clear()
        {
            for (auto pMem : m_memoryCache)
            {
                m_allocator.deallocate(pMem, 0);
            }
        }

    }; // END class single_cached_allocator<T>.

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    // Using single_cached_allocator for itself is restricted.
    template <class T, class U>
    class cached_allocator<T, ::salloc::cached_allocator<U> >;

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    template <class T>
    using local_cached_allocator = ::salloc::cached_allocator<T, ::std::allocator<T> >;

} // END namespace salloc.

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

namespace std {

    template <class T, class TAlloc>
    inline void swap(::salloc::cached_allocator<T, TAlloc>& _left, ::salloc::cached_allocator<T, TAlloc>& _right)
    {
        _left.swap(_right);
    }

} // END namespace std.

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#endif // SHARED___ALLOCATOR__SINGLE_CACHED_ALLOCATOR___HPP___
<|endoftext|>