<commit_before>/* $Id: alara.C,v 1.15 2002-05-06 18:03:24 wilsonp Exp $ */
#include "alara.h"

#include "Input/Input.h"
#include "Chains/Root.h"
#include "Util/Statistics.h"
#include "Output/Result.h"

/* See why Paul is using these silly STL things? */

int chainCode = 0;

/*!
 This list of elemental symbols is specially formatted to be used for
 looking up the atomic number of a given element.  For each element
 with atomic number, Z, and symbol, CC, the string " CC " exists at
 index Z-1.
*/
const char *SYMBOLS=" h  he li be b  c  n  o  f  ne na mg al si p  s  cl ar \
k  ca sc ti v  cr mn fe co ni cu zn ga ge as se br kr rb sr y  zr nb mo tc ru \
rh pd ag cd in sn sb te i  xe cs ba la ce pr nd pm sm eu gd tb dy ho er tm \
yb lu hf ta w  re os ir pt au hg tl pb bi po at rn fr ra ac th pa u  np \
pu am cm bk cf es fm md no lr ";

/// This is derived from a CVS variable to determine the version string
static char *id="$Name: not supported by cvs2svn $";

/*!
 This is the standard help/usage message that is printed when an incorrect
 command-line option is used, or when -h is used.
*/
static char *helpmsg="\
usage: %s [-h] [-r] [-t <tree_filename>] [-V] [-v <n>] [<input_filename>] \n\
\t -h                 Show this message\n\
\t -r                 Restart option for calculating new respones\n\
\t -t <tree_filename> Create tree file with given name\n\
\t -V                 Show version\n\
\t -v <n>             Set verbosity level\n\
\t <input_filename>   Name of input file\n\
See Users' Guide for more info.\n\
(http://www.cae.wisc.edu/~wilsonp/projects/ALARA/users.guide.html/)\n";

int main(int argc, char *argv[])
{
  int argNum = 1;
  int solved = FALSE;
  char *inFname = NULL;
  Root* rootList = new Root;
  topSchedule* schedule;

  verbose(-1,"ALARA %s",id);

  while (argNum<argc)
    {
      if (argv[argNum][0] != '-')
	if (inFname == NULL)
	  {
	    inFname = new char[strlen(argv[argNum])+1];
	    strcpy(inFname,argv[argNum]);
	    argNum++;
	    /* get next argument */
	    continue;
	  }
	else
	  error(1,"Only one input filename can be specified: %s.",inFname);

      while (argv[argNum][0] == '-')
	argv[argNum]++;
      switch (argv[argNum][0])
	{
#ifdef DVLPR
	case 'd':
	  if (argv[argNum][1] == '\0')
	    {
	      debug_level = atoi(argv[argNum+1]);
	      argNum+=2;
	    }
	  else
	    {
	      debug_level = atoi(argv[argNum]+1);
	      argNum++;
	    }
	  debug(0,"Set debug level to %d.",debug_level);
	  break;
#endif
	case 'v':
	  if (argv[argNum][1] == '\0')
	    {
	      verb_level = atoi(argv[argNum+1]);
	      argNum+=2;
	    }
	  else
	    {
	      verb_level = atoi(argv[argNum]+1);
	      argNum++;
	    }
	  verbose(0,"Set verbose level to %d.",verb_level);
	  break;
	case 'r':
          verbose(0,"Reusing binary dump data.");
	  solved=TRUE;
	  argNum+=1;
	  break;
	case 't':
	  if (argv[argNum][1] == '\0')
	    {
	      Statistics::initTree(argv[argNum+1]);
	      verbose(0,"Openned tree file %s.",argv[argNum+1]);
	      argNum+=2;
	    }
	  else
	    {
	      Statistics::initTree(argv[argNum]+1);
	      verbose(0,"Openned tree file %s.",argv[argNum]+1);
	      argNum++;
	    }
	  break;
	case 'h':
	  verbose(-1,helpmsg,argv[0]);
	case 'V':
	  exit(0);
	  break;
	default:
	  {
	    verbose(-1,helpmsg,argv[0]);
	    error(0,"Invlaid option: %s.",argv[argNum]);
	  }
	}
    }

  Input problemInput(inFname);

  /* INPUT */
  verbose(0,"Starting problem input processing.");
  verbose(1,"Reading input.");
  problemInput.read();
  verbose(1,"Cross-checking input for completeness and self-consistency.");
  problemInput.xCheck();
  verbose(1,"Preprocessing input.");
  problemInput.preProc(rootList,schedule);

  if (!solved)
    {
      verbose(0,"Starting problem solution.");

      rootList->solve(schedule);

      verbose(1,"Solved problem.");
    }

  Result::resetBinDump();
  problemInput.postProc(rootList);

  verbose(0,"Output.");

  Result::closeBinDump();

  delete rootList;
  delete inFname;

}
<commit_msg>Added option to skip post-processing.<commit_after>/* $Id: alara.C,v 1.16 2002-05-06 19:10:38 wilsonp Exp $ */
#include "alara.h"

#include "Input/Input.h"
#include "Chains/Root.h"
#include "Util/Statistics.h"
#include "Output/Result.h"

/* See why Paul is using these silly STL things? */

int chainCode = 0;

/*!
 This list of elemental symbols is specially formatted to be used for
 looking up the atomic number of a given element.  For each element
 with atomic number, Z, and symbol, CC, the string " CC " exists at
 index Z-1.
*/
const char *SYMBOLS=" h  he li be b  c  n  o  f  ne na mg al si p  s  cl ar \
k  ca sc ti v  cr mn fe co ni cu zn ga ge as se br kr rb sr y  zr nb mo tc ru \
rh pd ag cd in sn sb te i  xe cs ba la ce pr nd pm sm eu gd tb dy ho er tm \
yb lu hf ta w  re os ir pt au hg tl pb bi po at rn fr ra ac th pa u  np \
pu am cm bk cf es fm md no lr ";

/// This is derived from a CVS variable to determine the version string
static char *id="$Name: not supported by cvs2svn $";

/*!
 This is the standard help/usage message that is printed when an incorrect
 command-line option is used, or when -h is used.
*/
static char *helpmsg="\
usage: %s [-h] [-r] [-t <tree_filename>] [-V] [-v <n>] [<input_filename>] \n\
\t -h                 Show this message\n\
\t -c                 Option to only calculate chains and skip post-processing\n\
\t -r                 \"Restart\" option to skip chain calculation and only post-process\n\
\t -t <tree_filename> Create tree file with given name\n\
\t -V                 Show version\n\
\t -v <n>             Set verbosity level\n\
\t <input_filename>   Name of input file\n\
See Users' Guide for more info.\n\
(http://www.cae.wisc.edu/~wilsonp/projects/ALARA/users.guide.html/)\n";

int main(int argc, char *argv[])
{
  int argNum = 1;
  int solved = FALSE;
  int doOutput = TRUE;
  char *inFname = NULL;
  Root* rootList = new Root;
  topSchedule* schedule;

  verbose(-1,"ALARA %s",id);

  while (argNum<argc)
    {
      if (argv[argNum][0] != '-')
	if (inFname == NULL)
	  {
	    inFname = new char[strlen(argv[argNum])+1];
	    strcpy(inFname,argv[argNum]);
	    argNum++;
	    /* get next argument */
	    continue;
	  }
	else
	  error(1,"Only one input filename can be specified: %s.",inFname);

      while (argv[argNum][0] == '-')
	argv[argNum]++;
      switch (argv[argNum][0])
	{
#ifdef DVLPR
	case 'd':
	  if (argv[argNum][1] == '\0')
	    {
	      debug_level = atoi(argv[argNum+1]);
	      argNum+=2;
	    }
	  else
	    {
	      debug_level = atoi(argv[argNum]+1);
	      argNum++;
	    }
	  debug(0,"Set debug level to %d.",debug_level);
	  break;
#endif
	case 'v':
	  if (argv[argNum][1] == '\0')
	    {
	      verb_level = atoi(argv[argNum+1]);
	      argNum+=2;
	    }
	  else
	    {
	      verb_level = atoi(argv[argNum]+1);
	      argNum++;
	    }
	  verbose(0,"Set verbose level to %d.",verb_level);
	  break;
	case 'c':
	  verbose(0,"Calculating chains ONLY.");
	  doOutput=FALSE;
	  argNum+=1;
	  break;
	case 'r':
          verbose(0,"Reusing binary dump data.");
	  solved=TRUE;
	  argNum+=1;
	  break;
	case 't':
	  if (argv[argNum][1] == '\0')
	    {
	      Statistics::initTree(argv[argNum+1]);
	      verbose(0,"Openned tree file %s.",argv[argNum+1]);
	      argNum+=2;
	    }
	  else
	    {
	      Statistics::initTree(argv[argNum]+1);
	      verbose(0,"Openned tree file %s.",argv[argNum]+1);
	      argNum++;
	    }
	  break;
	case 'h':
	  verbose(-1,helpmsg,argv[0]);
	case 'V':
	  exit(0);
	  break;
	default:
	  {
	    verbose(-1,helpmsg,argv[0]);
	    error(0,"Invlaid option: %s.",argv[argNum]);
	  }
	}
    }

  Input problemInput(inFname);

  /* INPUT */
  verbose(0,"Starting problem input processing.");
  verbose(1,"Reading input.");
  problemInput.read();
  verbose(1,"Cross-checking input for completeness and self-consistency.");
  problemInput.xCheck();
  verbose(1,"Preprocessing input.");
  problemInput.preProc(rootList,schedule);

  if (!solved)
    {
      verbose(0,"Starting problem solution.");

      rootList->solve(schedule);

      verbose(1,"Solved problem.");
    }

  if (doOutput)
    {
      Result::resetBinDump();
      problemInput.postProc(rootList);

      verbose(0,"Output.");
    }

  Result::closeBinDump();

  delete rootList;
  delete inFname;

}
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2022 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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 AND CONTRIBUTORS
 * ``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
 * FOUNDATION 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.
 */

#pragma once

#include "SliceAllocation.hxx"
#include "util/ForeignFifoBuffer.hxx"

#include <stdint.h>

class SlicePool;
class SliceArea;

class SliceFifoBuffer : public ForeignFifoBuffer<std::byte> {
	SliceAllocation allocation;

public:
	SliceFifoBuffer() noexcept:ForeignFifoBuffer<std::byte>(nullptr) {}

	explicit SliceFifoBuffer(SlicePool &pool) noexcept
		:ForeignFifoBuffer<std::byte>(nullptr) {
		Allocate(pool);
	}

	SliceFifoBuffer(SliceFifoBuffer &&src) noexcept
		:ForeignFifoBuffer(std::move(src)),
		 allocation(std::move(src.allocation))
	{
		src.SetNull();
	}

	void swap(SliceFifoBuffer &other) noexcept {
		using std::swap;
		ForeignFifoBuffer<std::byte>::swap(other);
		swap(allocation, other.allocation);
	}

	friend void swap(SliceFifoBuffer &a, SliceFifoBuffer &b) noexcept {
		a.swap(b);
	}

	void Allocate(SlicePool &pool) noexcept;
	void Free() noexcept;

	bool IsDefinedAndFull() const noexcept {
		return IsDefined() && IsFull();
	}

	void AllocateIfNull(SlicePool &pool) noexcept {
		if (IsNull())
			Allocate(pool);
	}

	void FreeIfDefined() noexcept {
		if (IsDefined())
			Free();
	}

	void FreeIfEmpty() noexcept {
		if (empty())
			FreeIfDefined();
	}

	/**
	 * If this buffer is empty, free the buffer and reallocate a new
	 * one.  This is useful to work around #SliceArea fragmentation.
	 */
	void CycleIfEmpty(SlicePool &pool) noexcept {
		if (IsDefined() && empty()) {
			Free();
			Allocate(pool);
		}
	}

	using ForeignFifoBuffer<std::byte>::MoveFrom;

	/**
	 * Move as much data as possible from the specified buffer.  If
	 * the destination buffer is empty, the buffers are swapped.  Care
	 * is taken that neither buffer suddenly becomes nulled
	 * afterwards, because some callers may not be prepared for this.
	 */
	void MoveFrom(SliceFifoBuffer &src) noexcept {
		if (empty() && !IsNull() && !src.IsNull())
			/* optimized special case: swap buffer pointers instead of
			   copying data */
			swap(src);
		else
			ForeignFifoBuffer<std::byte>::MoveFrom(src);
	}

	/**
	 * Like MoveFrom(), but allow the destination to be nulled.  This
	 * is useful when #src can be freed, but this object cannot.
	 */
	void MoveFromAllowNull(SliceFifoBuffer &src) noexcept {
		if (empty() && (!src.empty() || !IsNull()))
			/* optimized special case: swap buffer pointers instead of
			   copying data */
			swap(src);
		else
			ForeignFifoBuffer<std::byte>::MoveFrom(src);
	}

	/**
	 * Like MoveFrom(), but allow the source to be nulled.  This is
	 * useful when this object can be freed, but #src cannot.
	 */
	void MoveFromAllowSrcNull(SliceFifoBuffer &src) noexcept {
		if (empty() && (!src.empty() || IsNull()))
			/* optimized special case: swap buffer pointers instead of
			   copying data */
			swap(src);
		else
			ForeignFifoBuffer<std::byte>::MoveFrom(src);
	}

	/**
	 * Like MoveFrom(), but allow both to be nulled.
	 */
	void MoveFromAllowBothNull(SliceFifoBuffer &src) noexcept {
		if (empty())
			/* optimized special case: swap buffer pointers instead of
			   copying data */
			swap(src);
		else
			ForeignFifoBuffer<std::byte>::MoveFrom(src);
	}

	/**
	 * Swaps the two buffers if #src is nulled.  This is useful when
	 * #src can be freed, but this object cannot.
	 */
	void SwapIfNull(SliceFifoBuffer &src) noexcept {
		if (src.IsNull() && empty() && !IsNull())
			swap(src);
	}
};
<commit_msg>memory/SliceFifoBuffer: remove method MoveFrom(SliceFifoBuffer)<commit_after>/*
 * Copyright 2007-2022 CM4all GmbH
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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 AND CONTRIBUTORS
 * ``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
 * FOUNDATION 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.
 */

#pragma once

#include "SliceAllocation.hxx"
#include "util/ForeignFifoBuffer.hxx"

#include <stdint.h>

class SlicePool;
class SliceArea;

class SliceFifoBuffer : public ForeignFifoBuffer<std::byte> {
	SliceAllocation allocation;

public:
	SliceFifoBuffer() noexcept:ForeignFifoBuffer<std::byte>(nullptr) {}

	explicit SliceFifoBuffer(SlicePool &pool) noexcept
		:ForeignFifoBuffer<std::byte>(nullptr) {
		Allocate(pool);
	}

	SliceFifoBuffer(SliceFifoBuffer &&src) noexcept
		:ForeignFifoBuffer(std::move(src)),
		 allocation(std::move(src.allocation))
	{
		src.SetNull();
	}

	void swap(SliceFifoBuffer &other) noexcept {
		using std::swap;
		ForeignFifoBuffer<std::byte>::swap(other);
		swap(allocation, other.allocation);
	}

	friend void swap(SliceFifoBuffer &a, SliceFifoBuffer &b) noexcept {
		a.swap(b);
	}

	void Allocate(SlicePool &pool) noexcept;
	void Free() noexcept;

	bool IsDefinedAndFull() const noexcept {
		return IsDefined() && IsFull();
	}

	void AllocateIfNull(SlicePool &pool) noexcept {
		if (IsNull())
			Allocate(pool);
	}

	void FreeIfDefined() noexcept {
		if (IsDefined())
			Free();
	}

	void FreeIfEmpty() noexcept {
		if (empty())
			FreeIfDefined();
	}

	/**
	 * If this buffer is empty, free the buffer and reallocate a new
	 * one.  This is useful to work around #SliceArea fragmentation.
	 */
	void CycleIfEmpty(SlicePool &pool) noexcept {
		if (IsDefined() && empty()) {
			Free();
			Allocate(pool);
		}
	}

	using ForeignFifoBuffer<std::byte>::MoveFrom;

	/**
	 * Move as much data as possible from the specified buffer.  If
	 * the destination buffer is empty, the buffers are swapped.  Care
	 * is taken that neither buffer suddenly becomes nulled
	 * afterwards, because some callers may not be prepared for this.
	 *
	 * Note: this method has been removed because it was not
	 * possible to implement it to be safe against unallocated
	 * instances.  Use MoveFromAllow*() instead.
	 */
	void MoveFrom(SliceFifoBuffer &src) noexcept = delete;

	/**
	 * Like MoveFrom(), but allow the destination to be nulled.  This
	 * is useful when #src can be freed, but this object cannot.
	 */
	void MoveFromAllowNull(SliceFifoBuffer &src) noexcept {
		if (empty() && (!src.empty() || !IsNull()))
			/* optimized special case: swap buffer pointers instead of
			   copying data */
			swap(src);
		else
			ForeignFifoBuffer<std::byte>::MoveFrom(src);
	}

	/**
	 * Like MoveFrom(), but allow the source to be nulled.  This is
	 * useful when this object can be freed, but #src cannot.
	 */
	void MoveFromAllowSrcNull(SliceFifoBuffer &src) noexcept {
		if (empty() && (!src.empty() || IsNull()))
			/* optimized special case: swap buffer pointers instead of
			   copying data */
			swap(src);
		else
			ForeignFifoBuffer<std::byte>::MoveFrom(src);
	}

	/**
	 * Like MoveFrom(), but allow both to be nulled.
	 */
	void MoveFromAllowBothNull(SliceFifoBuffer &src) noexcept {
		if (empty())
			/* optimized special case: swap buffer pointers instead of
			   copying data */
			swap(src);
		else
			ForeignFifoBuffer<std::byte>::MoveFrom(src);
	}

	/**
	 * Swaps the two buffers if #src is nulled.  This is useful when
	 * #src can be freed, but this object cannot.
	 */
	void SwapIfNull(SliceFifoBuffer &src) noexcept {
		if (src.IsNull() && empty() && !IsNull())
			swap(src);
	}
};
<|endoftext|>


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

#include "modules/canbus/vehicle/lincoln/protocol/throttle_63.h"

#include "gtest/gtest.h"

namespace apollo {
namespace canbus {
namespace lincoln {

TEST(Throttle63Test, General) {
  uint8_t data = 0x01;
  int32_t length = 8;
  ChassisDetail cd;
  Throttle63 throttle;
  throttle.Parse(&data, length, &cd);

  EXPECT_FALSE(cd.gas().throttle_enabled());
}

}  // namespace lincoln
}  // namespace apollo
}  // namespace canbus
<commit_msg>fixed data in throttle_63_test. #120<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

#include "modules/canbus/vehicle/lincoln/protocol/throttle_63.h"

#include "gtest/gtest.h"

namespace apollo {
namespace canbus {
namespace lincoln {

TEST(Throttle63Test, General) {
  uint8_t data[8] = {0x67, 0x62, 0x63, 0x64, 0x51, 0x52, 0x53, 0x54};
  int32_t length = 8;
  ChassisDetail cd;
  Throttle63 throttle;
  throttle.Parse(data, length, &cd);

  EXPECT_DOUBLE_EQ(cd.gas().throttle_input(), 38.439002059967905);
  EXPECT_DOUBLE_EQ(cd.gas().throttle_cmd(), 39.21416037232008);
  EXPECT_DOUBLE_EQ(cd.gas().throttle_output(), 32.155336842908326);
  EXPECT_EQ(cd.gas().watchdog_source(), 5);
  EXPECT_FALSE(cd.gas().throttle_enabled());
  EXPECT_FALSE(cd.gas().driver_override());
  EXPECT_TRUE(cd.gas().driver_activity());
  EXPECT_FALSE(cd.gas().watchdog_fault());
  EXPECT_TRUE(cd.gas().channel_1_fault());
  EXPECT_FALSE(cd.gas().channel_2_fault());
  EXPECT_FALSE(cd.gas().connector_fault());

  EXPECT_TRUE(cd.check_response().is_vcu_online());
}

}  // namespace lincoln
}  // namespace apollo
}  // namespace canbus
<|endoftext|>


<commit_before>/** @file

  Chunk decoding.

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */
#include <algorithm>
#include <cassert>

#include "chunk-decoder.h"

void
ChunkDecoder::parseSizeCharacter(const char a)
{
  assert(state_ == State::kSize);
  if (a >= '0' && a <= '9') {
    size_ = (size_ << 4) | (a - '0');
  } else if (a >= 'A' && a <= 'F') {
    size_ = (size_ << 4) | (a - 'A' + 10);
  } else if (a >= 'a' && a <= 'f') {
    size_ = (size_ << 4) | (a - 'a' + 10);
  } else if (a == '\r') {
    state_ = size_ == 0 ? State::kEndN : State::kDataN;
  } else {
    assert(false); // invalid input
  }
}

int
ChunkDecoder::parseSize(const char *p, const int64_t s)
{
  assert(p != nullptr);
  assert(s > 0);
  int length = 0;
  while (state_ != State::kData && *p != '\0' && length < s) {
    assert(state_ < State::kUpperBound); // VALID RANGE
    switch (state_) {
    case State::kData:
    case State::kInvalid:
    case State::kEnd:
    case State::kUpperBound:
      assert(false);
      break;

    case State::kDataN:
      assert(*p == '\n');
      state_ = (*p == '\n') ? State::kData : State::kInvalid;
      break;

    case State::kEndN:
      assert(*p == '\n');
      state_ = (*p == '\n') ? State::kEnd : State::kInvalid;
      return length;

    case State::kSizeR:
      assert(*p == '\r');
      state_ = (*p == '\r') ? State::kSizeN : State::kInvalid;
      break;

    case State::kSizeN:
      assert(*p == '\n');
      state_ = (*p == '\n') ? State::kSize : State::kInvalid;
      break;

    case State::kSize:
      parseSizeCharacter(*p);
      break;
    }
    ++length;
    ++p;
    assert(state_ != State::kInvalid);
  }
  return length;
}

bool
ChunkDecoder::isSizeState() const
{
  return state_ == State::kDataN || state_ == State::kEndN || state_ == State::kSize || state_ == State::kSizeN ||
         state_ == State::kSizeR;
}

int
ChunkDecoder::decode(const TSIOBufferReader &r)
{
  assert(r != nullptr);

  if (state_ == State::kEnd) {
    return 0;
  }

  {
    const int l = TSIOBufferReaderAvail(r);
    if (l < size_) {
      size_ -= l;
      return l;
    }
  }

  int64_t size;
  TSIOBufferBlock block = TSIOBufferReaderStart(r);

  // Trying to parse a size.
  if (isSizeState()) {
    while (block != nullptr && size_ == 0) {
      const char *p = TSIOBufferBlockReadStart(block, r, &size);
      assert(p != nullptr);
      const int i = parseSize(p, size);
      size -= i;
      TSIOBufferReaderConsume(r, i);
      if (state_ == State::kEnd) {
        assert(size_ == 0);
        return 0;
      }
      if (isSizeState()) {
        assert(size == 0);
        block = TSIOBufferBlockNext(block);
      }
    }
  }

  int length = 0;

  while (block != nullptr && state_ == State::kData) {
    assert(size_ > 0);
    const char *p = TSIOBufferBlockReadStart(block, r, &size);
    if (p != nullptr) {
      if (size >= size_) {
        length += size_;
        size_  = 0;
        state_ = State::kSizeR;
        break;
      } else {
        length += size;
        size_ -= size;
      }
    }
    block = TSIOBufferBlockNext(block);
  }

  return length;
}
<commit_msg>Fix for when multiplexer gets a 0 byte read event<commit_after>/** @file

  Chunk decoding.

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF licenses this file
  to you under the Apache License, Version 2.0 (the
  "License"); you may not use this file except in compliance
  with the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
 */
#include <algorithm>
#include <cassert>

#include "chunk-decoder.h"

void
ChunkDecoder::parseSizeCharacter(const char a)
{
  assert(state_ == State::kSize);
  if (a >= '0' && a <= '9') {
    size_ = (size_ << 4) | (a - '0');
  } else if (a >= 'A' && a <= 'F') {
    size_ = (size_ << 4) | (a - 'A' + 10);
  } else if (a >= 'a' && a <= 'f') {
    size_ = (size_ << 4) | (a - 'a' + 10);
  } else if (a == '\r') {
    state_ = size_ == 0 ? State::kEndN : State::kDataN;
  } else {
    assert(false); // invalid input
  }
}

int
ChunkDecoder::parseSize(const char *p, const int64_t s)
{
  assert(p != nullptr);
  assert(s > 0);
  int length = 0;
  while (state_ != State::kData && *p != '\0' && length < s) {
    assert(state_ < State::kUpperBound); // VALID RANGE
    switch (state_) {
    case State::kData:
    case State::kInvalid:
    case State::kEnd:
    case State::kUpperBound:
      assert(false);
      break;

    case State::kDataN:
      assert(*p == '\n');
      state_ = (*p == '\n') ? State::kData : State::kInvalid;
      break;

    case State::kEndN:
      assert(*p == '\n');
      state_ = (*p == '\n') ? State::kEnd : State::kInvalid;
      return length;

    case State::kSizeR:
      assert(*p == '\r');
      state_ = (*p == '\r') ? State::kSizeN : State::kInvalid;
      break;

    case State::kSizeN:
      assert(*p == '\n');
      state_ = (*p == '\n') ? State::kSize : State::kInvalid;
      break;

    case State::kSize:
      parseSizeCharacter(*p);
      break;
    }
    ++length;
    ++p;
    assert(state_ != State::kInvalid);
  }
  return length;
}

bool
ChunkDecoder::isSizeState() const
{
  return state_ == State::kDataN || state_ == State::kEndN || state_ == State::kSize || state_ == State::kSizeN ||
         state_ == State::kSizeR;
}

int
ChunkDecoder::decode(const TSIOBufferReader &r)
{
  assert(r != nullptr);

  if (state_ == State::kEnd) {
    return 0;
  }

  {
    const int l = TSIOBufferReaderAvail(r);
    if (l == 0) {
      return 0;
    } else if (l < size_) {
      size_ -= l;
      return l;
    }
  }

  int64_t size;
  TSIOBufferBlock block = TSIOBufferReaderStart(r);

  // Trying to parse a size.
  if (isSizeState()) {
    while (block != nullptr && size_ == 0) {
      const char *p = TSIOBufferBlockReadStart(block, r, &size);
      assert(p != nullptr);
      const int i = parseSize(p, size);
      size -= i;
      TSIOBufferReaderConsume(r, i);
      if (state_ == State::kEnd) {
        assert(size_ == 0);
        return 0;
      }
      if (isSizeState()) {
        assert(size == 0);
        block = TSIOBufferBlockNext(block);
      }
    }
  }

  int length = 0;

  while (block != nullptr && state_ == State::kData) {
    assert(size_ > 0);
    const char *p = TSIOBufferBlockReadStart(block, r, &size);
    if (p != nullptr) {
      if (size >= size_) {
        length += size_;
        size_  = 0;
        state_ = State::kSizeR;
        break;
      } else {
        length += size;
        size_ -= size;
      }
    }
    block = TSIOBufferBlockNext(block);
  }

  return length;
}
<|endoftext|>


<commit_before>#include "MeshLodTests.h"
#include "OgreDefaultHardwareBufferManager.h"
#include "OgreVertexIndexData.h"
#include "OgreEdgeListBuilder.h"
#include "OgreMesh.h"
#include "OgreMeshManager.h"
#include "OgreSubMesh.h"
#include "OgreMeshSerializer.h"
#include "OgreRoot.h"
#include "OgreException.h"
#include "OgreArchive.h"
#include "OgreArchiveManager.h"
#include "OgreFileSystem.h"
#include "OgreConfigFile.h"
#include "OgreMeshLodGenerator.h"
#include "OgrePixelCountLodStrategy.h"
#include "OgreLodCollapseCostQuadric.h"
#include "OgreRenderWindow.h"
#include "OgreLodConfigSerializer.h"

CPPUNIT_TEST_SUITE_REGISTRATION(MeshLodTests);

#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
#include "macUtils.h"
#endif

void MeshLodTests::setUp()
{
	OGRE_DELETE LogManager::getSingletonPtr();
	mLogManager = OGRE_NEW LogManager();
	mLogManager->createLog("MeshWithoutIndexDataTests.log", false);
	mLogManager->setLogDetail(LL_LOW);

#if OGRE_STATIC
        mStaticPluginLoader = OGRE_NEW StaticPluginLoader();
#endif

#ifdef OGRE_STATIC_LIB
	Root* root = OGRE_NEW Root(StringUtil::BLANK);

	mStaticPluginLoader.load();
#else
	Root* root = OGRE_NEW Root();

#endif
	CPPUNIT_ASSERT(!root->getAvailableRenderers().empty());
	root->setRenderSystem(root->getAvailableRenderers().back());
	root->initialise(false); // Needed for setting up HardwareBufferManager
	root->createRenderWindow("", 320, 240, false, NULL)->setHidden(true);
	new MeshLodGenerator;

	// Load resource paths from config file
	ConfigFile cf;
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
	cf.load(macBundlePath() + "/Contents/Resources/resources.cfg");
#elif OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#if OGRE_DEBUG_MODE
	cf.load("resources_d.cfg");
#else
	cf.load("resources.cfg");
#endif
#else
#ifdef OGRE_STATIC_LIB
	cf.load("bin/resources.cfg");
#else
	cf.load("resources.cfg");
#endif
#endif /* if OGRE_PLATFORM == OGRE_PLATFORM_APPLE */

	// Go through all sections & settings in the file
	ConfigFile::SectionIterator seci = cf.getSectionIterator();

	String secName, typeName, archName;
	while (seci.hasMoreElements()) {
		secName = seci.peekNextKey();
		ConfigFile::SettingsMultiMap* settings = seci.getNext();
		ConfigFile::SettingsMultiMap::iterator i;
		for (i = settings->begin(); i != settings->end(); ++i) {
			typeName = i->first;
			archName = i->second;
			ResourceGroupManager::getSingleton().addResourceLocation(
			    archName, typeName, secName);
		}
	}

	// +++++++++++++++++++++++++++++++
	// Create the mesh for testing
	{
		mMesh = MeshManager::getSingleton().load("Sinbad.mesh", ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME);
	}
	// +++++++++++++++++++++++++++++++
}

void MeshLodTests::tearDown()
{
	if (!mMesh.isNull()) {
		mMesh->unload();
		mMesh.setNull();
	}
	OGRE_DELETE MeshLodGenerator::getSingletonPtr();
	OGRE_DELETE Root::getSingletonPtr();
	OGRE_DELETE mLogManager;
}

void MeshLodTests::addProfile(LodConfig& config)
{
	// Get the first two vertices and put the edge into the profile
	// It doesn't matter if there is no such edge, because edges are removed and created dynamically.
	// The vertex positions should exist or you get an assert.
	VertexData* vertexData = config.mesh->getSubMesh(0)->vertexData;
	const VertexElement* elemPos = vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION);
	HardwareVertexBufferSharedPtr vbuf = vertexData->vertexBufferBinding->getBuffer(elemPos->getSource());
	assert(vbuf->getNumVertices() > 2);
	unsigned char* vertex = static_cast<unsigned char*>(vbuf->lock(HardwareBuffer::HBL_READ_ONLY));
	float* pFloat;
	elemPos->baseVertexPointerToElement(vertex, &pFloat);
	ProfiledEdge edge;
	edge.src.x = *pFloat++;
	edge.src.y = *pFloat++;
	edge.src.z = *pFloat;
	vertex += vbuf->getVertexSize();
	elemPos->baseVertexPointerToElement(vertex, &pFloat);
	edge.dst.x = *pFloat++;
	edge.dst.y = *pFloat++;
	edge.dst.z = *pFloat;
	edge.cost = LodData::NEVER_COLLAPSE_COST;
	config.advanced.profile.push_back(edge);
	vbuf->unlock();
}
void MeshLodTests::testMeshLodGenerator()
{

	LodConfig config;
	setTestLodConfig(config);

	MeshLodGenerator& gen = MeshLodGenerator::getSingleton();
	gen.generateLodLevels(config);
	addProfile(config);
	config.advanced.useBackgroundQueue = false;
	config.advanced.useCompression = false;
	config.advanced.useVertexNormals = false;
	gen.generateLodLevels(config);

	LodConfig config2(config);
	config2.advanced.useBackgroundQueue = true;
	config2.mesh->removeLodLevels();
	gen.generateLodLevels(config);
	blockedWaitForLodGeneration(config.mesh);
	CPPUNIT_ASSERT(config.levels.size() == config2.levels.size());
	for (size_t i = 0; i < config.levels.size(); i++) {
		CPPUNIT_ASSERT(config.levels[i].outSkipped == config2.levels[i].outSkipped);
		CPPUNIT_ASSERT(config.levels[i].outUniqueVertexCount == config2.levels[i].outUniqueVertexCount);
	}

}

void MeshLodTests::blockedWaitForLodGeneration(const MeshPtr& mesh)
{
	bool success = false;
	const int timeout = 5000;
	WorkQueue* wq = Root::getSingleton().getWorkQueue();
	for (int i = 0; i < timeout; i++) {
		OGRE_THREAD_SLEEP(1);
		wq->processResponses(); // Injects the Lod if ready
		if (mesh->getNumLodLevels() != 1) {
			success = true;
			break;
		}
	}
	// timeout
	CPPUNIT_ASSERT(success);
}

void MeshLodTests::testLodConfigSerializer()
{
	LodConfig config, config2;
	setTestLodConfig(config);
	addProfile(config);
	LodConfigSerializer serializer;
	serializer.exportLodConfig(config, "testLodConfigSerializer.lodconfig");
	serializer.importLodConfig(&config2, "testLodConfigSerializer.lodconfig");
	CPPUNIT_ASSERT(config.mesh->getHandle() == config2.mesh->getHandle());
	CPPUNIT_ASSERT(config.strategy == config2.strategy);
	CPPUNIT_ASSERT(config.advanced.outsideWalkAngle == config.advanced.outsideWalkAngle);
	CPPUNIT_ASSERT(config.advanced.outsideWeight == config.advanced.outsideWeight);
	CPPUNIT_ASSERT(config.advanced.useBackgroundQueue == config.advanced.useBackgroundQueue);
	CPPUNIT_ASSERT(config.advanced.useCompression == config.advanced.useCompression);
	CPPUNIT_ASSERT(config.advanced.useVertexNormals == config.advanced.useVertexNormals);
	{
		// Compare profiles
		LodProfile& p1 = config.advanced.profile;
		LodProfile& p2 = config2.advanced.profile;
		bool isProfileSameSize = (p1.size() == p2.size());
		CPPUNIT_ASSERT(isProfileSameSize);
		if (isProfileSameSize) {
			for (size_t i = 0; i < p1.size(); i++) {
				CPPUNIT_ASSERT(p1[i].src == p2[i].src);
				CPPUNIT_ASSERT(p1[i].dst == p2[i].dst);
				CPPUNIT_ASSERT(isEqual(p1[i].cost, p2[i].cost));
			}
		}
	}
	{
		// Compare Lod Levels
		LodConfig::LodLevelList& l1 = config.levels;
		LodConfig::LodLevelList& l2 = config2.levels;
		bool isLevelsSameSize = (l1.size() == l2.size());
		CPPUNIT_ASSERT(isLevelsSameSize);
		if (isLevelsSameSize) {
			for (size_t i = 0; i < l1.size(); i++) {
				CPPUNIT_ASSERT(l1[i].distance == l2[i].distance);
				CPPUNIT_ASSERT(l1[i].manualMeshName == l2[i].manualMeshName);
				CPPUNIT_ASSERT(l1[i].reductionMethod == l2[i].reductionMethod);
				CPPUNIT_ASSERT(isEqual(l1[i].reductionValue, l2[i].reductionValue));
			}
		}
	}
}

void MeshLodTests::testManualLodLevels()
{
	MeshLodGenerator& gen = MeshLodGenerator::getSingleton();
	LodConfig config;
	setTestLodConfig(config);
	gen.generateLodLevels(config, LodCollapseCostPtr(new LodCollapseCostQuadric()));
}

void MeshLodTests::testQuadricError()
{
	LodConfig config;
	setTestLodConfig(config);
	MeshLodGenerator& gen = MeshLodGenerator::getSingleton();
	gen.generateLodLevels(config, LodCollapseCostPtr(new LodCollapseCostQuadric()));
}

void MeshLodTests::setTestLodConfig(LodConfig& config)
{
	config.mesh = mMesh;
	config.strategy = PixelCountLodStrategy::getSingletonPtr();
	config.levels.clear();
	config.createGeneratedLodLevel(10, 0.1);
	config.createGeneratedLodLevel(9, 0.2);
	config.createGeneratedLodLevel(8, 0.3);
	config.advanced.outsideWeight = 1.0;
	config.advanced.useCompression = true;
	config.advanced.useVertexNormals = true;
	config.advanced.useBackgroundQueue = false;
}
bool MeshLodTests::isEqual(Real a, Real b)
{
	Real absoluteError = std::abs(a * 0.05);
	return ((a - absoluteError) <= b) && ((a + absoluteError) >= b);
}
<commit_msg>Use cocoa API by default.<commit_after>#include "MeshLodTests.h"
#include "OgreDefaultHardwareBufferManager.h"
#include "OgreVertexIndexData.h"
#include "OgreEdgeListBuilder.h"
#include "OgreMesh.h"
#include "OgreMeshManager.h"
#include "OgreSubMesh.h"
#include "OgreMeshSerializer.h"
#include "OgreRoot.h"
#include "OgreException.h"
#include "OgreArchive.h"
#include "OgreArchiveManager.h"
#include "OgreFileSystem.h"
#include "OgreConfigFile.h"
#include "OgreMeshLodGenerator.h"
#include "OgrePixelCountLodStrategy.h"
#include "OgreLodCollapseCostQuadric.h"
#include "OgreRenderWindow.h"
#include "OgreLodConfigSerializer.h"

CPPUNIT_TEST_SUITE_REGISTRATION(MeshLodTests);

#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
#include "macUtils.h"
#endif

void MeshLodTests::setUp()
{
	OGRE_DELETE LogManager::getSingletonPtr();
	mLogManager = OGRE_NEW LogManager();
	mLogManager->createLog("MeshWithoutIndexDataTests.log", false);
	mLogManager->setLogDetail(LL_LOW);

#if OGRE_STATIC
        mStaticPluginLoader = OGRE_NEW StaticPluginLoader();
#endif

#ifdef OGRE_STATIC_LIB
	Root* root = OGRE_NEW Root(StringUtil::BLANK);

	mStaticPluginLoader.load();
#else
	Root* root = OGRE_NEW Root();

#endif
	CPPUNIT_ASSERT(!root->getAvailableRenderers().empty());
	root->setRenderSystem(root->getAvailableRenderers().back());
	root->initialise(false); // Needed for setting up HardwareBufferManager
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
	Ogre::NameValuePairList misc;
	// Tell OGRE that we're using cocoa, so it doesn't need to make a window for us
	misc["macAPI"] = "cocoa";
	root->createRenderWindow("", 320, 240, false, &misc)->setHidden(true);
#else
	root->createRenderWindow("", 320, 240, false, NULL)->setHidden(true);
#endif
	new MeshLodGenerator;

	// Load resource paths from config file
	ConfigFile cf;
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
	cf.load(macBundlePath() + "/Contents/Resources/resources.cfg");
#elif OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#if OGRE_DEBUG_MODE
	cf.load("resources_d.cfg");
#else
	cf.load("resources.cfg");
#endif
#else
#ifdef OGRE_STATIC_LIB
	cf.load("bin/resources.cfg");
#else
	cf.load("resources.cfg");
#endif
#endif /* if OGRE_PLATFORM == OGRE_PLATFORM_APPLE */

	// Go through all sections & settings in the file
	ConfigFile::SectionIterator seci = cf.getSectionIterator();

	String secName, typeName, archName;
	while (seci.hasMoreElements()) {
		secName = seci.peekNextKey();
		ConfigFile::SettingsMultiMap* settings = seci.getNext();
		ConfigFile::SettingsMultiMap::iterator i;
		for (i = settings->begin(); i != settings->end(); ++i) {
			typeName = i->first;
			archName = i->second;
			ResourceGroupManager::getSingleton().addResourceLocation(
			    archName, typeName, secName);
		}
	}

	// +++++++++++++++++++++++++++++++
	// Create the mesh for testing
	{
		mMesh = MeshManager::getSingleton().load("Sinbad.mesh", ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME);
	}
	// +++++++++++++++++++++++++++++++
}

void MeshLodTests::tearDown()
{
	if (!mMesh.isNull()) {
		mMesh->unload();
		mMesh.setNull();
	}
	OGRE_DELETE MeshLodGenerator::getSingletonPtr();
	OGRE_DELETE Root::getSingletonPtr();
	OGRE_DELETE mLogManager;
}

void MeshLodTests::addProfile(LodConfig& config)
{
	// Get the first two vertices and put the edge into the profile
	// It doesn't matter if there is no such edge, because edges are removed and created dynamically.
	// The vertex positions should exist or you get an assert.
	VertexData* vertexData = config.mesh->getSubMesh(0)->vertexData;
	const VertexElement* elemPos = vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION);
	HardwareVertexBufferSharedPtr vbuf = vertexData->vertexBufferBinding->getBuffer(elemPos->getSource());
	assert(vbuf->getNumVertices() > 2);
	unsigned char* vertex = static_cast<unsigned char*>(vbuf->lock(HardwareBuffer::HBL_READ_ONLY));
	float* pFloat;
	elemPos->baseVertexPointerToElement(vertex, &pFloat);
	ProfiledEdge edge;
	edge.src.x = *pFloat++;
	edge.src.y = *pFloat++;
	edge.src.z = *pFloat;
	vertex += vbuf->getVertexSize();
	elemPos->baseVertexPointerToElement(vertex, &pFloat);
	edge.dst.x = *pFloat++;
	edge.dst.y = *pFloat++;
	edge.dst.z = *pFloat;
	edge.cost = LodData::NEVER_COLLAPSE_COST;
	config.advanced.profile.push_back(edge);
	vbuf->unlock();
}
void MeshLodTests::testMeshLodGenerator()
{

	LodConfig config;
	setTestLodConfig(config);

	MeshLodGenerator& gen = MeshLodGenerator::getSingleton();
	gen.generateLodLevels(config);
	addProfile(config);
	config.advanced.useBackgroundQueue = false;
	config.advanced.useCompression = false;
	config.advanced.useVertexNormals = false;
	gen.generateLodLevels(config);

	LodConfig config2(config);
	config2.advanced.useBackgroundQueue = true;
	config2.mesh->removeLodLevels();
	gen.generateLodLevels(config);
	blockedWaitForLodGeneration(config.mesh);
	CPPUNIT_ASSERT(config.levels.size() == config2.levels.size());
	for (size_t i = 0; i < config.levels.size(); i++) {
		CPPUNIT_ASSERT(config.levels[i].outSkipped == config2.levels[i].outSkipped);
		CPPUNIT_ASSERT(config.levels[i].outUniqueVertexCount == config2.levels[i].outUniqueVertexCount);
	}

}

void MeshLodTests::blockedWaitForLodGeneration(const MeshPtr& mesh)
{
	bool success = false;
	const int timeout = 5000;
	WorkQueue* wq = Root::getSingleton().getWorkQueue();
	for (int i = 0; i < timeout; i++) {
		OGRE_THREAD_SLEEP(1);
		wq->processResponses(); // Injects the Lod if ready
		if (mesh->getNumLodLevels() != 1) {
			success = true;
			break;
		}
	}
	// timeout
	CPPUNIT_ASSERT(success);
}

void MeshLodTests::testLodConfigSerializer()
{
	LodConfig config, config2;
	setTestLodConfig(config);
	addProfile(config);
	LodConfigSerializer serializer;
	serializer.exportLodConfig(config, "testLodConfigSerializer.lodconfig");
	serializer.importLodConfig(&config2, "testLodConfigSerializer.lodconfig");
	CPPUNIT_ASSERT(config.mesh->getHandle() == config2.mesh->getHandle());
	CPPUNIT_ASSERT(config.strategy == config2.strategy);
	CPPUNIT_ASSERT(config.advanced.outsideWalkAngle == config.advanced.outsideWalkAngle);
	CPPUNIT_ASSERT(config.advanced.outsideWeight == config.advanced.outsideWeight);
	CPPUNIT_ASSERT(config.advanced.useBackgroundQueue == config.advanced.useBackgroundQueue);
	CPPUNIT_ASSERT(config.advanced.useCompression == config.advanced.useCompression);
	CPPUNIT_ASSERT(config.advanced.useVertexNormals == config.advanced.useVertexNormals);
	{
		// Compare profiles
		LodProfile& p1 = config.advanced.profile;
		LodProfile& p2 = config2.advanced.profile;
		bool isProfileSameSize = (p1.size() == p2.size());
		CPPUNIT_ASSERT(isProfileSameSize);
		if (isProfileSameSize) {
			for (size_t i = 0; i < p1.size(); i++) {
				CPPUNIT_ASSERT(p1[i].src == p2[i].src);
				CPPUNIT_ASSERT(p1[i].dst == p2[i].dst);
				CPPUNIT_ASSERT(isEqual(p1[i].cost, p2[i].cost));
			}
		}
	}
	{
		// Compare Lod Levels
		LodConfig::LodLevelList& l1 = config.levels;
		LodConfig::LodLevelList& l2 = config2.levels;
		bool isLevelsSameSize = (l1.size() == l2.size());
		CPPUNIT_ASSERT(isLevelsSameSize);
		if (isLevelsSameSize) {
			for (size_t i = 0; i < l1.size(); i++) {
				CPPUNIT_ASSERT(l1[i].distance == l2[i].distance);
				CPPUNIT_ASSERT(l1[i].manualMeshName == l2[i].manualMeshName);
				CPPUNIT_ASSERT(l1[i].reductionMethod == l2[i].reductionMethod);
				CPPUNIT_ASSERT(isEqual(l1[i].reductionValue, l2[i].reductionValue));
			}
		}
	}
}

void MeshLodTests::testManualLodLevels()
{
	MeshLodGenerator& gen = MeshLodGenerator::getSingleton();
	LodConfig config;
	setTestLodConfig(config);
	gen.generateLodLevels(config, LodCollapseCostPtr(new LodCollapseCostQuadric()));
}

void MeshLodTests::testQuadricError()
{
	LodConfig config;
	setTestLodConfig(config);
	MeshLodGenerator& gen = MeshLodGenerator::getSingleton();
	gen.generateLodLevels(config, LodCollapseCostPtr(new LodCollapseCostQuadric()));
}

void MeshLodTests::setTestLodConfig(LodConfig& config)
{
	config.mesh = mMesh;
	config.strategy = PixelCountLodStrategy::getSingletonPtr();
	config.levels.clear();
	config.createGeneratedLodLevel(10, 0.1);
	config.createGeneratedLodLevel(9, 0.2);
	config.createGeneratedLodLevel(8, 0.3);
	config.advanced.outsideWeight = 1.0;
	config.advanced.useCompression = true;
	config.advanced.useVertexNormals = true;
	config.advanced.useBackgroundQueue = false;
}
bool MeshLodTests::isEqual(Real a, Real b)
{
	Real absoluteError = std::abs(a * 0.05);
	return ((a - absoluteError) <= b) && ((a + absoluteError) >= b);
}
<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2014 Torus Knot Software Ltd

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.
-----------------------------------------------------------------------------
*/

#include "OgreGLES2DefaultHardwareBufferManager.h"
#include "OgreRoot.h"
#include "OgreGLES2RenderSystem.h"
#include "OgreGLES2Util.h"

namespace Ogre {
    GLES2DefaultHardwareVertexBuffer::GLES2DefaultHardwareVertexBuffer(size_t vertexSize,
                                                                 size_t numVertices,
                                                                 HardwareBuffer::Usage usage)
        : HardwareVertexBuffer(0, vertexSize, numVertices, usage, true, false)
    {
        mData = static_cast<unsigned char*>(OGRE_MALLOC_SIMD(mSizeInBytes, MEMCATEGORY_GEOMETRY));
    }

    GLES2DefaultHardwareVertexBuffer::GLES2DefaultHardwareVertexBuffer(HardwareBufferManagerBase* mgr,
                                                                       size_t vertexSize,
                                                                       size_t numVertices,
                                                                       HardwareBuffer::Usage usage)
        : HardwareVertexBuffer(mgr, vertexSize, numVertices, usage, true, false)
    {
        mData = static_cast<unsigned char*>(OGRE_MALLOC_SIMD(mSizeInBytes, MEMCATEGORY_GEOMETRY));
    }

    GLES2DefaultHardwareVertexBuffer::~GLES2DefaultHardwareVertexBuffer()
    {
        OGRE_FREE_SIMD(mData, MEMCATEGORY_GEOMETRY);
    }

    void* GLES2DefaultHardwareVertexBuffer::lockImpl(size_t offset,
                                                  size_t length,
                                                  LockOptions options)
    {
        return mData + offset;
    }

    void GLES2DefaultHardwareVertexBuffer::unlockImpl(void)
    {
        // Nothing to do
    }

    void* GLES2DefaultHardwareVertexBuffer::lock(size_t offset, size_t length, LockOptions options, UploadOptions uploadOpt)
    {
        mIsLocked = true;
        return mData + offset;
    }

    void GLES2DefaultHardwareVertexBuffer::unlock(void)
    {
        mIsLocked = false;
        // Nothing to do
    }

    void GLES2DefaultHardwareVertexBuffer::readData(size_t offset,
                                                 size_t length,
                                                 void* pDest)
    {
        assert((offset + length) <= mSizeInBytes);
        memcpy(pDest, mData + offset, length);
    }

    void GLES2DefaultHardwareVertexBuffer::writeData(size_t offset,
                                                  size_t length,
                                                  const void* pSource,
                                                  bool discardWholeBuffer)
    {
        assert((offset + length) <= mSizeInBytes);
        // ignore discard, memory is not guaranteed to be zeroised
        memcpy(mData + offset, pSource, length);
    }

    GLES2DefaultHardwareIndexBuffer::GLES2DefaultHardwareIndexBuffer(IndexType idxType,
                                                               size_t numIndexes,
                                                               HardwareBuffer::Usage usage)
        : HardwareIndexBuffer(0, idxType, numIndexes, usage, true, false)
          // always software, never shadowed
    {
#if OGRE_NO_GLES3_SUPPORT == 1
        if (!Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_32BIT_INDEX) &&
            idxType == HardwareIndexBuffer::IT_32BIT)
        {
            OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
                "32 bit hardware buffers are not allowed in OpenGL ES.",
                "GLES2DefaultHardwareIndexBuffer");
        }
#endif
        mData = new unsigned char[mSizeInBytes];
    }

    GLES2DefaultHardwareIndexBuffer::~GLES2DefaultHardwareIndexBuffer()
    {
        delete [] mData;
    }

    void* GLES2DefaultHardwareIndexBuffer::lockImpl(size_t offset, size_t length, LockOptions options)
    {
        // Only for use internally, no 'locking' as such
        return mData + offset;
    }

    void GLES2DefaultHardwareIndexBuffer::unlockImpl(void)
    {
        // Nothing to do
    }

    void* GLES2DefaultHardwareIndexBuffer::lock(size_t offset, size_t length, LockOptions options, UploadOptions uploadOpt)
    {
        mIsLocked = true;
        return mData + offset;
    }

    void GLES2DefaultHardwareIndexBuffer::unlock(void)
    {
        mIsLocked = false;
        // Nothing to do
    }

    void GLES2DefaultHardwareIndexBuffer::readData(size_t offset, size_t length, void* pDest)
    {
        assert((offset + length) <= mSizeInBytes);
        memcpy(pDest, mData + offset, length);
    }

    void GLES2DefaultHardwareIndexBuffer::writeData(size_t offset, size_t length, const void* pSource,
            bool discardWholeBuffer)
    {
        assert((offset + length) <= mSizeInBytes);
        // ignore discard, memory is not guaranteed to be zeroised
        memcpy(mData + offset, pSource, length);
    }

    GLES2DefaultHardwareUniformBuffer::GLES2DefaultHardwareUniformBuffer(size_t bufferSize,
                                                                             HardwareBuffer::Usage usage,
                                                                             bool useShadowBuffer, const String& name)
    : HardwareUniformBuffer(0, bufferSize, usage, useShadowBuffer, name)
    {
        mData = static_cast<unsigned char*>(OGRE_MALLOC_SIMD(mSizeInBytes, MEMCATEGORY_GEOMETRY));
    }

    GLES2DefaultHardwareUniformBuffer::GLES2DefaultHardwareUniformBuffer(HardwareBufferManagerBase* mgr,
                                                                             size_t bufferSize,
                                                                             HardwareBuffer::Usage usage,
                                                                             bool useShadowBuffer, const String& name)
    : HardwareUniformBuffer(mgr, bufferSize, usage, useShadowBuffer, name)
    {
        mData = static_cast<unsigned char*>(OGRE_MALLOC_SIMD(mSizeInBytes, MEMCATEGORY_GEOMETRY));
    }

    GLES2DefaultHardwareUniformBuffer::~GLES2DefaultHardwareUniformBuffer()
    {
        OGRE_FREE_SIMD(mData, MEMCATEGORY_GEOMETRY);
    }

    void* GLES2DefaultHardwareUniformBuffer::lockImpl(size_t offset,
                                                        size_t length,
                                                        LockOptions options)
    {
        return mData + offset;
    }

    void GLES2DefaultHardwareUniformBuffer::unlockImpl(void)
    {
        // Nothing to do
    }

    void* GLES2DefaultHardwareUniformBuffer::lock(size_t offset, size_t length, LockOptions options, UploadOptions uploadOpt)
    {
        mIsLocked = true;
        return mData + offset;
    }

    void GLES2DefaultHardwareUniformBuffer::unlock(void)
    {
        mIsLocked = false;
        // Nothing to do
    }

    void GLES2DefaultHardwareUniformBuffer::readData(size_t offset,
                                                       size_t length,
                                                       void* pDest)
    {
        assert((offset + length) <= mSizeInBytes);
        memcpy(pDest, mData + offset, length);
    }

    void GLES2DefaultHardwareUniformBuffer::writeData(size_t offset,
                                                        size_t length,
                                                        const void* pSource,
                                                        bool discardWholeBuffer)
    {
        assert((offset + length) <= mSizeInBytes);
        // ignore discard, memory is not guaranteed to be zeroised
        memcpy(mData + offset, pSource, length);
    }

    GLES2DefaultHardwareBufferManagerBase::GLES2DefaultHardwareBufferManagerBase()
    {
    }

    GLES2DefaultHardwareBufferManagerBase::~GLES2DefaultHardwareBufferManagerBase()
    {
        destroyAllDeclarations();
        destroyAllBindings();
    }

    HardwareVertexBufferSharedPtr
        GLES2DefaultHardwareBufferManagerBase::createVertexBuffer(size_t vertexSize,
        size_t numVerts, HardwareBuffer::Usage usage, bool useShadowBuffer)
    {
        return HardwareVertexBufferSharedPtr(
            OGRE_NEW GLES2DefaultHardwareVertexBuffer(vertexSize, numVerts, usage));
    }

    HardwareIndexBufferSharedPtr
        GLES2DefaultHardwareBufferManagerBase::createIndexBuffer(HardwareIndexBuffer::IndexType itype,
        size_t numIndexes, HardwareBuffer::Usage usage, bool useShadowBuffer)
    {
        return HardwareIndexBufferSharedPtr(
            OGRE_NEW GLES2DefaultHardwareIndexBuffer(itype, numIndexes, usage));
    }

    HardwareUniformBufferSharedPtr
    GLES2DefaultHardwareBufferManagerBase::createUniformBuffer(size_t sizeBytes, HardwareBuffer::Usage usage,
                                                                 bool useShadowBuffer, const String& name)
    {
        if(!gleswIsSupported(3, 0))
        {
            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
                        "GLES2 does not support uniform buffer objects",
                        "GLES2DefaultHardwareBufferManager::createUniformBuffer");
        }

        return HardwareUniformBufferSharedPtr(new GLES2DefaultHardwareUniformBuffer(this, sizeBytes, usage, useShadowBuffer, name));
    }

    Ogre::RenderToVertexBufferSharedPtr GLES2DefaultHardwareBufferManagerBase::createRenderToVertexBuffer( void )
    {
        if(!gleswIsSupported(3, 0))
        {
            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
                    "Cannot create RenderToVertexBuffer in GLES2DefaultHardwareBufferManagerBase",
                    "GLES2DefaultHardwareBufferManagerBase::createRenderToVertexBuffer");
        }
//        return HardwareUniformBufferSharedPtr(new GLES2DefaultHardwareRenderToVertexBuffer(this, sizeBytes, usage, useShadowBuffer, name));
    }
}
<commit_msg>[iOS] fixed "control may reach end of non-void function" compiler warning / logic error<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2014 Torus Knot Software Ltd

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.
-----------------------------------------------------------------------------
*/

#include "OgreGLES2DefaultHardwareBufferManager.h"
#include "OgreRoot.h"
#include "OgreGLES2RenderSystem.h"
#include "OgreGLES2Util.h"

namespace Ogre {
    GLES2DefaultHardwareVertexBuffer::GLES2DefaultHardwareVertexBuffer(size_t vertexSize,
                                                                 size_t numVertices,
                                                                 HardwareBuffer::Usage usage)
        : HardwareVertexBuffer(0, vertexSize, numVertices, usage, true, false)
    {
        mData = static_cast<unsigned char*>(OGRE_MALLOC_SIMD(mSizeInBytes, MEMCATEGORY_GEOMETRY));
    }

    GLES2DefaultHardwareVertexBuffer::GLES2DefaultHardwareVertexBuffer(HardwareBufferManagerBase* mgr,
                                                                       size_t vertexSize,
                                                                       size_t numVertices,
                                                                       HardwareBuffer::Usage usage)
        : HardwareVertexBuffer(mgr, vertexSize, numVertices, usage, true, false)
    {
        mData = static_cast<unsigned char*>(OGRE_MALLOC_SIMD(mSizeInBytes, MEMCATEGORY_GEOMETRY));
    }

    GLES2DefaultHardwareVertexBuffer::~GLES2DefaultHardwareVertexBuffer()
    {
        OGRE_FREE_SIMD(mData, MEMCATEGORY_GEOMETRY);
    }

    void* GLES2DefaultHardwareVertexBuffer::lockImpl(size_t offset,
                                                  size_t length,
                                                  LockOptions options)
    {
        return mData + offset;
    }

    void GLES2DefaultHardwareVertexBuffer::unlockImpl(void)
    {
        // Nothing to do
    }

    void* GLES2DefaultHardwareVertexBuffer::lock(size_t offset, size_t length, LockOptions options, UploadOptions uploadOpt)
    {
        mIsLocked = true;
        return mData + offset;
    }

    void GLES2DefaultHardwareVertexBuffer::unlock(void)
    {
        mIsLocked = false;
        // Nothing to do
    }

    void GLES2DefaultHardwareVertexBuffer::readData(size_t offset,
                                                 size_t length,
                                                 void* pDest)
    {
        assert((offset + length) <= mSizeInBytes);
        memcpy(pDest, mData + offset, length);
    }

    void GLES2DefaultHardwareVertexBuffer::writeData(size_t offset,
                                                  size_t length,
                                                  const void* pSource,
                                                  bool discardWholeBuffer)
    {
        assert((offset + length) <= mSizeInBytes);
        // ignore discard, memory is not guaranteed to be zeroised
        memcpy(mData + offset, pSource, length);
    }

    GLES2DefaultHardwareIndexBuffer::GLES2DefaultHardwareIndexBuffer(IndexType idxType,
                                                               size_t numIndexes,
                                                               HardwareBuffer::Usage usage)
        : HardwareIndexBuffer(0, idxType, numIndexes, usage, true, false)
          // always software, never shadowed
    {
#if OGRE_NO_GLES3_SUPPORT == 1
        if (!Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_32BIT_INDEX) &&
            idxType == HardwareIndexBuffer::IT_32BIT)
        {
            OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
                "32 bit hardware buffers are not allowed in OpenGL ES.",
                "GLES2DefaultHardwareIndexBuffer");
        }
#endif
        mData = new unsigned char[mSizeInBytes];
    }

    GLES2DefaultHardwareIndexBuffer::~GLES2DefaultHardwareIndexBuffer()
    {
        delete [] mData;
    }

    void* GLES2DefaultHardwareIndexBuffer::lockImpl(size_t offset, size_t length, LockOptions options)
    {
        // Only for use internally, no 'locking' as such
        return mData + offset;
    }

    void GLES2DefaultHardwareIndexBuffer::unlockImpl(void)
    {
        // Nothing to do
    }

    void* GLES2DefaultHardwareIndexBuffer::lock(size_t offset, size_t length, LockOptions options, UploadOptions uploadOpt)
    {
        mIsLocked = true;
        return mData + offset;
    }

    void GLES2DefaultHardwareIndexBuffer::unlock(void)
    {
        mIsLocked = false;
        // Nothing to do
    }

    void GLES2DefaultHardwareIndexBuffer::readData(size_t offset, size_t length, void* pDest)
    {
        assert((offset + length) <= mSizeInBytes);
        memcpy(pDest, mData + offset, length);
    }

    void GLES2DefaultHardwareIndexBuffer::writeData(size_t offset, size_t length, const void* pSource,
            bool discardWholeBuffer)
    {
        assert((offset + length) <= mSizeInBytes);
        // ignore discard, memory is not guaranteed to be zeroised
        memcpy(mData + offset, pSource, length);
    }

    GLES2DefaultHardwareUniformBuffer::GLES2DefaultHardwareUniformBuffer(size_t bufferSize,
                                                                             HardwareBuffer::Usage usage,
                                                                             bool useShadowBuffer, const String& name)
    : HardwareUniformBuffer(0, bufferSize, usage, useShadowBuffer, name)
    {
        mData = static_cast<unsigned char*>(OGRE_MALLOC_SIMD(mSizeInBytes, MEMCATEGORY_GEOMETRY));
    }

    GLES2DefaultHardwareUniformBuffer::GLES2DefaultHardwareUniformBuffer(HardwareBufferManagerBase* mgr,
                                                                             size_t bufferSize,
                                                                             HardwareBuffer::Usage usage,
                                                                             bool useShadowBuffer, const String& name)
    : HardwareUniformBuffer(mgr, bufferSize, usage, useShadowBuffer, name)
    {
        mData = static_cast<unsigned char*>(OGRE_MALLOC_SIMD(mSizeInBytes, MEMCATEGORY_GEOMETRY));
    }

    GLES2DefaultHardwareUniformBuffer::~GLES2DefaultHardwareUniformBuffer()
    {
        OGRE_FREE_SIMD(mData, MEMCATEGORY_GEOMETRY);
    }

    void* GLES2DefaultHardwareUniformBuffer::lockImpl(size_t offset,
                                                        size_t length,
                                                        LockOptions options)
    {
        return mData + offset;
    }

    void GLES2DefaultHardwareUniformBuffer::unlockImpl(void)
    {
        // Nothing to do
    }

    void* GLES2DefaultHardwareUniformBuffer::lock(size_t offset, size_t length, LockOptions options, UploadOptions uploadOpt)
    {
        mIsLocked = true;
        return mData + offset;
    }

    void GLES2DefaultHardwareUniformBuffer::unlock(void)
    {
        mIsLocked = false;
        // Nothing to do
    }

    void GLES2DefaultHardwareUniformBuffer::readData(size_t offset,
                                                       size_t length,
                                                       void* pDest)
    {
        assert((offset + length) <= mSizeInBytes);
        memcpy(pDest, mData + offset, length);
    }

    void GLES2DefaultHardwareUniformBuffer::writeData(size_t offset,
                                                        size_t length,
                                                        const void* pSource,
                                                        bool discardWholeBuffer)
    {
        assert((offset + length) <= mSizeInBytes);
        // ignore discard, memory is not guaranteed to be zeroised
        memcpy(mData + offset, pSource, length);
    }

    GLES2DefaultHardwareBufferManagerBase::GLES2DefaultHardwareBufferManagerBase()
    {
    }

    GLES2DefaultHardwareBufferManagerBase::~GLES2DefaultHardwareBufferManagerBase()
    {
        destroyAllDeclarations();
        destroyAllBindings();
    }

    HardwareVertexBufferSharedPtr
        GLES2DefaultHardwareBufferManagerBase::createVertexBuffer(size_t vertexSize,
        size_t numVerts, HardwareBuffer::Usage usage, bool useShadowBuffer)
    {
        return HardwareVertexBufferSharedPtr(
            OGRE_NEW GLES2DefaultHardwareVertexBuffer(vertexSize, numVerts, usage));
    }

    HardwareIndexBufferSharedPtr
        GLES2DefaultHardwareBufferManagerBase::createIndexBuffer(HardwareIndexBuffer::IndexType itype,
        size_t numIndexes, HardwareBuffer::Usage usage, bool useShadowBuffer)
    {
        return HardwareIndexBufferSharedPtr(
            OGRE_NEW GLES2DefaultHardwareIndexBuffer(itype, numIndexes, usage));
    }

    HardwareUniformBufferSharedPtr
    GLES2DefaultHardwareBufferManagerBase::createUniformBuffer(size_t sizeBytes, HardwareBuffer::Usage usage,
                                                                 bool useShadowBuffer, const String& name)
    {
        if(!gleswIsSupported(3, 0))
        {
            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
                        "GLES2 does not support uniform buffer objects",
                        "GLES2DefaultHardwareBufferManager::createUniformBuffer");
        }

        return HardwareUniformBufferSharedPtr(new GLES2DefaultHardwareUniformBuffer(this, sizeBytes, usage, useShadowBuffer, name));
    }

    Ogre::RenderToVertexBufferSharedPtr GLES2DefaultHardwareBufferManagerBase::createRenderToVertexBuffer( void )
    {
        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
                    "Cannot create RenderToVertexBuffer in GLES2DefaultHardwareBufferManagerBase",
                    "GLES2DefaultHardwareBufferManagerBase::createRenderToVertexBuffer");
    }
}
<|endoftext|>


<commit_before>/** \file    generate_vufind_translation_files.cc
 *  \brief   A tool for creating the ".ini" files VuFind uses based on data in the SQL translations table.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
    Copyright (C) 2016,2017, Library of the University of Tübingen

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

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

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <algorithm>
#include <iostream>
#include <map>
#include <tuple>
#include <utility>
#include <vector>
#include <cstring>
#include "File.h"
#include "FileUtil.h"
#include "TranslationUtil.h"
#include "DbConnection.h"
#include "DbResultSet.h"
#include "DbRow.h"
#include "IniFile.h"
#include "StringUtil.h"
#include "util.h"

void Usage() {
    std::cerr << "Usage: " << ::progname << " [--verbose] output_directory_path\n";
    std::exit(EXIT_FAILURE);
}

// Generates a XX.ini output file with entries like the original file.  The XX is a 2-letter language code.
void ProcessLanguage(const bool verbose, const std::string &output_file_path, const std::string &_3letter_code,
                     DbConnection * const db_connection)
{
    if (verbose)
        std::cerr << "Processing language code: " << _3letter_code << '\n';

    std::unordered_map<std::string, std::pair<unsigned, std::string>> token_to_line_no_and_other_map;
    if (::access(output_file_path.c_str(), R_OK) != 0)
        logger->warning("\"" + output_file_path + "\" is not readable, maybe it doesn't exist?");
    else {
        TranslationUtil::ReadIniFile(output_file_path, &token_to_line_no_and_other_map);

        if (unlikely(not FileUtil::RenameFile(output_file_path, output_file_path + ".bak", /* remove_target = */true)))
            logger->error("failed to rename \"" + output_file_path + "\" to \"" + output_file_path + ".bak\"! ("
                          + std::string(::strerror(errno)) + ")");
    }

    File output(output_file_path, "w");
    if (unlikely(output.fail()))
        logger->error("failed to open \"" + output_file_path + "\" for writing!");

    db_connection->queryOrDie("SELECT token,translation FROM vufind_translations WHERE language_code='"
                              + _3letter_code + "'");
    DbResultSet result_set(db_connection->getLastResultSet());
    if (unlikely(result_set.empty()))
        logger->error("found no translations for language code \"" + _3letter_code + "\"!");
    if (verbose)
        std::cerr << "\tFound " << result_set.size() << " (token,translation) pairs.\n";

    std::vector<std::tuple<unsigned, std::string, std::string>> line_nos_tokens_and_translations;
    while (const DbRow row = result_set.getNextRow()) {
        const auto &token_to_line_no_and_other(token_to_line_no_and_other_map.find(row[0]));
        if (token_to_line_no_and_other != token_to_line_no_and_other_map.cend())
            line_nos_tokens_and_translations.emplace_back(token_to_line_no_and_other->second.first, row[0], row[1]);
        else
            line_nos_tokens_and_translations.emplace_back(token_to_line_no_and_other_map.size() + 1, row[0], row[1]);
    }

    std::sort(line_nos_tokens_and_translations.begin(), line_nos_tokens_and_translations.end(),
              [](const std::tuple<unsigned, std::string,std::string> &left,
                 const std::tuple<unsigned, std::string,std::string> &right)
              { return std::get<0>(left) < std::get<0>(right); });

    for (const auto &line_no_token_and_translation : line_nos_tokens_and_translations) {
        const std::string token(std::get<1>(line_no_token_and_translation));
        const std::string translation(std::get<2>(line_no_token_and_translation));
        if (not translation.empty())
            output << token << " = \"" << StringUtil::TrimWhite(translation) << "\"\n";
    }

    if (verbose)
        std::cerr << "Wrote " << line_nos_tokens_and_translations.size() << " language mappings to \""
                  << output_file_path << "\"\n";
}

void GetLanguageCodes(const bool verbose, DbConnection * const db_connection,
                      std::map<std::string, std::string> * language_codes)
{
    db_connection->queryOrDie("SELECT DISTINCT language_code FROM vufind_translations");
    DbResultSet language_codes_result_set(db_connection->getLastResultSet());
    if (unlikely(language_codes_result_set.empty()))
        logger->error("no language codes found, expected multiple!");

    while (const DbRow row = language_codes_result_set.getNextRow()) {
        const std::string german_language_code(
            TranslationUtil::MapFake3LetterEnglishLanguagesCodesToGermanLanguageCodes(row[0]));
        if (german_language_code == "???")
            continue;
        const std::string international_language_code(
            TranslationUtil::MapGerman3Or4LetterCodeToInternational2LetterCode(german_language_code));
        language_codes->emplace(international_language_code, row[0]);
    }
    if (verbose)
        std::cerr << "Found " << language_codes->size()
                  << " distinct language code in the \"vufind_translations\" table.\n";
}

const std::string CONF_FILE_PATH("/usr/local/var/lib/tuelib/translations.conf");

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc < 2)
        Usage();
    bool verbose(false);
    if (std::strcmp(argv[1], "--verbose") == 0) {
        verbose = true;
        --argc, ++argv;
    }
    if (argc != 2)
        Usage();

    const std::string output_directory(argv[1]);
    if (unlikely(not FileUtil::IsDirectory(output_directory)))
        logger->error("\"" + output_directory + "\" is not a directory or can't be read!");

    try {
        const IniFile ini_file(CONF_FILE_PATH);
        const std::string sql_database(ini_file.getString("Database", "sql_database"));
        const std::string sql_username(ini_file.getString("Database", "sql_username"));
        const std::string sql_password(ini_file.getString("Database", "sql_password"));
        DbConnection db_connection(sql_database, sql_username, sql_password);

        std::map<std::string, std::string> _2letter_and_3letter_codes;
        GetLanguageCodes(verbose, &db_connection, &_2letter_and_3letter_codes);
        for (const auto &_2letter_intl_code_and_fake_3letter_english_code : _2letter_and_3letter_codes)
            ProcessLanguage(verbose,
                            output_directory + "/" + _2letter_intl_code_and_fake_3letter_english_code.first + ".ini",
                            _2letter_intl_code_and_fake_3letter_english_code.second, &db_connection);
    } catch (const std::exception &x) {
        logger->error("caught exception: " + std::string(x.what()));
    }
}
<commit_msg>Normalize brackets<commit_after>/** \file    generate_vufind_translation_files.cc
 *  \brief   A tool for creating the ".ini" files VuFind uses based on data in the SQL translations table.
 *  \author  Dr. Johannes Ruscheinski
 */

/*
    Copyright (C) 2016,2017, Library of the University of Tübingen

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

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

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <algorithm>
#include <iostream>
#include <map>
#include <tuple>
#include <utility>
#include <vector>
#include <cstring>
#include "File.h"
#include "FileUtil.h"
#include "TranslationUtil.h"
#include "DbConnection.h"
#include "DbResultSet.h"
#include "DbRow.h"
#include "IniFile.h"
#include "StringUtil.h"
#include "util.h"

void Usage() {
    std::cerr << "Usage: " << ::progname << " [--verbose] output_directory_path\n";
    std::exit(EXIT_FAILURE);
}

// Needed since no consistent convention was used for brackets
std::string NormalizeBrackets(const std::string string_to_normalize) {
    return StringUtil::Map(string_to_normalize, "<>", "()");
}

// Generates a XX.ini output file with entries like the original file.  The XX is a 2-letter language code.
void ProcessLanguage(const bool verbose, const std::string &output_file_path, const std::string &_3letter_code,
                     DbConnection * const db_connection)
{
    if (verbose)
        std::cerr << "Processing language code: " << _3letter_code << '\n';

    std::unordered_map<std::string, std::pair<unsigned, std::string>> token_to_line_no_and_other_map;
    if (::access(output_file_path.c_str(), R_OK) != 0)
        logger->warning("\"" + output_file_path + "\" is not readable, maybe it doesn't exist?");
    else {
        TranslationUtil::ReadIniFile(output_file_path, &token_to_line_no_and_other_map);

        if (unlikely(not FileUtil::RenameFile(output_file_path, output_file_path + ".bak", /* remove_target = */true)))
            logger->error("failed to rename \"" + output_file_path + "\" to \"" + output_file_path + ".bak\"! ("
                          + std::string(::strerror(errno)) + ")");
    }

    File output(output_file_path, "w");
    if (unlikely(output.fail()))
        logger->error("failed to open \"" + output_file_path + "\" for writing!");

    db_connection->queryOrDie("SELECT token,translation FROM vufind_translations WHERE language_code='"
                              + _3letter_code + "'");
    DbResultSet result_set(db_connection->getLastResultSet());
    if (unlikely(result_set.empty()))
        logger->error("found no translations for language code \"" + _3letter_code + "\"!");
    if (verbose)
        std::cerr << "\tFound " << result_set.size() << " (token,translation) pairs.\n";

    std::vector<std::tuple<unsigned, std::string, std::string>> line_nos_tokens_and_translations;
    while (const DbRow row = result_set.getNextRow()) {
        const auto &token_to_line_no_and_other(token_to_line_no_and_other_map.find(row[0]));
        if (token_to_line_no_and_other != token_to_line_no_and_other_map.cend())
            line_nos_tokens_and_translations.emplace_back(token_to_line_no_and_other->second.first, row[0], row[1]);
        else
            line_nos_tokens_and_translations.emplace_back(token_to_line_no_and_other_map.size() + 1, row[0], row[1]);
    }

    std::sort(line_nos_tokens_and_translations.begin(), line_nos_tokens_and_translations.end(),
              [](const std::tuple<unsigned, std::string,std::string> &left,
                 const std::tuple<unsigned, std::string,std::string> &right)
              { return std::get<0>(left) < std::get<0>(right); });

    for (const auto &line_no_token_and_translation : line_nos_tokens_and_translations) {
        const std::string token(std::get<1>(line_no_token_and_translation));
        const std::string translation(std::get<2>(line_no_token_and_translation));
        if (not translation.empty())
            output << token << " = \"" << StringUtil::TrimWhite(NormalizeBrackets(translation)) << "\"\n";
    }

    if (verbose)
        std::cerr << "Wrote " << line_nos_tokens_and_translations.size() << " language mappings to \""
                  << output_file_path << "\"\n";
}

void GetLanguageCodes(const bool verbose, DbConnection * const db_connection,
                      std::map<std::string, std::string> * language_codes)
{
    db_connection->queryOrDie("SELECT DISTINCT language_code FROM vufind_translations");
    DbResultSet language_codes_result_set(db_connection->getLastResultSet());
    if (unlikely(language_codes_result_set.empty()))
        logger->error("no language codes found, expected multiple!");

    while (const DbRow row = language_codes_result_set.getNextRow()) {
        const std::string german_language_code(
            TranslationUtil::MapFake3LetterEnglishLanguagesCodesToGermanLanguageCodes(row[0]));
        if (german_language_code == "???")
            continue;
        const std::string international_language_code(
            TranslationUtil::MapGerman3Or4LetterCodeToInternational2LetterCode(german_language_code));
        language_codes->emplace(international_language_code, row[0]);
    }
    if (verbose)
        std::cerr << "Found " << language_codes->size()
                  << " distinct language code in the \"vufind_translations\" table.\n";
}

const std::string CONF_FILE_PATH("/usr/local/var/lib/tuelib/translations.conf");

int main(int argc, char **argv) {
    ::progname = argv[0];

    if (argc < 2)
        Usage();
    bool verbose(false);
    if (std::strcmp(argv[1], "--verbose") == 0) {
        verbose = true;
        --argc, ++argv;
    }
    if (argc != 2)
        Usage();

    const std::string output_directory(argv[1]);
    if (unlikely(not FileUtil::IsDirectory(output_directory)))
        logger->error("\"" + output_directory + "\" is not a directory or can't be read!");

    try {
        const IniFile ini_file(CONF_FILE_PATH);
        const std::string sql_database(ini_file.getString("Database", "sql_database"));
        const std::string sql_username(ini_file.getString("Database", "sql_username"));
        const std::string sql_password(ini_file.getString("Database", "sql_password"));
        DbConnection db_connection(sql_database, sql_username, sql_password);

        std::map<std::string, std::string> _2letter_and_3letter_codes;
        GetLanguageCodes(verbose, &db_connection, &_2letter_and_3letter_codes);
        for (const auto &_2letter_intl_code_and_fake_3letter_english_code : _2letter_and_3letter_codes)
            ProcessLanguage(verbose,
                            output_directory + "/" + _2letter_intl_code_and_fake_3letter_english_code.first + ".ini",
                            _2letter_intl_code_and_fake_3letter_english_code.second, &db_connection);
    } catch (const std::exception &x) {
        logger->error("caught exception: " + std::string(x.what()));
    }
}
<|endoftext|>


<commit_before>#include <irrlicht.h>
#include <iostream>

namespace ic = irr::core;
namespace iv = irr::video;

// Serialize an irrlicht vector3df
std::ostream& operator<<(std::ostream& out, const ic::vector3df vec)
{
    out << "(" << vec.X
        << "," << vec.Y
        << "," << vec.Z
        << ")";
    return out;
}

// Serialize an irrlicht vector3df
std::ostream& operator<<(std::ostream& out, const ic::vector3di vec)
{
    out << "(" << vec.X
        << "," << vec.Y
        << "," << vec.Z
        << ")";
    return out;
}

// Serialize an irrlicht vector3df
std::ostream& operator<<(std::ostream& out, const ic::vector2df vec)
{
    out << "(" << vec.X
        << "," << vec.Y
        << ")";
    return out;
}

// Serialize an irrlicht vector3df
std::ostream& operator<<(std::ostream& out, const ic::vector2di vec)
{
    out << "(" << vec.X
        << "," << vec.Y
        << ")";
    return out;
}

// Serialize an irrlicht matrix4
std::ostream& operator<<(std::ostream& out, const ic::matrix4 mat)
{
    for(int i=0 ; i<4 ; ++i)
    {
        for(int j=0 ; j<4 ; ++j)
        {
            out << mat(j,i) << " ";
        }
        out << std::endl;
    }
    return out;
}

// Serialize an irrlicht SColor
std::ostream& operator<<(std::ostream& out, const iv::SColor color)
{
    out << "(" << color.getAlpha()
        << "," << color.getRed()
        << "," << color.getGreen()
        << "," << color.getBlue()
        << ")";
    return out;
}

// Serialize an irrlicht SColorf
std::ostream& operator<<(std::ostream& out, const iv::SColorf color)
{
    out << "(" << color.getAlpha()
        << "," << color.getRed()
        << "," << color.getGreen()
        << "," << color.getBlue()
        << ")";
    return out;
}
<commit_msg>ENH: Add a function to flip along X axis meshes loaded from OBJ<commit_after>#include <irrlicht.h>
#include <iostream>

namespace ic = irr::core;
namespace iv = irr::video;
namespace is = irr::scene;

// Serialize an irrlicht vector3df
std::ostream& operator<<(std::ostream& out, const ic::vector3df vec)
{
    out << "(" << vec.X
        << "," << vec.Y
        << "," << vec.Z
        << ")";
    return out;
}

// Serialize an irrlicht vector3df
std::ostream& operator<<(std::ostream& out, const ic::vector3di vec)
{
    out << "(" << vec.X
        << "," << vec.Y
        << "," << vec.Z
        << ")";
    return out;
}

// Serialize an irrlicht vector3df
std::ostream& operator<<(std::ostream& out, const ic::vector2df vec)
{
    out << "(" << vec.X
        << "," << vec.Y
        << ")";
    return out;
}

// Serialize an irrlicht vector3df
std::ostream& operator<<(std::ostream& out, const ic::vector2di vec)
{
    out << "(" << vec.X
        << "," << vec.Y
        << ")";
    return out;
}

// Serialize an irrlicht matrix4
std::ostream& operator<<(std::ostream& out, const ic::matrix4 mat)
{
    for(int i=0 ; i<4 ; ++i)
    {
        for(int j=0 ; j<4 ; ++j)
        {
            out << mat(j,i) << " ";
        }
        out << std::endl;
    }
    return out;
}

// Serialize an irrlicht SColor
std::ostream& operator<<(std::ostream& out, const iv::SColor color)
{
    out << "(" << color.getAlpha()
        << "," << color.getRed()
        << "," << color.getGreen()
        << "," << color.getBlue()
        << ")";
    return out;
}

// Serialize an irrlicht SColorf
std::ostream& operator<<(std::ostream& out, const iv::SColorf color)
{
    out << "(" << color.getAlpha()
        << "," << color.getRed()
        << "," << color.getGreen()
        << "," << color.getBlue()
        << ")";
    return out;
}

// Load a mesh from an obj file, make an X symmetry, and flip the triangles
// This is to avoid the mesh to be misplaced, because of irrlicht left-hand convention.
is::IMesh * loadIMeshFromOBJ(is::ISceneManager * smgr, const char * filepath)
{
    is::IMesh * mesh = smgr->getMesh(filepath);

    iv::S3DVertex* vertexArray = (iv::S3DVertex*)mesh->getMeshBuffer(0)->getVertices();
    for(int i=0 ; i < mesh->getMeshBuffer(0)->getVertexCount() ; i++)
    {
      vertexArray[i].Pos.X = -vertexArray[i].Pos.X;
    }
    smgr->getMeshManipulator()->flipSurfaces(mesh);

    return mesh;
}
<|endoftext|>


<commit_before>/* Copyright (c) 2012-2013 LevelDOWN contributors
 * See list at <https://github.com/rvagg/node-leveldown#contributing>
 * MIT +no-false-attribs License <https://github.com/rvagg/node-leveldown/blob/master/LICENSE>
 */

#include <node.h>
#include <node_buffer.h>

#include "database.h"
#include "leveldown.h"
#include "async.h"
#include "iterator_async.h"

namespace leveldown {

/** NEXT-MULTI WORKER **/

NextWorker::NextWorker (
    Iterator* iterator
  , NanCallback *callback
  , void (*localCallback)(Iterator*)
) : AsyncWorker(NULL, callback)
  , iterator(iterator)
  , localCallback(localCallback)
{};

NextWorker::~NextWorker () {}

void NextWorker::Execute () {
  ok = iterator->IteratorNext(result);
  if (!ok)
    SetStatus(iterator->IteratorStatus());
}

void NextWorker::HandleOKCallback () {
  size_t idx = 0;
  v8::Local<v8::Array> returnArray;
  if (ok)
    returnArray = NanNew<v8::Array>(result.size());
  else {
    // make room and add for a null-value at the end,
    // signaling that we're at the end
    returnArray = NanNew<v8::Array>(result.size() + 1);
    returnArray->Set(
        NanNew<v8::Integer>(static_cast<int>(result.size()))
      w(NanNull()
    );

  }

  for(idx = 0; idx < result.size(); ++idx) {
    std::pair<std::string, std::string> row = result[idx];
    std::string key = row.first;
    std::string value = row.second;

    v8::Local<v8::Value> returnKey;
    if (iterator->keyAsBuffer) {
      returnKey = NanNewBufferHandle((char*)key.data(), key.size());
    } else {
      returnKey = NanNew<v8::String>((char*)key.data(), key.size());
    }

    v8::Local<v8::Value> returnValue;
    if (iterator->valueAsBuffer) {
      returnValue = NanNewBufferHandle((char*)value.data(), value.size());
    } else {
      returnValue = NanNew<v8::String>((char*)value.data(), value.size());
    }

    v8::Local<v8::Object> returnObject = NanNew<v8::Object>();
    returnObject->Set(NanNew("key"), returnKey);
    returnObject->Set(NanNew("value"), returnValue);
    returnArray->Set(NanNew<v8::Integer>(static_cast<int>(idx)), returnObject);
  }

  // clean up & handle the next/end state see iterator.cc/checkEndCallback
  localCallback(iterator);

  v8::Local<v8::Value> argv[] = {
      NanNull()
    , returnArray
  };
  callback->Call(2, argv);
}

/** END WORKER **/

EndWorker::EndWorker (
    Iterator* iterator
  , NanCallback *callback
) : AsyncWorker(NULL, callback)
  , iterator(iterator)
{};

EndWorker::~EndWorker () {}

void EndWorker::Execute () {
  iterator->IteratorEnd();
}

void EndWorker::HandleOKCallback () {
  iterator->Release();
  callback->Call(0, NULL);
}

} // namespace leveldown
<commit_msg>omg, embarrassing fumble (pressed ⌘+z before ⌘+s, lolz)<commit_after>/* Copyright (c) 2012-2013 LevelDOWN contributors
 * See list at <https://github.com/rvagg/node-leveldown#contributing>
 * MIT +no-false-attribs License <https://github.com/rvagg/node-leveldown/blob/master/LICENSE>
 */

#include <node.h>
#include <node_buffer.h>

#include "database.h"
#include "leveldown.h"
#include "async.h"
#include "iterator_async.h"

namespace leveldown {

/** NEXT-MULTI WORKER **/

NextWorker::NextWorker (
    Iterator* iterator
  , NanCallback *callback
  , void (*localCallback)(Iterator*)
) : AsyncWorker(NULL, callback)
  , iterator(iterator)
  , localCallback(localCallback)
{};

NextWorker::~NextWorker () {}

void NextWorker::Execute () {
  ok = iterator->IteratorNext(result);
  if (!ok)
    SetStatus(iterator->IteratorStatus());
}

void NextWorker::HandleOKCallback () {
  size_t idx = 0;
  v8::Local<v8::Array> returnArray;
  if (ok)
    returnArray = NanNew<v8::Array>(result.size());
  else {
    // make room and add for a null-value at the end,
    // signaling that we're at the end
    returnArray = NanNew<v8::Array>(result.size() + 1);
    returnArray->Set(
        NanNew<v8::Integer>(static_cast<int>(result.size()))
      , NanNull()
    );

  }

  for(idx = 0; idx < result.size(); ++idx) {
    std::pair<std::string, std::string> row = result[idx];
    std::string key = row.first;
    std::string value = row.second;

    v8::Local<v8::Value> returnKey;
    if (iterator->keyAsBuffer) {
      returnKey = NanNewBufferHandle((char*)key.data(), key.size());
    } else {
      returnKey = NanNew<v8::String>((char*)key.data(), key.size());
    }

    v8::Local<v8::Value> returnValue;
    if (iterator->valueAsBuffer) {
      returnValue = NanNewBufferHandle((char*)value.data(), value.size());
    } else {
      returnValue = NanNew<v8::String>((char*)value.data(), value.size());
    }

    v8::Local<v8::Object> returnObject = NanNew<v8::Object>();
    returnObject->Set(NanNew("key"), returnKey);
    returnObject->Set(NanNew("value"), returnValue);
    returnArray->Set(NanNew<v8::Integer>(static_cast<int>(idx)), returnObject);
  }

  // clean up & handle the next/end state see iterator.cc/checkEndCallback
  localCallback(iterator);

  v8::Local<v8::Value> argv[] = {
      NanNull()
    , returnArray
  };
  callback->Call(2, argv);
}

/** END WORKER **/

EndWorker::EndWorker (
    Iterator* iterator
  , NanCallback *callback
) : AsyncWorker(NULL, callback)
  , iterator(iterator)
{};

EndWorker::~EndWorker () {}

void EndWorker::Execute () {
  iterator->IteratorEnd();
}

void EndWorker::HandleOKCallback () {
  iterator->Release();
  callback->Call(0, NULL);
}

} // namespace leveldown
<|endoftext|>