<commit_before>/*
 *  Copyright (c) 2014 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "third_party/googletest/src/include/gtest/gtest.h"

#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/util.h"
#include "test/y4m_video_source.h"
#include "test/yuv_video_source.h"
#include "vp9/decoder/vp9_decoder.h"

typedef vpx_codec_stream_info_t vp9_stream_info_t;
struct vpx_codec_alg_priv {
  vpx_codec_priv_t        base;
  vpx_codec_dec_cfg_t     cfg;
  vp9_stream_info_t       si;
  struct VP9Decoder      *pbi;
  int                     postproc_cfg_set;
  vp8_postproc_cfg_t      postproc_cfg;
  vpx_decrypt_cb          decrypt_cb;
  void                   *decrypt_state;
  vpx_image_t             img;
  int                     img_avail;
  int                     flushed;
  int                     invert_tile_order;
  int                     frame_parallel_decode;

  // External frame buffer info to save for VP9 common.
  void *ext_priv;  // Private data associated with the external frame buffers.
  vpx_get_frame_buffer_cb_fn_t get_ext_fb_cb;
  vpx_release_frame_buffer_cb_fn_t release_ext_fb_cb;
};

static vpx_codec_alg_priv_t *get_alg_priv(vpx_codec_ctx_t *ctx) {
  return (vpx_codec_alg_priv_t *)ctx->priv;
}

namespace {

const unsigned int kFramerate = 50;
const int kCpuUsed = 2;

struct EncodePerfTestVideo {
  const char *name;
  uint32_t width;
  uint32_t height;
  uint32_t bitrate;
  int frames;
};

const EncodePerfTestVideo kVP9EncodePerfTestVectors[] = {
  {"niklas_1280_720_30.y4m", 1280, 720, 600, 10},
};

struct EncodeParameters {
  int32_t tile_rows;
  int32_t tile_cols;
  int32_t lossless;
  int32_t error_resilient;
  int32_t frame_parallel;
  vpx_color_space_t cs;
  // TODO(JBB): quantizers / bitrate
};

const EncodeParameters kVP9EncodeParameterSet[] = {
    {0, 0, 0, 1, 0, VPX_CS_BT_601},
    {0, 0, 0, 0, 0, VPX_CS_BT_709},
    {0, 0, 1, 0, 0, VPX_CS_BT_2020},
    {0, 2, 0, 0, 1, VPX_CS_UNKNOWN},
    // TODO(JBB): Test profiles (requires more work).
};

int is_extension_y4m(const char *filename) {
  const char *dot = strrchr(filename, '.');
  if (!dot || dot == filename)
    return 0;
  else
    return !strcmp(dot, ".y4m");
}

class VpxEncoderParmsGetToDecoder
    : public ::libvpx_test::EncoderTest,
      public ::libvpx_test::CodecTestWith2Params<EncodeParameters, \
                                                 EncodePerfTestVideo> {
 protected:
  VpxEncoderParmsGetToDecoder()
      : EncoderTest(GET_PARAM(0)),
        encode_parms(GET_PARAM(1)) {
  }

  virtual ~VpxEncoderParmsGetToDecoder() {}

  virtual void SetUp() {
    InitializeConfig();
    SetMode(::libvpx_test::kTwoPassGood);
    cfg_.g_lag_in_frames = 25;
    cfg_.g_error_resilient = encode_parms.error_resilient;
    dec_cfg_.threads = 4;
    test_video_ = GET_PARAM(2);
    cfg_.rc_target_bitrate = test_video_.bitrate;
  }

  virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
                                  ::libvpx_test::Encoder *encoder) {
    if (video->frame() == 1) {
      encoder->Control(VP9E_SET_COLOR_SPACE, encode_parms.cs);
      encoder->Control(VP9E_SET_LOSSLESS, encode_parms.lossless);
      encoder->Control(VP9E_SET_FRAME_PARALLEL_DECODING,
                       encode_parms.frame_parallel);
      encoder->Control(VP9E_SET_TILE_ROWS, encode_parms.tile_rows);
      encoder->Control(VP9E_SET_TILE_COLUMNS, encode_parms.tile_cols);
      encoder->Control(VP8E_SET_CPUUSED, kCpuUsed);
      encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1);
      encoder->Control(VP8E_SET_ARNR_MAXFRAMES, 7);
      encoder->Control(VP8E_SET_ARNR_STRENGTH, 5);
      encoder->Control(VP8E_SET_ARNR_TYPE, 3);
    }
  }

  virtual bool HandleDecodeResult(const vpx_codec_err_t res_dec,
                                  const libvpx_test::VideoSource& video,
                                  libvpx_test::Decoder *decoder) {
    vpx_codec_ctx_t* vp9_decoder = decoder->GetDecoder();
    vpx_codec_alg_priv_t* priv =
        (vpx_codec_alg_priv_t*) get_alg_priv(vp9_decoder);

    VP9Decoder* pbi = priv->pbi;
    VP9_COMMON* common = &pbi->common;

    if (encode_parms.lossless) {
      EXPECT_EQ(common->base_qindex, 0);
      EXPECT_EQ(common->y_dc_delta_q, 0);
      EXPECT_EQ(common->uv_dc_delta_q, 0);
      EXPECT_EQ(common->uv_ac_delta_q, 0);
      EXPECT_EQ(common->tx_mode, ONLY_4X4);
    }
    EXPECT_EQ(common->error_resilient_mode, encode_parms.error_resilient);
    if (encode_parms.error_resilient) {
      EXPECT_EQ(common->frame_parallel_decoding_mode, 1);
      EXPECT_EQ(common->use_prev_frame_mvs, 0);
    } else {
      EXPECT_EQ(common->frame_parallel_decoding_mode,
                encode_parms.frame_parallel);
    }
    EXPECT_EQ(common->color_space, encode_parms.cs);
    EXPECT_EQ(common->log2_tile_cols, encode_parms.tile_cols);
    EXPECT_EQ(common->log2_tile_rows, encode_parms.tile_rows);

    EXPECT_EQ(VPX_CODEC_OK, res_dec) << decoder->DecodeError();
    return VPX_CODEC_OK == res_dec;
  }

  EncodePerfTestVideo test_video_;

 private:
  EncodeParameters encode_parms;
};

// TODO(hkuang): This test conflicts with frame parallel decode. So disable it
// for now until fix.
TEST_P(VpxEncoderParmsGetToDecoder, DISABLED_BitstreamParms) {
  init_flags_ = VPX_CODEC_USE_PSNR;

  libvpx_test::VideoSource *video;
  if (is_extension_y4m(test_video_.name)) {
    video = new libvpx_test::Y4mVideoSource(test_video_.name,
                                            0, test_video_.frames);
  } else {
    video = new libvpx_test::YUVVideoSource(test_video_.name,
                                            VPX_IMG_FMT_I420,
                                            test_video_.width,
                                            test_video_.height,
                                            kFramerate, 1, 0,
                                            test_video_.frames);
  }

  ASSERT_NO_FATAL_FAILURE(RunLoop(video));
  delete(video);
}

VP9_INSTANTIATE_TEST_CASE(
    VpxEncoderParmsGetToDecoder,
    ::testing::ValuesIn(kVP9EncodeParameterSet),
    ::testing::ValuesIn(kVP9EncodePerfTestVectors));
}  // namespace
<commit_msg>fix BitstreamParms test<commit_after>/*
 *  Copyright (c) 2014 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "third_party/googletest/src/include/gtest/gtest.h"

#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/util.h"
#include "test/y4m_video_source.h"
#include "test/yuv_video_source.h"
#include "vp9/decoder/vp9_decoder.h"

#include "vp9/vp9_dx_iface.c"

static vpx_codec_alg_priv_t *get_alg_priv(vpx_codec_ctx_t *ctx) {
  return (vpx_codec_alg_priv_t *)ctx->priv;
}

namespace {

const unsigned int kFramerate = 50;
const int kCpuUsed = 2;

struct EncodePerfTestVideo {
  const char *name;
  uint32_t width;
  uint32_t height;
  uint32_t bitrate;
  int frames;
};

const EncodePerfTestVideo kVP9EncodePerfTestVectors[] = {
  {"niklas_1280_720_30.y4m", 1280, 720, 600, 10},
};

struct EncodeParameters {
  int32_t tile_rows;
  int32_t tile_cols;
  int32_t lossless;
  int32_t error_resilient;
  int32_t frame_parallel;
  vpx_color_space_t cs;
  // TODO(JBB): quantizers / bitrate
};

const EncodeParameters kVP9EncodeParameterSet[] = {
    {0, 0, 0, 1, 0, VPX_CS_BT_601},
    {0, 0, 0, 0, 0, VPX_CS_BT_709},
    {0, 0, 1, 0, 0, VPX_CS_BT_2020},
    {0, 2, 0, 0, 1, VPX_CS_UNKNOWN},
    // TODO(JBB): Test profiles (requires more work).
};

int is_extension_y4m(const char *filename) {
  const char *dot = strrchr(filename, '.');
  if (!dot || dot == filename)
    return 0;
  else
    return !strcmp(dot, ".y4m");
}

class VpxEncoderParmsGetToDecoder
    : public ::libvpx_test::EncoderTest,
      public ::libvpx_test::CodecTestWith2Params<EncodeParameters, \
                                                 EncodePerfTestVideo> {
 protected:
  VpxEncoderParmsGetToDecoder()
      : EncoderTest(GET_PARAM(0)),
        encode_parms(GET_PARAM(1)) {
  }

  virtual ~VpxEncoderParmsGetToDecoder() {}

  virtual void SetUp() {
    InitializeConfig();
    SetMode(::libvpx_test::kTwoPassGood);
    cfg_.g_lag_in_frames = 25;
    cfg_.g_error_resilient = encode_parms.error_resilient;
    dec_cfg_.threads = 4;
    test_video_ = GET_PARAM(2);
    cfg_.rc_target_bitrate = test_video_.bitrate;
  }

  virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
                                  ::libvpx_test::Encoder *encoder) {
    if (video->frame() == 1) {
      encoder->Control(VP9E_SET_COLOR_SPACE, encode_parms.cs);
      encoder->Control(VP9E_SET_LOSSLESS, encode_parms.lossless);
      encoder->Control(VP9E_SET_FRAME_PARALLEL_DECODING,
                       encode_parms.frame_parallel);
      encoder->Control(VP9E_SET_TILE_ROWS, encode_parms.tile_rows);
      encoder->Control(VP9E_SET_TILE_COLUMNS, encode_parms.tile_cols);
      encoder->Control(VP8E_SET_CPUUSED, kCpuUsed);
      encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1);
      encoder->Control(VP8E_SET_ARNR_MAXFRAMES, 7);
      encoder->Control(VP8E_SET_ARNR_STRENGTH, 5);
      encoder->Control(VP8E_SET_ARNR_TYPE, 3);
    }
  }

  virtual bool HandleDecodeResult(const vpx_codec_err_t res_dec,
                                  const libvpx_test::VideoSource& video,
                                  libvpx_test::Decoder *decoder) {
    vpx_codec_ctx_t* vp9_decoder = decoder->GetDecoder();
    vpx_codec_alg_priv_t* priv =
        (vpx_codec_alg_priv_t*) get_alg_priv(vp9_decoder);
    FrameWorkerData *const worker_data =
        reinterpret_cast<FrameWorkerData *>(priv->frame_workers[0].data1);
    VP9_COMMON *const common = &worker_data->pbi->common;

    if (encode_parms.lossless) {
      EXPECT_EQ(common->base_qindex, 0);
      EXPECT_EQ(common->y_dc_delta_q, 0);
      EXPECT_EQ(common->uv_dc_delta_q, 0);
      EXPECT_EQ(common->uv_ac_delta_q, 0);
      EXPECT_EQ(common->tx_mode, ONLY_4X4);
    }
    EXPECT_EQ(common->error_resilient_mode, encode_parms.error_resilient);
    if (encode_parms.error_resilient) {
      EXPECT_EQ(common->frame_parallel_decoding_mode, 1);
      EXPECT_EQ(common->use_prev_frame_mvs, 0);
    } else {
      EXPECT_EQ(common->frame_parallel_decoding_mode,
                encode_parms.frame_parallel);
    }
    EXPECT_EQ(common->color_space, encode_parms.cs);
    EXPECT_EQ(common->log2_tile_cols, encode_parms.tile_cols);
    EXPECT_EQ(common->log2_tile_rows, encode_parms.tile_rows);

    EXPECT_EQ(VPX_CODEC_OK, res_dec) << decoder->DecodeError();
    return VPX_CODEC_OK == res_dec;
  }

  EncodePerfTestVideo test_video_;

 private:
  EncodeParameters encode_parms;
};

TEST_P(VpxEncoderParmsGetToDecoder, BitstreamParms) {
  init_flags_ = VPX_CODEC_USE_PSNR;

  libvpx_test::VideoSource *video;
  if (is_extension_y4m(test_video_.name)) {
    video = new libvpx_test::Y4mVideoSource(test_video_.name,
                                            0, test_video_.frames);
  } else {
    video = new libvpx_test::YUVVideoSource(test_video_.name,
                                            VPX_IMG_FMT_I420,
                                            test_video_.width,
                                            test_video_.height,
                                            kFramerate, 1, 0,
                                            test_video_.frames);
  }

  ASSERT_NO_FATAL_FAILURE(RunLoop(video));
  delete(video);
}

VP9_INSTANTIATE_TEST_CASE(
    VpxEncoderParmsGetToDecoder,
    ::testing::ValuesIn(kVP9EncodeParameterSet),
    ::testing::ValuesIn(kVP9EncodePerfTestVectors));
}  // namespace
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2019 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * 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
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file Publication.hpp
 *
 */

#pragma once

#include <px4_platform_common/defines.h>
#include <systemlib/err.h>
#include <uORB/uORB.h>
#include "uORBDeviceNode.hpp"

#include "Publication.hpp"

namespace uORB
{

/**
 * Base publication multi wrapper class
 */
template<typename T, uint8_t QSIZE = DefaultQueueSize<T>::value>
class PublicationMulti : public PublicationBase
{
public:

	/**
	 * Constructor
	 *
	 * @param meta The uORB metadata (usually from the ORB_ID() macro) for the topic.
	 */
	PublicationMulti(ORB_ID id) :
		PublicationBase(id)
	{}

	PublicationMulti(const orb_metadata *meta) :
		PublicationBase(static_cast<ORB_ID>(meta->o_id))
	{}

	bool advertise()
	{
		if (!advertised()) {
			int instance = 0;
			_handle = orb_advertise_multi_queue(get_topic(), nullptr, &instance, QSIZE);
		}

		return advertised();
	}

	/**
	 * Publish the struct
	 * @param data The uORB message struct we are updating.
	 */
	bool publish(const T &data)
	{
		if (!advertised()) {
			advertise();
		}

		return (orb_publish(get_topic(), _handle, &data) == PX4_OK);
	}

	int get_instance() const
	{
		if (_handle) {
			return static_cast<uORB::DeviceNode *>(_handle)->get_instance();
		}

		return -1;
	}
};

/**
 * The publication multi class with data embedded.
 */
template<typename T>
class PublicationMultiData : public PublicationMulti<T>
{
public:
	/**
	 * Constructor
	 *
	 * @param meta The uORB metadata (usually from the ORB_ID() macro) for the topic.
	 */
	PublicationMultiData(ORB_ID id) : PublicationMulti<T>(id) {}
	PublicationMultiData(const orb_metadata *meta) : PublicationMulti<T>(meta) {}

	T	&get() { return _data; }
	void	set(const T &data) { _data = data; }

	// Publishes the embedded struct.
	bool	update() { return PublicationMulti<T>::publish(_data); }
	bool	update(const T &data)
	{
		_data = data;
		return PublicationMulti<T>::publish(_data);
	}

private:
	T _data{};
};

} // namespace uORB
<commit_msg>uORB: PublicationMulti get_instance() advertise if not already advertised<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2019 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * 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
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file Publication.hpp
 *
 */

#pragma once

#include <px4_platform_common/defines.h>
#include <systemlib/err.h>
#include <uORB/uORB.h>
#include "uORBDeviceNode.hpp"

#include "Publication.hpp"

namespace uORB
{

/**
 * Base publication multi wrapper class
 */
template<typename T, uint8_t QSIZE = DefaultQueueSize<T>::value>
class PublicationMulti : public PublicationBase
{
public:

	/**
	 * Constructor
	 *
	 * @param meta The uORB metadata (usually from the ORB_ID() macro) for the topic.
	 */
	PublicationMulti(ORB_ID id) :
		PublicationBase(id)
	{}

	PublicationMulti(const orb_metadata *meta) :
		PublicationBase(static_cast<ORB_ID>(meta->o_id))
	{}

	bool advertise()
	{
		if (!advertised()) {
			int instance = 0;
			_handle = orb_advertise_multi_queue(get_topic(), nullptr, &instance, QSIZE);
		}

		return advertised();
	}

	/**
	 * Publish the struct
	 * @param data The uORB message struct we are updating.
	 */
	bool publish(const T &data)
	{
		if (!advertised()) {
			advertise();
		}

		return (orb_publish(get_topic(), _handle, &data) == PX4_OK);
	}

	int get_instance()
	{
		// advertise if not already advertised
		if (advertise()) {
			return static_cast<uORB::DeviceNode *>(_handle)->get_instance();
		}

		return -1;
	}
};

/**
 * The publication multi class with data embedded.
 */
template<typename T>
class PublicationMultiData : public PublicationMulti<T>
{
public:
	/**
	 * Constructor
	 *
	 * @param meta The uORB metadata (usually from the ORB_ID() macro) for the topic.
	 */
	PublicationMultiData(ORB_ID id) : PublicationMulti<T>(id) {}
	PublicationMultiData(const orb_metadata *meta) : PublicationMulti<T>(meta) {}

	T	&get() { return _data; }
	void	set(const T &data) { _data = data; }

	// Publishes the embedded struct.
	bool	update() { return PublicationMulti<T>::publish(_data); }
	bool	update(const T &data)
	{
		_data = data;
		return PublicationMulti<T>::publish(_data);
	}

private:
	T _data{};
};

} // namespace uORB
<|endoftext|>


<commit_before>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * 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 "stdafx.h"

#include <sstream>

#include "store/api/item.h"
#include "item_vector.h"

namespace zorba { namespace simplestore {

ItemVector::ItemVector(std::vector<store::Item_t>& items)
  :
  store::Item(LIST)
{
  size_t numItems = items.size();

  theItems.resize(numItems);

  for (size_t i = 0; i < numItems; i++)
    theItems[i].transfer(items[i]);
}

zstring ItemVector::getStringValue() const
{
  size_t numItems = theItems.size();

  if (numItems == 1)
  {
    return theItems[0]->getStringValue();
  }
  else if (numItems > 0)
  {
    zstring val;

    theItems[0]->appendStringValue(val);

    for (size_t i = 1; i < numItems; ++i)
    {
      val += " ";
      theItems[i]->appendStringValue(val);
    }

    return val;
  }

  return zstring();
}

void ItemVector::getStringValue2(zstring& val) const
{
  size_t numItems = theItems.size();

  if (numItems == 1)
  {
    theItems[0]->getStringValue2(val);
    return;
  }
  else if (numItems > 0)
  {
    theItems[0]->appendStringValue(val);

    for (size_t i = 1; i < numItems; ++i)
    {
      val += " ";
      theItems[i]->appendStringValue(val);
    }
  }
}

void ItemVector::appendStringValue(zstring& buf) const
{
  size_t numItems = theItems.size();

  if (numItems > 0)
  {
    theItems[0]->appendStringValue(buf);

    for (size_t i = 1; i < numItems; ++i)
    {
      buf += " ";
      theItems[i]->appendStringValue(buf);
    }
  }
}

zstring ItemVector::show() const
{
  std::ostringstream res;
  res << "ItemVector size: " << size() + " [";
	for ( ulong i = 0; i < size(); i++)
		res << getItem(i)->show() << ", ";
	res << "]";

  return res.str();
}

} // namespace store
} // namespace zorba
/* vim:set et sw=2 ts=2: */
<commit_msg>Fixed incorrect use of +.<commit_after>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * 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 "stdafx.h"

#include <sstream>

#include "store/api/item.h"
#include "item_vector.h"

namespace zorba { namespace simplestore {

ItemVector::ItemVector(std::vector<store::Item_t>& items)
  :
  store::Item(LIST)
{
  size_t numItems = items.size();

  theItems.resize(numItems);

  for (size_t i = 0; i < numItems; i++)
    theItems[i].transfer(items[i]);
}

zstring ItemVector::getStringValue() const
{
  size_t numItems = theItems.size();

  if (numItems == 1)
  {
    return theItems[0]->getStringValue();
  }
  else if (numItems > 0)
  {
    zstring val;

    theItems[0]->appendStringValue(val);

    for (size_t i = 1; i < numItems; ++i)
    {
      val += " ";
      theItems[i]->appendStringValue(val);
    }

    return val;
  }

  return zstring();
}

void ItemVector::getStringValue2(zstring& val) const
{
  size_t numItems = theItems.size();

  if (numItems == 1)
  {
    theItems[0]->getStringValue2(val);
    return;
  }
  else if (numItems > 0)
  {
    theItems[0]->appendStringValue(val);

    for (size_t i = 1; i < numItems; ++i)
    {
      val += " ";
      theItems[i]->appendStringValue(val);
    }
  }
}

void ItemVector::appendStringValue(zstring& buf) const
{
  size_t numItems = theItems.size();

  if (numItems > 0)
  {
    theItems[0]->appendStringValue(buf);

    for (size_t i = 1; i < numItems; ++i)
    {
      buf += " ";
      theItems[i]->appendStringValue(buf);
    }
  }
}

zstring ItemVector::show() const
{
  std::ostringstream res;
  res << "ItemVector size: " << size() << " [";
	for ( ulong i = 0; i < size(); i++)
		res << getItem(i)->show() << ", ";
	res << "]";

  return res.str();
}

} // namespace store
} // namespace zorba
/* vim:set et sw=2 ts=2: */
<|endoftext|>


<commit_before>//----------------------------------*-C++-*----------------------------------//
/*!
 * \file   mc/Source.hh
 * \author Thomas M. Evans
 * \date   Mon May 05 14:22:41 2014
 * \brief  Source class definition.
 * \note   Copyright (C) 2014 Oak Ridge National Laboratory, UT-Battelle, LLC.
 */
//---------------------------------------------------------------------------//

#ifndef mc_Source_hh
#define mc_Source_hh

#include <memory>
#include <cmath>

#include "utils/Definitions.hh"
#include "utils/Constants.hh"
#include "rng/RNG_Control.hh"
#include "Physics.hh"

namespace profugus
{

//===========================================================================//
/*!
 * \class Source
 * \brief Base class definition for Monte Carlo sources.
 */
//===========================================================================//

template <class Geometry>
class Source
{
  public:
    //@{
    //! Useful typedefs.
    typedef Geometry                            Geometry_t;
    typedef typename Geometry_t::Geo_State_t    Geo_State_t;
    typedef Physics<Geometry>                   Physics_t;
    typedef typename Physics_t::Particle_t      Particle_t;
    typedef typename Geometry_t::Space_Vector   Space_Vector;
    typedef RNG_Control                         RNG_Control_t;
    typedef RNG_Control_t::RNG_t                RNG_t;
    typedef def::size_type                      size_type;
    //@}

    //@{
    //! Smart pointers
    typedef std::shared_ptr<Geometry_t>    SP_Geometry;
    typedef std::shared_ptr<Physics_t>     SP_Physics;
    typedef std::shared_ptr<Particle_t>    SP_Particle;
    typedef std::shared_ptr<RNG_Control_t> SP_RNG_Control;
    //@}

  protected:
    // >>> DATA

    // Geometry and physics.
    SP_Geometry b_geometry;
    SP_Physics  b_physics;

    // Random number controller.
    SP_RNG_Control b_rng_control;

    // Sample isotropic angle.
    void sample_angle(Space_Vector &omega, RNG_t rng)
    {
        using def::X; using def::Y; using def::Z;

        omega[Z]        = 1.0 - 2.0 * rng.ran();
        double phi      = constants::two_pi * rng.ran();
        double sintheta = std::sqrt(1.0 - omega[Z] * omega[Z]);

        omega[X] = sintheta * std::cos(phi);
        omega[Y] = sintheta * std::sin(phi);
    }

    // Calculate random number offsets.
    void make_RNG();

    // Node ids.
    int b_node, b_nodes;

  public:
    // Constructor.
    Source(SP_Geometry    geometry,
           SP_Physics     physics,
           SP_RNG_Control rng_control);

    //! Virtual destructor.
    virtual ~Source() = 0;

    // >>> VIRTUAL PUBLIC INTERFACE

    //! Get a particle from the source.
    virtual SP_Particle get_particle() = 0;

    //! Whether the source has finished emitting all its particles.
    virtual bool empty() const = 0;

    //! Number of particles to transport in the source on the current domain.
    virtual size_type num_to_transport() const = 0;

    //! Total number of particles to transport in the entire problem/cycle.
    virtual size_type total_num_to_transport() const = 0;

    // >>> INHERITED INTERFACE

    //! Get the geometry.
    const Geometry_t& geometry() const { return *b_geometry; }

    //! Get the physics.
    const Physics_t& physics() const { return *b_physics; }

    //! Get the RNG controller.
    const RNG_Control_t& rng_control() const { return *b_rng_control; }

    //! Number of random number streams generated so far (inclusive).
    int num_streams() const { return d_rng_stream; }

  private:
    // >>> DATA

    // Offsets used for random number generator selection.
    int d_rng_stream;
};

} // end namespace profugus

#endif // mc_Source_hh

//---------------------------------------------------------------------------//
//                 end of Source.hh
//---------------------------------------------------------------------------//
<commit_msg>Changing accessors to geometry and physics.<commit_after>//----------------------------------*-C++-*----------------------------------//
/*!
 * \file   mc/Source.hh
 * \author Thomas M. Evans
 * \date   Mon May 05 14:22:41 2014
 * \brief  Source class definition.
 * \note   Copyright (C) 2014 Oak Ridge National Laboratory, UT-Battelle, LLC.
 */
//---------------------------------------------------------------------------//

#ifndef mc_Source_hh
#define mc_Source_hh

#include <memory>
#include <cmath>

#include "utils/Definitions.hh"
#include "utils/Constants.hh"
#include "rng/RNG_Control.hh"
#include "Physics.hh"

namespace profugus
{

//===========================================================================//
/*!
 * \class Source
 * \brief Base class definition for Monte Carlo sources.
 */
//===========================================================================//

template <class Geometry>
class Source
{
  public:
    //@{
    //! Useful typedefs.
    typedef Geometry                            Geometry_t;
    typedef typename Geometry_t::Geo_State_t    Geo_State_t;
    typedef Physics<Geometry>                   Physics_t;
    typedef typename Physics_t::Particle_t      Particle_t;
    typedef typename Geometry_t::Space_Vector   Space_Vector;
    typedef RNG_Control                         RNG_Control_t;
    typedef RNG_Control_t::RNG_t                RNG_t;
    typedef def::size_type                      size_type;
    //@}

    //@{
    //! Smart pointers
    typedef std::shared_ptr<Geometry_t>    SP_Geometry;
    typedef std::shared_ptr<Physics_t>     SP_Physics;
    typedef std::shared_ptr<Particle_t>    SP_Particle;
    typedef std::shared_ptr<RNG_Control_t> SP_RNG_Control;
    //@}

  protected:
    // >>> DATA

    // Geometry and physics.
    SP_Geometry b_geometry;
    SP_Physics  b_physics;

    // Random number controller.
    SP_RNG_Control b_rng_control;

    // Sample isotropic angle.
    void sample_angle(Space_Vector &omega, RNG_t rng)
    {
        using def::X; using def::Y; using def::Z;

        omega[Z]        = 1.0 - 2.0 * rng.ran();
        double phi      = constants::two_pi * rng.ran();
        double sintheta = std::sqrt(1.0 - omega[Z] * omega[Z]);

        omega[X] = sintheta * std::cos(phi);
        omega[Y] = sintheta * std::sin(phi);
    }

    // Calculate random number offsets.
    void make_RNG();

    // Node ids.
    int b_node, b_nodes;

  public:
    // Constructor.
    Source(SP_Geometry    geometry,
           SP_Physics     physics,
           SP_RNG_Control rng_control);

    //! Virtual destructor.
    virtual ~Source() = 0;

    // >>> VIRTUAL PUBLIC INTERFACE

    //! Get a particle from the source.
    virtual SP_Particle get_particle() = 0;

    //! Whether the source has finished emitting all its particles.
    virtual bool empty() const = 0;

    //! Number of particles to transport in the source on the current domain.
    virtual size_type num_to_transport() const = 0;

    //! Total number of particles to transport in the entire problem/cycle.
    virtual size_type total_num_to_transport() const = 0;

    // >>> INHERITED INTERFACE

    //! Get the geometry.
    SP_Geometry geometry() const { return b_geometry; }

    //! Get the physics.
    SP_Physics physics() const { return b_physics; }

    //! Get the RNG controller.
    const RNG_Control_t& rng_control() const { return *b_rng_control; }

    //! Number of random number streams generated so far (inclusive).
    int num_streams() const { return d_rng_stream; }

  private:
    // >>> DATA

    // Offsets used for random number generator selection.
    int d_rng_stream;
};

} // end namespace profugus

#endif // mc_Source_hh

//---------------------------------------------------------------------------//
//                 end of Source.hh
//---------------------------------------------------------------------------//
<|endoftext|>


<commit_before>#include <algorithm>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include "renderer.hpp"

using std::cout;
using std::endl;
using std::runtime_error;
using std::size_t;
using std::string;
using std::stringstream;
using std::vector;

namespace render {

static const string EOL("\n");

class AllowedTypes {
public:
  AllowedTypes() {
    this->allowed = new vector<string>();
    this->allowed->push_back("char");
    this->allowed->push_back("uint8");
    this->allowed->push_back("uint16");
    this->allowed->push_back("uint32");
    this->allowed->push_back("uint64");
    this->allowed->push_back("int8");
    this->allowed->push_back("int16");
    this->allowed->push_back("int32");
    this->allowed->push_back("int64");
    this->allowed->push_back("float32");
    this->allowed->push_back("float64");
  }

  ~AllowedTypes() {
    if (this->allowed != NULL)
      delete this->allowed;
    this->allowed = NULL;
  }

  bool has(const string & descr) const {
    vector<string>::const_iterator pos
                    = std::find(this->allowed->begin(), this->allowed->end(), descr);
    return (pos != this->allowed->end());
  }

  friend std::ostream& operator<<(std::ostream &os, const AllowedTypes & thing) {
    size_t size = thing.allowed->size();
    for (size_t i = 0; i < size; i++) {
      os << thing.allowed->at(i);
      if (i + 1 < size)
	os << ", ";
    }
    return os;
  }

private:
  vector<string> * allowed;
};

Renderer::Renderer()
{
  this->m_showLines = false;
  this->m_dataDescr = new vector<string>();
}

Renderer::~Renderer()
{
  if (this->m_dataDescr != NULL)
    delete this->m_dataDescr;
  this->m_dataDescr = NULL;
}

void Renderer::setDataDescr(const std::string & descr)
{
  AllowedTypes allowed;
  if (! allowed.has(descr)) {
    stringstream msg;
    msg << "Encountered unknown type \"" << descr << "\". Allowed types are: "
	<< allowed;
    throw runtime_error(msg.str());
  }
  this->m_dataDescr->clear();
  this->m_dataDescr->push_back(descr);
}

void Renderer::showLines(const bool showLines)
{
  this->m_showLines = showLines;
}

template <typename NumT>
void Renderer::innerShowData(BinFile &file, size_t offset, size_t length)
{
  // this calculation of offset is just wrong
  size_t myOffset = 0;
  if ((offset % sizeof(NumT)) == 0)
    myOffset = offset / sizeof(NumT);

  vector<NumT> data;
  file.read(data, length);
  if (!(data.empty())) {
    for (size_t i = 0; i < data.size(); i++) {
      if (this->m_showLines)
	cout << (myOffset + i + 1) << " "; // start counting with one
      cout << data[i] << EOL;
    }
  }
}

/// Special version for strings
template <>
void Renderer::innerShowData<char>(BinFile &file, size_t offset, size_t length)
{
  stringstream data;
  file.read(data, length);
  cout << data.str() << endl;
}

void Renderer::showData(BinFile &file, size_t offset, size_t length)
{
  cout << "Renderer.showData(file, " << offset << ", " << length << ")" << endl;
  file.seek(offset);

  if (this->m_dataDescr->size() != 1)
    throw runtime_error("Do not know how to deal with multi-type data");

  string descr = this->m_dataDescr->at(0);

  if (descr == "char")
    innerShowData<char>(file, offset, length);
  else if (descr == "uint8")
    innerShowData<uint8_t>(file, offset, length);
  else if (descr == "int8")
    innerShowData<int8_t>(file, offset, length);
  else if (descr == "uint16")
    innerShowData<uint16_t>(file, offset, length);
  else if (descr == "int16")
    innerShowData<int16_t>(file, offset, length);
  else if (descr == "uint32")
    innerShowData<uint32_t>(file, offset, length);
  else if (descr == "int32")
    innerShowData<int32_t>(file, offset, length);
  else if (descr == "uint64")
    innerShowData<uint64_t>(file, offset, length);
  else if (descr == "int64")
    innerShowData<int64_t>(file, offset, length);
  else if (descr == "float")
    innerShowData<float>(file, offset, length);
  else if (descr == "double")
    innerShowData<double>(file, offset, length);
  else
    throw runtime_error("The code should have never gotten to this place");
}

const std::string getKnownDataDescr()
{
  stringstream msg;
  AllowedTypes types;
  msg << types;
  return msg.str();
}

} // namespace render
<commit_msg>Added some possible todo items.<commit_after>#include <algorithm>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include "renderer.hpp"

using std::cout;
using std::endl;
using std::runtime_error;
using std::size_t;
using std::string;
using std::stringstream;
using std::vector;

namespace render {

static const string EOL("\n");

class AllowedTypes {
public:
  AllowedTypes() {
    this->allowed = new vector<string>();
    this->allowed->push_back("char");
    this->allowed->push_back("uint8");
    this->allowed->push_back("uint16");
    this->allowed->push_back("uint32");
    this->allowed->push_back("uint64");
    this->allowed->push_back("int8");
    this->allowed->push_back("int16");
    this->allowed->push_back("int32");
    this->allowed->push_back("int64");
    this->allowed->push_back("float32");
    this->allowed->push_back("float64");
  }

  ~AllowedTypes() {
    if (this->allowed != NULL)
      delete this->allowed;
    this->allowed = NULL;
  }

  bool has(const string & descr) const {
    vector<string>::const_iterator pos
                    = std::find(this->allowed->begin(), this->allowed->end(), descr);
    return (pos != this->allowed->end());
  }

  friend std::ostream& operator<<(std::ostream &os, const AllowedTypes & thing) {
    size_t size = thing.allowed->size();
    for (size_t i = 0; i < size; i++) {
      os << thing.allowed->at(i);
      if (i + 1 < size)
	os << ", ";
    }
    return os;
  }

private:
  vector<string> * allowed;
};

Renderer::Renderer()
{
  this->m_showLines = false;
  this->m_dataDescr = new vector<string>();
}

Renderer::~Renderer()
{
  if (this->m_dataDescr != NULL)
    delete this->m_dataDescr;
  this->m_dataDescr = NULL;
}

void Renderer::setDataDescr(const std::string & descr)
{
  AllowedTypes allowed;
  if (! allowed.has(descr)) {
    stringstream msg;
    msg << "Encountered unknown type \"" << descr << "\". Allowed types are: "
	<< allowed;
    throw runtime_error(msg.str());
  }
  this->m_dataDescr->clear();
  this->m_dataDescr->push_back(descr);
}

void Renderer::showLines(const bool showLines)
{
  this->m_showLines = showLines;
}

template <typename NumT>
void Renderer::innerShowData(BinFile &file, size_t offset, size_t length)
{
  // this calculation of offset is just wrong
  size_t myOffset = 0;
  if ((offset % sizeof(NumT)) == 0)
    myOffset = offset / sizeof(NumT);

  vector<NumT> data;
  file.read(data, length);
  if (!(data.empty())) {
    for (size_t i = 0; i < data.size(); i++) {
      if (this->m_showLines)
	cout << (myOffset + i + 1) << " "; // start counting with one
      cout << data[i] << EOL;
    }
  }
}

/// Special version for strings
template <>
void Renderer::innerShowData<char>(BinFile &file, size_t offset, size_t length)
{
  stringstream data;
  file.read(data, length);
  cout << data.str() << endl;
}

void Renderer::showData(BinFile &file, size_t offset, size_t length)
{
  cout << "Renderer.showData(file, " << offset << ", " << length << ")" << endl;
  file.seek(offset);

  if (this->m_dataDescr->size() != 1)
    throw runtime_error("Do not know how to deal with multi-type data");
  string descr = this->m_dataDescr->at(0);

  // TODO there was the ability to show integrated values
  // TODO ? there was the ability to filter out tof error events
  // TODO ? there was the ability to create statistics on events

  if (descr == "char")
    innerShowData<char>(file, offset, length);
  else if (descr == "uint8")
    innerShowData<uint8_t>(file, offset, length);
  else if (descr == "int8")
    innerShowData<int8_t>(file, offset, length);
  else if (descr == "uint16")
    innerShowData<uint16_t>(file, offset, length);
  else if (descr == "int16")
    innerShowData<int16_t>(file, offset, length);
  else if (descr == "uint32")
    innerShowData<uint32_t>(file, offset, length);
  else if (descr == "int32")
    innerShowData<int32_t>(file, offset, length);
  else if (descr == "uint64")
    innerShowData<uint64_t>(file, offset, length);
  else if (descr == "int64")
    innerShowData<int64_t>(file, offset, length);
  else if (descr == "float")
    innerShowData<float>(file, offset, length);
  else if (descr == "double")
    innerShowData<double>(file, offset, length);
  else
    throw runtime_error("The code should have never gotten to this place");
}

const std::string getKnownDataDescr()
{
  stringstream msg;
  AllowedTypes types;
  msg << types;
  return msg.str();
}

} // namespace render
<|endoftext|>


<commit_before>#include <catch.hpp>

#include <regex>
#include "test_data.hpp"
#include "libslic3r.h"
#include "GCodeReader.hpp"

using namespace Slic3r::Test;
using namespace Slic3r;

std::regex perimeters_regex("G1 X[-0-9.]* Y[-0-9.]* E[-0-9.]* ; perimeter");
std::regex infill_regex("G1 X[-0-9.]* Y[-0-9.]* E[-0-9.]* ; infill");
std::regex skirt_regex("G1 X[-0-9.]* Y[-0-9.]* E[-0-9.]* ; skirt");

SCENARIO( "PrintGCode basic functionality") {
    GIVEN("A default configuration and a print test object") {
        auto config {Slic3r::Config::new_from_defaults()};
        auto gcode {std::stringstream("")};

        WHEN("the output is executed with no support material") {
            config->set("first_layer_extrusion_width", 0);
            config->set("gcode_comments", true);
            config->set("start_gcode", "");
            Slic3r::Model model;
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
            print->process();
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("Some text output is generated.") {
                REQUIRE(exported.size() > 0);
            }
            THEN("Exported text contains slic3r version") {
                REQUIRE(exported.find(SLIC3R_VERSION) != std::string::npos);
            }
            THEN("Exported text contains git commit id") {
                REQUIRE(exported.find("; Git Commit") != std::string::npos);
                REQUIRE(exported.find(BUILD_COMMIT) != std::string::npos);
            }
            THEN("Exported text contains extrusion statistics.") {
                REQUIRE(exported.find("; external perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; top solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; support material extrusion width") == std::string::npos);
                REQUIRE(exported.find("; first layer extrusion width") == std::string::npos);
            }
            THEN("Exported text does not contain cooling markers (they were consumed)") {
                REQUIRE(exported.find(";_EXTRUDE_SET_SPEED") == std::string::npos);
            }

            THEN("GCode preamble is emitted.") {
                REQUIRE(exported.find("G21 ; set units to millimeters") != std::string::npos);
            }

            THEN("Config options emitted for print config, default region config, default object config") {
                REQUIRE(exported.find("; first_layer_temperature") != std::string::npos);
                REQUIRE(exported.find("; layer_height") != std::string::npos);
                REQUIRE(exported.find("; fill_density") != std::string::npos);
            }
            THEN("Infill is emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, infill_regex));
            }
            THEN("Perimeters are emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, perimeters_regex));
            }
            THEN("Skirt is emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, skirt_regex));
            }
            THEN("final Z height is ~20mm") {
                double final_z {0.0};
                auto reader {GCodeReader()};
                reader.apply_config(print->config);
                reader.parse(exported, [&final_z] (GCodeReader& self, const GCodeReader::GCodeLine& line)
                {
                    final_z = std::max(final_z, static_cast<double>(self.Z)); // record the highest Z point we reach
                });
                REQUIRE(final_z == Approx(20.15));
            }
        }
        WHEN("output is executed with complete objects and two differently-sized meshes") {
            Slic3r::Model model;
            config->set("first_layer_extrusion_width", 0);
            config->set("first_layer_height", 0.3);
            config->set("support_material", false);
            config->set("raft_layers", 0);
            config->set("complete_objects", true);
            config->set("gcode_comments", true);
            config->set("between_objects_gcode", "; between-object-gcode");
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20, TestMesh::ipadstand}, model, config)};
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("Some text output is generated.") {
                REQUIRE(exported.size() > 0);
            }
            THEN("Infill is emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, infill_regex));
            }
            THEN("Perimeters are emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, perimeters_regex));
            }
            THEN("Skirt is emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, skirt_regex));
            }
            THEN("Between-object-gcode is emitted.") {
                REQUIRE(exported.find("; between-object-gcode") != std::string::npos);
            }
            THEN("final Z height is ~27mm") {
                double final_z {0.0};
                auto reader {GCodeReader()};
                reader.apply_config(print->config);
                reader.parse(exported, [&final_z] (GCodeReader& self, const GCodeReader::GCodeLine& line)
                {
                    final_z = std::max(final_z, static_cast<double>(self.Z)); // record the highest Z point we reach
                });
                REQUIRE(final_z == Approx(30).margin(0.1)); // close enough
            }
            THEN("Z height resets on object change") {
                double final_z {0.0};
                bool reset {false};
                auto reader {GCodeReader()};
                reader.apply_config(print->config);
                reader.parse(exported, [&final_z, &reset] (GCodeReader& self, const GCodeReader::GCodeLine& line)
                {
                    if (final_z > 0 && std::abs(self.Z - 0.3) < 0.01 ) { // saw higher Z before this, now it's lower
                        reset = true;
                    } else {
                        final_z = std::max(final_z, static_cast<double>(self.Z)); // record the highest Z point we reach
                    }
                });
                REQUIRE(reset == true);
            }
            THEN("Shorter object is printed before taller object.") {
                double final_z {0.0};
                bool reset {false};
                auto reader {GCodeReader()};
                reader.apply_config(print->config);
                reader.parse(exported, [&final_z, &reset] (GCodeReader& self, const GCodeReader::GCodeLine& line)
                {
                    if (final_z > 0 && std::abs(self.Z - 0.3) < 0.01 ) {
                        reset = (final_z > 20.0);
                    } else {
                        final_z = std::max(final_z, static_cast<double>(self.Z)); // record the highest Z point we reach
                    }
                });
                REQUIRE(reset == true);
            }
        }
        WHEN("the output is executed with support material") {
            Slic3r::Model model;
            config->set("first_layer_extrusion_width", 0);
            config->set("support_material", true);
            config->set("raft_layers", 3);
            config->set("gcode_comments", true);
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("Some text output is generated.") {
                REQUIRE(exported.size() > 0);
            }
            THEN("Exported text contains extrusion statistics.") {
                REQUIRE(exported.find("; external perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; top solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; support material extrusion width") != std::string::npos);
                REQUIRE(exported.find("; first layer extrusion width") == std::string::npos);
            }
            THEN("Raft is emitted.") {
                REQUIRE(exported.find("; raft") != std::string::npos);
            }
        }
        WHEN("the output is executed with a separate first layer extrusion width") {
            Slic3r::Model model;
            config->set("first_layer_extrusion_width", 0.5);
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("Some text output is generated.") {
                REQUIRE(exported.size() > 0);
            }
            THEN("Exported text contains extrusion statistics.") {
                REQUIRE(exported.find("; external perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; top solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; support material extrusion width") == std::string::npos);
                REQUIRE(exported.find("; first layer extrusion width") != std::string::npos);
            }
        }
        WHEN("Cooling is enabled and the fan is disabled.") {
            config->set("cooling", true);
            config->set("disable_fan_first_layers", 5);
            Slic3r::Model model;
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("GCode to disable fan is emitted."){
                REQUIRE(exported.find("M107") != std::string::npos);
            }
        }
        WHEN("end_gcode exists with layer_num and layer_z") {
            config->set("end_gcode", "; Layer_num [layer_num]\n; Layer_z [layer_z]");
            config->set("layer_height", 0.1);
            config->set("first_layer_height", 0.1);

            Slic3r::Model model;
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
            Slic3r::Test::gcode(gcode, print);

            auto exported {gcode.str()};
            THEN("layer_num and layer_z are processed in the end gcode") {\
                REQUIRE(exported.find("; Layer_num 199") != std::string::npos);
                REQUIRE(exported.find("; Layer_z 20") != std::string::npos);
            }
        }
        WHEN("current_extruder exists in start_gcode") {
            config->set("start_gcode", "; Extruder [current_extruder]");
            Slic3r::Model model;
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("current_extruder is processed in the start gcode and set for first extruder") {
                REQUIRE(exported.find("; Extruder 0") != std::string::npos);
            }
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("current_extruder is processed in the start gcode and set for second extruder") {
                REQUIRE(exported.find("; Extruder 1") != std::string::npos);
            }
        }

        gcode.clear();
    }
}
<commit_msg>Adjust test for current_extruder being second extruder<commit_after>#include <catch.hpp>

#include <regex>
#include "test_data.hpp"
#include "libslic3r.h"
#include "GCodeReader.hpp"

using namespace Slic3r::Test;
using namespace Slic3r;

std::regex perimeters_regex("G1 X[-0-9.]* Y[-0-9.]* E[-0-9.]* ; perimeter");
std::regex infill_regex("G1 X[-0-9.]* Y[-0-9.]* E[-0-9.]* ; infill");
std::regex skirt_regex("G1 X[-0-9.]* Y[-0-9.]* E[-0-9.]* ; skirt");

SCENARIO( "PrintGCode basic functionality") {
    GIVEN("A default configuration and a print test object") {
        auto config {Slic3r::Config::new_from_defaults()};
        auto gcode {std::stringstream("")};

        WHEN("the output is executed with no support material") {
            config->set("first_layer_extrusion_width", 0);
            config->set("gcode_comments", true);
            config->set("start_gcode", "");
            Slic3r::Model model;
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
            print->process();
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("Some text output is generated.") {
                REQUIRE(exported.size() > 0);
            }
            THEN("Exported text contains slic3r version") {
                REQUIRE(exported.find(SLIC3R_VERSION) != std::string::npos);
            }
            THEN("Exported text contains git commit id") {
                REQUIRE(exported.find("; Git Commit") != std::string::npos);
                REQUIRE(exported.find(BUILD_COMMIT) != std::string::npos);
            }
            THEN("Exported text contains extrusion statistics.") {
                REQUIRE(exported.find("; external perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; top solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; support material extrusion width") == std::string::npos);
                REQUIRE(exported.find("; first layer extrusion width") == std::string::npos);
            }
            THEN("Exported text does not contain cooling markers (they were consumed)") {
                REQUIRE(exported.find(";_EXTRUDE_SET_SPEED") == std::string::npos);
            }

            THEN("GCode preamble is emitted.") {
                REQUIRE(exported.find("G21 ; set units to millimeters") != std::string::npos);
            }

            THEN("Config options emitted for print config, default region config, default object config") {
                REQUIRE(exported.find("; first_layer_temperature") != std::string::npos);
                REQUIRE(exported.find("; layer_height") != std::string::npos);
                REQUIRE(exported.find("; fill_density") != std::string::npos);
            }
            THEN("Infill is emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, infill_regex));
            }
            THEN("Perimeters are emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, perimeters_regex));
            }
            THEN("Skirt is emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, skirt_regex));
            }
            THEN("final Z height is ~20mm") {
                double final_z {0.0};
                auto reader {GCodeReader()};
                reader.apply_config(print->config);
                reader.parse(exported, [&final_z] (GCodeReader& self, const GCodeReader::GCodeLine& line)
                {
                    final_z = std::max(final_z, static_cast<double>(self.Z)); // record the highest Z point we reach
                });
                REQUIRE(final_z == Approx(20.15));
            }
        }
        WHEN("output is executed with complete objects and two differently-sized meshes") {
            Slic3r::Model model;
            config->set("first_layer_extrusion_width", 0);
            config->set("first_layer_height", 0.3);
            config->set("support_material", false);
            config->set("raft_layers", 0);
            config->set("complete_objects", true);
            config->set("gcode_comments", true);
            config->set("between_objects_gcode", "; between-object-gcode");
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20, TestMesh::ipadstand}, model, config)};
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("Some text output is generated.") {
                REQUIRE(exported.size() > 0);
            }
            THEN("Infill is emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, infill_regex));
            }
            THEN("Perimeters are emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, perimeters_regex));
            }
            THEN("Skirt is emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, skirt_regex));
            }
            THEN("Between-object-gcode is emitted.") {
                REQUIRE(exported.find("; between-object-gcode") != std::string::npos);
            }
            THEN("final Z height is ~27mm") {
                double final_z {0.0};
                auto reader {GCodeReader()};
                reader.apply_config(print->config);
                reader.parse(exported, [&final_z] (GCodeReader& self, const GCodeReader::GCodeLine& line)
                {
                    final_z = std::max(final_z, static_cast<double>(self.Z)); // record the highest Z point we reach
                });
                REQUIRE(final_z == Approx(30).margin(0.1)); // close enough
            }
            THEN("Z height resets on object change") {
                double final_z {0.0};
                bool reset {false};
                auto reader {GCodeReader()};
                reader.apply_config(print->config);
                reader.parse(exported, [&final_z, &reset] (GCodeReader& self, const GCodeReader::GCodeLine& line)
                {
                    if (final_z > 0 && std::abs(self.Z - 0.3) < 0.01 ) { // saw higher Z before this, now it's lower
                        reset = true;
                    } else {
                        final_z = std::max(final_z, static_cast<double>(self.Z)); // record the highest Z point we reach
                    }
                });
                REQUIRE(reset == true);
            }
            THEN("Shorter object is printed before taller object.") {
                double final_z {0.0};
                bool reset {false};
                auto reader {GCodeReader()};
                reader.apply_config(print->config);
                reader.parse(exported, [&final_z, &reset] (GCodeReader& self, const GCodeReader::GCodeLine& line)
                {
                    if (final_z > 0 && std::abs(self.Z - 0.3) < 0.01 ) {
                        reset = (final_z > 20.0);
                    } else {
                        final_z = std::max(final_z, static_cast<double>(self.Z)); // record the highest Z point we reach
                    }
                });
                REQUIRE(reset == true);
            }
        }
        WHEN("the output is executed with support material") {
            Slic3r::Model model;
            config->set("first_layer_extrusion_width", 0);
            config->set("support_material", true);
            config->set("raft_layers", 3);
            config->set("gcode_comments", true);
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("Some text output is generated.") {
                REQUIRE(exported.size() > 0);
            }
            THEN("Exported text contains extrusion statistics.") {
                REQUIRE(exported.find("; external perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; top solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; support material extrusion width") != std::string::npos);
                REQUIRE(exported.find("; first layer extrusion width") == std::string::npos);
            }
            THEN("Raft is emitted.") {
                REQUIRE(exported.find("; raft") != std::string::npos);
            }
        }
        WHEN("the output is executed with a separate first layer extrusion width") {
            Slic3r::Model model;
            config->set("first_layer_extrusion_width", 0.5);
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("Some text output is generated.") {
                REQUIRE(exported.size() > 0);
            }
            THEN("Exported text contains extrusion statistics.") {
                REQUIRE(exported.find("; external perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; top solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; support material extrusion width") == std::string::npos);
                REQUIRE(exported.find("; first layer extrusion width") != std::string::npos);
            }
        }
        WHEN("Cooling is enabled and the fan is disabled.") {
            config->set("cooling", true);
            config->set("disable_fan_first_layers", 5);
            Slic3r::Model model;
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("GCode to disable fan is emitted."){
                REQUIRE(exported.find("M107") != std::string::npos);
            }
        }
        WHEN("end_gcode exists with layer_num and layer_z") {
            config->set("end_gcode", "; Layer_num [layer_num]\n; Layer_z [layer_z]");
            config->set("layer_height", 0.1);
            config->set("first_layer_height", 0.1);

            Slic3r::Model model;
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
            Slic3r::Test::gcode(gcode, print);

            auto exported {gcode.str()};
            THEN("layer_num and layer_z are processed in the end gcode") {\
                REQUIRE(exported.find("; Layer_num 199") != std::string::npos);
                REQUIRE(exported.find("; Layer_z 20") != std::string::npos);
            }
        }
        WHEN("current_extruder exists in start_gcode") {
            config->set("start_gcode", "; Extruder [current_extruder]");
            {
                Slic3r::Model model;
                auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
                Slic3r::Test::gcode(gcode, print);
                auto exported {gcode.str()};
                THEN("current_extruder is processed in the start gcode and set for first extruder") {
                    REQUIRE(exported.find("; Extruder 0") != std::string::npos);
                }
            }
            config->set("solid_infill_extruder", 2);
            config->set("support_material_extruder", 2);
            config->set("infill_extruder", 2);
            config->set("perimeter_extruder", 2);
            {
                Slic3r::Model model;
                auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
                Slic3r::Test::gcode(gcode, print);
                auto exported {gcode.str()};
                THEN("current_extruder is processed in the start gcode and set for second extruder") {
                    REQUIRE(exported.find("; Extruder 1") != std::string::npos);
                }
            }
        }

        gcode.clear();
    }
}
<|endoftext|>


<commit_before><commit_msg>debug git<commit_after><|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2013.  All rights reserved
 */
#include    "Stroika/Frameworks/StroikaPreComp.h"

#include    <iostream>

#include    "Stroika/Foundation/Execution/CommandLine.h"
#include    "Stroika/Foundation/Execution/Event.h"
#include    "Stroika/Foundation/Execution/Sleep.h"
#include    "Stroika/Frameworks/Service/Main.h"

using   namespace std;

using   namespace Stroika::Foundation;
using   namespace Stroika::Frameworks::Service;

using   Containers::Sequence;

/*
 *  Almost always would want to use logger with a service. But demarcate so clear what is 'service' demo
 *  and what is logger demo.
 */
#ifndef     qUseLogger
#define     qUseLogger 1
#endif

/*
 *  Most likely would want todo this. It has nothing todo with the service framework, but often desirable
 *  in service apps.
 */
#ifndef     qRegisterFatalErrorHandlers
#define     qRegisterFatalErrorHandlers 1
#endif

#if     qUseLogger
#include    "Stroika/Foundation/Execution/Logger.h"
using   Execution::Logger;
#endif

#if     qRegisterFatalErrorHandlers
#include    "Stroika/Foundation/Debug/Fatal.h"
#if     qPlatform_Windows
#include    "Stroika/Foundation/Execution/Platform/Windows/Exception.h"
#include    "Stroika/Foundation/Execution/Platform/Windows/StructuredException.h"
#endif
#endif

#if     qRegisterFatalErrorHandlers
namespace   {
    void    _FatalErorrHandler_ (const Characters::TChar* msg)
    {
        DbgTrace (TSTR ("Fatal Error %s encountered"), msg);
#if     qUseLogger
        Logger::Get ().Log (Logger::Priority::eCriticalError, L"Fatal Error: %s; Aborting...", Characters::TString2NarrowSDK (msg).c_str ());
#endif
    }
}
#endif

namespace {
    struct   AppRep_ : Main::IApplicationRep {
        AppRep_ () {
        }
        virtual ~AppRep_ () {
        }

    public:
        virtual void  MainLoop () override {
            Execution::Sleep (1 * 24 * 60 * 60);    // wait 1 day ... simple test....
        }
        virtual Main::ServiceDescription  GetServiceDescription () const override {
            Main::ServiceDescription    t;
            t.fPrettyName = L"Test Service";
            t.fRegistrationName = L"Test-Service";
            return t;
        }
    };
}

namespace {
    void    ShowUsage_ (const Execution::InvalidCommandLineArgument& e = Execution::InvalidCommandLineArgument ())
    {
        if (not e.fMessage.empty ()) {
            cerr << e.fMessage.AsUTF8 () << endl;
            cerr << endl;
        }
        cerr << "Usage: Sample-SimpleService [options] where options can be:\n";
        cerr << "\t--" << Characters::WideStringToNarrowSDKString (Main::CommandNames::kRunAsService) << "      /* Run this process as service (doesnt exit til serice done ...) */" << endl;
        cerr << "\t--" << Characters::WideStringToNarrowSDKString (Main::CommandNames::kStart) << "             /* Service/Control Function: Start the service */" << endl;
        cerr << "\t--" << Characters::WideStringToNarrowSDKString (Main::CommandNames::kStop) << "             /* Service/Control Function: Stop the service */" << endl;
        cerr << "\t--" << Characters::WideStringToNarrowSDKString (Main::CommandNames::kForcedStop) << "           /* kForcedStop */" << endl;
        cerr << "\t--" << Characters::WideStringToNarrowSDKString (Main::CommandNames::kRestart) << "		/*kRestart */" << endl;
        cerr << "\t--" << Characters::WideStringToNarrowSDKString (Main::CommandNames::kForcedRestart) << "      /* ForcedRestart */" << endl;
        cerr << "\t--" << Characters::WideStringToNarrowSDKString (Main::CommandNames::kReloadConfiguration) << "	     /* kReloadConfiguration */" << endl;
        cerr << "\t--" << Characters::WideStringToNarrowSDKString (Main::CommandNames::kPause) << "          /* kPause */" << endl;
        cerr << "\t--" << Characters::WideStringToNarrowSDKString (Main::CommandNames::kContinue) << "           /* kContinue */" << endl;
        cerr << "\t--Status	                             /* Service/Control Function: Print status of running service */ " << endl;
        cerr << "\t--run2Idle                         /* run2Idle */ " << endl;
        cerr << "\t--help                              /* help */ " << endl;
        cerr << endl;
    }
}

int main (int argc, const char* argv[])
{
#if     qRegisterFatalErrorHandlers
#if qPlatform_Windows
    Execution::Platform::Windows::RegisterDefaultHandler_invalid_parameter ();
    Execution::Platform::Windows::StructuredException::RegisterHandler ();      // map win32 structured exceptions to our own C++ class (mainly for better
#endif
    Debug::RegisterDefaultFatalErrorHandlers (_FatalErorrHandler_);
#endif

#if     qUseLogger
#if     qHas_Syslog
    Logger::Get ().SetAppender (Logger::IAppenderRepPtr (new Main::LoggerServiceWrapper (Logger::IAppenderRepPtr (new Logger::SysLogAppender (L"Stroika-Sample-SimpleService")))));
#elif   qPlatform_Windows
    //  -- NYI as of 2013-06-08
    //Logger::Get ().SetAppender (Logger::IAppenderRepPtr (new Main::LoggerServiceWrapper (Logger::IAppenderRepPtr (new Logger::WindowsEventLogAppender (L"Stroika-Sample-SimpleService")))));
#endif
#endif

    Sequence<String>  args    =   Execution::ParseCommandLine (argc, argv);
    shared_ptr<Main::IServiceIntegrationRep>    serviceIntegrationRep   =   Main::mkDefaultServiceIntegrationRep ();
    if (Execution::MatchesCommandLineArgument (args, L"run2Idle")) {
        cerr << "Warning: RunTilIdleService not really done correctly yet - no notion of idle" << endl;
        serviceIntegrationRep = shared_ptr<Main::IServiceIntegrationRep> (new Main::RunTilIdleService ());
    }
    Main    m (shared_ptr<AppRep_> (new AppRep_ ()), serviceIntegrationRep);
    if (Execution::MatchesCommandLineArgument (args, L"status")) {
        cout << m.GetServiceStatusMessage ().AsUTF8<string> ();
        return EXIT_SUCCESS;
    }
    else if (Execution::MatchesCommandLineArgument (args, L"help")) {
        ShowUsage_ ();
        return EXIT_SUCCESS;
    }
    try {
        m.Run (args);
    }
    catch (const Execution::InvalidCommandLineArgument& e) {
        ShowUsage_ (e);
    }
    catch (const std::exception& e) {
#if     qUseLogger
        // @todo - WRONG - GENERICALLYT HANLDLE e.wwhat() codepage issue better
        // not sure what codepage to use for convert???
        Logger::Get ().Log (Logger::Priority::eError, Characters::NarrowSDKStringToWide (e.what ()));
#endif
        cerr << "FAILED: '" << e.what () << "'" << endl;
        return EXIT_FAILURE;
    }
    catch (const Execution::StringException& e) {
#if     qUseLogger
        Logger::Get ().Log (Logger::Priority::eError, e.As<wstring> ());
#endif
        cerr << "FAILED: '" << Characters::WideStringToNarrowSDKString (e.As<wstring> ()) << "'" << endl;
        return EXIT_FAILURE;
    }
    catch (...) {
#if     qUseLogger
        Logger::Get ().Log (Logger::Priority::eError, L"Unknown Exception...");
#endif
        cerr << "Exception - terminating..." << endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}
<commit_msg>fixed a couple small issues iwth /Samples/SimpleService/Sources/SimpleService<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2013.  All rights reserved
 */
#include    "Stroika/Frameworks/StroikaPreComp.h"

#include    <iostream>

#include    "Stroika/Foundation/Execution/CommandLine.h"
#include    "Stroika/Foundation/Execution/Event.h"
#include    "Stroika/Foundation/Execution/Sleep.h"
#include    "Stroika/Frameworks/Service/Main.h"

using   namespace std;

using   namespace Stroika::Foundation;
using   namespace Stroika::Frameworks::Service;

using   Containers::Sequence;

/*
 *  Almost always would want to use logger with a service. But demarcate so clear what is 'service' demo
 *  and what is logger demo.
 */
#ifndef     qUseLogger
#define     qUseLogger 1
#endif

/*
 *  Most likely would want todo this. It has nothing todo with the service framework, but often desirable
 *  in service apps.
 */
#ifndef     qRegisterFatalErrorHandlers
#define     qRegisterFatalErrorHandlers 1
#endif

#if     qUseLogger
#include    "Stroika/Foundation/Execution/Logger.h"
using   Execution::Logger;
#endif

#if     qRegisterFatalErrorHandlers
#include    "Stroika/Foundation/Debug/Fatal.h"
#if     qPlatform_Windows
#include    "Stroika/Foundation/Execution/Platform/Windows/Exception.h"
#include    "Stroika/Foundation/Execution/Platform/Windows/StructuredException.h"
#endif
#endif

#if     qRegisterFatalErrorHandlers
namespace   {
    void    _FatalErorrHandler_ (const Characters::TChar* msg)
    {
        DbgTrace (TSTR ("Fatal Error %s encountered"), msg);
#if     qUseLogger
        Logger::Get ().Log (Logger::Priority::eCriticalError, L"Fatal Error: %s; Aborting...", Characters::TString2NarrowSDK (msg).c_str ());
#endif
    }
}
#endif

namespace {
    struct   AppRep_ : Main::IApplicationRep {
        AppRep_ () {
        }
        virtual ~AppRep_ () {
        }

    public:
        virtual void  MainLoop () override {
            Execution::Sleep (1 * 24 * 60 * 60);    // wait 1 day ... simple test....
        }
        virtual Main::ServiceDescription  GetServiceDescription () const override {
            Main::ServiceDescription    t;
            t.fPrettyName = L"Test Service";
            t.fRegistrationName = L"Test-Service";
            return t;
        }
    };
}

namespace {
    void    ShowUsage_ (const Execution::InvalidCommandLineArgument& e = Execution::InvalidCommandLineArgument ())
    {
        if (not e.fMessage.empty ()) {
            cerr << e.fMessage.AsUTF8 () << endl;
            cerr << endl;
        }
        cerr << "Usage: Sample-SimpleService [options] where options can be:\n";
        cerr << "\t--" << Characters::WideStringToNarrowSDKString (Main::CommandNames::kRunAsService) << "      /* Run this process as service (doesnt exit til serice done ...) */" << endl;
        cerr << "\t--" << Characters::WideStringToNarrowSDKString (Main::CommandNames::kStart) << "             /* Service/Control Function: Start the service */" << endl;
        cerr << "\t--" << Characters::WideStringToNarrowSDKString (Main::CommandNames::kStop) << "             /* Service/Control Function: Stop the service */" << endl;
        cerr << "\t--" << Characters::WideStringToNarrowSDKString (Main::CommandNames::kForcedStop) << "           /* kForcedStop */" << endl;
        cerr << "\t--" << Characters::WideStringToNarrowSDKString (Main::CommandNames::kRestart) << "		/*kRestart */" << endl;
        cerr << "\t--" << Characters::WideStringToNarrowSDKString (Main::CommandNames::kForcedRestart) << "      /* ForcedRestart */" << endl;
        cerr << "\t--" << Characters::WideStringToNarrowSDKString (Main::CommandNames::kReloadConfiguration) << "	     /* kReloadConfiguration */" << endl;
        cerr << "\t--" << Characters::WideStringToNarrowSDKString (Main::CommandNames::kPause) << "          /* kPause */" << endl;
        cerr << "\t--" << Characters::WideStringToNarrowSDKString (Main::CommandNames::kContinue) << "           /* kContinue */" << endl;
        cerr << "\t--Status	                             /* Service/Control Function: Print status of running service */ " << endl;
        cerr << "\t--run2Idle                         /* run2Idle */ " << endl;
        cerr << "\t--help                              /* help */ " << endl;
        cerr << endl;
    }
}

int main (int argc, const char* argv[])
{
#if     qRegisterFatalErrorHandlers
#if qPlatform_Windows
    Execution::Platform::Windows::RegisterDefaultHandler_invalid_parameter ();
    Execution::Platform::Windows::StructuredException::RegisterHandler ();
#endif
    Debug::RegisterDefaultFatalErrorHandlers (_FatalErorrHandler_);
#endif

#if     qUseLogger
#if     qHas_Syslog
    Logger::Get ().SetAppender (Logger::IAppenderRepPtr (new Logger::SysLogAppender (L"Stroika-Sample-SimpleService")));
#elif   qPlatform_Windows
    //  -- NYI as of 2013-06-08
    //Logger::Get ().SetAppender (Logger::IAppenderRepPtr (new Main::LoggerServiceWrapper (Logger::IAppenderRepPtr (new Logger::WindowsEventLogAppender (L"Stroika-Sample-SimpleService")))));
#endif
#endif

    Sequence<String>  args    =   Execution::ParseCommandLine (argc, argv);
    shared_ptr<Main::IServiceIntegrationRep>    serviceIntegrationRep   =   Main::mkDefaultServiceIntegrationRep ();
    if (Execution::MatchesCommandLineArgument (args, L"run2Idle")) {
        cerr << "Warning: RunTilIdleService not really done correctly yet - no notion of idle" << endl;
        serviceIntegrationRep = shared_ptr<Main::IServiceIntegrationRep> (new Main::RunTilIdleService ());
    }
#if     qUseLogger
    serviceIntegrationRep = shared_ptr<Main::IServiceIntegrationRep> (new Main::LoggerServiceWrapper (serviceIntegrationRep));
#endif
    Main    m (shared_ptr<AppRep_> (new AppRep_ ()), serviceIntegrationRep);
    if (Execution::MatchesCommandLineArgument (args, L"status")) {
        cout << m.GetServiceStatusMessage ().AsUTF8<string> ();
        return EXIT_SUCCESS;
    }
    else if (Execution::MatchesCommandLineArgument (args, L"help")) {
        ShowUsage_ ();
        return EXIT_SUCCESS;
    }
    try {
        m.Run (args);
    }
    catch (const Execution::InvalidCommandLineArgument& e) {
        ShowUsage_ (e);
    }
    catch (const std::exception& e) {
#if     qUseLogger
        // @todo - WRONG - GENERICALLYT HANLDLE e.wwhat() codepage issue better
        // not sure what codepage to use for convert???
        Logger::Get ().Log (Logger::Priority::eError, Characters::NarrowSDKStringToWide (e.what ()));
#endif
        cerr << "FAILED: '" << e.what () << "'" << endl;
        return EXIT_FAILURE;
    }
    catch (const Execution::StringException& e) {
#if     qUseLogger
        Logger::Get ().Log (Logger::Priority::eError, e.As<wstring> ());
#endif
        cerr << "FAILED: '" << Characters::WideStringToNarrowSDKString (e.As<wstring> ()) << "'" << endl;
        return EXIT_FAILURE;
    }
    catch (...) {
#if     qUseLogger
        Logger::Get ().Log (Logger::Priority::eError, L"Unknown Exception...");
#endif
        cerr << "Exception - terminating..." << endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}
<|endoftext|>