<commit_before>// Copyright 2015 Alessio Sclocco <a.sclocco@vu.nl>
//
// 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 <iostream>
#include <string>
#include <vector>
#include <exception>

#include <configuration.hpp>

#include <ArgumentList.hpp>
#include <Observation.hpp>
#include <InitializeOpenCL.hpp>
#include <Kernel.hpp>
#include <utils.hpp>
#include <Integration.hpp>
#include <Timer.hpp>
#include <Stats.hpp>

void initializeDeviceMemory(cl::Context & clContext, cl::CommandQueue * clQueue, cl::Buffer * input_d, const unsigned int input_size, cl::Buffer * output_d, const unsigned int output_size);

int main(int argc, char * argv[]) {
  bool reInit = false;
  unsigned int padding = 0;
  unsigned int integration = 0;
	unsigned int nrIterations = 0;
	unsigned int clPlatformID = 0;
	unsigned int clDeviceID = 0;
	unsigned int minThreads = 0;
  unsigned int maxThreads = 0;
  unsigned int maxItems = 0;
  unsigned int vectorWidth = 0;
  AstroData::Observation observation;
  PulsarSearch::integrationSamplesDMsConf conf;
  cl::Event event;

	try {
    isa::utils::ArgumentList args(argc, argv);

		nrIterations = args.getSwitchArgument< unsigned int >("-iterations");
		clPlatformID = args.getSwitchArgument< unsigned int >("-opencl_platform");
		clDeviceID = args.getSwitchArgument< unsigned int >("-opencl_device");
		padding = args.getSwitchArgument< unsigned int >("-padding");
		integration = args.getSwitchArgument< unsigned int >("-integration");
		minThreads = args.getSwitchArgument< unsigned int >("-min_threads");
		maxThreads = args.getSwitchArgument< unsigned int >("-max_threads");
		maxItems = args.getSwitchArgument< unsigned int >("-max_items");
    vectorWidth = args.getSwitchArgument< unsigned int >("-vector");
		observation.setNrSamplesPerSecond(args.getSwitchArgument< unsigned int >("-samples"));
    observation.setDMRange(args.getSwitchArgument< unsigned int >("-dms"), 0.0f, 0.0f);
	} catch ( isa::utils::EmptyCommandLine & err ) {
		std::cerr << argv[0] << " -iterations ... -opencl_platform ... -opencl_device ... -padding ... -integration ... -min_threads ... -max_threads ... -max_items ... -vector ... -samples ... -dms ... " << std::endl;
		return 1;
	} catch ( std::exception & err ) {
		std::cerr << err.what() << std::endl;
		return 1;
	}

  // Allocate host memory
  std::vector< dataType > input(observation.getNrDMs() * observation.getNrSamplesPerPaddedSecond(padding / sizeof(dataType)));
  std::vector< dataType > output(observation.getNrDMs() * isa::utils::pad(observation.getNrSamplesPerSecond() / integration, padding / sizeof(dataType)));

	// Initialize OpenCL
	cl::Context clContext;
	std::vector< cl::Platform > * clPlatforms = new std::vector< cl::Platform >();
	std::vector< cl::Device > * clDevices = new std::vector< cl::Device >();
	std::vector< std::vector< cl::CommandQueue > > * clQueues = new std::vector< std::vector < cl::CommandQueue > >();
  isa::OpenCL::initializeOpenCL(clPlatformID, 1, clPlatforms, &clContext, clDevices, clQueues);

	// Allocate device memory
  cl::Buffer input_d;
  cl::Buffer output_d;

  try {
    initializeDeviceMemory(clContext, &(clQueues->at(clDeviceID)[0]), input_d, input.size(), output_d, output.size());
  } catch ( cl::Error & err ) {
    std::cerr << err.what() << std::endl;
    return -1;
  }

	std::cout << std::fixed << std::endl;
	std::cout << "# nrDMs nrSamples integration samplesPerBlock samplesPerThread GFLOP/s GB/s time stdDeviation COV" << std::endl << std::endl;

	for ( unsigned int samples = minThreads; samples <= maxThreads; samples++) {
    conf.setNrSamplesPerBlock(samples);
    if ( conf.getNrSamplesPerBlock() % vectorWidth != 0 ) {
      continue;
    }

    for ( unsigned int samplesPerThread = 1; samplesPerThread <= maxItems; samplesPerThread++ ) {
      conf.setNrSamplesPerThread(samplesPerThread);
      if ( (observation.getNrSamplesPerSecond() % (integration * conf.getNrSamplesPerThread())) != 0 ) {
        continue;
      }

      // Generate kernel
      double gflops = isa::utils::giga(static_cast< uint64_t >(observation.getNrDMs()) * observation.getNrSamplesPerSecond());
      double gbs = isa::utils::giga((static_cast< uint64_t >(observation.getNrDMs()) * observation.getNrSamplesPerSecond()) + (static_cast< uint64_t >(observation.getNrDMs()) * (observation.getNrSamplesPerSecond() / integration)));
      isa::utils::Timer timer;
      cl::Kernel * kernel;

      std::string * code = PulsarSearch::getIntegrationSamplesDMsOpenCL< dataType >(conf, observation, dataName, integration, padding);
      if ( reInit ) {
        delete clQueues;
        clQueues = new std::vector< std::vector < cl::CommandQueue > >();
        isa::OpenCL::initializeOpenCL(clPlatformID, 1, clPlatforms, &clContext, clDevices, clQueues);
        try {
          initializeDeviceMemory(clContext, &(clQueues->at(clDeviceID)[0]), input_d, input.size(), output_d, output.size());
        } catch ( cl::Error & err ) {
          std::cerr << "Error in memory allocation: ";
          std::cerr << isa::utils::toString(err.err()) << "." << std::endl;
          return -1;
        }
        reInit = false;
      }
      try {
        kernel = isa::OpenCL::compile("integrationSamplesDMs" + isa::utils::toString(integration), *code, "-cl-mad-enable -Wall", *clContext, clDevices->at(clDeviceID));
      } catch ( isa::OpenCL::OpenCLError & err ) {
        std::cerr << err.what() << std::endl;
        delete code;
        break;
      }
      delete code;

      cl::NDRange global((observation.getNrSamplesPerSecond() / integration) / conf.getNrSamplesPerThread(), observation.getNrDMs());
      cl::NDRange local(conf.getNrSamplesPerBlock(), 1);
      kernel->setArg(0, input_d);
      kernel->setArg(1, output_d);
      try {
        // Warm-up run
        clQueues->at(clDeviceID)[0].finish();
        clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &event);
        event.wait();
        // Tuning runs
        for ( unsigned int iteration = 0; iteration < nrIterations; iteration++ ) {
          timer.start();
          clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &event);
          event.wait();
          timer.stop();
        }
      } catch ( cl::Error & err ) {
        std::cerr << "OpenCL error kernel execution (";
        std::cerr << conf.print() << "): ";
        std::cerr << isa::utils::toString(err.err()) << "." << std::endl;
        delete kernel;
        if ( err.err() == -4 || err.err() == -61 ) {
          return -1;
        }
        reInit = true;
        break;
      }
      delete kernel;

      std::cout << observation.getNrDMs() << " " << observation.getNrSamplesPerSecond() << " " << integration << " ";
      std::cout << conf.print() << " ";
      std::cout << std::setprecision(3);
      std::cout << gflops / timer.getAverageTime() << " ";
      std::cout << gbs / timer.getAverageTime() << " ";
      std::cout << std::setprecision(6);
      std::cout << timer.getAverageTime() << " " << timer.getStandardDeviation() << " ";
      std::cout << timer.getCoefficientOfVariation() <<  std::endl;
    }
  }

	std::cout << std::endl;

	return 0;
}

void initializeDeviceMemory(cl::Context & clContext, cl::CommandQueue * clQueue, cl::Buffer * input_d, const unsigned int input_size, cl::Buffer * output_d, const unsigned int output_size) {
  try {
    *input_d = cl::Buffer(clContext, CL_MEM_READ_WRITE, input_size * sizeof(dataType), 0, 0);
    *output_d = cl::Buffer(clContext, CL_MEM_READ_WRITE, output_size * sizeof(dataType), 0, 0);
    clQueue->finish();
  } catch ( cl::Error & err ) {
    std::cerr << "OpenCL error: " << isa::utils::toString(err.err()) << "." << std::endl;
    throw;
  }
}

<commit_msg>Missing header.<commit_after>// Copyright 2015 Alessio Sclocco <a.sclocco@vu.nl>
//
// 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 <iostream>
#include <string>
#include <vector>
#include <exception>
#include <iomanip>

#include <configuration.hpp>

#include <ArgumentList.hpp>
#include <Observation.hpp>
#include <InitializeOpenCL.hpp>
#include <Kernel.hpp>
#include <utils.hpp>
#include <Integration.hpp>
#include <Timer.hpp>
#include <Stats.hpp>

void initializeDeviceMemory(cl::Context & clContext, cl::CommandQueue * clQueue, cl::Buffer * input_d, const unsigned int input_size, cl::Buffer * output_d, const unsigned int output_size);

int main(int argc, char * argv[]) {
  bool reInit = false;
  unsigned int padding = 0;
  unsigned int integration = 0;
	unsigned int nrIterations = 0;
	unsigned int clPlatformID = 0;
	unsigned int clDeviceID = 0;
	unsigned int minThreads = 0;
  unsigned int maxThreads = 0;
  unsigned int maxItems = 0;
  unsigned int vectorWidth = 0;
  AstroData::Observation observation;
  PulsarSearch::integrationSamplesDMsConf conf;
  cl::Event event;

	try {
    isa::utils::ArgumentList args(argc, argv);

		nrIterations = args.getSwitchArgument< unsigned int >("-iterations");
		clPlatformID = args.getSwitchArgument< unsigned int >("-opencl_platform");
		clDeviceID = args.getSwitchArgument< unsigned int >("-opencl_device");
		padding = args.getSwitchArgument< unsigned int >("-padding");
		integration = args.getSwitchArgument< unsigned int >("-integration");
		minThreads = args.getSwitchArgument< unsigned int >("-min_threads");
		maxThreads = args.getSwitchArgument< unsigned int >("-max_threads");
		maxItems = args.getSwitchArgument< unsigned int >("-max_items");
    vectorWidth = args.getSwitchArgument< unsigned int >("-vector");
		observation.setNrSamplesPerSecond(args.getSwitchArgument< unsigned int >("-samples"));
    observation.setDMRange(args.getSwitchArgument< unsigned int >("-dms"), 0.0f, 0.0f);
	} catch ( isa::utils::EmptyCommandLine & err ) {
		std::cerr << argv[0] << " -iterations ... -opencl_platform ... -opencl_device ... -padding ... -integration ... -min_threads ... -max_threads ... -max_items ... -vector ... -samples ... -dms ... " << std::endl;
		return 1;
	} catch ( std::exception & err ) {
		std::cerr << err.what() << std::endl;
		return 1;
	}

  // Allocate host memory
  std::vector< dataType > input(observation.getNrDMs() * observation.getNrSamplesPerPaddedSecond(padding / sizeof(dataType)));
  std::vector< dataType > output(observation.getNrDMs() * isa::utils::pad(observation.getNrSamplesPerSecond() / integration, padding / sizeof(dataType)));

	// Initialize OpenCL
	cl::Context clContext;
	std::vector< cl::Platform > * clPlatforms = new std::vector< cl::Platform >();
	std::vector< cl::Device > * clDevices = new std::vector< cl::Device >();
	std::vector< std::vector< cl::CommandQueue > > * clQueues = new std::vector< std::vector < cl::CommandQueue > >();
  isa::OpenCL::initializeOpenCL(clPlatformID, 1, clPlatforms, &clContext, clDevices, clQueues);

	// Allocate device memory
  cl::Buffer input_d;
  cl::Buffer output_d;

  try {
    initializeDeviceMemory(clContext, &(clQueues->at(clDeviceID)[0]), input_d, input.size(), output_d, output.size());
  } catch ( cl::Error & err ) {
    std::cerr << err.what() << std::endl;
    return -1;
  }

	std::cout << std::fixed << std::endl;
	std::cout << "# nrDMs nrSamples integration samplesPerBlock samplesPerThread GFLOP/s GB/s time stdDeviation COV" << std::endl << std::endl;

	for ( unsigned int samples = minThreads; samples <= maxThreads; samples++) {
    conf.setNrSamplesPerBlock(samples);
    if ( conf.getNrSamplesPerBlock() % vectorWidth != 0 ) {
      continue;
    }

    for ( unsigned int samplesPerThread = 1; samplesPerThread <= maxItems; samplesPerThread++ ) {
      conf.setNrSamplesPerThread(samplesPerThread);
      if ( (observation.getNrSamplesPerSecond() % (integration * conf.getNrSamplesPerThread())) != 0 ) {
        continue;
      }

      // Generate kernel
      double gflops = isa::utils::giga(static_cast< uint64_t >(observation.getNrDMs()) * observation.getNrSamplesPerSecond());
      double gbs = isa::utils::giga((static_cast< uint64_t >(observation.getNrDMs()) * observation.getNrSamplesPerSecond()) + (static_cast< uint64_t >(observation.getNrDMs()) * (observation.getNrSamplesPerSecond() / integration)));
      isa::utils::Timer timer;
      cl::Kernel * kernel;

      std::string * code = PulsarSearch::getIntegrationSamplesDMsOpenCL< dataType >(conf, observation, dataName, integration, padding);
      if ( reInit ) {
        delete clQueues;
        clQueues = new std::vector< std::vector < cl::CommandQueue > >();
        isa::OpenCL::initializeOpenCL(clPlatformID, 1, clPlatforms, &clContext, clDevices, clQueues);
        try {
          initializeDeviceMemory(clContext, &(clQueues->at(clDeviceID)[0]), input_d, input.size(), output_d, output.size());
        } catch ( cl::Error & err ) {
          std::cerr << "Error in memory allocation: ";
          std::cerr << isa::utils::toString(err.err()) << "." << std::endl;
          return -1;
        }
        reInit = false;
      }
      try {
        kernel = isa::OpenCL::compile("integrationSamplesDMs" + isa::utils::toString(integration), *code, "-cl-mad-enable -Wall", *clContext, clDevices->at(clDeviceID));
      } catch ( isa::OpenCL::OpenCLError & err ) {
        std::cerr << err.what() << std::endl;
        delete code;
        break;
      }
      delete code;

      cl::NDRange global((observation.getNrSamplesPerSecond() / integration) / conf.getNrSamplesPerThread(), observation.getNrDMs());
      cl::NDRange local(conf.getNrSamplesPerBlock(), 1);
      kernel->setArg(0, input_d);
      kernel->setArg(1, output_d);
      try {
        // Warm-up run
        clQueues->at(clDeviceID)[0].finish();
        clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &event);
        event.wait();
        // Tuning runs
        for ( unsigned int iteration = 0; iteration < nrIterations; iteration++ ) {
          timer.start();
          clQueues->at(clDeviceID)[0].enqueueNDRangeKernel(*kernel, cl::NullRange, global, local, 0, &event);
          event.wait();
          timer.stop();
        }
      } catch ( cl::Error & err ) {
        std::cerr << "OpenCL error kernel execution (";
        std::cerr << conf.print() << "): ";
        std::cerr << isa::utils::toString(err.err()) << "." << std::endl;
        delete kernel;
        if ( err.err() == -4 || err.err() == -61 ) {
          return -1;
        }
        reInit = true;
        break;
      }
      delete kernel;

      std::cout << observation.getNrDMs() << " " << observation.getNrSamplesPerSecond() << " " << integration << " ";
      std::cout << conf.print() << " ";
      std::cout << std::setprecision(3);
      std::cout << gflops / timer.getAverageTime() << " ";
      std::cout << gbs / timer.getAverageTime() << " ";
      std::cout << std::setprecision(6);
      std::cout << timer.getAverageTime() << " " << timer.getStandardDeviation() << " ";
      std::cout << timer.getCoefficientOfVariation() <<  std::endl;
    }
  }

	std::cout << std::endl;

	return 0;
}

void initializeDeviceMemory(cl::Context & clContext, cl::CommandQueue * clQueue, cl::Buffer * input_d, const unsigned int input_size, cl::Buffer * output_d, const unsigned int output_size) {
  try {
    *input_d = cl::Buffer(clContext, CL_MEM_READ_WRITE, input_size * sizeof(dataType), 0, 0);
    *output_d = cl::Buffer(clContext, CL_MEM_READ_WRITE, output_size * sizeof(dataType), 0, 0);
    clQueue->finish();
  } catch ( cl::Error & err ) {
    std::cerr << "OpenCL error: " << isa::utils::toString(err.err()) << "." << std::endl;
    throw;
  }
}

<|endoftext|>


<commit_before>/**
*  Copyright (C) 2015 3D Repo Ltd
*
*  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 <cstdlib>
#include <gtest/gtest.h>
#include <repo/repo_controller.h>
#include <repo/error_codes.h>
#include "../repo_test_database_info.h"
#include "../repo_test_fileservice_info.h"
#include "../repo_test_utils.h"

using namespace repo;

static std::shared_ptr<RepoController> getController()
{
	static std::shared_ptr<RepoController> controller =
		std::make_shared<RepoController>();

	return controller;
}

TEST(RepoControllerTest, CommitScene){
	auto controller = getController();
	auto token = initController(controller.get());
	//Try to commit a scene without setting db/project name
	uint8_t errCode;
	auto scene = controller->loadSceneFromFile(getDataPath(simpleModel), errCode);
	EXPECT_EQ(0, errCode);
	EXPECT_FALSE(controller->commitScene(token, scene));
	EXPECT_FALSE(scene->isRevisioned());

	//Trying to commit a scene with empty db and project name should also fail
	scene->setDatabaseAndProjectName("", "");
	EXPECT_FALSE(controller->commitScene(token, scene));
	EXPECT_FALSE(scene->isRevisioned());

	scene->setDatabaseAndProjectName("balh", "");
	EXPECT_FALSE(controller->commitScene(token, scene));
	EXPECT_FALSE(scene->isRevisioned());

	scene->setDatabaseAndProjectName("", "blah");
	EXPECT_FALSE(controller->commitScene(token, scene));
	EXPECT_FALSE(scene->isRevisioned());

	//Setting the db name and project name should allow commit successfully
	scene->setDatabaseAndProjectName("commitSceneTest", "commitCube");
	EXPECT_TRUE(controller->commitScene(token, scene));
	EXPECT_TRUE(scene->isRevisioned());
	EXPECT_TRUE(projectExists("commitSceneTest", "commitCube"));
	EXPECT_EQ(scene->getOwner(), REPO_GTEST_DBUSER);

	auto scene2 = controller->loadSceneFromFile(getDataPath(simpleModel), errCode);
	std::string owner = "dog";
	EXPECT_EQ(errCode, 0);
	scene2->setDatabaseAndProjectName("commitSceneTest", "commitCube2");
	EXPECT_TRUE(controller->commitScene(token, scene2, owner));
	EXPECT_TRUE(scene2->isRevisioned());
	EXPECT_TRUE(projectExists("commitSceneTest", "commitCube2"));
	EXPECT_EQ(scene2->getOwner(), owner);

	//null pointer checks
	EXPECT_FALSE(controller->commitScene(token, nullptr));
	EXPECT_FALSE(controller->commitScene(nullptr, scene));
}

TEST(RepoControllerTest, LoadSceneFromFile){
	auto controller = getController();
	auto defaultG = core::model::RepoScene::GraphType::DEFAULT;
	auto optG = core::model::RepoScene::GraphType::OPTIMIZED;

	//standard import
	uint8_t errCode;
	auto scene = controller->loadSceneFromFile(getDataPath(simpleModel), errCode);
	ASSERT_TRUE(scene);
	EXPECT_EQ(errCode, 0);
	ASSERT_TRUE(scene->getRoot(defaultG));
	ASSERT_TRUE(scene->getRoot(optG));
	EXPECT_FALSE(scene->isMissingTexture());
	EXPECT_FALSE(scene->isRevisioned());
	EXPECT_TRUE(dynamic_cast<core::model::TransformationNode*>(scene->getRoot(defaultG))->isIdentity());

	//Import the scene with no transformation reduction
	auto sceneNoReduction = controller->loadSceneFromFile(getDataPath(simpleModel), errCode, false);
	EXPECT_EQ(errCode, 0);
	EXPECT_TRUE(sceneNoReduction);
	EXPECT_TRUE(sceneNoReduction->getRoot(defaultG));
	EXPECT_TRUE(sceneNoReduction->getRoot(optG));
	EXPECT_FALSE(sceneNoReduction->isMissingTexture());
	//There should be more transformations in the non-reduced scene than the standard scene
	EXPECT_TRUE(sceneNoReduction->getAllTransformations(defaultG).size()
			> scene->getAllTransformations(defaultG).size());

	//Import the scene with root trans rotated
	auto sceneRotated = controller->loadSceneFromFile(getDataPath(simpleModel), errCode, true, true);
	EXPECT_EQ(errCode, 0);
	EXPECT_TRUE(sceneRotated);
	ASSERT_TRUE(sceneRotated->getRoot(defaultG));
	EXPECT_TRUE(sceneRotated->getRoot(optG));
	EXPECT_FALSE(sceneRotated->isMissingTexture());
	//The root transformation should not be an identity
	core::model::TransformationNode *rootTrans = dynamic_cast<core::model::TransformationNode*>(sceneRotated->getRoot(defaultG));
	EXPECT_FALSE(rootTrans->isIdentity());

	//Import the scene with non existant file
	auto sceneNoFile = controller->loadSceneFromFile("thisFileDoesntExist.obj", errCode);
	EXPECT_EQ(errCode, REPOERR_MODEL_FILE_READ);
	EXPECT_FALSE(sceneNoFile);

	//Import the scene with bad Extension
	auto sceneBadExt = controller->loadSceneFromFile(getDataPath(badExtensionFile), errCode);
	EXPECT_EQ(errCode, REPOERR_FILE_TYPE_NOT_SUPPORTED);
	EXPECT_FALSE(sceneBadExt);

	//Import the scene with texture but not found
	auto sceneNoTex = controller->loadSceneFromFile(getDataPath(texturedModel), errCode);
	EXPECT_EQ(errCode, 0);
	EXPECT_TRUE(sceneNoTex);
	EXPECT_TRUE(sceneNoTex->getRoot(defaultG));
	EXPECT_TRUE(sceneNoTex->getRoot(optG));
	EXPECT_TRUE(sceneNoTex->isMissingTexture());

	//Import the scene with texture but not found
	auto sceneTex = controller->loadSceneFromFile(getDataPath(texturedModel2), errCode);
	EXPECT_EQ(errCode, 0);
	EXPECT_TRUE(sceneTex);
	EXPECT_TRUE(sceneTex->getRoot(defaultG));
	EXPECT_TRUE(sceneTex->getRoot(optG));
	EXPECT_FALSE(sceneTex->isMissingTexture());

	//FIXME: need to test with change of config, but this is probably not trival.
}
<commit_msg>revert back to calling the method again.<commit_after>/**
*  Copyright (C) 2015 3D Repo Ltd
*
*  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 <cstdlib>
#include <gtest/gtest.h>
#include <repo/repo_controller.h>
#include <repo/error_codes.h>
#include "../repo_test_database_info.h"
#include "../repo_test_fileservice_info.h"
#include "../repo_test_utils.h"

using namespace repo;

static std::shared_ptr<RepoController> getController()
{
	static std::shared_ptr<RepoController> controller =
		std::make_shared<RepoController>();

	return controller;
}

TEST(RepoControllerTest, CommitScene){
	auto controller = getController();
	auto token = initController(controller.get());
	//Try to commit a scene without setting db/project name
	uint8_t errCode;
	auto scene = controller->loadSceneFromFile(getDataPath(simpleModel), errCode);
	EXPECT_EQ(0, errCode);
	EXPECT_FALSE(controller->commitScene(token, scene));
	EXPECT_FALSE(scene->isRevisioned());

	//Trying to commit a scene with empty db and project name should also fail
	scene->setDatabaseAndProjectName("", "");
	EXPECT_FALSE(controller->commitScene(token, scene));
	EXPECT_FALSE(scene->isRevisioned());

	scene->setDatabaseAndProjectName("balh", "");
	EXPECT_FALSE(controller->commitScene(token, scene));
	EXPECT_FALSE(scene->isRevisioned());

	scene->setDatabaseAndProjectName("", "blah");
	EXPECT_FALSE(controller->commitScene(token, scene));
	EXPECT_FALSE(scene->isRevisioned());

	//Setting the db name and project name should allow commit successfully
	scene->setDatabaseAndProjectName("commitSceneTest", "commitCube");
	EXPECT_TRUE(controller->commitScene(initController(controller.get()), scene));
	EXPECT_TRUE(scene->isRevisioned());
	EXPECT_TRUE(projectExists("commitSceneTest", "commitCube"));
	EXPECT_EQ(scene->getOwner(), REPO_GTEST_DBUSER);

	auto scene2 = controller->loadSceneFromFile(getDataPath(simpleModel), errCode);
	std::string owner = "dog";
	EXPECT_EQ(errCode, 0);
	scene2->setDatabaseAndProjectName("commitSceneTest", "commitCube2");
	EXPECT_TRUE(controller->commitScene(initController(controller.get()), scene2, owner));
	EXPECT_TRUE(scene2->isRevisioned());
	EXPECT_TRUE(projectExists("commitSceneTest", "commitCube2"));
	EXPECT_EQ(scene2->getOwner(), owner);

	//null pointer checks
	EXPECT_FALSE(controller->commitScene(token, nullptr));
	EXPECT_FALSE(controller->commitScene(nullptr, scene));
}

TEST(RepoControllerTest, LoadSceneFromFile){
	auto controller = getController();
	auto defaultG = core::model::RepoScene::GraphType::DEFAULT;
	auto optG = core::model::RepoScene::GraphType::OPTIMIZED;

	//standard import
	uint8_t errCode;
	auto scene = controller->loadSceneFromFile(getDataPath(simpleModel), errCode);
	ASSERT_TRUE(scene);
	EXPECT_EQ(errCode, 0);
	ASSERT_TRUE(scene->getRoot(defaultG));
	ASSERT_TRUE(scene->getRoot(optG));
	EXPECT_FALSE(scene->isMissingTexture());
	EXPECT_FALSE(scene->isRevisioned());
	EXPECT_TRUE(dynamic_cast<core::model::TransformationNode*>(scene->getRoot(defaultG))->isIdentity());

	//Import the scene with no transformation reduction
	auto sceneNoReduction = controller->loadSceneFromFile(getDataPath(simpleModel), errCode, false);
	EXPECT_EQ(errCode, 0);
	EXPECT_TRUE(sceneNoReduction);
	EXPECT_TRUE(sceneNoReduction->getRoot(defaultG));
	EXPECT_TRUE(sceneNoReduction->getRoot(optG));
	EXPECT_FALSE(sceneNoReduction->isMissingTexture());
	//There should be more transformations in the non-reduced scene than the standard scene
	EXPECT_TRUE(sceneNoReduction->getAllTransformations(defaultG).size()
			> scene->getAllTransformations(defaultG).size());

	//Import the scene with root trans rotated
	auto sceneRotated = controller->loadSceneFromFile(getDataPath(simpleModel), errCode, true, true);
	EXPECT_EQ(errCode, 0);
	EXPECT_TRUE(sceneRotated);
	ASSERT_TRUE(sceneRotated->getRoot(defaultG));
	EXPECT_TRUE(sceneRotated->getRoot(optG));
	EXPECT_FALSE(sceneRotated->isMissingTexture());
	//The root transformation should not be an identity
	core::model::TransformationNode *rootTrans = dynamic_cast<core::model::TransformationNode*>(sceneRotated->getRoot(defaultG));
	EXPECT_FALSE(rootTrans->isIdentity());

	//Import the scene with non existant file
	auto sceneNoFile = controller->loadSceneFromFile("thisFileDoesntExist.obj", errCode);
	EXPECT_EQ(errCode, REPOERR_MODEL_FILE_READ);
	EXPECT_FALSE(sceneNoFile);

	//Import the scene with bad Extension
	auto sceneBadExt = controller->loadSceneFromFile(getDataPath(badExtensionFile), errCode);
	EXPECT_EQ(errCode, REPOERR_FILE_TYPE_NOT_SUPPORTED);
	EXPECT_FALSE(sceneBadExt);

	//Import the scene with texture but not found
	auto sceneNoTex = controller->loadSceneFromFile(getDataPath(texturedModel), errCode);
	EXPECT_EQ(errCode, 0);
	EXPECT_TRUE(sceneNoTex);
	EXPECT_TRUE(sceneNoTex->getRoot(defaultG));
	EXPECT_TRUE(sceneNoTex->getRoot(optG));
	EXPECT_TRUE(sceneNoTex->isMissingTexture());

	//Import the scene with texture but not found
	auto sceneTex = controller->loadSceneFromFile(getDataPath(texturedModel2), errCode);
	EXPECT_EQ(errCode, 0);
	EXPECT_TRUE(sceneTex);
	EXPECT_TRUE(sceneTex->getRoot(defaultG));
	EXPECT_TRUE(sceneTex->getRoot(optG));
	EXPECT_FALSE(sceneTex->isMissingTexture());

	//FIXME: need to test with change of config, but this is probably not trival.
}
<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2012.  All rights reserved
 */
#ifndef _Stroika_Foundation_Characters_String_inl_
#define _Stroika_Foundation_Characters_String_inl_

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include    "../Debug/Assertions.h"

namespace   Stroika {
    namespace   Foundation {
        namespace   Characters {

            template    <>
            inline  size_t  C_String::Length (const char* p)
            {
                RequireNotNull (p);
                return ::strlen (p);
            }
            template    <>
            inline  size_t  C_String::Length (const wchar_t* p)
            {
                RequireNotNull (p);
                return ::wcslen (p);
            }

            //  class   String::_Rep
            inline  String::_Rep::_Rep ()
            {
            }
            inline  String::_Rep::~_Rep ()
            {
            }
            inline  void    String::_Rep::CopyTo (Character* bufFrom, Character* bufTo) const
            {
                RequireNotNull (bufFrom);
                Require (bufFrom + GetLength () >= bufTo);
                size_t  nChars  =   GetLength ();
                (void)::memcpy (bufFrom, Peek (), nChars * sizeof (Character));
            }
            inline  void    String::_Rep::CopyTo (wchar_t* bufFrom, wchar_t* bufTo) const
            {
                RequireNotNull (bufFrom);
                Require (bufFrom + GetLength () >= bufTo);
                size_t  nChars  =   GetLength ();
                (void)::memcpy (bufFrom, Peek (), nChars * sizeof (Character));
            }

            //  class   String
            inline  String::String (const String& from)
                : _fRep (from._fRep)
            {
            }
            inline  String& String::operator= (const String& newString)
            {
                _fRep = newString._fRep;
                return (*this);
            }
            inline  String::~String ()
            {
            }
            inline  String::_Rep*   String::Clone_ (const _Rep& rep)
            {
                return (rep.Clone ());
            }
            inline  void    String::CopyTo (Character* bufFrom, Character* bufTo) const
            {
                RequireNotNull (bufFrom);
                Require (bufFrom + GetLength () >= bufTo);
                _fRep->CopyTo (bufFrom, bufTo);
            }
            inline  void    String::CopyTo (wchar_t* bufFrom, wchar_t* bufTo) const
            {
                RequireNotNull (bufFrom);
                Require (bufFrom + GetLength () >= bufTo);
                _fRep->CopyTo (bufFrom, bufTo);
            }
            inline  size_t  String::GetLength () const
            {
                return (_fRep->GetLength ());
            }
            inline  bool    String::empty () const
            {
                return _fRep->GetLength () == 0;
            }
            inline  void    String::clear ()
            {
                *this = String ();
            }
            inline  void    String::InsertAt (Character c, size_t at)
            {
                InsertAt (&c, &c + 1, at);
            }
            inline  void    String::InsertAt (const String& s, size_t at)
            {
                // NB: I don't THINK we need be careful if s.fRep == this->fRep because when we first derefence this->fRep it will force a CLONE, so OUR fRep will be unique
                // And no need to worry about lifetime of 'p' because we don't allow changes to 's' from two different threads at a time, and the rep would rep if accessed from
                // another thread could only change that other envelopes copy
                pair<const Character*, const Character*> d   =   s._fRep->GetData ();
                InsertAt (d.first, d.second, at);
            }
            inline  void    String::InsertAt (const wchar_t* from, const wchar_t* to, size_t at)
            {
                InsertAt (reinterpret_cast<const Character*> (from), reinterpret_cast<const Character*> (to), at);
            }
            inline  String& String::operator+= (Character appendage)
            {
                InsertAt (appendage, GetLength ());
                return (*this);
            }
            inline  String& String::operator+= (const String& appendage)
            {
                InsertAt (appendage, GetLength ());
                return (*this);
            }
            inline  Character   String::operator[] (size_t i) const
            {
                Require (i >= 0);
                Require (i < GetLength ());
                return (_fRep->GetAt (i));
            }
            template    <>
            inline  void    String::As (wstring* into) const
            {
                RequireNotNull (into);
                size_t  n   =   GetLength ();
                const Character* cp =   _fRep->Peek ();
                Assert (sizeof (Character) == sizeof (wchar_t));        // going to want to clean this up!!!    --LGP 2011-09-01
                const wchar_t* wcp  =   (const wchar_t*)cp;
                into->assign (wcp, wcp + n);
            }
            template    <>
            inline  wstring String::As () const
            {
                wstring r;
                As (&r);
                return r;
            }
            template    <>
            inline  const wchar_t*  String::As () const
            {
// I'm not sure of the Peek() semantics, so I'm not sure this is right, but document Peek() better so this is safe!!!   -- LGP 2011-09-01
                return (const wchar_t*)_fRep->Peek ();
            }
            template    <>
            inline  const Character*    String::As () const
            {
// I'm not sure of the Peek() semantics, so I'm not sure this is right, but document Peek() better so this is safe!!!   -- LGP 2011-09-01
                return (const Character*)_fRep->Peek ();
            }
            template    <>
            inline  string  String::AsUTF8 () const
            {
                string  r;
                AsUTF8 (&r);
                return r;
            }
            inline  std::string String::AsUTF8 () const
            {
                return AsUTF8<std::string> ();
            }
            inline  void        String::AsUTF8 (std::string* into) const
            {
                AsUTF8<std::string> (into);
            }
            template    <>
            inline  string  String::AsASCII () const
            {
                string  r;
                AsASCII (&r);
                return r;
            }
            inline  std::string String::AsASCII () const
            {
                return AsASCII<std::string> ();
            }
            inline  void    String::AsASCII (std::string* into) const
            {
                AsASCII<std::string> (into);
            }
            inline  size_t  String::length () const
            {
                return GetLength ();
            }
            inline  size_t  String::size () const
            {
                return GetLength ();
            }
            inline  const wchar_t*  String::data () const
            {
                return As<const wchar_t*> ();
            }
            inline  size_t String::find (wchar_t c) const
            {
                return IndexOf (c);
            }
            inline  size_t String::rfind (wchar_t c) const
            {
                return RIndexOf (c);
            }
            inline  int String::Compare (const String& rhs, CompareOptions co) const
            {
                pair<const Character*, const Character*> d   =   rhs._fRep->GetData ();
                return _fRep->Compare (d.first, d.second, co);
            }
            inline  int String::Compare (const Character* rhsStart, const Character* rhsEnd, CompareOptions co) const
            {
                return _fRep->Compare (rhsStart, rhsEnd, co);
            }
            inline  int String::Compare (const wchar_t* rhsStart, const wchar_t* rhsEnd, CompareOptions co) const
            {
                static_assert (sizeof (Character) == sizeof (wchar_t), "Character and wchar_t must be same size");
                return _fRep->Compare (reinterpret_cast<const Character*> (rhsStart), reinterpret_cast<const Character*> (rhsEnd), co);
            }

            inline  bool    operator== (const String& lhs, const String& rhs)
            {
                if (lhs._fRep == rhs._fRep) {
                    return (true);
                }
                pair<const Character*, const Character*> d   =   rhs._fRep->GetData ();
                return lhs.Compare (d.first, d.second, String::eWithCase_CO) == 0;
            }
            inline  bool    operator== (const wchar_t* lhs, const String& rhs)
            {
                RequireNotNull (lhs);
                return rhs.Compare (lhs, lhs + ::wcslen (lhs), String::eWithCase_CO) == 0;
            }
            inline  bool    operator== (const String& lhs, const wchar_t* rhs)
            {
                RequireNotNull (rhs);
                return lhs.Compare (rhs, rhs + ::wcslen (rhs), String::eWithCase_CO) == 0;
            }
            inline  bool    operator< (const String& lhs, const String& rhs)
            {
                if (lhs._fRep == rhs._fRep) {
                    return (false);
                }
                pair<const Character*, const Character*> d   =   rhs._fRep->GetData ();
                return lhs.Compare (d.first, d.second, String::eWithCase_CO) < 0;
            }
            inline  bool    operator< (const wchar_t* lhs, const String& rhs)
            {
                RequireNotNull (lhs);
                return rhs.Compare (lhs, lhs + ::wcslen (lhs), String::eWithCase_CO) >= 0;
            }
            inline  bool    operator< (const String& lhs, const wchar_t* rhs)
            {
                RequireNotNull (rhs);
                return lhs.Compare (rhs, rhs + ::wcslen (rhs), String::eWithCase_CO) < 0;
            }
            inline  bool    operator<= (const String& lhs, const String& rhs)
            {
                if (lhs._fRep == rhs._fRep) {
                    return (false);
                }
                pair<const Character*, const Character*> d   =   rhs._fRep->GetData ();
                return lhs.Compare (d.first, d.second, String::eWithCase_CO) <= 0;
            }
            inline  bool    operator<= (const wchar_t* lhs, const String& rhs)
            {
                RequireNotNull (lhs);
                return rhs.Compare (lhs, lhs + ::wcslen (lhs), String::eWithCase_CO) > 0;
            }
            inline  bool    operator<= (const String& lhs, const wchar_t* rhs)
            {
                RequireNotNull (rhs);
                return lhs.Compare (rhs, rhs + ::wcslen (rhs), String::eWithCase_CO) <= 0;
            }
            inline  bool    operator!= (const String& lhs, const String& rhs)
            {
                return (bool (not (lhs == rhs)));
            }
            inline  bool    operator!= (const wchar_t* lhs, const String& rhs)
            {
                return (bool (not (lhs == rhs)));
            }
            inline  bool    operator!= (const String& lhs, const wchar_t* rhs)
            {
                return (bool (not (lhs == rhs)));
            }
            inline  bool    operator> (const String& lhs, const String& rhs)
            {
                return (bool (not (lhs <= rhs)));
            }
            inline  bool    operator> (const wchar_t* lhs, const String& rhs)
            {
                return (bool (not (lhs <= rhs)));
            }
            inline  bool    operator> (const String& lhs, const wchar_t* rhs)
            {
                return (bool (not (lhs <= rhs)));
            }
            inline  bool    operator>= (const String& lhs, const String& rhs)
            {
                return (bool (not (lhs < rhs)));
            }
            inline  bool    operator>= (const wchar_t* lhs, const String& rhs)
            {
                return (bool (not (lhs < rhs)));
            }
            inline  bool    operator>= (const String& lhs, const wchar_t* rhs)
            {
                return (bool (not (lhs < rhs)));
            }

#if 0
            //  class   String_CharArray
            inline  String_CharArray::String_CharArray (const String_CharArray& s)
                : String (s)
            {
            }
            inline  String_CharArray& String_CharArray::operator= (const String_CharArray& s)
            {
                String::operator= (s);
                return (*this);
            }
#endif

            //  class   String_BufferedArray
            inline  String_BufferedArray::String_BufferedArray (const String_BufferedArray& s)
                : String (s)
            {
            }
            inline  String_BufferedArray& String_BufferedArray::operator= (const String_BufferedArray& s)
            {
                String::operator= (s);
                return (*this);
            }

            //  class   String_ExternalMemoryOwnership_ApplicationLifetime_ReadOnly
            inline  String_ExternalMemoryOwnership_ApplicationLifetime_ReadOnly::String_ExternalMemoryOwnership_ApplicationLifetime_ReadOnly (const String_ExternalMemoryOwnership_ApplicationLifetime_ReadOnly& s)
                : String (s)
            {
            }
            inline  String_ExternalMemoryOwnership_ApplicationLifetime_ReadOnly& String_ExternalMemoryOwnership_ApplicationLifetime_ReadOnly::operator= (const String_ExternalMemoryOwnership_ApplicationLifetime_ReadOnly& s)
            {
                String::operator= (s);
                return (*this);
            }

            //  class   String_ExternalMemoryOwnership_ApplicationLifetime_ReadWrite
            inline  String_ExternalMemoryOwnership_ApplicationLifetime_ReadWrite::String_ExternalMemoryOwnership_ApplicationLifetime_ReadWrite (const String_ExternalMemoryOwnership_ApplicationLifetime_ReadWrite& s)
                : String (s)
            {
            }
            inline  String_ExternalMemoryOwnership_ApplicationLifetime_ReadWrite& String_ExternalMemoryOwnership_ApplicationLifetime_ReadWrite::operator= (const String_ExternalMemoryOwnership_ApplicationLifetime_ReadWrite& s)
            {
                String::operator= (s);
                return (*this);
            }
        }
    }
}

#endif // _Stroika_Foundation_Characters_String_inl_
<commit_msg>Include BlockAllocated.h in Strings.inl - though not directly used - because the BlockAllocation moduleneeds to be INITIALIZED before calls to teh Strings code is used, and the ModuleInit<> mechanism requires these #includes to get the ModuleInit<> stuff called at the right point<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2012.  All rights reserved
 */
#ifndef _Stroika_Foundation_Characters_String_inl_
#define _Stroika_Foundation_Characters_String_inl_

/*
 ********************************************************************************
 ***************************** Implementation Details ***************************
 ********************************************************************************
 */
#include    "../Debug/Assertions.h"
#include    "../Memory/BlockAllocated.h"		// #include here because the CPP module depends on BlockAllocated, and this #include needed assure ModuleInit<> proper order

namespace   Stroika {
    namespace   Foundation {
        namespace   Characters {

            template    <>
            inline  size_t  C_String::Length (const char* p)
            {
                RequireNotNull (p);
                return ::strlen (p);
            }
            template    <>
            inline  size_t  C_String::Length (const wchar_t* p)
            {
                RequireNotNull (p);
                return ::wcslen (p);
            }

            //  class   String::_Rep
            inline  String::_Rep::_Rep ()
            {
            }
            inline  String::_Rep::~_Rep ()
            {
            }
            inline  void    String::_Rep::CopyTo (Character* bufFrom, Character* bufTo) const
            {
                RequireNotNull (bufFrom);
                Require (bufFrom + GetLength () >= bufTo);
                size_t  nChars  =   GetLength ();
                (void)::memcpy (bufFrom, Peek (), nChars * sizeof (Character));
            }
            inline  void    String::_Rep::CopyTo (wchar_t* bufFrom, wchar_t* bufTo) const
            {
                RequireNotNull (bufFrom);
                Require (bufFrom + GetLength () >= bufTo);
                size_t  nChars  =   GetLength ();
                (void)::memcpy (bufFrom, Peek (), nChars * sizeof (Character));
            }

            //  class   String
            inline  String::String (const String& from)
                : _fRep (from._fRep)
            {
            }
            inline  String& String::operator= (const String& newString)
            {
                _fRep = newString._fRep;
                return (*this);
            }
            inline  String::~String ()
            {
            }
            inline  String::_Rep*   String::Clone_ (const _Rep& rep)
            {
                return (rep.Clone ());
            }
            inline  void    String::CopyTo (Character* bufFrom, Character* bufTo) const
            {
                RequireNotNull (bufFrom);
                Require (bufFrom + GetLength () >= bufTo);
                _fRep->CopyTo (bufFrom, bufTo);
            }
            inline  void    String::CopyTo (wchar_t* bufFrom, wchar_t* bufTo) const
            {
                RequireNotNull (bufFrom);
                Require (bufFrom + GetLength () >= bufTo);
                _fRep->CopyTo (bufFrom, bufTo);
            }
            inline  size_t  String::GetLength () const
            {
                return (_fRep->GetLength ());
            }
            inline  bool    String::empty () const
            {
                return _fRep->GetLength () == 0;
            }
            inline  void    String::clear ()
            {
                *this = String ();
            }
            inline  void    String::InsertAt (Character c, size_t at)
            {
                InsertAt (&c, &c + 1, at);
            }
            inline  void    String::InsertAt (const String& s, size_t at)
            {
                // NB: I don't THINK we need be careful if s.fRep == this->fRep because when we first derefence this->fRep it will force a CLONE, so OUR fRep will be unique
                // And no need to worry about lifetime of 'p' because we don't allow changes to 's' from two different threads at a time, and the rep would rep if accessed from
                // another thread could only change that other envelopes copy
                pair<const Character*, const Character*> d   =   s._fRep->GetData ();
                InsertAt (d.first, d.second, at);
            }
            inline  void    String::InsertAt (const wchar_t* from, const wchar_t* to, size_t at)
            {
                InsertAt (reinterpret_cast<const Character*> (from), reinterpret_cast<const Character*> (to), at);
            }
            inline  String& String::operator+= (Character appendage)
            {
                InsertAt (appendage, GetLength ());
                return (*this);
            }
            inline  String& String::operator+= (const String& appendage)
            {
                InsertAt (appendage, GetLength ());
                return (*this);
            }
            inline  Character   String::operator[] (size_t i) const
            {
                Require (i >= 0);
                Require (i < GetLength ());
                return (_fRep->GetAt (i));
            }
            template    <>
            inline  void    String::As (wstring* into) const
            {
                RequireNotNull (into);
                size_t  n   =   GetLength ();
                const Character* cp =   _fRep->Peek ();
                Assert (sizeof (Character) == sizeof (wchar_t));        // going to want to clean this up!!!    --LGP 2011-09-01
                const wchar_t* wcp  =   (const wchar_t*)cp;
                into->assign (wcp, wcp + n);
            }
            template    <>
            inline  wstring String::As () const
            {
                wstring r;
                As (&r);
                return r;
            }
            template    <>
            inline  const wchar_t*  String::As () const
            {
// I'm not sure of the Peek() semantics, so I'm not sure this is right, but document Peek() better so this is safe!!!   -- LGP 2011-09-01
                return (const wchar_t*)_fRep->Peek ();
            }
            template    <>
            inline  const Character*    String::As () const
            {
// I'm not sure of the Peek() semantics, so I'm not sure this is right, but document Peek() better so this is safe!!!   -- LGP 2011-09-01
                return (const Character*)_fRep->Peek ();
            }
            template    <>
            inline  string  String::AsUTF8 () const
            {
                string  r;
                AsUTF8 (&r);
                return r;
            }
            inline  std::string String::AsUTF8 () const
            {
                return AsUTF8<std::string> ();
            }
            inline  void        String::AsUTF8 (std::string* into) const
            {
                AsUTF8<std::string> (into);
            }
            template    <>
            inline  string  String::AsASCII () const
            {
                string  r;
                AsASCII (&r);
                return r;
            }
            inline  std::string String::AsASCII () const
            {
                return AsASCII<std::string> ();
            }
            inline  void    String::AsASCII (std::string* into) const
            {
                AsASCII<std::string> (into);
            }
            inline  size_t  String::length () const
            {
                return GetLength ();
            }
            inline  size_t  String::size () const
            {
                return GetLength ();
            }
            inline  const wchar_t*  String::data () const
            {
                return As<const wchar_t*> ();
            }
            inline  size_t String::find (wchar_t c) const
            {
                return IndexOf (c);
            }
            inline  size_t String::rfind (wchar_t c) const
            {
                return RIndexOf (c);
            }
            inline  int String::Compare (const String& rhs, CompareOptions co) const
            {
                pair<const Character*, const Character*> d   =   rhs._fRep->GetData ();
                return _fRep->Compare (d.first, d.second, co);
            }
            inline  int String::Compare (const Character* rhsStart, const Character* rhsEnd, CompareOptions co) const
            {
                return _fRep->Compare (rhsStart, rhsEnd, co);
            }
            inline  int String::Compare (const wchar_t* rhsStart, const wchar_t* rhsEnd, CompareOptions co) const
            {
                static_assert (sizeof (Character) == sizeof (wchar_t), "Character and wchar_t must be same size");
                return _fRep->Compare (reinterpret_cast<const Character*> (rhsStart), reinterpret_cast<const Character*> (rhsEnd), co);
            }

            inline  bool    operator== (const String& lhs, const String& rhs)
            {
                if (lhs._fRep == rhs._fRep) {
                    return (true);
                }
                pair<const Character*, const Character*> d   =   rhs._fRep->GetData ();
                return lhs.Compare (d.first, d.second, String::eWithCase_CO) == 0;
            }
            inline  bool    operator== (const wchar_t* lhs, const String& rhs)
            {
                RequireNotNull (lhs);
                return rhs.Compare (lhs, lhs + ::wcslen (lhs), String::eWithCase_CO) == 0;
            }
            inline  bool    operator== (const String& lhs, const wchar_t* rhs)
            {
                RequireNotNull (rhs);
                return lhs.Compare (rhs, rhs + ::wcslen (rhs), String::eWithCase_CO) == 0;
            }
            inline  bool    operator< (const String& lhs, const String& rhs)
            {
                if (lhs._fRep == rhs._fRep) {
                    return (false);
                }
                pair<const Character*, const Character*> d   =   rhs._fRep->GetData ();
                return lhs.Compare (d.first, d.second, String::eWithCase_CO) < 0;
            }
            inline  bool    operator< (const wchar_t* lhs, const String& rhs)
            {
                RequireNotNull (lhs);
                return rhs.Compare (lhs, lhs + ::wcslen (lhs), String::eWithCase_CO) >= 0;
            }
            inline  bool    operator< (const String& lhs, const wchar_t* rhs)
            {
                RequireNotNull (rhs);
                return lhs.Compare (rhs, rhs + ::wcslen (rhs), String::eWithCase_CO) < 0;
            }
            inline  bool    operator<= (const String& lhs, const String& rhs)
            {
                if (lhs._fRep == rhs._fRep) {
                    return (false);
                }
                pair<const Character*, const Character*> d   =   rhs._fRep->GetData ();
                return lhs.Compare (d.first, d.second, String::eWithCase_CO) <= 0;
            }
            inline  bool    operator<= (const wchar_t* lhs, const String& rhs)
            {
                RequireNotNull (lhs);
                return rhs.Compare (lhs, lhs + ::wcslen (lhs), String::eWithCase_CO) > 0;
            }
            inline  bool    operator<= (const String& lhs, const wchar_t* rhs)
            {
                RequireNotNull (rhs);
                return lhs.Compare (rhs, rhs + ::wcslen (rhs), String::eWithCase_CO) <= 0;
            }
            inline  bool    operator!= (const String& lhs, const String& rhs)
            {
                return (bool (not (lhs == rhs)));
            }
            inline  bool    operator!= (const wchar_t* lhs, const String& rhs)
            {
                return (bool (not (lhs == rhs)));
            }
            inline  bool    operator!= (const String& lhs, const wchar_t* rhs)
            {
                return (bool (not (lhs == rhs)));
            }
            inline  bool    operator> (const String& lhs, const String& rhs)
            {
                return (bool (not (lhs <= rhs)));
            }
            inline  bool    operator> (const wchar_t* lhs, const String& rhs)
            {
                return (bool (not (lhs <= rhs)));
            }
            inline  bool    operator> (const String& lhs, const wchar_t* rhs)
            {
                return (bool (not (lhs <= rhs)));
            }
            inline  bool    operator>= (const String& lhs, const String& rhs)
            {
                return (bool (not (lhs < rhs)));
            }
            inline  bool    operator>= (const wchar_t* lhs, const String& rhs)
            {
                return (bool (not (lhs < rhs)));
            }
            inline  bool    operator>= (const String& lhs, const wchar_t* rhs)
            {
                return (bool (not (lhs < rhs)));
            }

#if 0
            //  class   String_CharArray
            inline  String_CharArray::String_CharArray (const String_CharArray& s)
                : String (s)
            {
            }
            inline  String_CharArray& String_CharArray::operator= (const String_CharArray& s)
            {
                String::operator= (s);
                return (*this);
            }
#endif

            //  class   String_BufferedArray
            inline  String_BufferedArray::String_BufferedArray (const String_BufferedArray& s)
                : String (s)
            {
            }
            inline  String_BufferedArray& String_BufferedArray::operator= (const String_BufferedArray& s)
            {
                String::operator= (s);
                return (*this);
            }

            //  class   String_ExternalMemoryOwnership_ApplicationLifetime_ReadOnly
            inline  String_ExternalMemoryOwnership_ApplicationLifetime_ReadOnly::String_ExternalMemoryOwnership_ApplicationLifetime_ReadOnly (const String_ExternalMemoryOwnership_ApplicationLifetime_ReadOnly& s)
                : String (s)
            {
            }
            inline  String_ExternalMemoryOwnership_ApplicationLifetime_ReadOnly& String_ExternalMemoryOwnership_ApplicationLifetime_ReadOnly::operator= (const String_ExternalMemoryOwnership_ApplicationLifetime_ReadOnly& s)
            {
                String::operator= (s);
                return (*this);
            }

            //  class   String_ExternalMemoryOwnership_ApplicationLifetime_ReadWrite
            inline  String_ExternalMemoryOwnership_ApplicationLifetime_ReadWrite::String_ExternalMemoryOwnership_ApplicationLifetime_ReadWrite (const String_ExternalMemoryOwnership_ApplicationLifetime_ReadWrite& s)
                : String (s)
            {
            }
            inline  String_ExternalMemoryOwnership_ApplicationLifetime_ReadWrite& String_ExternalMemoryOwnership_ApplicationLifetime_ReadWrite::operator= (const String_ExternalMemoryOwnership_ApplicationLifetime_ReadWrite& s)
            {
                String::operator= (s);
                return (*this);
            }
        }
    }
}

#endif // _Stroika_Foundation_Characters_String_inl_
<|endoftext|>


<commit_before>/*
  Copyright (c) 2014, J.D. Koftinoff Software, Ltd.
  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 of J.D. Koftinoff Software, Ltd. 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.
*/

#include "JDKSAvdeccMCU_World.hpp"
#include "JDKSAvdeccMCU_Apc.hpp"

#if defined( __APPLE__ )
namespace JDKSAvdeccMCU
{

void ApcStateMachine::start() {}

void ApcStateMachine::finish() {}

void ApcStateMachine::executeState()
{
    switch ( m_state )
    {
    case StateBegin:
        executeStateBegin();
        break;
    case StateInitialize:
        executeStateInitialize();
        break;
    case StateWaitForConnect:
        executeStateWaitForConnect();
        break;
    case StateAccept:
        executeStateAccept();
        break;
    case StateStartTransfer:
        executeStateStartTransfer();
        break;
    case StateWaiting:
        executeStateWaiting();
        break;
    case StateClosed:
        executeStateClosed();
        break;
    case StateLinkStatus:
        executeStateLinkStatus();
        break;
    case StateReceiveMsg:
        executeStateReceiveMsg();
        break;
    case StateSendMsg:
        executeStateSendMsg();
        break;
    case StateEntityIdAssigned:
        executeStateEntityIdAssigned();
        break;
    case StateSendNop:
        executeStateSendNop();
        break;
    case StateFinish:
        executeStateFinish();
        break;
    case StateEnd:
        executeStateEnd();
        break;
    default:
        executeStateEnd();
        break;
    }
}

void ApcStateMachine::gotoStateBegin() { m_state = StateBegin; }

void ApcStateMachine::executeStateBegin() { gotoStateInitialize(); }

void ApcStateMachine::gotoStateInitialize()
{
    m_state = StateInitialize;
    initialize();
    connectToProxy( m_addr );
}

void ApcStateMachine::executeStateInitialize() { gotoStateWaitForConnect(); }

void ApcStateMachine::gotoStateWaitForConnect()
{
    m_state = StateWaitForConnect;
}

void ApcStateMachine::executeStateWaitForConnect()
{
    if ( m_tcpConnected )
    {
        gotoStateAccept();
    }
    else if ( m_finished )
    {
        gotoStateFinish();
    }
}

void ApcStateMachine::gotoStateAccept()
{
    m_state = StateAccept;
    sendHttpRequest( m_addr );
}

void ApcStateMachine::executeStateAccept()
{
    if ( getHttpResponse() )
    {
        gotoStateStartTransfer();
    }
    else
    {
        gotoStateClosed();
    }
}

void ApcStateMachine::gotoStateStartTransfer()
{

}

void ApcStateMachine::executeStateStartTransfer()
{

}

void ApcStateMachine::gotoStateWaiting()
{

}
}

#endif
<commit_msg>clang-format applied<commit_after>/*
  Copyright (c) 2014, J.D. Koftinoff Software, Ltd.
  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 of J.D. Koftinoff Software, Ltd. 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.
*/

#include "JDKSAvdeccMCU_World.hpp"
#include "JDKSAvdeccMCU_Apc.hpp"

#if defined( __APPLE__ )
namespace JDKSAvdeccMCU
{

void ApcStateMachine::start() {}

void ApcStateMachine::finish() {}

void ApcStateMachine::executeState()
{
    switch ( m_state )
    {
    case StateBegin:
        executeStateBegin();
        break;
    case StateInitialize:
        executeStateInitialize();
        break;
    case StateWaitForConnect:
        executeStateWaitForConnect();
        break;
    case StateAccept:
        executeStateAccept();
        break;
    case StateStartTransfer:
        executeStateStartTransfer();
        break;
    case StateWaiting:
        executeStateWaiting();
        break;
    case StateClosed:
        executeStateClosed();
        break;
    case StateLinkStatus:
        executeStateLinkStatus();
        break;
    case StateReceiveMsg:
        executeStateReceiveMsg();
        break;
    case StateSendMsg:
        executeStateSendMsg();
        break;
    case StateEntityIdAssigned:
        executeStateEntityIdAssigned();
        break;
    case StateSendNop:
        executeStateSendNop();
        break;
    case StateFinish:
        executeStateFinish();
        break;
    case StateEnd:
        executeStateEnd();
        break;
    default:
        executeStateEnd();
        break;
    }
}

void ApcStateMachine::gotoStateBegin() { m_state = StateBegin; }

void ApcStateMachine::executeStateBegin() { gotoStateInitialize(); }

void ApcStateMachine::gotoStateInitialize()
{
    m_state = StateInitialize;
    initialize();
    connectToProxy( m_addr );
}

void ApcStateMachine::executeStateInitialize() { gotoStateWaitForConnect(); }

void ApcStateMachine::gotoStateWaitForConnect()
{
    m_state = StateWaitForConnect;
}

void ApcStateMachine::executeStateWaitForConnect()
{
    if ( m_tcpConnected )
    {
        gotoStateAccept();
    }
    else if ( m_finished )
    {
        gotoStateFinish();
    }
}

void ApcStateMachine::gotoStateAccept()
{
    m_state = StateAccept;
    sendHttpRequest( m_addr );
}

void ApcStateMachine::executeStateAccept()
{
    if ( getHttpResponse() )
    {
        gotoStateStartTransfer();
    }
    else
    {
        gotoStateClosed();
    }
}

void ApcStateMachine::gotoStateStartTransfer() {}

void ApcStateMachine::executeStateStartTransfer() {}

void ApcStateMachine::gotoStateWaiting() {}
}

#endif
<|endoftext|>


<commit_before>/*
Copyright (c) 2015 Dilyan Rusev

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 "scene.h"
#include "json/json.h"
#include "tinyxml2.h"
#include <fstream>
#include <memory>
#include "SDL_log.h"

using namespace std;

namespace foo {

Scene::Scene() {}

Scene::Scene(Scene &&other) {
	swap(*this, other);
}

Scene::~Scene() {}

Scene& Scene::operator=(Scene &&other) {
	if (this != &other) {
		id_.clear();
		title_.clear();
		textures_.clear();
		spritesheets_.clear();
		objects_.clear();

		swap(*this, other);
	}
	return *this;
}

void Scene::LoadFromFile(const char *file_name) {
	SDL_LogInfo(
		SDL_LOG_CATEGORY_SYSTEM,
		"Loading scene from %s...\n",
		file_name);

	string prefix(file_name);
	auto last_separator = prefix.find_last_of('\\');
	if (string::npos == last_separator) {
		last_separator = prefix.find_last_of('/');
	}
	if (string::npos != last_separator) {
		prefix.erase(last_separator + 1, string::npos);
	}

	ifstream in_file(file_name);
	Json::Value in;
	in_file >> in;

	const Json::Value &json_id = in["id"];
	if (!json_id.isNull()) {
		id_ = json_id.asString();
	}

	title_ = in["title"].asString();
	width_ = in["width"].asInt();
	height_ = in["height"].asInt();

	ProcessSpritesheets(prefix, in["spritesheets"]);
	ProcessTextures(prefix, in["textures"]);
	ProcessSceneObjects(prefix, in["objects"]);
}

void Scene::ProcessTextures(
		const string &prefix,
		const Json::Value &in) {
	SDL_LogInfo(
		SDL_LOG_CATEGORY_SYSTEM,
		"Processing scene textures...\n");

	textures_.clear();

	if (in.isNull() || !in.isArray()) {
		return;
	}

	for (Json::Value::ArrayIndex i = 0;
		i < in.size();
		++i) {
		const auto &json_object = in[i];

		SceneTexture texture;
		texture.id = json_object["id"].asString();
		texture.path = prefix + json_object["path"].asString();
		textures_.emplace_back(std::move(texture));
	}
}

void Scene::ProcessSpritesheets(
		const string &prefix,
		const Json::Value &in) {
	SDL_LogInfo(
		SDL_LOG_CATEGORY_SYSTEM,
		"Processing scene spritesheets...\n");

	spritesheets_.clear();

	if (in.isNull() || !in.isArray()) {
		return;
	}

	for (Json::Value::ArrayIndex i = 0;
		i < in.size();
		++i) {
		const auto &json_object = in[i];

		SceneSpritesheet sheet;
		sheet.id = json_object["id"].asString();
		sheet.path = prefix + json_object["path"].asString();
		ProcessTextureAtlasXml(prefix, sheet);
	}
}

void Scene::ProcessTextureAtlasXml(
		const string &prefix,
		SceneSpritesheet &out) const {
	SDL_LogInfo(
		SDL_LOG_CATEGORY_SYSTEM,
		"Processing XML texture atlas %s...\n",
		out.path.c_str());

	using namespace tinyxml2;

	out.regions.clear();
	XMLDocument doc;
	XMLError error;

	error = doc.LoadFile(out.path.c_str());
	if (error != XML_NO_ERROR) {
		SDL_LogError(
			SDL_LOG_CATEGORY_SYSTEM,
			"Failed to load atlas %s: %d\n",
			out.path.c_str(),
			error);
		throw runtime_error("Failed to load atlas file");
	}

	XMLElement *root = doc.RootElement();
	if (!root) {
		throw runtime_error("Atlas file has no root XML element");
	}

	const char *raw_path = root->Attribute("imagePath");
	if (!raw_path) {
		throw runtime_error("Failed to get TextureAtlas.imagePath");
	}

	out.image_path = prefix + string(raw_path);

	for (XMLElement *current = root->FirstChildElement("SubTexture");
			current;
			current = current->NextSiblingElement("SubTexture")) {
		SceneSceneSpritesheetRegion region;

		const char *raw_name = current->Attribute("name");
		if (!raw_name) {
			throw runtime_error("Failed to get SubTexture.name");
		}
		region.name = raw_name;

		if (current->QueryAttribute("x", &region.x)
				!= XML_NO_ERROR) {
			SDL_LogError(
				SDL_LOG_CATEGORY_SYSTEM,
				"Failed on element %s\n",
				raw_name);
			throw runtime_error("Failed to get SubTexture.x");
		}

		if (current->QueryAttribute("y", &region.y)
				!= XML_NO_ERROR) {
			SDL_LogError(
				SDL_LOG_CATEGORY_SYSTEM,
				"Failed on element %s\n",
				raw_name);
			throw runtime_error("Failed to get SubTexture.y");
		}

		if (current->QueryAttribute("width", &region.width)
				!= XML_NO_ERROR) {
			SDL_LogError(
				SDL_LOG_CATEGORY_SYSTEM,
				"Failed on element %s\n",
				raw_name);
			throw runtime_error("Failed to get SubTexture.width");
		}

		if (current->QueryAttribute("height", &region.height)
				!= XML_NO_ERROR) {
			SDL_LogError(
				SDL_LOG_CATEGORY_SYSTEM,
				"Failed on element %s\n",
				raw_name);
			throw runtime_error("Failed to get SubTexture.height");
		}

		out.regions.emplace_back(move(region));
	}

	SDL_LogInfo(
		SDL_LOG_CATEGORY_SYSTEM,
		"Processed %lu SubTexture-s.\n",
		static_cast<unsigned long>(out.regions.size()));
}

void Scene::ProcessSceneObjects(
		const string &prefix,
		const Json::Value &in) {
	SDL_LogInfo(SDL_LOG_CATEGORY_SYSTEM, "Processing scene objects...\n");
	objects_.clear();

	if (in.isNull() || !in.isArray()) {
		return;
	}

	for (Json::Value::ArrayIndex i = 0;
		i < in.size();
		++i) {
		const auto &json_object = in[i];

		SceneObject object;
		object.id = json_object["id"].asString();
		if (!object.id.size()) {
			SDL_LogWarn(
				SDL_LOG_CATEGORY_SYSTEM,
				"Empty object id: skipping\n");
			continue;
		}

		const auto &json_position = json_object["position"];
		if (json_position.isNull()
			|| !json_position.isArray()
			|| 2 != json_position.size()
			|| !json_position[0].isInt()
			|| !json_position[1].isInt()) {
			SDL_LogWarn(
				SDL_LOG_CATEGORY_SYSTEM,
				"Missing or malformatted position for %s: skipping\n",
				object.id.c_str());
			continue;
		}
		object.x = json_position[0].asInt();
		object.y = json_position[1].asInt();

		ProcessObjectComponents(prefix, json_object["components"], object);

		objects_.emplace_back(move(object));
	}
}

void Scene::ProcessObjectComponents(
		const string &prefix,
		const Json::Value &in,
		SceneObject &out) const {
	if (in.isNull()) {
		return;
	}

	for (Json::Value::ArrayIndex i = 0;
		i < in.size();
		++i) {
		const auto &json_object = in[i];

		const auto &json_type = json_object["type"];
		if (json_type.isNull() || !json_type.isString()) {
			SDL_LogWarn(
				SDL_LOG_CATEGORY_SYSTEM,
				"Missing or malformatted component type for"
				" %s: skipping\n",
				out.id.c_str());
			continue;
		}
		const auto &type = json_type.asString();

		if (type == "texture") {
			if (out.texture) {
				SDL_LogWarn(
					SDL_LOG_CATEGORY_SYSTEM,
					"Redefined texture component for %s: ignoring\n",
					out.id.c_str());
				continue;
			}

			out.texture = ProcessTextureComponent(
				out, json_object);
		} else if (type == "texture_repeat") {
			if (out.texture_repeat) {
				SDL_LogWarn(
					SDL_LOG_CATEGORY_SYSTEM,
					"Redefined texture_repeat component for %s: ignoring\n",
					out.id.c_str());
				continue;
			}

			out.texture_repeat = ProcessTextureRepeatComponent(
				out, json_object);
		} else {
			SDL_LogWarn(
				SDL_LOG_CATEGORY_SYSTEM,
				"Unknown component type %s for %s: ignoring\n",
				type.c_str(),
				out.id.c_str());
		}
	}
}

unique_ptr<SceneComponentTexture>
Scene::ProcessTextureComponent(
		const SceneObject &object,
		const Json::Value &in) const {
	const auto &json_texture_id = in["texture_id"];
	if (json_texture_id.isNull() || !json_texture_id.isString()) {
		SDL_LogWarn(
			SDL_LOG_CATEGORY_SYSTEM,
			"Missing texture_id for texture component "
			"in %s\n",
			object.id.c_str());
		return nullptr;
	}

	auto ptr = unique_ptr<SceneComponentTexture>(
		new SceneComponentTexture);
	ptr->texture_id = json_texture_id.asString();
	return move(ptr);
}

unique_ptr<SceneComponentTextureRepeat>
Scene::ProcessTextureRepeatComponent(
		const SceneObject &object,
		const Json::Value &in) const {
	const auto &json_repeat = in["repeat"];
	if (json_repeat.isNull()
		|| !json_repeat.isArray()
		|| json_repeat.size() != 2
		|| !json_repeat[0].isInt()
		|| !json_repeat[1].isInt()) {
		SDL_LogWarn(
			SDL_LOG_CATEGORY_SYSTEM,
			"Missing or malformated repeat texture_repeat "
			"comonent in %s\n",
			object.id.c_str());
		return nullptr;
	}

	auto ptr = unique_ptr<SceneComponentTextureRepeat>(
		new SceneComponentTextureRepeat);
	ptr->repeat_x = json_repeat[0].asInt();
	ptr->repeat_y = json_repeat[1].asInt();
	return move(ptr);
}

} // namespace foo<commit_msg>fix bug: not adding to list<commit_after>/*
Copyright (c) 2015 Dilyan Rusev

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 "scene.h"
#include "json/json.h"
#include "tinyxml2.h"
#include <fstream>
#include <memory>
#include "SDL_log.h"

using namespace std;

namespace foo {

Scene::Scene() {}

Scene::Scene(Scene &&other) {
	swap(*this, other);
}

Scene::~Scene() {}

Scene& Scene::operator=(Scene &&other) {
	if (this != &other) {
		id_.clear();
		title_.clear();
		textures_.clear();
		spritesheets_.clear();
		objects_.clear();

		swap(*this, other);
	}
	return *this;
}

void Scene::LoadFromFile(const char *file_name) {
	SDL_LogInfo(
		SDL_LOG_CATEGORY_SYSTEM,
		"Loading scene from %s...\n",
		file_name);

	string prefix(file_name);
	auto last_separator = prefix.find_last_of('\\');
	if (string::npos == last_separator) {
		last_separator = prefix.find_last_of('/');
	}
	if (string::npos != last_separator) {
		prefix.erase(last_separator + 1, string::npos);
	}

	ifstream in_file(file_name);
	Json::Value in;
	in_file >> in;

	const Json::Value &json_id = in["id"];
	if (!json_id.isNull()) {
		id_ = json_id.asString();
	}

	title_ = in["title"].asString();
	width_ = in["width"].asInt();
	height_ = in["height"].asInt();

	ProcessSpritesheets(prefix, in["spritesheets"]);
	ProcessTextures(prefix, in["textures"]);
	ProcessSceneObjects(prefix, in["objects"]);
}

void Scene::ProcessTextures(
		const string &prefix,
		const Json::Value &in) {
	SDL_LogInfo(
		SDL_LOG_CATEGORY_SYSTEM,
		"Processing scene textures...\n");

	textures_.clear();

	if (in.isNull() || !in.isArray()) {
		return;
	}

	for (Json::Value::ArrayIndex i = 0;
		i < in.size();
		++i) {
		const auto &json_object = in[i];

		SceneTexture texture;
		texture.id = json_object["id"].asString();
		texture.path = prefix + json_object["path"].asString();
		textures_.emplace_back(std::move(texture));
	}
}

void Scene::ProcessSpritesheets(
		const string &prefix,
		const Json::Value &in) {
	SDL_LogInfo(
		SDL_LOG_CATEGORY_SYSTEM,
		"Processing scene spritesheets...\n");

	spritesheets_.clear();

	if (in.isNull() || !in.isArray()) {
		return;
	}

	for (Json::Value::ArrayIndex i = 0;
		i < in.size();
		++i) {
		const auto &json_object = in[i];

		SceneSpritesheet sheet;
		sheet.id = json_object["id"].asString();
		sheet.path = prefix + json_object["path"].asString();
		ProcessTextureAtlasXml(prefix, sheet);

		spritesheets_.emplace_back(move(sheet));
	}
}

void Scene::ProcessTextureAtlasXml(
		const string &prefix,
		SceneSpritesheet &out) const {
	SDL_LogInfo(
		SDL_LOG_CATEGORY_SYSTEM,
		"Processing XML texture atlas %s...\n",
		out.path.c_str());

	using namespace tinyxml2;

	out.regions.clear();
	XMLDocument doc;
	XMLError error;

	error = doc.LoadFile(out.path.c_str());
	if (error != XML_NO_ERROR) {
		SDL_LogError(
			SDL_LOG_CATEGORY_SYSTEM,
			"Failed to load atlas %s: %d\n",
			out.path.c_str(),
			error);
		throw runtime_error("Failed to load atlas file");
	}

	XMLElement *root = doc.RootElement();
	if (!root) {
		throw runtime_error("Atlas file has no root XML element");
	}

	const char *raw_path = root->Attribute("imagePath");
	if (!raw_path) {
		throw runtime_error("Failed to get TextureAtlas.imagePath");
	}

	out.image_path = prefix + string(raw_path);

	for (XMLElement *current = root->FirstChildElement("SubTexture");
			current;
			current = current->NextSiblingElement("SubTexture")) {
		SceneSceneSpritesheetRegion region;

		const char *raw_name = current->Attribute("name");
		if (!raw_name) {
			throw runtime_error("Failed to get SubTexture.name");
		}
		region.name = raw_name;

		if (current->QueryAttribute("x", &region.x)
				!= XML_NO_ERROR) {
			SDL_LogError(
				SDL_LOG_CATEGORY_SYSTEM,
				"Failed on element %s\n",
				raw_name);
			throw runtime_error("Failed to get SubTexture.x");
		}

		if (current->QueryAttribute("y", &region.y)
				!= XML_NO_ERROR) {
			SDL_LogError(
				SDL_LOG_CATEGORY_SYSTEM,
				"Failed on element %s\n",
				raw_name);
			throw runtime_error("Failed to get SubTexture.y");
		}

		if (current->QueryAttribute("width", &region.width)
				!= XML_NO_ERROR) {
			SDL_LogError(
				SDL_LOG_CATEGORY_SYSTEM,
				"Failed on element %s\n",
				raw_name);
			throw runtime_error("Failed to get SubTexture.width");
		}

		if (current->QueryAttribute("height", &region.height)
				!= XML_NO_ERROR) {
			SDL_LogError(
				SDL_LOG_CATEGORY_SYSTEM,
				"Failed on element %s\n",
				raw_name);
			throw runtime_error("Failed to get SubTexture.height");
		}

		out.regions.emplace_back(move(region));
	}

	SDL_LogInfo(
		SDL_LOG_CATEGORY_SYSTEM,
		"Processed %lu SubTexture-s.\n",
		static_cast<unsigned long>(out.regions.size()));
}

void Scene::ProcessSceneObjects(
		const string &prefix,
		const Json::Value &in) {
	SDL_LogInfo(SDL_LOG_CATEGORY_SYSTEM, "Processing scene objects...\n");
	objects_.clear();

	if (in.isNull() || !in.isArray()) {
		return;
	}

	for (Json::Value::ArrayIndex i = 0;
		i < in.size();
		++i) {
		const auto &json_object = in[i];

		SceneObject object;
		object.id = json_object["id"].asString();
		if (!object.id.size()) {
			SDL_LogWarn(
				SDL_LOG_CATEGORY_SYSTEM,
				"Empty object id: skipping\n");
			continue;
		}

		const auto &json_position = json_object["position"];
		if (json_position.isNull()
			|| !json_position.isArray()
			|| 2 != json_position.size()
			|| !json_position[0].isInt()
			|| !json_position[1].isInt()) {
			SDL_LogWarn(
				SDL_LOG_CATEGORY_SYSTEM,
				"Missing or malformatted position for %s: skipping\n",
				object.id.c_str());
			continue;
		}
		object.x = json_position[0].asInt();
		object.y = json_position[1].asInt();

		ProcessObjectComponents(prefix, json_object["components"], object);

		objects_.emplace_back(move(object));
	}
}

void Scene::ProcessObjectComponents(
		const string &prefix,
		const Json::Value &in,
		SceneObject &out) const {
	if (in.isNull()) {
		return;
	}

	for (Json::Value::ArrayIndex i = 0;
		i < in.size();
		++i) {
		const auto &json_object = in[i];

		const auto &json_type = json_object["type"];
		if (json_type.isNull() || !json_type.isString()) {
			SDL_LogWarn(
				SDL_LOG_CATEGORY_SYSTEM,
				"Missing or malformatted component type for"
				" %s: skipping\n",
				out.id.c_str());
			continue;
		}
		const auto &type = json_type.asString();

		if (type == "texture") {
			if (out.texture) {
				SDL_LogWarn(
					SDL_LOG_CATEGORY_SYSTEM,
					"Redefined texture component for %s: ignoring\n",
					out.id.c_str());
				continue;
			}

			out.texture = ProcessTextureComponent(
				out, json_object);
		} else if (type == "texture_repeat") {
			if (out.texture_repeat) {
				SDL_LogWarn(
					SDL_LOG_CATEGORY_SYSTEM,
					"Redefined texture_repeat component for %s: ignoring\n",
					out.id.c_str());
				continue;
			}

			out.texture_repeat = ProcessTextureRepeatComponent(
				out, json_object);
		} else {
			SDL_LogWarn(
				SDL_LOG_CATEGORY_SYSTEM,
				"Unknown component type %s for %s: ignoring\n",
				type.c_str(),
				out.id.c_str());
		}
	}
}

unique_ptr<SceneComponentTexture>
Scene::ProcessTextureComponent(
		const SceneObject &object,
		const Json::Value &in) const {
	const auto &json_texture_id = in["texture_id"];
	if (json_texture_id.isNull() || !json_texture_id.isString()) {
		SDL_LogWarn(
			SDL_LOG_CATEGORY_SYSTEM,
			"Missing texture_id for texture component "
			"in %s\n",
			object.id.c_str());
		return nullptr;
	}

	auto ptr = unique_ptr<SceneComponentTexture>(
		new SceneComponentTexture);
	ptr->texture_id = json_texture_id.asString();
	return move(ptr);
}

unique_ptr<SceneComponentTextureRepeat>
Scene::ProcessTextureRepeatComponent(
		const SceneObject &object,
		const Json::Value &in) const {
	const auto &json_repeat = in["repeat"];
	if (json_repeat.isNull()
		|| !json_repeat.isArray()
		|| json_repeat.size() != 2
		|| !json_repeat[0].isInt()
		|| !json_repeat[1].isInt()) {
		SDL_LogWarn(
			SDL_LOG_CATEGORY_SYSTEM,
			"Missing or malformated repeat texture_repeat "
			"comonent in %s\n",
			object.id.c_str());
		return nullptr;
	}

	auto ptr = unique_ptr<SceneComponentTextureRepeat>(
		new SceneComponentTextureRepeat);
	ptr->repeat_x = json_repeat[0].asInt();
	ptr->repeat_y = json_repeat[1].asInt();
	return move(ptr);
}

} // namespace foo<|endoftext|>